我找到了这个使用小地图缩放的好例子,但它是用旧版本 v3 编写的。我几乎将其转换为v4,但是d3.event
有问题。在 v3 中,d3.event
似乎在调用缩放的两个元素之间共享缩放参数。因此,如果我在主画布上缩放,然后在小地图画布上缩放 - d3.event 将具有主画布缩放d3.event
的最后一个缩放值,并且它将继续按应有的方式缩放。但在 v4 中,两个 d3 缩放事件都有某种单独的缩放或平移值。如文档中所示:
缩放行为将缩放状态存储在应用缩放行为的元素上,而不是存储在缩放行为本身上。这是因为缩放行为可以同时应用于多个元素,并且每个元素都可以独立缩放。
但这留下了一个问题,我如何在两个元素上有一个共享的缩放事件?
编辑 :
还要感谢比尔·怀特,他在同一帖子中发布了他的更新文章 - D3 MINIMAP V4 更新。这篇文章实际上是我在问题中发布的示例的更新。
可以在此处找到问题的答案。
@mbostock在一个问题线程中友好地回答了我的问题。我也找到了另一种解决方案。我成功地将他的代码中的一些逻辑和公式直接实现到我的缩放处理程序中。它就像一个魅力。
因此,这是从 v3 到 v4 的更新缩放处理程序:
注意: 不包括翻译边界检查。
// ....
var scale = 1;
var minScale = .5;
var maxScale = 7.5;
var translation = [0, 0];
// ....
// Used for both main canvas and minimap zoom
var zoom = d3.zoom()
.on('zoom', zoomHandler);
function zoomHandler(newScale) {
var prevScale = scale;
var previousTranslation = getXYFromTranslate(panCanvas.attr('transform'));
var isZoomEvent = d3.event && d3.event.sourceEvent.deltaY;
var isDragEvent = d3.event && (d3.event.sourceEvent.movementX || d3.event.sourceEvent.movementY);
if (isZoomEvent) {
scale = calculateNewScale(prevScale, d3.event.sourceEvent);
scale = checkScaleBounderies(scale);
var mousePosition = d3.mouse(this);
// Based on d3.js zoom algorythm
translation[0] = mousePosition[0] - ((mousePosition[0] - previousTranslation[0]) / prevScale) * scale;
translation[1] = mousePosition[1] - ((mousePosition[1] - previousTranslation[1]) / prevScale) * scale;
} else if (isDragEvent) {
translation[0] = previousTranslation[0] + d3.event.sourceEvent.movementX;
translation[1] = previousTranslation[1] + d3.event.sourceEvent.movementY;
} else if (newScale) {
scale = newScale;
}
// Apply the new dimensions to the main canvas
panCanvas.attr('transform', 'translate(' + translation + ') scale(' + scale + ')');
// Apply the new dimensions to the minimap
minimap.scale(scale).render();
}
// Calculate the new scale value based on d3.js zoom formula
function calculateNewScale(prevScale, event) {
return prevScale * Math.pow(2, -event.deltaY * (event.deltaMode ? 120 : 1) / 500);
}
// Check if scale has reached max or min
function checkScaleBounderies(newScale) {
return Math.max(minScale, Math.min(maxScale, newScale));
}
//....
function getXYFromTranslate(transform) {
// Create a dummy g for calculation purposes only. This will never
// be appended to the DOM and will be discarded once this function
// returns.
var g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
// Set the transform attribute to the provided string value.
g.setAttributeNS(null, 'transform', transform);
// consolidate the SVGTransformList containing all transformations
// to a single SVGTransform of type SVG_TRANSFORM_MATRIX and get
// its SVGMatrix.
var matrix = g.transform.baseVal.consolidate().matrix;
// As per definition values e and f are the ones for the translation.
return [matrix.e, matrix.f];
}