Folded area in nvd3js - X axis overflow

I am trying to implement a “broken cell table” with d3js and nvd3.js similar to this example . In addition, I would like to use a context brush, such as this one , to select a date range that affects the diagram of the folded area. Actually, this already works, but somehow it draws some lines on top of the Y-axis as soon as the selected date range does not contain the first date. Just look at the following image: This is the bug

Here is my code:

Paginated table

var margin = { top : 10, right : 20, bottom : 100, left : 20 }, width = 960, height = 300; var svg_stack = d3.select("#stack").append("svg").attr("width", width + margin.left + margin.right).attr("height", (height + margin.top + margin.bottom)); function initStackChart() { nv.addGraph(function() { var chart = nv.models.stackedAreaChart().x(function(d) { return Date.parse(new Date(d[0])) }).y(function(d) { return d[1] }).clipEdge(false); chart.xAxis.tickFormat(function(d) { return d3.time.format('%x')(new Date(d)) }); chart.yAxis.tickFormat(d3.format(',.2f')); if (!!time_range) { chart.xDomain([time_range[0], time_range[1]]); } d3.select('#stack svg').datum(temp_data).transition().duration(100).call(chart); nv.utils.windowResize(chart.update); return chart; }); } 

Brush

 var margin = {top: 10, right: 20, bottom: 0, left: 20}, width = 960, height = 50; var contextHeight = 50; contextWidth = width; var parseDate = d3.time.format("%Y-%m-%d").parse; var x = d3.time.scale().range([0, width]), y = d3.scale.linear().range([contextHeight, 0]); var xAxis = d3.svg.axis().scale(x).tickSize(contextHeight).tickPadding(-10).orient("bottom"); var brush = d3.svg.brush() .x(x) .on("brush", brushed); var area2 = d3.svg.area() .interpolate("monotone") .x(function(d) { return x(d.time); }) .y0(contextHeight) .y1(0); var svg_brush = d3.select("#brush").append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom); svg_brush.append("defs").append("clipPath") .attr("id", "clip") .append("rect") .attr("width", width) .attr("height", height); var context = svg_brush.append("g").attr("class","context") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); function initBrush(data) { x.domain(d3.extent(data.map(function(d) { return d.time; }))); context.append("g") .attr("class", "x axis top") .attr("transform", "translate(0,0)") .call(xAxis); context.append("g") .attr("class", "x brush") .call(brush) .selectAll("rect") .attr("y", 0) .attr("height", contextHeight); }; function brushed() { var b = brush.empty() ? x.domain() : brush.extent(); console.log(b); time_range=b; initStackChart(); } 

Data

 var temp_data = [ { key: "Node0", values: [ [ 1364795940000, 10 ], [ 1365020480000, 30 ], [ 1365630480000, 30 ], [ 1366000480012, 30 ], [ 1366012740000, 0 ] ] }, { key: "Node1", values: [ [ 1364795940000, 10 ], [ 1365020480000, 20 ], [ 1365630480000, 34 ], [ 1366000480012, 82 ], [ 1366012740000, 0 ] ] }, { key: "Node2", values: [ [ 1364795940000, 20 ], [ 1365020480000, 10 ], [ 1365630480000, 0 ], [ 1366000480012, 100 ], [ 1366012740000, 80 ] ] }, { key: "Node3", values: [ [ 1364795940000, 10 ], [ 1365020480000, 60 ], [ 1365630480000, 10 ], [ 1366000480012, 10 ], [ 1366012740000, 10 ] ] }, { key: "Node4", values: [ [ 1364795940000, 16 ], [ 1365020480000, 32 ], [ 1365630480000, 10 ], [ 1366000480012, 90 ], [ 1366012740000, 10 ] ] }, { key: "Node5", values: [ [ 1364795940000, 10 ], [ 1365020480000, 50 ], [ 1365630480000, 10 ], [ 1366000480012, 20 ], [ 1366012740000, 110 ] ] }, { key: "Node6", values: [ [ 1364795940000, 19 ], [ 1365020480000, 55 ], [ 1365630480000, 32 ], [ 1366000480012, 12 ], [ 1366012740000, 12 ] ] }, { key: "Node7", values: [ [ 1364795940000, 0 ], [ 1365020480000, 20 ], [ 1365630480000, 40 ], [ 1366000480012, 30 ], [ 1366012740000, 20 ] ] }, { key: "Node8", values: [ [ 1364795940000, 12 ], [ 1365020480000, 31 ], [ 1365630480000, 40 ], [ 1366000480012, 20 ], [ 1366012740000, 15 ] ] }, { key: "Node9", values: [ [ 1364795940000, 10 ], [ 1365020480000, 35 ], [ 1365630480000, 50 ], [ 1366000480012, 30 ], [ 1366012740000, 90 ] ] } ] 

