【发布时间】:2015-03-28 18:26:32
【问题描述】:
我正在尝试将相当标准的 d3 拖动/缩放功能应用于径向树布局。
问题是,如果我将 zoomhandler 定义为这样...
svg.attr("transform","translate("+d3.event.translate+")scale("+d3.event.scale+")");
...然后缩放完全跟随鼠标,但整个径向树在第一次缩放时从错误的位置开始(即(0,0) 坐标)。
而如果我将 zoomhandler 定义为这样...
svg.attr("transform", "translate(" + (w/2 + d3.event.translate[0]) +
"," + (h/2 + d3.event.translate[1]) + ")scale(" + d3.event.scale + ")" );
...然后树的行为正确,但缩放不跟随鼠标(事实上,为了在不移动树的情况下放大/缩小树,我的鼠标需要定位在 0,0 坐标屏幕左上角)
我很欣赏这是一个之前讨论过的话题(我认为最值得注意的是:Using D3, can semantic zoom be applied to a radial tree?),但我仍然不清楚如何解决这个问题,因此非常感谢任何专门解决此问题的人的任何意见让径向树同时缩放到鼠标位置并同时保持锚定在屏幕中心的问题。谢谢!
这里有详细的完整代码...
var w = 1200;
var h = 1000;
var data = [{'parent_id' : '1', 'items_count' : '2'}
, {'parent_id' : '2', 'items_count' : '4'}
, {'parent_id' : '3', 'items_count' : '3'}
, {'parent_id' : '4', 'items_count' : '2'}
, {'parent_id' : '5', 'items_count' : '1'}
, {'parent_id' : '6', 'items_count' : '6'}
, {'parent_id' : '7', 'items_count' : '2'}
, {'parent_id' : '8', 'items_count' : '4'}
, {'parent_id' : '9', 'items_count' : '5'}
, {'parent_id' : '10', 'items_count' : '7'}
];
var treeRadius = 300;
var searchCircleRadius = 60;
var circleRadiusScale = d3.scale.linear()
.domain([0, d3.max(data, function(d) { return d.items_count; })])
.range([10, 40]);
var dataTree = {
children: data.map(function(d) { return { parent_id: d.parent_id, items_count: d.items_count}; })
};
var tree = d3.layout.tree()
.size([360, treeRadius]);
var mainSvg = d3.select("body").append("svg")
.attr("width", w)
.attr("height", h);
var svg = mainSvg
.append("g")
.attr("transform", "translate(" + (w / 2) + "," + (h / 2) + ")");
var childGroupZoom = svg.append("g");
var zoomListener = d3.behavior.zoom()
.scaleExtent([0.1, 1.75])
.on("zoom", zoomHandler);
function zoomHandler() {
//1) for both of these, the tree starts in centre of screen, drag works nicely, but zoom doesn't follow mouse
//childGroupZoom.attr("transform", "translate(" + (d3.event.translate[0]) + "," + (d3.event.translate[1]) + ") scale(" + d3.event.scale + ")");
childGroupZoom.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
//2) follows the mouse on zoom but jump to top-left on first zoom/drag (because it's applied to "svg" which already has a translate applied)...
//svg.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")"); //follows mouse on zoom but starts at wrong place
//3) same as the first category - the tree doesn't jump, but the zoom doesn't follow the mouse
//svg.attr("transform", "translate(" + (w/2 + d3.event.translate[0]) + "," + (h/2 + d3.event.translate[1]) + ")scale(" + d3.event.scale + ")" ); //starts in centre but doesn't follow mouse!
}
zoomListener(mainSvg);
var nodes = tree.nodes(dataTree);
var basicNode = childGroupZoom.selectAll(".node");
var node = basicNode
.data(nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "rotate(" + (d.x - 90) + ") translate(" + d.y + ")";
});
var outlineCircles = node.append("circle")
.attr("r", function(d,i) { if (i<1) {
return searchCircleRadius;
} else {
return circleRadiusScale(d.items_count);
}})
.attr("stroke", "#0099FF")
.attr("stroke-width", "3")
.attr("transform", function(d) {return "rotate(" + (-d.x + 90) + ")";});
<!DOCTYPE html>
<html>
<head>
<title>Demo</title>
<script src="http://d3js.org/d3.v3.min.js"></script>
</head>
<body>
</body>
</html>
【问题讨论】:
-
我想你正在做这样的事情:翻译到对象中心、缩放、翻译回上一个位置。
-
感谢 bvj 的回复 - 我已经在上面添加了确切的详细信息
-
抱歉追,但有人对此有任何想法吗?我完全被卡住了,找不到解释这个概念的任何其他资源。谢谢!
-
这是完整的工作代码,列出了缩放处理程序中问题的本质...
标签: d3.js