我有一个d3.js力布局,对力计算进行了一些调整。由于我处理大型数据集,有时图表部分或全部位于视口之外。我想添加一个命令来重新缩放并将图形居中放在视口内,但是遇到了一些麻烦。
我有一个画布和一个视口:
this.svg_canvas = d3.select("#" + this.container_id)
.append("svg")
.attr("width", this.width)
.attr("height", this.height)
.call(this.zoom_behavior.bind(this))
;
this.viewport = this.svg_canvas.append("g")
.attr("id", "viewport")
;
我有缩放和平移视口的缩放行为:
this.zoom_behavior = d3.behavior.zoom()
.scaleExtent([GraphView.MIN_ZOOM, GraphView.MAX_ZOOM])
.on('zoom', this._handleZoom.bind(this))
;
GraphView.prototype._handleZoom = function() {
var translate = d3.event.translate;
var scale = d3.event.scale;
this.viewport.attr("transform",
"translate(" + translate + ") " +
"scale(" + scale + ")");
};
所有这一切都可行。
我添加了一个"重新定位和缩放"应该执行缩放和转换以将图形带到视口的方法。它应该工作的方式是首先找到图形的范围(通过我的boundingBox()
方法),然后使用适当的缩放和转换参数调用zoom.behavior
:
GraphView.prototype.recenterAndScale = function(nodes) {
var bounding_box = this._boundingBox(nodes || this.force.nodes());
var viewport = this.zoom_behavior.size(); // viewport [width, height]
var tx = viewport[0]/2 - bounding_box.x0;
var ty = viewport[1]/2 - bounding_box.y0;
var scale = Math.min(viewport[0]/bounding_box.dx, viewport[1]/bounding_box.dy);
this.zoom_behavior.translate([tx, ty])
.scale(scale)
.event(this.svg_canvas)
;
};
这不起作用。它(通常)将图形定位在视口的边缘。也许我正在使用错误的引用。是否存在如何执行此操作的在线示例"正确" (使用d3成语)?
为了完整性,这里是我对boundingBox()
的定义 - 它返回图中节点的几何中心和范围。据我所知,这是正常的:
// Return {dx:, dy:, x0:, y0:} for the given nodes. If no nodes
// are given, return {dx: 0, dy: 0, x0: 0, y0: 0}
GraphView.prototype._boundingBox = function(nodes) {
if (nodes.length === 0) {
return {dx: 0, dy: 0, x0: 0, y0: 0};
} else {
var min_x = Number.MAX_VALUE;
var min_y = Number.MAX_VALUE;
var max_x = -Number.MAX_VALUE;
var max_y = -Number.MAX_VALUE;
nodes.forEach(function(node) {
if (node.x < min_x) min_x = node.x;
if (node.x > max_x) max_x = node.x;
if (node.y < min_y) min_y = node.y;
if (node.y > max_y) max_y = node.y;
});
return {dx: max_x - min_x,
dy: max_y - min_y,
x0: (max_x + min_x) / 2.0,
y0: (max_y + min_y) / 2.0
};
}
}
答案 0 :(得分:0)
这实际上非常简单:我需要在计算翻译时应用缩放效果。更正后的recenterAndScale()
方法是:
GraphView.prototype.recenterAndScale = function(nodes) {
var bbox = this._boundingBox(nodes || this.force.nodes());
var viewport = this.zoom_behavior.size(); // => [width, height]
var scale = Math.min(viewport[0]/bbox.dx, viewport[1]/bbox.dy);
var tx = viewport[0]/2 - bbox.x0 * scale; // <<< account for scale
var ty = viewport[1]/2 - bbox.y0 * scale; // <<< account for scale
this.zoom_behavior.translate([tx, ty])
.scale(scale)
.event(this.svg_canvas)
;
};