d3缩放:滚动轴在滚动上,拖动轴在拖动上,缩放轴在捏上

亚历克斯·莱指甲

我希望将绘图的缩放行为配置为具有三种交互方式:

  • 应该可以使用滚轮从左向右平移。
  • 使用mousedown拖动事件,应该可以从左向右平移。
  • 应该可以在出现捏事件的情况下放大一维(例如,按下控制键的滚轮)。

现在,我可以使后两个在此Fiddle中工作:https : //jsfiddle.net/s1t7mrpw/6/

缩放功能如下所示:

function zoomed() {

  if (d3.event.sourceEvent.ctrlKey || d3.event.sourceEvent.type === 'mousemove') {

    view.attr("transform", d3.event.transform);
    centerline.call(xAxis.scale(d3.event.transform.rescaleX(x)));
    d3.event.transform.y = 0;
    g.attr("transform", d3.event.transform);

  } else {

    current_transform = d3.zoomTransform(view);
    current_transform.x = current_transform.x - d3.event.sourceEvent.deltaY;

    // what do I do here to pan the axis and update `view`'s transform? 
    // centerline.call(xAxis.scale(d3.event.transform.rescaleX(x))); ? 
    // view.attr('transform', current_transform); ? 

    g.attr('transform', current_transform);
  }
}

它使用来自以下块的重新缩放术语:

并且它使用d3-xyzoom在x和y方向上进行独立缩放。

但是else当用户只是滚动(不按控制键)时,我不知道如何平移支架中的轴

我以前曾为它使用单独的触发器,wheel.zoom但随后我还需要处理其他功能中的控制键。

我基本上想要的是mousemove当按下控制键时的默认缩放行为,但是在未按下控制键时平移而不是在滚动时缩放。

安德鲁·里德(Andrew Reid)

我在此答案上使用d3-zoom,因为它更常见并且是d3捆绑包的一部分。d3-xyzoom作为一个附加模块,以d3-zoom为基础添加了一些有用的功能,因此此解决方案应与带有较小修订的xyzoom一起使用-但我认为没有必要使用它

关键挑战在于使用滚轮来应用平移更改而不是比例更改。粗略地说,当发生无控制的滚动事件时,您可以抓住所选内容的转换(应该是节点),并通过获取滚动并为其创建x偏移量来更新它以平移视图矩形。但是,您不会更新zoomTransform来抵消由缩放引起的缩放变化-因此,当您通过拖动进行平移时,矩形会更改大小,因为尚未更新缩放行为所使用的zoomTransform。同样,如果不考虑缩放比例,则可以关闭转换。

应用于元素的缩放变换(作为“变换”属性)与缩放行为所跟踪的缩放变换之间的分离是SO上许多麻烦的原因-但它允许更自由的实现选项,因为不需要使用元素的transform属性即可应用缩放行为(在画布中很有用,对非正统的事物(例如颜色)进行缩放等)。

我将在这里提出一个基本的解决方案。

首先,可以通过修改d3.event.transform对象本身(或在d3.zoomTransform(selection.node)其中选择是最初调用缩放的选择的位置)来更新由缩放行为跟踪的缩放变换

其次,当d3.event.transform对象注册为按比例滚动时,我们需要覆盖此比例,并在需要时将此比例转换为平移。为此,我们需要跟踪当前(事件前)的翻译和缩放比例-因此我们可以手动对其进行修改:

// Keep track of zoom state:
var k = 1;   
var tx = 0;

function zoomed() {
  var t = d3.event.transform;

  // If control is not pressed and a wheel was turned, set the scale to last known scale, and modify transform.x by some amount:
  if(!d3.event.sourceEvent.ctrlKey && d3.event.sourceEvent.type == "wheel") {
    t.k > k ? tx += 40/k : tx -= 40/k;
    t.k = k;
    t.x = tx;
  }
  // otherwise, proceed as normal, but track current k and tx:
  else {
    k = t.k;
    tx = t.x;
  }

  // Apply the transform:
  view.attr("transform", "translate("+[t.x,0]+")scale("+[t.k,1]+")");
  axisG.call(xAxis.scale(t.rescaleX(xScale)));

}

上面,我修改了转轮/滚动应转换的事件的变换tk和tk。通过将tk与存储的k值进行比较,我可以确定方向:通常是缩小还是放大事件,然后可以将其转换为当前转换值的变化。通过将tk设置回原始的k值,我可以停止发生比例缩放的更改。

对于其他缩放事件,与往常一样,除了,我存储tx和tk值以备以后轮转事件发生时使用,而不是缩放。

注意:我已经设置了y缩放比例,并在转换中将其转换为硬编码零,因此我们完全不必担心y分量。

var width = 500;
var height = 120;

// Keep track of zoom state:
var k = 1; 
var tx = 0;

// Some text to show the transform parameters:
var p = d3.select("body")
  .append("p");  

// Nothing unordinary here:
var svg = d3.select("body")
   .append("svg")
   .attr("width",width)
   .attr("height",height);
   
var xScale = d3.scaleLinear()
  .domain([0,100])
  .range([20,width-20])
  
var xAxis = d3.axisTop(xScale);

var axisG = svg.append("g")
  .attr("transform","translate(0,50)")
  .call(xAxis);
  
var view = svg.append("rect")
  .attr("width", 20)
  .attr("height",20)
  .attr("x", width/2)
  .attr("y", 60)

var zoom = d3.zoom()
  .on("zoom",zoomed);
  
svg.call(zoom)


function zoomed() {
  var t = d3.event.transform;

  // If control is not pressed and a wheel was turned, set the scale to last known scale, and modify transform.x by some amount:
  if(!d3.event.sourceEvent.ctrlKey && d3.event.sourceEvent.type == "wheel") {
	t.k > k ? tx += 40/k : tx -= 40/k;
	t.k = k;
	t.x = tx;
  }
  // otherwise, proceed as normal, but track current k and tx:
  else {
	k = t.k;
	tx = t.x;
  }
  
  // Apply the transform:
  view.attr("transform", "translate("+[t.x,0]+")scale("+[t.k,1]+")");
  axisG.call(xAxis.scale(t.rescaleX(xScale)));
  
  // Show current zoom transform:
  p.text("transform.k:" + t.k + ", transform.x: " + t.x);

}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.6.0/d3.min.js"></script>

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章