使 D3.js 2D 图表具有响应性

Posted

技术标签:

【中文标题】使 D3.js 2D 图表具有响应性【英文标题】:Make D3.js 2D graph chart responsive 【发布时间】:2016-07-22 21:00:47 【问题描述】:

首先,我想明确表示我确实通过了***中发布的以下链接:

Resize svg when window is resized in d3.js

以下是 jsfiddle 和代码的链接: https://jsfiddle.net/adityap16/d61gtadm/8/

代码-

var data = [
"mytime": "2015-12-01T11:10:00.000Z", "value": 64,
"mytime": "2015-12-01T11:15:00.000Z", "value": 67,
"mytime": "2015-12-01T11:20:00.000Z", "value": 70,
"mytime": "2015-12-01T11:25:00.000Z", "value": 64,
"mytime": "2015-12-01T11:30:00.000Z", "value": 72,
"mytime": "2015-12-01T11:35:00.000Z", "value": 75,
"mytime": "2015-12-01T11:40:00.000Z", "value": 71,
"mytime": "2015-12-01T11:45:00.000Z", "value": 80
];
var parseDate = d3.time.format("%Y-%m-%dT%H:%M:%S.%LZ").parse;

data.forEach(function(d) 
          d.mytime = parseDate(d.mytime);
        );
//var margin =  top: 30, right: 30, bottom: 40, left:50 ,
var margin =  top: 30, right: 30, bottom: 40, left:50 ,
height = 200,
width = 800;
var color =  "green";
var xaxis_param = "mytime";
var yaxis_param = "value"
var params1 =  margin:margin,height:height,width:width, color: color, xaxis_param:xaxis_param, yaxis_param :yaxis_param;
draw_graph(data,params1);




function  draw_graph(data,params)


    //Get the margin 
    var xaxis_param = params.xaxis_param;
    var yaxis_param = params.yaxis_param;
    var color_code = params.color;
    var margin = params.margin;
    var height = params.height - margin.top - margin.bottom,
        width = params.width - margin.left - margin.right;

    var x_extent = d3.extent(data, function(d)
        return d[xaxis_param]);
    var y_extent = d3.extent(data, function(d)
        return d[yaxis_param]);

    var x_scale = d3.time.scale()
        .domain(x_extent)
        .range([0,width]);


    var y_scale = d3.scale.linear()
        .domain([0,y_extent[1]])
        .range([height,0]);



    //Line
    var lineGen = d3.svg.line()
        .x(function (d) 
            return x_scale(d[xaxis_param]);
        )
        .y(function (d) 
            return y_scale(d[yaxis_param]);
        );
    var myChart = d3.select('body').append('svg')
                    .attr('class','my-chart')
                    .style('background', '#E7E0CB')
                    .attr('width', width + margin.left + margin.right)
                    .attr('height', height + margin.top + margin.bottom)
                    .append('g')
                    .attr('transform', 'translate('+ margin.left +', '+ margin.top +')');
            myChart
                    .append('svg:path')
                    .datum(data)
                    .attr('class', 'line')
                    .attr("d",lineGen)
                    .attr('stroke', color_code)
                    .attr('stroke-width', 1)
                    .attr('fill', 'none');


    var legend = myChart.append("g")
          .attr("class", "legend")
          .attr("transform", "translate(" + 5 + "," + (height - 25) + ")")

        legend.append("rect")
          .style("fill", color_code)
          .attr("width", 20)
          .attr("height", 20);

        legend.append("text")
          .text(yaxis_param)
          .attr("x", 25)
          .attr("y", 12);

    var vGuideScale = d3.scale.linear()
        .domain([0,y_extent[1]])
        .range([height, 0])

    var vAxis = d3.svg.axis()
        .scale(vGuideScale)
        .orient('left')
        .ticks(5)


    var hAxis = d3.svg.axis()
        .scale(x_scale)
        .orient('bottom')
        .ticks(d3.time.minute, 5);

  myChart.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(hAxis);

  myChart.append("g")
      .attr("class", "y axis")
      .call(vAxis)



票数最高的解决方案讨论了定义类并使其在 css 文件中响应。当我尝试以这种方式定义它时,代码返回“未定义宽度”错误。我认为这是因为轴和其他元素是根据可变宽度计算的。我能想出的唯一可行的解​​决方案是:

var screenWidth =  window.innerWidth;
screenWidth = screenWidth - 0.5*screenWidth;

但在此之后,每当调整窗口大小时,我都必须调用 d3.select(window).on('resize', resize);并将我的代码放入 resize() 函数中。我对 javascript 和 d3 很陌生,所以我可能在已经发布的解决方案中遗漏了一些东西。谢谢。

【问题讨论】:

我从您的链接问题中获取了最佳答案并将其应用于您的图表here 嗨@mar​​k,jsfiddle 没有显示完整的数据。如果您注意到它只显示到 11:35 的数据,而数据是到 11:45。谢谢! 我的错,视图框大小需要与初始图大小匹配:jsfiddle.net/d61gtadm/11 嘿,谢谢@mark。我能够弄清楚,但现在我被这个问题困住了***.com/questions/36428423/… 【参考方案1】:

我强烈推荐以下关于名为 Building Responsive Visualizations in D3 的博客文章。它提供了一个很好的最终结果,并且相当优雅地将您从一个大图表一直带到一个迷你图。

我不想从文章中复制/粘贴大量代码,但为了确保这不是链接,只回答主要步骤是:

监听窗口resize事件:

d3.select(window).on('resize', function() 

);

抓取容器的高度/宽度

let width = parseInt(d3.select(container).style("width"));
let height= parseInt(d3.select(container).style("height"));

设置任意比例的范围并重新渲染

xAxisScale.range([0, width]);
yAxisScale.range([height, 0]);

d3.select(".x-axis").attr("transform", "translate(" + [0, height] + ")").call(xAxis);
d3.select(".y-axis").call(yAxis);

如果需要火花线,请隐藏轴

if(width < 500 || height < 500) 
    d3.select(".x-axis").style("display", "none");
    d3.select(".y-axis").style("display", "none");


除此之外,您还可以添加一些额外的内容,例如在您的迷你图上添加乞求/结束值之类的文章,并在点数大大超过您的宽度时重新采样您的数据以达到合理的分辨率。

【讨论】:

感谢您的回复!。我会尝试并告诉你。 嘿,我无法集成调整大小功能,你能在工作示例中帮助我吗?再次感谢! @AdityaPatel 您需要更加具体。为什么不能集成呢? 感谢您的回复。因此,如果您在我的代码中注意到,我调用了一个 draw_graph 函数,我应该在这个函数内部还是外部调用 resize 函数。当我尝试将它放在函数中并出于某种原因编写代码时。我的图表仍然没有反应。以下是它的 jsfiddle jsfiddle.net/adityap16/L1Lq868s/1 @AdityaPatel 你的 jsfiddle 正在选择 #graph 而不是包含元素。因此,您正在阅读图表的现有宽度/高度。在您的resize 函数中,将两个parseInt(d3.select("#graph") 更改为parseInt(d3.select("body"),它将按预期工作。

以上是关于使 D3.js 2D 图表具有响应性的主要内容,如果未能解决你的问题,请参考以下文章

如何使流图响应式(d3.js)?

Vega 图表 - 如何使图表具有响应性

如何使 D3.js 中的强制布局图响应屏幕/浏览器大小

在 React 应用程序中使 D3 图表具有响应性

使 d3.js 可视化布局响应的最佳方法是啥?

D3.js系列——交互式操作和布局