【问题标题】:d3 zoom pan to specific region of line graphd3缩放平移到折线图的特定区域
【发布时间】:2020-11-07 15:52:37
【问题描述】:

我看到很多关于基于点击事件进行缩放和平移的教程和资源,但我有一个折线图,我希望用户能够根据与特定数据范围对齐的点击按钮进行放大。

[具体来说:图表是使用所有数据启动的,但是当用户点击 1、2 或 3 时,会使用一些效果来显示他们正在“放大”到图表的子集]

我尝试在下面的代码中使用转换,但它看起来有点不稳定。我想我想要更接近自动缩放/平移的东西来传达按钮正在“飞”你到图表中的某个区域。

我在下面附上了我的代码,但想知道如何实现这个效果?任何帮助表示赞赏!

function getFilteredData(data, group) {
  console.log(group)
  if (group === 4) {
    return data
  } else {
    return data.filter(function (point) { return point.group === parseInt(group); });
  }
}

var data3 = [
  { group: 1, ser1: 1, ser2: 3 },
  { group: 1, ser1: 2, ser2: 5 },
  { group: 1, ser1: 3, ser2: 9 },
  { group: 1, ser1: 4, ser2: 3 },
  { group: 1, ser1: 5, ser2: 5 },
  { group: 1, ser1: 6, ser2: 9 },
  { group: 2, ser1: 7, ser2: 10 },
  { group: 2, ser1: 8, ser2: 9 },
  { group: 2, ser1: 9, ser2: 10 },
  { group: 2, ser1: 10, ser2: 20 },
  { group: 2, ser1: 11, ser2: 10 },
  { group: 2, ser1: 12, ser2: 12 },
  { group: 3, ser1: 13, ser2: 20 },
  { group: 3, ser1: 14, ser2: 12 },
  { group: 3, ser1: 15, ser2: 4 },
  { group: 3, ser1: 16, ser2: 22 },
  { group: 3, ser1: 17, ser2: 2 },
  { group: 3, ser1: 18, ser2: 4 },
]

var studio = [
  { x: 0, y: 8 },
  { x: 18, y: 8 }
]

var line = d3.line()
  .x(d => x(d.x))
  .y(d => y(d.y))

// set the dimensions and margins of the graph
var margin = { top: 10, right: 30, bottom: 30, left: 50 },
  width = 700 - margin.left - margin.right,
  height = 400 - margin.top - margin.bottom;

// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
  .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 + ")");

// Initialise a X axis:
var x = d3.scaleLinear().range([0, width - 100]);
var xAxis = d3.axisBottom().scale(x);
svg.append("g")
  .attr("transform", "translate(0," + height + ")")
  .attr("class", "myXaxis")

// Initialize an Y axis
var y = d3.scaleLinear().range([height, 0]);
var yAxis = d3.axisLeft().scale(y);
svg.append("g")
  .attr("class", "myYaxis")

// create the Y axis
y.domain([0, d3.max(data3, function (d) { return d.ser2 })]);
svg.selectAll(".myYaxis")
  .transition()
  .duration(1000)
  .call(yAxis);

// Create a function that takes a dataset as input and update the plot:
function update(data) {

  // Create the X axis:
  x.domain([d3.min(data, function (d) { return d.ser1 }), d3.max(data, function (d) { return d.ser1 })]);
  svg.selectAll(".myXaxis").transition()
    .duration(1000)
    .call(xAxis);

  // Create a update selection: bind to the new data
  var u = svg.selectAll(".lineTest")
    .data([data], function (d) { return d.ser1 });

  // Update the line
  u
    .enter()
    .append("path")
    .attr("class", "lineTest")
    .merge(u)
    .transition()
    .duration(1000)
    .attr("d", d3.line()
      .x(function (d) { return x(d.ser1); })
      .y(function (d) { return y(d.ser2); }))
    .attr("fill", "none")
    .attr("stroke", "steelblue")
    .attr("stroke-width", 2.5)

}

// At the beginning, I run the update function on the first dataset:
update(data3)
.mayabtn {
  margin-left: 30px;
}
<script src="https://d3js.org/d3.v5.js"></script>
<button onclick="update(getFilteredData(data3, 1))" class="mayabtn">1.0</button>
<button onclick="update(getFilteredData(data3, 2))">2.0</button>
<button onclick="update(getFilteredData(data3, 3))">3.0</button>
<button onclick="update(getFilteredData(data3, 4))">All</button>

<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>

