Svg d3中力有向图的语义缩放
通过几何缩放力有向图已经显示了许多 在几何缩放中,我只需要在缩放函数中添加一个变换属性。然而,在语义缩放中,若我只在节点中添加一个transform属性,链接将不会连接到节点。所以,我想知道是否有一个解决方案的几何缩放力定向图在d3 下面是我的例子,几何缩放与前面的案例。我有两个问题:Svg d3中力有向图的语义缩放,svg,d3.js,zooming,force-layout,Svg,D3.js,Zooming,Force Layout,通过几何缩放力有向图已经显示了许多 在几何缩放中,我只需要在缩放函数中添加一个变换属性。然而,在语义缩放中,若我只在节点中添加一个transform属性,链接将不会连接到节点。所以,我想知道是否有一个解决方案的几何缩放力定向图在d3 下面是我的例子,几何缩放与前面的案例。我有两个问题: 当我缩小,然后拖动整个图形时,图形会奇怪地消失 使用相同的重画函数 这只更新一个svg元素的“transform”属性。但是如何使函数改变节点的位置呢 但我想做的是。我尝试过修改缩放和变换功能,但不确定正确的方法
您必须变换节点并重新绘制路径 “语义缩放”的概念是更改布局的比例,而不是单个元素的大小 如果如链接示例中所示设置了缩放行为,它会自动为您更新x和y比例。然后根据这些比例重新设置节点的位置,还可以重新设置链接的位置和形状 如果链接是直线,请使用更新的x和y刻度重新设置x1、y1、x2和y2位置。如果链接是使用d3.svg.diagonal和x和y比例创建的路径,请使用相同的函数重新设置“d”属性
如果您需要更具体的说明,您必须发布您的代码。我试图找到一个好的教程链接,但找不到任何真正涵盖所有问题的内容,因此我将自己一步一步地写出来 首先,你需要清楚地了解你想要完成什么。这对于两种类型的缩放是不同的。我真的不喜欢Mike Bostock介绍的术语(它与术语的非d3用法不完全一致),但我们还是坚持使用它,以便与其他d3示例保持一致 在“几何缩放”中,您正在缩放整个图像。圆圈和线条变得越来越大,距离也越来越远。SVG有一种通过“transform”属性实现这一点的简单方法。当您在SVG元素上设置
transform=“scale(2)”
时,它会被绘制为所有元素的两倍大。对于一个圆,它的半径绘制一个大的两倍,它的cx
和cy
位置绘制距离(0,0)点两倍的距离。整个坐标系都会改变,所以一个单位现在等于屏幕上的两个像素,而不是一个
类似地,transform=“translate(-50100)”
更改整个坐标系,使坐标系的(0,0)点向左移动50个单位,从左上角(默认原点)向下移动100个单位
如果同时平移和缩放SVG元素,则顺序很重要。如果“平移”在“缩放”之前,则平移以原始单位表示。如果“平移”在缩放之后,则平移以缩放单位表示
该方法创建一个函数,用于侦听鼠标滚轮和拖动事件,以及与缩放相关的触摸屏事件。它将这些用户事件转换为自定义的“缩放”事件
缩放事件被赋予一个比例因子(单个数字)和一个平移因子(两个数字的数组),行为对象根据用户的移动来计算。你如何处理这些数字取决于你自己它们不会直接更改任何内容。(将比例附加到缩放行为功能时除外,如下所述。)
对于几何缩放,通常需要在包含要缩放内容的
元素上设置“缩放和平移变换”属性。此示例在由均匀放置的网格线组成的简单SVG上实现了几何缩放方法:缩放代码很简单:
function zoom() {
console.log("zoom", d3.event.translate, d3.event.scale);
vis.attr("transform",
"translate(" + d3.event.translate + ")"
+ " scale(" + d3.event.scale + ")"
);
}
缩放是通过在“vis”上设置transform属性来完成的,这是一个d3选择,包含一个
元素,该元素本身包含我们要缩放的所有内容。平移和缩放因子直接来自d3行为创建的缩放事件
结果是所有东西都变大或变小了——网格线的宽度以及它们之间的间距。线条仍有笔划宽度:1.5
但是屏幕上1.5等于什么的定义对于他们和转换后的
元素中的任何其他内容都已更改
对于每个缩放事件,平移和缩放因子也会记录到控制台。看看这个,你会注意到如果你缩小了,比例会在0到1之间;如果放大,它将大于1。如果平移(拖动以移动)图形,则比例根本不会改变。但是,平移数字在平移和缩放时都会发生变化。这是因为translate表示图形中(0,0)点相对于SVG左上角的位置。缩放时,(0,0)与图形上任何其他点之间的距离将发生变化。因此,为了使鼠标或手指触摸下的内容保持在屏幕上相同的位置,(0,0)点的位置必须移动
在该示例中,您还应注意一些其他事项:
- 我已经用这个方法修改了缩放行为对象。这将设置缩放事件中行为将使用的缩放值的限制,无论用户旋转轮子多少次
- 转换在
元素上,而不是
本身。这是因为SVG元素作为一个整体被视为一个HTML元素,并且具有不同的trafunction zoom() { node.call(transform); // update link position update(); } function transform(d){ // change node x, y position, not sure what function to put here. }
function zoom() { console.log("zoom", d3.event.translate, d3.event.scale); vis.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")" ); }
zoomedPositionX = d3.event.translate[0] + d3.event.scale * dataPositionX zoomedPositionY = d3.event.translate[1] + d3.event.scale * dataPositionY
vLines.attr("x1", function(d){return d;}) .attr("y1", 0) .attr("x2", function(d){return d;}) .attr("y2", h);
vLines.attr("x1", function(d){ return d3.event.translate[0] + d*d3.event.scale; }) .attr("y1", d3.event.translate[1]) .attr("x2", function(d){ return d3.event.translate[0] + d*d3.event.scale; }) .attr("y2", d3.event.translate[1] + h*d3.event.scale);
function zoom() { console.log("zoom", d3.event.translate, d3.event.scale); scaleFactor = d3.event.scale; translation = d3.event.translate; tick(); //update positions }
function tick() { linkLines.attr("x1", function (d) { return translation[0] + scaleFactor*d.source.x; }) .attr("y1", function (d) { return translation[1] + scaleFactor*d.source.y; }) .attr("x2", function (d) { return translation[0] + scaleFactor*d.target.x; }) .attr("y2", function (d) { return translation[1] + scaleFactor*d.target.y; }); nodeCircles.attr("cx", function (d) { return translation[0] + scaleFactor*d.x; }) .attr("cy", function (d) { return translation[1] + scaleFactor*d.y; }); }
function dragged(d){ if (d.fixed) return; //root is fixed //get mouse coordinates relative to the visualization //coordinate system: var mouse = d3.mouse(vis.node()); d.x = mouse[0]; d.y = mouse[1]; tick();//re-position this node and any links }
zoomedPositionX = d3.event.translate[0] + d3.event.scale * dataPositionX zoomedPositionY = d3.event.translate[1] + d3.event.scale * dataPositionY
dataPositionX = (zoomedPositionX - d3.event.translate[0]) / d3.event.scale dataPositionY = (zoomedPositionY - d3.event.translate[1]) / d3.event.scale
function dragged(d){ if (d.fixed) return; //root is fixed //get mouse coordinates relative to the visualization //coordinate system: var mouse = d3.mouse(vis.node()); d.x = (mouse[0] - translation[0])/scaleFactor; d.y = (mouse[1] - translation[1])/scaleFactor; tick();//re-position this node and any links }
/*** Configure zoom behaviour ***/ var zoomer = d3.behavior.zoom() .scaleExtent([0.1,10]) //allow 10 times zoom in or out .on("zoom", zoom) //define the event handler function .x(xScale) .y(yScale); //attach the scales so their domains //will be updated automatically function zoom() { console.log("zoom", d3.event.translate, d3.event.scale); //the zoom behaviour has already changed //the domain of the x and y scales //so we just have to redraw using them drawLines(); } function drawLines() { //put positioning in a separate function //that can be called at initialization as well vLines.attr("x1", function(d){ return xScale(d); }) .attr("y1", yScale(0) ) .attr("x2", function(d){ return xScale(d); }) /* etc. */
/* Set the display size based on the SVG size and re-draw */ function setSize() { var svgStyles = window.getComputedStyle(svg.node()); var svgW = parseInt(svgStyles["width"]); var svgH = parseInt(svgStyles["height"]); //Set the output range of the scales xScale.range([0, svgW]); yScale.range([0, svgH]); //re-attach the scales to the zoom behaviour zoomer.x(xScale) .y(yScale); //resize the background rect.attr("width", svgW) .attr("height", svgH); //console.log(xScale.range(), yScale.range()); drawLines(); } //adapt size to window changes: window.addEventListener("resize", setSize, false) setSize(); //initialize width and height
function dragged(d){ if (d.fixed) return; //root is fixed //get mouse coordinates relative to the visualization //coordinate system: var mouse = d3.mouse(vis.node()); d.x = xScale.invert(mouse[0]); d.y = yScale.invert(mouse[1]); tick();//re-position this node and any links }