计算未在 data() 范围内定义的折线坐标

Calculations of polyline coordinates not defined in data() scope

我在计算 svg:poly 元素的 "d" 属性时遇到问题。我做的模型的情况:

演示版http://jsfiddle.net/2efxadLy/1/

// array of points
var points = [{
    name: "a",
    coord: [22, 35]
}, {
    name: "b",
    coord: [2, 55]
}, {
    name: "c",
    coord: [42, 5]
}, {
    name: "d",
    coord: [5, 57]
}];

// array of connectors
var connectors = [
    ["a", "c"],
    ["b", "c"],
    ["d", "a"]
];

// styles
var styles = {
line: {
    "stroke": "black",
    "stroke-width": 1,
    "fill": "none"
},
board: {
    "width": 100,
    "height": 100
}};

// svg element
var svg = d3.select("body").append("svg").attr(styles.board);

// three connectors between points
var path = svg.selectAll("path").data(connectors).enter().append("svg:path").attr(styles.line);
// attempt to fill the "d" attribute of the path
path.attr("d", function (d) {// d -- the array of connector pair ["a", "c"] etc. 
    var from = d[0],// "a"
        to = d[1],// "c"
        point_from = points.filter(function (item) {// [22,35]
            return (item.name === from);
        })[0],
        point_to = points.filter(function (item) {// [42,5]
            return (item.name === to);
        })[0];
    var coords = [point_from, point_to];
    // ERROR!
    // I can not place coords in line() function
    // the line() function expects some "d3.data" type argument
    // but there is no "d3.selection" to produce this data type
    var l = d3.svg.line(/* missed content */).extrapolate("basis");
    return(l);
});

因此,我有 3 个 path 没有 "d" 属性:

我知道,我可以使用模式,我将在其中一个接一个地添加连接器:

var line_function = d3.svg.line().x(function(d) {
            return (d.x);
        }).y(function(d) {
            return d.y;
        }).interpolate("basis");

connectors.forEach(function(pair){
    var from = pair[0], to = pair[1];
    var coordinate_array = [{x: ..., y; ...},{x: ..., y; ...}];
    board.data(coordinate_array).enter().append("svg:path").attr("d", line_function(coordinate_array)).attr(...);
});

但我正在寻找一些 "inline" 原生 d3 解决方案。在我的情况下,在绘图之前我应该​​ "prepare the data" 的解决方案不起作用。它只是一个复杂问题的模型。抱歉!

我想您可能对 d3.svg.line() 的使用方式有些误解。在这个例子中:

var lineGenerator = d3.svg.line()

lineGenerator 是一个函数,它接受一个点数组和 returns 一个字符串,该字符串是分配给属性 <path d="...">.

的路径描述

在所有这些中,不需要绑定到 d3 选择。

所以你可以根据你的 coords 数组为你需要的路径描述创建一个生成器,如下所示:

// converts an array of 2 points (coords) or svg line path data
var lineGenerator = d3.svg.line()
  .x(function(point) { return point.coord[0]; })
  .y(function(point) { return point.coord[1]; })
  .interpolate("basis")

稍后,在 path.attr("d", function (d) { ... }) 中,组装完成后 var coords = [point_from, point_to],只需调用线生成器即可。

return lineGenerator(coords);

这是fiddle

错误是行生成器函数 d3.svg.line() 应该被内联调用为 (fn)():

path.attr("d", (d3.svg.line())(/* points */));     

作为参数,提到为 points,我们可以将函数与点数组 return 一起使用,例如:

path.attr("d", (d3.svg.line())(function(){
    return([[1,2],[3,4],[5,6]]);
})); 

方法 x()y() 应该仅在坐标关联数组的情况下使用,并且在定义为对数组的点的情况下可以避免:

[1,2],[3,4],[5,6]

演示:http://jsfiddle.net/602fxj2e/

最后,我的示例代码应该这样更正:

// svg element
var p = d3.select("body").append("svg").attr(styles.board).selectAll("path").data(connectors).enter().append("svg:path").attr(styles.line)
    .attr("d", function (d) {
    var from = d[0], // "a"
        to = d[1], // "c"
        point_from = points.filter(function (item) { // [22,35]
            return (item.name === from);
        })[0].coord,
        point_to = points.filter(function (item) { // [42,5]
            return (item.name === to);
        })[0].coord,
        dots = [point_from, [point_from[0] + 100, point_from[1] + 50], // just to make it looks funny
            [point_to[0] + 200, point_to[1] + 100], point_to];
    return ((d3.svg.line().interpolate("basis"))(dots));
    // simple return should be [point_from, point_to]
});

演示:http://jsfiddle.net/2efxadLy/6/