Added gradient for sankey and cleaned code
This commit is contained in:
parent
518da3236f
commit
d9036c7af1
|
@ -66,6 +66,8 @@
|
|||
"@cypress/code-coverage": "^3.10.7",
|
||||
"@rollup/plugin-typescript": "^11.1.1",
|
||||
"@types/cors": "^2.8.13",
|
||||
"@types/d3": "^7.4.0",
|
||||
"@types/d3-sankey": "^0.12.1",
|
||||
"@types/eslint": "^8.37.0",
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/js-yaml": "^4.0.5",
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -25,6 +25,12 @@ importers:
|
|||
'@types/cors':
|
||||
specifier: ^2.8.13
|
||||
version: 2.8.13
|
||||
'@types/d3':
|
||||
specifier: ^7.4.0
|
||||
version: 7.4.0
|
||||
'@types/d3-sankey':
|
||||
specifier: ^0.12.1
|
||||
version: 0.12.1
|
||||
'@types/eslint':
|
||||
specifier: ^8.37.0
|
||||
version: 8.37.0
|
||||
|
@ -3983,6 +3989,10 @@ packages:
|
|||
'@types/d3-color': 3.1.0
|
||||
dev: true
|
||||
|
||||
/@types/d3-path@1.0.9:
|
||||
resolution: {integrity: sha512-NaIeSIBiFgSC6IGUBjZWcscUJEq7vpVu7KthHN8eieTV9d9MqkSOZLH4chq1PmcKy06PNe3axLeKmRIyxJ+PZQ==}
|
||||
dev: true
|
||||
|
||||
/@types/d3-path@3.0.0:
|
||||
resolution: {integrity: sha512-0g/A+mZXgFkQxN3HniRDbXMN79K3CdTpLsevj+PXiTcb2hVyvkZUBg37StmgCQkaD84cUJ4uaDAWq7UJOQy2Tg==}
|
||||
dev: true
|
||||
|
@ -3999,6 +4009,12 @@ packages:
|
|||
resolution: {integrity: sha512-IIE6YTekGczpLYo/HehAy3JGF1ty7+usI97LqraNa8IiDur+L44d0VOjAvFQWJVdZOJHukUJw+ZdZBlgeUsHOQ==}
|
||||
dev: true
|
||||
|
||||
/@types/d3-sankey@0.12.1:
|
||||
resolution: {integrity: sha512-10X6l6lXB42udBNX9/fDN+kJuooifSMk7+x4U9815eobavldqis4wDdFQUQjMazh+qlzsUZsGzXKxfWFUVt+3w==}
|
||||
dependencies:
|
||||
'@types/d3-shape': 1.3.8
|
||||
dev: true
|
||||
|
||||
/@types/d3-scale-chromatic@3.0.0:
|
||||
resolution: {integrity: sha512-dsoJGEIShosKVRBZB0Vo3C8nqSDqVGujJU6tPznsBJxNJNwMF8utmS83nvCBKQYPpjCzaaHcrf66iTRpZosLPw==}
|
||||
dev: true
|
||||
|
@ -4013,6 +4029,12 @@ packages:
|
|||
resolution: {integrity: sha512-xCB0z3Hi8eFIqyja3vW8iV01+OHGYR2di/+e+AiOcXIOrY82lcvWW8Ke1DYE/EUVMsBl4Db9RppSBS3X1U6J0w==}
|
||||
dev: true
|
||||
|
||||
/@types/d3-shape@1.3.8:
|
||||
resolution: {integrity: sha512-gqfnMz6Fd5H6GOLYixOZP/xlrMtJms9BaS+6oWxTKHNqPGZ93BkWWupQSCYm6YHqx6h9wjRupuJb90bun6ZaYg==}
|
||||
dependencies:
|
||||
'@types/d3-path': 1.0.9
|
||||
dev: true
|
||||
|
||||
/@types/d3-shape@3.1.0:
|
||||
resolution: {integrity: sha512-jYIYxFFA9vrJ8Hd4Se83YI6XF+gzDL1aC5DCsldai4XYYiVNdhtpGbA/GM6iyQ8ayhSp3a148LY34hy7A4TxZA==}
|
||||
dependencies:
|
||||
|
|
Loading…
Reference in New Issue