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

时间:2015-03-21 06:43:37

标签: javascript svg d3.js

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

DEMO 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”属性:

enter image description here

我知道,我可以使用该模式,我将逐一添加连接器:

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(...);
});

但我正在寻找一些“内联”原生d3解决方案。在绘图之前我应该​​“准备数据”的解决方案在我的情况下不起作用。这只是一个复杂问题的典范。遗憾!

2 个答案:

答案 0 :(得分:1)

我想也许你对d3.svg.line()的使用方式有点误解。在这个例子中:

var lineGenerator = d3.svg.line()

lineGenerator是一个函数,它接受一个点数组并返回一个String,它是分配给属性<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

答案 1 :(得分:0)

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

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

作为参数,提到为points,我们可以使用带点数组的函数返回如下:

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

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

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

DEMO: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]
});

DEMO:http://jsfiddle.net/2efxadLy/6/