nvd3js中的堆积面积图 - X轴溢出 [英] Stacked Area Chart in nvd3js - X Axis overflow

查看:634
本文介绍了nvd3js中的堆积面积图 - X轴溢出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用类似于使用以下代码(数据和标记与其堆叠图示例相同):

  nv.addGraph (function(){
var chart = nv.models.stackedAreaChart()
.x(function(d){return d [0]})
.y return d [1]})
.clipEdge(true);

var chart2 = nv.models.stackedAreaChart()
.x(function(d){return d [0]})
.y 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;
});

基本上你正在做什么 - 创建一个全新的图表函数,同一个容器。图表函数主要选择所有相同的对象,并更改其属性 - 导致平滑过渡。但是,它赋予< clipPath> 元素(以确保每个元素都有唯一的id)的随机ID代码不再与它用作剪辑路径属性。你可以把它称为NVD3代码中的一个错误,但它也部分是因为你以意想不到的方式使用该函数。



相反,如果我使用这个代码:

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

剪切路径仍然可以正常工作。注意区别?不是创建和调用整个新的图表函数,我只是更新了图表函数与新的域,并调用函数的 update()方法。尝试重新安排你的刷牙功能来做更新,不仅应该修复你的剪切路径问题,但你的代码应该更快。



2 >

那么如何使用原始代码实现这个呢?



首先,在 nv.addGraph()中创建一个可以通过 brushed()函数访问的变量。 / p>

然后,在 brushed()函数中,修改保存的图表函数以应用新的x域,然后调用函数对象的更新方法。

  var margin = {
top:10,
right:20,
bottom:100,
left:20
},width = 960,height = 300;

var chart; // NEW!声明一个可以被
//初始化和更新函数访问的变量

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!novarstatement!
//这被分配给上面声明的图表变量

/ *图表初始化代码的其余部分,与之前相同* /

});
}

/ *所有时间线刷新的初始化代码在这里,直到:* /

function brushed(){
var b = brush.empty()? x.domain():brush.extent();
console.log(b);
time_range = b;

chart.xDomain(b); //修改保存的图表对象
chart.update(); //使用保存的函数更新图表
}


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 date range, which effects the Stacked Area Chart. Actually, this is already working 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 have a look on the following picture:

Here is my code:

Stacked Area Chart

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 ]  
  ]
}
]

Thank you.

解决方案

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
}

这篇关于nvd3js中的堆积面积图 - X轴溢出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