refactor: correct shapes types

All of the shapes in
`packages/mermaid/src/rendering-util/rendering-elements/shapes/` use
`D3.Selection`s as input parameters and as return parameters.

Although, for some reason, passing them to roughjs seems to work?
This commit is contained in:
Alois Klink 2024-10-17 22:29:38 +09:00
parent cfe7cce41d
commit 9afb181d06
62 changed files with 431 additions and 241 deletions

View File

@ -1,4 +1,5 @@
import type { Entries } from 'type-fest';
import type { D3Selection } from '../../types.js';
import type { Node, ShapeRenderOptions } from '../types.js';
import { anchor } from './shapes/anchor.js';
import { bowTieRect } from './shapes/bowTieRect.js';
@ -57,8 +58,12 @@ import { waveEdgedRectangle } from './shapes/waveEdgedRectangle.js';
import { waveRectangle } from './shapes/waveRectangle.js';
import { windowPane } from './shapes/windowPane.js';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type ShapeHandler = (parent: any, node: Node, options: ShapeRenderOptions) => unknown;
type MaybePromise<T> = T | Promise<T>;
type ShapeHandler = <T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node,
options: ShapeRenderOptions
) => MaybePromise<D3Selection<SVGGElement>>;
export interface ShapeDefinition {
semanticName: string;

View File

@ -1,11 +1,13 @@
import { log } from '../../../logger.js';
import { updateNodeBounds, getNodeClasses } from './util.js';
import intersect from '../intersect/index.js';
import type { Node } from '../../types.ts';
import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import { handleUndefinedAttr } from '../../../utils.js';
import type { D3Selection } from '../../../types.js';
export const anchor = (parent: SVGAElement, node: Node): Promise<SVGAElement> => {
export function anchor<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles } = styles2String(node);
node.labelStyle = labelStyles;
const classes = getNodeClasses(node);
@ -14,7 +16,6 @@ export const anchor = (parent: SVGAElement, node: Node): Promise<SVGAElement> =>
cssClasses = 'anchor';
}
const shapeSvg = parent
// @ts-ignore - SVGElement is not typed
.insert('g')
.attr('class', cssClasses)
.attr('id', node.domId || node.id);
@ -23,6 +24,7 @@ export const anchor = (parent: SVGAElement, node: Node): Promise<SVGAElement> =>
const { cssStyles } = node;
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, { fill: 'black', stroke: 'none', fillStyle: 'solid' });
@ -31,7 +33,7 @@ export const anchor = (parent: SVGAElement, node: Node): Promise<SVGAElement> =>
}
const roughNode = rc.circle(0, 0, radius * 2, options);
const circleElem = shapeSvg.insert(() => roughNode, ':first-child');
circleElem.attr('class', 'anchor').attr('style', cssStyles);
circleElem.attr('class', 'anchor').attr('style', handleUndefinedAttr(cssStyles));
updateNodeBounds(node, circleElem);
@ -41,4 +43,4 @@ export const anchor = (parent: SVGAElement, node: Node): Promise<SVGAElement> =>
};
return shapeSvg;
};
}

View File

@ -1,8 +1,9 @@
import { labelHelper, updateNodeBounds, getNodeClasses, createPathFromPoints } from './util.js';
import intersect from '../intersect/index.js';
import type { Node } from '../../types.ts';
import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
function generateArcPoints(
x1: number,
@ -70,7 +71,7 @@ function generateArcPoints(
return points;
}
export const bowTieRect = async (parent: SVGAElement, node: Node) => {
export async function bowTieRect<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node));
@ -91,6 +92,7 @@ export const bowTieRect = async (parent: SVGAElement, node: Node) => {
...generateArcPoints(w / 2, h / 2, w / 2, -h / 2, rx, ry, true),
];
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
@ -122,4 +124,4 @@ export const bowTieRect = async (parent: SVGAElement, node: Node) => {
};
return shapeSvg;
};
}

View File

@ -1,11 +1,12 @@
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
import intersect from '../intersect/index.js';
import type { Node } from '../../types.ts';
import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import { insertPolygonShape } from './insertPolygonShape.js';
import { createPathFromPoints } from './util.js';
import type { D3Selection } from '../../../types.js';
// const createPathFromPoints = (points: { x: number; y: number }[]): string => {
// const pointStrings = points.map((p, i) => `${i === 0 ? 'M' : 'L'}${p.x},${p.y}`);
@ -13,7 +14,7 @@ import { createPathFromPoints } from './util.js';
// return pointStrings.join(' ');
// };
export async function card(parent: SVGAElement, node: Node): Promise<SVGAElement> {
export async function card<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node));
@ -34,10 +35,11 @@ export async function card(parent: SVGAElement, node: Node): Promise<SVGAElement
{ x: left + padding, y: top },
];
let polygon: d3.Selection<SVGPolygonElement | SVGGElement, unknown, null, undefined>;
let polygon: D3Selection<SVGGElement> | Awaited<ReturnType<typeof insertPolygonShape>>;
const { cssStyles } = node;
if (node.look === 'handDrawn') {
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
const pathData = createPathFromPoints(points);

View File

@ -1,12 +1,11 @@
import intersect from '../intersect/index.js';
import type { Node } from '../../types.js';
import type { SVG } from '../../../diagram-api/types.js';
// @ts-ignore TODO: Fix rough typings
import rough from 'roughjs';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import { createPathFromPoints, getNodeClasses } from './util.js';
import type { D3Selection } from '../../../types.js';
export const choice = (parent: SVG, node: Node) => {
export function choice<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { nodeStyles } = styles2String(node);
node.label = '';
const shapeSvg = parent
@ -24,7 +23,7 @@ export const choice = (parent: SVG, node: Node) => {
{ x: -s / 2, y: 0 },
];
// @ts-ignore TODO: Fix rough typings
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
@ -53,4 +52,4 @@ export const choice = (parent: SVG, node: Node) => {
};
return shapeSvg;
};
}

View File

@ -4,8 +4,10 @@ import intersect from '../intersect/index.js';
import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
import { handleUndefinedAttr } from '../../../utils.js';
export const circle = async (parent: SVGAElement, node: Node): Promise<SVGAElement> => {
export async function circle<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox, halfPadding } = await labelHelper(parent, node, getNodeClasses(node));
@ -15,12 +17,13 @@ export const circle = async (parent: SVGAElement, node: Node): Promise<SVGAEleme
const { cssStyles } = node;
if (node.look === 'handDrawn') {
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
const roughNode = rc.circle(0, 0, radius * 2, options);
circleElem = shapeSvg.insert(() => roughNode, ':first-child');
circleElem.attr('class', 'basic label-container').attr('style', cssStyles);
circleElem.attr('class', 'basic label-container').attr('style', handleUndefinedAttr(cssStyles));
} else {
circleElem = shapeSvg
.insert('circle', ':first-child')
@ -39,4 +42,4 @@ export const circle = async (parent: SVGAElement, node: Node): Promise<SVGAEleme
};
return shapeSvg;
};
}

View File

