Skip to content

Commit

Permalink
fix(interaction): Fix on eventRect rederaw
Browse files Browse the repository at this point in the history
- Rewirte of .getMaxDataCountTarget(), to get unique value based on x
Axis.
- .updateDataIndexByX() & .updateXs() are based on the
.getMaxDataCountTrarget()
- Add .updatePointClass() to update data point's class
- Refactor point.js to not receive `cssClassFn` on udpating data point's
class
- Update .getUnique() to handle datetime type

Fix #1028
Ref #1019
Ref #963
  • Loading branch information
netil committed Aug 19, 2019
1 parent 90792fa commit dc5f67a
Show file tree
Hide file tree
Showing 8 changed files with 244 additions and 64 deletions.
181 changes: 180 additions & 1 deletion spec/interactions/interaction-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,8 @@ describe("INTERACTION", () => {
axis: {
x: {
tick: {
fit: false
fit: false,
count: 5
},
type: "timeseries"
}
Expand All @@ -167,6 +168,126 @@ describe("INTERACTION", () => {
});
});

describe("timeseries #4", () => {
before(() => {
args = {
data: {
x: "x",
json: {
Temperature:["29.39", "29.7", "29.37", "28.87", "28.62", "27.72", "27.61", "27.82", "27.48", "26.78", "26.62", "26.64", "26.29", "26.01", "25.84", "25.07", "24.85", "24.01", "23.83", "22.8", "23", "22.64", "22.77", "22.64", "22.64", "22.62", "22.51", "21.42", "21.18", "20.93", "20.66", "20.48", "20.7", "21.24", "22.14", "22.78", "23.43", "23.16", "27.48", "26.78", "26.62", "26.64", "26.29", "26.01", "25.84", "25.07", "24.85", "24.01"],
x:["01-01-2015 00:00", "02-01-2015 00:00", "03-01-2015 00:00", "04-01-2015 00:00", "05-01-2015 00:00", "06-01-2015 00:00", "07-01-2015 00:00", "08-01-2015 00:00", "09-01-2015 00:00", "10-01-2015 00:00", "11-01-2015 00:00", "12-01-2015 00:00", "01-01-2016 00:00", "02-01-2016 00:00", "03-01-2016 00:00", "04-01-2016 00:00", "05-01-2016 00:00", "06-01-2016 00:00", "07-01-2016 00:00", "08-01-2016 00:00", "09-01-2016 00:00", "10-01-2016 00:00", "11-01-2016 00:00", "12-01-2016 00:00", "01-01-2017 00:00", "02-01-2017 00:00", "03-01-2017 00:00", "04-01-2017 00:00", "05-01-2017 00:00", "06-01-2017 00:00", "07-01-2017 00:00", "08-01-2017 00:00", "09-01-2017 00:00", "10-01-2017 00:00", "11-01-2017 00:00", "12-01-2017 00:00", "01-01-2018 00:00", "02-01-2018 00:00", "03-01-2018 00:00", "04-01-2018 00:00", "05-01-2018 00:00", "06-01-2018 00:00", "07-01-2018 00:00", "08-01-2018 00:00", "09-01-2018 00:00", "10-01-2018 00:00", "11-01-2018 00:00", "12-01-2018 00:00"]
},
type: "area",
xFormat: "%m-%d-%Y %H:%M"
},
axis: {
x: {
tick: {
fit: false,
count: 5
},
type: "timeseries"
}
}
};
});

it("check if rect & data points are generated correctly", () => {
const rect = chart.$.main.selectAll(`.${CLASS.eventRectsSingle} rect`);
const dataLen = chart.data()[0].values.length;
const circles = chart.$.line.circles;

rect.each((d, i) => {
expect(d.index).to.be.equal(i);
});

expect(rect.size()).to.be.equal(dataLen);
expect(circles.size()).to.be.equal(dataLen);

circles.each(function(d, i) {
expect(this.classList.contains(`${CLASS.shape}-${i}`)).to.be.true;
expect(d.index).to.be.equal(i);
});
});
});

describe("timeseries #5", () => {
before(() => {
args = {
data: {
x: "x",
columns: [
["x", "2013-01-01", "2013-01-02", "2013-01-03", "2013-01-04", "2013-01-05", "2013-01-06", "2013-01-07", "2013-01-08", "2013-01-09", "2013-01-10", "2013-01-11", "2013-01-12"],
["sample", 30, 200, 100, 400, 150, 250, 30, 200, 100, 400, 150, 250],
["sample2", 130, 100, 200, 300, 250, 150, 230, 130]
]
},
axis: {
x: {
type: "timeseries",
tick: {
values: [
"2013-01-05",
"2013-01-10"
]
}
}
}
};
});

it("check if rect & data points are generated correctly", () => {
const rect = chart.$.main.selectAll(`.${CLASS.eventRectsSingle} rect`);
const dataLen = chart.data()[0].values.length;
const circles = chart.$.line.circles;

const sampleCircle = circles.filter(d => d.id === "sample");
const sample2Circle = circles.filter(d => d.id === "sample2");

rect.each((d, i) => {
expect(d.index).to.be.equal(i);
});

expect(rect.size()).to.be.equal(dataLen);
expect(sampleCircle.size()).to.be.equal(dataLen);

sampleCircle.each(function(d, i) {
expect(this.classList.contains(`${CLASS.circle}-${i}`)).to.be.true;
expect(d.index).to.be.equal(i);
});

sample2Circle.each(function(d, i) {
expect(this.classList.contains(`${CLASS.circle}-${i}`)).to.be.true;
expect(d.index).to.be.equal(i);
});
});

it("check changes when 'sample' data is hidden", done => {
// when
chart.toggle("sample");

setTimeout(() => {
const rect = chart.$.main.selectAll(`.${CLASS.eventRectsSingle} rect`);
const dataLen = chart.data()[1].values.length;
const circles = chart.$.line.circles.filter(d => d.id === "sample2");

rect.each((d, i) => {
expect(d.index).to.be.equal(i);
});

expect(rect.size()).to.be.equal(dataLen);
expect(circles.size()).to.be.equal(dataLen);

circles.each(function(d, i) {
expect(this.classList.contains(`${CLASS.circle}-${i}`)).to.be.true;
expect(d.index).to.be.equal(i);
});

done();
}, 500);
});
});

describe("indexed", () => {
before(() => {
args = {
Expand All @@ -193,6 +314,64 @@ describe("INTERACTION", () => {
});
});
});

describe("flow", () => {
before(() => {
args = {
data: {
x: "x",
columns: [
["x", "2012-12-29", "2012-12-30", "2012-12-31"],
["data1", 230, 300, 330],
["data2", 190, 230, 200]
]
},
axis: {
x: {
type: "timeseries",
tick: {
format: "%m/%d"
}
}
}
};
});

it("check rect & data points generated after flow correctly", done => {
setTimeout(() => {
chart.flow({
columns: [
["x", '2013-01-11', '2013-01-21'],
["data1", 500, 200],
["data2", 100, 300]
],
duration: 500,
done: function() {
const rect = chart.$.main.selectAll(`.${CLASS.eventRectsSingle} rect`);
const circlesData1 = chart.$.main.selectAll(`.${CLASS.circles}-data1 circle`);
const circlesData2 = chart.$.main.selectAll(`.${CLASS.circles}-data2 circle`);

rect.each((d, i) => {
expect(d.index).to.be.equal(i);
});

["data1", "data2"].forEach(v => {
expect(rect.size()).to.be.equal(chart.data(v)[0].values.length);
});

[circlesData1, circlesData2].forEach(v => {
v.each(function(d, i) {
expect(this.classList.contains(`${CLASS.circle}-${i}`)).to.be.true;
expect(d.index).to.be.equal(i);
});
});

done();
}
});
}, 500);
});
});
});
});

