ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

d3 v5轴比例更改摇摄方式太多

2019-12-10 21:38:07  阅读:382  来源: 互联网

标签:reactjs d3-js zoom javascript


我有一个简单的图表,其中时间作为X轴.预期的行为是,在拖动图形时,X轴只会平移以显示数据的其他部分.

为了方便起见,由于我的X轴位于react组件中,因此创建我的图表的函数将X比例尺,x轴及其附加的元素分别设置为this.xScale,this.xAxis和this.gX. .

如果将其设置为我的zoom方法的内容,则一切正常:

        this.gX.call(this.xAxis.scale(d3.event.transform.rescaleX(this.xScale)))

X轴通过触摸输入平滑移动.但是,这对我不起作用,因为稍后在更新图表时(响应轴的变化而移动数据点)时,我需要更改this.xAxis,以便将这些点映射到不同的位置.

因此,然后将我的zoom方法的内容设置为此:

        this.xScale = d3.event.transform.rescaleX(this.xScale);
        this.xAxis = this.xAxis.scale(this.xScale);
        this.gX.call(this.xAxis);

据我所知,这应该完全相同.但是,当我使用此代码时,即使不运行我的updateChart()函数(更新数据点),平移时X轴也会按比例缩放,这比正常情况大得多.我的X轴基于时间,因此从2014年到2018年的时域突然包括1920年代初.

我究竟做错了什么?

解决方法:

问题

使用scale.rescaleX时,您将基于当前的缩放变换(基于平移和缩放)来修改缩放的域.

但是,从d3.event.transfrom返回的变换不是上一个缩放变换的变化,它表示累积变换.我们要在原始比例上应用此变换,因为该变换表示相对于原始状态的更改.但是,您正在按先前的缩放变换修改的比例应用此累积变换:

     this.xScale = d3.event.transform.rescaleX(this.xScale);

让我们研究一下翻译事件(例如平移)期间的操作:

>向右平移10个单位
>将比例尺的范围移动10个单位.

那行得通,但是如果我们再次平移:

>向右平移10个单位
>将刻度域再移动20个单位.

为什么?因为缩放变换跟踪相对于初始状态的缩放状态,但是您只想用状态变化而不是缩放变换的累积变化来更新比例.因此,此时域已移动30个单位,但用户只能平移20个单位.

规模也会发生同样的事情:

>在图形中心放大2倍(缩放变换比例= 2)
>重新缩放比例,使其具有一半的范围(是详细信息的两倍)
>在图形中心再次放大2倍(缩放变换比例= 4)
>重新缩放比例,使其具有当前域的四分之一(已经是原始域的一半,因此我们现在放大8倍:2×4).

在第四步,d3.event.transform.k == 4,并且rescaleX现在将比例缩放为4倍,它并不“知道”该缩放比例已经被缩放为2倍.

如果我们继续应用缩放,甚至会变得更糟,例如,如果我们从k = 4缩小到k = 2,d3.event.transform.k == 2,尽管尝试缩小,我们仍在放大2倍,现在我们是16x:2x4x2.相反,如果我们放大,则得到64x(2x4x8)

这种效果在平移上尤其糟糕-在平移事件中始终会连续触发缩放,因此,缩放比例将在已累计应用缩放转换的缩放比例上重新应用.平移可以轻松触发数十个缩放事件.在下面的比较代码段中,尽管起始位置为2014-2018,但平移一下就可以轻松将您带入1920年代.

更正此问题的最简单方法(以及规范方法)与您在代码中用于平移(但不能更新)的方法非常相似:

 this.gX.call(this.xAxis.scale(d3.event.transform.rescaleX(this.xScale)))

我们在这里做什么?我们正在创建一个新的比例尺,同时保持原始比例尺-d3.event.transform.rescaleX(this.xScale).我们向轴提供新的比例尺.但是,正如您注意到的那样,在更新图形时遇到问题,xScale并不是轴使用的比例,因为我们现在有两个不同的比例.

解决的办法是使用我所说的参考量表和工作量表.参考比例将用于基于当前缩放变换更新工作比例.每当创建/更新轴或点时,都将使用工作刻度.最初,两个比例尺可能是相同的,因此我们可以这样创建比例尺:

var xScale = d3.scaleLinear().domain(...).range(...) // working
var xScaleReference = xScale.copy();                 // reference

像往常一样,我们可以使用xScale更新或放置元素.

缩放时,我们可以使用以下命令更新xScale(和轴):

xScale = d3.event.transform.rescaleX(xScaleReference)
xAxis.scale(xScale);
selection.call(xAxis);

这是一个比较,它具有与您所注意到的相同的域,但是很快就可以到达高音阶的1920年代(使用一个音阶).底部比预期的要多得多(并使用工作和参考比例):

var svg = d3.select("body")
  .append("svg")
  .attr("width", 400)
  .attr("height", 200);

var parseTime = d3.timeParse("%Y")
 
 
var start = parseTime("2014");
var end = parseTime("2018");
 
///////////////////
// Single scale updated by zoom transform:
var a = d3.scaleTime()
  .domain([start,end])
  .range([20,380])
  
var aAxis = d3.axisBottom(a).ticks(5);

var aAxisG = svg.append("g")
  .attr("transform","translate(0,30)")
  .call(aAxis);

/////////////////
// Reference and working scale:
var b = d3.scaleTime()
  .domain([start,end])
  .range([20,380])
  
var bReference = b.copy();

var bAxis = d3.axisBottom(b).ticks(5);
  
var bAxisG = svg.append("g")
  .attr("transform","translate(0,80)")
  .call(bAxis);

/////////////////
// Zoom:
var zoom = d3.zoom()
  .on("zoom", function() {
    a = d3.event.transform.rescaleX(a);
    b = d3.event.transform.rescaleX(bReference);
    
    aAxisG.call(aAxis.scale(a));
    bAxisG.call(bAxis.scale(b));


})

svg.call(zoom);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

我们可以看到与Mike Bostock的示例(例如brush and zoom)所采用的方法相同,其中x2和y2代表参考比例,x和y代表工作比例.

标签:reactjs,d3-js,zoom,javascript
来源: https://codeday.me/bug/20191210/2104313.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有