D3 添加缩放和平移
D3 add zoom and pan
我需要缩放和平移一组 svg 元素,如下例:
https://embed.plnkr.co/kVw0rWMo728dmbm8EjuG/
我已经完成了缩放行为,但是当我拖动鼠标(平移)时无法移动图形。我试过:
var zoom = d3.zoom()
.scaleExtent([1, 100])
.translateExtent([[150, 150],[150, 150]])
.on('zoom', zoomFn);
d3.select('svg')
.select('g')
.style("transform-origin", "50% 50% 0");
function zoomFn() {
d3.select('svg').select('g')
.style('transform', 'translate(' + d3.event.translate + ')' + ' scale(' + d3.event.transform.k + ')');
}
d3.select('svg')
.select('rect')
.call(zoom);
如何在该示例中添加平移行为?
有几件事:
第一
d3.event.translate
不包含变换 x 和 y 值,使用 d3.event.transform 获取这些值。变换对象具有 x、y 和 k 属性。
第二
如果使用 .style()
放置变换,您需要指定偏移量的单位是像素:
var t = d3.event.transform;
d3.select("zoomedElement")
.style('transform', 'translate('+t.x+"px,"+t.y + 'px)scale(' + t.k + ')');
或者,您可以在不使用 px
的情况下使用 .attr()
:
var t = d3.event.transform;
d3.select("zoomedElement")
.style('transform', 'translate('+[t.x,t.y]+')scale(' + t.k + ')');
让我们看看你的 plunker 有那些变化(没有翻译范围):
var zoom = d3.zoom()
.scaleExtent([1, 100])
.on('zoom', zoomFn);
d3.select('svg')
.select('g')
.style("transform-origin", "50% 50% 0");
function zoomFn() {
var t = d3.event.transform;
d3.select('svg').select('g')
.style('transform', 'translate('+t.x+"px,"+t.y + 'px)scale(' + t.k + ')');
}
d3.select('svg')
.select('rect')
.call(zoom);
.zoom-layer {
fill: #EEE;
fill-opacity: 0.25;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.0.0/d3.min.js"></script>
<svg width="300" height="300">
<g>
<circle cx=150 cy=150 r=20 style="fill:#F22"></circle>
<rect x=0 y=0 width=300 height=300 class="zoom-layer"></rect>
</g>
</svg>
您可能希望做出不包含矩形的选择 - 它应该保持不变,以便整个 SVG 表面保持交互
第三
您似乎想要一个平移范围,有时设置起来有点棘手。 答案在缩放 extent/translate 范围上更深入,但我将讨论如何将你的圈子限制在屏幕上:
翻译 [0,0] 你的圆圈位于 svg 的中间。如果我们翻译 [-150,-150],您的圆圈位于 svg 的左上角。如果圆以 cx=150 cy=150 为中心,那么可视区域的左上角现在是 [150,150]。因此右下角是 [450,450]。可见范围为:[[150,150],[450,450]]
.
翻译 [150,150],您的圆圈位于 SVG 的右下角。因为圆仍然在[150,150],所以右下角在[150,150] (平移和圆位置在这里具有相同的值不利于清晰)。左上角位于 [-150,-150]
。可见范围必须是:[[-150,-150],[150,150]]
.
我们从可见范围限制中取极端值,因为这是使圆保持可见的平移范围:
var translateExtent = [[-150,-150],[450,450]]
当然,如果你在所有角落都有东西而不是中间,你会有更大的范围。
我们可以将所有内容应用到代码段中:
var zoom = d3.zoom()
.scaleExtent([1, 100])
.translateExtent([[-150,-150],[450, 450]])
.on('zoom', zoomFn);
d3.select('svg')
.select('g')
.style("transform-origin", "50% 50% 0");
function zoomFn() {
var t = d3.event.transform;
d3.select('svg').select('g')
.style('transform', 'translate('+t.x+"px,"+t.y + 'px)scale(' + t.k + ')');
console.log(t.x,t.y)
}
d3.select('svg')
.select('rect')
.call(zoom);
.zoom-layer {
fill: #aaa;
fill-opacity: 0.25;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="300" height="300">
<g>
<circle cx=150 cy=150 r=20 style="fill:#F22"></circle>
</g>
<rect x=0 y=0 width=300 height=300 class="zoom-layer"></rect>
</svg>
我需要缩放和平移一组 svg 元素,如下例:
https://embed.plnkr.co/kVw0rWMo728dmbm8EjuG/
我已经完成了缩放行为,但是当我拖动鼠标(平移)时无法移动图形。我试过:
var zoom = d3.zoom()
.scaleExtent([1, 100])
.translateExtent([[150, 150],[150, 150]])
.on('zoom', zoomFn);
d3.select('svg')
.select('g')
.style("transform-origin", "50% 50% 0");
function zoomFn() {
d3.select('svg').select('g')
.style('transform', 'translate(' + d3.event.translate + ')' + ' scale(' + d3.event.transform.k + ')');
}
d3.select('svg')
.select('rect')
.call(zoom);
如何在该示例中添加平移行为?
有几件事:
第一
d3.event.translate
不包含变换 x 和 y 值,使用 d3.event.transform 获取这些值。变换对象具有 x、y 和 k 属性。
第二
如果使用 .style()
放置变换,您需要指定偏移量的单位是像素:
var t = d3.event.transform;
d3.select("zoomedElement")
.style('transform', 'translate('+t.x+"px,"+t.y + 'px)scale(' + t.k + ')');
或者,您可以在不使用 px
的情况下使用 .attr()
:
var t = d3.event.transform;
d3.select("zoomedElement")
.style('transform', 'translate('+[t.x,t.y]+')scale(' + t.k + ')');
让我们看看你的 plunker 有那些变化(没有翻译范围):
var zoom = d3.zoom()
.scaleExtent([1, 100])
.on('zoom', zoomFn);
d3.select('svg')
.select('g')
.style("transform-origin", "50% 50% 0");
function zoomFn() {
var t = d3.event.transform;
d3.select('svg').select('g')
.style('transform', 'translate('+t.x+"px,"+t.y + 'px)scale(' + t.k + ')');
}
d3.select('svg')
.select('rect')
.call(zoom);
.zoom-layer {
fill: #EEE;
fill-opacity: 0.25;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.0.0/d3.min.js"></script>
<svg width="300" height="300">
<g>
<circle cx=150 cy=150 r=20 style="fill:#F22"></circle>
<rect x=0 y=0 width=300 height=300 class="zoom-layer"></rect>
</g>
</svg>
您可能希望做出不包含矩形的选择 - 它应该保持不变,以便整个 SVG 表面保持交互
第三
您似乎想要一个平移范围,有时设置起来有点棘手。
翻译 [0,0] 你的圆圈位于 svg 的中间。如果我们翻译 [-150,-150],您的圆圈位于 svg 的左上角。如果圆以 cx=150 cy=150 为中心,那么可视区域的左上角现在是 [150,150]。因此右下角是 [450,450]。可见范围为:[[150,150],[450,450]]
.
翻译 [150,150],您的圆圈位于 SVG 的右下角。因为圆仍然在[150,150],所以右下角在[150,150] (平移和圆位置在这里具有相同的值不利于清晰)。左上角位于 [-150,-150]
。可见范围必须是:[[-150,-150],[150,150]]
.
我们从可见范围限制中取极端值,因为这是使圆保持可见的平移范围:
var translateExtent = [[-150,-150],[450,450]]
当然,如果你在所有角落都有东西而不是中间,你会有更大的范围。
我们可以将所有内容应用到代码段中:
var zoom = d3.zoom()
.scaleExtent([1, 100])
.translateExtent([[-150,-150],[450, 450]])
.on('zoom', zoomFn);
d3.select('svg')
.select('g')
.style("transform-origin", "50% 50% 0");
function zoomFn() {
var t = d3.event.transform;
d3.select('svg').select('g')
.style('transform', 'translate('+t.x+"px,"+t.y + 'px)scale(' + t.k + ')');
console.log(t.x,t.y)
}
d3.select('svg')
.select('rect')
.call(zoom);
.zoom-layer {
fill: #aaa;
fill-opacity: 0.25;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="300" height="300">
<g>
<circle cx=150 cy=150 r=20 style="fill:#F22"></circle>
</g>
<rect x=0 y=0 width=300 height=300 class="zoom-layer"></rect>
</svg>