ele*_*119 4 javascript zooming d3.js reactjs
我有一个以时间为 X 轴的简单图表。预期行为是在图形中拖动时,X 轴只会平移以显示数据的其他部分。
为了方便起见,因为我的X轴是在反应组分中,创建我的图表的函数设置X标尺,x轴,并且元件被附接到为this.xScale
,this.xAxis
,和this.gX
,分别。
如果我将其设置为缩放方法的内容,则一切正常:
this.gX.call(this.xAxis.scale(d3.event.transform.rescaleX(this.xScale)))
Run Code Online (Sandbox Code Playgroud)
X 轴随着触摸输入平滑移动。但是,这对我不起作用,因为稍后当我更新图表时(移动数据点以响应轴的变化),我需要this.xAxis
进行更改,以便点将映射到不同的位置。
所以,我然后将我的缩放方法的内容设置为:
this.xScale = d3.event.transform.rescaleX(this.xScale);
this.xAxis = this.xAxis.scale(this.xScale);
this.gX.call(this.xAxis);
Run Code Online (Sandbox Code Playgroud)
据我所知,这应该以完全相同的方式运行。但是,当我使用此代码时,即使没有运行我的updateChart()
函数(更新数据点),X 轴在平移时也会不规则地缩放,比正常情况要多得多。我的 X 轴是基于时间的,所以突然间从 2014 年到 2018 年的时域包括了 1920 年代初期。
我究竟做错了什么?
当您使用 scale.rescaleX 时,您正在修改基于当前缩放变换(基于平移和缩放)的缩放域。
但是,从返回的变换d3.event.transfrom
不是前一个缩放变换的变化,它代表了累积变换。我们想在我们的原始比例上应用这个变换,因为变换代表了原始状态的变化。但是,您是在由先前缩放变换修改的比例上应用此累积变换:
this.xScale = d3.event.transform.rescaleX(this.xScale);
Run Code Online (Sandbox Code Playgroud)
让我们研究一下它在平移事件(例如平移)期间的作用:
这有效,但如果我们再次平移:
为什么?因为缩放变换会跟踪相对于初始状态的缩放状态,但您希望仅使用状态变化来更新比例,而不是缩放变换的累积变化。因此,此时域已经移动了 30 个单位,但用户只平移了 20 个。
同样的事情发生在规模上:
在第四步,d3.event.transform.k == 4
rescaleX 现在将比例缩放四倍,它不“知道”比例已经被缩放了两倍。
如果我们继续应用缩放,情况会变得更糟,例如,如果我们从 k=4 缩小到 k=2,d3.event.transform.k == 2
尽管尝试缩小,我们仍然放大 2 倍,现在我们处于 16 倍:2x4x2。如果我们放大,我们会得到 64x (2x4x8)
这种效果在平移上尤其糟糕 - 甚至在整个平移事件中都会不断触发缩放,因此缩放会在已经累积应用缩放变换的缩放上累积重新应用。平移可以轻松触发数十个缩放事件。在下面的比较片段中,尽管起始域是 2014-2018 年,但稍微平移就可以轻松将您带入 1920 年代。
纠正此问题的最简单方法(以及规范方法)与您在代码中使用的用于平移(但不更新)的方法非常相似:
this.gX.call(this.xAxis.scale(d3.event.transform.rescaleX(this.xScale)))
Run Code Online (Sandbox Code Playgroud)
我们在这里做什么?我们正在创建一个新的规模,同时保持原来的相同 - d3.event.transform.rescaleX(this.xScale)
。我们为轴提供新的比例。但是,正如您所注意到的,在更新图形时遇到问题时,xScale
不是轴使用的比例,因为我们现在有两个不同的比例。
解决方案是使用我所说的参考比例和工作比例。参考比例将用于根据当前缩放变换更新工作比例。每当创建/更新轴或点时都将使用工作比例。一开始,两个比例可能是相同的,所以我们可以这样创建比例:
var xScale = d3.scaleLinear().domain(...).range(...) // working
var xScaleReference = xScale.copy(); // reference
Run Code Online (Sandbox Code Playgroud)
我们可以像往常一样使用 xScale 更新或放置元素。
在缩放时,我们可以更新 xScale(和轴):
xScale = d3.event.transform.rescaleX(xScaleReference)
xAxis.scale(xScale);
selection.call(xAxis);
Run Code Online (Sandbox Code Playgroud)
这是一个比较,它与您注意到的域具有相同的域,但是很快就可以到达 1920 年代的上层(使用一个比例)。底部更符合预期(并使用工作和参考比例):
this.xScale = d3.event.transform.rescaleX(this.xScale);
Run Code Online (Sandbox Code Playgroud)
this.gX.call(this.xAxis.scale(d3.event.transform.rescaleX(this.xScale)))
Run Code Online (Sandbox Code Playgroud)
我们可以在 Mike Bostock 的示例中看到相同的方法,例如这个Brush 和 zoom,其中 x2 和 y2 代表参考比例,x 和 y 代表工作比例。
归档时间: |
|
查看次数: |
1037 次 |
最近记录: |