将缩放行为从v3更新为v5

问题描述 投票:3回答:1

我面临的问题是由于版本不匹配,我无法在我的代码中编写以下函数。代码是

var zoom = d3.behavior.zoom()
.x(x)
.y(y)
.scaleExtent([1, 10])
.on("zoom", zoomed);

我试过这种方式

  const zoom = d3.zoom()
  .scaleExtent([1, 4])
  .x(this.xScale)
  .on('zoom', () => {})

但它对我不起作用。

如何在d3版本5中编写相同的功能?我想使用d3版本5使折线图在x轴上滚动,y轴为固定位置

这是我的实施基本代码

    private createLineChart() {
    this.width = 2000 - this.margin.left - this.margin.right;
    this.height = 600 - this.margin.top - this.margin.bottom;

// X AXIS
this.xScale = d3.scaleBand()
  .domain(this.dataset[0].fluencyData.map((data) => {
    return new Date(data.date);
  }))
  .range([0, this.width]);

// Y AXIS
this.yScale = d3.scaleLinear()
  .domain([0, 110])
  .range([this.height, 0]);

// Line Generator
this.line = d3.line()
  .x((data) => this.xScale(new Date(data.date)))
  .y((data) => this.yScale(data.wcpm));
// .curve(d3.curveMonotoneX);

// Add SVG to Div
this.svg = d3.select('#displayChart').append('svg')
  .attr('preserveAspectRatio', 'xMinYMin meet')
  .attr(
    'viewBox',
    '0 0 ' +
    (this.width + this.margin.left + this.margin.right) +
    ' ' +
    (this.height + this.margin.top + this.margin.bottom))
  // .attr('width', this.width + this.margin.left + this.margin.right)
  // .attr('height', this.height + this.margin.top + this.margin.bottom)
  .append('g')
  .attr('transform', 'translate(' + this.margin.left + ',' + this.margin.top + ')');

// Define the div for the tooltip
this.toolTipDiv = d3.select('#displayChart').append('div')
  .attr('class', 'tooltip')
  .style('opacity', 0);

// Append XAXIS to the SVG
this.svg.append('g')
  .attr('class', 'xAxis')
  .attr('transform', 'translate(0,' + this.height + ')')
  .call(d3.axisBottom(this.xScale).tickSizeOuter(0).tickFormat(d3.timeFormat('%b %d')));

const zoom = d3.zoom()
  .scaleExtent([1, 4])
  .extent([100, 100], [this.width - 100, this.height - 100])
  .x(this.xScale)
  .on('zoom', () => {
    console.log(d3.event.transform);
    // this.svg.select('#displayChart').attr('d', this.line);
  });
this.svg.call(zoom);

// Append YAXIS to SVG
this.svg.append('g')
  .attr('class', 'yAxis')
  .call(d3.axisLeft(this.yScale).tickSize(-this.width)
  );

// Make a Path for Dataset
this.svg.append('path')
  .datum(this.dataset[0].fluencyData)
  .attr('class', 'line')
  .attr('d', this.line)
  .attr('transform', 'translate(' + this.margin.left + ',0)');

// Text Heading of DATE in chart
this.svg.append('text')
  .attr('transform', 'translate(' + (-20) + ',' + (this.height + 13) + ')')
  .attr('dy', '.35em')
  .attr('class', ' xAxis')
  .text('Date');
 }
 }

我得到的错误是

LineChartComponent_Host.ngfactory.js? [sm]:1 ERROR TypeError: d3__WEBPACK_IMPORTED_MODULE_2__.zoom(...).scaleExtent(...).x is not a function
    at LineChartComponent.push../src/app/line-chart/line-chart.component.ts
d3.js charts zoom
1个回答
3
投票

使用d3v3和之前,缩放可以跟踪比例的状态。从文档中,scale.x():“指定x缩放,其缩放时应自动调整域。” (docs)。这会修改原始比例。

D3v4 +没有zoom.x或zoom.y方法。

使用d3v4 +时,变焦不会跟踪或修改d3刻度的状态。事实上,对于d3v4 +,缩放行为甚至不跟踪当前缩放状态:“缩放行为不再在内部存储活动缩放变换(即可见区域;缩放和平移)。缩放变换现在存储在任何缩放变换中已应用缩放行为的元素。(change log)“。

作为其中的一部分,更重要的是,“缩放行为不再依赖于比例,但您可以使用transform.rescaleX,transform.rescaleY,transform.invertX或transform.invertY来转换比例域(change log)”。

因此,我们需要自己做这个,而不是让缩放更新d3比例。最常见的方法是通过参考比例保持不变,以及我们应用缩放变换的比例:

var zoom = d3.zoom()
  .on("zoom",zoomed)

var x = d3.scaleLinear()....   // working scale
var x2 = x.copy(); // reference scale.

function zoomed() {
  x = d3.event.transform.rescaleX(x2) // update the working scale.
  // do something...
}

所以,像这样:

var x = d3.scale.linear()
  .domain([0,1])
  .range([0,500]);

var zoom = d3.behavior.zoom()
.x(x)
.scaleExtent([1, 10])
.on("zoom", zoomed);

var svg = d3.select("svg")
  .call(zoom);
  
var axis = d3.svg.axis()
   .orient("bottom")
   .scale(x);
  
var axisG = svg.append("g")
    .attr("transform", "translate(0,30)")
    .call(axis);
  
function zoomed() {
   axisG.call(axis);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>

<svg width="500" height="200"></svg>

变成这样的东西:

var x = d3.scaleLinear()
  .domain([0,1])
  .range([0,500]);
var x2 = x.copy(); // reference.

var zoom = d3.zoom()
  .scaleExtent([1, 10])
  .on("zoom", zoomed);

var svg = d3.select("svg")
  .call(zoom);
  
var axis = d3.axisBottom().scale(x)
  
var axisG = svg.append("g")
    .attr("transform", "translate(0,30)")
    .call(axis);
  
function zoomed() {
   x = d3.event.transform.rescaleX(x2)
   axis.scale(x);
   axisG.call(axis);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

<svg width="500" height="200"></svg>

请注意,d3.event.transform.rescaleX用于连续比例 - 您有一个序数带比例,因此我们需要对波段和/或点比例使用略微修改的方法:

var x = d3.scaleBand()
  .domain(d3.range(10).map(function(d) { return d/10; }))
  .range([0,500]);
var x2 = x.copy(); // reference.

var zoom = d3.zoom()
  .scaleExtent([1, 10])
  .on("zoom", zoomed);

var svg = d3.select("svg")
  .call(zoom);
  
var axis = d3.axisBottom().scale(x)
  
var axisG = svg.append("g")
    .attr("transform", "translate(0,30)")
    .call(axis);
  
function zoomed() {
   // Rescale the range of x using the reference range of x2.
   x.range(x2.range().map(function(d) {
     return d3.event.transform.applyX(d);
   }))
   axisG.call(axis);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

<svg width="500" height="200"></svg>

这是带/点尺度解决方案基于this issue和Bostock提出的解决方案

© www.soinside.com 2019 - 2024. All rights reserved.