Stacked Area Chart in nvd3js - X Axis overflow

前端 未结 1 849
一个人的身影
一个人的身影 2021-01-05 06:11

I am trying to implement a \'Stacked Area Chart\' with d3js and nvd3.js similar to this example. Additionally, I\'d like to use a context brush like this one to select a dat

相关标签:
1条回答
  • 2021-01-05 06:53

    Change .clipEdge(false); to .clipEdge(true); in your chart settings.

    Edit

    Okay, I've managed to recreate your problem on the NVD3 live code site with the following code (data and markup the same as their stacked graph example):

    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;
    });
    

    Which is basically what you are doing -- creating a completely new chart function, and calling it on the same container. The chart function mostly selects all the same objects, and changes their attributes -- resulting in the smooth transition. But, the random id code it gives to the <clipPath> element (to ensure that each element has a unique id) no longer matches up with the one it uses as the "clip-path" attribute. You could call this a bug in the NVD3 code, but it is also partly because you are using the function 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;
    });
    

    The clipping paths still work nicely. Notice the difference? Instead of creating and calling an entire new chart function, I have just updated the chart function with the new domain, and called the function's update() method. Try re-arranging your brushing function to do the update that way, and not only should you fix your clipping path problem, but your code should be faster as well.

    Edit 2

    So how to implement this with your original code?

    First, you need to save the chart-function object created within nv.addGraph() into a variable that can be accessed by your brushed() function.

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

    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
    }
    
    0 讨论(0)
提交回复
热议问题