finish work
This commit is contained in:
parent
316c73613c
commit
60196889bb
@ -65,6 +65,8 @@ const drawDiagram = async () => {
|
|||||||
height: 48,
|
height: 48,
|
||||||
labels: [{ text: tool.name || 'Tool' }]
|
labels: [{ text: tool.name || 'Tool' }]
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// 默认按照链表进行串联
|
||||||
state.edges = tools.slice(1).map((_, i) => ({
|
state.edges = tools.slice(1).map((_, i) => ({
|
||||||
id: `e${i}`,
|
id: `e${i}`,
|
||||||
sources: [String(i)],
|
sources: [String(i)],
|
||||||
@ -80,14 +82,19 @@ function renderSvg() {
|
|||||||
const width = Math.max(...state.nodes.map(n => (n.x || 0) + (n.width || 160)), 400) + 60;
|
const width = Math.max(...state.nodes.map(n => (n.x || 0) + (n.width || 160)), 400) + 60;
|
||||||
const height = Math.max(...state.nodes.map(n => (n.y || 0) + (n.height || 48)), 300) + 60;
|
const height = Math.max(...state.nodes.map(n => (n.y || 0) + (n.height || 48)), 300) + 60;
|
||||||
|
|
||||||
d3.select(svgContainer.value).selectAll('*').remove();
|
// 不再全量清空,只清空 svg 元素
|
||||||
|
let svg = d3.select(svgContainer.value).select('svg');
|
||||||
const svg = d3
|
if (svg.empty()) {
|
||||||
.select(svgContainer.value)
|
svg = d3
|
||||||
.append('svg')
|
.select(svgContainer.value)
|
||||||
.attr('width', width)
|
.append('svg')
|
||||||
.attr('height', height)
|
.attr('width', width)
|
||||||
.style('user-select', 'none');
|
.attr('height', height)
|
||||||
|
.style('user-select', 'none');
|
||||||
|
} else {
|
||||||
|
svg.attr('width', width).attr('height', height);
|
||||||
|
svg.selectAll('defs').remove();
|
||||||
|
}
|
||||||
|
|
||||||
// Arrow marker
|
// Arrow marker
|
||||||
svg
|
svg
|
||||||
@ -104,41 +111,65 @@ function renderSvg() {
|
|||||||
.attr('d', 'M 0 0 L 10 5 L 0 10 z')
|
.attr('d', 'M 0 0 L 10 5 L 0 10 z')
|
||||||
.attr('fill', 'var(--main-color)');
|
.attr('fill', 'var(--main-color)');
|
||||||
|
|
||||||
// Draw edges
|
// Draw edges with enter animation
|
||||||
|
const allSections: { id: string, section: any }[] = [];
|
||||||
(state.edges || []).forEach(edge => {
|
(state.edges || []).forEach(edge => {
|
||||||
const sections = edge.sections || [];
|
const sections = edge.sections || [];
|
||||||
sections.forEach(section => {
|
sections.forEach((section, idx) => {
|
||||||
svg.append('line')
|
allSections.push({
|
||||||
.attr('x1', section.startPoint.x + 30)
|
id: (edge.id || '') + '-' + (section.id || idx),
|
||||||
.attr('y1', section.startPoint.y + 30)
|
section
|
||||||
.attr('x2', section.endPoint.x + 30)
|
});
|
||||||
.attr('y2', section.endPoint.y + 30)
|
|
||||||
.attr('stroke', 'var(--main-color)')
|
|
||||||
.attr('stroke-width', 2.5)
|
|
||||||
.attr('marker-end', 'url(#arrow)');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Draw nodes
|
const edgeSelection = svg.selectAll<SVGLineElement, any>('.edge')
|
||||||
const nodeGroup = svg.selectAll('.node')
|
.data(allSections, d => d.id);
|
||||||
.data(state.nodes, d => d.id)
|
|
||||||
.enter()
|
edgeSelection.exit().remove();
|
||||||
|
|
||||||
|
const edgeEnter = edgeSelection.enter()
|
||||||
|
.append('line')
|
||||||
|
.attr('class', 'edge')
|
||||||
|
.attr('x1', d => d.section.startPoint.x + 30)
|
||||||
|
.attr('y1', d => d.section.startPoint.y + 30)
|
||||||
|
.attr('x2', d => d.section.endPoint.x + 30)
|
||||||
|
.attr('y2', d => d.section.endPoint.y + 30)
|
||||||
|
.attr('stroke', 'var(--main-color)')
|
||||||
|
.attr('stroke-width', 2.5)
|
||||||
|
.attr('marker-end', 'url(#arrow)')
|
||||||
|
.attr('opacity', 0);
|
||||||
|
|
||||||
|
edgeEnter
|
||||||
|
.transition()
|
||||||
|
.duration(600)
|
||||||
|
.attr('opacity', 1);
|
||||||
|
|
||||||
|
edgeSelection.merge(edgeEnter)
|
||||||
|
.transition()
|
||||||
|
.duration(600)
|
||||||
|
.ease(d3.easeCubicInOut)
|
||||||
|
.attr('x1', d => d.section.startPoint.x + 30)
|
||||||
|
.attr('y1', d => d.section.startPoint.y + 30)
|
||||||
|
.attr('x2', d => d.section.endPoint.x + 30)
|
||||||
|
.attr('y2', d => d.section.endPoint.y + 30);
|
||||||
|
|
||||||
|
// --- 节点动画部分 ---
|
||||||
|
const nodeGroup = svg.selectAll<SVGGElement, any>('.node')
|
||||||
|
.data(state.nodes, d => d.id);
|
||||||
|
|
||||||
|
nodeGroup.exit().remove();
|
||||||
|
|
||||||
|
const nodeGroupEnter = nodeGroup.enter()
|
||||||
.append('g')
|
.append('g')
|
||||||
.attr('class', 'node')
|
.attr('class', 'node')
|
||||||
.attr('transform', d => `translate(${(d.x || 0) + 30}, ${(d.y || 0) + 30})`)
|
.attr('transform', d => `translate(${(d.x || 0) + 30}, ${(d.y || 0) + 30})`)
|
||||||
.style('cursor', 'pointer')
|
.style('cursor', 'pointer')
|
||||||
.on('mousedown', function (event, d) {
|
.attr('opacity', 0)
|
||||||
event.stopPropagation();
|
.on('mousedown', null)
|
||||||
state.draggingNodeId = d.id;
|
|
||||||
state.offset = {
|
|
||||||
x: event.offsetX - ((d.x || 0) + 30),
|
|
||||||
y: event.offsetY - ((d.y || 0) + 30)
|
|
||||||
};
|
|
||||||
})
|
|
||||||
.on('mouseup', function (event, d) {
|
.on('mouseup', function (event, d) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
if (state.selectedNodeId && state.selectedNodeId !== d.id) {
|
if (state.selectedNodeId && state.selectedNodeId !== d.id) {
|
||||||
// Add new edge
|
|
||||||
state.edges.push({
|
state.edges.push({
|
||||||
id: `e${state.selectedNodeId}_${d.id}_${Date.now()}`,
|
id: `e${state.selectedNodeId}_${d.id}_${Date.now()}`,
|
||||||
sources: [state.selectedNodeId],
|
sources: [state.selectedNodeId],
|
||||||
@ -153,7 +184,7 @@ function renderSvg() {
|
|||||||
state.draggingNodeId = null;
|
state.draggingNodeId = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
nodeGroup.append('rect')
|
nodeGroupEnter.append('rect')
|
||||||
.attr('width', d => d.width)
|
.attr('width', d => d.width)
|
||||||
.attr('height', d => d.height)
|
.attr('height', d => d.height)
|
||||||
.attr('rx', 16)
|
.attr('rx', 16)
|
||||||
@ -162,7 +193,7 @@ function renderSvg() {
|
|||||||
.attr('stroke', 'var(--main-color)')
|
.attr('stroke', 'var(--main-color)')
|
||||||
.attr('stroke-width', 2);
|
.attr('stroke-width', 2);
|
||||||
|
|
||||||
nodeGroup.append('text')
|
nodeGroupEnter.append('text')
|
||||||
.attr('x', d => d.width / 2)
|
.attr('x', d => d.width / 2)
|
||||||
.attr('y', d => d.height / 2 + 6)
|
.attr('y', d => d.height / 2 + 6)
|
||||||
.attr('text-anchor', 'middle')
|
.attr('text-anchor', 'middle')
|
||||||
@ -171,24 +202,18 @@ function renderSvg() {
|
|||||||
.attr('font-weight', 600)
|
.attr('font-weight', 600)
|
||||||
.text(d => d.labels?.[0]?.text || 'Tool');
|
.text(d => d.labels?.[0]?.text || 'Tool');
|
||||||
|
|
||||||
// Drag behavior
|
// 节点 enter 动画
|
||||||
d3.select(window)
|
nodeGroupEnter
|
||||||
.on('mousemove.diagram', event => {
|
.transition()
|
||||||
if (state.draggingNodeId) {
|
.duration(600)
|
||||||
const node = state.nodes.find(n => n.id === state.draggingNodeId);
|
.attr('opacity', 1);
|
||||||
if (node) {
|
|
||||||
node.x = event.offsetX - state.offset.x - 30;
|
// 节点 update 动画
|
||||||
node.y = event.offsetY - state.offset.y - 30;
|
nodeGroup
|
||||||
renderSvg();
|
.transition()
|
||||||
}
|
.duration(600)
|
||||||
}
|
.ease(d3.easeCubicInOut)
|
||||||
})
|
.attr('transform', d => `translate(${(d.x || 0) + 30}, ${(d.y || 0) + 30})`);
|
||||||
.on('mouseup.diagram', () => {
|
|
||||||
if (state.draggingNodeId) {
|
|
||||||
state.draggingNodeId = null;
|
|
||||||
recomputeLayout().then(renderSvg);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
39
yarn.lock
39
yarn.lock
@ -492,10 +492,10 @@
|
|||||||
resolved "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.3.1.tgz"
|
resolved "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.3.1.tgz"
|
||||||
integrity sha512-XxVUZv48RZAd87ucGS48jPf6pKu0yV5UCg9f4FFwtrYxXOwWuVJo6wOvSLKEoMQKjv8GsX/mhP6UsC1lRwbUWg==
|
integrity sha512-XxVUZv48RZAd87ucGS48jPf6pKu0yV5UCg9f4FFwtrYxXOwWuVJo6wOvSLKEoMQKjv8GsX/mhP6UsC1lRwbUWg==
|
||||||
|
|
||||||
"@esbuild/darwin-arm64@0.25.5":
|
"@esbuild/win32-x64@0.25.5":
|
||||||
version "0.25.5"
|
version "0.25.5"
|
||||||
resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz"
|
resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz"
|
||||||
integrity sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==
|
integrity sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==
|
||||||
|
|
||||||
"@faker-js/faker@^9.8.0":
|
"@faker-js/faker@^9.8.0":
|
||||||
version "9.8.0"
|
version "9.8.0"
|
||||||
@ -736,7 +736,7 @@
|
|||||||
"@nodelib/fs.scandir" "2.1.5"
|
"@nodelib/fs.scandir" "2.1.5"
|
||||||
fastq "^1.6.0"
|
fastq "^1.6.0"
|
||||||
|
|
||||||
"@openmcp/renderer@file:/Users/bytedance/projects/openmcp-client/renderer":
|
"@openmcp/renderer@file:C:\\Users\\K\\project\\openmcp-client\\renderer":
|
||||||
version "0.1.0"
|
version "0.1.0"
|
||||||
resolved "file:renderer"
|
resolved "file:renderer"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -764,7 +764,7 @@
|
|||||||
vue-router "^4.5.0"
|
vue-router "^4.5.0"
|
||||||
xml2js "^0.6.2"
|
xml2js "^0.6.2"
|
||||||
|
|
||||||
"@openmcp/service@file:/Users/bytedance/projects/openmcp-client/service":
|
"@openmcp/service@file:C:\\Users\\K\\project\\openmcp-client\\service":
|
||||||
version "0.0.1"
|
version "0.0.1"
|
||||||
resolved "file:service"
|
resolved "file:service"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -869,10 +869,10 @@
|
|||||||
estree-walker "^2.0.2"
|
estree-walker "^2.0.2"
|
||||||
picomatch "^4.0.2"
|
picomatch "^4.0.2"
|
||||||
|
|
||||||
"@rollup/rollup-darwin-arm64@4.44.0":
|
"@rollup/rollup-win32-x64-msvc@4.44.0":
|
||||||
version "4.44.0"
|
version "4.44.0"
|
||||||
resolved "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.44.0.tgz"
|
resolved "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.44.0.tgz"
|
||||||
integrity sha512-VGF3wy0Eq1gcEIkSCr8Ke03CWT+Pm2yveKLaDvq51pPpZza3JX/ClxXOCmTYYq3us5MvEuNRTaeyFThCKRQhOA==
|
integrity sha512-Q2Mgwt+D8hd5FIPUuPDsvPR7Bguza6yTkJxspDGkZj7tBRn2y4KSWYuIXpftFSjBra76TbKerCV7rgFPQrn+wQ==
|
||||||
|
|
||||||
"@rushstack/node-core-library@5.13.1":
|
"@rushstack/node-core-library@5.13.1":
|
||||||
version "5.13.1"
|
version "5.13.1"
|
||||||
@ -1665,10 +1665,10 @@
|
|||||||
ora "^8.1.0"
|
ora "^8.1.0"
|
||||||
semver "^7.6.2"
|
semver "^7.6.2"
|
||||||
|
|
||||||
"@vscode/vsce-sign-darwin-arm64@2.0.5":
|
"@vscode/vsce-sign-win32-x64@2.0.5":
|
||||||
version "2.0.5"
|
version "2.0.5"
|
||||||
resolved "https://registry.npmjs.org/@vscode/vsce-sign-darwin-arm64/-/vsce-sign-darwin-arm64-2.0.5.tgz"
|
resolved "https://registry.npmjs.org/@vscode/vsce-sign-win32-x64/-/vsce-sign-win32-x64-2.0.5.tgz"
|
||||||
integrity sha512-z2Q62bk0ptADFz8a0vtPvnm6vxpyP3hIEYMU+i1AWz263Pj8Mc38cm/4sjzxu+LIsAfhe9HzvYNS49lV+KsatQ==
|
integrity sha512-1ixKFGM2FwM+6kQS2ojfY3aAelICxjiCzeg4nTHpkeU1Tfs4RC+lVLrgq5NwcBC7ZLr6UfY3Ct3D6suPeOf7BQ==
|
||||||
|
|
||||||
"@vscode/vsce-sign@^2.0.0":
|
"@vscode/vsce-sign@^2.0.0":
|
||||||
version "2.0.6"
|
version "2.0.6"
|
||||||
@ -3456,10 +3456,10 @@ es-set-tostringtag@^2.1.0:
|
|||||||
has-tostringtag "^1.0.2"
|
has-tostringtag "^1.0.2"
|
||||||
hasown "^2.0.2"
|
hasown "^2.0.2"
|
||||||
|
|
||||||
esbuild-darwin-arm64@0.14.54:
|
esbuild-windows-64@0.14.54:
|
||||||
version "0.14.54"
|
version "0.14.54"
|
||||||
resolved "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.54.tgz"
|
resolved "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.54.tgz"
|
||||||
integrity sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==
|
integrity sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==
|
||||||
|
|
||||||
esbuild@^0.14.14:
|
esbuild@^0.14.14:
|
||||||
version "0.14.54"
|
version "0.14.54"
|
||||||
@ -3916,11 +3916,6 @@ fs.realpath@^1.0.0:
|
|||||||
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
|
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
|
||||||
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
|
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
|
||||||
|
|
||||||
fsevents@~2.3.2, fsevents@~2.3.3:
|
|
||||||
version "2.3.3"
|
|
||||||
resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz"
|
|
||||||
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
|
|
||||||
|
|
||||||
function-bind@^1.1.2:
|
function-bind@^1.1.2:
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz"
|
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz"
|
||||||
@ -6985,10 +6980,10 @@ tunnel@0.0.6:
|
|||||||
resolved "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz"
|
resolved "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz"
|
||||||
integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==
|
integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==
|
||||||
|
|
||||||
turbo-darwin-arm64@2.5.4:
|
turbo-windows-64@2.5.4:
|
||||||
version "2.5.4"
|
version "2.5.4"
|
||||||
resolved "https://registry.npmjs.org/turbo-darwin-arm64/-/turbo-darwin-arm64-2.5.4.tgz"
|
resolved "https://registry.npmjs.org/turbo-windows-64/-/turbo-windows-64-2.5.4.tgz"
|
||||||
integrity sha512-2+Nx6LAyuXw2MdXb7pxqle3MYignLvS7OwtsP9SgtSBaMlnNlxl9BovzqdYAgkUW3AsYiQMJ/wBRb7d+xemM5A==
|
integrity sha512-EQUO4SmaCDhO6zYohxIjJpOKRN3wlfU7jMAj3CgcyTPvQR/UFLEKAYHqJOnJtymbQmiiM/ihX6c6W6Uq0yC7mA==
|
||||||
|
|
||||||
turbo@^2.5.3:
|
turbo@^2.5.3:
|
||||||
version "2.5.4"
|
version "2.5.4"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user