I am using d3 to draw a line from a relative svg position and hence want to access the coordinates of the element itself. I tried something like this (where "this" refers to the element)
我使用d3从相对svg位置绘制一条线,因此希望访问元素本身的坐标。我尝试了这样的方法(这里的“this”指的是元素)
.attr("x1", this.x)
.attr("y1", this.y)
but the x1 and y1 just defaults to zero. What is the correct way to get the coordinates of the svg element?
但x1和y1只是默认为零。获得svg元素坐标的正确方法是什么?
EDIT:
编辑:
Here's my (by request) my whole code. I'm trying to implement this on the collapsible tree, where I draw a line when I hover with the mouse over a circle node. The starting point of the line should be from the circle I click on and the ending point should be a fixed point on the svg plane.
这是我的全部代码。我尝试在可折叠树上实现它,当我用鼠标悬停在一个圆形节点上时,我在这里画一条线。线条的起始点应该是我点击的圆圈,终点应该是svg平面上的一个固定点。
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<script type="text/javascript" src="d3.v3.js"></script>
<script type="text/javascript" src="d3.layout.js"></script>
<style type="text/css">
.node circle {
cursor: pointer;
fill: #fff;
stroke: steelblue;
stroke-width: 1.5px;
}
.node text {
font: 10px sans-serif;
}
path.link {
fill: none;
stroke: #ccc;
stroke-width: 1.5px;
}
</style>
</head>
<body>
<div id="chart"></div>
<script type="text/javascript">
var m = [20, 120, 20, 120],
w = 2240 - m[1] - m[3],
h = 800 - m[0] - m[2],
i = 0,
duration = 500,
root;
var tree = d3.layout.tree()
.size([h, w]);
var diagonal = d3.svg.diagonal()
.projection(function(d) { return [d.y, d.x]; });
var vis = d3.select("#chart").append("svg")
.attr("width", w + m[1] + m[3])
.attr("height", h + m[0] + m[2])
.append("g")
.attr("transform", "translate(" + m[3] + "," + m[0] + ")");
function loadData(json) {
root = json;
d3.select("#processName").html(root.text);
root.x0 = h / 2;
root.y0 = 0;
root.children.forEach(collapse);
update(root);
}
function collapse(d) {
if (d.children) {
d._children = d.children;
d._children.forEach(collapse);
d.children = null;
}
};
// Toggle children on click.
function click(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
update(d);
}
function update(source) {
// Compute the new tree layout.
var nodes = tree.nodes(root).reverse();
// Normalize for fixed-depth.
nodes.forEach(function(d) { d.y = d.depth * 180; });
// Update the nodes…
var node = vis.selectAll("g.node")
.data(nodes, function(d) { return d.id || (d.id = ++i); });
// Enter any new nodes at the parent's previous position.
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
.on("click", click);
nodeEnter.append("circle")
.attr("r", 1e-6)
.style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; })
.on('mouseover', function(d, i){
var dataset = [1,2,3,4] // HERE
vis.selectAll("line") // HERE
.data(dataset) // HERE
.enter() // HERE
.append("line") // HERE
.attr("x1", this.x) // HERE'S THE PROBLEM FOR PERRY
.attr("y1", this.y) // HERE'S THE PROBLEM FOR PERRY
.attr("x2", 500) // HERE
.attr("y2", 500) // HERE
.style("stroke", "rgb(6,120,155)");} // HERE
);
nodeEnter.append("text")
.attr("x", function(d) { return d.children || d._children ? -10 : 10; })
.attr("dy", ".35em")
.attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
.text(function(d) { return d.name; })
.style("fill-opacity", 1e-6);
// Transition nodes to their new position.
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });
nodeUpdate.select("circle")
.attr("r", 4.5)
.style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });
nodeUpdate.select("text")
.style("fill-opacity", 1);
// Transition exiting nodes to the parent's new position.
var nodeExit = node.exit().transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; })
.remove();
nodeExit.select("circle")
.attr("r", 1e-6);
nodeExit.select("text")
.style("fill-opacity", 1e-6);
// Update the links…
var link = vis.selectAll("path.link")
.data(tree.links(nodes), function(d) { return d.target.id; });
// Enter any new links at the parent's previous position.
link.enter().insert("path", "g")
.attr("class", "link")
.attr("d", function(d) {
var o = {x: source.x0, y: source.y0};
return diagonal({source: o, target: o});
})
.transition()
.duration(duration)
.attr("d", diagonal);
// Transition links to their new position.
link.transition()
.duration(duration)
.attr("d", diagonal);
// Transition exiting nodes to the parent's new position.
link.exit().transition()
.duration(duration)
.attr("d", function(d) {
var o = {x: source.x, y: source.y};
return diagonal({source: o, target: o});
})
.remove();
// Stash the old positions for transition.
nodes.forEach(function(d) {
d.x0 = d.x;
d.y0 = d.y;
});
};
loadData({
"name": "flare",
"children": [
{
"name": "analytics",
"children": [
{
"name": "cluster",
"children": [
{"name": "AgglomerativeCluster", "size": 3938},
{"name": "CommunityStructure", "size": 3812},
{"name": "HierarchicalCluster", "size": 6714},
{"name": "MergeEdge", "size": 743}
]
},
{
"name": "graph",
"children": [
{"name": "BetweennessCentrality", "size": 3534},
{"name": "LinkDistance", "size": 5731},
{"name": "MaxFlowMinCut", "size": 7840},
{"name": "ShortestPaths", "size": 5914},
{"name": "SpanningTree", "size": 3416}
]
},
{
"name": "optimization",
"children": [
{"name": "AspectRatioBanker", "size": 7074}
]
}
]
},
{
"name": "animate",
"children": [
{"name": "Easing", "size": 17010},
{"name": "FunctionSequence", "size": 5842},
{
"name": "interpolate",
"children": [
{"name": "ArrayInterpolator", "size": 1983},
{"name": "ColorInterpolator", "size": 2047},
{"name": "DateInterpolator", "size": 1375},
{"name": "Interpolator", "size": 8746},
{"name": "MatrixInterpolator", "size": 2202},
{"name": "NumberInterpolator", "size": 1382},
{"name": "ObjectInterpolator", "size": 1629},
{"name": "PointInterpolator", "size": 1675},
{"name": "RectangleInterpolator", "size": 2042}
]
},
{"name": "ISchedulable", "size": 1041},
{"name": "Parallel", "size": 5176},
{"name": "Pause", "size": 449},
{"name": "Scheduler", "size": 5593},
{"name": "Sequence", "size": 5534},
{"name": "Transition", "size": 9201},
{"name": "Transitioner", "size": 19975},
{"name": "TransitionEvent", "size": 1116},
{"name": "Tween", "size": 6006}
]
},
{
"name": "data",
"children": [
{
"name": "converters",
"children": [
{"name": "Converters", "size": 721},
{"name": "DelimitedTextConverter", "size": 4294},
{"name": "GraphMLConverter", "size": 9800},
{"name": "IDataConverter", "size": 1314},
{"name": "JSONConverter", "size": 2220}
]
},
{"name": "DataField", "size": 1759},
{"name": "DataSchema", "size": 2165},
{"name": "DataSet", "size": 586},
{"name": "DataSource", "size": 3331},
{"name": "DataTable", "size": 772},
{"name": "DataUtil", "size": 3322}
]
},
{
"name": "display",
"children": [
{"name": "DirtySprite", "size": 8833},
{"name": "LineSprite", "size": 1732},
{"name": "RectSprite", "size": 3623},
{"name": "TextSprite", "size": 10066}
]
},
{
"name": "flex",
"children": [
{"name": "FlareVis", "size": 4116}
]
},
{
"name": "physics",
"children": [
{"name": "DragForce", "size": 1082},
{"name": "GravityForce", "size": 1336},
{"name": "IForce", "size": 319},
{"name": "NBodyForce", "size": 10498},
{"name": "Particle", "size": 2822},
{"name": "Simulation", "size": 9983},
{"name": "Spring", "size": 2213},
{"name": "SpringForce", "size": 1681}
]
},
{
"name": "query",
"children": [
{"name": "AggregateExpression", "size": 1616},
{"name": "And", "size": 1027},
{"name": "Arithmetic", "size": 3891},
{"name": "Average", "size": 891},
{"name": "BinaryExpression", "size": 2893},
{"name": "Comparison", "size": 5103},
{"name": "CompositeExpression", "size": 3677},
{"name": "Count", "size": 781},
{"name": "DateUtil", "size": 4141},
{"name": "Distinct", "size": 933},
{"name": "Expression", "size": 5130},
{"name": "ExpressionIterator", "size": 3617},
{"name": "Fn", "size": 3240},
{"name": "If", "size": 2732},
{"name": "IsA", "size": 2039},
{"name": "Literal", "size": 1214},
{"name": "Match", "size": 3748},
{"name": "Maximum", "size": 843},
{
"name": "methods",
"children": [
{"name": "add", "size": 593},
{"name": "and", "size": 330},
{"name": "average", "size": 287},
{"name": "count", "size": 277},
{"name": "distinct", "size": 292},
{"name": "div", "size": 595},
{"name": "eq", "size": 594},
{"name": "fn", "size": 460},
{"name": "gt", "size": 603},
{"name": "gte", "size": 625},
{"name": "iff", "size": 748},
{"name": "isa", "size": 461},
{"name": "lt", "size": 597},
{"name": "lte", "size": 619},
{"name": "max", "size": 283},
{"name": "min", "size": 283},
{"name": "mod", "size": 591},
{"name": "mul", "size": 603},
{"name": "neq", "size": 599},
{"name": "not", "size": 386},
{"name": "or", "size": 323},
{"name": "orderby", "size": 307},
{"name": "range", "size": 772},
{"name": "select", "size": 296},
{"name": "stddev", "size": 363},
{"name": "sub", "size": 600},
{"name": "sum", "size": 280},
{"name": "update", "size": 307},
{"name": "variance", "size": 335},
{"name": "where", "size": 299},
{"name": "xor", "size": 354},
{"name": "_", "size": 264}
]
},
{"name": "Minimum", "size": 843},
{"name": "Not", "size": 1554},
{"name": "Or", "size": 970},
{"name": "Query", "size": 13896},
{"name": "Range", "size": 1594},
{"name": "StringUtil", "size": 4130},
{"name": "Sum", "size": 791},
{"name": "Variable", "size": 1124},
{"name": "Variance", "size": 1876},
{"name": "Xor", "size": 1101}
]
},
{
"name": "scale",
"children": [
{"name": "IScaleMap", "size": 2105},
{"name": "LinearScale", "size": 1316},
{"name": "LogScale", "size": 3151},
{"name": "OrdinalScale", "size": 3770},
{"name": "QuantileScale", "size": 2435},
{"name": "QuantitativeScale", "size": 4839},
{"name": "RootScale", "size": 1756},
{"name": "Scale", "size": 4268},
{"name": "ScaleType", "size": 1821},
{"name": "TimeScale", "size": 5833}
]
},
{
"name": "util",
"children": [
{"name": "Arrays", "size": 8258},
{"name": "Colors", "size": 10001},
{"name": "Dates", "size": 8217},
{"name": "Displays", "size": 12555},
{"name": "Filter", "size": 2324},
{"name": "Geometry", "size": 10993},
{
"name": "heap",
"children": [
{"name": "FibonacciHeap", "size": 9354},
{"name": "HeapNode", "size": 1233}
]
},
{"name": "IEvaluable", "size": 335},
{"name": "IPredicate", "size": 383},
{"name": "IValueProxy", "size": 874},
{
"name": "math",
"children": [
{"name": "DenseMatrix", "size": 3165},
{"name": "IMatrix", "size": 2815},
{"name": "SparseMatrix", "size": 3366}
]
},
{"name": "Maths", "size": 17705},
{"name": "Orientation", "size": 1486},
{
"name": "palette",
"children": [
{"name": "ColorPalette", "size": 6367},
{"name": "Palette", "size": 1229},
{"name": "ShapePalette", "size": 2059},
{"name": "SizePalette", "size": 2291}
]
},
{"name": "Property", "size": 5559},
{"name": "Shapes", "size": 19118},
{"name": "Sort", "size": 6887},
{"name": "Stats", "size": 6557},
{"name": "Strings", "size": 22026}
]
},
{
"name": "vis",
"children": [
{
"name": "axis",
"children": [
{"name": "Axes", "size": 1302},
{"name": "Axis", "size": 24593},
{"name": "AxisGridLine", "size": 652},
{"name": "AxisLabel", "size": 636},
{"name": "CartesianAxes", "size": 6703}
]
},
{
"name": "controls",
"children": [
{"name": "AnchorControl", "size": 2138},
{"name": "ClickControl", "size": 3824},
{"name": "Control", "size": 1353},
{"name": "ControlList", "size": 4665},
{"name": "DragControl", "size": 2649},
{"name": "ExpandControl", "size": 2832},
{"name": "HoverControl", "size": 4896},
{"name": "IControl", "size": 763},
{"name": "PanZoomControl", "size": 5222},
{"name": "SelectionControl", "size": 7862},
{"name": "TooltipControl", "size": 8435}
]
},
{
"name": "data",
"children": [
{"name": "Data", "size": 20544},
{"name": "DataList", "size": 19788},
{"name": "DataSprite", "size": 10349},
{"name": "EdgeSprite", "size": 3301},
{"name": "NodeSprite", "size": 19382},
{
"name": "render",
"children": [
{"name": "ArrowType", "size": 698},
{"name": "EdgeRenderer", "size": 5569},
{"name": "IRenderer", "size": 353},
{"name": "ShapeRenderer", "size": 2247}
]
},
{"name": "ScaleBinding", "size": 11275},
{"name": "Tree", "size": 7147},
{"name": "TreeBuilder", "size": 9930}
]
},
{
"name": "events",
"children": [
{"name": "DataEvent", "size": 2313},
{"name": "SelectionEvent", "size": 1880},
{"name": "TooltipEvent", "size": 1701},
{"name": "VisualizationEvent", "size": 1117}
]
},
{
"name": "legend",
"children": [
{"name": "Legend", "size": 20859},
{"name": "LegendItem", "size": 4614},
{"name": "LegendRange", "size": 10530}
]
},
{
"name": "operator",
"children": [
{
"name": "distortion",
"children": [
{"name": "BifocalDistortion", "size": 4461},
{"name": "Distortion", "size": 6314},
{"name": "FisheyeDistortion", "size": 3444}
]
},
{
"name": "encoder",
"children": [
{"name": "ColorEncoder", "size": 3179},
{"name": "Encoder", "size": 4060},
{"name": "PropertyEncoder", "size": 4138},
{"name": "ShapeEncoder", "size": 1690},
{"name": "SizeEncoder", "size": 1830}
]
},
{
"name": "filter",
"children": [
{"name": "FisheyeTreeFilter", "size": 5219},
{"name": "GraphDistanceFilter", "size": 3165},
{"name": "VisibilityFilter", "size": 3509}
]
},
{"name": "IOperator", "size": 1286},
{
"name": "label",
"children": [
{"name": "Labeler", "size": 9956},
{"name": "RadialLabeler", "size": 3899},
{"name": "StackedAreaLabeler", "size": 3202}
]
},
{
"name": "layout",
"children": [
{"name": "AxisLayout", "size": 6725},
{"name": "BundledEdgeRouter", "size": 3727},
{"name": "CircleLayout", "size": 9317},
{"name": "CirclePackingLayout", "size": 12003},
{"name": "DendrogramLayout", "size": 4853},
{"name": "ForceDirectedLayout", "size": 8411},
{"name": "IcicleTreeLayout", "size": 4864},
{"name": "IndentedTreeLayout", "size": 3174},
{"name": "Layout", "size": 7881},
{"name": "NodeLinkTreeLayout", "size": 12870},
{"name": "PieLayout", "size": 2728},
{"name": "RadialTreeLayout", "size": 12348},
{"name": "RandomLayout", "size": 870},
{"name": "StackedAreaLayout", "size": 9121},
{"name": "TreeMapLayout", "size": 9191}
]
},
{"name": "Operator", "size": 2490},
{"name": "OperatorList", "size": 5248},
{"name": "OperatorSequence", "size": 4190},
{"name": "OperatorSwitch", "size": 2581},
{"name": "SortOperator", "size": 2023}
]
},
{"name": "Visualization", "size": 16540}
]
}
]
});
</script>
</body>
</html>
5 个解决方案
#1
20
The way to determine the coordinates depends on what element you're working with. For circle
s for example, the cx
and cy
attributes determine the center position. In addition, you may have a translation
applied through the transform
attribute which changes the reference point of any coordinates.
确定坐标的方法取决于你使用的是什么元素。对于圆圈,cx和cy属性决定了中心位置。此外,您还可以通过转换属性应用转换属性,从而改变任何坐标的参考点。
Most of the ways used in general to get screen coordinates won't work for SVGs. In addition, you may not want absolute coordinates if the line you want to draw is in the same container as the elements it connects.
通常用于获得屏幕坐标的大多数方法都不能用于SVGs。此外,如果您想要绘制的行与它连接的元素在同一个容器中,您可能不需要绝对坐标。
Edit:
编辑:
In your particular code, it's quite difficult to get the position of the node because its determined by a translation of the parent element. So you need to get the transform attribute of the parent node and extract the translation from that.
在您的特定代码中,很难获得节点的位置,因为它由父元素的翻译决定。因此需要获取父节点的转换属性并从中提取转换。
d3.transform(d3.select(this.parentNode).attr("transform")).translate
Working jsfiddle here.
jsfiddle这里工作。
#2
44
The element.getBoundingClientRect()
method will return the proper coordinates of an element relative to the viewport regardless of whether the svg has been scaled and/or translated.
getboundingclientrect()方法将返回一个元素相对于viewport的适当坐标,无论svg是否被缩放和/或翻译。
看这个问题和答案。
While getBBox() works for an untransformed space, if scale and translation have been applied to the layout then it will no longer be accurate. The getBoundingClientRect() function has worked well for me in a force layout project when pan and zoom are in effect, where I wanted to attach HTML Div elements as labels to the nodes instead of using SVG Text elements.
当getBBox()用于未转换的空间时,如果将缩放和转换应用到布局中,那么它将不再是准确的。当平移和缩放生效时,getBoundingClientRect()函数在一个强制布局项目中很有效,我希望将HTML Div元素作为标签附加到节点上,而不是使用SVG文本元素。
#3
5
You can use the function getBBox() to get the bounding box for the path. This will give you the position and size of the tightest rectangle that could contain the rendered path.
您可以使用函数getBBox()来获得路径的边界框。这将给出可能包含呈现路径的最紧的矩形的位置和大小。
An advantage of using this method over reading the x and y values is that it will work with all graphical objects. There are more objects than paths that do not have x and y, for example circles that have cx and cy instead.
使用这种方法来读取x和y值的一个优点是,它将与所有图形对象一起工作。有更多的对象,而不是没有x和y的路径,例如有cx和cy的圆。
#4
3
I use the consolidate function, like so:
我使用合并函数,像这样:
element.transform.baseVal.consolidate()
The .e and .f values correspond to the x and y coordinates
e和。f值对应于x和y坐标。
#5
1
i can handle it like that ;
我可以这样处理;
svg.selectAll("rect")
.data(zones)
.enter()
.append("rect")
.attr("id", function (d) { return "zone" + d.zone; })
.attr("class", "zone")
.attr("x", function (d, i) {
if (parseInt(i / (wcount)) % 2 == 0) {
this.xcor = (i % wcount) * zoneW;
}
else {
this.xcor = (zoneW * (wcount - 1)) - ((i % wcount) * zoneW);
}
return this.xcor;
})
and anymore you can find x coordinate
你可以找到x坐标。
svg.select("#zone1").on("click",function(){alert(this.xcor});
#1
20
The way to determine the coordinates depends on what element you're working with. For circle
s for example, the cx
and cy
attributes determine the center position. In addition, you may have a translation
applied through the transform
attribute which changes the reference point of any coordinates.
确定坐标的方法取决于你使用的是什么元素。对于圆圈,cx和cy属性决定了中心位置。此外,您还可以通过转换属性应用转换属性,从而改变任何坐标的参考点。
Most of the ways used in general to get screen coordinates won't work for SVGs. In addition, you may not want absolute coordinates if the line you want to draw is in the same container as the elements it connects.
通常用于获得屏幕坐标的大多数方法都不能用于SVGs。此外,如果您想要绘制的行与它连接的元素在同一个容器中,您可能不需要绝对坐标。
Edit:
编辑:
In your particular code, it's quite difficult to get the position of the node because its determined by a translation of the parent element. So you need to get the transform attribute of the parent node and extract the translation from that.
在您的特定代码中,很难获得节点的位置,因为它由父元素的翻译决定。因此需要获取父节点的转换属性并从中提取转换。
d3.transform(d3.select(this.parentNode).attr("transform")).translate
Working jsfiddle here.
jsfiddle这里工作。
#2
44
The element.getBoundingClientRect()
method will return the proper coordinates of an element relative to the viewport regardless of whether the svg has been scaled and/or translated.
getboundingclientrect()方法将返回一个元素相对于viewport的适当坐标,无论svg是否被缩放和/或翻译。
看这个问题和答案。
While getBBox() works for an untransformed space, if scale and translation have been applied to the layout then it will no longer be accurate. The getBoundingClientRect() function has worked well for me in a force layout project when pan and zoom are in effect, where I wanted to attach HTML Div elements as labels to the nodes instead of using SVG Text elements.
当getBBox()用于未转换的空间时,如果将缩放和转换应用到布局中,那么它将不再是准确的。当平移和缩放生效时,getBoundingClientRect()函数在一个强制布局项目中很有效,我希望将HTML Div元素作为标签附加到节点上,而不是使用SVG文本元素。
#3
5
You can use the function getBBox() to get the bounding box for the path. This will give you the position and size of the tightest rectangle that could contain the rendered path.
您可以使用函数getBBox()来获得路径的边界框。这将给出可能包含呈现路径的最紧的矩形的位置和大小。
An advantage of using this method over reading the x and y values is that it will work with all graphical objects. There are more objects than paths that do not have x and y, for example circles that have cx and cy instead.
使用这种方法来读取x和y值的一个优点是,它将与所有图形对象一起工作。有更多的对象,而不是没有x和y的路径,例如有cx和cy的圆。
#4
3
I use the consolidate function, like so:
我使用合并函数,像这样:
element.transform.baseVal.consolidate()
The .e and .f values correspond to the x and y coordinates
e和。f值对应于x和y坐标。
#5
1
i can handle it like that ;
我可以这样处理;
svg.selectAll("rect")
.data(zones)
.enter()
.append("rect")
.attr("id", function (d) { return "zone" + d.zone; })
.attr("class", "zone")
.attr("x", function (d, i) {
if (parseInt(i / (wcount)) % 2 == 0) {
this.xcor = (i % wcount) * zoneW;
}
else {
this.xcor = (zoneW * (wcount - 1)) - ((i % wcount) * zoneW);
}
return this.xcor;
})
and anymore you can find x coordinate
你可以找到x坐标。
svg.select("#zone1").on("click",function(){alert(this.xcor});