finish work

This commit is contained in:
锦恢 2025-07-01 00:17:14 +08:00
parent 316c73613c
commit 60196889bb
2 changed files with 93 additions and 73 deletions

View File

@ -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()) {
svg = d3
.select(svgContainer.value) .select(svgContainer.value)
.append('svg') .append('svg')
.attr('width', width) .attr('width', width)
.attr('height', height) .attr('height', height)
.style('user-select', 'none'); .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(() => {

View File

@ -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"