From c41fc672545b9936d3d3e2e5472103c361464cd8 Mon Sep 17 00:00:00 2001 From: Nikolay Rozhkov Date: Sun, 18 Jun 2023 03:23:11 +0300 Subject: [PATCH] Added nodes and paths --- .../src/diagrams/sankey/sankeyRenderer.ts | 132 ++++++++++++++---- packages/mermaid/src/setupGraphViewbox.js | 1 + 2 files changed, 108 insertions(+), 25 deletions(-) diff --git a/packages/mermaid/src/diagrams/sankey/sankeyRenderer.ts b/packages/mermaid/src/diagrams/sankey/sankeyRenderer.ts index 8731dd5ce..6a184ef86 100644 --- a/packages/mermaid/src/diagrams/sankey/sankeyRenderer.ts +++ b/packages/mermaid/src/diagrams/sankey/sankeyRenderer.ts @@ -9,7 +9,7 @@ import { // rgb as d3rgb, map as d3map, } from 'd3'; -import { sankey as d3sankey, sankeyLinkHorizontal } from 'd3-sankey'; +import { sankey as d3Sankey, sankeyLinkHorizontal as d3SankeyLinkHorizontal } from 'd3-sankey'; import { configureSvgSize } from '../../setupGraphViewbox.js'; import sankeyDB from './sankeyDB.js'; @@ -35,7 +35,7 @@ export const draw = function (text: string, id: string, _version: string, diagOb log.debug('Parsed sankey diagram'); // Figure out what is happening there - // The main thing is svg object that is a wrapper from d3 for svg operations + // The main thing is svg object that is a d3 wrapper for svg operations // const { securityLevel, sequence: conf } = configApi.getConfig(); let sandboxElement; @@ -49,13 +49,15 @@ export const draw = function (text: string, id: string, _version: string, diagOb const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document; const svg = securityLevel === 'sandbox' ? root.select(`[id="${id}"]`) : d3select(`[id="${id}"]`); - // Establish svg dimensions + // Establish svg dimensions and get width and height // const elem = doc.getElementById(id); const width = elem.parentElement.offsetWidth; + const height = 100; // TODO calculate height? - const height = 600; + // FIX: using max width prevents height from being set configureSvgSize(svg, height, width, true); + svg.attr('height', height); // that's why we need this line // Prepare data for construction // This must be a mutable object with 2 properties: @@ -84,7 +86,7 @@ export const draw = function (text: string, id: string, _version: string, diagOb // Construct and configure a Sankey generator // That will be a function that calculates nodes and links dimensions // - const sankey = d3sankey() + const sankey = d3Sankey() .nodeId((d) => d.id) // we use 'id' property to identify node .nodeWidth(36) .nodePadding(290) @@ -100,10 +102,10 @@ export const draw = function (text: string, id: string, _version: string, diagOb // Compute the Sankey layout // Namely calculate nodes and links positions // Our `graph` object will be mutated by this + // and enriched with some properties // sankey(graph); - // debugger; // const node = svg.append("g") // .selectAll("rect") @@ -118,30 +120,110 @@ export const draw = function (text: string, id: string, _version: string, diagOb // // .attr("stroke-opacity", nodeStrokeOpacity) // // .attr("stroke-linejoin", nodeStrokeLinejoin) + // Get color scheme for the graph const color = d3scaleOrdinal(d3schemeTableau10); - // Creates the rects that represent the nodes. - const rect = svg - .append('g') - .attr('stroke', '#000') - .selectAll('rect') - .data(graph.nodes) - .join('rect') - .attr('x', (d) => d.x0) - .attr('y', (d) => d.y0) - .attr('height', (d) => d.y1 - d.y0) - .attr('width', (d) => d.x1 - d.x0) - .attr('fill', (d) => color(d.node)); - // // add in the links - // var link = svg.append("g") + // Creates the groups for nodes + svg + .append('g') + .attr('class', 'nodes') + .attr('stroke', '#000') + .selectAll('.node') + .data(graph.nodes) + .join('g') + .attr('class', 'node') + .attr("transform", function (d) { return "translate(" + d.x0 + "," + d.y0 + ")"; }) + .attr('x', (d) => d.x0) + .attr('y', (d) => d.y0) + .append('rect') + .attr('height', (d) => {console.log(d); return (d.y1 - d.y0);}) + .attr('width', (d) => d.x1 - d.x0) + .attr('fill', (d) => color(d.id)); + + // Create text for nodes + svg + .append("g") + .attr('class', 'node-labels') + .attr("font-family", "sans-serif") + .attr("font-size", 12) + .selectAll('text') + .data(graph.nodes) + .join('text') + .attr("x", d => d.x0 < width / 2 ? d.x1 + 6 : d.x0 - 6) + .attr("y", d => (d.y1 + d.y0) / 2) + .attr("dy", "0.35em") + .attr("text-anchor", d => d.x0 < width / 2 ? "start" : "end") + .text(d => d.id) + + // Add links + // svg + // .append("g") // .selectAll(".link") // .data(graph.links) // .enter() - // .append("path") - // .attr("class", "link") - // .attr("d", sankeyLinkHorizontal()) - // .style("stroke-width", function (d) { return Math.max(1, d.dy); }) - // .sort(function (a, b) { return b.dy - a.dy; }); + // .append("path") + // .attr("class", "link") + // .attr("d", sankeyLinkHorizontal()) + // .style("stroke-width", function (d) { return Math.max(1, d.dy); }) + // .sort(function (a, b) { return b.dy - a.dy; }); + + // Creates the paths that represent the links. + const link_g = svg.append("g") + .attr('class', 'links') + .attr("fill", "none") + .attr("stroke-opacity", 0.5) + .selectAll(".link") + .data(graph.links) + .join("g") + .attr('class', 'link') + .style("mix-blend-mode", "multiply"); + + link_g.append("path") + .attr("d", d3SankeyLinkHorizontal()) + .attr("stroke", d => color(d.source.id)) + .attr("stroke-width", d => Math.max(1, d.width)); + + // linkColor === "source-target" ? (d) => d.uid + // : linkColor === "source" ? (d) => color(d.source.category) + // : linkColor === "target" ? (d) => color(d.target.category) + // : linkColor + + // svg.append("g") + // .attr("font-family", "sans-serif") + // .attr("font-size", 10) + // .selectAll("text") + // .data(nodes) + // .join("text") + // .attr("x", d => d.x0 < width / 2 ? d.x1 + 6 : d.x0 - 6) + // .attr("y", d => (d.y1 + d.y0) / 2) + // .attr("dy", "0.35em") + // .attr("text-anchor", d => d.x0 < width / 2 ? "start" : "end") + // .text(d => d.name); + + // Create links + // .attr("transform", null) + // .append("g") + // .attr("font-family", "sans-serif") + // .attr("font-size", 10) + // .selectAll("text") + // .data(nodes) + // .join("text") + // .attr("x", d => d.x0 < width / 2 ? d.x1 + 6 : d.x0 - 6) + // .attr("y", d => (d.y1 + d.y0) / 2) + // .attr("dy", "0.35em") + // .attr("text-anchor", d => d.x0 < width / 2 ? "start" : "end") + // .text(d => d.name); + // .attr("y", function (d) { return d.dy / 2; }) + // .attr("dy", ".35em") + // .attr("text-anchor", "end") + // .attr("transform", null) + // .text(function (d) { return d.name; }) + // .filter(function (d) { return d.x < width / 2; }) + // .attr("x", 6 + generator.nodeWidth()) + // .attr("text-anchor", "start"); + + // .selectAll('rect') + // // add in the nodes // var node = svg.append("g") diff --git a/packages/mermaid/src/setupGraphViewbox.js b/packages/mermaid/src/setupGraphViewbox.js index 0396d654f..9294f8024 100644 --- a/packages/mermaid/src/setupGraphViewbox.js +++ b/packages/mermaid/src/setupGraphViewbox.js @@ -25,6 +25,7 @@ export const calculateSvgSizeAttrs = function (height, width, useMaxWidth) { if (useMaxWidth) { attrs.set('width', '100%'); attrs.set('style', `max-width: ${width}px;`); + // TODO: when using max width it does not set height? Is it intended? } else { attrs.set('height', height); attrs.set('width', width);