Expand Down
8 changes: 5 additions & 3 deletions src/api/api.flow.js
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,8 @@ extend(ChartInternal.prototype, {
]);

gt.call(wait, () => {
const isRotated = config.axis_rotated;

// remove flowed elements
if (flowLength) {
const target = {
Expand Down Expand Up @@ -372,11 +374,11 @@ extend(ChartInternal.prototype, {
.attr("transform", null);

xgridLines.select("line")
.attr("x1", config.axis_rotated ? 0 : xv)
.attr("x2", config.axis_rotated ? $$.width : xv);
.attr("x1", isRotated ? 0 : xv)
.attr("x2", isRotated ? $$.width : xv);

xgridLines.select("text")
.attr("x", config.axis_rotated ? $$.width : 0)
.attr("x", isRotated ? $$.width : 0)
.attr("y", xv);

mainBar
Expand Down
65 changes: 25 additions & 40 deletions src/data/data.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,16 +191,9 @@ extend(ChartInternal.prototype, {
};
},

updateXs() {
const $$ = this;
const targets = $$.data.targets;

if (targets.length) {
$$.xs = [];

targets[0].values.forEach(v => {
$$.xs[v.index] = v.x;
});
updateXs(values) {
if (values.length) {
this.xs = values.map(v => v.x);
}
},

Expand Down Expand Up @@ -365,23 +358,22 @@ extend(ChartInternal.prototype, {
return Math.max(...this.data.targets.map(t => t.values.length));
},

getMaxDataCountTarget(targets) {
const length = targets.length;
let max = 0;
let maxTarget;
getMaxDataCountTarget() {
let target = this.filterTargetsToShow() || [];
const length = target.length;

if (length > 1) {
targets.forEach(t => {
if (t.values.length > max) {
maxTarget = t;
max = t.values.length;
}
});
} else {
maxTarget = length ? targets[0] : null;
target = target.map(t => t.values)
.reduce((a, b) => a.concat(b))
.map(v => v.x);

target = sortValue(getUnique(target))
.map((x, index) => ({x, index}));
} else if (length) {
target = target[0].values;
}

return maxTarget;
return target;
},

mapToIds(targets) {
Expand Down Expand Up @@ -842,29 +834,22 @@ extend(ChartInternal.prototype, {

/**
* Sort data index to be aligned with x axis.
* @param {Array} tickValues Tick array values
* @private
*/
updateDataIndexByX() {
updateDataIndexByX(tickValues) {
const $$ = this;
const isTimeSeries = $$.isTimeSeries();
const tickValues = $$.flowing ?
$$.getMaxDataCountTarget($$.data.targets).values.map(v => v.x) :
($$.axis.getTickValues("x") || []);

$$.data.targets.forEach(t => {
t.values.forEach((v, i) => {
if (isTimeSeries) {
tickValues.some((d, j) => {
if (+d === +v.x) {
v.index = j;
return true;
}

return false;
});
} else {
v.index = tickValues.indexOf(v.x);
}
tickValues.some((d, j) => {
if (+d.x === +v.x) {
v.index = j;
return true;
}

return false;
});

if (!isNumber(v.index) || v.index === -1) {
v.index = i;
Expand Down
12 changes: 5 additions & 7 deletions src/interactions/interaction.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,12 @@ extend(ChartInternal.prototype, {
.merge(eventRectUpdate);
} else {
// Set data and update $$.eventRect
let xAxisTickValues = $$.axis.getTickValues("x");
const xAxisTickValues = $$.getMaxDataCountTarget();

xAxisTickValues = ($$.flowing || !xAxisTickValues || config.axis_x_tick_count) ?
$$.getMaxDataCountTarget($$.data.targets).values :
xAxisTickValues.map((x, index) => ({x, index}));
// update data's index value to be alinged with the x Axis
$$.updateDataIndexByX(xAxisTickValues);
$$.updateXs(xAxisTickValues);
$$.updatePointClass(true);

eventRects.datum(xAxisTickValues);

Expand Down Expand Up @@ -211,9 +212,6 @@ extend(ChartInternal.prototype, {
rectW = $$.getEventRectWidth();
rectX = d => xScale(d.x) - (rectW / 2);
} else {
// update index for x that is used by prevX and nextX
$$.updateXs();

const getPrevNextX = d => {
const index = d.index;

Expand Down
3 changes: 0 additions & 3 deletions src/internals/ChartInternal.js
Original file line number Diff line number Diff line change
Expand Up @@ -631,9 +631,6 @@ export default class ChartInternal {
// @TODO: Make 'init' state to be accessible everywhere not passing as argument.
$$.axis.redrawAxis(targetsToShow, wth, transitions, flow, initializing);

// update data's index value to be alinged with the x Axis
$$.updateDataIndexByX();

// update circleY based on updated parameters
$$.updateCircleY();

Expand Down
8 changes: 7 additions & 1 deletion src/internals/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,13 @@ const getCssRules = styleSheets => {
* @return {Array} Unique array value
* @private
*/
const getUnique = data => data.filter((v, i, self) => self.indexOf(v) === i);
const getUnique = data => {
const isDate = data[0] instanceof Date;
const d = (isDate ? data.map(Number) : data)
.filter((v, i, self) => self.indexOf(v) === i);

return isDate ? d.map(v => new Date(v)) : d;
};

/**
* Merge array
Expand Down
4 changes: 2 additions & 2 deletions src/shape/line.js
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,7 @@ extend(ChartInternal.prototype, {
$$.mainCircle.exit().remove();

$$.mainCircle = $$.mainCircle.enter()
.append($$.point("create", this, $$.classCircle.bind($$), $$.pointR.bind($$), $$.color))
.append($$.point("create", this, $$.pointR.bind($$), $$.color))
.merge($$.mainCircle)
.style("stroke", $$.color)
.style("opacity", $$.initialOpacityForCircle.bind($$));
Expand All @@ -561,7 +561,7 @@ extend(ChartInternal.prototype, {
const result = fn(d);

mainCircles.push(result);
}).attr("class", $$.classCircle.bind($$));
});

const posAttr = $$.isCirclePoint() ? "c" : "";

Expand Down
Loading

0 comments on commit dc5f67a

Please sign in to comment.