【问题讨论】:

    标签: d3.js


    【解决方案1】:

    一种可能的方法如下:

    • 不要更改线的基准对象,因此您始终绘制整个光谱;
    • 不过改x.domain(),然后重新画线;
    • 使用clipPath 元素避免行溢出。

    因为这条线已经画好了,所以当 x.domain() 改变时,它只会左右移动。这会产生所需的缩放效果。

    function getFilteredData(data, group) {
      console.log(group)
      if (group === 4) {
        return data
      } else {
        return data.filter(function (point) { return point.group === parseInt(group); });
      }
    }
    
    var data3 = [
      { group: 1, ser1: 1, ser2: 3 },
      { group: 1, ser1: 2, ser2: 5 },
      { group: 1, ser1: 3, ser2: 9 },
      { group: 1, ser1: 4, ser2: 3 },
      { group: 1, ser1: 5, ser2: 5 },
      { group: 1, ser1: 6, ser2: 9 },
      { group: 2, ser1: 7, ser2: 10 },
      { group: 2, ser1: 8, ser2: 9 },
      { group: 2, ser1: 9, ser2: 10 },
      { group: 2, ser1: 10, ser2: 20 },
      { group: 2, ser1: 11, ser2: 10 },
      { group: 2, ser1: 12, ser2: 12 },
      { group: 3, ser1: 13, ser2: 20 },
      { group: 3, ser1: 14, ser2: 12 },
      { group: 3, ser1: 15, ser2: 4 },
      { group: 3, ser1: 16, ser2: 22 },
      { group: 3, ser1: 17, ser2: 2 },
      { group: 3, ser1: 18, ser2: 4 },
    ]
    
    var studio = [
      { x: 0, y: 8 },
      { x: 18, y: 8 }
    ]
    
    var line = d3.line()
      .x(function (d) { return x(d.ser1); })
      .y(function (d) { return y(d.ser2); })
    
    // set the dimensions and margins of the graph
    var margin = { top: 10, right: 30, bottom: 30, left: 50 },
      width = 700 - margin.left - margin.right,
      height = 400 - margin.top - margin.bottom;
    
    // append the svg object to the body of the page
    var svg = d3.select("#my_dataviz")
      .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 + ")");
    
    svg.append("defs")
      .append("clipPath")
      .attr("id", "chart-path")
      .append("rect")
      .attr("width", width)
      .attr("height", height);
    
    // Initialise a X axis:
    var x = d3.scaleLinear().range([0, width]);
    var xAxis = d3.axisBottom().scale(x);
    svg.append("g")
      .attr("transform", "translate(0," + height + ")")
      .attr("class", "myXaxis")
    
    // Initialize an Y axis
    var y = d3.scaleLinear().range([height, 0]);
    var yAxis = d3.axisLeft().scale(y);
    svg.append("g")
      .attr("class", "myYaxis")
    
    // create the Y axis
    y.domain([0, d3.max(data3, function (d) { return d.ser2 })]);
    svg.selectAll(".myYaxis")
      .transition()
      .duration(1000)
      .call(yAxis);
    
    // Create a update selection: bind to the new data
    var u = svg.selectAll(".lineTest")
      .data([data3])
      .enter()
      .append("path")
      .attr("class", "lineTest")
      .attr("fill", "none")
      .attr("stroke", "steelblue")
      .attr("stroke-width", 2.5)
      .attr("clip-path", "url(#chart-path)");
    
    // Create a function that takes a dataset as input and update the plot:
    function update(data) {
    
      // Create the X axis:
      x.domain(d3.extent(data, function (d) { return d.ser1 }));
      svg.selectAll(".myXaxis")
        .transition()
        .duration(1000)
        .call(xAxis);
      u.transition()
        .duration(1000)
        .attr("d", line);
    }
    
    // At the beginning, I run the update function on the first dataset:
    update(data3)
    .mayabtn {
      margin-left: 30px;
    }
    <script src="https://d3js.org/d3.v5.js"></script>
    <button onclick="update(getFilteredData(data3, 1))" class="mayabtn">1.0</button>
    <button onclick="update(getFilteredData(data3, 2))">2.0</button>
    <button onclick="update(getFilteredData(data3, 3))">3.0</button>
    <button onclick="update(getFilteredData(data3, 4))">All</button>
    
    <!-- Create a div where the graph will take place -->
    <div id="my_dataviz"></div>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-06-28
      • 1970-01-01
      • 1970-01-01
      • 2016-02-08
      • 1970-01-01
      • 2016-06-17
      • 1970-01-01
      • 2014-07-13
      相关资源
      最近更新 更多