Thanks.

+7
javascript date
source share
1 answer

Change .clipEdge(false); on .clipEdge(true); in the chart settings.

Edit

Well, I was able to recreate your problem on the NVD3 open source site with the following code (the data and markup are the same as their stacked graphs):

 nv.addGraph(function() { var chart = nv.models.stackedAreaChart() .x(function(d) { return d[0] }) .y(function(d) { return d[1] }) .clipEdge(true); var chart2 = nv.models.stackedAreaChart() .x(function(d) { return d[0] }) .y(function(d) { return d[1] }) .xDomain([1096516800000, 1270008000000]) .clipEdge(true); chart.xAxis .showMaxMin(false) .tickFormat(function(d) { return d3.time.format('%x')(new Date(d)) }); chart.yAxis .tickFormat(d3.format(',.2f')); chart2.xAxis .showMaxMin(false) .tickFormat(function(d) { return d3.time.format('%x')(new Date(d)) }); chart2.yAxis .tickFormat(d3.format(',.2f')); d3.select('#chart svg') .datum(data) .transition().duration(500).call(chart) .transition().delay(3000).duration(500) .call(chart2); nv.utils.windowResize(chart.update); return chart2; }); 

This is basically what you do - creating a completely new chart function and calling it in one container. The chart function basically selects all the same objects and changes their attributes, which leads to a smooth transition. But the random id code that it provides to the <clipPath> element (to ensure that each element has a unique identifier) ​​no longer matches the one that it uses as the clip path attribute. You may call this a bug in the NVD3 code, but also in part because you use this feature in unexpected ways.

In contrast, if I use this code:

 nv.addGraph(function() { var chart = nv.models.stackedAreaChart() .x(function(d) { return d[0] }) .y(function(d) { return d[1] }) .clipEdge(true); chart.xAxis .showMaxMin(false) .tickFormat(function(d) { return d3.time.format('%x')(new Date(d)) }); chart.yAxis .tickFormat(d3.format(',.2f')); var svg = d3.select('#chart svg') .datum(data) .transition().duration(500).call(chart); nv.utils.windowResize(chart.update); var change = window.setTimeout(function(){ chart.xDomain([1096516800000, 1270008000000]); chart.update(); }, 3000); return chart; }); 

Clipping paths still work well. Pay attention to the difference? Instead of creating and calling the entire new chart function, I just updated the chart function with a new domain and called the update() method. Try reinstalling the brush function to make the update this way, and you should not only fix the clipping path problem, but your code should be faster.

Edit 2

So how to implement this with your source code?

First, you need to save the chart function object created in nv.addGraph() to a variable that can be accessed using the brushed() function.

Then in your brushed() function, you modify the saved chart function to apply the new x-domain, and then you call the update method of the function object.

 var margin = { top : 10, right : 20, bottom : 100, left : 20 }, width = 960, height = 300; var chart; // NEW! declare a variable that can be accessed by both // initialization and update functions var svg_stack = d3.select("#stack") .append("svg") .attr("width", width + margin.left + margin.right) .attr("height", (height + margin.top + margin.bottom)); function initStackChart() { nv.addGraph(function() { chart = nv.models.stackedAreaChart() // NEW! no "var" statement! // this gets assigned to the chart variable declared above /* rest of chart initialization code, the same as before */ }); } /* All the initialization code for the timeline brushing goes here, until: */ function brushed() { var b = brush.empty() ? x.domain() : brush.extent(); console.log(b); time_range=b; chart.xDomain(b); //modify the saved chart object chart.update(); //update the chart using the saved function } 
+5
source share

All Articles