@ -1,10 +1,10 @@
import { log } from '../../../logger.js';
import { getNodeClasses, updateNodeBounds } from './util.js';
import type { SVG } from '../../../diagram-api/types.js';
import type { Node } from '../../types.ts';
import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import intersect from '../intersect/index.js';
import type { D3Selection } from '../../../types.js';
function createLine(r: number) {
const xAxis45 = Math.cos(Math.PI / 4); // cosine of 45 degrees
@ -20,7 +20,7 @@ function createLine(r: number) {
M ${pointQ1.x},${pointQ1.y} L ${pointQ3.x},${pointQ3.y}`;
}
export const crossedCircle = (parent: SVG, node: Node) => {
export function crossedCircle<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
node.label = '';
@ -31,7 +31,7 @@ export const crossedCircle = (parent: SVG, node: Node) => {
const radius = Math.max(30, node?.width ?? 0);
const { cssStyles } = node;
// @ts-expect-error shapeSvg d3 class is incorrect?
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
@ -64,4 +64,4 @@ export const crossedCircle = (parent: SVG, node: Node) => {
};
return shapeSvg;
};
}

View File

@ -1,8 +1,9 @@
import { labelHelper, updateNodeBounds, getNodeClasses, createPathFromPoints } from './util.js';
import intersect from '../intersect/index.js';
import type { Node } from '../../types.ts';
import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
function generateCirclePoints(
centerX: number,
@ -34,7 +35,10 @@ function generateCirclePoints(
return points;
}
export const curlyBraceLeft = async (parent: SVGAElement, node: Node) => {
export async function curlyBraceLeft<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node
) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox, label } = await labelHelper(parent, node, getNodeClasses(node));
@ -66,6 +70,7 @@ export const curlyBraceLeft = async (parent: SVGAElement, node: Node) => {
{ x: w / 2, y: h / 2 + radius },
];
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, { fill: 'none' });
@ -107,4 +112,4 @@ export const curlyBraceLeft = async (parent: SVGAElement, node: Node) => {
};
return shapeSvg;
};
}

View File

@ -1,8 +1,9 @@
import { labelHelper, updateNodeBounds, getNodeClasses, createPathFromPoints } from './util.js';
import intersect from '../intersect/index.js';
import type { Node } from '../../types.ts';
import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
function generateCirclePoints(
centerX: number,
@ -34,7 +35,10 @@ function generateCirclePoints(
return points;
}
export const curlyBraceRight = async (parent: SVGAElement, node: Node) => {
export async function curlyBraceRight<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node
) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox, label } = await labelHelper(parent, node, getNodeClasses(node));
@ -66,6 +70,7 @@ export const curlyBraceRight = async (parent: SVGAElement, node: Node) => {
{ x: -w / 2, y: h / 2 + radius },
];
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, { fill: 'none' });
@ -107,4 +112,4 @@ export const curlyBraceRight = async (parent: SVGAElement, node: Node) => {
};
return shapeSvg;
};
}

View File

@ -1,8 +1,9 @@
import { labelHelper, updateNodeBounds, getNodeClasses, createPathFromPoints } from './util.js';
import intersect from '../intersect/index.js';
import type { Node } from '../../types.ts';
import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
function generateCirclePoints(
centerX: number,
@ -34,7 +35,10 @@ function generateCirclePoints(
return points;
}
export const curlyBraces = async (parent: SVGAElement, node: Node) => {
export async function curlyBraces<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node
) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox, label } = await labelHelper(parent, node, getNodeClasses(node));
@ -81,6 +85,7 @@ export const curlyBraces = async (parent: SVGAElement, node: Node) => {
...generateCirclePoints(-w / 2 + radius + radius / 2, h / 2, radius, 30, -180, -270),
];
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, { fill: 'none' });
@ -126,4 +131,4 @@ export const curlyBraces = async (parent: SVGAElement, node: Node) => {
};
return shapeSvg;
};
}

View File

@ -6,11 +6,15 @@ import {
generateCirclePoints,
} from './util.js';
import intersect from '../intersect/index.js';
import type { Node } from '../../types.ts';
import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
export const curvedTrapezoid = async (parent: SVGAElement, node: Node) => {
export async function curvedTrapezoid<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node
) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node));
@ -21,6 +25,7 @@ export const curvedTrapezoid = async (parent: SVGAElement, node: Node) => {
const radius = h / 2;
const { cssStyles } = node;
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
@ -67,4 +72,4 @@ export const curvedTrapezoid = async (parent: SVGAElement, node: Node) => {
};
return shapeSvg;
};
}

View File

@ -3,6 +3,8 @@ import intersect from '../intersect/index.js';
import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
import { handleUndefinedAttr } from '../../../utils.js';
export const createCylinderPathD = (
x: number,
@ -48,7 +50,7 @@ export const createInnerCylinderPathD = (
): string => {
return [`M${x - width / 2},${-height / 2}`, `a${rx},${ry} 0,0,0 ${width},0`].join(' ');
};
export const cylinder = async (parent: SVGAElement, node: Node) => {
export async function cylinder<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox, label } = await labelHelper(parent, node, getNodeClasses(node));
@ -57,10 +59,11 @@ export const cylinder = async (parent: SVGAElement, node: Node) => {
const ry = rx / (2.5 + w / 50);
const h = Math.max(bbox.height + ry + node.padding, node.height ?? 0);
let cylinder: d3.Selection<SVGPathElement | SVGGElement, unknown, null, undefined>;
let cylinder: D3Selection<SVGPathElement> | D3Selection<SVGGElement>;
const { cssStyles } = node;
if (node.look === 'handDrawn') {
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const outerPathData = createOuterCylinderPathD(0, 0, w, h, rx, ry);
const innerPathData = createInnerCylinderPathD(0, ry, w, h, rx, ry);
@ -79,7 +82,7 @@ export const cylinder = async (parent: SVGAElement, node: Node) => {
.insert('path', ':first-child')
.attr('d', pathData)
.attr('class', 'basic label-container')
.attr('style', cssStyles)
.attr('style', handleUndefinedAttr(cssStyles))
.attr('style', nodeStyles);
}
@ -119,4 +122,4 @@ export const cylinder = async (parent: SVGAElement, node: Node) => {
};
return shapeSvg;
};
}

View File

@ -1,10 +1,14 @@
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
import intersect from '../intersect/index.js';
import type { Node } from '../../types.ts';
import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
export const dividedRectangle = async (parent: SVGAElement, node: Node) => {
export async function dividedRectangle<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node
) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox, label } = await labelHelper(parent, node, getNodeClasses(node));
@ -17,6 +21,7 @@ export const dividedRectangle = async (parent: SVGAElement, node: Node) => {
const { cssStyles } = node;
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
if (node.look !== 'handDrawn') {
@ -63,4 +68,4 @@ export const dividedRectangle = async (parent: SVGAElement, node: Node) => {
};
return shapeSvg;
};
}

View File

@ -1,8 +1,10 @@
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
import intersect from '../intersect/index.js';
import type { Node } from '../../types.ts';
import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
import { handleUndefinedAttr } from '../../../utils.js';
export const createCylinderPathD = (
x: number,
@ -48,7 +50,7 @@ export const createInnerCylinderPathD = (
): string => {
return [`M${x - width / 2},${-height / 2}`, `a${rx},${ry} 0,0,0 ${width},0`].join(' ');
};
export const cylinder = async (parent: SVGAElement, node: Node) => {
export async function cylinder<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node));
@ -57,10 +59,11 @@ export const cylinder = async (parent: SVGAElement, node: Node) => {
const ry = rx / (2.5 + w / 50);
const h = bbox.height + ry + node.padding;
let cylinder: d3.Selection<SVGPathElement | SVGGElement, unknown, null, undefined>;
let cylinder: D3Selection<SVGPathElement> | D3Selection<SVGGElement>;
const { cssStyles } = node;
if (node.look === 'handDrawn') {
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const outerPathData = createOuterCylinderPathD(0, 0, w, h, rx, ry);
const innerPathData = createInnerCylinderPathD(0, ry, w, h, rx, ry);
@ -79,7 +82,7 @@ export const cylinder = async (parent: SVGAElement, node: Node) => {
.insert('path', ':first-child')
.attr('d', pathData)
.attr('class', 'basic label-container')
.attr('style', cssStyles)
.attr('style', handleUndefinedAttr(cssStyles))
.attr('style', nodeStyles);
}
@ -114,4 +117,4 @@ export const cylinder = async (parent: SVGAElement, node: Node) => {
};
return shapeSvg;
};
}

View File

@ -4,8 +4,13 @@ import intersect from '../intersect/index.js';
import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
import { handleUndefinedAttr } from '../../../utils.js';
export const doublecircle = async (parent: SVGAElement, node: Node): Promise<SVGAElement> => {
export async function doublecircle<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node
) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox, halfPadding } = await labelHelper(parent, node, getNodeClasses(node));
@ -17,6 +22,7 @@ export const doublecircle = async (parent: SVGAElement, node: Node): Promise<SVG
const { cssStyles } = node;
if (node.look === 'handDrawn') {
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const outerOptions = userNodeOverrides(node, { roughness: 0.2, strokeWidth: 2.5 });
@ -26,7 +32,9 @@ export const doublecircle = async (parent: SVGAElement, node: Node): Promise<SVG
circleGroup = shapeSvg.insert('g', ':first-child');
// circleGroup = circleGroup.insert(() => outerRoughNode, ':first-child');
circleGroup.attr('class', node.cssClasses).attr('style', cssStyles);
circleGroup
.attr('class', handleUndefinedAttr(node.cssClasses))
.attr('style', handleUndefinedAttr(cssStyles));
circleGroup.node()?.appendChild(outerRoughNode);
circleGroup.node()?.appendChild(innerRoughNode);
@ -60,4 +68,4 @@ export const doublecircle = async (parent: SVGAElement, node: Node): Promise<SVG
};
return shapeSvg;
};
}

View File

@ -4,8 +4,14 @@ import type { Node, RectOptions } from '../../types.js';
import { createRoundedRectPathD } from './roundedRectPath.js';
import { userNodeOverrides, styles2String } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
import { handleUndefinedAttr } from '../../../utils.js';
export const drawRect = async (parent: SVGAElement, node: Node, options: RectOptions) => {
export async function drawRect<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node,
options: RectOptions
) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
// console.log('IPI labelStyles:', labelStyles);
@ -39,15 +45,15 @@ export const drawRect = async (parent: SVGAElement, node: Node, options: RectOpt
: rc.rectangle(x, y, totalWidth, totalHeight, options);
rect = shapeSvg.insert(() => roughNode, ':first-child');
rect.attr('class', 'basic label-container').attr('style', cssStyles);
rect.attr('class', 'basic label-container').attr('style', handleUndefinedAttr(cssStyles));
} else {
rect = shapeSvg.insert('rect', ':first-child');
rect
.attr('class', 'basic label-container')
.attr('style', nodeStyles)
.attr('rx', rx)
.attr('ry', ry)
.attr('rx', handleUndefinedAttr(rx))
.attr('ry', handleUndefinedAttr(ry))
.attr('x', x)
.attr('y', y)
.attr('width', totalWidth)
@ -61,4 +67,4 @@ export const drawRect = async (parent: SVGAElement, node: Node, options: RectOpt
};
return shapeSvg;
};
}

View File

@ -1,16 +1,16 @@
import rough from 'roughjs';
import type { SVG } from '../../../diagram-api/types.js';
import { log } from '../../../logger.js';
import type { Node, ShapeRenderOptions } from '../../types.ts';
import type { Node, ShapeRenderOptions } from '../../types.js';
import intersect from '../intersect/index.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import { getNodeClasses, updateNodeBounds } from './util.js';
import type { D3Selection } from '../../../types.js';
export const filledCircle = (
parent: SVG,
export function filledCircle<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node,
{ config: { themeVariables } }: ShapeRenderOptions
) => {
) {
const { labelStyles, nodeStyles } = styles2String(node);
node.label = '';
node.labelStyle = labelStyles;
@ -21,7 +21,7 @@ export const filledCircle = (
const radius = 7;
const { cssStyles } = node;
// @ts-expect-error shapeSvg d3 class is incorrect?
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const { nodeBorder } = themeVariables;
const options = userNodeOverrides(node, { fillStyle: 'solid' });
@ -53,4 +53,4 @@ export const filledCircle = (
};
return shapeSvg;
};
}

View File

@ -1,12 +1,16 @@
import { log } from '../../../logger.js';
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
import intersect from '../intersect/index.js';
import type { Node } from '../../types.ts';
import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import { createPathFromPoints } from './util.js';
import type { D3Selection } from '../../../types.js';
export const flippedTriangle = async (parent: SVGAElement, node: Node): Promise<SVGAElement> => {
export async function flippedTriangle<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node
) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox, label } = await labelHelper(parent, node, getNodeClasses(node));
@ -23,6 +27,7 @@ export const flippedTriangle = async (parent: SVGAElement, node: Node): Promise<
const { cssStyles } = node;
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
if (node.look !== 'handDrawn') {
@ -60,4 +65,4 @@ export const flippedTriangle = async (parent: SVGAElement, node: Node): Promise<
};
return shapeSvg;
};
}

View File

@ -1,15 +1,15 @@
import rough from 'roughjs';
import type { SVG } from '../../../diagram-api/types.js';
import type { Node, ShapeRenderOptions } from '../../types.js';
import intersect from '../intersect/index.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import { getNodeClasses, updateNodeBounds } from './util.js';
import type { D3Selection } from '../../../types.js';
export const forkJoin = (
parent: SVG,
export function forkJoin<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node,
{ dir, config: { state, themeVariables } }: ShapeRenderOptions
) => {
) {
const { nodeStyles } = styles2String(node);
node.label = '';
const shapeSvg = parent
@ -29,7 +29,7 @@ export const forkJoin = (
const x = (-1 * width) / 2;
const y = (-1 * height) / 2;
// @ts-ignore TODO: Fix rough typings
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {
stroke: themeVariables.lineColor,
@ -63,4 +63,4 @@ export const forkJoin = (
return intersect.rect(node, point);
};
return shapeSvg;
};
}

View File

@ -7,11 +7,15 @@ import {
generateCirclePoints,
} from './util.js';
import intersect from '../intersect/index.js';
import type { Node } from '../../types.ts';
import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
export const halfRoundedRectangle = async (parent: SVGAElement, node: Node) => {
export async function halfRoundedRectangle<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node
) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const minWidth = 80,
@ -22,6 +26,7 @@ export const halfRoundedRectangle = async (parent: SVGAElement, node: Node) => {
const radius = h / 2;
const { cssStyles } = node;
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
@ -64,4 +69,4 @@ export const halfRoundedRectangle = async (parent: SVGAElement, node: Node) => {
return pos;
};
return shapeSvg;
};
}

View File

@ -3,8 +3,8 @@ import intersect from '../intersect/index.js';
import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import { insertPolygonShape } from './insertPolygonShape.js';
import type { D3Selection } from '../../../types.js';
export const createHexagonPathD = (
x: number,
@ -24,7 +24,7 @@ export const createHexagonPathD = (
].join(' ');
};
export const hexagon = async (parent: SVGAElement, node: Node): Promise<SVGAElement> => {
export async function hexagon<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node));
@ -42,10 +42,11 @@ export const hexagon = async (parent: SVGAElement, node: Node): Promise<SVGAElem
{ x: 0, y: -h / 2 },
];
let polygon: d3.Selection<SVGPolygonElement | SVGGElement, unknown, null, undefined>;
let polygon: D3Selection<SVGGElement> | Awaited<ReturnType<typeof insertPolygonShape>>;
const { cssStyles } = node;
if (node.look === 'handDrawn') {
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
const pathData = createHexagonPathD(0, 0, w, h, m);
@ -76,4 +77,4 @@ export const hexagon = async (parent: SVGAElement, node: Node): Promise<SVGAElem
};
return shapeSvg;
};
}

View File

@ -1,11 +1,12 @@
import { log } from '../../../logger.js';
import { labelHelper, updateNodeBounds, getNodeClasses, createPathFromPoints } from './util.js';
import intersect from '../intersect/index.js';
import type { Node } from '../../types.ts';
import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
export const hourglass = async (parent: SVGAElement, node: Node) => {
export async function hourglass<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
node.label = '';
node.labelStyle = labelStyles;
@ -16,6 +17,7 @@ export const hourglass = async (parent: SVGAElement, node: Node) => {
const { cssStyles } = node;
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
@ -57,4 +59,4 @@ export const hourglass = async (parent: SVGAElement, node: Node) => {
};
return shapeSvg;
};
}

View File

@ -1,17 +1,17 @@
import rough from 'roughjs';
import type { SVG } from '../../../diagram-api/types.js';
import { log } from '../../../logger.js';
import { getIconSVG } from '../../icons.js';
import type { Node, ShapeRenderOptions } from '../../types.ts';
import type { Node, ShapeRenderOptions } from '../../types.js';
import intersect from '../intersect/index.js';
import { compileStyles, styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import { labelHelper, updateNodeBounds } from './util.js';
import type { D3Selection } from '../../../types.js';
export const icon = async (
parent: SVG,
export async function icon<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node,
{ config: { themeVariables, flowchart } }: ShapeRenderOptions
) => {
) {
const { labelStyles } = styles2String(node);
node.labelStyle = labelStyles;
const assetHeight = node.assetHeight ?? 48;
@ -33,6 +33,7 @@ export const icon = async (
const labelPadding = node.label ? 8 : 0;
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, { stroke: 'none', fill: 'none' });
@ -64,7 +65,7 @@ export const icon = async (
fallbackPrefix: '',
})}</g>`
);
const iconBBox = iconElem.node().getBBox();
const iconBBox = iconElem.node()!.getBBox();
const iconWidth = iconBBox.width;
const iconHeight = iconBBox.height;
const iconX = iconBBox.x;
@ -134,4 +135,4 @@ export const icon = async (
};
return shapeSvg;
};
}

