function constrain(transform, extent, translateExtent) {
var dx0 = transform.invertX(extent[0][0]) - translateExtent[0][0],
dx1 = transform.invertX(extent[1][0]) - translateExtent[1][0],
dy0 = transform.invertY(extent[0][1]) - translateExtent[0][1],
dy1 = transform.invertY(extent[1][1]) - translateExtent[1][1];
return transform.translate(
dx1 > dx0 ? (dx0 + dx1) / 2 : Math.min(0, dx0) || Math.max(0, dx1),
dy1 > dy0 ? (dy0 + dy1) / 2 : Math.min(0, dy0) || Math.max(0, dy1)
zoom.extent([extent]) 设置视图范围 viewport extent。
参数 extent 是一个数组 [[x0, y0], [x1, y1]],其中 [x0, y0] 表示视图范围的左上角,而 [x1, y1] 表示视图范围的右下角。
参数 extent 也可以是一个返回数组的函数,它会被选择集中的元素依次调用,并传递当前所遍历的元素所绑定的数据 datum d 作为参数。而函数内的 this 指向当前所遍历的元素节点。
💡 如果缩放器绑定的是普通的 HTML 元素,则视图范围的默认值 [[0, 0], [width, height]] 即与元素的宽高大小相同;如果缩放器绑定的是 SVG 类型的元素,则视图范围的默认值是 SVG 的 viewBox(如果没有设置 viewBox 属性,就使用 SVG 的宽高,即 viewport)。
视图的范围 viewport extent 对于一些函数有影响,如通过 zoom.scaleBy() 和 zoom.scaleTo() 方法触发的变换,其视图的中心会保持不变;视图中心和大小会影响使用插值器 d3.interpolateZoom 创建的过渡动画的路径;而平移范围 translate extent 的约束需要依赖视图范围(平移范围应该大于视图范围)。
zoom.translateExtent([extent]) 设置平移范围 translate extent。
参数 extent 是一个数组 [[x0, y0], [x1, y1]],其中 [x0, y0] 表示平移范围的左上角,而 [x1, y1] 表示平移范围的右下角。默认值是 [[-∞, -∞], [+∞, +∞]]
💡 该方法虽然约束的是平移操作,但可能造成缩小时平移的发生。
⚠️ 该约束在通过 zoom.scaleBy()、zoom.scaleTo()、zoom.translateBy() 方法执行变换时生效;但是通过 zoom.transform() 方法执行变换时不生效
以上三个方法提及的两个特殊的范围:viewport extent 视图范围、translate extent 平移范围。通过设置视图范围的大小,以及通过平移范围来约束视图(范围,一个数组)可以修改的位置,可以间接来限制元素可以平移的位置,通过这两个特殊范围的配合可以实现特定的元素不被移出画面外这一需求。
zoom.scaleExtent([extent]) 设置缩放比例的范围。参数 extent 是一个的数组 [k0, k1],表示缩放比例的范围,其中 k0 是可设置的最小缩放比例,k1 是可设置的最大缩放比例。默认范围是 [0,∞]
如果达到了约束的缩放比例极限时,即使用户继续滑动鼠标滚轮,缩放变换也会被忽略。
💡 以上方法限制视图的缩放,但可能会造成一个「副作用」,即当视图缩放达到了约束的缩放比例极限时,用户还继续滚动就会造成页面的滚动(如果当时页面是可滚动的),如果希望修正这个「副作用」,可以在相应的选择集上监听 wheel 事件并取消它的默认行为
selection
.on(zoom)
.on("wheel", event => event.preventDefault());
⚠️ 该约束在通过 zoom.scaleBy()、zoom.scaleTo()、zoom.translateBy() 方法执行变换时生效;但是通过 zoom.transform() 方法执行变换时不生效
zoom.filter[(filter)] 用于判断是否执行缩放变换操作。参数 filter 是一个返回布尔值的函数,当返回的是 falsy 时忽略变换操作。它用以限制特定条件下不响应缩放变换操作。
函数 filter 接收当前的缩放事件 event 和当前调用缩放器的选择集的元素所绑定的数据 datum d 作为参数,而函数内的 this 指向当前元素节点。
其默认值如下,因此按下 Ctrl(但是可以在滚动鼠标滑轮时按下 Ctrl)或使用鼠标的次级按键(对于右手用户,次级按键一般是指鼠标的右键)时,默认是无法进行缩放平移操作,因为这些操作一般有其他用途
function filter(event) {
return (!event.ctrlKey || event.type === 'wheel') && !event.button;
zoom.wheelDelta([delta]) 设置鼠标滚轮的每次滚动的 delta 值,参数 delta 是一个函数,最后返回修改后的 delta 值 Δ。
参数 delta 默认值如下
function wheelDelta(event) {
return -event.deltaY * (event.deltaMode === 1 ? 0.05 : event.deltaMode ? 1 : 0.002);
该值用于在鼠标滚轮时计算缩放比例 k×2Δ(其中 k 是原始的缩放比例),例如当 Δ=1 时,视图的元素会缩小一半;当 Δ=−1 时,视图的元素会放大一倍
zoom.clickDistance([distance]) 设置点击事件中,鼠标按下与放开鼠标之间允许的最大距离(该距离通过点击事件的 event.clientX、event.clientY 计算得到),如果大于等于该距离,就不会抛出点击事件。
💡 可以想象以鼠标按下点为圆心,以参数 distance 为半径,在该圆内释放鼠标,都会抛出点击事件,在圆外(或圆周上)放开鼠标,点击事件都会被忽略(因为此时更应该触发拖拽事件)。参数默认值 distance 是 0
该方法可用于优化点击放大的场景,而原始画面中有大量较小的元素,从鼠标的按下到释放可能会发生微小的移动,避免识别为对该元素的拖拽操作,可以通过设置「可移动式点击的最大距离」,来区分点击事件和拖拽事件。
zoom.tapDistance([distance]) 对于触屏设备在双击时,两次点击允许的最大距离(该距离通过首次点击的 touchstart 和第二次点击的 touchend 事件的 event.clientX、event.clientY 计算得到),如果大于等于该距离,就不会抛出 dblclick 双击事件。
💡 其应用场景和前一个方法类似,一般是为了区分双击事件和拖拽事件,参数默认值 distance 是 10
JavaScript
- 340
-
zhouf95943
JavaScript
- 1470
-
Benbinbin