From 87e227da7c58448b18be801def3180ac150402b6 Mon Sep 17 00:00:00 2001 From: Kbowers <92726146+kbowers-ibm@users.noreply.github.com> Date: Wed, 16 Oct 2024 15:27:59 +0200 Subject: [PATCH] NO-ISSUE: Adding new SVGS to the BPMN editor (#132) * NO-ISSUE: Adding new SVGs to the new BPMN Editor * fixing fill changes --- .../src/diagram/nodes/NodeIcons.tsx | 8 +- .../src/diagram/nodes/NodeSvgs.tsx | 623 ++++++++++++++---- .../morphing/useEventNodeMorphingActions.tsx | 22 +- 3 files changed, 522 insertions(+), 131 deletions(-) diff --git a/packages/bpmn-editor/src/diagram/nodes/NodeIcons.tsx b/packages/bpmn-editor/src/diagram/nodes/NodeIcons.tsx index db6772074bc..d32bf47c998 100644 --- a/packages/bpmn-editor/src/diagram/nodes/NodeIcons.tsx +++ b/packages/bpmn-editor/src/diagram/nodes/NodeIcons.tsx @@ -52,11 +52,11 @@ export function NodeIcon({ nodeType }: { nodeType: BpmnNodeType }) { export function EventDefitnitionIcon({ variant, - fill, + filled, stroke, }: { variant?: EventVariant; - fill: boolean; + filled: boolean; stroke: string; }) { const cx = nodeSvgProps.x + nodeSvgProps.width / 2; @@ -69,14 +69,14 @@ export function EventDefitnitionIcon({ ); diff --git a/packages/bpmn-editor/src/diagram/nodes/NodeSvgs.tsx b/packages/bpmn-editor/src/diagram/nodes/NodeSvgs.tsx index ef94d23379f..253d9735a81 100644 --- a/packages/bpmn-editor/src/diagram/nodes/NodeSvgs.tsx +++ b/packages/bpmn-editor/src/diagram/nodes/NodeSvgs.tsx @@ -159,14 +159,15 @@ export function StartEventNodeSvg(__props: NodeSvgProps & { variant: EventVarian /> ); @@ -185,8 +186,8 @@ export function IntermediateCatchEventNodeSvg( const { rimWidth, variant, ...props } = { ..._props }; - const outerCirculeRadius = width / 2; - const innerCircleRadius = outerCirculeRadius - (rimWidth ?? 5); + const outerCircleRadius = width / 2; + const innerCircleRadius = outerCircleRadius - (rimWidth ?? 5); const cx = x + width / 2; const cy = y + height / 2; @@ -202,7 +203,7 @@ export function IntermediateCatchEventNodeSvg( fill={NODE_COLORS.intermediateCatchEvent.background} stroke={NODE_COLORS.intermediateCatchEvent.foreground} strokeLinejoin={"round"} - r={outerCirculeRadius} + r={outerCircleRadius} {...props} /> ); @@ -245,8 +247,8 @@ export function IntermediateThrowEventNodeSvg( const { rimWidth, variant, ...props } = { ..._props }; - const outerCirculeRadius = width / 2; - const innerCircleRadius = outerCirculeRadius - (rimWidth ?? 5); + const outerCircleRadius = width / 2; + const innerCircleRadius = outerCircleRadius - (rimWidth ?? 5); const cx = x + width / 2; const cy = y + height / 2; @@ -262,7 +264,7 @@ export function IntermediateThrowEventNodeSvg( fill={NODE_COLORS.intermediateThrowEvent.background} stroke={NODE_COLORS.intermediateThrowEvent.foreground} strokeLinejoin={"round"} - r={outerCirculeRadius} + r={outerCircleRadius} {...props} /> ); @@ -324,14 +327,15 @@ export function EndEventNodeSvg(__props: NodeSvgProps & { variant: EventVariant /> ); @@ -749,8 +753,9 @@ export function EventVariantSymbolSvg({ x, y, innerCircleRadius, - outerCirculeRadius, + outerCircleRadius, fill, + filled, }: { variant: EventVariant | "none"; stroke: string; @@ -760,118 +765,81 @@ export function EventVariantSymbolSvg({ x: number; y: number; innerCircleRadius: number; - outerCirculeRadius: number; - fill: boolean; + outerCircleRadius: number; + fill?: string; + filled: boolean; }) { return ( <> - {/* FIXME: Tiago: tmp icon */} {variant === "messageEventDefinition" && ( - <> - - ✉️ - - + )} - {/* FIXME: Tiago: tmp icon */} {variant === "timerEventDefinition" && ( - <> - - 🕑 - - + )} - {/* FIXME: Tiago: tmp icon */} {variant === "errorEventDefinition" && ( - <> - - ⚡️ - - + )} - {/* FIXME: Tiago: tmp icon */} {variant === "escalationEventDefinition" && ( - <> - - ☝️ - - + )} - {/* FIXME: Tiago: tmp icon */} {variant === "cancelEventDefinition" && ( - <> - - ❌ - - + )} - {/* FIXME: Tiago: tmp icon */} {variant === "compensateEventDefinition" && ( - <> - - ⏪ - - + )} - {/* FIXME: Tiago: tmp icon */} {variant === "conditionalEventDefinition" && ( - <> - - ≣ - - + )} - {/* FIXME: Tiago: tmp icon */} {variant === "linkEventDefinition" && ( - <> - - ⇨ - - + )} {variant === "signalEventDefinition" && ( )} @@ -892,7 +860,7 @@ export function EventVariantSymbolSvg({ fill={NODE_COLORS.endEvent.foreground} stroke={NODE_COLORS.endEvent.foreground} strokeLinejoin={"round"} - r={outerCirculeRadius / 2} + r={outerCircleRadius / 2} /> )} @@ -902,6 +870,429 @@ export function EventVariantSymbolSvg({ ); } +export function MessageEventSymbolSvg({ + stroke, + cx, + cy, + innerCircleRadius, + fill, + filled, +}: { + stroke: string; + cx: number; + cy: number; + innerCircleRadius: number; + fill: string; + filled: boolean; +}) { + const bodyWidth = innerCircleRadius * 1.2; + const bodyHeight = innerCircleRadius * 0.8; + + const envelopeBody = { + topLeft: { x: cx - bodyWidth / 2, y: cy - bodyHeight / 2 }, + bottomRight: { x: cx + bodyWidth / 2, y: cy + bodyHeight / 2 }, + }; + + const flapHeight = bodyHeight * 0.5; + const envelopeFlap = [ + { x: envelopeBody.topLeft.x, y: envelopeBody.topLeft.y }, + { x: envelopeBody.bottomRight.x, y: envelopeBody.topLeft.y }, + { x: cx, y: envelopeBody.topLeft.y + flapHeight }, + ]; + + return ( + <> + + + `${point.x},${point.y}`).join(" ")} + strokeWidth={1.5} + strokeLinejoin={"round"} + fill={filled ? stroke : fill} + stroke={stroke} + /> + + {filled && ( + <> + + + + )} + + ); +} + +export function TimerEventSymbolSvg({ + stroke, + cx, + cy, + innerCircleRadius, + outerCircleRadius, + filled, +}: { + stroke: string; + cx: number; + cy: number; + innerCircleRadius: number; + outerCircleRadius: number; + filled: boolean; +}) { + const padding = 1.2 * (outerCircleRadius - innerCircleRadius); + const clockRadius = innerCircleRadius - padding; + + const shortHandLength = clockRadius * 0.5; + const longHandLength = clockRadius * 0.9; + + const hourHandAngle = Math.PI / 12; + const minuteHandAngle = (-5 * Math.PI) / 12; + + const hourHand = { + x: cx + shortHandLength * Math.cos(hourHandAngle), + y: cy + shortHandLength * Math.sin(hourHandAngle), + }; + + const minuteHand = { + x: cx + longHandLength * Math.cos(minuteHandAngle), + y: cy + longHandLength * Math.sin(minuteHandAngle), + }; + + return ( + <> + + + + + + + {Array.from({ length: 12 }, (_, index) => { + const angle = (index / 12) * 2 * Math.PI; + const x1 = cx + clockRadius * Math.cos(angle); + const y1 = cy + clockRadius * Math.sin(angle); + const x2 = cx + (clockRadius - padding * 0.5) * Math.cos(angle); + const y2 = cy + (clockRadius - padding * 0.5) * Math.sin(angle); + + return ; + })} + + ); +} + +export function ErrorEventSymbolSvg({ + stroke, + cx, + cy, + innerCircleRadius, + outerCircleRadius, + filled, +}: { + stroke: string; + cx: number; + cy: number; + innerCircleRadius: number; + outerCircleRadius: number; + filled: boolean; +}) { + const padding = 1.5 * (outerCircleRadius - innerCircleRadius); + const hx = innerCircleRadius - padding; + const hy = innerCircleRadius - padding; + + const scaleFactor = 20; + const shiftLeft = 3.5; + const shiftUp = 1; + + const points = [ + { x: cx - shiftLeft, y: cy }, + { x: cx - hx * 0.037 * scaleFactor - shiftLeft, y: cy + hy * 0.052 * scaleFactor - shiftUp }, + { x: cx - hx * 0.003 * scaleFactor - shiftLeft, y: cy - hy * 0.05 * scaleFactor - shiftUp }, + { x: cx + hx * 0.027 * scaleFactor - shiftLeft, y: cy + hy * 0.016 * scaleFactor - shiftUp }, + { x: cx + hx * 0.058 * scaleFactor - shiftLeft, y: cy - hy * 0.046 * scaleFactor - shiftUp }, + { x: cx + hx * 0.029 * scaleFactor - shiftLeft, y: cy + hy * 0.066 * scaleFactor - shiftUp }, + { x: cx - shiftLeft, y: cy }, + ]; + + return ( + <> + `${point.x},${point.y}`).join(" ")} + strokeWidth={1.5} + strokeLinejoin={"round"} + fill={filled ? stroke : "transparent"} + stroke={stroke} + /> + + ); +} + +export function EscalationEventSymbolSvg({ + stroke, + cx, + cy, + innerCircleRadius, + filled, +}: { + stroke: string; + cx: number; + cy: number; + innerCircleRadius: number; + filled: boolean; +}) { + const arrowHeight = innerCircleRadius * 1.2; + const arrowBaseWidth = innerCircleRadius * 1; + + const arrow = [ + { x: cx - arrowBaseWidth / 2, y: cy + arrowHeight / 2 }, // left + { x: cx, y: cy - arrowHeight / 2 }, // top center + { x: cx + arrowBaseWidth / 2, y: cy + arrowHeight / 2 }, // right + { x: cx, y: cy + arrowHeight / 20 }, // mid center + ] as const; + + return ( + <> + `${point.x},${point.y}`).join(" ")} + strokeWidth={1.5} + strokeLinejoin={"round"} + fill={filled ? stroke : "transparent"} + stroke={stroke} + /> + + ); +} + +export function CancelEventSymbolSvg({ + stroke, + cx, + cy, + innerCircleRadius, + filled, +}: { + stroke: string; + cx: number; + cy: number; + innerCircleRadius: number; + filled: boolean; +}) { + const farXPoint = 1.3; + const closeXPoint = 1.7; + const lowYPoint = 9; + const highYPoint = 5; + + const cross = [ + { x: cx - innerCircleRadius / farXPoint, y: cy - innerCircleRadius + lowYPoint }, // upper left point 1 + { x: cx - innerCircleRadius / closeXPoint, y: cy - innerCircleRadius + highYPoint }, // upper left point 2 + { x: cx, y: cy - innerCircleRadius / highYPoint }, // upper joiner + { x: cx + innerCircleRadius / closeXPoint, y: cy - innerCircleRadius + highYPoint }, // upper right point 2 + { x: cx + innerCircleRadius / farXPoint, y: cy - innerCircleRadius + lowYPoint }, // upper right point 1 + { x: cx + innerCircleRadius / highYPoint, y: cy }, // right joiner + { x: cx + innerCircleRadius / farXPoint, y: cy + innerCircleRadius - lowYPoint }, // lower right point 2 + { x: cx + innerCircleRadius / closeXPoint, y: cy + innerCircleRadius - highYPoint }, // lower right point 1 + { x: cx, y: cy + innerCircleRadius / highYPoint }, // lower joiner + { x: cx - innerCircleRadius / closeXPoint, y: cy + innerCircleRadius - highYPoint }, // lower left point 1 + { x: cx - innerCircleRadius / farXPoint, y: cy + innerCircleRadius - lowYPoint }, // lower left point 2 + { x: cx - innerCircleRadius / highYPoint, y: cy }, // left joiner + ] as const; + + return ( + <> + `${point.x},${point.y}`).join(" ")} + strokeWidth={1.5} + strokeLinejoin={"round"} + fill={filled ? stroke : "transparent"} + stroke={stroke} + /> + + ); +} + +export function CompensationEventSymbolSvg({ + stroke, + cx, + cy, + x, + y, + innerCircleRadius, + outerCircleRadius, + filled, +}: { + stroke: string; + cx: number; + cy: number; + x: number; + y: number; + innerCircleRadius: number; + outerCircleRadius: number; + filled: boolean; +}) { + const padding = 1.5 * (outerCircleRadius - innerCircleRadius); + + const hx = x + innerCircleRadius - padding * 0.6; + const hy = y + innerCircleRadius - padding * 0.2; + + const rightOffset = 0.15 * innerCircleRadius; + + const firstTriangle = [ + { x: cx + hx - rightOffset, y: cy - hy + (outerCircleRadius - innerCircleRadius) }, + { x: cx - rightOffset, y: cy }, + { x: cx + hx - rightOffset, y: cy + hy - (outerCircleRadius - innerCircleRadius) }, + ] as const; + + const secondTriangle = [ + { x: cx - rightOffset, y: cy - hy + (outerCircleRadius - innerCircleRadius) }, + { x: cx - hx - rightOffset, y: cy }, + { x: cx - rightOffset, y: cy + hy - (outerCircleRadius - innerCircleRadius) }, + ] as const; + + return ( + <> + `${point.x},${point.y}`).join(" ")} + strokeWidth={1.5} + strokeLinejoin={"round"} + fill={filled ? stroke : "transparent"} + stroke={stroke} + /> + `${point.x},${point.y}`).join(" ")} + strokeWidth={1.5} + strokeLinejoin={"round"} + fill={filled ? stroke : "transparent"} + stroke={stroke} + /> + + ); +} + +export function ConditionalEventSymbolSvg({ + stroke, + cx, + cy, + outerCircleRadius, + filled, +}: { + stroke: string; + cx: number; + cy: number; + outerCircleRadius: number; + filled: boolean; +}) { + const squareSize = outerCircleRadius * 1.1; + const lineSpacing = squareSize / 5; + const lineThickness = 2; + + return ( + <> + + + {[...Array(4)].map((_, index) => ( + + ))} + + ); +} + +export function LinkEventSymbolSvg({ + stroke, + cx, + cy, + innerCircleRadius, + filled, +}: { + stroke: string; + cx: number; + cy: number; + innerCircleRadius: number; + filled: boolean; +}) { + const arrowHeight = innerCircleRadius * 1.2; + const arrowBaseWidth = innerCircleRadius * 1; + const shiftLeft = 7; + const rectangleHeight = 5; + const arrowPadding = 2; + + const arrow = [ + { x: cx - arrowBaseWidth / 2 - shiftLeft, y: cy + arrowHeight / 2 - rectangleHeight }, // bottom left rectangle + { x: cx - arrowBaseWidth / 2 - shiftLeft, y: cy - arrowHeight / 2 + rectangleHeight }, // top left rectangle + { x: cx + arrowBaseWidth / 2, y: cy - arrowHeight / 2 + rectangleHeight }, // top right rectangle + { x: cx + arrowBaseWidth / 2, y: cy - arrowHeight / 2 - arrowPadding }, // upper arrow start + { x: cx + arrowBaseWidth / 2 + 8, y: cy }, // arrow point + { x: cx + arrowBaseWidth / 2, y: cy + arrowHeight / 2 + arrowPadding }, // lower arrow start + { x: cx + arrowBaseWidth / 2, y: cy + arrowHeight / 2 - rectangleHeight }, // bottom right rectangle + ] as const; + + return ( + <> + `${point.x},${point.y}`).join(" ")} + strokeWidth={1.5} + strokeLinejoin={"round"} + fill={filled ? stroke : "transparent"} + stroke={stroke} + /> + + ); +} + export function SignalEventSymbolSvg({ stroke, strokeWidth, @@ -910,8 +1301,8 @@ export function SignalEventSymbolSvg({ x, y, innerCircleRadius, - outerCirculeRadius, - fill, + outerCircleRadius, + filled, }: { stroke: string; strokeWidth?: number; @@ -920,10 +1311,10 @@ export function SignalEventSymbolSvg({ x: number; y: number; innerCircleRadius: number; - outerCirculeRadius: number; - fill: boolean; + outerCircleRadius: number; + filled: boolean; }) { - const padding = 1.5 * (outerCirculeRadius - innerCircleRadius); + const padding = 1.5 * (outerCircleRadius - innerCircleRadius); const hx = x + innerCircleRadius - padding; const hy = y + innerCircleRadius - padding; const triangle = [ @@ -935,10 +1326,10 @@ export function SignalEventSymbolSvg({ return ( <> `${point.x},${point.y}`).join(" ")} + strokeWidth={strokeWidth ?? 1.5} strokeLinejoin={"round"} - fill={fill ? stroke : "transparent"} + fill={filled ? stroke : "transparent"} stroke={stroke} /> diff --git a/packages/bpmn-editor/src/diagram/nodes/morphing/useEventNodeMorphingActions.tsx b/packages/bpmn-editor/src/diagram/nodes/morphing/useEventNodeMorphingActions.tsx index c3f35494286..bf5ba008eb6 100644 --- a/packages/bpmn-editor/src/diagram/nodes/morphing/useEventNodeMorphingActions.tsx +++ b/packages/bpmn-editor/src/diagram/nodes/morphing/useEventNodeMorphingActions.tsx @@ -41,7 +41,7 @@ export function useEventNodeMorphingActions(event: Event) { const bpmnEditorStoreApi = useBpmnEditorStoreApi(); const foregroundColor = NODE_COLORS[event.__$$element].foreground; - const fill = event.__$$element === "intermediateThrowEvent" || event.__$$element === "endEvent"; + const filled = event.__$$element === "intermediateThrowEvent" || event.__$$element === "endEvent"; const morphEvent = useCallback( (eventDefinitionElement: undefined | Unpacked["__$$element"]) => { @@ -165,63 +165,63 @@ export function useEventNodeMorphingActions(event: Event) { action: () => morphEvent(undefined), } as const, // none { - icon: , + icon: , key: "2", title: "Message", id: "messageEventDefinition", action: () => morphEvent("messageEventDefinition"), } as const, { - icon: , + icon: , key: "3", title: "Timer", id: "timerEventDefinition", action: () => morphEvent("timerEventDefinition"), } as const, { - icon: , + icon: , key: "4", title: "Error", id: "errorEventDefinition", action: () => morphEvent("errorEventDefinition"), } as const, { - icon: , + icon: , key: "5", title: "Escalation", id: "escalationEventDefinition", action: () => morphEvent("escalationEventDefinition"), } as const, { - icon: , + icon: , key: "6", title: "Cancelation", id: "cancelEventDefinition", action: () => morphEvent("cancelEventDefinition"), } as const, { - icon: , + icon: , key: "7", title: "Compensation", id: "compensateEventDefinition", action: () => morphEvent("compensateEventDefinition"), } as const, { - icon: , + icon: , key: "8", title: "Conditional", id: "conditionalEventDefinition", action: () => morphEvent("conditionalEventDefinition"), } as const, { - icon: , + icon: , key: "9", title: "Link", id: "linkEventDefinition", action: () => morphEvent("linkEventDefinition"), } as const, { - icon: , + icon: , key: "0", title: "Signal", id: "signalEventDefinition", @@ -235,7 +235,7 @@ export function useEventNodeMorphingActions(event: Event) { action: () => morphEvent("terminateEventDefinition"), } as const, ]; - }, [event.__$$element, foregroundColor, fill, morphEvent]); + }, [event.__$$element, foregroundColor, filled, morphEvent]); return morphingActions; }