|
|
@@ -136,11 +136,11 @@
|
|
|
cx: 0,
|
|
|
cy: 0,
|
|
|
r: radius,
|
|
|
- fill: isRoot ? '#3aa0ff' : '#53a8ff',
|
|
|
- stroke: isRoot ? '#8ec9ff' : '#a7d1ff',
|
|
|
+ fill: isRoot ? '#2a50ec' : '#5b74e8',
|
|
|
+ stroke: isRoot ? '#b9c9ff' : '#c3d0fa',
|
|
|
lineWidth: 1.5,
|
|
|
- shadowColor: 'rgba(51, 144, 255, 0.22)',
|
|
|
- shadowBlur: 18,
|
|
|
+ shadowColor: isRoot ? 'rgba(42, 80, 236, 0.28)' : 'rgba(42, 80, 236, 0.16)',
|
|
|
+ shadowBlur: isRoot ? 20 : 16,
|
|
|
shadowOffsetX: 0,
|
|
|
shadowOffsetY: 8,
|
|
|
cursor: 'pointer' as const,
|
|
|
@@ -172,9 +172,9 @@
|
|
|
? {
|
|
|
cx: toggleCenterX,
|
|
|
cy: toggleCenterY,
|
|
|
- r: 14,
|
|
|
+ r: 13,
|
|
|
fill: '#ffffff',
|
|
|
- stroke: '#dbeafe',
|
|
|
+ stroke: '#d7e1f8',
|
|
|
lineWidth: 1,
|
|
|
shadowColor: 'rgba(15, 23, 42, 0.12)',
|
|
|
shadowBlur: 8,
|
|
|
@@ -194,7 +194,7 @@
|
|
|
x: toggleCenterX,
|
|
|
y: toggleCenterY,
|
|
|
text: isCollapsed ? '+' : '-',
|
|
|
- fill: '#2563eb',
|
|
|
+ fill: '#2a50ec',
|
|
|
fontSize: 16,
|
|
|
fontWeight: 700,
|
|
|
textAlign: 'center',
|
|
|
@@ -213,7 +213,7 @@
|
|
|
x: toggleCenterX,
|
|
|
y: toggleCenterY + 22,
|
|
|
text: toggleLabel,
|
|
|
- fill: '#2563eb',
|
|
|
+ fill: '#5b6577',
|
|
|
fontSize: 10,
|
|
|
textAlign: 'center',
|
|
|
textBaseline: 'middle',
|
|
|
@@ -231,8 +231,8 @@
|
|
|
y: 0,
|
|
|
text: titleText,
|
|
|
fill: '#ffffff',
|
|
|
- fontSize: 15,
|
|
|
- fontWeight: 500,
|
|
|
+ fontSize: 14,
|
|
|
+ fontWeight: 600,
|
|
|
textAlign: 'center',
|
|
|
textBaseline: 'middle',
|
|
|
wordWrap: true,
|
|
|
@@ -519,15 +519,15 @@
|
|
|
if (!raw) {
|
|
|
return `
|
|
|
<div style="min-width:156px;padding:8px 10px;box-sizing:border-box;">
|
|
|
- <div style="color:#334155;font-size:12px;font-weight:600;line-height:18px;">交易关系</div>
|
|
|
+ <div style="color:#1f2937;font-size:12px;font-weight:600;line-height:18px;">交易关系</div>
|
|
|
</div>
|
|
|
`;
|
|
|
}
|
|
|
|
|
|
return `
|
|
|
<div style="min-width:156px;padding:8px 10px;box-sizing:border-box;">
|
|
|
- <div style="color:#334155;font-size:12px;font-weight:600;line-height:18px;">${escapeHtml(buildEdgeTitle(raw))}</div>
|
|
|
- <div style="margin-top:4px;color:#64748b;font-size:11px;line-height:16px;">${escapeHtml(buildEdgeValue(raw))}</div>
|
|
|
+ <div style="color:#1f2937;font-size:12px;font-weight:600;line-height:18px;">${escapeHtml(buildEdgeTitle(raw))}</div>
|
|
|
+ <div style="margin-top:4px;color:#5b6577;font-size:11px;line-height:16px;">${escapeHtml(buildEdgeValue(raw))}</div>
|
|
|
</div>
|
|
|
`;
|
|
|
};
|
|
|
@@ -883,6 +883,20 @@
|
|
|
});
|
|
|
};
|
|
|
|
|
|
+ const fitGraphView = async () => {
|
|
|
+ const currentGraph = graph.value;
|
|
|
+ if (!isGraphUsable(currentGraph)) return;
|
|
|
+ try {
|
|
|
+ await currentGraph.fitView({ when: 'always', direction: 'both' }, false);
|
|
|
+ if (currentGraph.getZoom() > 1) {
|
|
|
+ await currentGraph.zoomTo(1, false);
|
|
|
+ await currentGraph.fitCenter(false);
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.warn('[MoneyFlowGraph] fit view failed:', error);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
const handleResize = () => {
|
|
|
const currentGraph = graph.value;
|
|
|
if (!isGraphUsable(currentGraph)) return;
|
|
|
@@ -893,6 +907,7 @@
|
|
|
}
|
|
|
lastResizeSize.value = [width, height];
|
|
|
currentGraph.resize(width, height);
|
|
|
+ void fitGraphView();
|
|
|
scheduleHitAreaSync();
|
|
|
};
|
|
|
|
|
|
@@ -914,6 +929,7 @@
|
|
|
width,
|
|
|
height,
|
|
|
autoResize: false,
|
|
|
+ padding: 28,
|
|
|
data: graphData,
|
|
|
layout: {
|
|
|
type: 'compact-box',
|
|
|
@@ -934,32 +950,38 @@
|
|
|
edge: {
|
|
|
type: 'cubic-horizontal',
|
|
|
style: {
|
|
|
- stroke: '#9db7d6',
|
|
|
- lineWidth: 2.5,
|
|
|
+ stroke: '#b9c6e8',
|
|
|
+ lineWidth: 2,
|
|
|
cursor: (datum: EdgeData) => (parseIds(getEdgeRaw(datum)?.ids).length ? 'pointer' : 'default'),
|
|
|
label: (datum: EdgeData) => Boolean(buildEdgeLabelText(getEdgeRaw(datum))),
|
|
|
labelText: (datum: EdgeData) => buildEdgeLabelText(getEdgeRaw(datum)),
|
|
|
labelPlacement: 'center',
|
|
|
- labelAutoRotate: true,
|
|
|
+ labelAutoRotate: false,
|
|
|
labelWordWrap: true,
|
|
|
labelMaxWidth: 220,
|
|
|
- labelFill: '#5e5e5e',
|
|
|
- labelFontSize: 12,
|
|
|
- labelBackground: false,
|
|
|
+ labelFill: '#5b6577',
|
|
|
+ labelFontSize: 11,
|
|
|
+ labelBackground: true,
|
|
|
+ labelBackgroundFill: '#ffffff',
|
|
|
+ labelBackgroundOpacity: 0.92,
|
|
|
+ labelBackgroundStroke: '#e7ebf3',
|
|
|
+ labelBackgroundLineWidth: 1,
|
|
|
+ labelBackgroundRadius: 4,
|
|
|
+ labelPadding: [2, 6, 2, 6],
|
|
|
startArrow: (datum: EdgeData) => getEdgeRaw(datum)?.state === 'left',
|
|
|
- startArrowFill: '#9db7d6',
|
|
|
+ startArrowFill: '#b9c6e8',
|
|
|
startArrowSize: EDGE_ARROW_SIZE,
|
|
|
startArrowOffset: EDGE_ARROW_OFFSET,
|
|
|
endArrow: (datum: EdgeData) => getEdgeRaw(datum)?.state !== 'left',
|
|
|
- endArrowFill: '#9db7d6',
|
|
|
+ endArrowFill: '#b9c6e8',
|
|
|
endArrowSize: EDGE_ARROW_SIZE,
|
|
|
endArrowOffset: EDGE_ARROW_OFFSET,
|
|
|
},
|
|
|
state: {
|
|
|
active: {
|
|
|
- stroke: '#3b82f6',
|
|
|
+ stroke: '#2a50ec',
|
|
|
lineWidth: 3,
|
|
|
- labelFill: '#334155',
|
|
|
+ labelFill: '#1e3ed0',
|
|
|
},
|
|
|
},
|
|
|
},
|
|
|
@@ -1023,6 +1045,7 @@
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ await fitGraphView();
|
|
|
scheduleHitAreaSync();
|
|
|
};
|
|
|
|