From 824b139c2e4421b5c69229e72b198a542d5d251a Mon Sep 17 00:00:00 2001 From: Jacob Rideout Date: Tue, 19 Nov 2013 20:38:54 -0500 Subject: [PATCH] Refactor to remove group stack and fix coloring --- Gruntfile.js | 1 - spec/composite-chart-spec.js | 22 +-- spec/line-chart-spec.js | 6 +- spec/series-chart-spec.js | 4 +- src/bar-chart.js | 52 +++--- src/base-chart.js | 39 +---- src/box-plot.js | 2 +- src/color-chart.js | 18 ++- src/composite-chart.js | 57 +++---- src/coordinate-grid-chart.js | 26 +-- src/geo-choropleth-chart.js | 2 +- src/heatmap.js | 4 +- src/legend.js | 21 +-- src/line-chart.js | 71 +++++---- src/pie-chart.js | 6 +- src/series-chart.js | 3 +- src/stackable-chart.js | 301 ++++++++++++----------------------- src/utils.js | 160 +------------------ test/bar-chart-test.js | 3 +- test/data-addition-test.js | 2 +- test/stackable-chart-test.js | 111 ------------- test/web-renders/stock.html | 2 +- web/examples/composite.html | 4 +- web/play-ground.html | 6 +- 24 files changed, 268 insertions(+), 655 deletions(-) delete mode 100644 test/stackable-chart-test.js diff --git a/Gruntfile.js b/Gruntfile.js index 23eb70e83..a952d47fa 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -136,7 +136,6 @@ module.exports = function (grunt) { flatten: true, src: [output.js, output.js + ".map", - 'node_modules/jquery/tmp/jquery.js', 'node_modules/d3/d3.js', 'node_modules/crossfilter/crossfilter.js', 'test/env-data.js'], diff --git a/spec/composite-chart-spec.js b/spec/composite-chart-spec.js index 67f090fc8..7b7825978 100644 --- a/spec/composite-chart-spec.js +++ b/spec/composite-chart-spec.js @@ -20,15 +20,16 @@ describe('dc.compositeChart', function() { .x(d3.time.scale().domain([new Date(2012, 4, 20), new Date(2012, 7, 15)])) .transitionDuration(0) .xUnits(d3.time.days) + .shareColors(true) .compose([ dc.barChart(chart) .centerBar(true) - .group(dateValueSumGroup, 'Date Value Group') + .group(dateValueSumGroup, 'Date Value Group Bar') .gap(1), dc.lineChart(chart) .group(dateIdSumGroup, 'Date ID Group') - .stack(dateValueSumGroup, 'Date Value Group') - .stack(dateValueSumGroup, 'Date Value Group'), + .stack(dateValueSumGroup, 'Date Value Group Line 1') + .stack(dateValueSumGroup, 'Date Value Group Line 2'), dc.lineChart(chart) .group(dateGroup, 'Date Group') ]); @@ -307,21 +308,22 @@ describe('dc.compositeChart', function() { function legendText(n) { return d3.select(chart.selectAll('g.dc-legend g.dc-legend-item text')[0][n]).text(); } - expect(legendText(0)).toBe('Date Value Group'); + expect(legendText(0)).toBe('Date Value Group Bar'); expect(legendText(1)).toBe('Date ID Group'); - expect(legendText(2)).toBe('Date Value Group'); - expect(legendText(3)).toBe('Date Value Group'); + expect(legendText(2)).toBe('Date Value Group Line 1'); + expect(legendText(3)).toBe('Date Value Group Line 2'); expect(legendText(4)).toBe('Date Group'); }); it('should properly delegate highlighting to its children', function () { var firstItem = chart.select('g.dc-legend g.dc-legend-item'); - var firstLine = chart.children()[0].select("path.line"); firstItem.on("mouseover")(firstItem.datum()); - expect(firstLine.classed("highlight")).toBeTruthy(); + expect(chart.selectAll("rect.highlight").size()).toBe(6); + expect(chart.selectAll("path.fadeout").size()).toBe(4); firstItem.on("mouseout")(firstItem.datum()); - expect(firstLine.classed("highlight")).toBeFalsy(); + expect(chart.selectAll("rect.highlight").size()).toBe(0); + expect(chart.selectAll("path.fadeout").size()).toBe(0); }); }); @@ -385,6 +387,8 @@ describe('dc.compositeChart', function() { .brushOn(false) .dimension(dimension) .shareTitle(false) + .x(d3.scale.ordinal()) + .xUnits(dc.units.ordinal) .compose([ dc.lineChart(chart) .group(group, "Series 1") diff --git a/spec/line-chart-spec.js b/spec/line-chart-spec.js index c88a34816..68f4ae9a0 100644 --- a/spec/line-chart-spec.js +++ b/spec/line-chart-spec.js @@ -525,7 +525,7 @@ describe('dc.lineChart', function() { }); describe('stack hiding', function () { - describe('hiding first stack', function () { + describe('first stack', function () { beforeEach(function () { chart.hideStack("stack 0"); chart.render(); @@ -542,7 +542,7 @@ describe('dc.lineChart', function() { }); }); - describe('hiding any other stack', function () { + describe('any other stack', function () { beforeEach(function () { chart.title("stack 2", function (d) { return "stack 2: " + d.value; }); chart.hideStack("stack 1"); @@ -560,7 +560,7 @@ describe('dc.lineChart', function() { }); it('should color chart dots the same as line paths', function () { - var lineColor = chart.select('g._1 path.line').attr("fill"); + var lineColor = chart.select('g._1 path.line').attr("stroke"); var circleColor = chart.select('g._1 circle.dot').attr("fill"); expect(lineColor).toEqual(circleColor); }); diff --git a/spec/series-chart-spec.js b/spec/series-chart-spec.js index eb2bb0cab..9c1c59749 100644 --- a/spec/series-chart-spec.js +++ b/spec/series-chart-spec.js @@ -24,7 +24,7 @@ describe('dc.seriesChart', function() { .x(d3.scale.linear().domain([1,2])) .dimension(dimensionColorData) .group(groupColorData) - .colors(["#000001", "#000002"]) + .ordinalColors(["#000001", "#000002"]) .seriesAccessor(function(d) { return +d.key[0];}) .keyAccessor(function(d) { return +d.key[1];}) .valueAccessor(function(d) { return +d.value ;}) @@ -50,9 +50,7 @@ describe('dc.seriesChart', function() { it('should color lines using the colors in the data', function() { var lines = chart.selectAll("path.line"); - expect(d3.select(lines[0][0]).attr("fill")).toBe("#000001"); expect(d3.select(lines[0][0]).attr("stroke")).toBe("#000001"); - expect(d3.select(lines[0][1]).attr("fill")).toBe("#000002"); expect(d3.select(lines[0][1]).attr("stroke")).toBe("#000002"); }); }); diff --git a/src/bar-chart.js b/src/bar-chart.js index c4412868a..105a55b11 100644 --- a/src/bar-chart.js +++ b/src/bar-chart.js @@ -48,7 +48,7 @@ dc.barChart = function (parent, chartGroup) { _chart.plotData = function () { var layers = _chart.chartBodyG().selectAll("g.stack") - .data(_chart.stackLayers()); + .data(_chart.data()); calculateBarWidth(); @@ -64,8 +64,6 @@ dc.barChart = function (parent, chartGroup) { renderBars(layer, i, d); }); - - _chart.stackLayers(null); }; function barHeight(d) { @@ -74,17 +72,15 @@ dc.barChart = function (parent, chartGroup) { function renderBars(layer, layerIndex, d) { var bars = layer.selectAll("rect.bar") - .data(d.points, dc.pluck('data', _chart.keyAccessor())); + .data(d.values, dc.pluck('x')); bars.enter() .append("rect") .attr("class", "bar") - .attr("fill", _chart.getColor); - - if (_chart.renderTitle()) { - bars.append("title").text(dc.pluck('data', _chart.getTitleOfVisibleByIndex(layerIndex))); + .attr("fill", dc.pluck('data',_chart.getColor)); - } + if (_chart.renderTitle()) + bars.append("title").text(dc.pluck('data',_chart.title(d.name))); if (_chart.isOrdinal()) bars.on("click", onClick); @@ -108,8 +104,8 @@ dc.barChart = function (parent, chartGroup) { .attr("height", function (d) { return barHeight(d); }) - .attr("fill", _chart.getColor) - .select("title").text(dc.pluck('data', _chart.getTitleOfVisibleByIndex(layerIndex))); + .attr("fill", dc.pluck('data',_chart.getColor)) + .select("title").text(dc.pluck('data',_chart.title(d.name))); dc.transition(bars.exit(), _chart.transitionDuration()) .attr("height", 0) @@ -139,10 +135,10 @@ dc.barChart = function (parent, chartGroup) { if (_chart.isOrdinal()) { if (_chart.hasFilter()) { bars.classed(dc.constants.SELECTED_CLASS, function (d) { - return _chart.hasFilter(_chart.keyAccessor()(d.data)); + return _chart.hasFilter(d.x); }); bars.classed(dc.constants.DESELECTED_CLASS, function (d) { - return !_chart.hasFilter(_chart.keyAccessor()(d.data)); + return !_chart.hasFilter(d.x); }); } else { bars.classed(dc.constants.SELECTED_CLASS, false); @@ -154,8 +150,7 @@ dc.barChart = function (parent, chartGroup) { var end = extent[1]; bars.classed(dc.constants.DESELECTED_CLASS, function (d) { - var xValue = _chart.keyAccessor()(d.data); - return xValue < start || xValue >= end; + return d.x < start || d.x >= end; }); } else { bars.classed(dc.constants.DESELECTED_CLASS, false); @@ -225,24 +220,27 @@ dc.barChart = function (parent, chartGroup) { return extent; }; + function colorFilter(color,inv) { + return function() { + var item = d3.select(this); + var match = item.attr('fill') == color; + return inv ? !match : match; + }; + } + _chart.legendHighlight = function (d) { if(!_chart.isLegendableHidden(d)) { - _chart.select('.chart-body').selectAll('rect.bar').filter(function () { - return d3.select(this).attr('fill') == d.color; - }).classed('highlight', true); - _chart.select('.chart-body').selectAll('rect.bar').filter(function () { - return d3.select(this).attr('fill') != d.color; - }).classed('fadeout', true); + _chart.selectAll('rect.bar') + .classed('highlight', colorFilter(d.color)) + .classed('fadeout', colorFilter(d.color,true)); + } }; _chart.legendReset = function (d) { - _chart.selectAll('.chart-body').selectAll('rect.bar').filter(function () { - return d3.select(this).attr('fill') == d.color; - }).classed('highlight', false); - _chart.selectAll('.chart-body').selectAll('rect.bar').filter(function () { - return d3.select(this).attr('fill') != d.color; - }).classed('fadeout', false); + _chart.selectAll('rect.bar') + .classed('highlight', false) + .classed('fadeout', false); }; dc.override(_chart, "xAxisMax", function() { diff --git a/src/base-chart.js b/src/base-chart.js index 4b06bf4ce..acf41a1d4 100644 --- a/src/base-chart.js +++ b/src/base-chart.js @@ -188,40 +188,11 @@ dc.baseChart = function (_chart) { _chart.group = function (g, name) { if (!arguments.length) return _group; _group = g; + _chart._groupName = name; _chart.expireCache(); - if (typeof name === 'string') _chart._setGroupName(_group, name); return _chart; }; - // store groups names in the group itself - // __names__ -> - // chart (in referenced by multiple charts) -> - // array of accessors, array of names - function groupName(chart, g, accessor) { - var c = chart.chartID(), - k = '__names__'; - if (!accessor || accessor == chart.valueAccessor()) - accessor = "default"; - if (!g[k]) g[k] = {}; - if (!g[k][c]) g[k][c] = {a:[],n:[]}; - var i = g[k][c].a.indexOf(accessor); - if (i == -1) { - i = g[k][c].a.length; - g[k][c].a[i] = accessor; - g[k][c].n[i] = {name:''}; - } - return g[k][c].n[i]; - } - - - _chart._getGroupName = function (g, accessor) { - return groupName(_chart, g, accessor).name; - }; - - _chart._setGroupName = function (g, name, accessor) { - groupName(_chart, g, accessor).name = name; - }; - /** #### .ordering([orderFunction]) Get or set an accessor to order ordinal charts @@ -465,11 +436,17 @@ dc.baseChart = function (_chart) { var result = _chart.doRedraw(); + if (_legend) _legend.render(); + _chart.activateRenderlets("postRedraw"); return result; }; + _chart.redrawGroup = function () { + dc.redrawAll(_chart.chartGroup()); + }; + _chart._invokeFilteredListener = function (f) { if (f !== undefined) _listeners.filtered(_chart, f); }; @@ -589,7 +566,7 @@ dc.baseChart = function (_chart) { var filter = _chart.keyAccessor()(d); dc.events.trigger(function () { _chart.filter(filter); - dc.redrawAll(_chart.chartGroup()); + _chart.redrawGroup(); }); }; diff --git a/src/box-plot.js b/src/box-plot.js index 7ef758a1f..00f2052ca 100644 --- a/src/box-plot.js +++ b/src/box-plot.js @@ -126,7 +126,7 @@ dc.boxPlot = function (parent, chartGroup) { .on("click", function(d) { _chart.filter(d.key); //_chart.focus(_chart.filter()); - dc.redrawAll(_chart.chartGroup()); + _chart.redrawGroup(); }); } diff --git a/src/color-chart.js b/src/color-chart.js index 38a7c6554..74e640ffc 100644 --- a/src/color-chart.js +++ b/src/color-chart.js @@ -7,13 +7,10 @@ chart implementation. dc.colorChart = function(_chart) { var _colors = d3.scale.category20c(); + var _defaultAccessor = true; var _colorAccessor = function(d) { return _chart.keyAccessor()(d); }; - var _colorCalculator = function(value) { - return _colors(value,_chart); - }; - /** #### .colors([colorScale]) Retrieve current color scale or set a new color scale. This methods accepts any @@ -35,7 +32,7 @@ dc.colorChart = function(_chart) { _chart.colors = function(_) { if (!arguments.length) return _colors; if (_ instanceof Array) _colors = d3.scale.quantize().range(_); // depricated legacy support, note: this fails for ordinal domains - else _colors = _; + else _colors = d3.functor(_); return _chart; }; @@ -74,9 +71,14 @@ dc.colorChart = function(_chart) { _chart.colorAccessor = function(_){ if(!arguments.length) return _colorAccessor; _colorAccessor = _; + _defaultAccessor = false; return _chart; }; + _chart.defaultColorAccessor = function() { + return _defaultAccessor; + }; + /** #### .colorDomain([domain]) Set or get the current domain for the color mapping function. The domain must be supplied as an array. @@ -107,12 +109,12 @@ dc.colorChart = function(_chart) { **/ _chart.getColor = function(d, i){ - return _colorCalculator(_colorAccessor(d, i)); + return _colors(_colorAccessor.call(this,d, i)); }; _chart.colorCalculator = function(_){ - if(!arguments.length) return _colorCalculator; - _colorCalculator = _; + if(!arguments.length) return _chart.getColor; + _chart.getColor = _; return _chart; }; diff --git a/src/composite-chart.js b/src/composite-chart.js index e5dd8f79f..9428342e4 100644 --- a/src/composite-chart.js +++ b/src/composite-chart.js @@ -198,13 +198,7 @@ dc.compositeChart = function (parent, chartGroup) { child.width(_chart.width()); child.margins(_chart.margins()); - if (_shareTitle) { - child.title(_chart.title()); - } - - if (_shareColors && child.colorAccessor() === child._layerColorAccessor) { - child.colorCalculator(function() {return child.colors()(i);}); - } + if (_shareTitle) child.title(_chart.title()); }); return _chart; }; @@ -261,11 +255,9 @@ dc.compositeChart = function (parent, chartGroup) { } function getYAxisMin(charts) { - var allMins = []; - for (var i = 0; i < charts.length; ++i) { - allMins.push(charts[i].yAxisMin()); - } - return allMins; + return charts.map(function(c) { + return c.yAxisMin(); + }); } function yAxisMin() { @@ -277,11 +269,9 @@ dc.compositeChart = function (parent, chartGroup) { } function getYAxisMax(charts) { - var allMaxes = []; - for (var i = 0; i < charts.length; ++i) { - allMaxes.push(charts[i].yAxisMax()); - } - return allMaxes; + return charts.map(function(c) { + return c.yAxisMax(); + }); } function yAxisMax() { @@ -293,11 +283,9 @@ dc.compositeChart = function (parent, chartGroup) { } function getAllXAxisMinFromChildCharts() { - var allMins = []; - for (var i = 0; i < _children.length; ++i) { - allMins.push(_children[i].xAxisMin()); - } - return allMins; + return _children.map(function(c) { + return c.xAxisMin(); + }); } _chart.xAxisMin = function () { @@ -305,11 +293,9 @@ dc.compositeChart = function (parent, chartGroup) { }; function getAllXAxisMaxFromChildCharts() { - var allMaxes = []; - for (var i = 0; i < _children.length; ++i) { - allMaxes.push(_children[i].xAxisMax()); - } - return allMaxes; + return _children.map(function(c) { + return c.xAxisMax(); + }); } _chart.xAxisMax = function () { @@ -317,18 +303,11 @@ dc.compositeChart = function (parent, chartGroup) { }; _chart.legendables = function () { - var items = []; - _children.forEach(function(child, i) { - if (_shareColors) - child.colors(_chart.colors()); - - var childLegendables = child.legendables(); - if (childLegendables.length) - items.push.apply(items,childLegendables); - else - items.push(dc.utils.createLegendable(child, child.group(), child.valueAccessor(), child.colorCalculator()(i))); - }); - return items; + return _children.reduce(function(items,child) { + if (_shareColors) child.colors(_chart.colors()); + items.push.apply(items, child.legendables()); + return items; + },[]); }; _chart.legendHighlight = function (d) { diff --git a/src/coordinate-grid-chart.js b/src/coordinate-grid-chart.js index 7d941abba..11a6d7a91 100644 --- a/src/coordinate-grid-chart.js +++ b/src/coordinate-grid-chart.js @@ -23,7 +23,7 @@ dc.coordinateGridChart = function (_chart) { var _x; var _xOriginalDomain; - var _xAxis = d3.svg.axis(); + var _xAxis = d3.svg.axis().orient("bottom"); var _xUnits = dc.units.integers; var _xAxisPadding = 0; var _xElasticity = false; @@ -31,7 +31,7 @@ dc.coordinateGridChart = function (_chart) { var _xAxisLabelPadding = 0; var _y; - var _yAxis = d3.svg.axis(); + var _yAxis = d3.svg.axis().orient("left"); var _yAxisPadding = 0; var _yElasticity = false; var _yAxisLabel; @@ -285,13 +285,17 @@ dc.coordinateGridChart = function (_chart) { return _chart.xUnits() === dc.units.ordinal; }; + _chart._ordinalXDomain = function() { + var groups = _chart.computeOrderedGroups(_chart.data()); + return groups.map(_chart.keyAccessor()); + }; + function prepareXAxis(g) { if (_chart.elasticX() && !_chart.isOrdinal()) { _x.domain([_chart.xAxisMin(), _chart.xAxisMax()]); } else if (_chart.isOrdinal() && _x.domain().length===0) { - var orderedData = _chart.computeOrderedGroups(_chart.data()); - _x.domain(orderedData.map(_chart.keyAccessor())); + _x.domain(_chart._ordinalXDomain()); } if (_chart.isOrdinal()) { @@ -300,7 +304,7 @@ dc.coordinateGridChart = function (_chart) { _x.range([0, _chart.xAxisLength()]); } - _xAxis = _xAxis.scale(_chart.x()).orient("bottom"); + _xAxis = _xAxis.scale(_chart.x()); renderVerticalGridLines(g); } @@ -401,12 +405,8 @@ dc.coordinateGridChart = function (_chart) { _y.range([_chart.yAxisHeight(), 0]); _yAxis = _yAxis.scale(_y); - if (_useRightYAxis) { + if (_useRightYAxis) _yAxis.orient("right"); - } - else { - _yAxis.orient("left"); - } renderHorizontalGridLines(g); }; @@ -728,14 +728,14 @@ dc.coordinateGridChart = function (_chart) { if (_chart.brushIsEmpty(extent)) { dc.events.trigger(function () { _chart.filter(null); - dc.redrawAll(_chart.chartGroup()); + _chart.redrawGroup(); }, dc.constants.EVENT_DELAY); } else { var rangedFilter = dc.filters.RangedFilter(extent[0], extent[1]); dc.events.trigger(function () { _chart.replaceFilter(rangedFilter); - dc.redrawAll(_chart.chartGroup()); + _chart.redrawGroup(); }, dc.constants.EVENT_DELAY); } }; @@ -889,7 +889,7 @@ dc.coordinateGridChart = function (_chart) { _chart._invokeZoomedListener(); dc.events.trigger(function () { - dc.redrawAll(_chart.chartGroup()); + _chart.redrawGroup(); }, dc.constants.EVENT_DELAY); _refocused = !rangesEqual(domain, _xOriginalDomain); diff --git a/src/geo-choropleth-chart.js b/src/geo-choropleth-chart.js index 2c4d677db..35e75d14a 100644 --- a/src/geo-choropleth-chart.js +++ b/src/geo-choropleth-chart.js @@ -149,7 +149,7 @@ dc.geoChoroplethChart = function (parent, chartGroup) { var selectedRegion = geoJson(layerIndex).keyAccessor(d); dc.events.trigger(function () { _chart.filter(selectedRegion); - dc.redrawAll(_chart.chartGroup()); + _chart.redrawGroup(); }); }; diff --git a/src/heatmap.js b/src/heatmap.js index 2764cf8ca..9568e703d 100644 --- a/src/heatmap.js +++ b/src/heatmap.js @@ -43,7 +43,7 @@ dc.heatMap = function (parent, chartGroup) { var filter = d.key; dc.events.trigger(function() { _chart.filter(filter); - dc.redrawAll(_chart.chartGroup()); + _chart.redrawGroup(); }); }; @@ -64,7 +64,7 @@ dc.heatMap = function (parent, chartGroup) { _chart.filter(d.key); }); } - dc.redrawAll(_chart.chartGroup()); + _chart.redrawGroup(); }); } diff --git a/src/legend.js b/src/legend.js index bc9ac77bb..3fa202117 100644 --- a/src/legend.js +++ b/src/legend.js @@ -37,15 +37,13 @@ dc.legend = function () { _g = _parent.svg().append("g") .attr("class", "dc-legend") .attr("transform", "translate(" + _x + "," + _y + ")"); + var legendables = _parent.legendables(); var itemEnter = _g.selectAll('g.dc-legend-item') - .data(_parent.legendables()) + .data(legendables) .enter() .append("g") .attr("class", "dc-legend-item") - .classed("fadeout", function(d) { - return _parent.isLegendableHidden(d); - }) .on("mouseover", function(d) { _parent.legendHighlight(d); }) @@ -56,7 +54,12 @@ dc.legend = function () { _parent.legendToggle(d); }); - if (_parent.legendables().some(function (legendItem) { return legendItem.dashstyle; })) { + _g.selectAll('g.dc-legend-item') + .classed("fadeout", function(d) { + return d.chart.isLegendableHidden(d); + }); + + if (legendables.some(dc.pluck('dashstyle'))) { itemEnter .append("line") .attr("x1", 0) @@ -64,18 +67,18 @@ dc.legend = function () { .attr("x2", _itemHeight) .attr("y2", _itemHeight / 2) .attr("stroke-width", 2) - .attr("stroke-dasharray", function(d){return d.dashstyle;}) - .attr("stroke", function(d){return d.color;}); + .attr("stroke-dasharray", dc.pluck('dashstyle')) + .attr("stroke", dc.pluck('color')); } else { itemEnter .append("rect") .attr("width", _itemHeight) .attr("height", _itemHeight) - .attr("fill", function(d){return d.color;}); + .attr("fill", function(d){return d?d.color:"blue";}); } itemEnter.append("text") - .text(function(d){return d.name;}) + .text(dc.pluck('name')) .attr("x", _itemHeight + LABEL_GAP) .attr("y", function(){return _itemHeight / 2 + (this.clientHeight?this.clientHeight:13) / 2 - 2;}); diff --git a/src/line-chart.js b/src/line-chart.js index 15ea47dd6..2122d6245 100644 --- a/src/line-chart.js +++ b/src/line-chart.js @@ -57,7 +57,7 @@ dc.lineChart = function (parent, chartGroup) { if (layersList.empty()) layersList = chartBody.append("g").attr("class", "stack-list"); - var layers = layersList.selectAll("g.stack").data(_chart.stackLayers()); + var layers = layersList.selectAll("g.stack").data(_chart.data()); var layersEnter = layers .enter() @@ -71,8 +71,6 @@ dc.lineChart = function (parent, chartGroup) { drawArea(layersEnter, layers); drawDots(chartBody, layers); - - _chart.stackLayers(null); }; _chart.interpolate = function(_){ @@ -118,6 +116,10 @@ dc.lineChart = function (parent, chartGroup) { return _chart; }; + function colors(d, i) { + return _chart.getColor.call(d,d.values,i); + } + function drawLine(layersEnter, layers) { var line = d3.svg.line() .x(function (d) { @@ -131,17 +133,17 @@ dc.lineChart = function (parent, chartGroup) { if (_defined) line.defined(_defined); - var path = layersEnter.append("path") .attr("class", "line") - .attr("stroke", _chart.getColor) - .attr("fill", _chart.getColor); + .attr("stroke", colors); if (_dashStyle) path.attr("stroke-dasharray", _dashStyle); dc.transition(layers.select("path.line"), _chart.transitionDuration()) + //.ease("linear") + .attr("stroke", colors) .attr("d", function (d) { - return safeD(line(d.points)); + return safeD(line(d.values)); }); } @@ -162,17 +164,18 @@ dc.lineChart = function (parent, chartGroup) { if (_defined) area.defined(_defined); - layersEnter.append("path") .attr("class", "area") - .attr("fill", _chart.getColor) + .attr("fill", colors) .attr("d", function (d) { - return safeD(area(d.points)); + return safeD(area(d.values)); }); dc.transition(layers.select("path.area"), _chart.transitionDuration()) + //.ease("linear") + .attr("fill", colors) .attr("d", function (d) { - return safeD(area(d.points)); + return safeD(area(d.values)); }); } } @@ -190,8 +193,7 @@ dc.lineChart = function (parent, chartGroup) { if (tooltips.empty()) tooltips = chartBody.append("g").attr("class", tooltipListClass); layers.each(function (d, layerIndex) { - var layer = d3.select(this); - var points = layer.datum().points; + var points = d.values; if (_defined) points = points.filter(_defined); var g = tooltips.select("g." + TOOLTIP_G_CLASS + "._" + layerIndex); @@ -199,7 +201,8 @@ dc.lineChart = function (parent, chartGroup) { createRefLines(g); - var dots = g.selectAll("circle." + DOT_CIRCLE_CLASS).data(points); + var dots = g.selectAll("circle." + DOT_CIRCLE_CLASS) + .data(points,dc.pluck('x')); dots.enter() .append("circle") @@ -218,7 +221,7 @@ dc.lineChart = function (parent, chartGroup) { hideDot(dot); hideRefLines(g); }) - .append("title").text(dc.pluck('data', _chart.getTitleOfVisibleByIndex(layerIndex))); + .append("title").text(dc.pluck('data', _chart.title(d.name))); dots.attr("cx", function (d) { return dc.utils.safeNumber(_chart.x()(d.x)); @@ -226,7 +229,7 @@ dc.lineChart = function (parent, chartGroup) { .attr("cy", function (d) { return dc.utils.safeNumber(_chart.y()(d.y + d.y0)); }) - .select("title").text(dc.pluck('data', _chart.getTitleOfVisibleByIndex(layerIndex))); + .select("title").text(dc.pluck('data', _chart.title(d.name))); dots.exit().remove(); }); @@ -321,25 +324,37 @@ dc.lineChart = function (parent, chartGroup) { return _chart; }; + function colorFilter(color,inv) { + return function() { + var item = d3.select(this); + var match = item.attr('stroke') == color || item.attr('fill') == color; + return inv ? !match : match; + }; + } + _chart.legendHighlight = function (d) { if(!_chart.isLegendableHidden(d)) { - _chart.selectAll('.chart-body').selectAll('path').filter(function () { - return d3.select(this).attr('fill') == d.color; - }).classed('highlight', true); - _chart.selectAll('.chart-body').selectAll('path').filter(function () { - return d3.select(this).attr('fill') != d.color; - }).classed('fadeout', true); + _chart.selectAll('path.line, path.area') + .classed('highlight', colorFilter(d.color)) + .classed('fadeout', colorFilter(d.color,true)); + } }; _chart.legendReset = function (d) { - _chart.selectAll('.chart-body').selectAll('path').filter(function () { - return d3.select(this).attr('fill') == d.color; - }).classed('highlight', false); - _chart.selectAll('.chart-body').selectAll('path').filter(function () { - return d3.select(this).attr('fill') != d.color; - }).classed('fadeout', false); + _chart.selectAll('path.line, path.area') + .classed('highlight', false) + .classed('fadeout', false); }; + dc.override(_chart,'legendables', function() { + var legendables = _chart._legendables(); + if (!_dashStyle) return legendables; + return legendables.map(function(l) { + l.dashstyle = _dashStyle; + return l; + }); + }); + return _chart.anchor(parent, chartGroup); }; diff --git a/src/pie-chart.js b/src/pie-chart.js index d0d52ff90..cf174aeff 100644 --- a/src/pie-chart.js +++ b/src/pie-chart.js @@ -380,16 +380,12 @@ dc.pieChart = function (parent, chartGroup) { _chart.legendables = function() { return _chart.data().map(function (d, i) { - var legendable = { name: d.key, data: d.value, others: d.others }; + var legendable = { name: d.key, data: d.value, others: d.others, chart:_chart }; legendable.color = _chart.getColor(d,i); return legendable; }); }; - _chart.getColor = function(d,i) { - return _chart.colorCalculator()(_chart.colorAccessor()(d, i)); - }; - _chart.legendHighlight = function(d) { highlightSliceFromLegendable(d, true); }; diff --git a/src/series-chart.js b/src/series-chart.js index 0d74f856c..6313495fd 100644 --- a/src/series-chart.js +++ b/src/series-chart.js @@ -59,8 +59,7 @@ dc.seriesChart = function (parent, chartGroup) { .dimension(_chart.dimension()) .group({all:d3.functor(sub.values)}, sub.key) .keyAccessor(_chart.keyAccessor()) - .valueAccessor(_chart.valueAccessor()) - .colorCalculator(function() {return subChart.colors()(sub.key);}); + .valueAccessor(_chart.valueAccessor()); }); // this works around the fact compositeChart doesn't really // have a removal interface diff --git a/src/stackable-chart.js b/src/stackable-chart.js index efb7dc60c..273d71703 100644 --- a/src/stackable-chart.js +++ b/src/stackable-chart.js @@ -5,21 +5,46 @@ charts can then selectively mix-in this capability. **/ dc.stackableChart = function (_chart) { - var _groupStack = new dc.utils.GroupStack(); + var _stackLayout = d3.layout.stack() - .offset("zero") - .order("default") - .values(function (d) { - return d.points; - }); - var _allGroups; - var _allValueAccessors; - var _allKeyAccessors; - var _stackLayers; - var _hiddenStacks = []; + .values(prepareValues); + + var _stack = []; + var _titles = {}; var _hidableStacks = false; + function prepareValues(layer, layerIdx) { + var valAccessor = layer.accessor || _chart.valueAccessor(); + layer.name = String(layer.name || layerIdx); + layer.values = layer.group.all().map(function(d,i) { + return {x: _chart.keyAccessor()(d,i), + y: layer.hidden ? null : valAccessor(d,i), + data: d, + layer: layer.name, + hidden: layer.hidden}; + }); + + layer.values = layer.values.filter(domainFilter()); + return layer.values; + } + + function domainFilter() { + if (!_chart.x()) return d3.functor(true); + var xDomain = _chart.x().domain(); + if (_chart.isOrdinal()) { + // TODO #416 + //var domainSet = d3.set(xDomain); + return function(p) { + return true; //domainSet.has(p.x); + }; + } + return function(p) { + //return true; + return p.x >= xDomain[0] && p.x <= xDomain[xDomain.length-1]; + }; + } + /** #### .stack(group[, name, accessor]) Stack a new crossfilter group into this chart with optionally a custom value accessor. All stacks in the same chart will @@ -35,25 +60,28 @@ dc.stackableChart = function (_chart) { **/ _chart.stack = function (group, name, accessor) { - if(!arguments.length) - _groupStack.clear(); - - _groupStack.setDefaultAccessor(_chart.valueAccessor()); + if (!arguments.length) return _stack; - if (typeof name === 'string') { - _chart._setGroupName(group, name, accessor); - _groupStack.addNamedGroup(group, name, accessor); - } - else { + if (arguments.length <= 2) accessor = name; - _groupStack.addGroup(group, accessor); - } - _chart.expireCache(); + var layer = {group:group}; + if (typeof name === 'string') layer.name = name; + if (typeof accessor === 'function') layer.accessor = accessor; + _stack.push(layer); return _chart; }; + dc.override(_chart,'group', function (g,n,f) { + if (!arguments.length) return _chart._group(); + _stack = []; + _titles = {}; + _chart.stack(g,n); + if (f) _chart.valueAccessor(f); + return _chart._group(g,n); + }); + /** #### .hidableStacks([boolean]) Allow named stacks to be hidden or shown by clicking on legend items. @@ -66,6 +94,11 @@ dc.stackableChart = function (_chart) { return _chart; }; + function findLayerByName(n) { + var i = _stack.map(dc.pluck('name')).indexOf(n); + return _stack[i]; + } + /** #### .hideStack(name) Hide all stacks on the chart with the given name. @@ -73,7 +106,8 @@ dc.stackableChart = function (_chart) { **/ _chart.hideStack = function (stackName) { - _groupStack.hideGroups(stackName, _chart._getGroupName(_chart.group()) == stackName); + var layer = findLayerByName(stackName); + if (layer) layer.hidden = true; }; /** @@ -83,167 +117,57 @@ dc.stackableChart = function (_chart) { **/ _chart.showStack = function (stackName) { - _groupStack.showGroups(stackName, _chart._getGroupName(_chart.group()) == stackName); - }; - - _chart.expireCache = function () { - _allGroups = null; - _allValueAccessors = null; - _allKeyAccessors = null; - _stackLayers = null; - return _chart; + var layer = findLayerByName(stackName); + if (layer) layer.hidden = false; }; _chart.allGroups = function () { - if (_allGroups === null) { - _allGroups = []; - - _allGroups.push(_chart.group()); - - for (var i = 0; i < _groupStack.size(); ++i) - _allGroups.push(_groupStack.getGroupByIndex(i)); - } - - return _allGroups; + return _stack.map(dc.pluck('group')); }; _chart.allValueAccessors = function () { - if (_allValueAccessors === null) { - _allValueAccessors = []; - - _allValueAccessors.push(_chart.valueAccessor()); - - for (var i = 0; i < _groupStack.size(); ++i) - _allValueAccessors.push(_groupStack.getAccessorByIndex(i)); - } - - return _allValueAccessors; + return _stack.map(function(layer) { + return layer.accessor || _chart.valueAccessor(); + }); }; - _chart.getValueAccessorByIndex = function (groupIndex) { - return _chart.allValueAccessors()[groupIndex]; + _chart.getValueAccessorByIndex = function (index) { + return _stack[index].accessor || _chart.valueAccessor(); }; _chart.yAxisMin = function () { - var min, all = flattenStack(); - - min = d3.min(all, function (p) { + var min = d3.min(flattenStack(), function (p) { return (p.y + p.y0 < p.y0) ? (p.y + p.y0) : p.y0; }); - min = dc.utils.subtract(min, _chart.yAxisPadding()); + return dc.utils.subtract(min, _chart.yAxisPadding()); - return min; }; _chart.yAxisMax = function () { - var max, all = flattenStack(); - - max = d3.max(all, function (p) { + var max = d3.max(flattenStack(), function (p) { return p.y + p.y0; }); - max = dc.utils.add(max, _chart.yAxisPadding()); - - return max; + return dc.utils.add(max, _chart.yAxisPadding()); }; function flattenStack() { - var all = []; - - if (_chart.x()) { - var xDomain = _chart.x().domain(); - var test; - if(_chart.isOrdinal()) { - var domainSet = d3.set(xDomain); - test = function(p) { - return domainSet.has(p.x); - }; - } - else { - test = function(p) { - return p.x >= xDomain[0] && p.x <= xDomain[xDomain.length-1]; - }; - } - _chart.stackLayers().forEach(function (e) { - e.points.forEach(function (p) { - if (test(p)) - all.push(p); - }); - }); - } else { - _chart.stackLayers().forEach(function (e) { - all = all.concat(e.points); - }); - } - - return all; + return _chart.data().reduce(function(all,layer) { + return all.concat(layer.values); + },[]); } - _chart.allKeyAccessors = function () { - if (_allKeyAccessors === null) { - _allKeyAccessors = []; - - _allKeyAccessors.push(_chart.keyAccessor()); - - for (var i = 0; i < _groupStack.size(); ++i) - _allKeyAccessors.push(_chart.keyAccessor()); - } - - return _allKeyAccessors; - }; - - _chart.getKeyAccessorByIndex = function (groupIndex) { - return _chart.allKeyAccessors()[groupIndex]; - }; - _chart.xAxisMin = function () { - var min = _chart.allGroups().reduce(function(min,group,groupIndex) { - var m = dc.utils.groupMin(group, _chart.getKeyAccessorByIndex(groupIndex)); - return (min === null || min > m) ? m : min; - },null); - + var min = d3.min(flattenStack(), dc.pluck('x')); return dc.utils.subtract(min, _chart.xAxisPadding()); }; _chart.xAxisMax = function () { - var max = _chart.allGroups().reduce(function(max,group,groupIndex) { - var m = dc.utils.groupMax(group, _chart.getKeyAccessorByIndex(groupIndex)); - return (max === null || max < m) ? m : max; - },null); - + var max = d3.max(flattenStack(), dc.pluck('x')); return dc.utils.add(max, _chart.xAxisPadding()); }; - function calculateDataPointMatrix(group, groupIndex) { - group.all().forEach(function(d, dataIndex) { - var key = _chart.getKeyAccessorByIndex(groupIndex)(d); - var value = _chart.getValueAccessorByIndex(groupIndex)(d); - _groupStack.setDataPoint(groupIndex, dataIndex, {data: d, x: key, y: value, layer: groupIndex}); - }); - } - - _chart.calculateDataPointMatrixForAll = function () { - _groupStack.clearDataLayers(); - _chart.allGroups().forEach(calculateDataPointMatrix); - }; - - _chart.getChartStack = function () { - return _groupStack; - }; - - dc.override(_chart, "valueAccessor", function (_) { - if (!arguments.length) return _chart._valueAccessor(); - _chart.expireCache(); - return _chart._valueAccessor(_); - }); - - dc.override(_chart, "keyAccessor", function (_) { - if (!arguments.length) return _chart._keyAccessor(); - _chart.expireCache(); - return _chart._keyAccessor(_); - }); - /** #### .title([stackName], [titleFunction]) Set or get the title function. Chart class will use this function to render svg title (usually interpreted by browser @@ -260,81 +184,64 @@ dc.stackableChart = function (_chart) { var secondTitleFunction = chart.title("second stack"); ); ``` - **/ dc.override(_chart, "title", function (stackName, titleAccessor) { if (!stackName) return _chart._title(); - var firstStack = _chart.group() && stackName === _chart._getGroupName(_chart.group()); + if (typeof stackName === 'function') return _chart._title(stackName); + if (stackName == _chart._groupName && typeof titleAccessor === 'function') + return _chart._title(titleAccessor); - if (typeof stackName === 'function') { - return _chart._title(stackName); - } - else if (!titleAccessor) { - if (firstStack) - return _chart._title(); - else - return _groupStack.getTitle(stackName); - } + if (typeof titleAccessor !== 'function') return _titles[stackName] || _chart._title(); - if (firstStack) - return _chart._title(titleAccessor); - else - _groupStack.setTitle(stackName, titleAccessor); + _titles[stackName] = titleAccessor; return _chart; }); - _chart.getTitleOfVisibleByIndex = function (index) { - return _chart.title(_groupStack.getNameOfVisibleByIndex(index - 1)) || _chart.title(); - }; - _chart.stackLayout = function (stack) { if (!arguments.length) return _stackLayout; _stackLayout = stack; return _chart; }; - _chart.stackLayers = function (_) { - if (!arguments.length) { - if (_stackLayers === null) { - _chart.calculateDataPointMatrixForAll(); - var layers = _groupStack.toLayers(); - if (layers.length === 0) return []; - _stackLayers = _chart.stackLayout()(layers); - } - return _stackLayers; - } else { - _stackLayers = _; - } + function visability(l) { + return !l.hidden; + } + + _chart.data(function() { + // return _stackLayout(_stack); + var layers = _stack.filter(visability); + return layers.length ? _chart.stackLayout()(layers) : []; + }); + + _chart._ordinalXDomain = function() { + return flattenStack().map(dc.pluck('x')); }; - _chart._layerColorAccessor = function(d){return d.layer === undefined ? d.index : d.layer;}; - _chart.colorAccessor(_chart._layerColorAccessor); + _chart.colorAccessor(function(d,i) { + var layer = this.layer || this.name || d.name || d.layer; + return layer; + }); _chart.legendables = function () { - return _chart.allGroups().map(function (g, i) { - return dc.utils.createLegendable(_chart, g, _chart.getValueAccessorByIndex(i), _chart.colorCalculator()(i)); + return _stack.map(function (layer, i) { + return {chart:_chart, name:layer.name, color:_chart.getColor.call(layer,layer.values,i)}; }); }; _chart.isLegendableHidden = function (d) { - return _hiddenStacks.indexOf(d.name) !== -1; + var layer = findLayerByName(d.name); + return layer ? layer.hidden : false; }; _chart.legendToggle = function (d) { if(_hidableStacks) { - var index; - if ((index = _hiddenStacks.indexOf(d.name)) !== -1) { - _hiddenStacks.splice(index, 1); - _chart.showStack(d.name); - } - else { - _hiddenStacks.push(d.name); - _chart.hideStack(d.name); - } + if (_chart.isLegendableHidden(d)) _chart.showStack(d.name); + else _chart.hideStack(d.name); + //_chart.redraw(); + dc.renderAll(_chart.chartGroup()); } - _chart.render(); }; return _chart; diff --git a/src/utils.js b/src/utils.js index 43def71f2..65b3067fe 100644 --- a/src/utils.js +++ b/src/utils.js @@ -31,9 +31,8 @@ dc.printers.filter = function (filter) { }; dc.pluck = function(n,f) { - return function(d,i) { - return f ? f.call(this,d[n],i) : d[n]; - }; + if (!f) return function(d) { return d[n]; }; + return function(d,i) { return f.call(d,d[n],i); }; }; dc.utils = {}; @@ -90,138 +89,6 @@ dc.utils.subtract = function (l, r) { } }; -dc.utils.GroupStack = function () { - var _dataLayers = [[ ]]; - var _groups = []; - var _defaultAccessor; - var _hideChartGroup; - - function initializeDataLayer(i) { - if (!_dataLayers[i]) - _dataLayers[i] = []; - } - - this.setDataPoint = function (layerIndex, pointIndex, data) { - initializeDataLayer(layerIndex); - _dataLayers[layerIndex][pointIndex] = data; - }; - - this.getDataPoint = function (x, y) { - initializeDataLayer(x); - var dataPoint = _dataLayers[x][y]; - if (dataPoint === undefined) - dataPoint = 0; - return dataPoint; - }; - - this.addGroup = function (group, accessor) { - if (!accessor) - accessor = _defaultAccessor; - _groups.push([group, accessor]); - return _groups.length - 1; - }; - - this.addNamedGroup = function (group, name, accessor) { - var groupIndex = this.addGroup(group, accessor); - _groups[groupIndex].name = name; - return name; - }; - - this.getGroupByIndex = function (index) { - return _groups[index][0]; - }; - - this.getAccessorByIndex = function (index) { - return _groups[index][1]; - }; - - this.getNameOfVisibleByIndex = function (index) { - if (index === -1) { - if (_hideChartGroup) index++; - else return; - } - - var visible = _groups.filter(function(group) { - return !group.hidden; - }); - - return visible[index].name; - }; - - this.size = function () { - return _groups.length; - }; - - this.clear = function () { - _dataLayers = []; - _groups = []; - }; - - this.setDefaultAccessor = function (retriever) { - _defaultAccessor = retriever; - }; - - this.getDataLayers = function () { - return _dataLayers; - }; - - this.clearDataLayers = function() { - _dataLayers = [[ ]]; - }; - - this.showGroups = function(name, showChartGroup) { - if (showChartGroup) _hideChartGroup = false; - this.toggleGroups(name, false); - }; - - this.hideGroups = function(name, hideChartGroup) { - if (hideChartGroup) _hideChartGroup = true; - this.toggleGroups(name, true); - }; - - this.toggleGroups = function(name, value) { - for (var i = 0; i < _groups.length; ++i) { - if (_groups[i].name === name) - _groups[i].hidden = value; - } - }; - - this.setTitle = function(name, titleAccessor) { - for (var i = 0; i < _groups.length; ++i) { - if (_groups[i].name === name) - _groups[i].title = titleAccessor; - } - }; - - this.getTitle = function(name) { - for (var i = 0; i < _groups.length; ++i) { - if (_groups[i].name === name) - return _groups[i].title; - } - }; - - this.toLayers = function () { - var layers = []; - - for (var i = 0; i < _dataLayers.length; ++i) { - if (i === 0 && _hideChartGroup) - continue; - if (i > 0 && _groups[i-1].hidden) - continue; - - var layer = {index: i, points: []}; - var dataPoints = _dataLayers[i]; - - for (var j = 0; j < dataPoints.length; ++j) - layer.points.push(dataPoints[j]); - - layers.push(layer); - } - - return layers; - }; -}; - dc.utils.isNumber = function(n) { return n===+n; }; @@ -234,8 +101,8 @@ dc.utils.isInteger = function (n) { return n===+n && n===(n|0); }; -dc.utils.isNegligible = function (max) { - return max === undefined || (max < dc.constants.NEGLIGIBLE_NUMBER && max > -dc.constants.NEGLIGIBLE_NUMBER); +dc.utils.isNegligible = function (n) { + return !dc.utils.isNumber(n) || (n < dc.constants.NEGLIGIBLE_NUMBER && n > -dc.constants.NEGLIGIBLE_NUMBER); }; dc.utils.clamp = function (val, min, max) { @@ -247,18 +114,6 @@ dc.utils.uniqueId = function () { return ++_idCounter; }; -dc.utils.groupMax = function (group, accessor) { - var max = d3.max(group.all(), accessor); - if (dc.utils.isNegligible(max)) max = 0; - return max; -}; - -dc.utils.groupMin = function (group, accessor) { - var min = d3.min(group.all(), accessor); - if (dc.utils.isNegligible(min)) min = 0; - return min; -}; - dc.utils.nameToId = function (name) { return name.toLowerCase().replace(/[\s]/g, "_").replace(/[\.']/g, ""); }; @@ -269,11 +124,4 @@ dc.utils.appendOrSelect = function (parent, name) { return element; }; -dc.utils.createLegendable = function (chart, group, accessor, color) { - var legendable = {name: chart._getGroupName(group, accessor), data: group}; - if (color) legendable.color = color; - if (chart.dashStyle && chart.dashStyle()) legendable.dashstyle = chart.dashStyle(); - return legendable; -}; - dc.utils.safeNumber = function(n){return dc.utils.isNumber(+n)?+n:0;}; diff --git a/test/bar-chart-test.js b/test/bar-chart-test.js index f52fc67cf..bf7e47550 100644 --- a/test/bar-chart-test.js +++ b/test/bar-chart-test.js @@ -797,8 +797,7 @@ suite.addBatch({ return chart; }, 'chart should only render correct number of bars': function (chart) { - // TODO: will be nice to only render what is necessary - only one bar - assert.lengthOf(chart.selectAll("rect.bar")[0], 6); + assert.lengthOf(chart.selectAll("rect.bar")[0], 1); }, 'bar width should be resized accordingly': function (chart) { //console.log(chart.selectAll("rect.bar")[0][0].attr("width")); diff --git a/test/data-addition-test.js b/test/data-addition-test.js index a136b4283..ef7481be4 100644 --- a/test/data-addition-test.js +++ b/test/data-addition-test.js @@ -120,7 +120,7 @@ suite.addBatch({ baseData2.add(json2); chart.render(); - assert.equal(chart.getChartStack().getDataLayers()[0].length, 2); + assert.equal(chart.data()[0].values.length, 2); } } }); diff --git a/test/stackable-chart-test.js b/test/stackable-chart-test.js deleted file mode 100644 index 73b7e6a27..000000000 --- a/test/stackable-chart-test.js +++ /dev/null @@ -1,111 +0,0 @@ -require("./env"); - -var vows = require('vows'); -var assert = require('assert'); - -var suite = vows.describe('Stackable chart'); - -suite.addBatch({ - 'chart stack': { - topic: function () { - return new dc.utils.GroupStack(); - }, - - 'is an object': function (stack) { - assert.isTrue(stack instanceof dc.utils.GroupStack); - }, - 'is a data point matrix holder': function(stack){ - stack.setDataPoint(1, 1, 99); - assert.equal(stack.getDataPoint(1, 1), 99); - }, - 'does not cause error when retrieving uninitialized data point': function(stack){ - assert.equal(stack.getDataPoint(1, 2), 0); - }, - 'be able to add group to stack': function(stack){ - var group = {}; - var index = stack.addGroup(group); - assert.equal(stack.getGroupByIndex(index), group); - assert.equal(stack.size(), 1); - stack.clear(); - }, - 'be able to add group with retriever': function(stack){ - var retriever = {}; - var index = stack.addGroup({}, retriever); - assert.equal(stack.getAccessorByIndex(index), retriever); - assert.equal(stack.size(), 1); - stack.clear(); - }, - 'be able to hide and show stacked groups': function(stack) { - stack.addNamedGroup({}, "first group"); - stack.addNamedGroup({}, "second group"); - - stack.setDataPoint(0, 0, 77); - stack.setDataPoint(1, 0, 55); - stack.setDataPoint(2, 0, 33); - stack.hideGroups("first group"); - - var layers = stack.toLayers(); - assert.equal(layers.length, 2); - assert.equal(layers[0].points[0], 77); - assert.equal(layers[1].points[0], 33); - - stack.showGroups("first group"); - - assert.equal(stack.toLayers().length, 3); - - stack.clear(); - }, - 'be able to hide and show the main group': function(stack) { - stack.addNamedGroup({}, "first group"); - stack.addNamedGroup({}, "second group"); - - stack.setDataPoint(0, 0, 77); - stack.setDataPoint(1, 0, 55); - stack.setDataPoint(2, 0, 33); - stack.hideGroups("main group", true); - - var layers = stack.toLayers(); - assert.equal(layers.length, 2); - assert.equal(layers[0].points[0], 55); - assert.equal(layers[1].points[0], 33); - - stack.showGroups("main group", true); - - assert.equal(stack.toLayers().length, 3); - - stack.clear(); - }, - 'should use default retriever if custom retriever is missing': function(stack){ - var retriever = {}; - stack.setDefaultAccessor(retriever); - var index = stack.addGroup({}); - assert.equal(stack.getAccessorByIndex(index), retriever); - stack.clear(); - }, - 'should be able to get visible stack names by index': function (stack) { - stack.addNamedGroup({}, "first group"); - stack.addNamedGroup({}, "second group"); - stack.hideGroups("first group"); - assert.equal(stack.getNameOfVisibleByIndex(0), "second group"); - stack.clear(); - }, - 'should be able to get and set title accessor functions by name': function(stack) { - var firstTitle = function() {}; - var secondTitle = function() {}; - stack.addNamedGroup({}, "first group"); - stack.addNamedGroup({}, "second group"); - - stack.setTitle("first group", firstTitle); - stack.setTitle("second group", secondTitle); - - assert.equal(stack.getTitle("first group"), firstTitle); - assert.equal(stack.getTitle("second group"), secondTitle); - - stack.clear(); - } - } -}); - -suite.export(module); - - diff --git a/test/web-renders/stock.html b/test/web-renders/stock.html index 468335a54..d65d02a8a 100644 --- a/test/web-renders/stock.html +++ b/test/web-renders/stock.html @@ -207,7 +207,7 @@

Nasdaq 100 Index 1985/11/01-2012/06/29

- 11/01/1985 + 11/01/1985 121.0012/01/1985 130.0001/01/1986 131.0002/01/1986 diff --git a/web/examples/composite.html b/web/examples/composite.html index 8d4cc1954..45952dd8d 100644 --- a/web/examples/composite.html +++ b/web/examples/composite.html @@ -37,13 +37,13 @@ var chart1 = dc.lineChart() .dimension(dim) - .colors(['red']) + .colors('red') .group(grp1, "Top Line") .dashStyle([2,2]); var chart2 = dc.lineChart() .dimension(dim) - .colors(['blue']) + .colors('blue') .group(grp2, "Bottom Line") .dashStyle([5,5]); diff --git a/web/play-ground.html b/web/play-ground.html index af52887be..9b87b1828 100644 --- a/web/play-ground.html +++ b/web/play-ground.html @@ -6,15 +6,12 @@ - - - + + +