在调整大小时重新创建D3多折线图(响应)

时间:2018-11-29 12:03:59

标签: javascript d3.js

为了具有响应性的D3多折线图,我添加了一个调整大小的功能,尽管该功能被调用,但它似乎不起作用:

  var data = [{
    Date: "2016-10-10",
    ValueOne: 1,
    ValueTwo: 0
  }, {
    Date: "2016-10-17",
    ValueOne: 23,
    ValueTwo: 2
  }, {
    Date: "2016-10-24",
    ValueOne: 32,
    ValueTwo: 17
  }, {
    Date: "2016-10-31",
    ValueOne: 57,
    ValueTwo: 40
  }, {
    Date: "2016-11-07",
    ValueOne: 74,
    ValueTwo: 56
  }];


var  margin = {top: 10, right: 50, bottom: 100, left: 50},
// Set default width and height
    widther = (window.innerWidth),
    width = widther - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;

    
// Determine current size, which determines vars
function set_vars() {

    var width = window.innerWidth - margin.left - margin.right,
        height = 500 - margin.top - margin.bottom;
        
}

function drawGraphic() {

    var svg = d3.select('#charts')
      .append('svg')
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
      .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    //Parses date for correct time format
    var formatTime = d3.timeFormat("%Y-%m-%d");

    data.forEach(function(d) {
      d.Date = new Date(d.Date)
    });

    var valueOneData = data.map(function(d) {
      return {
        date: d.Date,
        value: d.ValueOne
      }
    });

    var valueTwoData = data.map(function(d) {
      return {
        date: d.Date,
        value: d.ValueTwo
      }
    });

    var xScale = d3.scaleTime()
      .range([0, width])
      .domain(d3.extent(data, function(d) {
        return d.Date
      }));

    var yScale = d3.scaleLinear()
      .range([height, 0])
      .domain([0, d3.max(data, function(d) {
        return d.ValueOne
      }) * 1.05]);

    var lineGenerator = d3.line()
      .x(function(d) {
        return xScale(d.date)
      })
      .y(function(d) {
        return yScale(d.value)
      });

    var gX = svg.append("g")
      .attr("transform", `translate(0,${height})`)
      .call(d3.axisBottom(xScale).tickFormat(function(d) {
        return formatTime(d)
      }).tickValues(data.map(function(d) {
        return d.Date
      })))
      .selectAll("text")
      .style("text-anchor", "end")
      .attr("transform", "rotate(-65)")
      .attr("y", 4)
      .attr("x", -10)
      .attr("dy", ".35em");

    var gY = svg.append("g")
      .call(d3.axisLeft(yScale));

    var valueOneLine = svg.append("path")
      .datum(valueOneData)
      .attr("d", lineGenerator)
      .style("fill", "none")
      .style("stroke", "#124");

    var valueTwoLine = svg.append("path")
      .datum(valueTwoData)
      .attr("d", lineGenerator)
      .style("fill", "none")
      .style("stroke", "#c7003b");

  //RESPONSIVENESS ATTEMPT NO1
  d3.select(window).on("resize", resized);

}

//Resize function
function resized() {
    d3.select("svg").remove();
    set_vars();
    drawGraphic();
    console.log("FUNCTION IS BEING CALLED")
}

set_vars();
drawGraphic();

 //RESPONSIVENESS ATTEMPT NO2
 window.addEventListener("resize", function(){ d3.select("svg").remove(); set_vars(); drawGraphic(); });
<script src="https://d3js.org/d3.v4.min.js"></script>
<div id="charts"></div>

在代码段中,我尝试了两种方法来做到这一点。他们都没有使图表从头开始重新创建。此jsfiddle中也存在相同的问题。

1 个答案:

答案 0 :(得分:1)

问题在于每次调整窗口大小时都会解析数据。

第一次解析数据中的日期时,调用parseDate(d.date)的其他所有调用都会失败,因为它已经被解析为有效日期。你懂吗?

因此,移动解析代码,使其仅执行一次:

// parse data just once
data.forEach(function(d) {
  d.date = parseDate(d.date);
  d.value = +d.value;
});

中部链接:https://jsfiddle.net/a5rqt0L1/

建议:我觉得这不是制作响应式图表的正确方法,例如,删除SVG并重新添加到主体,并且所有配置都要进行多次。这是我的处理方式:

  1. 解析数据,将svg附加初始高度和宽度,将X,Y轴附加一次一次,但将drawBars(绘制实际的条形图)移动到将使用的单独函数d3自己的输入,退出和更新选择逻辑。
  2. 在调整窗口大小时,只需更改SVG的高度和宽度,通过.call(xAxis)...重新渲染轴,然后调用drawBars函数即可。

希望这会有所帮助。