背景
在React前端項目中使用D3JS定製可視化組件,treemap支持節點的新建、刪除、縮放、全屏等功能
技術實現
首先圖表線和點的數據
// dataSource初始數據
const hierarchyData = d3.hierarchy(dataSource)
// hierarchy layout and add node.x,node.y
const treeNode = this.tree(hierarchyData);
nodes = treeNode.descendants();
links = treeNode.links();
nodes = nodes.map(node => {
if (node.active) {
node.active = false;
if (node.parent) {
node.parent.active = false;
}
}
if (node.data.name === currentNode.name) {
node.active = true;
if (node.parent) {
node.parent.active = true;
}
}
return node;
});
畫線path
<g>
{
links.map((link, i) => {
const start = { x: link.source.x, y: link.source.y + CONSTANT.STARTBUF };
const end = { x: link.target.x, y: link.target.y + CONSTANT.ENDBUF };
const pathLink = this.bezierCurveGenerator({ source: start, target: end });
return <path
key={i}
d={pathLink}
fill='none'
stroke={CONSTANT.THEME.LINESTROKE}
strokeWidth='1'
strokeDasharray={CONSTANT.THEME.DASHARRAY}
markerEnd='url(#arrow)'/>
})}
</g>
畫節點
<g>
{nodes.map((node, i) => {
node.type = node.data.type;
node.tmp = node.data.tmp;
node.error = node.data.error;
node.avgTime = node.data.avgTime;
node.name = node.data.name;
return (<g key={i} transform={`translate(${node.y}, ${node.x - 10})`}>
<defs>
<marker id="arrow"
markerUnits="strokeWidth"
markerWidth={CONSTANT.MARKER.MARKERWIDTH}
markerHeight={CONSTANT.MARKER.MARKERHIEGHT}
viewBox={CONSTANT.MARKER.VIEWBOX}
refX={CONSTANT.MARKER.REFX}
refY={CONSTANT.MARKER.REFY}
orient={CONSTANT.MARKER.ORIENT}>
<path d={CONSTANT.MARKER.PATH} fill={CONSTANT.MARKER.FILL} />
</marker>
</defs>
<circle
cx={CONSTANT.CIRCLE.CX}
cy={CONSTANT.CIRCLE.CY}
r={CONSTANT.CIRCLE.R}
fill='#fff'
stroke={node.active ? CONSTANT.THEME.ACTIVE : CONSTANT.THEME.NONEACTIVE}
strokeWidth={node.active ? 2 : 1}
style={{cursor: 'pointer'}}
onClick={(event) => this.nodeActive(event, node)} />
<image
href={node.depth === 0 ? user : node.depth === 1 ? earth : minusCircle}
style={{cursor: 'pointer'}}
onClick={(event) => this.nodeActive(event, node)}/>
<rect x='10' y='32' width='40' height='20'
fill={node.data.type === CONSTANT.PROD ? CONSTANT.THEME.RECTBLUE : CONSTANT.THEME.RECTRED} />
<text
x='17' y='46'
fill={node.data.type === CONSTANT.PROD ? CONSTANT.THEME.TEXTBLACK : CONSTANT.THEME.TEXTWHITE}
style={{fontSize: CONSTANT.THEME.FONTSIZE}}>
{node.type}
</text>
<text x='5' y='47' fill='#000' textAnchor='end' style={{fontSize: CONSTANT.THEME.FONTSIZE}}>
{node.name}
</text>
</g>)
})}
</g>