我已经修改mbostock的drag+zoom example有一个4倍的变焦速度,并把它放在一个jsfiddle。我已经在下面解释了我的想法。这是我第一次尝试堆栈溢出的答案,请好。
正如RaúlMartín的回答中所解释的,您可以使用redraw()
函数中的公式来更改缩放比率。您需要进行一些额外的步骤,以确保d3行为仍可以很好地与修改后的缩放比率一起使用。
变焦中心位于所选位置(例如光标)
默认情况下D3行为着重于鼠标指针,例如变焦如果鼠标指针位于图像的左上角,则会放大左上角而不是图像的中心。为了获得这种效果,它缩放图像,然后更改图像的平移,使鼠标光标下的点位于屏幕上的相同位置。这就是为什么zoom.translate()
的值在您滚动鼠标滚轮时发生变化,即使图像看起来不像在屏幕上移动。
如果更改缩放速度,d3 zoom.translate()
值不再正确。要制定出正确的翻译,你需要了解以下信息(忽略的数值):
var prev_translate = [100,100] // x, y translation of the image in last redraw
var prev_scale = 0.1 // Scale applied to the image last redraw
var new_scale = 0.4 // The new scale being applied
var zoom_cp = [150, 150] // The zoom "center point" e.g. mouse pointer
摸出new_translate
应用到图像的公式则是:
new_translate[0] = zoom_cp[0] - (zoom_cp[0] - prev_translate[0])
* new_scale/prev_scale;
new_translate[1] = zoom_cp[1] - (zoom_cp[1] - prev_translate[1])
* new_scale/prev_scale;
你可以与您的新的规模以及应用到图像:
svg.attr("transform", "translate(" + new_translate + ")scale(" + new_scale + ")");
然后您就必须更新prev_scale = new_scale
和prev_translate = new_translate
准备好了redraw()
潘的下一次迭代,不进行缩放
D3的缩放行为让您无需通过单击并拖动缩放平移。如果单击并拖动,则zoom.scale()
保持不变,但zoom.translate()
更改。即使修改了变焦速度后,新的zoom.translate()
值仍然正确。但是,您需要知道何时使用此zoom.translate()
值以及何时使用您计算的用于放大中心点的平移值。
通过查看prev_scale
是否与new scale
相同,您可以计算出平移还是缩放。如果两个值相同,则表示正在进行平移,您可以使用new_translate = zoom.translate()
移动图像。否则,您知道正在进行缩放,您可以如上所述计算new_translate
的值。我通过在zoomstart
事件中添加一个函数来完成此操作。
var zoom_type = "?";
var scale_grad = 4; // Zoom speed multiple
var intercept = 1 * (1 - scale_grad)
var svg = d3.select("body").append("svg:svg")
.attr("width", 1000)
.attr("height", 2000)
.append("svg:g")
.call(d3.behavior.zoom()
.on("zoom", redraw)
.on("zoomstart", zoomstarted))
.append("svg:g");
function zoomstarted() {
zoom_type = "?";
}
function redraw() {
var scale = d3.event.scale;
// Use a linear scale, don't let it go below the minimum scale
// extent
var new_scale = Math.max(scale_grad * scale + intercept,
scale_extent[0]);
// If hit the minimum scale extent then stop d3 zoom from
// going any further
if (new_scale == scale_extent[0]) {
zoom.scale((scale_extent[0] - intercept)/scale_grad);
}
// Set up zoom_type if have just started
// If the scale hasn't changed then a pure translation is
// taking place, otherwise it is a scale
if (zoom_type == "?") {
if (new_scale == prev_scale) {
zoom_type = "translate"
} else {
zoom_type = "scale"
}
}
// zoom_cp is the static point during the zoom, set as
// mouse pointer position (you need to define a listener to track)
var new_translate = [0, 0];
zoom_cp = [mouse_x, mouse_y];
// If the event is a translate just apply d3 translate
// Otherwise calculate what translation is required to
// keep the zoom center point static
if (zoom_type == "translate") {
new_translate = d3.event.translate
} else if (zoom_type == "scale") {
new_translate[0] = zoom_cp[0]
- (zoom_cp[0] - prev_translate[0]) * new_scale/prev_scale;
new_translate[1] = zoom_cp[1]
- (zoom_cp[1] - prev_translate[1]) * new_scale/prev_scale;
}
// Update the variables that track the last iteration of the
// zoom
prev_translate = new_translate;
prev_scale = new_scale;
zoom.translate(new_translate);
// Apply scale and translate behaviour
svg.attr("transform", "translate(" + new_translate +
")scale(" + new_scale + ")");
}
你知道了吗? – kishanio
@ kishanio我提出了一个解决方案 –