为与 D3.js 中的圆对齐的路径添加一致的边距
Add consistent margin to paths aligned to circles in D3.js
我有 this graph I've made with D3.js,它基本上只是几个圆圈,中间有路径。我想要的是将路径算法减少到尽可能简洁和整齐地计算路径的 "margins" 的东西,这样它们就不会与圆圈重叠。
这是 HTML:
<div class="graph"></div>
这里是 JavaScript:
var graph = d3.select('.graph')
.append('svg')
.attr('width', window.innerWidth)
.attr('height', window.innerHeight);
var defs = graph.append('svg:defs');
var blueGradient = defs.append('svg:linearGradient')
.attr('id', 'b')
.attr('x1', 0)
.attr('y1', 0)
.attr('x2', 0)
.attr('y2', 1)
.attr('spreadMethod', 'pad');
blueGradient.append('svg:stop')
.attr('offset', '0%')
.attr('stop-color', '#e4f5fc')
.attr('stop-opacity', 1);
blueGradient.append('svg:stop')
.attr('offset', '100%')
.attr('stop-color', '#2ab0ed')
.attr('stop-opacity', 1);
var orangeGradient = defs.append('svg:linearGradient')
.attr('id', 'o')
.attr('x1', 0)
.attr('y1', 0)
.attr('x2', 0)
.attr('y2', 1)
.attr('spreadMethod', 'pad');
orangeGradient.append('svg:stop')
.attr('offset', '0%')
.attr('stop-color', '#f6e6b4')
.attr('stop-opacity', 1);
orangeGradient.append('svg:stop')
.attr('offset', '100%')
.attr('stop-color', '#ed9017')
.attr('stop-opacity', 1);
var head = defs.append('svg:marker')
.attr('id', 'head')
.attr('orient', 'auto')
.attr('markerWidth', 2)
.attr('markerHeight', 4)
.attr('refX', 0.1)
.attr('refY', 2);
head.append('path')
.attr('d', 'M0,0 V4 L2,2 Z')
.attr('fill', '#aaa');
var nodes = [{
x: 200,
y: 50,
c: 'b',
},
{
x: 400,
y: 50,
c: 'b'
},
{
x: 600,
y: 50,
c: 'b'
},
{
x: 725,
y: 175,
c: 'b'
},
{
x: 600,
y: 300,
c: 'o'
},
{
x: 400,
y: 300,
c: 'o'
},
{
x: 200,
y: 300,
c: 'o'
},
{
x: 75,
y: 175,
c: 'o'
}
];
var lineData = d3.line()
.x(function(d) {
return d.x;
})
.y(function(d) {
return d.y;
});
graph.selectAll('path.nodes')
.data(nodes)
.enter()
.append('path')
.attr('d', function(currentNode, i) {
var nextNode = i < nodes.length - 1 ?
nodes[i + 1] :
nodes[0];
startPath = {
x: currentNode.x,
y: currentNode.y,
c: currentNode.c
};
endPath = {
x: nextNode.x,
y: nextNode.y,
c: nextNode.c
};
var diff = {
x: nextNode.x - currentNode.x,
y: nextNode.y - currentNode.y
};
var margins = {
current: {
x: 0,
y: 0
},
next: {
x: 0,
y: 0
}
};
if (diff.x > 0) {
margins.current.x = 20;
} else if (diff.x < 0) {
margins.current.x = -20;
}
if (diff.y > 0) {
margins.current.y = 20;
} else if (diff.y < 0) {
margins.current.y = -20;
}
if (margins.current.x != 0) {
margins.next.x = margins.current.x < 0 ?
Math.abs(margins.current.x * 1.5) :
margins.current.x * -1.5;
}
if (margins.current.y != 0) {
margins.next.y = margins.current.y < 0 ?
Math.abs(margins.current.y * 1.5) :
margins.current.y * -1.5;
}
startPath.x += margins.current.x;
startPath.y += margins.current.y;
endPath.x += margins.next.x;
endPath.y += margins.next.y;
return lineData([startPath, endPath]);
})
.attr('stroke', '#aaa')
.attr('stroke-width', 10)
.attr('fill', 'none')
.attr('marker-end', 'url(#head)');
graph.selectAll('circle.nodes')
.data(nodes)
.enter()
.append('svg:circle')
.attr('cx', function(d) {
return d.x;
})
.attr('cy', function(d) {
return d.y;
})
.attr('r', 19)
.attr('fill', function(d) {
return 'url(#' + d.c + ')';
})
.attr('stroke', function(d) {
switch (d.c) {
case 'b':
return '#2E75B6';
case 'o':
return '#BF9000';
}
});
谁能帮我弄清楚为什么我的所有路径都没有整齐一致地与圆圈隔开? 20
单位距离(我通过 margins
对象添加的边距)不应该是相同的,无论路径与圆的角度和方向如何?
如果代码中还有什么我可以优化的地方,请告诉我。谢谢!
这里的问题是一个几何问题。同y
位置时一个圆到另一个圆的距离小于不在同一位置y
时一个圆到另一个圆的距离 ] 位置。请记住,对于边为 s 的给定正方形,该正方形的对角线为 s√2.
因此,您可以使用另一个幻数改进您的 if
语句:
if (diff.x > 0 && diff.y === 0) {
margins.current.x = 30;
} else if (diff.x < 0 && diff.y === 0) {
margins.current.x = -30;
} else if (diff.x > 0) {
margins.current.x = 20;
} else if (diff.x < 0) {
margins.current.x = -20;
}
这是更新后的 fiddle:https://jsfiddle.net/z5g9mtr7/
我有 this graph I've made with D3.js,它基本上只是几个圆圈,中间有路径。我想要的是将路径算法减少到尽可能简洁和整齐地计算路径的 "margins" 的东西,这样它们就不会与圆圈重叠。
这是 HTML:
<div class="graph"></div>
这里是 JavaScript:
var graph = d3.select('.graph')
.append('svg')
.attr('width', window.innerWidth)
.attr('height', window.innerHeight);
var defs = graph.append('svg:defs');
var blueGradient = defs.append('svg:linearGradient')
.attr('id', 'b')
.attr('x1', 0)
.attr('y1', 0)
.attr('x2', 0)
.attr('y2', 1)
.attr('spreadMethod', 'pad');
blueGradient.append('svg:stop')
.attr('offset', '0%')
.attr('stop-color', '#e4f5fc')
.attr('stop-opacity', 1);
blueGradient.append('svg:stop')
.attr('offset', '100%')
.attr('stop-color', '#2ab0ed')
.attr('stop-opacity', 1);
var orangeGradient = defs.append('svg:linearGradient')
.attr('id', 'o')
.attr('x1', 0)
.attr('y1', 0)
.attr('x2', 0)
.attr('y2', 1)
.attr('spreadMethod', 'pad');
orangeGradient.append('svg:stop')
.attr('offset', '0%')
.attr('stop-color', '#f6e6b4')
.attr('stop-opacity', 1);
orangeGradient.append('svg:stop')
.attr('offset', '100%')
.attr('stop-color', '#ed9017')
.attr('stop-opacity', 1);
var head = defs.append('svg:marker')
.attr('id', 'head')
.attr('orient', 'auto')
.attr('markerWidth', 2)
.attr('markerHeight', 4)
.attr('refX', 0.1)
.attr('refY', 2);
head.append('path')
.attr('d', 'M0,0 V4 L2,2 Z')
.attr('fill', '#aaa');
var nodes = [{
x: 200,
y: 50,
c: 'b',
},
{
x: 400,
y: 50,
c: 'b'
},
{
x: 600,
y: 50,
c: 'b'
},
{
x: 725,
y: 175,
c: 'b'
},
{
x: 600,
y: 300,
c: 'o'
},
{
x: 400,
y: 300,
c: 'o'
},
{
x: 200,
y: 300,
c: 'o'
},
{
x: 75,
y: 175,
c: 'o'
}
];
var lineData = d3.line()
.x(function(d) {
return d.x;
})
.y(function(d) {
return d.y;
});
graph.selectAll('path.nodes')
.data(nodes)
.enter()
.append('path')
.attr('d', function(currentNode, i) {
var nextNode = i < nodes.length - 1 ?
nodes[i + 1] :
nodes[0];
startPath = {
x: currentNode.x,
y: currentNode.y,
c: currentNode.c
};
endPath = {
x: nextNode.x,
y: nextNode.y,
c: nextNode.c
};
var diff = {
x: nextNode.x - currentNode.x,
y: nextNode.y - currentNode.y
};
var margins = {
current: {
x: 0,
y: 0
},
next: {
x: 0,
y: 0
}
};
if (diff.x > 0) {
margins.current.x = 20;
} else if (diff.x < 0) {
margins.current.x = -20;
}
if (diff.y > 0) {
margins.current.y = 20;
} else if (diff.y < 0) {
margins.current.y = -20;
}
if (margins.current.x != 0) {
margins.next.x = margins.current.x < 0 ?
Math.abs(margins.current.x * 1.5) :
margins.current.x * -1.5;
}
if (margins.current.y != 0) {
margins.next.y = margins.current.y < 0 ?
Math.abs(margins.current.y * 1.5) :
margins.current.y * -1.5;
}
startPath.x += margins.current.x;
startPath.y += margins.current.y;
endPath.x += margins.next.x;
endPath.y += margins.next.y;
return lineData([startPath, endPath]);
})
.attr('stroke', '#aaa')
.attr('stroke-width', 10)
.attr('fill', 'none')
.attr('marker-end', 'url(#head)');
graph.selectAll('circle.nodes')
.data(nodes)
.enter()
.append('svg:circle')
.attr('cx', function(d) {
return d.x;
})
.attr('cy', function(d) {
return d.y;
})
.attr('r', 19)
.attr('fill', function(d) {
return 'url(#' + d.c + ')';
})
.attr('stroke', function(d) {
switch (d.c) {
case 'b':
return '#2E75B6';
case 'o':
return '#BF9000';
}
});
谁能帮我弄清楚为什么我的所有路径都没有整齐一致地与圆圈隔开? 20
单位距离(我通过 margins
对象添加的边距)不应该是相同的,无论路径与圆的角度和方向如何?
如果代码中还有什么我可以优化的地方,请告诉我。谢谢!
这里的问题是一个几何问题。同y
位置时一个圆到另一个圆的距离小于不在同一位置y
时一个圆到另一个圆的距离 ] 位置。请记住,对于边为 s 的给定正方形,该正方形的对角线为 s√2.
因此,您可以使用另一个幻数改进您的 if
语句:
if (diff.x > 0 && diff.y === 0) {
margins.current.x = 30;
} else if (diff.x < 0 && diff.y === 0) {
margins.current.x = -30;
} else if (diff.x > 0) {
margins.current.x = 20;
} else if (diff.x < 0) {
margins.current.x = -20;
}
这是更新后的 fiddle:https://jsfiddle.net/z5g9mtr7/