mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-27 11:19:38 +02:00
Added gradient for sankey and cleaned code
This commit is contained in:
@@ -73,7 +73,6 @@ const findOrCreateNode = function (ID: string): SankeyNode {
|
||||
return node;
|
||||
};
|
||||
|
||||
// TODO: this will be better using getters in typescript
|
||||
const getNodes = () => nodes;
|
||||
const getLinks = () => links;
|
||||
|
||||
|
@@ -2,7 +2,6 @@ import { DiagramDefinition } from '../../diagram-api/types.js';
|
||||
// @ts-ignore: jison doesn't export types
|
||||
import parser from './parser/sankey.jison';
|
||||
import db from './sankeyDB.js';
|
||||
import styles from './styles.js';
|
||||
import renderer from './sankeyRenderer.js';
|
||||
import { prepareTextForParsing } from './sankeyUtils.js';
|
||||
|
||||
@@ -13,5 +12,5 @@ export const diagram: DiagramDefinition = {
|
||||
parser,
|
||||
db,
|
||||
renderer,
|
||||
styles,
|
||||
styles: () => {},
|
||||
};
|
||||
|
@@ -4,7 +4,9 @@ import * as configApi from '../../config.js';
|
||||
|
||||
import {
|
||||
select as d3select,
|
||||
// @ts-ignore TODO: make proper import
|
||||
scaleOrdinal as d3scaleOrdinal,
|
||||
// @ts-ignore TODO: make proper import
|
||||
schemeTableau10 as d3schemeTableau10,
|
||||
} from 'd3';
|
||||
|
||||
@@ -17,6 +19,7 @@ import {
|
||||
sankeyJustify as d3SankeyJustify,
|
||||
} from 'd3-sankey';
|
||||
import { configureSvgSize } from '../../setupGraphViewbox.js';
|
||||
import { Uid } from './sankeyUtils.js';
|
||||
|
||||
/**
|
||||
* Draws a sequenceDiagram in the tag with id: id based on the graph definition in text.
|
||||
@@ -31,14 +34,15 @@ export const draw = function (text: string, id: string, _version: string, diagOb
|
||||
// The main thing is svg object that is a d3 wrapper for svg operations
|
||||
//
|
||||
const { securityLevel, sequence: conf } = configApi.getConfig();
|
||||
let sandboxElement;
|
||||
let sandboxElement: any;
|
||||
if (securityLevel === 'sandbox') {
|
||||
sandboxElement = d3select('#i' + id);
|
||||
}
|
||||
const root =
|
||||
securityLevel === 'sandbox'
|
||||
? d3select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
: d3select('body');
|
||||
let root = d3select('body');
|
||||
|
||||
if (securityLevel === 'sandbox' && sandboxElement) {
|
||||
d3select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
}
|
||||
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||
const svg = securityLevel === 'sandbox' ? root.select(`[id="${id}"]`) : d3select(`[id="${id}"]`);
|
||||
|
||||
@@ -46,11 +50,11 @@ export const draw = function (text: string, id: string, _version: string, diagOb
|
||||
//
|
||||
const elem = doc.getElementById(id);
|
||||
const width = elem.parentElement.offsetWidth;
|
||||
const height = 600; // 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
|
||||
configureSvgSize(svg, height, width, false);
|
||||
// svg.attr('height', height); // that's why we need this line
|
||||
|
||||
// Prepare data for construction based on diagObj.db
|
||||
// This must be a mutable object with 2 properties:
|
||||
@@ -68,7 +72,6 @@ export const draw = function (text: string, id: string, _version: string, diagOb
|
||||
// ]
|
||||
// };
|
||||
//
|
||||
|
||||
const graph = diagObj.db.getGraph();
|
||||
const nodeAligns = {
|
||||
left: d3SankeyLeft,
|
||||
@@ -83,13 +86,13 @@ export const draw = function (text: string, id: string, _version: string, diagOb
|
||||
//
|
||||
const nodeWidth = 10;
|
||||
const sankey = d3Sankey()
|
||||
.nodeId((d) => d.id) // we use 'id' property to identify node
|
||||
.nodeId((d: any) => d.id) // we use 'id' property to identify node
|
||||
.nodeWidth(nodeWidth)
|
||||
.nodePadding(10)
|
||||
.nodeAlign(nodeAlign) // d3.sankeyLeft, etc.
|
||||
.nodeAlign(nodeAlign)
|
||||
.extent([
|
||||
[0, 0],
|
||||
[width - nodeWidth, height],
|
||||
[width, height],
|
||||
]);
|
||||
|
||||
// Compute the Sankey layout: calculate nodes and links positions
|
||||
@@ -98,9 +101,9 @@ export const draw = function (text: string, id: string, _version: string, diagOb
|
||||
sankey(graph);
|
||||
|
||||
// Get color scheme for the graph
|
||||
const color = d3scaleOrdinal(d3schemeTableau10);
|
||||
const colorScheme = d3scaleOrdinal(d3schemeTableau10);
|
||||
|
||||
// Create groups for nodes
|
||||
// Create rectangles for nodes
|
||||
svg
|
||||
.append('g')
|
||||
.attr('class', 'nodes')
|
||||
@@ -108,17 +111,17 @@ export const draw = function (text: string, id: string, _version: string, diagOb
|
||||
.data(graph.nodes)
|
||||
.join('g')
|
||||
.attr('class', 'node')
|
||||
.attr('transform', function (d) {
|
||||
.attr('transform', function (d: any) {
|
||||
return 'translate(' + d.x0 + ',' + d.y0 + ')';
|
||||
})
|
||||
.attr('x', (d) => d.x0)
|
||||
.attr('y', (d) => d.y0)
|
||||
.attr('x', (d: any) => d.x0)
|
||||
.attr('y', (d: any) => d.y0)
|
||||
.append('rect')
|
||||
.attr('height', (d) => {
|
||||
.attr('height', (d: any) => {
|
||||
return d.y1 - d.y0;
|
||||
})
|
||||
.attr('width', (d) => d.x1 - d.x0)
|
||||
.attr('fill', (d) => color(d.id));
|
||||
.attr('width', (d: any) => d.x1 - d.x0)
|
||||
.attr('fill', (d: any) => colorScheme(d.id));
|
||||
|
||||
// Create labels for nodes
|
||||
svg
|
||||
@@ -129,14 +132,14 @@ export const draw = function (text: string, id: string, _version: string, diagOb
|
||||
.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('x', (d: any) => (d.x0 < width / 2 ? d.x1 + 6 : d.x0 - 6))
|
||||
.attr('y', (d: any) => (d.y1 + d.y0) / 2)
|
||||
.attr('dy', '0.35em')
|
||||
.attr('text-anchor', (d) => (d.x0 < width / 2 ? 'start' : 'end'))
|
||||
.text((d) => d.label);
|
||||
.attr('text-anchor', (d: any) => (d.x0 < width / 2 ? 'start' : 'end'))
|
||||
.text((d: any) => d.label);
|
||||
|
||||
// Creates the paths that represent the links.
|
||||
const link_g = svg
|
||||
const link = svg
|
||||
.append('g')
|
||||
.attr('class', 'links')
|
||||
.attr('fill', 'none')
|
||||
@@ -147,11 +150,27 @@ export const draw = function (text: string, id: string, _version: string, diagOb
|
||||
.attr('class', 'link')
|
||||
.style('mix-blend-mode', 'multiply');
|
||||
|
||||
link_g
|
||||
const gradient = link.append("linearGradient")
|
||||
.attr("id", d => (d.uid = Uid.next("linearGradient-")).id)
|
||||
.attr("gradientUnits", "userSpaceOnUse")
|
||||
.attr("x1", d => d.source.x1)
|
||||
.attr("x2", d => d.target.x0);
|
||||
|
||||
gradient
|
||||
.append("stop")
|
||||
.attr("offset", "0%")
|
||||
.attr("stop-color", d => colorScheme(d.source.id));
|
||||
|
||||
gradient
|
||||
.append("stop")
|
||||
.attr("offset", "100%")
|
||||
.attr("stop-color", d => colorScheme(d.target.id));
|
||||
|
||||
link
|
||||
.append('path')
|
||||
.attr('d', d3SankeyLinkHorizontal())
|
||||
.attr('stroke', (d) => color(d.source.id))
|
||||
.attr('stroke-width', (d) => Math.max(1, d.width));
|
||||
.attr('stroke', (d: any) => d.uid)
|
||||
.attr('stroke-width', (d: any) => Math.max(1, d.width));
|
||||
};
|
||||
|
||||
export default {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
export const prepareTextForParsing = (text: string): string => {
|
||||
const prepareTextForParsing = (text: string): string => {
|
||||
const textToParse = text
|
||||
.replaceAll(/^[^\S\n\r]+|[^\S\n\r]+$/g, '') // remove all trailing spaces for each row
|
||||
.replaceAll(/([\n\r])+/g, '\n') // remove empty lines duplicated
|
||||
@@ -6,3 +6,33 @@ export const prepareTextForParsing = (text: string): string => {
|
||||
|
||||
return textToParse;
|
||||
};
|
||||
|
||||
|
||||
class Uid {
|
||||
private static count: number = 0;
|
||||
id: string;
|
||||
href: string;
|
||||
|
||||
public static next(name: string): Uid {
|
||||
return new Uid(name + ++Uid.count);
|
||||
}
|
||||
|
||||
constructor(id: string) {
|
||||
this.id = id;
|
||||
this.href = `#${id}`;
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return "url(" + this.href + ")";
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
Uid,
|
||||
prepareTextForParsing
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -1,5 +0,0 @@
|
||||
const getStyles = (options) =>
|
||||
`
|
||||
`;
|
||||
|
||||
export default getStyles;
|
@@ -29,7 +29,6 @@ import state from './diagrams/state/styles.js';
|
||||
import journey from './diagrams/user-journey/styles.js';
|
||||
import timeline from './diagrams/timeline/styles.js';
|
||||
import mindmap from './diagrams/mindmap/styles.js';
|
||||
import sankey from './diagrams/sankey/styles.js';
|
||||
import themes from './themes/index.js';
|
||||
|
||||
async function checkValidStylisCSSStyleSheet(stylisString: string) {
|
||||
@@ -99,7 +98,7 @@ describe('styles', () => {
|
||||
sequence,
|
||||
state,
|
||||
timeline,
|
||||
sankey,
|
||||
sankey: () => {},
|
||||
})) {
|
||||
test(`should return a valid style for diagram ${diagramId} and theme ${themeId}`, async () => {
|
||||
const { default: getStyles, addStylesForDiagram } = await import('./styles.js');
|
||||
|
Reference in New Issue
Block a user