我正在尝试使用父数据和嵌套数据生成SVG元素,但是在出现问题时遇到了问题。这与Combining Parent and Nested Data with d3.js非常相似,这非常有用,但并未完全解决我的问题。
对于这个例子,我正在绘制由多个点组成的SVG路径。我想绘制每个路径的线段的切线。它主要是工作,但我不能为切线路径创建组,而是最终在SVG的根目录。我希望结构看起来像这样:
<svg width="100" height="100">
<g id="0" class="linegroup">
<g class="linepath">
<path d="M0,0L10,10L20,20"></path>
</g>
<g class="tangentgroup">
<path class="tan" d="M5,5L-5,15"></path>
<path class="tan" d="M15,15L5,25"></path>
</g>
</g>
<g id="1" class="linegroup">
<g class="linepath">
<path d="M30,30L40,40L50,50"></path>
</g>
<g class="tangentgroup">
<path class="tan" d="M35,35L25,45"></path>
<path class="tan" d="M45,45L35,55"></path>
</g>
</g>
</svg>
但相反,所有切线路径都被附加到svg,我无法创建“切线组”SVG组:
<svg width="100" height="100">
<g id="0" class="linegroup">
<g class="linepath">
<path d="M0,0L10,10L20,20"></path>
</g>
</g>
<g id="1" class="linegroup">
<g class="linepath">
<path d="M30,30L40,40L50,50"></path>
</g>
</g>
<path class="tan" d="M5,5L-5,15"></path>
<path class="tan" d="M15,15L5,25"></path>
<path class="tan" d="M35,35L25,45"></path>
<path class="tan" d="M45,45L35,55"></path>
</svg>
这是我目前的代码。我也愿意接受有关如何以其他方式改进它的建议。
// test data
var lines = [{
id: 0,
coordinates: [[0,0],[10,10],[20,20]]},
{
id: 1,
coordinates: [[30,30],[40,40],[50,50]]
}];
var diameter = 100;
var d3line = d3.svg.line();
var svg = d3.select("body").append("svg")
.attr("width", diameter)
.attr("height", diameter);
// create groups for each line and its tangents
var linegroups = svg.selectAll('.linegroup')
.data(lines)
.enter().append('g')
.attr('class', 'linegroup')
.attr('id', function(d) { return d.id; });
// add the line path
linegroups.append('g')
.attr('class', 'linepath')
.append('path')
.attr("d", function(d) { return d3line(d.coordinates); });
/////// Problem section ////////
// create a group for the line's segment's tangents,
// and create a tangent path for each segment
linegroups.each(function(line, i) {
d3.selectAll(this)
// The "tangentgroup" groups never show up
.append('g')
.attr('class', 'tangentgroup')
.data(lineSegments(line.coordinates))
// 'tan' paths get appended to parent svg, not to 'linegroup'.
.enter().append('path')
.attr('class', 'tan')
.attr('d', function (d) {
return d3line(tangentFromMidpoint(d));
});
});
////////////////////////////////
// returns lineSegments, comprised of pairs of points
function lineSegments (coordinates) {
return d3.range(coordinates.length - 1).map(function(i) {
return [coordinates[i], coordinates[i + 1]];
});
}
// returns a tangent line starting from the mid-point of the original line
function tangentFromMidpoint (line) {
var p1 = line[0];
var p2 = line[1];
var midPoint = [(p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2];
var tv = tangentVectors(p1,p2)[0];
return [midPoint, [tv[0] + midPoint[0], tv[1] + midPoint[1]]];
}
// Returns both tangent vectors (not unit-vector) for a line
function tangentVectors (p1,p2) {
// if we define dx=x2-x1 and dy=y2-y1,
// then the normals are (-dy, dx) and (dy, -dx)
var dx = p2[0] - p1[0];
var dy = p2[1] - p1[1];
return [[-dy, dx, dy, -dx]];
}
答案 0 :(得分:1)
问题在于,您首先在没有.data()
的情况下致电.selectAll()
,然后对.enter()
选项进行操作。代码应该是
linegroups.each(function(line, i) {
d3.select(this)
.append('g')
.attr('class', 'tangentgroup')
.selectAll("path")
.data(lineSegments(line.coordinates))
.enter().append('path')
.attr('class', 'tan')
.attr('d', function (d) {
return d3line(tangentFromMidpoint(d));
});
});
完整演示here。你甚至不需要.each()
:
linegroups.append('g')
.attr('class', 'tangentgroup')
.selectAll("path")
.data(function(line) { return lineSegments(line.coordinates); })
.enter().append('path')
.attr('class', 'tan')
.attr('d', function (d) {
return d3line(tangentFromMidpoint(d));
});
完整演示here。