带ZOOM的D3多系列折线图

时间:2017-01-11 12:49:15

标签: javascript d3.js

在这里为新手问题道歉。我尝试使用在线影响因素(基本上绘制多行)的一些数据重现此示例https://bl.ocks.org/mbostock/3884955,但使用滚动缩放以隔离部分数据。听起来很简单,但我似乎无法让它发挥作用!

< svg width = "960"
height = "500" > < /svg>
<script src="/ / d3js.org / d3.v4.min.js "></script>
<script>

var svg = d3.select("svg"),
    margin = {top: 20, right: 80, bottom: 30, left: 100},
    width = svg.attr("width") - margin.left - margin.right,
    height = svg.attr("height") - margin.top - margin.bottom,
    g = svg.append("g").attr("transform ", "translate(" + margin.left +
          ", " + margin.top + ")"); 

var zoom = d3.zoom()
    .scaleExtent([1, 32])
    .translateExtent([[0, 0], [width, height]])
    .extent([[0, 0], [width, height]])
    .on("zoom", zoomed);

var xAxis = d3.axisBottom(x),
    yAxis = d3.axisLeft(y);

var parseTime = d3.timeParse(" % d / % m / % Y ");

var x = d3.scaleTime().range([0, width]),
    y = d3.scaleLinear().range([height, 0]),
    z = d3.scaleOrdinal(d3.schemeCategory10);

var line = d3.line()
    .curve(d3.curveBasis)
    .x(function(d) { return x(d.date); })
    .y(function(d) { return y(d.engagement); });

d3.csv("stack2.csv", type, function(error, data) {
  if (error) throw error;

  var influencers = data.columns.slice(1).map(function(id) {
    return {
      id: id,
      values: data.map(function(d) {
        return {date: d.date, engagement: d[id]};
      })
    };
  });


  x.domain(d3.extent(data, function(d) { return d.date; }));

  y.domain([d3.min(influencers, function(c) { 
       return d3.min(c.values, function(d) { 
           return d.engagement; }); }),
 d3.max(influencers, function(c) { 
       return d3.max(c.values, function(d) { 
           return d.engagement; }); })
  ]);

  z.domain(influencers.map(function(c) { return c.id; }));

  g.append("g")
      .attr("class", "axis axis--x")
      .attr("transform", "translate(0, " + height + ")")
      .call(d3.axisBottom(x));

  g.append("g")
      .attr("class", "axis axis--y")
      .call(d3.axisLeft(y))
    .append("text")
      .attr("transform", "rotate(-90)")
      .attr("y", 5)
      .attr("dy", "0.71em")
      .attr("fill", "#000")
      .text("Engagement");

 var influ = g.selectAll(".influ")
  .data(influencers)
  .enter().append("g")
  .attr("class", "influ");

influ.append("path")
  .attr("class", "line")
  .attr("d", function(d) {
    return line(d.values);
  })
  .style("stroke", "lightgrey")
  .on("mouseover", function(d, i) {
    d3.select(this).transition()
      .style("stroke", function(d) {
        return z(d.id);
      })
      .style("stroke-width", 3)
    console.log(d.id);
  })
  .on("mouseout", function(d) {
    d3.select(this).transition()
      .style("stroke", "lightgrey")
      .style("stroke-width", 1)
  })


influ.append("text")
  .datum(function(d) {
    return {
      id: d.id,
      value: d.values[d.values.length - 1]
    };
  })
  .attr("transform", function(d) {
    return "translate(" + x(d.value.date) + "," + y(d.value.engagement) + ")";
  })
  .attr("x", 3)
  .attr("dy", ".35em")
  .style("opacity", 0.7)
  .style("font", "10px sans-serif")
  .text(function(d) {
    return d.id;
  });

svg.call(zoom)

});

function type(d, _, columns) {
  d.date = parseTime(d.date);
  for (var i = 1, n = columns.length, c; i < n; ++i) d[c = columns[i]] = +d[c];
  return d;
}

function zoomed() {
  var t = d3.event.transform,
    xt = t.rescaleX(x);
  g.selectAll("path.line").attr("d", function(d) {
    return xt(d.date);
  });
  g.select(".axis--x").call(xAxis.scale(xt));
}

< /script>

我认为问题与这部分有关:

function zoomed() {
  var t = d3.event.transform,
    xt = t.rescaleX(x);
  g.selectAll("path.line").attr("d", function(d) {
    return xt(d.date);
  });
  g.select(".axis--x").call(xAxis.scale(xt));
}

Axis缩放很好,但我不认为我正确地调用了折线图的数据。我认为g.selectAll肯定会选择这些行,因为它们会在滚动时消失...所以我假设.attr("d", function(d) {return xt(d.date);是错误的。有人有任何提示吗?

2 个答案:

答案 0 :(得分:1)

我在几天前写的交互式折线图D3图中使用了这些线条。我已经广泛评论过,所以它应该是非常自我解释的。这非常有效并且没有错误。

function zoomed() {
  lastEventTransform = d3.event.transform;

  // Rescale axes using current zoom transform
  gX.call(xAxis.scale(lastEventTransform.rescaleX(x)));
  gY.call(yAxis.scale(lastEventTransform.rescaleY(y)));

  // Create new scales that incorporate current zoom transform on original scale
  var xt = lastEventTransform.rescaleX(x),
      yt = lastEventTransform.rescaleY(y);

  // Apply new scale to create new definition of d3.line method for path drawing of line plots
  var line = d3.line()
      .x(function(d) { return xt(d.x); })
      .y(function(d) { return yt(d.y); });

  // Update all line-plot elements with new line method that incorporates transform
  innerSvg.selectAll(".line")
      .attr("d", function(d) { return line(d.values); });

  // Update any scatter points if you are also plotting them
  innerSvg.selectAll(".dot")
      .attr("cx", function(d) {return xt(d.x); })
      .attr("cy", function(d) {return yt(d.y); });
}

注意:gXgY只是d3 g组元素,这些元素在设置绘图时最初会调用它们。

答案 1 :(得分:0)

此缩放功能欺骗域更改,然后重新绘制新域上的行。它是我现在可以管理的最好的......但不是很优雅!

function zoomed() {
  var t = d3.event.transform;
  // var t = d3.event.scaleBy;
  var xt = t.rescaleY(y);
  domain = yAxis.scale().domain();
  g.select(".axis--y").call(yAxis.scale(xt));

  g.selectAll("path.line").attr("d", function(d) { 
    if ( d3.max(d.values.map(function(dd) { return dd.engagement } )) > domain[1] ) {
      return null
    }
    else {
      return line(d.values)
    }
   });



  if (domain[1] > 50000000) {
    max = 50000000
  } else if ( domain[1] < 500 ) {
    max = 500
  } else {
    max = domain[1]
  }

  y.domain([0, max]);
}

它可以缩放,但它很容易将轴与线条分开。如果有人有更好的东西让我知道!

相关问题