d3.js - 我需要哪些概念和技术来实现这种图
问题描述
我想画出某些功能块如何相互交互的动态视觉效果。我很难定义我需要什么样的图表,以及最适合从什么(如果有的话)d3 布局函数开始。我什至不确定我的示例是否属于图表的定义。
总体思路是将一组函数及其输入和输出可视化。它以一组输入开始,以一组输出结束。在这之间有几个函数,每个函数都接受输入并生成 1 个或多个输出。每个输出都可以作为一个或多个功能的输入。所以每条边/线代表一个输出被转移到一个函数作为输入(并且是单向的)
我不是在寻找代码中的答案,而是对我需要从哪些概念开始的洞察力。该图像可能有问题,无法从字面上实现,但我无法指出具体是什么。
解决方案
const nodes = [
{
id: 1,
title: 'Function A',
x: 100,
y: 25,
points: [
{
id: 11,
dx: 50,
dy: 0
},
{
id: 12,
dx: 0,
dy: 20
}
]
},
{
id: 2,
title: 'Function B',
x: 300,
y: 100,
points: [
{
id: 21,
dx: -50,
dy: 0
},
{
id: 22,
dx: 0,
dy: 20
}
]
},
{
id: 3,
title: 'Function C',
x: 170,
y: 160,
points: [
{
id: 31,
dx: 0,
dy: -20
},
{
id: 32,
dx: 50,
dy: 0
}
]
}
];
const links = [
{source: 11, target:21},
{source: 12, target:31},
{source: 22, target:32}
];
var selectedNode = null;
const renderNodes = svg => {
const allNodes = svg.selectAll('.node').data(nodes, node => node.id);
const addedNodes = allNodes.enter()
.append('g')
.style('cursor', 'pointer')
.attr('transform', d => `translate(${d.x},${d.y})`)
.on('click', d => {
selectedNode = d.id;
renderAll();
});
addedNodes.append('rect')
.attr('width', 100)
.attr('height', 40)
.attr('x', -50)
.attr('y', -20)
.attr('rx', 5);
addedNodes.append('text')
.text(d => d.title)
.style('fill', 'white')
.attr('y', 6)
.attr('text-anchor', 'middle');
addedNodes.merge(allNodes)
.select('rect')
.style('fill', d => (d.id === selectedNode) ? 'blue' : 'black');
allNodes.exit().remove();
};
const renderConnectionPoints = (svg, points) => {
const allPoints = svg.selectAll('.point').data(points, point => point.id);
const addedPoints = allPoints.enter()
.append('g')
.style('cursor', 'pointer')
.attr('transform', d => `translate(${d.x},${d.y})`);
addedPoints.append('circle')
.attr('r', 4)
.style('fill', 'white');
addedPoints.merge(allPoints)
.select('circle')
.style('stroke', d => (d.parentId === selectedNode) ? 'blue' : 'black');
allPoints.exit().remove();
}
const renderLinks = (svg, _links) => {
const linkPath = d => `M ${d.source.x}, ${d.source.y}
C ${(d.source.x + d.target.x) / 2}, ${d.source.y}
${(d.source.x + d.target.x) / 2}, ${d.target.y}
${d.target.x}, ${d.target.y}`;
const allLinks = svg.selectAll('.link').data(_links, link => link.id);
const addedLinks = allLinks.enter()
.append('path')
.style('fill', 'none')
.attr('d', linkPath);
addedLinks.merge(allLinks)
.style('stroke', d => (d.source.parentId === selectedNode ||
d.target.parentId === selectedNode) ? 'blue' : 'lightgray');
allLinks.exit().remove();
}
const getPoints = () => nodes.reduce((all, node) => {
node.points.forEach(point => all.push({
id: point.id, x: node.x + point.dx, y: node.y + point.dy, parentId: node.id}));
return all;
}, []);
const getLinks = points => links.map(link => {
const source = points.find(point => point.id === link.source);
const target = points.find(point => point.id === link.target);
return {source, target};
});
const renderAll = () => {
const svg = d3.select('svg');
const points = getPoints();
const _links = getLinks(points);
renderNodes(svg);
renderLinks(svg, _links);
renderConnectionPoints(svg, points);
}
renderAll();
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width='400' height='180'>
</svg>
Hi, Take a look at the snippet. The data model is very simple: nodes, their connection points and links Just provide your data and use the snippet's code to render it. Good luck and feel free to ask any question :)
推荐阅读
- java - Java - 如何将方形数组(二维)向右旋转 90 度?
- docker - Go 1.11 Docker build 中自己的包的未知导入路径
- r - 自定义R中的排序功能
- raspberry-pi - 播放视频时,Raspberry Pi 3 上的 Gstreamer 噼啪声
- oracle - 为什么我的 Oracle ORDS 插件不起作用?
- excel - 如果 X 和 Y 为空,则邮件合并跳过
- reactjs - antd 不导入所有图标
- c# - 验证输入 DataGridView 的日期
- database-normalization - 这是违反 BCNF 吗?
- c++ - 如何限制 QLayout 增长?