Fixed Ordering Rule

master
johnkiernander 2014-04-16 19:26:45 +01:00
parent 61965f6ae2
commit 1d720360d2
5 changed files with 900 additions and 21 deletions

212
dist/dimple.v1.2.0.js vendored
View File

@ -688,7 +688,7 @@ var dimple = {
key,
storyCat = "",
orderedStoryboardArray = [],
seriesCat = "",
seriesCat = [],
orderedSeriesArray = [],
xCat = "",
xSortArray = [],
@ -738,6 +738,7 @@ var dimple = {
sortedData.sort(function (a, b) {
var returnValue = 0,
cats,
comp,
p,
q,
aMatch,
@ -751,15 +752,16 @@ var dimple = {
if (yCat !== "" && returnValue === 0) {
returnValue = ySortArray.indexOf(a[yCat]) - ySortArray.indexOf(b[yCat]);
}
if (seriesCat !== null && seriesCat !== undefined && seriesCat.length > 0) {
if (seriesCat && seriesCat.length > 0 && returnValue === 0) {
cats = [].concat(seriesCat);
returnValue = 0;
for (p = 0; p < orderedSeriesArray.length; p += 1) {
comp = [].concat(orderedSeriesArray[p]);
aMatch = true;
bMatch = true;
for (q = 0; q < cats.length; q += 1) {
aMatch = aMatch && (a[cats[q]] === orderedSeriesArray[p][q]);
bMatch = bMatch && (b[cats[q]] === orderedSeriesArray[p][q]);
aMatch = aMatch && (a[cats[q]] === comp[q]);
bMatch = bMatch && (b[cats[q]] === comp[q]);
}
if (aMatch && bMatch) {
returnValue = 0;
@ -2602,6 +2604,202 @@ var dimple = {
// License: "https://github.com/PMSI-AlignAlytics/dimple/blob/master/MIT-LICENSE.txt"
// Source: /src/objects/plot/area.js
dimple.plot.area = {
// By default the values are stacked
stacked: true,
// The axis positions affecting the area series
supportedAxes: ["x", "y", "c"],
// Draw the axis
draw: function (chart, series, duration) {
// Get the position data
var data = series._positionData,
areaData = [],
theseShapes = null,
className = "dimple-series-" + chart.series.indexOf(series),
firstAgg = (series.x._hasCategories() || series.y._hasCategories() ? 0 : 1),
interpolation,
graded = false,
i,
k,
key,
keyString,
rowIndex,
updated,
removed,
orderedSeriesArray,
dataClone,
onEnter = function (e, shape, chart, series) {
d3.select(shape).style("opacity", 1);
dimple._showPointTooltip(e, shape, chart, series);
},
onLeave = function (e, shape, chart, series) {
d3.select(shape).style("opacity", (series.lineMarkers ? dimple._helpers.opacity(e, chart, series) : 0));
dimple._removeTooltip(e, shape, chart, series);
},
drawMarkers = function (d) {
dimple._drawMarkers(d, chart, series, duration, className, graded, onEnter, onLeave);
},
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 val;
},
getArea = 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
interpolation = (series.interpolation === "step" ? "step-after" : series.interpolation);
// Get the array of ordered values
orderedSeriesArray = dimple._getSeriesOrder(series.data || chart.data, series);
if (series.c && ((series.x._hasCategories() && series.y._hasMeasure()) || (series.y._hasCategories() && series.x._hasMeasure()))) {
graded = true;
}
// Create a set of area data grouped by the aggregation field
for (i = 0; i < data.length; i += 1) {
key = [];
rowIndex = -1;
// Skip the first category unless there is a category axis on x or y
for (k = firstAgg; k < data[i].aggField.length; k += 1) {
key.push(data[i].aggField[k]);
}
// Find the corresponding row in the areaData
keyString = dimple._createClass(key);
for (k = 0; k < areaData.length; k += 1) {
if (areaData[k].keyString === keyString) {
rowIndex = k;
break;
}
}
// Add a row to the area data if none was found
if (rowIndex === -1) {
rowIndex = areaData.length;
areaData.push({
key: key,
keyString: keyString,
color: "white",
data: [],
area: {},
entryExit: {}
});
}
// Add this row to the relevant data
areaData[rowIndex].data.push(data[i]);
}
// Sort the area data itself based on the order series array - this matters for stacked areas and default color
// consistency with colors usually awarded in terms of prominence
if (orderedSeriesArray) {
areaData.sort(function (a, b) {
return dimple._arrayIndexCompare(orderedSeriesArray, a.key, b.key);
});
}
// 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 = "";
}
}
// Get the points that this area will appear
areaData[i].entry = getArea(interpolation, "_previousOrigin")(dataClone);
areaData[i].update = getArea(interpolation)(dataClone);
areaData[i].exit = getArea(interpolation, "_origin")(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) {
chart._tooltipGroup.remove();
}
if (series.shapes === null || series.shapes === undefined) {
theseShapes = chart._group.selectAll("." + className).data(areaData);
} else {
theseShapes = series.shapes.data(areaData, function (d) { return d.key; });
}
// Add
theseShapes
.enter()
.append("path")
.attr("id", function (d) { return d.key; })
.attr("class", function (d) {
return className + " dimple-line " + d.keyString;
})
.attr("d", function (d) {
return d.entry;
})
.call(function () {
// Apply formats optionally
if (!chart.noFormats) {
this.attr("opacity", function (d) { return (graded ? 1 : d.color.opacity); })
.attr("fill", "none")
.attr("stroke", function (d) { return (graded ? "url(#fill-line-gradient-" + d.keyString + ")" : d.color.stroke); })
.attr("stroke-width", series.lineWeight);
}
})
.each(drawMarkers);
// Update
updated = dimple._handleTransition(theseShapes, duration)
.attr("d", function (d) { return d.update; })
.each(drawMarkers);
// Remove
removed = dimple._handleTransition(theseShapes.exit(), duration)
.attr("d", function (d) { return d.exit; })
.each(drawMarkers);
dimple._postDrawHandling(series, updated, removed, duration);
// Save the shapes to the series array
series.shapes = theseShapes;
}
};
// Copyright: 2014 PMSI-AlignAlytics
// License: "https://github.com/PMSI-AlignAlytics/dimple/blob/master/MIT-LICENSE.txt"
// Source: /src/objects/plot/area.js
dimple.plot.area_old = {
stacked: true,
supportedAxes: ["x", "y", "c"],
@ -3288,7 +3486,7 @@ var dimple = {
// Source: /src/objects/plot/line.js
dimple.plot.line = {
// By default the bubble values are not stacked
// By default the values are not stacked
stacked: false,
// The axis positions affecting the line series
@ -3344,7 +3542,7 @@ var dimple = {
// Handle the special interpolation handling for step
interpolation = (series.interpolation === "step" ? "step-after" : series.interpolation);
//
// Get the array of ordered values
orderedSeriesArray = dimple._getSeriesOrder(series.data || chart.data, series);
@ -3423,7 +3621,7 @@ var dimple = {
lineData[i].update = getLine(interpolation)(dataClone);
lineData[i].exit = getLine(interpolation, "_origin")(dataClone);
// Add the color in this loop, it can't be done during initialisation of the row becase
// 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
lineData[i].color = chart.getColor(lineData[i].key.length > 0 ? lineData[i].key[lineData[i].key.length - 1] : "All");
}

File diff suppressed because one or more lines are too long

View File

@ -40,7 +40,7 @@
key,
storyCat = "",
orderedStoryboardArray = [],
seriesCat = "",
seriesCat = [],
orderedSeriesArray = [],
xCat = "",
xSortArray = [],
@ -90,6 +90,7 @@
sortedData.sort(function (a, b) {
var returnValue = 0,
cats,
comp,
p,
q,
aMatch,
@ -103,15 +104,16 @@
if (yCat !== "" && returnValue === 0) {
returnValue = ySortArray.indexOf(a[yCat]) - ySortArray.indexOf(b[yCat]);
}
if (seriesCat !== null && seriesCat !== undefined && seriesCat.length > 0) {
if (seriesCat && seriesCat.length > 0 && returnValue === 0) {
cats = [].concat(seriesCat);
returnValue = 0;
for (p = 0; p < orderedSeriesArray.length; p += 1) {
comp = [].concat(orderedSeriesArray[p]);
aMatch = true;
bMatch = true;
for (q = 0; q < cats.length; q += 1) {
aMatch = aMatch && (a[cats[q]] === orderedSeriesArray[p][q]);
bMatch = bMatch && (b[cats[q]] === orderedSeriesArray[p][q]);
aMatch = aMatch && (a[cats[q]] === comp[q]);
bMatch = bMatch && (b[cats[q]] === comp[q]);
}
if (aMatch && bMatch) {
returnValue = 0;

View File

@ -0,0 +1,481 @@
// Copyright: 2014 PMSI-AlignAlytics
// License: "https://github.com/PMSI-AlignAlytics/dimple/blob/master/MIT-LICENSE.txt"
// Source: /src/objects/plot/area.js
dimple.plot.area = {
stacked: true,
supportedAxes: ["x", "y", "c"],
draw: function (chart, series, duration) {
// Get self pointer for inner functions
var self = this,
data = series._positionData,
uniqueValues = [],
firstAgg = 1,
graded = false,
seriesClass = "series" + chart.series.indexOf(series),
line,
catPoints = {},
markers,
markerBacks;
if (chart._tooltipGroup !== null && chart._tooltipGroup !== undefined) {
chart._tooltipGroup.remove();
}
// If there is a category axis we should draw a line for each aggField. Otherwise
// the first aggField defines the points and the others define the line
if (series.x._hasCategories() || series.y._hasCategories()) {
firstAgg = 0;
}
data.forEach(function (d) {
var filter = [],
match = false,
k;
for (k = firstAgg; k < d.aggField.length; k += 1) {
filter.push(d.aggField[k]);
}
uniqueValues.forEach(function (e) {
match = match || (e === filter.join("/"));
}, this);
if (!match) {
uniqueValues.push(filter.join("/"));
}
}, this);
if (series.c !== null && series.c !== undefined && ((series.x._hasCategories() && series.y._hasMeasure()) || (series.y._hasCategories() && series.x._hasMeasure()))) {
graded = true;
uniqueValues.forEach(function (seriesValue) {
dimple._addGradient(seriesValue, "fill-area-gradient-" + seriesValue.join("_").replace(" ", ""), (series.x._hasCategories() ? series.x : series.y), data, chart, duration, "fill");
dimple._addGradient(seriesValue, "stroke-area-gradient-" + seriesValue.join("_").replace(" ", ""), (series.x._hasCategories() ? series.x : series.y), data, chart, duration, "stroke");
}, this);
}
line = d3.svg.line()
.x(function (d) { return dimple._helpers.cx(d, chart, series); })
.y(function (d) { return dimple._helpers.cy(d, chart, series); });
if (series.shapes === null || series.shapes === undefined) {
series.shapes = chart._group.selectAll(".area." + seriesClass)
.data(uniqueValues)
.enter()
.append("svg:path")
.attr("opacity", function(d) { return chart.getColor(d).opacity; });
}
series.shapes
.data(uniqueValues)
.transition()
.duration(duration)
.attr("class", function (d) { return seriesClass + " series area " + d.split(" ").join("_"); })
.attr("d", function (d) {
var seriesData,
baseline = [],
max = 0,
row,
newObj,
j,
k,
m,
q,
r;
seriesData = dimple.filterData(data, "aggField", d);
seriesData.sort(function (a, b) {
var sortValue = 0;
if (series.x._hasCategories()) {
sortValue = (dimple._helpers.cx(a, chart, series) < dimple._helpers.cx(b, chart, series) ? -1 : 1);
} else if (series.y._hasCategories()) {
sortValue = (dimple._helpers.cy(a, chart, series) < dimple._helpers.cy(b, chart, series) ? -1 : 1);
}
return sortValue;
});
for (j = seriesData.length - 1; j >= 0; j -= 1) {
row = seriesData[j];
newObj = { cx: 0, cy: 0, height: 0, width: 0, xOffset: 0, yOffset: 0 };
if (series.x._hasCategories()) {
// Fix the x properties
newObj.cx = row.cx;
newObj.width = row.width;
newObj.xOffset = row.xOffset;
// Find the largest value for the xField less than this value
if (catPoints[row.xField] === undefined) {
catPoints[row.xField] = [];
} else {
max = 0;
for (k = 0; k <= catPoints[row.xField].length; k += 1) {
q = catPoints[row.xField][k];
if ((row.cy >= 0 && q >= 0) || (row.cy <= 0 && q <= 0)) {
if (Math.abs(q) <= Math.abs(row.cy) && Math.abs(q) > Math.abs(max)) {
max = q;
}
}
}
newObj.cy = max;
}
baseline.push(newObj);
catPoints[row.xField].push(row.cy);
} else if (series.y._hasCategories()) {
// Fix the y properties
newObj.cy = row.cy;
newObj.height = row.height;
newObj.yOffset = row.yOffset;
// Find the largest value for the xField less than this value
if (catPoints[row.yField] === undefined) {
catPoints[row.yField] = [];
} else {
max = 0;
for (m = 0; m <= catPoints[row.yField].length; m += 1) {
r = catPoints[row.yField][m];
if ((row.cx >= 0 && r >= 0) || (row.cx <= 0 && r <= 0)) {
if (Math.abs(r) <= Math.abs(row.cx) && Math.abs(r) > Math.abs(max)) {
max = r;
}
}
}
newObj.cx = max;
}
baseline.push(newObj);
catPoints[row.yField].push(row.cx);
}
}
//return line(startPoint.concat(seriesData).concat(endPoint));
return line(seriesData.concat(baseline).concat(seriesData[0]));
})
.call(function () {
if (!chart.noFormats) {
this.attr("fill", function (d) { return (graded ? "url(#fill-area-gradient-" + d.join("_").replace(" ", "") + ")" : chart.getColor(d).fill); })
.attr("stroke", function (d) { return (graded ? "url(#stroke-area-gradient-" + d.join("_").replace(" ", "") + ")" : chart.getColor(d).stroke); })
.attr("stroke-width", series.lineWeight);
}
});
if (series.lineMarkers) {
if (series._markerBacks === null || series._markerBacks === undefined) {
markerBacks = chart._group.selectAll(".markerBacks." + seriesClass).data(data);
} else {
markerBacks = series._markerBacks.data(data, function (d) { return d.key; });
}
// Add
markerBacks
.enter()
.append("circle")
.attr("id", function (d) { return d.key; })
.attr("class", "markerBacks " + seriesClass)
.attr("cx", function (d) { return dimple._helpers.cx(d, chart, series); })
.attr("cy", function (d) { return dimple._helpers.cy(d, chart, series); })
.attr("r", 0)
.attr("fill", "white")
.attr("stroke", "none");
// Update
markerBacks
.transition().duration(duration)
.attr("cx", function (d) { return dimple._helpers.cx(d, chart, series); })
.attr("cy", function (d) { return dimple._helpers.cy(d, chart, series); })
.attr("r", 2 + series.lineWeight);
// Remove
markerBacks
.exit()
.transition().duration(duration)
.attr("r", 0)
.each("end", function () {
d3.select(this).remove();
});
series._markerBacks = markerBacks;
}
// Deal with markers in the same way as main series to fix #28
if (series._markers === null || series._markers === undefined) {
markers = chart._group.selectAll(".markers." + seriesClass).data(data);
} else {
markers = series._markers.data(data, function (d) { return d.key; });
}
// Add the actual marker. We need to do this even if we aren't displaying them because they
// catch hover events
markers
.enter()
.append("circle")
.attr("id", function (d) { return d.key; })
.attr("class", "markers " + seriesClass)
.on("mouseover", function (e) {
self.enterEventHandler(e, this, chart, series);
})
.on("mouseleave", function (e) {
self.leaveEventHandler(e, this, chart, series);
})
.attr("cx", function (d) { return dimple._helpers.cx(d, chart, series); })
.attr("cy", function (d) { return dimple._helpers.cy(d, chart, series); })
.attr("r", 0)
.attr("opacity", function (d) { return (series.lineMarkers ? chart.getColor(d).opacity : 0); })
.call(function () {
if (!chart.noFormats) {
this.attr("fill", "white")
.style("stroke-width", series.lineWeight)
.attr("stroke", function (d) {
return (graded ? dimple._helpers.fill(d, chart, series) : chart.getColor(d.aggField[d.aggField.length - 1]).stroke);
});
}
});
markers
.transition().duration(duration)
.attr("cx", function (d) { return dimple._helpers.cx(d, chart, series); })
.attr("cy", function (d) { return dimple._helpers.cy(d, chart, series); })
.attr("r", 2 + series.lineWeight)
.call(function () {
if (!chart.noFormats) {
this.attr("fill", "white")
.style("stroke-width", series.lineWeight)
.attr("stroke", function (d) {
return (graded ? dimple._helpers.fill(d, chart, series) : chart.getColor(d.aggField[d.aggField.length - 1]).stroke);
});
}
});
markers
.exit()
.transition().duration(duration)
.attr("r", 0)
.each("end", function () {
d3.select(this).remove();
});
// Save the shapes to the series array
series._markers = markers;
},
// Handle the mouse enter event
enterEventHandler: function (e, shape, chart, series) {
// The margin between the text and the box
var textMargin = 5,
// The margin between the ring and the popup
popupMargin = 10,
// The popup animation duration in ms
animDuration = 750,
// Collect some facts about the highlighted bubble
selectedShape = d3.select(shape),
cx = parseFloat(selectedShape.attr("cx")),
cy = parseFloat(selectedShape.attr("cy")),
r = parseFloat(selectedShape.attr("r")),
opacity = dimple._helpers.opacity(e, chart, series),
fill = dimple._helpers.fill(e, chart, series),
dropDest = series._dropLineOrigin(),
// Fade the popup stroke mixing the shape fill with 60% white
popupStrokeColor = d3.rgb(
d3.rgb(fill).r + 0.6 * (255 - d3.rgb(fill).r),
d3.rgb(fill).g + 0.6 * (255 - d3.rgb(fill).g),
d3.rgb(fill).b + 0.6 * (255 - d3.rgb(fill).b)
),
// Fade the popup fill mixing the shape fill with 80% white
popupFillColor = d3.rgb(
d3.rgb(fill).r + 0.8 * (255 - d3.rgb(fill).r),
d3.rgb(fill).g + 0.8 * (255 - d3.rgb(fill).g),
d3.rgb(fill).b + 0.8 * (255 - d3.rgb(fill).b)
),
t,
y = 0,
w = 0,
h = 0,
box,
overlap,
rows = [];
if (chart._tooltipGroup !== null && chart._tooltipGroup !== undefined) {
chart._tooltipGroup.remove();
}
chart._tooltipGroup = chart.svg.append("g");
// On hover make the line marker visible immediately
selectedShape.style("opacity", 1);
// Add a ring around the data point
chart._tooltipGroup.append("circle")
.attr("cx", cx)
.attr("cy", cy)
.attr("r", r)
.attr("opacity", 0)
.style("fill", "none")
.style("stroke", fill)
.style("stroke-width", 1)
.transition()
.duration(animDuration / 2)
.ease("linear")
.attr("opacity", 1)
.attr("r", r + 4)
.style("stroke-width", 2);
// Add a drop line to the x axis
if (dropDest.y !== null) {
chart._tooltipGroup.append("line")
.attr("x1", cx)
.attr("y1", (cy < dropDest.y ? cy + r + 4 : cy - r - 4))
.attr("x2", cx)
.attr("y2", (cy < dropDest.y ? cy + r + 4 : cy - r - 4))
.style("fill", "none")
.style("stroke", fill)
.style("stroke-width", 2)
.style("stroke-dasharray", ("3, 3"))
.style("opacity", opacity)
.transition()
.delay(animDuration / 2)
.duration(animDuration / 2)
.ease("linear")
// Added 1px offset to cater for svg issue where a transparent
// group overlapping a line can sometimes hide it in some browsers
// Issue #10
.attr("y2", (cy < dropDest.y ? dropDest.y - 1 : dropDest.y + 1));
}
// Add a drop line to the y axis
if (dropDest.x !== null) {
chart._tooltipGroup.append("line")
.attr("x1", (cx < dropDest.x ? cx + r + 4 : cx - r - 4))
.attr("y1", cy)
.attr("x2", (cx < dropDest.x ? cx + r + 4 : cx - r - 4))
.attr("y2", cy)
.style("fill", "none")
.style("stroke", fill)
.style("stroke-width", 2)
.style("stroke-dasharray", ("3, 3"))
.style("opacity", opacity)
.transition()
.delay(animDuration / 2)
.duration(animDuration / 2)
.ease("linear")
// Added 1px offset to cater for svg issue where a transparent
// group overlapping a line can sometimes hide it in some browsers
// Issue #10
.attr("x2", (cx < dropDest.x ? dropDest.x - 1 : dropDest.x + 1));
}
// Add a group for text
t = chart._tooltipGroup.append("g");
// Create a box for the popup in the text group
box = t.append("rect")
.attr("class", "chartTooltip");
// Add the series categories
if (series.categoryFields !== null && series.categoryFields !== undefined && series.categoryFields.length > 0) {
series.categoryFields.forEach(function (c, i) {
if (c !== null && c !== undefined && e.aggField[i] !== null && e.aggField[i] !== undefined) {
// If the category name and value match don't display the category name
rows.push(c + (e.aggField[i] !== c ? ": " + e.aggField[i] : ""));
}
}, this);
}
if (series.x._hasTimeField()) {
if (e.xField[0] !== null && e.xField[0] !== undefined) {
rows.push(series.x.timeField + ": " + series.x._getFormat()(e.xField[0]));
}
} else if (series.x._hasCategories()) {
// Add the x axis categories
series.x.categoryFields.forEach(function (c, i) {
if (c !== null && c !== undefined && e.xField[i] !== null && e.xField[i] !== undefined) {
// If the category name and value match don't display the category name
rows.push(c + (e.xField[i] !== c ? ": " + e.xField[i] : ""));
}
}, this);
} else {
// Add the axis measure value
if (series.x.measure !== null && series.x.measure !== undefined && e.width !== null && e.width !== undefined) {
rows.push(series.x.measure + ": " + series.x._getFormat()(e.width));
}
}
if (series.y._hasTimeField()) {
if (e.yField[0] !== null && e.yField[0] !== undefined) {
rows.push(series.y.timeField + ": " + series.y._getFormat()(e.yField[0]));
}
} else if (series.y._hasCategories()) {
// Add the y axis categories
series.y.categoryFields.forEach(function (c, i) {
if (c !== null && c !== undefined && e.yField[i] !== null && e.yField[i] !== undefined) {
rows.push(c + (e.yField[i] !== c ? ": " + e.yField[i] : ""));
}
}, this);
} else {
// Add the axis measure value
if (series.y.measure !== null && series.y.measure !== undefined && e.height !== null && e.height !== undefined) {
rows.push(series.y.measure + ": " + series.y._getFormat()(e.height));
}
}
if (series.z !== null && series.z !== undefined) {
// Add the axis measure value
if (series.z.measure !== null && series.z.measure !== undefined && e.zValue !== null && e.zValue !== undefined) {
rows.push(series.z.measure + ": " + series.z._getFormat()(e.zValue));
}
}
if (series.c !== null && series.c !== undefined) {
// Add the axis measure value
if (series.c.measure !== null && series.c.measure !== undefined && e.cValue !== null && e.cValue !== undefined) {
rows.push(series.c.measure + ": " + series.c._getFormat()(e.cValue));
}
}
// Get distinct text rows to deal with cases where 2 axes have the same dimensionality
rows = rows.filter(function(elem, pos) {
return rows.indexOf(elem) === pos;
});
// Create a text object for every row in the popup
t.selectAll(".textHoverShapes").data(rows).enter()
.append("text")
.attr("class", "chartTooltip")
.text(function (d) { return d; })
.style("font-family", "sans-serif")
.style("font-size", "10px");
// Get the max height and width of the text items
t.each(function () {
w = (this.getBBox().width > w ? this.getBBox().width : w);
h = (this.getBBox().width > h ? this.getBBox().height : h);
});
// Position the text relative to the bubble, the absolute positioning
// will be done by translating the group
t.selectAll("text")
.attr("x", 0)
.attr("y", function () {
// Increment the y position
y += this.getBBox().height;
// Position the text at the centre point
return y - (this.getBBox().height / 2);
});
// Draw the box with a margin around the text
box.attr("x", -textMargin)
.attr("y", -textMargin)
.attr("height", Math.floor(y + textMargin) - 0.5)
.attr("width", w + 2 * textMargin)
.attr("rx", 5)
.attr("ry", 5)
.style("fill", popupFillColor)
.style("stroke", popupStrokeColor)
.style("stroke-width", 2)
.style("opacity", 0.95);
// Shift the ring margin left or right depending on whether it will overlap the edge
overlap = cx + r + textMargin + popupMargin + w > parseFloat(chart.svg.node().getBBox().width);
// Translate the shapes to the x position of the bubble (the x position of the shapes is handled)
t.attr("transform", "translate(" +
(overlap ? cx - (r + textMargin + popupMargin + w) : cx + r + textMargin + popupMargin) + " , " +
(cy - ((y - (h - textMargin)) / 2)) +
")");
},
// Handle the mouse leave event
leaveEventHandler: function (e, shape, chart, series) {
// Return the opacity of the marker
d3.select(shape).style("opacity", (series.lineMarkers ? dimple._helpers.opacity(e, chart, series) : 0));
if (chart._tooltipGroup !== null && chart._tooltipGroup !== undefined) {
chart._tooltipGroup.remove();
}
}
};

View File

@ -688,7 +688,7 @@ var dimple = {
key,
storyCat = "",
orderedStoryboardArray = [],
seriesCat = "",
seriesCat = [],
orderedSeriesArray = [],
xCat = "",
xSortArray = [],
@ -738,6 +738,7 @@ var dimple = {
sortedData.sort(function (a, b) {
var returnValue = 0,
cats,
comp,
p,
q,
aMatch,
@ -751,15 +752,16 @@ var dimple = {
if (yCat !== "" && returnValue === 0) {
returnValue = ySortArray.indexOf(a[yCat]) - ySortArray.indexOf(b[yCat]);
}
if (seriesCat !== null && seriesCat !== undefined && seriesCat.length > 0) {
if (seriesCat && seriesCat.length > 0 && returnValue === 0) {
cats = [].concat(seriesCat);
returnValue = 0;
for (p = 0; p < orderedSeriesArray.length; p += 1) {
comp = [].concat(orderedSeriesArray[p]);
aMatch = true;
bMatch = true;
for (q = 0; q < cats.length; q += 1) {
aMatch = aMatch && (a[cats[q]] === orderedSeriesArray[p][q]);
bMatch = bMatch && (b[cats[q]] === orderedSeriesArray[p][q]);
aMatch = aMatch && (a[cats[q]] === comp[q]);
bMatch = bMatch && (b[cats[q]] === comp[q]);
}
if (aMatch && bMatch) {
returnValue = 0;
@ -2602,6 +2604,202 @@ var dimple = {
// License: "https://github.com/PMSI-AlignAlytics/dimple/blob/master/MIT-LICENSE.txt"
// Source: /src/objects/plot/area.js
dimple.plot.area = {
// By default the values are stacked
stacked: true,
// The axis positions affecting the area series
supportedAxes: ["x", "y", "c"],
// Draw the axis
draw: function (chart, series, duration) {
// Get the position data
var data = series._positionData,
areaData = [],
theseShapes = null,
className = "dimple-series-" + chart.series.indexOf(series),
firstAgg = (series.x._hasCategories() || series.y._hasCategories() ? 0 : 1),
interpolation,
graded = false,
i,
k,
key,
keyString,
rowIndex,
updated,
removed,
orderedSeriesArray,
dataClone,
onEnter = function (e, shape, chart, series) {
d3.select(shape).style("opacity", 1);
dimple._showPointTooltip(e, shape, chart, series);
},
onLeave = function (e, shape, chart, series) {
d3.select(shape).style("opacity", (series.lineMarkers ? dimple._helpers.opacity(e, chart, series) : 0));
dimple._removeTooltip(e, shape, chart, series);
},
drawMarkers = function (d) {
dimple._drawMarkers(d, chart, series, duration, className, graded, onEnter, onLeave);
},
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 val;
},
getArea = 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
interpolation = (series.interpolation === "step" ? "step-after" : series.interpolation);
// Get the array of ordered values
orderedSeriesArray = dimple._getSeriesOrder(series.data || chart.data, series);
if (series.c && ((series.x._hasCategories() && series.y._hasMeasure()) || (series.y._hasCategories() && series.x._hasMeasure()))) {
graded = true;
}
// Create a set of area data grouped by the aggregation field
for (i = 0; i < data.length; i += 1) {
key = [];
rowIndex = -1;
// Skip the first category unless there is a category axis on x or y
for (k = firstAgg; k < data[i].aggField.length; k += 1) {
key.push(data[i].aggField[k]);
}
// Find the corresponding row in the areaData
keyString = dimple._createClass(key);
for (k = 0; k < areaData.length; k += 1) {
if (areaData[k].keyString === keyString) {
rowIndex = k;
break;
}
}
// Add a row to the area data if none was found
if (rowIndex === -1) {
rowIndex = areaData.length;
areaData.push({
key: key,
keyString: keyString,
color: "white",
data: [],
area: {},
entryExit: {}
});
}
// Add this row to the relevant data
areaData[rowIndex].data.push(data[i]);
}
// Sort the area data itself based on the order series array - this matters for stacked areas and default color
// consistency with colors usually awarded in terms of prominence
if (orderedSeriesArray) {
areaData.sort(function (a, b) {
return dimple._arrayIndexCompare(orderedSeriesArray, a.key, b.key);
});
}
// 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 = "";
}
}
// Get the points that this area will appear
areaData[i].entry = getArea(interpolation, "_previousOrigin")(dataClone);
areaData[i].update = getArea(interpolation)(dataClone);
areaData[i].exit = getArea(interpolation, "_origin")(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) {
chart._tooltipGroup.remove();
}
if (series.shapes === null || series.shapes === undefined) {
theseShapes = chart._group.selectAll("." + className).data(areaData);
} else {
theseShapes = series.shapes.data(areaData, function (d) { return d.key; });
}
// Add
theseShapes
.enter()
.append("path")
.attr("id", function (d) { return d.key; })
.attr("class", function (d) {
return className + " dimple-line " + d.keyString;
})
.attr("d", function (d) {
return d.entry;
})
.call(function () {
// Apply formats optionally
if (!chart.noFormats) {
this.attr("opacity", function (d) { return (graded ? 1 : d.color.opacity); })
.attr("fill", "none")
.attr("stroke", function (d) { return (graded ? "url(#fill-line-gradient-" + d.keyString + ")" : d.color.stroke); })
.attr("stroke-width", series.lineWeight);
}
})
.each(drawMarkers);
// Update
updated = dimple._handleTransition(theseShapes, duration)
.attr("d", function (d) { return d.update; })
.each(drawMarkers);
// Remove
removed = dimple._handleTransition(theseShapes.exit(), duration)
.attr("d", function (d) { return d.exit; })
.each(drawMarkers);
dimple._postDrawHandling(series, updated, removed, duration);
// Save the shapes to the series array
series.shapes = theseShapes;
}
};
// Copyright: 2014 PMSI-AlignAlytics
// License: "https://github.com/PMSI-AlignAlytics/dimple/blob/master/MIT-LICENSE.txt"
// Source: /src/objects/plot/area.js
dimple.plot.area_old = {
stacked: true,
supportedAxes: ["x", "y", "c"],
@ -3288,7 +3486,7 @@ var dimple = {
// Source: /src/objects/plot/line.js
dimple.plot.line = {
// By default the bubble values are not stacked
// By default the values are not stacked
stacked: false,
// The axis positions affecting the line series
@ -3344,7 +3542,7 @@ var dimple = {
// Handle the special interpolation handling for step
interpolation = (series.interpolation === "step" ? "step-after" : series.interpolation);
//
// Get the array of ordered values
orderedSeriesArray = dimple._getSeriesOrder(series.data || chart.data, series);
@ -3423,7 +3621,7 @@ var dimple = {
lineData[i].update = getLine(interpolation)(dataClone);
lineData[i].exit = getLine(interpolation, "_origin")(dataClone);
// Add the color in this loop, it can't be done during initialisation of the row becase
// 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
lineData[i].color = chart.getColor(lineData[i].key.length > 0 ? lineData[i].key[lineData[i].key.length - 1] : "All");
}