d3缩放平移到折线图的特定区域 [英] d3 zoom pan to specific region of line graph

查看:48
本文介绍了d3缩放平移到折线图的特定区域的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我看到了许多有关基于单击事件进行缩放和平移的教程和资源,但是我有一个折线图,希望用户能够基于与某些数据范围对齐的单击按钮来放大.>

[具体来说:该图是使用所有数据启动的,但是当用户单击1、2或3时,会使用某种效果,表明他们正在缩放".成为图的子集]

我尝试在下面的代码中使用转换,但看起来有点不方便.我想我想要更接近自动缩放/平移的东西来传达按钮在飞"动.您到图表中的特定区域.

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

  function getFilteredData(data,group){console.log(组)如果(组=== 4){返回数据} 别的 {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))//设置图形的尺寸和边距var margin = {顶部:10,右侧:30,底部:30,左侧:50},宽度= 700-margin.left-margin.right,高度= 400-margin.top-margin.bottom;//将svg对象附加到页面主体var svg = d3.select(#my_dataviz").append("svg").attr("width",width + margin.left + margin.right).attr("height",高度+ margin.top + margin.bottom).append("g").attr("transform","translate(" + margin.left +," + margin.top +)");//初始化X轴: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")//初始化Y轴var y = d3.scaleLinear().range([height,0]);var yAxis = d3.axisLeft().scale(y);svg.append("g").attr("class","myYaxis")//创建Y轴y.domain([0,d3.max(data3,function(d){return d.ser2})]));svg.selectAll(.myYaxis").过渡().duration(1000).call(yAxis);//创建一个将数据集作为输入并更新绘图的函数:函数更新(数据){//创建X轴: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);//创建更新选择:绑定到新数据var u = svg.selectAll(.lineTest").data([data],function(d){return d.ser1});//更新该行ü.进入().append(路径").attr("class","lineTest").merge(u).过渡().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)}//首先,我在第一个数据集上运行update函数:update(data3) 

  .mayabtn {左边距: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))">全部</button><!-创建将要在其中进行图形绘制的div->< div id ="my_dataviz"></div>  

解决方案

一种可能的方法是:

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

由于线条已经绘制,因此x.domain()更改时,它只会左右移动.这样可以提供所需的缩放效果.

  function getFilteredData(data,group){console.log(组)如果(组=== 4){返回数据} 别的 {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);})//设置图形的尺寸和边距var margin = {顶部:10,右侧:30,底部:30,左侧:50},宽度= 700-margin.left-margin.right,高度= 400-margin.top-margin.bottom;//将svg对象附加到页面主体var svg = d3.select(#my_dataviz").append("svg").attr("width",width + margin.left + margin.right).attr("height",高度+ margin.top + margin.bottom).append("g").attr("transform","translate(" + margin.left +," + margin.top +)");svg.append("defs").append("clipPath").attr("id",图表路径").append("rect").attr("width",width).attr("height",height);//初始化X轴:var x = d3.scaleLinear().range([0,width]);var xAxis = d3.axisBottom().scale(x);svg.append("g").attr("transform","translate(0," + height +)").attr("class","myXaxis")//初始化Y轴var y = d3.scaleLinear().range([height,0]);var yAxis = d3.axisLeft().scale(y);svg.append("g").attr("class","myYaxis")//创建Y轴y.domain([0,d3.max(data3,function(d){return d.ser2})]));svg.selectAll(.myYaxis").过渡().duration(1000).call(yAxis);//创建更新选择:绑定到新数据var u = svg.selectAll(.lineTest").data([data3]).进入().append(路径").attr("class","lineTest").attr("fill","none").attr("stroke","steelblue").attr("stroke-width",2.5).attr("clip-path","url(#chart-path)");//创建一个将数据集作为输入并更新绘图的函数:函数更新(数据){//创建X轴:x.domain(d3.extent(data,function(d){return d.ser1}));svg.selectAll(.myXaxis").过渡().duration(1000).call(xAxis);u.transition().duration(1000).attr("d",line);}//首先,我在第一个数据集上运行update函数:update(data3) 

  .mayabtn {左边距: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))">全部</button><!-创建将要在其中进行图形绘制的div->< div id ="my_dataviz"></div>  

I see a lot of tutorials and resources for zooming and panning based on click events, but I have a line graph that I want the user to be able to zoom into based on clicking buttons which align with certain data ranges.

[Specifically: the graph is initiated using all data, but when the user clicks on either 1, 2, or 3 use some effect that shows they're "zooming" into a subset of the graph]

I tried using a transform in the code below but it looks a little wonky. I think I want something closer to an automatic zoom/pan to convey that the buttons are "flying" you to certain region within the graph.

I've attached my code below but was wondering how to achieve this effect? Any help appreciated!

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>

解决方案

One possible way would be the following:

  • Don't change the datum object of the line, so you always plot the entire spectrum;
  • Change the x.domain(), however, and then re-draw the line;
  • Use a clipPath element to avoid the line from overflowing.

Because the line has already been drawn, it will just be moved left and right when the x.domain() changes. This gives the desired zoom effect.

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>

这篇关于d3缩放平移到折线图的特定区域的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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