我希望将绘图的缩放行为配置为具有三种交互方式:
现在,我可以使后两个在此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
当按下控制键时的默认缩放行为,但是在未按下控制键时平移而不是在滚动时缩放。
我在此答案上使用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] 删除。
我来说两句