mirror of https://github.com/vitalif/dimple
Stepped Interpolation Implementation
parent
41955de85c
commit
1b1b8231c9
|
@ -2643,6 +2643,11 @@ var dimple = {
|
||||||
basePoints,
|
basePoints,
|
||||||
basePoint,
|
basePoint,
|
||||||
cat,
|
cat,
|
||||||
|
catVal,
|
||||||
|
group,
|
||||||
|
p,
|
||||||
|
b,
|
||||||
|
l,
|
||||||
lastAngle,
|
lastAngle,
|
||||||
catCoord,
|
catCoord,
|
||||||
valCoord,
|
valCoord,
|
||||||
|
@ -2680,6 +2685,9 @@ var dimple = {
|
||||||
.y(function (d) { return (series.y._hasCategories() || !originProperty ? d.y : series.y[originProperty]); })
|
.y(function (d) { return (series.y._hasCategories() || !originProperty ? d.y : series.y[originProperty]); })
|
||||||
.interpolate(inter);
|
.interpolate(inter);
|
||||||
},
|
},
|
||||||
|
sortByVal = function (a, b) {
|
||||||
|
return parseFloat(a) - parseFloat(b);
|
||||||
|
},
|
||||||
sortByX = function (a, b) {
|
sortByX = function (a, b) {
|
||||||
return parseFloat(a.x) - parseFloat(b.x);
|
return parseFloat(a.x) - parseFloat(b.x);
|
||||||
},
|
},
|
||||||
|
@ -2750,7 +2758,9 @@ var dimple = {
|
||||||
points: [],
|
points: [],
|
||||||
area: {},
|
area: {},
|
||||||
entry: {},
|
entry: {},
|
||||||
exit: {}
|
exit: {},
|
||||||
|
// Group refers to groupings along the category axis. If there are groupings it will be recorded, otherwise all is used as a default
|
||||||
|
group: (catCoord && data[i][catCoord + "Field"] && data[i][catCoord + "Field"].length >= 2 ? data[i][catCoord + "Field"][0] : "All")
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Add this row to the relevant data
|
// Add this row to the relevant data
|
||||||
|
@ -2779,7 +2789,32 @@ var dimple = {
|
||||||
// if there is a category axis, add the points to a distinct set. Set these to use the origin value
|
// if there is a category axis, add the points to a distinct set. Set these to use the origin value
|
||||||
// this will be updated with the last value in each case as we build the areas
|
// this will be updated with the last value in each case as we build the areas
|
||||||
if (catCoord) {
|
if (catCoord) {
|
||||||
catPoints[areaData[i].points[areaData[i].points.length - 1][catCoord]] = series[valCoord]._previousOrigin;
|
if (!catPoints[areaData[i].group]) {
|
||||||
|
catPoints[areaData[i].group] = {};
|
||||||
|
}
|
||||||
|
catPoints[areaData[i].group][areaData[i].points[areaData[i].points.length - 1][catCoord]] = series[valCoord]._previousOrigin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
points = areaData[i].points;
|
||||||
|
// If this is a step interpolation we need to add in some extra points to the category axis
|
||||||
|
// This is a little tricky but we need to add a new point duplicating the last category value. In order
|
||||||
|
// to place the point we need to calculate the gap between the last x and the penultimate x and apply that
|
||||||
|
// gap again.
|
||||||
|
if (series.interpolation === "step" && points.length > 1 && catCoord) {
|
||||||
|
if (series.x._hasCategories()) {
|
||||||
|
points.push({
|
||||||
|
x : 2 * points[points.length - 1].x - points[points.length - 2].x,
|
||||||
|
y : points[points.length - 1].y
|
||||||
|
});
|
||||||
|
catPoints[areaData[i].group][points[points.length - 1][catCoord]] = series[valCoord]._previousOrigin;
|
||||||
|
} else if (series.y._hasCategories()) {
|
||||||
|
points = [{
|
||||||
|
x : points[0].x,
|
||||||
|
y : 2 * points[0].y - points[1].y
|
||||||
|
}].concat(points);
|
||||||
|
catPoints[areaData[i].group][points[0][catCoord]] = series[valCoord]._previousOrigin;
|
||||||
|
// The prepend above breaks the reference so it needs to be reapplied here.
|
||||||
|
areaData[i].points = points;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2787,47 +2822,54 @@ var dimple = {
|
||||||
// catPoints needs to be lookup, but also accessed sequentially so we need to create an array of keys
|
// catPoints needs to be lookup, but also accessed sequentially so we need to create an array of keys
|
||||||
for (cat in catPoints) {
|
for (cat in catPoints) {
|
||||||
if (catPoints.hasOwnProperty(cat)) {
|
if (catPoints.hasOwnProperty(cat)) {
|
||||||
allPoints.push(parseFloat(cat));
|
allPoints[cat] = [];
|
||||||
|
for (catVal in catPoints[cat]) {
|
||||||
|
if (catPoints[cat].hasOwnProperty(catVal)) {
|
||||||
|
allPoints[cat].push(parseFloat(catVal));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Sort the points as integers
|
||||||
|
allPoints[cat].sort(sortByVal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Sort the points as integers
|
|
||||||
allPoints.sort(function (a, b) { return parseFloat(a) - parseFloat(b); });
|
|
||||||
|
|
||||||
// Create the areas
|
// Create the areas
|
||||||
for (i = 0; i < areaData.length; i += 1) {
|
for (i = 0; i < areaData.length; i += 1) {
|
||||||
points = areaData[i].points;
|
points = areaData[i].points;
|
||||||
|
group = areaData[i].group;
|
||||||
basePoints = [];
|
basePoints = [];
|
||||||
finalPointArray = [];
|
finalPointArray = [];
|
||||||
// If this should have colour gradients, add them
|
// If this should have colour gradients, add them
|
||||||
if (graded) {
|
if (graded) {
|
||||||
dimple._addGradient(areaData[i].key, "fill-area-gradient-" + areaData[i].keyString, (series.x._hasCategories() ? series.x : series.y), data, chart, duration, "fill");
|
dimple._addGradient(areaData[i].key, "fill-area-gradient-" + areaData[i].keyString, (series.x._hasCategories() ? series.x : series.y), data, chart, duration, "fill");
|
||||||
}
|
}
|
||||||
|
|
||||||
// All points will only be populated if there is a category axis
|
// All points will only be populated if there is a category axis
|
||||||
if (allPoints && allPoints.length > 0) {
|
if (allPoints[group] && allPoints[group].length > 0) {
|
||||||
// Iterate the point array because we need to fill in zero points for missing ones, otherwise the areas
|
// Iterate the point array because we need to fill in zero points for missing ones, otherwise the areas
|
||||||
// will cross where an upper area has no value and a lower value has a spike Issue #7
|
// will cross where an upper area has no value and a lower value has a spike Issue #7
|
||||||
for (j = 0, k = 0; j < allPoints.length; j += 1) {
|
for (j = 0, k = 0; j < allPoints[group].length; j += 1) {
|
||||||
// We are only interested in points between the first and last point of this areas data (i.e. don't fill ends - important
|
// We are only interested in points between the first and last point of this areas data (i.e. don't fill ends - important
|
||||||
// for grouped area charts)
|
// for grouped area charts). We have to use a strange criteria here. If there are no group gaps on a grouped area
|
||||||
if (allPoints[j] >= points[0][catCoord] && allPoints[j] <= points[points.length - 1][catCoord]) {
|
// chart the end point of one series will clash with the start point of another, therefore we have to ignore fill-in's within
|
||||||
|
// a couple of pixels of the start and end points
|
||||||
|
if (allPoints[group][j] >= points[0][catCoord] && allPoints[group][j] <= points[points.length - 1][catCoord]) {
|
||||||
// Get a base point, this needs to go on the base points array as well as filling in gaps in the point array.
|
// Get a base point, this needs to go on the base points array as well as filling in gaps in the point array.
|
||||||
// Create a point using the coordinate on the category axis and the last recorded value
|
// Create a point using the coordinate on the category axis and the last recorded value
|
||||||
// position from the dictionary
|
// position from the dictionary
|
||||||
basePoint = {};
|
basePoint = {};
|
||||||
basePoint[catCoord] = allPoints[j];
|
basePoint[catCoord] = allPoints[group][j];
|
||||||
basePoint[valCoord] = catPoints[allPoints[j]];
|
basePoint[valCoord] = catPoints[group][allPoints[group][j]];
|
||||||
// add the base point
|
// add the base point
|
||||||
basePoints.push(basePoint);
|
basePoints.push(basePoint);
|
||||||
// handle missing points
|
// handle missing points
|
||||||
if (points[k][catCoord] > allPoints[j]) {
|
if (points[k][catCoord] > allPoints[group][j]) {
|
||||||
// If there is a missing point we need to in fill
|
// If there is a missing point we need to in fill
|
||||||
finalPointArray.push(basePoint);
|
finalPointArray.push(basePoint);
|
||||||
} else {
|
} else {
|
||||||
// They must be the same
|
// They must be the same
|
||||||
finalPointArray.push(points[k]);
|
finalPointArray.push(points[k]);
|
||||||
// Use this to update the dictionary to the new value coordinate
|
// Use this to update the dictionary to the new value coordinate
|
||||||
catPoints[allPoints[j]] = points[k][valCoord];
|
catPoints[areaData[i].group][allPoints[group][j]] = points[k][valCoord];
|
||||||
k += 1;
|
k += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2863,88 +2905,30 @@ var dimple = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The final array of points for the entire outskirts of the area
|
// Reverse the base points so that they are in the correct order for the path
|
||||||
finalPointArray = finalPointArray.concat(basePoints.reverse()).concat(finalPointArray[0]);
|
basePoints = basePoints.reverse();
|
||||||
|
|
||||||
// Get the points that this area will appear
|
// Get the points that this area will appear
|
||||||
areaData[i].entry = getArea(interpolation, "_previousOrigin")(finalPointArray);
|
p = getArea(interpolation, "_previousOrigin")(finalPointArray);
|
||||||
areaData[i].update = getArea(interpolation)(finalPointArray);
|
b = getArea((interpolation === "step-after" ? "step-before" : (interpolation === "step-before" ? "step-after" : interpolation)), "_previousOrigin")(basePoints);
|
||||||
areaData[i].exit = getArea(interpolation, "_origin")(finalPointArray);
|
l = getArea("linear", "_previousOrigin")(finalPointArray);
|
||||||
|
areaData[i].entry = p + "L" + b.substring(1) + "L" + l.substring(1, l.indexOf("L"));
|
||||||
|
|
||||||
|
p = getArea(interpolation)(finalPointArray);
|
||||||
|
b = getArea(interpolation === "step-after" ? "step-before" : (interpolation === "step-before" ? "step-after" : interpolation))(basePoints);
|
||||||
|
l = getArea("linear")(finalPointArray);
|
||||||
|
areaData[i].update = p + "L" + b.substring(1) + "L" + l.substring(1, l.indexOf("L"));
|
||||||
|
|
||||||
|
p = getArea(interpolation, "_origin")(finalPointArray);
|
||||||
|
b = getArea((interpolation === "step-after" ? "step-before" : (interpolation === "step-before" ? "step-after" : interpolation)), "_origin")(basePoints);
|
||||||
|
l = getArea("linear", "_origin")(finalPointArray);
|
||||||
|
areaData[i].exit = p + "L" + b.substring(1) + "L" + l.substring(1, l.indexOf("L"));
|
||||||
|
|
||||||
// Add the color in this loop, it can't be done during initialisation of the row because
|
// Add the color in this loop, it can't be done during initialisation of the row because
|
||||||
// the areas should be ordered first (to ensure standard distribution of colors
|
// the areas should be ordered first (to ensure standard distribution of colors
|
||||||
areaData[i].color = chart.getColor(areaData[i].key.length > 0 ? areaData[i].key[areaData[i].key.length - 1] : "All");
|
areaData[i].color = chart.getColor(areaData[i].key.length > 0 ? areaData[i].key[areaData[i].key.length - 1] : "All");
|
||||||
|
|
||||||
}
|
}
|
||||||
// // Create a set of area data grouped by the aggregation field
|
|
||||||
// for (i = 0; i < areaData.length; i += 1) {
|
|
||||||
//
|
|
||||||
// // Sort the points so that areas are connected in the correct order
|
|
||||||
// areaData[i].data.sort(dimple._getSeriesSortPredicate(chart, series, orderedSeriesArray));
|
|
||||||
//
|
|
||||||
// // If this should have colour gradients, add them
|
|
||||||
// if (graded) {
|
|
||||||
// dimple._addGradient(areaData[i].key, "fill-area-gradient-" + areaData[i].keyString, (series.x._hasCategories() ? series.x : series.y), data, chart, duration, "fill");
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Clone the data before adding elements
|
|
||||||
// dataClone = [].concat(areaData[i].data);
|
|
||||||
//
|
|
||||||
// // If this is a custom dimple step area duplicate the last datum so that the final step is completed
|
|
||||||
// if (series.interpolation === "step") {
|
|
||||||
// if (series.x._hasCategories()) {
|
|
||||||
// // Clone the last row and duplicate it.
|
|
||||||
// dataClone = dataClone.concat(JSON.parse(JSON.stringify(dataClone[dataClone.length - 1])));
|
|
||||||
// dataClone[dataClone.length - 1].cx = "";
|
|
||||||
// dataClone[dataClone.length - 1].x = "";
|
|
||||||
// }
|
|
||||||
// if (series.y._hasCategories()) {
|
|
||||||
// // Clone the last row and duplicate it.
|
|
||||||
// dataClone = [JSON.parse(JSON.stringify(dataClone[0]))].concat(dataClone);
|
|
||||||
// dataClone[0].cy = "";
|
|
||||||
// dataClone[0].y = "";
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Add zero baseline for this row
|
|
||||||
// if (series.x._hasCategories() && series.y._hasMeasure()) {
|
|
||||||
// for (j = dataClone.length - 1; j >= 0; j -= 1) {
|
|
||||||
// areaData[i].baseData.push({
|
|
||||||
// x : dataClone[j].x,
|
|
||||||
// cx : dataClone[j].cx,
|
|
||||||
// xOffset : dataClone[j].xOffset,
|
|
||||||
// width : dataClone[j].width,
|
|
||||||
// y: (i === 0 ? 0 : areaData[i - 1].data[j].y),
|
|
||||||
// cy : (i === 0 ? 0 : areaData[i - 1].data[j].cy),
|
|
||||||
// yOffset: (i === 0 ? 0 : areaData[i - 1].data[j].yOffset),
|
|
||||||
// height: (i === 0 ? 0 : areaData[i - 1].data[j].height)
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// } else if (series.y._hasCategories() && series.x._hasMeasure()) {
|
|
||||||
// for (j = dataClone.length - 1; j >= 0; j -= 1) {
|
|
||||||
// areaData[i].baseData.push({
|
|
||||||
// x : (i === 0 ? 0 : areaData[i - 1].data[j].x),
|
|
||||||
// cx : (i === 0 ? 0 : areaData[i - 1].data[j].cx),
|
|
||||||
// xOffset : (i === 0 ? 0 : areaData[i - 1].data[j].xOffset),
|
|
||||||
// width : (i === 0 ? 0 : areaData[i - 1].data[j].width),
|
|
||||||
// y: dataClone[j].y,
|
|
||||||
// cy : dataClone[j].cy,
|
|
||||||
// yOffset: dataClone[j].yOffset,
|
|
||||||
// height: dataClone[j].height
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Get the points that this area will appear
|
|
||||||
// areaData[i].entry = getArea(interpolation, "_previousOrigin")(areaData[i].baseData.concat(dataClone));
|
|
||||||
// areaData[i].update = getArea(interpolation)(areaData[i].baseData.concat(dataClone));
|
|
||||||
// areaData[i].exit = getArea(interpolation, "_origin")(areaData[i].baseData.concat(dataClone));
|
|
||||||
//
|
|
||||||
// // Add the color in this loop, it can't be done during initialisation of the row because
|
|
||||||
// // the areas should be ordered first (to ensure standard distribution of colors
|
|
||||||
// areaData[i].color = chart.getColor(areaData[i].key.length > 0 ? areaData[i].key[areaData[i].key.length - 1] : "All");
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (chart._tooltipGroup !== null && chart._tooltipGroup !== undefined) {
|
if (chart._tooltipGroup !== null && chart._tooltipGroup !== undefined) {
|
||||||
chart._tooltipGroup.remove();
|
chart._tooltipGroup.remove();
|
||||||
|
@ -2971,13 +2955,12 @@ var dimple = {
|
||||||
// Apply formats optionally
|
// Apply formats optionally
|
||||||
if (!chart.noFormats) {
|
if (!chart.noFormats) {
|
||||||
this.attr("opacity", function (d) { return (graded ? 1 : d.color.opacity); })
|
this.attr("opacity", function (d) { return (graded ? 1 : d.color.opacity); })
|
||||||
.attr("fill", function (d) { return (graded ? "url(#fill-line-gradient-" + d.keyString + ")" : d.color.fill); })
|
.attr("fill", function (d) { return (graded ? "url(#fill-area-gradient-" + d.keyString + ")" : d.color.fill); })
|
||||||
.attr("stroke", function (d) { return (graded ? "url(#stroke-line-gradient-" + d.keyString + ")" : d.color.stroke); })
|
.attr("stroke", function (d) { return (graded ? "url(#stroke-area-gradient-" + d.keyString + ")" : d.color.stroke); })
|
||||||
.attr("stroke-width", series.lineWeight);
|
.attr("stroke-width", series.lineWeight);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.each(drawMarkers);
|
.each(drawMarkers);
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
updated = dimple._handleTransition(theseShapes, duration)
|
updated = dimple._handleTransition(theseShapes, duration)
|
||||||
.attr("d", function (d) { return d.update; })
|
.attr("d", function (d) { return d.update; })
|
||||||
|
@ -3222,6 +3205,7 @@ var dimple = {
|
||||||
interpolation,
|
interpolation,
|
||||||
graded = false,
|
graded = false,
|
||||||
i,
|
i,
|
||||||
|
j,
|
||||||
k,
|
k,
|
||||||
key,
|
key,
|
||||||
keyString,
|
keyString,
|
||||||
|
@ -3229,7 +3213,6 @@ var dimple = {
|
||||||
updated,
|
updated,
|
||||||
removed,
|
removed,
|
||||||
orderedSeriesArray,
|
orderedSeriesArray,
|
||||||
dataClone,
|
|
||||||
onEnter = function () {
|
onEnter = function () {
|
||||||
return function (e, shape, chart, series) {
|
return function (e, shape, chart, series) {
|
||||||
d3.select(shape).style("opacity", 1);
|
d3.select(shape).style("opacity", 1);
|
||||||
|
@ -3254,14 +3237,33 @@ var dimple = {
|
||||||
} else {
|
} else {
|
||||||
val = dimple._helpers["c" + position](datum, chart, series);
|
val = dimple._helpers["c" + position](datum, chart, series);
|
||||||
}
|
}
|
||||||
return val;
|
// Remove long decimals from the coordinates as this fills the dom up with noise and makes matching below less likely to work. It
|
||||||
|
// shouldn't really matter but positioning to < 0.1 pixel is pretty pointless anyway.
|
||||||
|
return parseFloat(val.toFixed(1));
|
||||||
},
|
},
|
||||||
getLine = function (inter, originProperty) {
|
getLine = function (inter, originProperty) {
|
||||||
return d3.svg.line()
|
return d3.svg.line()
|
||||||
.x(function (d) { return (series.x._hasCategories() || !originProperty ? coord("x", d) : series.x[originProperty]); })
|
.x(function (d) { return (series.x._hasCategories() || !originProperty ? d.x : series.x[originProperty]); })
|
||||||
.y(function (d) { return (series.y._hasCategories() || !originProperty ? coord("y", d) : series.y[originProperty]); })
|
.y(function (d) { return (series.y._hasCategories() || !originProperty ? d.y : series.y[originProperty]); })
|
||||||
.interpolate(inter);
|
.interpolate(inter);
|
||||||
};
|
};
|
||||||
|
// coord = function (position, datum) {
|
||||||
|
// var val;
|
||||||
|
// if (series.interpolation === "step" && series[position]._hasCategories()) {
|
||||||
|
// series.barGap = 0;
|
||||||
|
// series.clusterBarGap = 0;
|
||||||
|
// val = dimple._helpers[position](datum, chart, series) + (position === "y" ? dimple._helpers.height(datum, chart, series) : 0);
|
||||||
|
// } else {
|
||||||
|
// val = dimple._helpers["c" + position](datum, chart, series);
|
||||||
|
// }
|
||||||
|
// return parseFloat(val).toFixed(1);
|
||||||
|
// },
|
||||||
|
// getLine = function (inter, originProperty) {
|
||||||
|
// return d3.svg.line()
|
||||||
|
// .x(function (d) { return (series.x._hasCategories() || !originProperty ? coord("x", d) : series.x[originProperty]); })
|
||||||
|
// .y(function (d) { return (series.y._hasCategories() || !originProperty ? coord("y", d) : series.y[originProperty]); })
|
||||||
|
// .interpolate(inter);
|
||||||
|
// };
|
||||||
|
|
||||||
// Handle the special interpolation handling for step
|
// Handle the special interpolation handling for step
|
||||||
interpolation = (series.interpolation === "step" ? "step-after" : series.interpolation);
|
interpolation = (series.interpolation === "step" ? "step-after" : series.interpolation);
|
||||||
|
@ -3297,8 +3299,10 @@ var dimple = {
|
||||||
keyString: keyString,
|
keyString: keyString,
|
||||||
color: "white",
|
color: "white",
|
||||||
data: [],
|
data: [],
|
||||||
|
points: [],
|
||||||
line: {},
|
line: {},
|
||||||
entryExit: {}
|
entry: {},
|
||||||
|
exit: {}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Add this row to the relevant data
|
// Add this row to the relevant data
|
||||||
|
@ -3321,28 +3325,55 @@ var dimple = {
|
||||||
if (graded) {
|
if (graded) {
|
||||||
dimple._addGradient(lineData[i].key, "fill-line-gradient-" + lineData[i].keyString, (series.x._hasCategories() ? series.x : series.y), data, chart, duration, "fill");
|
dimple._addGradient(lineData[i].key, "fill-line-gradient-" + lineData[i].keyString, (series.x._hasCategories() ? series.x : series.y), data, chart, duration, "fill");
|
||||||
}
|
}
|
||||||
// Clone the data before adding elements
|
|
||||||
dataClone = [].concat(lineData[i].data);
|
// Get points here, this is so that as well as drawing the line with them, we can also
|
||||||
// If this is a custom dimple step line duplicate the last datum so that the final step is completed
|
// use them for the baseline
|
||||||
if (series.interpolation === "step") {
|
for (j = 0; j < lineData[i].data.length; j += 1) {
|
||||||
|
lineData[i].points.push({
|
||||||
|
x: coord("x", lineData[i].data[j]),
|
||||||
|
y: coord("y", lineData[i].data[j])
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// If this is a step interpolation we need to add in some extra points to the category axis
|
||||||
|
// This is a little tricky but we need to add a new point duplicating the last category value. In order
|
||||||
|
// to place the point we need to calculate the gap between the last x and the penultimate x and apply that
|
||||||
|
// gap again.
|
||||||
|
if (series.interpolation === "step" && lineData[i].points.length > 1) {
|
||||||
if (series.x._hasCategories()) {
|
if (series.x._hasCategories()) {
|
||||||
// Clone the last row and duplicate it.
|
lineData[i].points.push({
|
||||||
dataClone = dataClone.concat(JSON.parse(JSON.stringify(dataClone[dataClone.length - 1])));
|
x : 2 * lineData[i].points[lineData[i].points.length - 1].x - lineData[i].points[lineData[i].points.length - 2].x,
|
||||||
dataClone[dataClone.length - 1].cx = "";
|
y : lineData[i].points[lineData[i].points.length - 1].y
|
||||||
dataClone[dataClone.length - 1].x = "";
|
});
|
||||||
}
|
} else if (series.y._hasCategories()) {
|
||||||
if (series.y._hasCategories()) {
|
lineData[i].points = [{
|
||||||
// Clone the last row and duplicate it.
|
x : lineData[i].points[0].x,
|
||||||
dataClone = [JSON.parse(JSON.stringify(dataClone[0]))].concat(dataClone);
|
y : 2 * lineData[i].points[0].y - lineData[i].points[1].y
|
||||||
dataClone[0].cy = "";
|
}].concat(lineData[i].points);
|
||||||
dataClone[0].y = "";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// // Clone the data before adding elements
|
||||||
|
// dataClone = [].concat(lineData[i].data);
|
||||||
|
// // If this is a custom dimple step line duplicate the last datum so that the final step is completed
|
||||||
|
// if (series.interpolation === "step") {
|
||||||
|
// if (series.x._hasCategories()) {
|
||||||
|
// // Clone the last row and duplicate it.
|
||||||
|
// dataClone = dataClone.concat(JSON.parse(JSON.stringify(dataClone[dataClone.length - 1])));
|
||||||
|
// dataClone[dataClone.length - 1].cx = "";
|
||||||
|
// dataClone[dataClone.length - 1].x = "";
|
||||||
|
// }
|
||||||
|
// if (series.y._hasCategories()) {
|
||||||
|
// // Clone the last row and duplicate it.
|
||||||
|
// dataClone = [JSON.parse(JSON.stringify(dataClone[0]))].concat(dataClone);
|
||||||
|
// dataClone[0].cy = "";
|
||||||
|
// dataClone[0].y = "";
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
// Get the points that this line will appear
|
// Get the points that this line will appear
|
||||||
lineData[i].entry = getLine(interpolation, "_previousOrigin")(dataClone);
|
lineData[i].entry = getLine(interpolation, "_previousOrigin")(lineData[i].points);
|
||||||
lineData[i].update = getLine(interpolation)(dataClone);
|
lineData[i].update = getLine(interpolation)(lineData[i].points);
|
||||||
lineData[i].exit = getLine(interpolation, "_origin")(dataClone);
|
lineData[i].exit = getLine(interpolation, "_origin")(lineData[i].points);
|
||||||
|
|
||||||
// Add the color in this loop, it can't be done during initialisation of the row because
|
// Add the color in this loop, it can't be done during initialisation of the row because
|
||||||
// the lines should be ordered first (to ensure standard distribution of colors
|
// the lines should be ordered first (to ensure standard distribution of colors
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -35,6 +35,11 @@
|
||||||
basePoints,
|
basePoints,
|
||||||
basePoint,
|
basePoint,
|
||||||
cat,
|
cat,
|
||||||
|
catVal,
|
||||||
|
group,
|
||||||
|
p,
|
||||||
|
b,
|
||||||
|
l,
|
||||||
lastAngle,
|
lastAngle,
|
||||||
catCoord,
|
catCoord,
|
||||||
valCoord,
|
valCoord,
|
||||||
|
@ -72,6 +77,9 @@
|
||||||
.y(function (d) { return (series.y._hasCategories() || !originProperty ? d.y : series.y[originProperty]); })
|
.y(function (d) { return (series.y._hasCategories() || !originProperty ? d.y : series.y[originProperty]); })
|
||||||
.interpolate(inter);
|
.interpolate(inter);
|
||||||
},
|
},
|
||||||
|
sortByVal = function (a, b) {
|
||||||
|
return parseFloat(a) - parseFloat(b);
|
||||||
|
},
|
||||||
sortByX = function (a, b) {
|
sortByX = function (a, b) {
|
||||||
return parseFloat(a.x) - parseFloat(b.x);
|
return parseFloat(a.x) - parseFloat(b.x);
|
||||||
},
|
},
|
||||||
|
@ -142,7 +150,9 @@
|
||||||
points: [],
|
points: [],
|
||||||
area: {},
|
area: {},
|
||||||
entry: {},
|
entry: {},
|
||||||
exit: {}
|
exit: {},
|
||||||
|
// Group refers to groupings along the category axis. If there are groupings it will be recorded, otherwise all is used as a default
|
||||||
|
group: (catCoord && data[i][catCoord + "Field"] && data[i][catCoord + "Field"].length >= 2 ? data[i][catCoord + "Field"][0] : "All")
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Add this row to the relevant data
|
// Add this row to the relevant data
|
||||||
|
@ -171,7 +181,32 @@
|
||||||
// if there is a category axis, add the points to a distinct set. Set these to use the origin value
|
// if there is a category axis, add the points to a distinct set. Set these to use the origin value
|
||||||
// this will be updated with the last value in each case as we build the areas
|
// this will be updated with the last value in each case as we build the areas
|
||||||
if (catCoord) {
|
if (catCoord) {
|
||||||
catPoints[areaData[i].points[areaData[i].points.length - 1][catCoord]] = series[valCoord]._previousOrigin;
|
if (!catPoints[areaData[i].group]) {
|
||||||
|
catPoints[areaData[i].group] = {};
|
||||||
|
}
|
||||||
|
catPoints[areaData[i].group][areaData[i].points[areaData[i].points.length - 1][catCoord]] = series[valCoord]._previousOrigin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
points = areaData[i].points;
|
||||||
|
// If this is a step interpolation we need to add in some extra points to the category axis
|
||||||
|
// This is a little tricky but we need to add a new point duplicating the last category value. In order
|
||||||
|
// to place the point we need to calculate the gap between the last x and the penultimate x and apply that
|
||||||
|
// gap again.
|
||||||
|
if (series.interpolation === "step" && points.length > 1 && catCoord) {
|
||||||
|
if (series.x._hasCategories()) {
|
||||||
|
points.push({
|
||||||
|
x : 2 * points[points.length - 1].x - points[points.length - 2].x,
|
||||||
|
y : points[points.length - 1].y
|
||||||
|
});
|
||||||
|
catPoints[areaData[i].group][points[points.length - 1][catCoord]] = series[valCoord]._previousOrigin;
|
||||||
|
} else if (series.y._hasCategories()) {
|
||||||
|
points = [{
|
||||||
|
x : points[0].x,
|
||||||
|
y : 2 * points[0].y - points[1].y
|
||||||
|
}].concat(points);
|
||||||
|
catPoints[areaData[i].group][points[0][catCoord]] = series[valCoord]._previousOrigin;
|
||||||
|
// The prepend above breaks the reference so it needs to be reapplied here.
|
||||||
|
areaData[i].points = points;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -179,47 +214,54 @@
|
||||||
// catPoints needs to be lookup, but also accessed sequentially so we need to create an array of keys
|
// catPoints needs to be lookup, but also accessed sequentially so we need to create an array of keys
|
||||||
for (cat in catPoints) {
|
for (cat in catPoints) {
|
||||||
if (catPoints.hasOwnProperty(cat)) {
|
if (catPoints.hasOwnProperty(cat)) {
|
||||||
allPoints.push(parseFloat(cat));
|
allPoints[cat] = [];
|
||||||
|
for (catVal in catPoints[cat]) {
|
||||||
|
if (catPoints[cat].hasOwnProperty(catVal)) {
|
||||||
|
allPoints[cat].push(parseFloat(catVal));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Sort the points as integers
|
||||||
|
allPoints[cat].sort(sortByVal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Sort the points as integers
|
|
||||||
allPoints.sort(function (a, b) { return parseFloat(a) - parseFloat(b); });
|
|
||||||
|
|
||||||
// Create the areas
|
// Create the areas
|
||||||
for (i = 0; i < areaData.length; i += 1) {
|
for (i = 0; i < areaData.length; i += 1) {
|
||||||
points = areaData[i].points;
|
points = areaData[i].points;
|
||||||
|
group = areaData[i].group;
|
||||||
basePoints = [];
|
basePoints = [];
|
||||||
finalPointArray = [];
|
finalPointArray = [];
|
||||||
// If this should have colour gradients, add them
|
// If this should have colour gradients, add them
|
||||||
if (graded) {
|
if (graded) {
|
||||||
dimple._addGradient(areaData[i].key, "fill-area-gradient-" + areaData[i].keyString, (series.x._hasCategories() ? series.x : series.y), data, chart, duration, "fill");
|
dimple._addGradient(areaData[i].key, "fill-area-gradient-" + areaData[i].keyString, (series.x._hasCategories() ? series.x : series.y), data, chart, duration, "fill");
|
||||||
}
|
}
|
||||||
|
|
||||||
// All points will only be populated if there is a category axis
|
// All points will only be populated if there is a category axis
|
||||||
if (allPoints && allPoints.length > 0) {
|
if (allPoints[group] && allPoints[group].length > 0) {
|
||||||
// Iterate the point array because we need to fill in zero points for missing ones, otherwise the areas
|
// Iterate the point array because we need to fill in zero points for missing ones, otherwise the areas
|
||||||
// will cross where an upper area has no value and a lower value has a spike Issue #7
|
// will cross where an upper area has no value and a lower value has a spike Issue #7
|
||||||
for (j = 0, k = 0; j < allPoints.length; j += 1) {
|
for (j = 0, k = 0; j < allPoints[group].length; j += 1) {
|
||||||
// We are only interested in points between the first and last point of this areas data (i.e. don't fill ends - important
|
// We are only interested in points between the first and last point of this areas data (i.e. don't fill ends - important
|
||||||
// for grouped area charts)
|
// for grouped area charts). We have to use a strange criteria here. If there are no group gaps on a grouped area
|
||||||
if (allPoints[j] >= points[0][catCoord] && allPoints[j] <= points[points.length - 1][catCoord]) {
|
// chart the end point of one series will clash with the start point of another, therefore we have to ignore fill-in's within
|
||||||
|
// a couple of pixels of the start and end points
|
||||||
|
if (allPoints[group][j] >= points[0][catCoord] && allPoints[group][j] <= points[points.length - 1][catCoord]) {
|
||||||
// Get a base point, this needs to go on the base points array as well as filling in gaps in the point array.
|
// Get a base point, this needs to go on the base points array as well as filling in gaps in the point array.
|
||||||
// Create a point using the coordinate on the category axis and the last recorded value
|
// Create a point using the coordinate on the category axis and the last recorded value
|
||||||
// position from the dictionary
|
// position from the dictionary
|
||||||
basePoint = {};
|
basePoint = {};
|
||||||
basePoint[catCoord] = allPoints[j];
|
basePoint[catCoord] = allPoints[group][j];
|
||||||
basePoint[valCoord] = catPoints[allPoints[j]];
|
basePoint[valCoord] = catPoints[group][allPoints[group][j]];
|
||||||
// add the base point
|
// add the base point
|
||||||
basePoints.push(basePoint);
|
basePoints.push(basePoint);
|
||||||
// handle missing points
|
// handle missing points
|
||||||
if (points[k][catCoord] > allPoints[j]) {
|
if (points[k][catCoord] > allPoints[group][j]) {
|
||||||
// If there is a missing point we need to in fill
|
// If there is a missing point we need to in fill
|
||||||
finalPointArray.push(basePoint);
|
finalPointArray.push(basePoint);
|
||||||
} else {
|
} else {
|
||||||
// They must be the same
|
// They must be the same
|
||||||
finalPointArray.push(points[k]);
|
finalPointArray.push(points[k]);
|
||||||
// Use this to update the dictionary to the new value coordinate
|
// Use this to update the dictionary to the new value coordinate
|
||||||
catPoints[allPoints[j]] = points[k][valCoord];
|
catPoints[areaData[i].group][allPoints[group][j]] = points[k][valCoord];
|
||||||
k += 1;
|
k += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -255,88 +297,30 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The final array of points for the entire outskirts of the area
|
// Reverse the base points so that they are in the correct order for the path
|
||||||
finalPointArray = finalPointArray.concat(basePoints.reverse()).concat(finalPointArray[0]);
|
basePoints = basePoints.reverse();
|
||||||
|
|
||||||
// Get the points that this area will appear
|
// Get the points that this area will appear
|
||||||
areaData[i].entry = getArea(interpolation, "_previousOrigin")(finalPointArray);
|
p = getArea(interpolation, "_previousOrigin")(finalPointArray);
|
||||||
areaData[i].update = getArea(interpolation)(finalPointArray);
|
b = getArea((interpolation === "step-after" ? "step-before" : (interpolation === "step-before" ? "step-after" : interpolation)), "_previousOrigin")(basePoints);
|
||||||
areaData[i].exit = getArea(interpolation, "_origin")(finalPointArray);
|
l = getArea("linear", "_previousOrigin")(finalPointArray);
|
||||||
|
areaData[i].entry = p + "L" + b.substring(1) + "L" + l.substring(1, l.indexOf("L"));
|
||||||
|
|
||||||
|
p = getArea(interpolation)(finalPointArray);
|
||||||
|
b = getArea(interpolation === "step-after" ? "step-before" : (interpolation === "step-before" ? "step-after" : interpolation))(basePoints);
|
||||||
|
l = getArea("linear")(finalPointArray);
|
||||||
|
areaData[i].update = p + "L" + b.substring(1) + "L" + l.substring(1, l.indexOf("L"));
|
||||||
|
|
||||||
|
p = getArea(interpolation, "_origin")(finalPointArray);
|
||||||
|
b = getArea((interpolation === "step-after" ? "step-before" : (interpolation === "step-before" ? "step-after" : interpolation)), "_origin")(basePoints);
|
||||||
|
l = getArea("linear", "_origin")(finalPointArray);
|
||||||
|
areaData[i].exit = p + "L" + b.substring(1) + "L" + l.substring(1, l.indexOf("L"));
|
||||||
|
|
||||||
// Add the color in this loop, it can't be done during initialisation of the row because
|
// Add the color in this loop, it can't be done during initialisation of the row because
|
||||||
// the areas should be ordered first (to ensure standard distribution of colors
|
// the areas should be ordered first (to ensure standard distribution of colors
|
||||||
areaData[i].color = chart.getColor(areaData[i].key.length > 0 ? areaData[i].key[areaData[i].key.length - 1] : "All");
|
areaData[i].color = chart.getColor(areaData[i].key.length > 0 ? areaData[i].key[areaData[i].key.length - 1] : "All");
|
||||||
|
|
||||||
}
|
}
|
||||||
// // Create a set of area data grouped by the aggregation field
|
|
||||||
// for (i = 0; i < areaData.length; i += 1) {
|
|
||||||
//
|
|
||||||
// // Sort the points so that areas are connected in the correct order
|
|
||||||
// areaData[i].data.sort(dimple._getSeriesSortPredicate(chart, series, orderedSeriesArray));
|
|
||||||
//
|
|
||||||
// // If this should have colour gradients, add them
|
|
||||||
// if (graded) {
|
|
||||||
// dimple._addGradient(areaData[i].key, "fill-area-gradient-" + areaData[i].keyString, (series.x._hasCategories() ? series.x : series.y), data, chart, duration, "fill");
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Clone the data before adding elements
|
|
||||||
// dataClone = [].concat(areaData[i].data);
|
|
||||||
//
|
|
||||||
// // If this is a custom dimple step area duplicate the last datum so that the final step is completed
|
|
||||||
// if (series.interpolation === "step") {
|
|
||||||
// if (series.x._hasCategories()) {
|
|
||||||
// // Clone the last row and duplicate it.
|
|
||||||
// dataClone = dataClone.concat(JSON.parse(JSON.stringify(dataClone[dataClone.length - 1])));
|
|
||||||
// dataClone[dataClone.length - 1].cx = "";
|
|
||||||
// dataClone[dataClone.length - 1].x = "";
|
|
||||||
// }
|
|
||||||
// if (series.y._hasCategories()) {
|
|
||||||
// // Clone the last row and duplicate it.
|
|
||||||
// dataClone = [JSON.parse(JSON.stringify(dataClone[0]))].concat(dataClone);
|
|
||||||
// dataClone[0].cy = "";
|
|
||||||
// dataClone[0].y = "";
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Add zero baseline for this row
|
|
||||||
// if (series.x._hasCategories() && series.y._hasMeasure()) {
|
|
||||||
// for (j = dataClone.length - 1; j >= 0; j -= 1) {
|
|
||||||
// areaData[i].baseData.push({
|
|
||||||
// x : dataClone[j].x,
|
|
||||||
// cx : dataClone[j].cx,
|
|
||||||
// xOffset : dataClone[j].xOffset,
|
|
||||||
// width : dataClone[j].width,
|
|
||||||
// y: (i === 0 ? 0 : areaData[i - 1].data[j].y),
|
|
||||||
// cy : (i === 0 ? 0 : areaData[i - 1].data[j].cy),
|
|
||||||
// yOffset: (i === 0 ? 0 : areaData[i - 1].data[j].yOffset),
|
|
||||||
// height: (i === 0 ? 0 : areaData[i - 1].data[j].height)
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// } else if (series.y._hasCategories() && series.x._hasMeasure()) {
|
|
||||||
// for (j = dataClone.length - 1; j >= 0; j -= 1) {
|
|
||||||
// areaData[i].baseData.push({
|
|
||||||
// x : (i === 0 ? 0 : areaData[i - 1].data[j].x),
|
|
||||||
// cx : (i === 0 ? 0 : areaData[i - 1].data[j].cx),
|
|
||||||
// xOffset : (i === 0 ? 0 : areaData[i - 1].data[j].xOffset),
|
|
||||||
// width : (i === 0 ? 0 : areaData[i - 1].data[j].width),
|
|
||||||
// y: dataClone[j].y,
|
|
||||||
// cy : dataClone[j].cy,
|
|
||||||
// yOffset: dataClone[j].yOffset,
|
|
||||||
// height: dataClone[j].height
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Get the points that this area will appear
|
|
||||||
// areaData[i].entry = getArea(interpolation, "_previousOrigin")(areaData[i].baseData.concat(dataClone));
|
|
||||||
// areaData[i].update = getArea(interpolation)(areaData[i].baseData.concat(dataClone));
|
|
||||||
// areaData[i].exit = getArea(interpolation, "_origin")(areaData[i].baseData.concat(dataClone));
|
|
||||||
//
|
|
||||||
// // Add the color in this loop, it can't be done during initialisation of the row because
|
|
||||||
// // the areas should be ordered first (to ensure standard distribution of colors
|
|
||||||
// areaData[i].color = chart.getColor(areaData[i].key.length > 0 ? areaData[i].key[areaData[i].key.length - 1] : "All");
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (chart._tooltipGroup !== null && chart._tooltipGroup !== undefined) {
|
if (chart._tooltipGroup !== null && chart._tooltipGroup !== undefined) {
|
||||||
chart._tooltipGroup.remove();
|
chart._tooltipGroup.remove();
|
||||||
|
@ -363,13 +347,12 @@
|
||||||
// Apply formats optionally
|
// Apply formats optionally
|
||||||
if (!chart.noFormats) {
|
if (!chart.noFormats) {
|
||||||
this.attr("opacity", function (d) { return (graded ? 1 : d.color.opacity); })
|
this.attr("opacity", function (d) { return (graded ? 1 : d.color.opacity); })
|
||||||
.attr("fill", function (d) { return (graded ? "url(#fill-line-gradient-" + d.keyString + ")" : d.color.fill); })
|
.attr("fill", function (d) { return (graded ? "url(#fill-area-gradient-" + d.keyString + ")" : d.color.fill); })
|
||||||
.attr("stroke", function (d) { return (graded ? "url(#stroke-line-gradient-" + d.keyString + ")" : d.color.stroke); })
|
.attr("stroke", function (d) { return (graded ? "url(#stroke-area-gradient-" + d.keyString + ")" : d.color.stroke); })
|
||||||
.attr("stroke-width", series.lineWeight);
|
.attr("stroke-width", series.lineWeight);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.each(drawMarkers);
|
.each(drawMarkers);
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
updated = dimple._handleTransition(theseShapes, duration)
|
updated = dimple._handleTransition(theseShapes, duration)
|
||||||
.attr("d", function (d) { return d.update; })
|
.attr("d", function (d) { return d.update; })
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
interpolation,
|
interpolation,
|
||||||
graded = false,
|
graded = false,
|
||||||
i,
|
i,
|
||||||
|
j,
|
||||||
k,
|
k,
|
||||||
key,
|
key,
|
||||||
keyString,
|
keyString,
|
||||||
|
@ -27,7 +28,6 @@
|
||||||
updated,
|
updated,
|
||||||
removed,
|
removed,
|
||||||
orderedSeriesArray,
|
orderedSeriesArray,
|
||||||
dataClone,
|
|
||||||
onEnter = function () {
|
onEnter = function () {
|
||||||
return function (e, shape, chart, series) {
|
return function (e, shape, chart, series) {
|
||||||
d3.select(shape).style("opacity", 1);
|
d3.select(shape).style("opacity", 1);
|
||||||
|
@ -52,14 +52,33 @@
|
||||||
} else {
|
} else {
|
||||||
val = dimple._helpers["c" + position](datum, chart, series);
|
val = dimple._helpers["c" + position](datum, chart, series);
|
||||||
}
|
}
|
||||||
return val;
|
// Remove long decimals from the coordinates as this fills the dom up with noise and makes matching below less likely to work. It
|
||||||
|
// shouldn't really matter but positioning to < 0.1 pixel is pretty pointless anyway.
|
||||||
|
return parseFloat(val.toFixed(1));
|
||||||
},
|
},
|
||||||
getLine = function (inter, originProperty) {
|
getLine = function (inter, originProperty) {
|
||||||
return d3.svg.line()
|
return d3.svg.line()
|
||||||
.x(function (d) { return (series.x._hasCategories() || !originProperty ? coord("x", d) : series.x[originProperty]); })
|
.x(function (d) { return (series.x._hasCategories() || !originProperty ? d.x : series.x[originProperty]); })
|
||||||
.y(function (d) { return (series.y._hasCategories() || !originProperty ? coord("y", d) : series.y[originProperty]); })
|
.y(function (d) { return (series.y._hasCategories() || !originProperty ? d.y : series.y[originProperty]); })
|
||||||
.interpolate(inter);
|
.interpolate(inter);
|
||||||
};
|
};
|
||||||
|
// coord = function (position, datum) {
|
||||||
|
// var val;
|
||||||
|
// if (series.interpolation === "step" && series[position]._hasCategories()) {
|
||||||
|
// series.barGap = 0;
|
||||||
|
// series.clusterBarGap = 0;
|
||||||
|
// val = dimple._helpers[position](datum, chart, series) + (position === "y" ? dimple._helpers.height(datum, chart, series) : 0);
|
||||||
|
// } else {
|
||||||
|
// val = dimple._helpers["c" + position](datum, chart, series);
|
||||||
|
// }
|
||||||
|
// return parseFloat(val).toFixed(1);
|
||||||
|
// },
|
||||||
|
// getLine = function (inter, originProperty) {
|
||||||
|
// return d3.svg.line()
|
||||||
|
// .x(function (d) { return (series.x._hasCategories() || !originProperty ? coord("x", d) : series.x[originProperty]); })
|
||||||
|
// .y(function (d) { return (series.y._hasCategories() || !originProperty ? coord("y", d) : series.y[originProperty]); })
|
||||||
|
// .interpolate(inter);
|
||||||
|
// };
|
||||||
|
|
||||||
// Handle the special interpolation handling for step
|
// Handle the special interpolation handling for step
|
||||||
interpolation = (series.interpolation === "step" ? "step-after" : series.interpolation);
|
interpolation = (series.interpolation === "step" ? "step-after" : series.interpolation);
|
||||||
|
@ -95,8 +114,10 @@
|
||||||
keyString: keyString,
|
keyString: keyString,
|
||||||
color: "white",
|
color: "white",
|
||||||
data: [],
|
data: [],
|
||||||
|
points: [],
|
||||||
line: {},
|
line: {},
|
||||||
entryExit: {}
|
entry: {},
|
||||||
|
exit: {}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Add this row to the relevant data
|
// Add this row to the relevant data
|
||||||
|
@ -119,28 +140,55 @@
|
||||||
if (graded) {
|
if (graded) {
|
||||||
dimple._addGradient(lineData[i].key, "fill-line-gradient-" + lineData[i].keyString, (series.x._hasCategories() ? series.x : series.y), data, chart, duration, "fill");
|
dimple._addGradient(lineData[i].key, "fill-line-gradient-" + lineData[i].keyString, (series.x._hasCategories() ? series.x : series.y), data, chart, duration, "fill");
|
||||||
}
|
}
|
||||||
// Clone the data before adding elements
|
|
||||||
dataClone = [].concat(lineData[i].data);
|
// Get points here, this is so that as well as drawing the line with them, we can also
|
||||||
// If this is a custom dimple step line duplicate the last datum so that the final step is completed
|
// use them for the baseline
|
||||||
if (series.interpolation === "step") {
|
for (j = 0; j < lineData[i].data.length; j += 1) {
|
||||||
|
lineData[i].points.push({
|
||||||
|
x: coord("x", lineData[i].data[j]),
|
||||||
|
y: coord("y", lineData[i].data[j])
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// If this is a step interpolation we need to add in some extra points to the category axis
|
||||||
|
// This is a little tricky but we need to add a new point duplicating the last category value. In order
|
||||||
|
// to place the point we need to calculate the gap between the last x and the penultimate x and apply that
|
||||||
|
// gap again.
|
||||||
|
if (series.interpolation === "step" && lineData[i].points.length > 1) {
|
||||||
if (series.x._hasCategories()) {
|
if (series.x._hasCategories()) {
|
||||||
// Clone the last row and duplicate it.
|
lineData[i].points.push({
|
||||||
dataClone = dataClone.concat(JSON.parse(JSON.stringify(dataClone[dataClone.length - 1])));
|
x : 2 * lineData[i].points[lineData[i].points.length - 1].x - lineData[i].points[lineData[i].points.length - 2].x,
|
||||||
dataClone[dataClone.length - 1].cx = "";
|
y : lineData[i].points[lineData[i].points.length - 1].y
|
||||||
dataClone[dataClone.length - 1].x = "";
|
});
|
||||||
}
|
} else if (series.y._hasCategories()) {
|
||||||
if (series.y._hasCategories()) {
|
lineData[i].points = [{
|
||||||
// Clone the last row and duplicate it.
|
x : lineData[i].points[0].x,
|
||||||
dataClone = [JSON.parse(JSON.stringify(dataClone[0]))].concat(dataClone);
|
y : 2 * lineData[i].points[0].y - lineData[i].points[1].y
|
||||||
dataClone[0].cy = "";
|
}].concat(lineData[i].points);
|
||||||
dataClone[0].y = "";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// // Clone the data before adding elements
|
||||||
|
// dataClone = [].concat(lineData[i].data);
|
||||||
|
// // If this is a custom dimple step line duplicate the last datum so that the final step is completed
|
||||||
|
// if (series.interpolation === "step") {
|
||||||
|
// if (series.x._hasCategories()) {
|
||||||
|
// // Clone the last row and duplicate it.
|
||||||
|
// dataClone = dataClone.concat(JSON.parse(JSON.stringify(dataClone[dataClone.length - 1])));
|
||||||
|
// dataClone[dataClone.length - 1].cx = "";
|
||||||
|
// dataClone[dataClone.length - 1].x = "";
|
||||||
|
// }
|
||||||
|
// if (series.y._hasCategories()) {
|
||||||
|
// // Clone the last row and duplicate it.
|
||||||
|
// dataClone = [JSON.parse(JSON.stringify(dataClone[0]))].concat(dataClone);
|
||||||
|
// dataClone[0].cy = "";
|
||||||
|
// dataClone[0].y = "";
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
// Get the points that this line will appear
|
// Get the points that this line will appear
|
||||||
lineData[i].entry = getLine(interpolation, "_previousOrigin")(dataClone);
|
lineData[i].entry = getLine(interpolation, "_previousOrigin")(lineData[i].points);
|
||||||
lineData[i].update = getLine(interpolation)(dataClone);
|
lineData[i].update = getLine(interpolation)(lineData[i].points);
|
||||||
lineData[i].exit = getLine(interpolation, "_origin")(dataClone);
|
lineData[i].exit = getLine(interpolation, "_origin")(lineData[i].points);
|
||||||
|
|
||||||
// Add the color in this loop, it can't be done during initialisation of the row because
|
// Add the color in this loop, it can't be done during initialisation of the row because
|
||||||
// the lines should be ordered first (to ensure standard distribution of colors
|
// the lines should be ordered first (to ensure standard distribution of colors
|
||||||
|
|
257
tmp/dimple.js
257
tmp/dimple.js
|
@ -2643,6 +2643,11 @@ var dimple = {
|
||||||
basePoints,
|
basePoints,
|
||||||
basePoint,
|
basePoint,
|
||||||
cat,
|
cat,
|
||||||
|
catVal,
|
||||||
|
group,
|
||||||
|
p,
|
||||||
|
b,
|
||||||
|
l,
|
||||||
lastAngle,
|
lastAngle,
|
||||||
catCoord,
|
catCoord,
|
||||||
valCoord,
|
valCoord,
|
||||||
|
@ -2680,6 +2685,9 @@ var dimple = {
|
||||||
.y(function (d) { return (series.y._hasCategories() || !originProperty ? d.y : series.y[originProperty]); })
|
.y(function (d) { return (series.y._hasCategories() || !originProperty ? d.y : series.y[originProperty]); })
|
||||||
.interpolate(inter);
|
.interpolate(inter);
|
||||||
},
|
},
|
||||||
|
sortByVal = function (a, b) {
|
||||||
|
return parseFloat(a) - parseFloat(b);
|
||||||
|
},
|
||||||
sortByX = function (a, b) {
|
sortByX = function (a, b) {
|
||||||
return parseFloat(a.x) - parseFloat(b.x);
|
return parseFloat(a.x) - parseFloat(b.x);
|
||||||
},
|
},
|
||||||
|
@ -2750,7 +2758,9 @@ var dimple = {
|
||||||
points: [],
|
points: [],
|
||||||
area: {},
|
area: {},
|
||||||
entry: {},
|
entry: {},
|
||||||
exit: {}
|
exit: {},
|
||||||
|
// Group refers to groupings along the category axis. If there are groupings it will be recorded, otherwise all is used as a default
|
||||||
|
group: (catCoord && data[i][catCoord + "Field"] && data[i][catCoord + "Field"].length >= 2 ? data[i][catCoord + "Field"][0] : "All")
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Add this row to the relevant data
|
// Add this row to the relevant data
|
||||||
|
@ -2779,7 +2789,32 @@ var dimple = {
|
||||||
// if there is a category axis, add the points to a distinct set. Set these to use the origin value
|
// if there is a category axis, add the points to a distinct set. Set these to use the origin value
|
||||||
// this will be updated with the last value in each case as we build the areas
|
// this will be updated with the last value in each case as we build the areas
|
||||||
if (catCoord) {
|
if (catCoord) {
|
||||||
catPoints[areaData[i].points[areaData[i].points.length - 1][catCoord]] = series[valCoord]._previousOrigin;
|
if (!catPoints[areaData[i].group]) {
|
||||||
|
catPoints[areaData[i].group] = {};
|
||||||
|
}
|
||||||
|
catPoints[areaData[i].group][areaData[i].points[areaData[i].points.length - 1][catCoord]] = series[valCoord]._previousOrigin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
points = areaData[i].points;
|
||||||
|
// If this is a step interpolation we need to add in some extra points to the category axis
|
||||||
|
// This is a little tricky but we need to add a new point duplicating the last category value. In order
|
||||||
|
// to place the point we need to calculate the gap between the last x and the penultimate x and apply that
|
||||||
|
// gap again.
|
||||||
|
if (series.interpolation === "step" && points.length > 1 && catCoord) {
|
||||||
|
if (series.x._hasCategories()) {
|
||||||
|
points.push({
|
||||||
|
x : 2 * points[points.length - 1].x - points[points.length - 2].x,
|
||||||
|
y : points[points.length - 1].y
|
||||||
|
});
|
||||||
|
catPoints[areaData[i].group][points[points.length - 1][catCoord]] = series[valCoord]._previousOrigin;
|
||||||
|
} else if (series.y._hasCategories()) {
|
||||||
|
points = [{
|
||||||
|
x : points[0].x,
|
||||||
|
y : 2 * points[0].y - points[1].y
|
||||||
|
}].concat(points);
|
||||||
|
catPoints[areaData[i].group][points[0][catCoord]] = series[valCoord]._previousOrigin;
|
||||||
|
// The prepend above breaks the reference so it needs to be reapplied here.
|
||||||
|
areaData[i].points = points;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2787,47 +2822,54 @@ var dimple = {
|
||||||
// catPoints needs to be lookup, but also accessed sequentially so we need to create an array of keys
|
// catPoints needs to be lookup, but also accessed sequentially so we need to create an array of keys
|
||||||
for (cat in catPoints) {
|
for (cat in catPoints) {
|
||||||
if (catPoints.hasOwnProperty(cat)) {
|
if (catPoints.hasOwnProperty(cat)) {
|
||||||
allPoints.push(parseFloat(cat));
|
allPoints[cat] = [];
|
||||||
|
for (catVal in catPoints[cat]) {
|
||||||
|
if (catPoints[cat].hasOwnProperty(catVal)) {
|
||||||
|
allPoints[cat].push(parseFloat(catVal));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Sort the points as integers
|
||||||
|
allPoints[cat].sort(sortByVal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Sort the points as integers
|
|
||||||
allPoints.sort(function (a, b) { return parseFloat(a) - parseFloat(b); });
|
|
||||||
|
|
||||||
// Create the areas
|
// Create the areas
|
||||||
for (i = 0; i < areaData.length; i += 1) {
|
for (i = 0; i < areaData.length; i += 1) {
|
||||||
points = areaData[i].points;
|
points = areaData[i].points;
|
||||||
|
group = areaData[i].group;
|
||||||
basePoints = [];
|
basePoints = [];
|
||||||
finalPointArray = [];
|
finalPointArray = [];
|
||||||
// If this should have colour gradients, add them
|
// If this should have colour gradients, add them
|
||||||
if (graded) {
|
if (graded) {
|
||||||
dimple._addGradient(areaData[i].key, "fill-area-gradient-" + areaData[i].keyString, (series.x._hasCategories() ? series.x : series.y), data, chart, duration, "fill");
|
dimple._addGradient(areaData[i].key, "fill-area-gradient-" + areaData[i].keyString, (series.x._hasCategories() ? series.x : series.y), data, chart, duration, "fill");
|
||||||
}
|
}
|
||||||
|
|
||||||
// All points will only be populated if there is a category axis
|
// All points will only be populated if there is a category axis
|
||||||
if (allPoints && allPoints.length > 0) {
|
if (allPoints[group] && allPoints[group].length > 0) {
|
||||||
// Iterate the point array because we need to fill in zero points for missing ones, otherwise the areas
|
// Iterate the point array because we need to fill in zero points for missing ones, otherwise the areas
|
||||||
// will cross where an upper area has no value and a lower value has a spike Issue #7
|
// will cross where an upper area has no value and a lower value has a spike Issue #7
|
||||||
for (j = 0, k = 0; j < allPoints.length; j += 1) {
|
for (j = 0, k = 0; j < allPoints[group].length; j += 1) {
|
||||||
// We are only interested in points between the first and last point of this areas data (i.e. don't fill ends - important
|
// We are only interested in points between the first and last point of this areas data (i.e. don't fill ends - important
|
||||||
// for grouped area charts)
|
// for grouped area charts). We have to use a strange criteria here. If there are no group gaps on a grouped area
|
||||||
if (allPoints[j] >= points[0][catCoord] && allPoints[j] <= points[points.length - 1][catCoord]) {
|
// chart the end point of one series will clash with the start point of another, therefore we have to ignore fill-in's within
|
||||||
|
// a couple of pixels of the start and end points
|
||||||
|
if (allPoints[group][j] >= points[0][catCoord] && allPoints[group][j] <= points[points.length - 1][catCoord]) {
|
||||||
// Get a base point, this needs to go on the base points array as well as filling in gaps in the point array.
|
// Get a base point, this needs to go on the base points array as well as filling in gaps in the point array.
|
||||||
// Create a point using the coordinate on the category axis and the last recorded value
|
// Create a point using the coordinate on the category axis and the last recorded value
|
||||||
// position from the dictionary
|
// position from the dictionary
|
||||||
basePoint = {};
|
basePoint = {};
|
||||||
basePoint[catCoord] = allPoints[j];
|
basePoint[catCoord] = allPoints[group][j];
|
||||||
basePoint[valCoord] = catPoints[allPoints[j]];
|
basePoint[valCoord] = catPoints[group][allPoints[group][j]];
|
||||||
// add the base point
|
// add the base point
|
||||||
basePoints.push(basePoint);
|
basePoints.push(basePoint);
|
||||||
// handle missing points
|
// handle missing points
|
||||||
if (points[k][catCoord] > allPoints[j]) {
|
if (points[k][catCoord] > allPoints[group][j]) {
|
||||||
// If there is a missing point we need to in fill
|
// If there is a missing point we need to in fill
|
||||||
finalPointArray.push(basePoint);
|
finalPointArray.push(basePoint);
|
||||||
} else {
|
} else {
|
||||||
// They must be the same
|
// They must be the same
|
||||||
finalPointArray.push(points[k]);
|
finalPointArray.push(points[k]);
|
||||||
// Use this to update the dictionary to the new value coordinate
|
// Use this to update the dictionary to the new value coordinate
|
||||||
catPoints[allPoints[j]] = points[k][valCoord];
|
catPoints[areaData[i].group][allPoints[group][j]] = points[k][valCoord];
|
||||||
k += 1;
|
k += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2863,88 +2905,30 @@ var dimple = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The final array of points for the entire outskirts of the area
|
// Reverse the base points so that they are in the correct order for the path
|
||||||
finalPointArray = finalPointArray.concat(basePoints.reverse()).concat(finalPointArray[0]);
|
basePoints = basePoints.reverse();
|
||||||
|
|
||||||
// Get the points that this area will appear
|
// Get the points that this area will appear
|
||||||
areaData[i].entry = getArea(interpolation, "_previousOrigin")(finalPointArray);
|
p = getArea(interpolation, "_previousOrigin")(finalPointArray);
|
||||||
areaData[i].update = getArea(interpolation)(finalPointArray);
|
b = getArea((interpolation === "step-after" ? "step-before" : (interpolation === "step-before" ? "step-after" : interpolation)), "_previousOrigin")(basePoints);
|
||||||
areaData[i].exit = getArea(interpolation, "_origin")(finalPointArray);
|
l = getArea("linear", "_previousOrigin")(finalPointArray);
|
||||||
|
areaData[i].entry = p + "L" + b.substring(1) + "L" + l.substring(1, l.indexOf("L"));
|
||||||
|
|
||||||
|
p = getArea(interpolation)(finalPointArray);
|
||||||
|
b = getArea(interpolation === "step-after" ? "step-before" : (interpolation === "step-before" ? "step-after" : interpolation))(basePoints);
|
||||||
|
l = getArea("linear")(finalPointArray);
|
||||||
|
areaData[i].update = p + "L" + b.substring(1) + "L" + l.substring(1, l.indexOf("L"));
|
||||||
|
|
||||||
|
p = getArea(interpolation, "_origin")(finalPointArray);
|
||||||
|
b = getArea((interpolation === "step-after" ? "step-before" : (interpolation === "step-before" ? "step-after" : interpolation)), "_origin")(basePoints);
|
||||||
|
l = getArea("linear", "_origin")(finalPointArray);
|
||||||
|
areaData[i].exit = p + "L" + b.substring(1) + "L" + l.substring(1, l.indexOf("L"));
|
||||||
|
|
||||||
// Add the color in this loop, it can't be done during initialisation of the row because
|
// Add the color in this loop, it can't be done during initialisation of the row because
|
||||||
// the areas should be ordered first (to ensure standard distribution of colors
|
// the areas should be ordered first (to ensure standard distribution of colors
|
||||||
areaData[i].color = chart.getColor(areaData[i].key.length > 0 ? areaData[i].key[areaData[i].key.length - 1] : "All");
|
areaData[i].color = chart.getColor(areaData[i].key.length > 0 ? areaData[i].key[areaData[i].key.length - 1] : "All");
|
||||||
|
|
||||||
}
|
}
|
||||||
// // Create a set of area data grouped by the aggregation field
|
|
||||||
// for (i = 0; i < areaData.length; i += 1) {
|
|
||||||
//
|
|
||||||
// // Sort the points so that areas are connected in the correct order
|
|
||||||
// areaData[i].data.sort(dimple._getSeriesSortPredicate(chart, series, orderedSeriesArray));
|
|
||||||
//
|
|
||||||
// // If this should have colour gradients, add them
|
|
||||||
// if (graded) {
|
|
||||||
// dimple._addGradient(areaData[i].key, "fill-area-gradient-" + areaData[i].keyString, (series.x._hasCategories() ? series.x : series.y), data, chart, duration, "fill");
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Clone the data before adding elements
|
|
||||||
// dataClone = [].concat(areaData[i].data);
|
|
||||||
//
|
|
||||||
// // If this is a custom dimple step area duplicate the last datum so that the final step is completed
|
|
||||||
// if (series.interpolation === "step") {
|
|
||||||
// if (series.x._hasCategories()) {
|
|
||||||
// // Clone the last row and duplicate it.
|
|
||||||
// dataClone = dataClone.concat(JSON.parse(JSON.stringify(dataClone[dataClone.length - 1])));
|
|
||||||
// dataClone[dataClone.length - 1].cx = "";
|
|
||||||
// dataClone[dataClone.length - 1].x = "";
|
|
||||||
// }
|
|
||||||
// if (series.y._hasCategories()) {
|
|
||||||
// // Clone the last row and duplicate it.
|
|
||||||
// dataClone = [JSON.parse(JSON.stringify(dataClone[0]))].concat(dataClone);
|
|
||||||
// dataClone[0].cy = "";
|
|
||||||
// dataClone[0].y = "";
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Add zero baseline for this row
|
|
||||||
// if (series.x._hasCategories() && series.y._hasMeasure()) {
|
|
||||||
// for (j = dataClone.length - 1; j >= 0; j -= 1) {
|
|
||||||
// areaData[i].baseData.push({
|
|
||||||
// x : dataClone[j].x,
|
|
||||||
// cx : dataClone[j].cx,
|
|
||||||
// xOffset : dataClone[j].xOffset,
|
|
||||||
// width : dataClone[j].width,
|
|
||||||
// y: (i === 0 ? 0 : areaData[i - 1].data[j].y),
|
|
||||||
// cy : (i === 0 ? 0 : areaData[i - 1].data[j].cy),
|
|
||||||
// yOffset: (i === 0 ? 0 : areaData[i - 1].data[j].yOffset),
|
|
||||||
// height: (i === 0 ? 0 : areaData[i - 1].data[j].height)
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// } else if (series.y._hasCategories() && series.x._hasMeasure()) {
|
|
||||||
// for (j = dataClone.length - 1; j >= 0; j -= 1) {
|
|
||||||
// areaData[i].baseData.push({
|
|
||||||
// x : (i === 0 ? 0 : areaData[i - 1].data[j].x),
|
|
||||||
// cx : (i === 0 ? 0 : areaData[i - 1].data[j].cx),
|
|
||||||
// xOffset : (i === 0 ? 0 : areaData[i - 1].data[j].xOffset),
|
|
||||||
// width : (i === 0 ? 0 : areaData[i - 1].data[j].width),
|
|
||||||
// y: dataClone[j].y,
|
|
||||||
// cy : dataClone[j].cy,
|
|
||||||
// yOffset: dataClone[j].yOffset,
|
|
||||||
// height: dataClone[j].height
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Get the points that this area will appear
|
|
||||||
// areaData[i].entry = getArea(interpolation, "_previousOrigin")(areaData[i].baseData.concat(dataClone));
|
|
||||||
// areaData[i].update = getArea(interpolation)(areaData[i].baseData.concat(dataClone));
|
|
||||||
// areaData[i].exit = getArea(interpolation, "_origin")(areaData[i].baseData.concat(dataClone));
|
|
||||||
//
|
|
||||||
// // Add the color in this loop, it can't be done during initialisation of the row because
|
|
||||||
// // the areas should be ordered first (to ensure standard distribution of colors
|
|
||||||
// areaData[i].color = chart.getColor(areaData[i].key.length > 0 ? areaData[i].key[areaData[i].key.length - 1] : "All");
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (chart._tooltipGroup !== null && chart._tooltipGroup !== undefined) {
|
if (chart._tooltipGroup !== null && chart._tooltipGroup !== undefined) {
|
||||||
chart._tooltipGroup.remove();
|
chart._tooltipGroup.remove();
|
||||||
|
@ -2971,13 +2955,12 @@ var dimple = {
|
||||||
// Apply formats optionally
|
// Apply formats optionally
|
||||||
if (!chart.noFormats) {
|
if (!chart.noFormats) {
|
||||||
this.attr("opacity", function (d) { return (graded ? 1 : d.color.opacity); })
|
this.attr("opacity", function (d) { return (graded ? 1 : d.color.opacity); })
|
||||||
.attr("fill", function (d) { return (graded ? "url(#fill-line-gradient-" + d.keyString + ")" : d.color.fill); })
|
.attr("fill", function (d) { return (graded ? "url(#fill-area-gradient-" + d.keyString + ")" : d.color.fill); })
|
||||||
.attr("stroke", function (d) { return (graded ? "url(#stroke-line-gradient-" + d.keyString + ")" : d.color.stroke); })
|
.attr("stroke", function (d) { return (graded ? "url(#stroke-area-gradient-" + d.keyString + ")" : d.color.stroke); })
|
||||||
.attr("stroke-width", series.lineWeight);
|
.attr("stroke-width", series.lineWeight);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.each(drawMarkers);
|
.each(drawMarkers);
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
updated = dimple._handleTransition(theseShapes, duration)
|
updated = dimple._handleTransition(theseShapes, duration)
|
||||||
.attr("d", function (d) { return d.update; })
|
.attr("d", function (d) { return d.update; })
|
||||||
|
@ -3222,6 +3205,7 @@ var dimple = {
|
||||||
interpolation,
|
interpolation,
|
||||||
graded = false,
|
graded = false,
|
||||||
i,
|
i,
|
||||||
|
j,
|
||||||
k,
|
k,
|
||||||
key,
|
key,
|
||||||
keyString,
|
keyString,
|
||||||
|
@ -3229,7 +3213,6 @@ var dimple = {
|
||||||
updated,
|
updated,
|
||||||
removed,
|
removed,
|
||||||
orderedSeriesArray,
|
orderedSeriesArray,
|
||||||
dataClone,
|
|
||||||
onEnter = function () {
|
onEnter = function () {
|
||||||
return function (e, shape, chart, series) {
|
return function (e, shape, chart, series) {
|
||||||
d3.select(shape).style("opacity", 1);
|
d3.select(shape).style("opacity", 1);
|
||||||
|
@ -3254,14 +3237,33 @@ var dimple = {
|
||||||
} else {
|
} else {
|
||||||
val = dimple._helpers["c" + position](datum, chart, series);
|
val = dimple._helpers["c" + position](datum, chart, series);
|
||||||
}
|
}
|
||||||
return val;
|
// Remove long decimals from the coordinates as this fills the dom up with noise and makes matching below less likely to work. It
|
||||||
|
// shouldn't really matter but positioning to < 0.1 pixel is pretty pointless anyway.
|
||||||
|
return parseFloat(val.toFixed(1));
|
||||||
},
|
},
|
||||||
getLine = function (inter, originProperty) {
|
getLine = function (inter, originProperty) {
|
||||||
return d3.svg.line()
|
return d3.svg.line()
|
||||||
.x(function (d) { return (series.x._hasCategories() || !originProperty ? coord("x", d) : series.x[originProperty]); })
|
.x(function (d) { return (series.x._hasCategories() || !originProperty ? d.x : series.x[originProperty]); })
|
||||||
.y(function (d) { return (series.y._hasCategories() || !originProperty ? coord("y", d) : series.y[originProperty]); })
|
.y(function (d) { return (series.y._hasCategories() || !originProperty ? d.y : series.y[originProperty]); })
|
||||||
.interpolate(inter);
|
.interpolate(inter);
|
||||||
};
|
};
|
||||||
|
// coord = function (position, datum) {
|
||||||
|
// var val;
|
||||||
|
// if (series.interpolation === "step" && series[position]._hasCategories()) {
|
||||||
|
// series.barGap = 0;
|
||||||
|
// series.clusterBarGap = 0;
|
||||||
|
// val = dimple._helpers[position](datum, chart, series) + (position === "y" ? dimple._helpers.height(datum, chart, series) : 0);
|
||||||
|
// } else {
|
||||||
|
// val = dimple._helpers["c" + position](datum, chart, series);
|
||||||
|
// }
|
||||||
|
// return parseFloat(val).toFixed(1);
|
||||||
|
// },
|
||||||
|
// getLine = function (inter, originProperty) {
|
||||||
|
// return d3.svg.line()
|
||||||
|
// .x(function (d) { return (series.x._hasCategories() || !originProperty ? coord("x", d) : series.x[originProperty]); })
|
||||||
|
// .y(function (d) { return (series.y._hasCategories() || !originProperty ? coord("y", d) : series.y[originProperty]); })
|
||||||
|
// .interpolate(inter);
|
||||||
|
// };
|
||||||
|
|
||||||
// Handle the special interpolation handling for step
|
// Handle the special interpolation handling for step
|
||||||
interpolation = (series.interpolation === "step" ? "step-after" : series.interpolation);
|
interpolation = (series.interpolation === "step" ? "step-after" : series.interpolation);
|
||||||
|
@ -3297,8 +3299,10 @@ var dimple = {
|
||||||
keyString: keyString,
|
keyString: keyString,
|
||||||
color: "white",
|
color: "white",
|
||||||
data: [],
|
data: [],
|
||||||
|
points: [],
|
||||||
line: {},
|
line: {},
|
||||||
entryExit: {}
|
entry: {},
|
||||||
|
exit: {}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Add this row to the relevant data
|
// Add this row to the relevant data
|
||||||
|
@ -3321,28 +3325,55 @@ var dimple = {
|
||||||
if (graded) {
|
if (graded) {
|
||||||
dimple._addGradient(lineData[i].key, "fill-line-gradient-" + lineData[i].keyString, (series.x._hasCategories() ? series.x : series.y), data, chart, duration, "fill");
|
dimple._addGradient(lineData[i].key, "fill-line-gradient-" + lineData[i].keyString, (series.x._hasCategories() ? series.x : series.y), data, chart, duration, "fill");
|
||||||
}
|
}
|
||||||
// Clone the data before adding elements
|
|
||||||
dataClone = [].concat(lineData[i].data);
|
// Get points here, this is so that as well as drawing the line with them, we can also
|
||||||
// If this is a custom dimple step line duplicate the last datum so that the final step is completed
|
// use them for the baseline
|
||||||
if (series.interpolation === "step") {
|
for (j = 0; j < lineData[i].data.length; j += 1) {
|
||||||
|
lineData[i].points.push({
|
||||||
|
x: coord("x", lineData[i].data[j]),
|
||||||
|
y: coord("y", lineData[i].data[j])
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// If this is a step interpolation we need to add in some extra points to the category axis
|
||||||
|
// This is a little tricky but we need to add a new point duplicating the last category value. In order
|
||||||
|
// to place the point we need to calculate the gap between the last x and the penultimate x and apply that
|
||||||
|
// gap again.
|
||||||
|
if (series.interpolation === "step" && lineData[i].points.length > 1) {
|
||||||
if (series.x._hasCategories()) {
|
if (series.x._hasCategories()) {
|
||||||
// Clone the last row and duplicate it.
|
lineData[i].points.push({
|
||||||
dataClone = dataClone.concat(JSON.parse(JSON.stringify(dataClone[dataClone.length - 1])));
|
x : 2 * lineData[i].points[lineData[i].points.length - 1].x - lineData[i].points[lineData[i].points.length - 2].x,
|
||||||
dataClone[dataClone.length - 1].cx = "";
|
y : lineData[i].points[lineData[i].points.length - 1].y
|
||||||
dataClone[dataClone.length - 1].x = "";
|
});
|
||||||
}
|
} else if (series.y._hasCategories()) {
|
||||||
if (series.y._hasCategories()) {
|
lineData[i].points = [{
|
||||||
// Clone the last row and duplicate it.
|
x : lineData[i].points[0].x,
|
||||||
dataClone = [JSON.parse(JSON.stringify(dataClone[0]))].concat(dataClone);
|
y : 2 * lineData[i].points[0].y - lineData[i].points[1].y
|
||||||
dataClone[0].cy = "";
|
}].concat(lineData[i].points);
|
||||||
dataClone[0].y = "";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// // Clone the data before adding elements
|
||||||
|
// dataClone = [].concat(lineData[i].data);
|
||||||
|
// // If this is a custom dimple step line duplicate the last datum so that the final step is completed
|
||||||
|
// if (series.interpolation === "step") {
|
||||||
|
// if (series.x._hasCategories()) {
|
||||||
|
// // Clone the last row and duplicate it.
|
||||||
|
// dataClone = dataClone.concat(JSON.parse(JSON.stringify(dataClone[dataClone.length - 1])));
|
||||||
|
// dataClone[dataClone.length - 1].cx = "";
|
||||||
|
// dataClone[dataClone.length - 1].x = "";
|
||||||
|
// }
|
||||||
|
// if (series.y._hasCategories()) {
|
||||||
|
// // Clone the last row and duplicate it.
|
||||||
|
// dataClone = [JSON.parse(JSON.stringify(dataClone[0]))].concat(dataClone);
|
||||||
|
// dataClone[0].cy = "";
|
||||||
|
// dataClone[0].y = "";
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
// Get the points that this line will appear
|
// Get the points that this line will appear
|
||||||
lineData[i].entry = getLine(interpolation, "_previousOrigin")(dataClone);
|
lineData[i].entry = getLine(interpolation, "_previousOrigin")(lineData[i].points);
|
||||||
lineData[i].update = getLine(interpolation)(dataClone);
|
lineData[i].update = getLine(interpolation)(lineData[i].points);
|
||||||
lineData[i].exit = getLine(interpolation, "_origin")(dataClone);
|
lineData[i].exit = getLine(interpolation, "_origin")(lineData[i].points);
|
||||||
|
|
||||||
// Add the color in this loop, it can't be done during initialisation of the row because
|
// Add the color in this loop, it can't be done during initialisation of the row because
|
||||||
// the lines should be ordered first (to ensure standard distribution of colors
|
// the lines should be ordered first (to ensure standard distribution of colors
|
||||||
|
|
Loading…
Reference in New Issue