View File

@ -1,17 +1,17 @@
import rough from 'roughjs';
import type { SVG } from '../../../diagram-api/types.js';
import { log } from '../../../logger.js';
import { getIconSVG } from '../../icons.js';
import type { Node, ShapeRenderOptions } from '../../types.ts';
import type { Node, ShapeRenderOptions } from '../../types.js';
import intersect from '../intersect/index.js';
import { compileStyles, styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import { labelHelper, updateNodeBounds } from './util.js';
import type { D3Selection } from '../../../types.js';
export const iconCircle = async (
parent: SVG,
export async function iconCircle<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node,
{ config: { themeVariables, flowchart } }: ShapeRenderOptions
) => {
) {
const { labelStyles } = styles2String(node);
node.labelStyle = labelStyles;
const assetHeight = node.assetHeight ?? 48;
@ -28,6 +28,7 @@ export const iconCircle = async (
const { nodeBorder } = themeVariables;
const { stylesMap } = compileStyles(node);
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, { stroke: 'transparent' });
@ -46,7 +47,7 @@ export const iconCircle = async (
})}</g>`
);
}
const iconBBox = iconElem.node().getBBox();
const iconBBox = iconElem.node()!.getBBox();
const iconWidth = iconBBox.width;
const iconHeight = iconBBox.height;
const iconX = iconBBox.x;
@ -98,4 +99,4 @@ export const iconCircle = async (
};
return shapeSvg;
};
}

View File

@ -1,18 +1,18 @@
import rough from 'roughjs';
import type { SVG } from '../../../diagram-api/types.js';
import { log } from '../../../logger.js';
import { getIconSVG } from '../../icons.js';
import type { Node, ShapeRenderOptions } from '../../types.ts';
import type { Node, ShapeRenderOptions } from '../../types.js';
import intersect from '../intersect/index.js';
import { compileStyles, styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import { createRoundedRectPathD } from './roundedRectPath.js';
import { labelHelper, updateNodeBounds } from './util.js';
import type { D3Selection } from '../../../types.js';
export const iconRounded = async (
parent: SVG,
export async function iconRounded<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node,
{ config: { themeVariables, flowchart } }: ShapeRenderOptions
) => {
) {
const { labelStyles } = styles2String(node);
node.labelStyle = labelStyles;
const assetHeight = node.assetHeight ?? 48;
@ -38,6 +38,7 @@ export const iconRounded = async (
const labelPadding = node.label ? 8 : 0;
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, { stroke: 'transparent' });
@ -69,7 +70,7 @@ export const iconRounded = async (
fallbackPrefix: '',
})}</g>`
);
const iconBBox = iconElem.node().getBBox();
const iconBBox = iconElem.node()!.getBBox();
const iconWidth = iconBBox.width;
const iconHeight = iconBBox.height;
const iconX = iconBBox.x;
@ -139,4 +140,4 @@ export const iconRounded = async (
};
return shapeSvg;
};
}

