创建人工缩放变换事件

T3d*_*b0t 5 javascript d3.js

我在 D3 中有一个时间轴,带有高度修改的拖动/滚动平移/缩放。缩放回调使用d3.event.transform缩放行为生成的对象。

我需要添加一个使用我现有回调的程序化缩放。我已经尝试并尝试这样做而不这样做,但我还没有让它工作,重用现有结构会更容易和更快。

所以输入是一个新的域,即[new Date(1800,0), new Date(2000,0)],输出应该是一个新的d3.event.transform,它的行为与鼠标滚轮事件的输出完全一样。

一些示例现有代码:

this.xScale = d3.scaleTime()
  .domain(this.initialDateRange)
  .range([0, this.w]);

this.xScaleShadow = d3.scaleTime()
  .domain(this.xScale.domain())
  .range([0, this.w]);

this.zoomBehavior = d3.zoom()
  .extent([[0, 0], [this.w, this.h]])
  .on('zoom', this.zoomHandler.bind(this));

this.timelineSVG
  .call(zoomBehavior);

... 

function zoomHandler(transformEvent) {
  this.xScale.domain(transformEvent.rescaleX(this.xScaleShadow).domain());

  // update UI
  this.timeAxis.transformHandler(transformEvent);
  this.updateGraphics();
}
Run Code Online (Sandbox Code Playgroud)

示例目标:

function zoomTo(extents){
  var newTransform = ?????(extents);

  zoomHandler(newTransform);
}
Run Code Online (Sandbox Code Playgroud)

(请不要将此问题标记为重复,我的问题更具体,指的是更新的 d3 API)

And*_*eid 5

假设我理解问题:

简单地根据您的问题的标题,我们可以使用zoom.transform在 d3v4 和 d3v5 中以编程方式分配缩放变换并触发缩放事件,如下所示:

selection.call(zoom.transform, newTransform)
Run Code Online (Sandbox Code Playgroud)

其中 selection 是调用缩放的选择,zoom是缩放行为对象的名称,是缩放对象zoom.transform的函数,用于设置应用于选择的缩放变换(并发出开始、缩放和结束事件) ,虽然newTransform是提供给改造zoom.transform作为参数(见selection.call()文档有关这种模式的更多信息,但它是一样的zoom.transform(selection,newTransform))。

下面您可以通过单击按钮来设置矩形的缩放缩放不是在空间上而是在颜色上应用,但是从语义或几何上缩放数据时的原理是相同的。

selection.call(zoom.transform, newTransform)
Run Code Online (Sandbox Code Playgroud)
var scale = d3.scaleSqrt()
  .range(["red","blue","yellow"])
  .domain([1,40,1600]);
  
var zoom = d3.zoom()
  .on("zoom", zoomed)
  .scaleExtent([1,1600])
    

var rect = d3.select("svg")
  .append("rect")
  .attr("width", 400)
  .attr("height", 200)
  .attr("fill","red")
  .call(zoom);
  
// Call zoom.transform initially to trigger zoom (otherwise current zoom isn't shown to start). 
rect.call(zoom.transform, d3.zoomIdentity);

// Call zoom.transform to set k to 100 on button push:
d3.select("button").on("click", function() {
  var newTransform = d3.zoomIdentity.scale(100);
  rect.call(zoom.transform, newTransform);
})

// Zoom function:
function zoomed(){
  var k = d3.event.transform.k;
  rect.attr("fill", scale(k));
  d3.select("#currentZoom").text(k);
}
Run Code Online (Sandbox Code Playgroud)
rect {
  cursor: pointer;
}
Run Code Online (Sandbox Code Playgroud)

如果对比例应用缩放变换,我们需要根据新的范围重新缩放。这类似于现有的画笔和缩放示例,但我将在仅使用比例和轴的裸骨示例中分解它(您也可以使用鼠标缩放比例本身):

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<button>Trigger Zoom</button> <br />
<span> Current Zoom: </span><span id="currentZoom"></span><br />
<svg></svg>
Run Code Online (Sandbox Code Playgroud)
var width = 400;
var height = 200;

var svg = d3.select("svg")
  .attr("width",width)
  .attr("height",height);
  
// The scale used to display the axis.
var scale = d3.scaleLinear()
  .range([0,width])
  .domain([0,100]);
  
// The reference scale
var shadowScale = scale.copy();

var axis = d3.axisBottom()
  .scale(scale);
  
var g = svg.append("g")
  .attr("transform","translate(0,50)")
  .call(axis);
  
// Standard zoom behavior:
var zoom = d3.zoom()
  .scaleExtent([1,10])
  .translateExtent([[0, 0], [width, height]])
  .on("zoom", zoomed);
 
// Rect to interface with mouse for zoom events.
var rect = svg.append("rect")
  .attr("width",width)
  .attr("height",height)
  .attr("fill","none")
  .call(zoom);
  
d3.select("#extent")
  .on("click", function() {
    // Redfine the scale based on extent
    var extent = [10,20];

    // Build a new zoom transform:
    var transform = d3.zoomIdentity
      .scale( width/ ( scale(extent[1]) - scale(extent[0]) ) ) // how wide is the full domain relative to the shown domain?
      .translate(-scale(extent[0]), 0);  // Shift the transform to account for starting value
      
    // Apply the new zoom transform:
    rect.call(zoom.transform, transform);

  })
  
d3.select("#reset")
  .on("click", function() {
    // Create an identity transform
    var transform = d3.zoomIdentity;
    
    // Apply the transform:
    rect.call(zoom.transform, transform);
  })

// Handle both regular and artificial zooms:  
function zoomed() {
  var t = d3.event.transform;
  scale.domain(t.rescaleX(shadowScale).domain());
  g.call(axis);
}
Run Code Online (Sandbox Code Playgroud)
rect {
  pointer-events: all;
}
Run Code Online (Sandbox Code Playgroud)

看一下关键部分,当我们想放大到一定程度时,我们可以使用以下几行:

d3.select("something")
  .on("click", function() {
    // Redfine the scale based on scaled extent we want to show
    var extent = [10,20];

    // Build a new zoom transform (using d3.zoomIdentity as a base)
    var transform = d3.zoomIdentity
      // how wide is the full domain relative to the shown domain?
      .scale( width/(scale(extent[1]) - scale(extent[0])) ) 
      // Shift the transform to account for starting value
      .translate(-scale(extent[0]), 0);  

    // Apply the new zoom transform:
    rect.call(zoom.transform, transform);

  })
Run Code Online (Sandbox Code Playgroud)

请注意,通过使用d3.zoomIdentity,我们可以利用恒等变换(及其内置的重新缩放方法)并修改其缩放和变换以满足我们的需要。