View File

@ -1,17 +1,17 @@
import rough from 'roughjs';
import type { SVG } from '../../../diagram-api/types.js';
import { log } from '../../../logger.js';
import { getIconSVG } from '../../icons.js';
import type { Node, ShapeRenderOptions } from '../../types.ts';
import type { Node, ShapeRenderOptions } from '../../types.js';
import intersect from '../intersect/index.js';
import { compileStyles, styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import { labelHelper, updateNodeBounds } from './util.js';
import type { D3Selection } from '../../../types.js';
export const iconSquare = async (
parent: SVG,
export async function iconSquare<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node,
{ config: { themeVariables, flowchart } }: ShapeRenderOptions
) => {
) {
const { labelStyles } = styles2String(node);
node.labelStyle = labelStyles;
const assetHeight = node.assetHeight ?? 48;
@ -37,6 +37,7 @@ export const iconSquare = async (
const labelPadding = node.label ? 8 : 0;
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, { stroke: 'transparent' });
@ -68,7 +69,7 @@ export const iconSquare = async (
fallbackPrefix: '',
})}</g>`
);
const iconBBox = iconElem.node().getBBox();
const iconBBox = iconElem.node()!.getBBox();
const iconWidth = iconBBox.width;
const iconHeight = iconBBox.height;
const iconX = iconBBox.x;
@ -138,4 +139,4 @@ export const iconSquare = async (
};
return shapeSvg;
};
}

View File

@ -1,16 +1,16 @@
import rough from 'roughjs';
import type { SVG } from '../../../diagram-api/types.js';
import { log } from '../../../logger.js';
import type { Node, ShapeRenderOptions } from '../../types.ts';
import type { Node, ShapeRenderOptions } from '../../types.js';
import intersect from '../intersect/index.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import { labelHelper, updateNodeBounds } from './util.js';
import type { D3Selection } from '../../../types.js';
export const imageSquare = async (
parent: SVG,
export async function imageSquare<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node,
{ config: { flowchart } }: ShapeRenderOptions
) => {
) {
const img = new Image();
img.src = node?.img ?? '';
await img.decode();
@ -52,6 +52,7 @@ export const imageSquare = async (
const labelPadding = node.label ? 8 : 0;
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
@ -145,4 +146,4 @@ export const imageSquare = async (
};
return shapeSvg;
};
}

View File

@ -1,5 +1,7 @@
export function insertPolygonShape(
parent: any,
import type { D3Selection } from '../../../types.js';
export function insertPolygonShape<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
w: number,
h: number,
points: { x: number; y: number }[]

View File

@ -4,6 +4,7 @@ import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import { insertPolygonShape } from './insertPolygonShape.js';
import type { D3Selection } from '../../../types.js';
// export const createInvertedTrapezoidPathD = (
// x: number,
@ -20,7 +21,10 @@ import { insertPolygonShape } from './insertPolygonShape.js';
// ].join(' ');
// };
export const inv_trapezoid = async (parent: SVGAElement, node: Node): Promise<SVGAElement> => {
export async function inv_trapezoid<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node
) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node));
@ -35,10 +39,11 @@ export const inv_trapezoid = async (parent: SVGAElement, node: Node): Promise<SV
{ x: (-3 * h) / 6, y: -h },
];
let polygon: d3.Selection<SVGPolygonElement | SVGGElement, unknown, null, undefined>;
let polygon: typeof shapeSvg | ReturnType<typeof insertPolygonShape>;
const { cssStyles } = node;
if (node.look === 'handDrawn') {
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
const pathData = createPathFromPoints(points);
@ -70,4 +75,4 @@ export const inv_trapezoid = async (parent: SVGAElement, node: Node): Promise<SV
};
return shapeSvg;
};
}

View File

@ -2,8 +2,12 @@ import type { Node, RectOptions } from '../../types.js';
import { drawRect } from './drawRect.js';
import { labelHelper, updateNodeBounds } from './util.js';
import intersect from '../intersect/index.js';
import type { D3Selection } from '../../../types.js';
export const roundedRect = async (parent: SVGAElement, node: Node) => {
export async function roundedRect<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node
) {
const options = {
rx: 5,
ry: 5,
@ -13,9 +17,9 @@ export const roundedRect = async (parent: SVGAElement, node: Node) => {
} as RectOptions;
return drawRect(parent, node, options);
};
}
export const labelRect = async (parent: SVGElement, node: Node) => {
export async function labelRect<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { shapeSvg, bbox, label } = await labelHelper(parent, node, 'label');
// log.trace('Classes = ', node.class);
@ -52,4 +56,4 @@ export const labelRect = async (parent: SVGElement, node: Node) => {
};
return shapeSvg;
};
}

View File

@ -4,8 +4,9 @@ import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import { insertPolygonShape } from './insertPolygonShape.js';
import type { D3Selection } from '../../../types.js';
export const lean_left = async (parent: SVGAElement, node: Node): Promise<SVGAElement> => {
export async function lean_left<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node));
@ -18,10 +19,11 @@ export const lean_left = async (parent: SVGAElement, node: Node): Promise<SVGAEl
{ x: -(3 * h) / 6, y: -h },
];
let polygon: d3.Selection<SVGPolygonElement | SVGGElement, unknown, null, undefined>;
let polygon: typeof shapeSvg | ReturnType<typeof insertPolygonShape>;
const { cssStyles } = node;
if (node.look === 'handDrawn') {
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
const pathData = createPathFromPoints(points);
@ -53,4 +55,4 @@ export const lean_left = async (parent: SVGAElement, node: Node): Promise<SVGAEl
};
return shapeSvg;
};
}

View File

@ -4,8 +4,9 @@ import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import { insertPolygonShape } from './insertPolygonShape.js';
import type { D3Selection } from '../../../types.js';
export const lean_right = async (parent: SVGAElement, node: Node): Promise<SVGAElement> => {
export async function lean_right<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node));
@ -18,10 +19,11 @@ export const lean_right = async (parent: SVGAElement, node: Node): Promise<SVGAE
{ x: 0, y: -h },
];
let polygon: d3.Selection<SVGPolygonElement | SVGGElement, unknown, null, undefined>;
let polygon: typeof shapeSvg | ReturnType<typeof insertPolygonShape>;
const { cssStyles } = node;
if (node.look === 'handDrawn') {
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
const pathData = createPathFromPoints(points);
@ -52,4 +54,4 @@ export const lean_right = async (parent: SVGAElement, node: Node): Promise<SVGAE
};
return shapeSvg;
};
}

View File

@ -1,13 +1,13 @@
import { log } from '../../../logger.js';
import { getNodeClasses, updateNodeBounds } from './util.js';
import type { Node } from '../../types.ts';
import type { SVG } from '../../../diagram-api/types.js';
import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import intersect from '../intersect/index.js';
import { createPathFromPoints } from './util.js';
import type { D3Selection } from '../../../types.js';
export const lightningBolt = (parent: SVG, node: Node) => {
export function lightningBolt<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
node.label = '';
node.labelStyle = labelStyles;
@ -63,4 +63,4 @@ export const lightningBolt = (parent: SVG, node: Node) => {
};
return shapeSvg;
};
}

View File

@ -3,6 +3,8 @@ import intersect from '../intersect/index.js';
import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
import { handleUndefinedAttr } from '../../../utils.js';
export const createCylinderPathD = (
x: number,
@ -54,7 +56,10 @@ export const createInnerCylinderPathD = (
): string => {
return [`M${x - width / 2},${-height / 2}`, `a${rx},${ry} 0,0,0 ${width},0`].join(' ');
};
export const linedCylinder = async (parent: SVGAElement, node: Node) => {
export async function linedCylinder<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node
) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox, label } = await labelHelper(parent, node, getNodeClasses(node));
@ -64,10 +69,11 @@ export const linedCylinder = async (parent: SVGAElement, node: Node) => {
const h = Math.max(bbox.height + ry + (node.padding ?? 0), node.height ?? 0);
const outerOffset = h * 0.1; // 10% of height
let cylinder: d3.Selection<SVGPathElement | SVGGElement, unknown, null, undefined>;
let cylinder: typeof shapeSvg | D3Selection<SVGPathElement>;
const { cssStyles } = node;
if (node.look === 'handDrawn') {
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const outerPathData = createOuterCylinderPathD(0, 0, w, h, rx, ry, outerOffset);
const innerPathData = createInnerCylinderPathD(0, ry, w, h, rx, ry);
@ -89,7 +95,7 @@ export const linedCylinder = async (parent: SVGAElement, node: Node) => {
.insert('path', ':first-child')
.attr('d', pathData)
.attr('class', 'basic label-container')
.attr('style', cssStyles)
.attr('style', handleUndefinedAttr(cssStyles))
.attr('style', nodeStyles);
}
@ -130,4 +136,4 @@ export const linedCylinder = async (parent: SVGAElement, node: Node) => {
};
return shapeSvg;
};
}

View File

@ -5,11 +5,15 @@ import {
generateFullSineWavePoints,
} from './util.js';
import intersect from '../intersect/index.js';
import type { Node } from '../../types.ts';
import type { Node } from '../../types.js';
import rough from 'roughjs';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import type { D3Selection } from '../../../types.js';
export const linedWaveEdgedRect = async (parent: SVGAElement, node: Node) => {
export async function linedWaveEdgedRect<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node
) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox, label } = await labelHelper(parent, node, getNodeClasses(node));
@ -19,6 +23,7 @@ export const linedWaveEdgedRect = async (parent: SVGAElement, node: Node) => {
const finalH = h + waveAmplitude;
const { cssStyles } = node;
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
@ -75,4 +80,4 @@ export const linedWaveEdgedRect = async (parent: SVGAElement, node: Node) => {
};
return shapeSvg;
};
}

View File

@ -1,10 +1,11 @@
import { labelHelper, getNodeClasses, updateNodeBounds, createPathFromPoints } from './util.js';
import type { Node } from '../../types.ts';
import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import intersect from '../intersect/index.js';
import type { D3Selection } from '../../../types.js';
export const multiRect = async (parent: SVGAElement, node: Node) => {
export async function multiRect<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox, label } = await labelHelper(parent, node, getNodeClasses(node));
@ -15,6 +16,7 @@ export const multiRect = async (parent: SVGAElement, node: Node) => {
const y = -h / 2;
const { cssStyles } = node;
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
@ -78,4 +80,4 @@ export const multiRect = async (parent: SVGAElement, node: Node) => {
};
return shapeSvg;
};
}

View File

@ -6,11 +6,15 @@ import {
generateFullSineWavePoints,
} from './util.js';
import intersect from '../intersect/index.js';
import type { Node } from '../../types.ts';
import type { Node } from '../../types.js';
import rough from 'roughjs';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import type { D3Selection } from '../../../types.js';
export const multiWaveEdgedRectangle = async (parent: SVGAElement, node: Node) => {
export async function multiWaveEdgedRectangle<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node
) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox, label } = await labelHelper(parent, node, getNodeClasses(node));
@ -59,6 +63,7 @@ export const multiWaveEdgedRectangle = async (parent: SVGAElement, node: Node) =
{ x, y },
];
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
@ -100,4 +105,4 @@ export const multiWaveEdgedRectangle = async (parent: SVGAElement, node: Node) =
};
return shapeSvg;
};
}

View File

@ -3,12 +3,13 @@ import type { Node, ShapeRenderOptions } from '../../types.js';
import intersect from '../intersect/index.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import { getNodeClasses, labelHelper, updateNodeBounds } from './util.js';
import type { D3Selection } from '../../../types.js';
export const note = async (
parent: SVGAElement,
export async function note<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node,
{ config: { themeVariables } }: ShapeRenderOptions
) => {
) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node));
@ -55,4 +56,4 @@ export const note = async (
};
return shapeSvg;
};
}

View File

@ -5,6 +5,7 @@ import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import { insertPolygonShape } from './insertPolygonShape.js';
import type { D3Selection } from '../../../types.js';
export const createDecisionBoxPathD = (x: number, y: number, size: number): string => {
return [
@ -16,7 +17,7 @@ export const createDecisionBoxPathD = (x: number, y: number, size: number): stri
].join(' ');
};
export const question = async (parent: SVGAElement, node: Node): Promise<SVGAElement> => {
export async function question<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node));
@ -32,10 +33,11 @@ export const question = async (parent: SVGAElement, node: Node): Promise<SVGAEle
{ x: 0, y: -s / 2 },
];
let polygon: d3.Selection<SVGPolygonElement | SVGGElement, unknown, null, undefined>;
let polygon: typeof shapeSvg | ReturnType<typeof insertPolygonShape>;
const { cssStyles } = node;
if (node.look === 'handDrawn') {
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
const pathData = createDecisionBoxPathD(0, 0, s);
@ -71,4 +73,4 @@ export const question = async (parent: SVGAElement, node: Node): Promise<SVGAEle
};
return shapeSvg;
};
}

View File

@ -3,11 +3,12 @@ import intersect from '../intersect/index.js';
import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
export const rect_left_inv_arrow = async (
parent: SVGAElement,
export async function rect_left_inv_arrow<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node
): Promise<SVGAElement> => {
) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox, label } = await labelHelper(parent, node, getNodeClasses(node));
@ -28,6 +29,7 @@ export const rect_left_inv_arrow = async (
];
const { cssStyles } = node;
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
@ -63,4 +65,4 @@ export const rect_left_inv_arrow = async (
};
return shapeSvg;
};
}

View File

@ -9,8 +9,12 @@ import rough from 'roughjs';
import { getConfig } from '../../../diagram-api/diagramAPI.js';
import { createRoundedRectPathD } from './roundedRectPath.js';
import { log } from '../../../logger.js';
import type { D3Selection } from '../../../types.js';
export const rectWithTitle = async (parent: SVGElement, node: Node) => {
export async function rectWithTitle<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node
) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
let classes;
@ -36,7 +40,7 @@ export const rectWithTitle = async (parent: SVGElement, node: Node) => {
const title = node.label;
const text = label.node().appendChild(await createLabel(title, node.labelStyle, true, true));
const text = label.node()!.appendChild(await createLabel(title, node.labelStyle, true, true));
let bbox = { width: 0, height: 0 };
if (evaluate(getConfig()?.flowchart?.htmlLabels)) {
const div = text.children[0];
@ -49,7 +53,7 @@ export const rectWithTitle = async (parent: SVGElement, node: Node) => {
const textRows = description || [];
const titleBox = text.getBBox();
const descr = label
.node()
.node()!
.appendChild(
await createLabel(
textRows.join ? textRows.join('<br/>') : textRows,
@ -87,7 +91,7 @@ export const rectWithTitle = async (parent: SVGElement, node: Node) => {
// Get the size of the label
// Bounding box for title and text
bbox = label.node().getBBox();
bbox = label.node()!.getBBox();
// Center the label
label.attr(
@ -151,4 +155,4 @@ export const rectWithTitle = async (parent: SVGElement, node: Node) => {
};
return shapeSvg;
};
}

View File

@ -1,7 +1,11 @@
import type { Node, RectOptions } from '../../types.js';
import type { D3Selection } from '../../../types.js';
import { drawRect } from './drawRect.js';
export const roundedRect = async (parent: SVGAElement, node: Node) => {
export async function roundedRect<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node
) {
const options = {
rx: 5,
ry: 5,
@ -11,4 +15,4 @@ export const roundedRect = async (parent: SVGAElement, node: Node) => {
} as RectOptions;
return drawRect(parent, node, options);
};
}

View File

@ -1,10 +1,15 @@
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
import intersect from '../intersect/index.js';
import type { Node } from '../../types.ts';
import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
import { handleUndefinedAttr } from '../../../utils.js';
export const shadedProcess = async (parent: SVGAElement, node: Node) => {
export async function shadedProcess<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node
) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox, label } = await labelHelper(parent, node, getNodeClasses(node));
@ -15,6 +20,7 @@ export const shadedProcess = async (parent: SVGAElement, node: Node) => {
const y = -bbox.height / 2 - halfPadding;
const { cssStyles } = node;
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
@ -40,7 +46,7 @@ export const shadedProcess = async (parent: SVGAElement, node: Node) => {
const rect = shapeSvg.insert(() => roughNode, ':first-child');
rect.attr('class', 'basic label-container').attr('style', cssStyles);
rect.attr('class', 'basic label-container').attr('style', handleUndefinedAttr(cssStyles));
if (nodeStyles && node.look !== 'handDrawn') {
rect.selectAll('path').attr('style', nodeStyles);
@ -62,4 +68,4 @@ export const shadedProcess = async (parent: SVGAElement, node: Node) => {
};
return shapeSvg;
};
}

View File

@ -1,10 +1,11 @@
import { labelHelper, updateNodeBounds, getNodeClasses, createPathFromPoints } from './util.js';
import intersect from '../intersect/index.js';
import type { Node } from '../../types.ts';
import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
export const slopedRect = async (parent: SVGAElement, node: Node) => {
export async function slopedRect<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox, label } = await labelHelper(parent, node, getNodeClasses(node));
@ -15,6 +16,7 @@ export const slopedRect = async (parent: SVGAElement, node: Node) => {
const { cssStyles } = node;
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
@ -58,4 +60,4 @@ export const slopedRect = async (parent: SVGAElement, node: Node) => {
};
return shapeSvg;
};
}

View File

@ -1,7 +1,8 @@
import type { Node, RectOptions } from '../../types.js';
import type { D3Selection } from '../../../types.js';
import { drawRect } from './drawRect.js';
export const squareRect = async (parent: SVGAElement, node: Node) => {
export async function squareRect<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const options = {
rx: 0,
ry: 0,
@ -10,4 +11,4 @@ export const squareRect = async (parent: SVGAElement, node: Node) => {
labelPaddingY: (node?.padding || 0) * 1,
} as RectOptions;
return drawRect(parent, node, options);
};
}

View File

@ -4,6 +4,8 @@ import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import { createRoundedRectPathD } from './roundedRectPath.js';
import type { D3Selection } from '../../../types.js';
import { handleUndefinedAttr } from '../../../utils.js';
export const createStadiumPathD = (
x: number,
@ -50,7 +52,7 @@ export const createStadiumPathD = (
].join(' ');
};
export const stadium = async (parent: SVGAElement, node: Node) => {
export async function stadium<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node));
@ -61,6 +63,7 @@ export const stadium = async (parent: SVGAElement, node: Node) => {
let rect;
const { cssStyles } = node;
if (node.look === 'handDrawn') {
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
@ -68,7 +71,7 @@ export const stadium = async (parent: SVGAElement, node: Node) => {
const roughNode = rc.path(pathData, options);
rect = shapeSvg.insert(() => roughNode, ':first-child');
rect.attr('class', 'basic label-container').attr('style', cssStyles);
rect.attr('class', 'basic label-container').attr('style', handleUndefinedAttr(cssStyles));
} else {
rect = shapeSvg.insert('rect', ':first-child');
@ -90,4 +93,4 @@ export const stadium = async (parent: SVGAElement, node: Node) => {
};
return shapeSvg;
};
}

View File

@ -1,11 +1,12 @@
import type { Node, RectOptions } from '../../types.js';
import type { D3Selection } from '../../../types.js';
import { drawRect } from './drawRect.js';
export const state = async (parent: SVGAElement, node: Node) => {
export async function state<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const options = {
rx: 5,
ry: 5,
classes: 'flowchart-node',
} as RectOptions;
return drawRect(parent, node, options);
};
}

View File

@ -1,15 +1,15 @@
import rough from 'roughjs';
import type { SVG } from '../../../diagram-api/types.js';
import type { Node, ShapeRenderOptions } from '../../types.js';
import intersect from '../intersect/index.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import { updateNodeBounds } from './util.js';
import type { D3Selection } from '../../../types.js';
export const stateEnd = (
parent: SVG,
export function stateEnd<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node,
{ config: { themeVariables } }: ShapeRenderOptions
) => {
) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { cssStyles } = node;
@ -59,4 +59,4 @@ export const stateEnd = (
};
return shapeSvg;
};
}

View File

@ -1,15 +1,15 @@
import rough from 'roughjs';
import type { SVG } from '../../../diagram-api/types.js';
import type { Node, ShapeRenderOptions } from '../../types.js';
import intersect from '../intersect/index.js';
import { solidStateFill } from './handDrawnShapeStyles.js';
import { updateNodeBounds } from './util.js';
import type { D3Selection } from '../../../types.js';
export const stateStart = (
parent: SVG,
export function stateStart<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node,
{ config: { themeVariables } }: ShapeRenderOptions
) => {
) {
const { lineColor } = themeVariables;
const shapeSvg = parent
@ -17,20 +17,20 @@ export const stateStart = (
.attr('class', 'node default')
.attr('id', node.domId || node.id);
let circle;
let circle: D3Selection<SVGCircleElement> | D3Selection<SVGGElement>;
if (node.look === 'handDrawn') {
// @ts-ignore TODO: Fix rough typings
const rc = rough.svg(shapeSvg);
const roughNode = rc.circle(0, 0, 14, solidStateFill(lineColor));
circle = shapeSvg.insert(() => roughNode);
// center the circle around its coordinate
circle.attr('class', 'state-start').attr('r', 7).attr('width', 14).attr('height', 14);
} else {
circle = shapeSvg.insert('circle', ':first-child');
// center the circle around its coordinate
circle.attr('class', 'state-start').attr('r', 7).attr('width', 14).attr('height', 14);
}
// center the circle around its coordinate
// @ts-ignore TODO: Fix typings
circle.attr('class', 'state-start').attr('r', 7).attr('width', 14).attr('height', 14);
updateNodeBounds(node, circle);
node.intersect = function (point) {
@ -38,4 +38,4 @@ export const stateStart = (
};
return shapeSvg;
};
}

View File

@ -4,6 +4,8 @@ import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import { insertPolygonShape } from './insertPolygonShape.js';
import type { D3Selection } from '../../../types.js';
import { handleUndefinedAttr } from '../../../utils.js';
export const createSubroutinePathD = (
x: number,
@ -31,7 +33,7 @@ export const createSubroutinePathD = (
].join(' ');
};
export const subroutine = async (parent: SVGAElement, node: Node) => {
export async function subroutine<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node));
@ -55,6 +57,7 @@ export const subroutine = async (parent: SVGAElement, node: Node) => {
];
if (node.look === 'handDrawn') {
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
@ -66,7 +69,7 @@ export const subroutine = async (parent: SVGAElement, node: Node) => {
shapeSvg.insert(() => l2, ':first-child');
const rect = shapeSvg.insert(() => roughNode, ':first-child');
const { cssStyles } = node;
rect.attr('class', 'basic label-container').attr('style', cssStyles);
rect.attr('class', 'basic label-container').attr('style', handleUndefinedAttr(cssStyles));
updateNodeBounds(node, rect);
} else {
const el = insertPolygonShape(shapeSvg, w, h, points);
@ -81,4 +84,4 @@ export const subroutine = async (parent: SVGAElement, node: Node) => {
};
return shapeSvg;
};
}

View File

@ -1,10 +1,11 @@
import { labelHelper, getNodeClasses, updateNodeBounds, createPathFromPoints } from './util.js';
import type { Node } from '../../types.ts';
import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import intersect from '../intersect/index.js';
import type { D3Selection } from '../../../types.js';
export const taggedRect = async (parent: SVGAElement, node: Node) => {
export async function taggedRect<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node));
@ -16,6 +17,7 @@ export const taggedRect = async (parent: SVGAElement, node: Node) => {
const tagHeight = 0.2 * h;
const { cssStyles } = node;
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
@ -65,4 +67,4 @@ export const taggedRect = async (parent: SVGAElement, node: Node) => {
};
return shapeSvg;
};
}

View File

@ -6,11 +6,15 @@ import {
createPathFromPoints,
} from './util.js';
import intersect from '../intersect/index.js';
import type { Node } from '../../types.ts';
import type { Node } from '../../types.js';
import rough from 'roughjs';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import type { D3Selection } from '../../../types.js';
export const taggedWaveEdgedRectangle = async (parent: SVGAElement, node: Node) => {
export async function taggedWaveEdgedRectangle<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node
) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox, label } = await labelHelper(parent, node, getNodeClasses(node));
@ -22,6 +26,7 @@ export const taggedWaveEdgedRectangle = async (parent: SVGAElement, node: Node)
const finalH = h + waveAmplitude;
const { cssStyles } = node;
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
@ -97,4 +102,4 @@ export const taggedWaveEdgedRectangle = async (parent: SVGAElement, node: Node)
};
return shapeSvg;
};
}

View File

@ -1,9 +1,10 @@
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
import intersect from '../intersect/index.js';
import type { Node } from '../../types.ts';
import type { Node } from '../../types.js';
import { styles2String } from './handDrawnShapeStyles.js';
import type { D3Selection } from '../../../types.js';
export async function text(parent: SVGAElement, node: Node): Promise<SVGAElement> {
export async function text<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;

View File

@ -1,8 +1,10 @@
import { labelHelper, getNodeClasses, updateNodeBounds } from './util.js';
import type { Node } from '../../types.ts';
import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import intersect from '../intersect/index.js';
import type { D3Selection } from '../../../types.js';
import { handleUndefinedAttr } from '../../../utils.js';
export const createCylinderPathD = (
x: number,
@ -49,7 +51,10 @@ export const createInnerCylinderPathD = (
return [`M${x + width / 2},${-height / 2}`, `a${rx},${ry} 0,0,0 0,${height}`].join(' ');
};
export const tiltedCylinder = async (parent: SVGAElement, node: Node) => {
export async function tiltedCylinder<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node
) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox, label, halfPadding } = await labelHelper(
@ -64,9 +69,10 @@ export const tiltedCylinder = async (parent: SVGAElement, node: Node) => {
const w = bbox.width + rx + labelPadding;
const { cssStyles } = node;
let cylinder: d3.Selection<SVGPathElement | SVGGElement, unknown, null, undefined>;
let cylinder: D3Selection<SVGGElement> | D3Selection<SVGPathElement>;
if (node.look === 'handDrawn') {
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const outerPathData = createOuterCylinderPathD(0, 0, w, h, rx, ry);
const innerPathData = createInnerCylinderPathD(0, 0, w, h, rx, ry);
@ -84,19 +90,19 @@ export const tiltedCylinder = async (parent: SVGAElement, node: Node) => {
.insert('path', ':first-child')
.attr('d', pathData)
.attr('class', 'basic label-container')
.attr('style', cssStyles)
.attr('style', handleUndefinedAttr(cssStyles))
.attr('style', nodeStyles);
cylinder.attr('class', 'basic label-container');
if (cssStyles) {
cylinder.selectAll('path').attr('style', cssStyles);
}
if (nodeStyles) {
cylinder.selectAll('path').attr('style', nodeStyles);
}
}
cylinder.attr('class', 'basic label-container');
if (cssStyles && node.look !== 'handDrawn') {
cylinder.selectAll('path').attr('style', cssStyles);
}
if (nodeStyles && node.look !== 'handDrawn') {
cylinder.selectAll('path').attr('style', nodeStyles);
}
cylinder.attr('label-offset-x', rx);
cylinder.attr('transform', `translate(${-w / 2}, ${h / 2} )`);
@ -133,4 +139,4 @@ export const tiltedCylinder = async (parent: SVGAElement, node: Node) => {
};
return shapeSvg;
};
}

View File

@ -4,6 +4,7 @@ import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import { insertPolygonShape } from './insertPolygonShape.js';
import type { D3Selection } from '../../../types.js';
// export const createTrapezoidPathD = (
// x: number,
@ -20,7 +21,7 @@ import { insertPolygonShape } from './insertPolygonShape.js';
// ].join(' ');
// };
export const trapezoid = async (parent: SVGAElement, node: Node): Promise<SVGAElement> => {
export async function trapezoid<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node));
@ -34,10 +35,11 @@ export const trapezoid = async (parent: SVGAElement, node: Node): Promise<SVGAEl
{ x: 0, y: -h },
];
let polygon: d3.Selection<SVGPolygonElement | SVGGElement, unknown, null, undefined>;
let polygon: typeof shapeSvg | ReturnType<typeof insertPolygonShape>;
const { cssStyles } = node;
if (node.look === 'handDrawn') {
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
const pathData = createPathFromPoints(points);
@ -68,4 +70,4 @@ export const trapezoid = async (parent: SVGAElement, node: Node): Promise<SVGAEl
};
return shapeSvg;
};
}

View File

@ -1,10 +1,14 @@
import { labelHelper, updateNodeBounds, getNodeClasses, createPathFromPoints } from './util.js';
import intersect from '../intersect/index.js';
import type { Node } from '../../types.ts';
import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
export const trapezoidalPentagon = async (parent: SVGAElement, node: Node) => {
export async function trapezoidalPentagon<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node
) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node));
@ -14,6 +18,7 @@ export const trapezoidalPentagon = async (parent: SVGAElement, node: Node) => {
const h = Math.max(minHeight, bbox.height + (node.padding ?? 0) * 2, node?.height ?? 0);
const { cssStyles } = node;
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
@ -53,4 +58,4 @@ export const trapezoidalPentagon = async (parent: SVGAElement, node: Node) => {
};
return shapeSvg;
};
}

View File

@ -1,14 +1,15 @@
import { log } from '../../../logger.js';
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
import intersect from '../intersect/index.js';
import type { Node } from '../../types.ts';
import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import { createPathFromPoints } from './util.js';
import { evaluate } from '../../../diagrams/common/common.js';
import { getConfig } from '../../../diagram-api/diagramAPI.js';
import type { D3Selection } from '../../../types.js';
export const triangle = async (parent: SVGAElement, node: Node): Promise<SVGAElement> => {
export async function triangle<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox, label } = await labelHelper(parent, node, getNodeClasses(node));
@ -26,6 +27,7 @@ export const triangle = async (parent: SVGAElement, node: Node): Promise<SVGAEle
const { cssStyles } = node;
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
if (node.look !== 'handDrawn') {
@ -63,4 +65,4 @@ export const triangle = async (parent: SVGAElement, node: Node): Promise<SVGAEle
};
return shapeSvg;
};
}

View File

@ -6,11 +6,15 @@ import {
createPathFromPoints,
} from './util.js';
import intersect from '../intersect/index.js';
import type { Node } from '../../types.ts';
import type { Node } from '../../types.js';
import rough from 'roughjs';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import type { D3Selection } from '../../../types.js';
export const waveEdgedRectangle = async (parent: SVGAElement, node: Node) => {
export async function waveEdgedRectangle<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node
) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox, label } = await labelHelper(parent, node, getNodeClasses(node));
@ -25,6 +29,7 @@ export const waveEdgedRectangle = async (parent: SVGAElement, node: Node) => {
const widthDif = minWidth - w;
const extraW = widthDif > 0 ? widthDif / 2 : 0;
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
@ -75,4 +80,4 @@ export const waveEdgedRectangle = async (parent: SVGAElement, node: Node) => {
};
return shapeSvg;
};
}

View File

@ -6,11 +6,15 @@ import {
generateFullSineWavePoints,
} from './util.js';
import intersect from '../intersect/index.js';
import type { Node } from '../../types.ts';
import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
export const waveRectangle = async (parent: SVGAElement, node: Node) => {
export async function waveRectangle<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node
) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node));
@ -39,6 +43,7 @@ export const waveRectangle = async (parent: SVGAElement, node: Node) => {
const finalH = h + waveAmplitude * 2;
const { cssStyles } = node;
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
@ -76,4 +81,4 @@ export const waveRectangle = async (parent: SVGAElement, node: Node) => {
};
return shapeSvg;
};
}

View File

@ -1,10 +1,11 @@
import { labelHelper, getNodeClasses, updateNodeBounds } from './util.js';
import type { Node } from '../../types.ts';
import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import intersect from '../intersect/index.js';
import type { D3Selection } from '../../../types.js';
export const windowPane = async (parent: SVGAElement, node: Node) => {
export async function windowPane<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox, label } = await labelHelper(parent, node, getNodeClasses(node));
@ -15,6 +16,7 @@ export const windowPane = async (parent: SVGAElement, node: Node) => {
const y = -h / 2;
const { cssStyles } = node;
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
@ -62,4 +64,4 @@ export const windowPane = async (parent: SVGAElement, node: Node) => {
};
return shapeSvg;
};
}

View File

@ -69,6 +69,11 @@ export interface ParseResult {
// This makes it clear that we're working with a d3 selected element of some kind, even though it's hard to specify the exact type.
export type D3Element = any;
/**
* Helper type for d3 selections.
*/
export type D3Selection<T extends SVGElement> = d3.Selection<T, unknown, Element | null, unknown>;
export interface RenderResult {
/**
* The svg code for the rendered graph.

View File

@ -1,5 +1,5 @@
import { sanitizeUrl } from '@braintree/sanitize-url';
import type { CurveFactory } from 'd3';
import type { BaseType, CurveFactory } from 'd3';
import {
curveBasis,
curveBasisClosed,
@ -940,3 +940,15 @@ export const getEdgeId = (
) => {
return `${prefix ? `${prefix}_` : ''}${from}_${to}_${counter}${suffix ? `_${suffix}` : ''}`;
};
/**
* D3's `selection.attr` method doesn't officially support `undefined`.
*
* However, it seems if you do pass `undefined`, it seems to be treated as `null`
* (e.g. it removes the attribute).
*/
export function handleUndefinedAttr(
attrValue: Parameters<d3.Selection<BaseType, unknown, HTMLElement, any>['attr']>[1] | undefined
) {
return attrValue ?? null;
}