mirror of
https://gitee.com/ByteDance/flowgram.ai.git
synced 2025-07-07 17:43:29 +08:00
feat(demo): workflow running style support
This commit is contained in:
parent
e2e80efb7a
commit
e8c60a8443
@ -8,6 +8,7 @@ import { ZoomSelect } from './zoom-select';
|
||||
import { SwitchVertical } from './switch-vertical';
|
||||
import { ToolContainer, ToolSection } from './styles';
|
||||
import { Save } from './save';
|
||||
import { Run } from './run';
|
||||
import { Readonly } from './readonly';
|
||||
import { MinimapSwitch } from './minimap-switch';
|
||||
import { Minimap } from './minimap';
|
||||
@ -50,6 +51,7 @@ export const DemoTools = () => {
|
||||
/>
|
||||
</Tooltip>
|
||||
<Save disabled={playground.config.readonly} />
|
||||
<Run />
|
||||
</ToolSection>
|
||||
</ToolContainer>
|
||||
);
|
||||
|
||||
108
apps/demo-fixed-layout/src/components/tools/run.tsx
Normal file
108
apps/demo-fixed-layout/src/components/tools/run.tsx
Normal file
@ -0,0 +1,108 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
import {
|
||||
usePlayground,
|
||||
FlowNodeEntity,
|
||||
FixedLayoutPluginContext,
|
||||
useClientContext,
|
||||
delay,
|
||||
} from '@flowgram.ai/fixed-layout-editor';
|
||||
import { Button } from '@douyinfe/semi-ui';
|
||||
|
||||
const styleElement = document.createElement('style');
|
||||
const RUNNING_COLOR = 'rgb(78, 64, 229)';
|
||||
const RUNNING_INTERVAL = 1000;
|
||||
|
||||
function getRunningNodes(targetNode?: FlowNodeEntity | undefined, addChildren?: boolean): string[] {
|
||||
const result: string[] = [];
|
||||
if (targetNode) {
|
||||
result.push(targetNode.id);
|
||||
if (addChildren) {
|
||||
result.push(...targetNode.allChildren.map((n) => n.id));
|
||||
}
|
||||
if (targetNode.parent) {
|
||||
result.push(targetNode.parent.id);
|
||||
}
|
||||
if (targetNode.pre) {
|
||||
result.push(...getRunningNodes(targetNode.pre, true));
|
||||
}
|
||||
if (targetNode.parent) {
|
||||
if (targetNode.parent.pre) {
|
||||
result.push(...getRunningNodes(targetNode.parent.pre, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function clear() {
|
||||
styleElement.innerText = '';
|
||||
}
|
||||
|
||||
function runningNode(ctx: FixedLayoutPluginContext, nodeId: string) {
|
||||
const nodes = getRunningNodes(ctx.document.getNode(nodeId), true);
|
||||
if (nodes.length === 0) {
|
||||
styleElement.innerText = '';
|
||||
} else {
|
||||
const content = nodes
|
||||
.map(
|
||||
(n) => `
|
||||
path[data-line-id$="${n}"] {
|
||||
animation: flowingDash 0.5s linear infinite;
|
||||
stroke-dasharray: 8, 5;
|
||||
stroke: ${RUNNING_COLOR} !important;
|
||||
}
|
||||
marker[data-line-id$="${n}"] path {
|
||||
fill: ${RUNNING_COLOR} !important;
|
||||
}
|
||||
[data-node-id$="${n}"] {
|
||||
border: 1px dashed ${RUNNING_COLOR} !important;
|
||||
border-radius: 8px;
|
||||
}
|
||||
[data-label-id$="${n}"] {
|
||||
color: ${RUNNING_COLOR} !important;
|
||||
}
|
||||
`
|
||||
)
|
||||
.join('\n');
|
||||
styleElement.innerText = `
|
||||
@keyframes flowingDash {
|
||||
to {
|
||||
stroke-dashoffset: -13;
|
||||
}
|
||||
}
|
||||
${content}
|
||||
`;
|
||||
}
|
||||
if (!styleElement.parentNode) {
|
||||
document.body.appendChild(styleElement);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the simulation and highlight the lines
|
||||
*/
|
||||
export function Run() {
|
||||
const [isRunning, setRunning] = useState(false);
|
||||
const ctx = useClientContext();
|
||||
const playground = usePlayground();
|
||||
const onRun = async () => {
|
||||
setRunning(true);
|
||||
playground.config.readonly = true;
|
||||
const nodes = ctx.document.root.blocks.slice();
|
||||
while (nodes.length > 0) {
|
||||
const currentNode = nodes.shift();
|
||||
runningNode(ctx, currentNode!.id);
|
||||
await delay(RUNNING_INTERVAL);
|
||||
}
|
||||
|
||||
playground.config.readonly = false;
|
||||
clear();
|
||||
setRunning(false);
|
||||
};
|
||||
return (
|
||||
<Button onClick={onRun} loading={isRunning}>
|
||||
Run
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
@ -10,6 +10,7 @@ import { ZoomSelect } from './zoom-select';
|
||||
import { SwitchLine } from './switch-line';
|
||||
import { ToolContainer, ToolSection } from './styles';
|
||||
import { Save } from './save';
|
||||
import { Run } from './run';
|
||||
import { Readonly } from './readonly';
|
||||
import { MinimapSwitch } from './minimap-switch';
|
||||
import { Minimap } from './minimap';
|
||||
@ -71,6 +72,7 @@ export const DemoTools = () => {
|
||||
<AddNode disabled={playground.config.readonly} />
|
||||
<Divider layout="vertical" style={{ height: '16px' }} margin={3} />
|
||||
<Save disabled={playground.config.readonly} />
|
||||
<Run />
|
||||
</ToolSection>
|
||||
</ToolContainer>
|
||||
);
|
||||
|
||||
28
apps/demo-free-layout/src/components/tools/run.tsx
Normal file
28
apps/demo-free-layout/src/components/tools/run.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
import { useService } from '@flowgram.ai/free-layout-editor';
|
||||
import { Button } from '@douyinfe/semi-ui';
|
||||
|
||||
import { RunningService } from '../../services';
|
||||
|
||||
/**
|
||||
* Run the simulation and highlight the lines
|
||||
*/
|
||||
export function Run() {
|
||||
const [isRunning, setRunning] = useState(false);
|
||||
const runningService = useService(RunningService);
|
||||
const onRun = async () => {
|
||||
setRunning(true);
|
||||
await runningService.startRun();
|
||||
setRunning(false);
|
||||
};
|
||||
return (
|
||||
<Button
|
||||
onClick={onRun}
|
||||
loading={isRunning}
|
||||
style={{ backgroundColor: 'rgba(171,181,255,0.3)', borderRadius: '8px' }}
|
||||
>
|
||||
Run
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
@ -13,7 +13,7 @@ import { createContainerNodePlugin } from '@flowgram.ai/free-container-plugin';
|
||||
import { onDragLineEnd } from '../utils';
|
||||
import { FlowNodeRegistry, FlowDocumentJSON } from '../typings';
|
||||
import { shortcuts } from '../shortcuts';
|
||||
import { CustomService } from '../services';
|
||||
import { CustomService, RunningService } from '../services';
|
||||
import { createSyncVariablePlugin } from '../plugins';
|
||||
import { defaultFormMeta } from '../nodes/default-form-meta';
|
||||
import { WorkflowNodeType } from '../nodes';
|
||||
@ -135,6 +135,10 @@ export function useEditorProps(
|
||||
onContentChange: debounce((ctx, event) => {
|
||||
console.log('Auto Save: ', event, ctx.document.toJSON());
|
||||
}, 1000),
|
||||
/**
|
||||
* Running line
|
||||
*/
|
||||
isFlowingLine: (ctx, line) => ctx.get(RunningService).isFlowingLine(line),
|
||||
/**
|
||||
* Shortcuts
|
||||
*/
|
||||
@ -144,6 +148,7 @@ export function useEditorProps(
|
||||
*/
|
||||
onBind: ({ bind }) => {
|
||||
bind(CustomService).toSelf().inSingletonScope();
|
||||
bind(RunningService).toSelf().inSingletonScope();
|
||||
},
|
||||
/**
|
||||
* Playground init
|
||||
|
||||
@ -1 +1,2 @@
|
||||
export { CustomService } from './custom-service';
|
||||
export { RunningService } from './running-service';
|
||||
|
||||
47
apps/demo-free-layout/src/services/running-service.ts
Normal file
47
apps/demo-free-layout/src/services/running-service.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import {
|
||||
injectable,
|
||||
inject,
|
||||
WorkflowDocument,
|
||||
Playground,
|
||||
delay,
|
||||
WorkflowLineEntity,
|
||||
WorkflowNodeEntity,
|
||||
WorkflowNodeLinesData,
|
||||
} from '@flowgram.ai/free-layout-editor';
|
||||
const RUNNING_INTERVAL = 1000;
|
||||
|
||||
@injectable()
|
||||
export class RunningService {
|
||||
@inject(Playground) playground: Playground;
|
||||
|
||||
@inject(WorkflowDocument) document: WorkflowDocument;
|
||||
|
||||
private _runningNodes: WorkflowNodeEntity[] = [];
|
||||
|
||||
async addRunningNode(node: WorkflowNodeEntity): Promise<void> {
|
||||
this._runningNodes.push(node);
|
||||
node.renderData.node.classList.add('node-running');
|
||||
this.document.linesManager.forceUpdate(); // Refresh line renderer
|
||||
await delay(RUNNING_INTERVAL);
|
||||
// Child Nodes
|
||||
await Promise.all(node.blocks.map((nextNode) => this.addRunningNode(nextNode)));
|
||||
// Sibling Nodes
|
||||
const nextNodes = node.getData(WorkflowNodeLinesData).outputNodes;
|
||||
await Promise.all(nextNodes.map((nextNode) => this.addRunningNode(nextNode)));
|
||||
}
|
||||
|
||||
async startRun(): Promise<void> {
|
||||
await this.addRunningNode(this.document.getNode('start_0')!);
|
||||
this._runningNodes.forEach((node) => {
|
||||
node.renderData.node.classList.remove('node-running');
|
||||
});
|
||||
this._runningNodes = [];
|
||||
this.document.linesManager.forceUpdate();
|
||||
}
|
||||
|
||||
isFlowingLine(line: WorkflowLineEntity) {
|
||||
return this._runningNodes.some((node) =>
|
||||
node.getData(WorkflowNodeLinesData).outputLines.includes(line)
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -15,6 +15,16 @@
|
||||
background-color: var(--g-playground-selectBox-background);
|
||||
}
|
||||
|
||||
@keyframes blink {
|
||||
0% { opacity: 1; }
|
||||
50% { opacity: 0; }
|
||||
100% { opacity: 1; }
|
||||
}
|
||||
|
||||
.node-running {
|
||||
border: 1px dashed rgb(78, 64, 229) !important;
|
||||
border-radius: 8px;
|
||||
}
|
||||
.demo-editor {
|
||||
flex-grow: 1;
|
||||
position: relative;
|
||||
|
||||
@ -8,5 +8,5 @@ import { usePlaygroundContainer } from './use-playground-container';
|
||||
*/
|
||||
export function useService<T>(identifier: interfaces.ServiceIdentifier<T>): T {
|
||||
const container = usePlaygroundContainer();
|
||||
return container.get(identifier) as T;
|
||||
return container.get?.(identifier) as T;
|
||||
}
|
||||
|
||||
@ -32,6 +32,7 @@ export interface FlowTransitionLine {
|
||||
activated?: boolean; // 是否激活态
|
||||
side?: LABEL_SIDE_TYPE; // 区分是否分支前缀线条
|
||||
style?: React.CSSProperties;
|
||||
lineId?: string;
|
||||
}
|
||||
|
||||
// 内置几种标签
|
||||
@ -52,6 +53,7 @@ export interface FlowTransitionLabel {
|
||||
width?: number; // 宽度
|
||||
rotate?: string; // 循环, 如 '60deg'
|
||||
props?: Record<string, any>;
|
||||
labelId?: string;
|
||||
}
|
||||
|
||||
export interface AdderProps {
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
exports[`flow-label-layer > test render 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
data-label-id="start"
|
||||
style="position: absolute; left: 0px; top: 0px; transform: translate(-50%, -50%);"
|
||||
>
|
||||
<div
|
||||
@ -14,6 +15,7 @@ exports[`flow-label-layer > test render 1`] = `
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
data-label-id="mock"
|
||||
style="position: absolute; left: 0px; top: 0px; transform: translate(-50%, -50%);"
|
||||
>
|
||||
<div
|
||||
@ -21,9 +23,11 @@ exports[`flow-label-layer > test render 1`] = `
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
data-label-id="mock"
|
||||
style="position: absolute; left: 0px; top: 0px; transform: translate(-50%, -50%);"
|
||||
/>
|
||||
<div
|
||||
data-label-id="mock"
|
||||
style="position: absolute; left: 0px; top: 0px; transform: translate(-50%, -50%);"
|
||||
>
|
||||
<div
|
||||
@ -32,6 +36,7 @@ exports[`flow-label-layer > test render 1`] = `
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
data-label-id="mock"
|
||||
style="position: absolute; left: 0px; top: 0px; transform: translate(-50%, -50%);"
|
||||
>
|
||||
<div
|
||||
@ -48,6 +53,7 @@ exports[`flow-label-layer > test render 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
data-label-id="mock"
|
||||
style="position: absolute; left: 0px; top: 0px; transform: translate(-50%, -50%);"
|
||||
>
|
||||
<div
|
||||
@ -67,6 +73,7 @@ exports[`flow-label-layer > test render 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
data-label-id="mock"
|
||||
style="position: absolute; left: 0px; top: 0px; transform: translate(-50%, -50%);"
|
||||
>
|
||||
<div
|
||||
@ -86,27 +93,33 @@ exports[`flow-label-layer > test render 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
data-label-id="mock"
|
||||
style="position: absolute; left: 0px; top: 0px; transform: translate(-50%, -50%);"
|
||||
>
|
||||
<div
|
||||
data-label-id="mock"
|
||||
style="font-size: 12px; color: rgb(187, 191, 196); text-align: center; white-space: nowrap; line-height: 20px;"
|
||||
>
|
||||
123
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
data-label-id="mock"
|
||||
style="position: absolute; left: 0px; top: 0px; transform: translate(-50%, -50%);"
|
||||
>
|
||||
<div
|
||||
data-label-id="mock"
|
||||
style="font-size: 12px; color: rgb(187, 191, 196); text-align: center; white-space: nowrap; line-height: 20px; width: 100px; transform: rotate(90deg);"
|
||||
>
|
||||
catch-text
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
data-label-id="mock"
|
||||
style="position: absolute; left: 0px; top: 0px; transform: translate(-50%, -50%);"
|
||||
/>
|
||||
<div
|
||||
data-label-id="mock"
|
||||
style="position: absolute; left: 0px; top: 0px; transform: translate(-50%, -50%);"
|
||||
/>
|
||||
</DocumentFragment>
|
||||
|
||||
@ -23,7 +23,7 @@ function CustomLine(props: PropsType): JSX.Element {
|
||||
|
||||
const Component = renderer.renderer as (props: FlowTransitionLine) => JSX.Element;
|
||||
|
||||
return <Component {...line} />;
|
||||
return <Component lineId={props.lineId} {...line} />;
|
||||
}
|
||||
|
||||
export default CustomLine;
|
||||
|
||||
@ -59,19 +59,45 @@ export function createLabels(labelProps: LabelOpts): void {
|
||||
switch (type) {
|
||||
case FlowTransitionLabelEnum.BRANCH_DRAGGING_LABEL:
|
||||
child = (
|
||||
<BranchDraggableRenderer rendererRegistry={rendererRegistry} data={data} {...props} />
|
||||
<BranchDraggableRenderer
|
||||
labelId={label.labelId || labelProps.data.entity.id}
|
||||
rendererRegistry={rendererRegistry}
|
||||
data={data}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case FlowTransitionLabelEnum.ADDER_LABEL:
|
||||
child = <Adder rendererRegistry={rendererRegistry} data={data} {...props} />;
|
||||
child = (
|
||||
<Adder
|
||||
labelId={label.labelId || labelProps.data.entity.id}
|
||||
rendererRegistry={rendererRegistry}
|
||||
data={data}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
|
||||
case FlowTransitionLabelEnum.COLLAPSE_LABEL:
|
||||
child = <Collapse rendererRegistry={rendererRegistry} data={data} {...props} />;
|
||||
child = (
|
||||
<Collapse
|
||||
labelId={label.labelId || labelProps.data.entity.id}
|
||||
rendererRegistry={rendererRegistry}
|
||||
data={data}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
|
||||
case FlowTransitionLabelEnum.COLLAPSE_ADDER_LABEL:
|
||||
child = <CollapseAdder rendererRegistry={rendererRegistry} data={data} {...props} />;
|
||||
child = (
|
||||
<CollapseAdder
|
||||
labelId={label.labelId || labelProps.data.entity.id}
|
||||
rendererRegistry={rendererRegistry}
|
||||
data={data}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
|
||||
case FlowTransitionLabelEnum.TEXT_LABEL:
|
||||
@ -81,6 +107,7 @@ export function createLabels(labelProps: LabelOpts): void {
|
||||
const text = rendererRegistry.getText(renderKey) || renderKey;
|
||||
child = (
|
||||
<div
|
||||
data-label-id={label.labelId || labelProps.data.entity.id}
|
||||
style={{
|
||||
...TEXT_LABEL_STYLE,
|
||||
...props?.style,
|
||||
@ -103,6 +130,7 @@ export function createLabels(labelProps: LabelOpts): void {
|
||||
renderer.renderer as (props: any) => JSX.Element,
|
||||
{
|
||||
node: data.entity,
|
||||
labelId: label.labelId || labelProps.data.entity.id,
|
||||
...props,
|
||||
} as CustomLabelProps
|
||||
);
|
||||
@ -118,6 +146,7 @@ export function createLabels(labelProps: LabelOpts): void {
|
||||
return (
|
||||
<div
|
||||
key={`${data.entity.id}${index}`}
|
||||
data-label-id={label.labelId || labelProps.data.entity.id}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
left: offsetX,
|
||||
|
||||
@ -48,7 +48,12 @@ export function createLines(props: PropsType): void {
|
||||
switch (line.type) {
|
||||
case FlowTransitionLineEnum.STRAIGHT_LINE:
|
||||
return (
|
||||
<StraightLine key={`${data.entity.id}${index}`} activated={lineActivated} {...line} />
|
||||
<StraightLine
|
||||
key={`${data.entity.id}_${index}`}
|
||||
lineId={data.entity.id}
|
||||
activated={lineActivated}
|
||||
{...line}
|
||||
/>
|
||||
);
|
||||
|
||||
case FlowTransitionLineEnum.DIVERGE_LINE:
|
||||
@ -57,7 +62,8 @@ export function createLines(props: PropsType): void {
|
||||
case FlowTransitionLineEnum.ROUNDED_LINE:
|
||||
return (
|
||||
<RoundedTurningLine
|
||||
key={`${data.entity.id}${index}`}
|
||||
key={`${data.entity.id}_${index}`}
|
||||
lineId={data.entity.id}
|
||||
isHorizontal={!isVertical}
|
||||
activated={lineActivated || draggingLineActivated}
|
||||
{...line}
|
||||
@ -70,7 +76,8 @@ export function createLines(props: PropsType): void {
|
||||
case FlowTransitionLineEnum.CUSTOM_LINE:
|
||||
return (
|
||||
<CustomLine
|
||||
key={`${data.entity.id}${index}`}
|
||||
key={`${data.entity.id}_${index}`}
|
||||
lineId={data.entity.id}
|
||||
{...line}
|
||||
rendererRegistry={rendererRegistry}
|
||||
/>
|
||||
|
||||
@ -2,14 +2,15 @@ import React from 'react';
|
||||
|
||||
import { useBaseColor } from '../hooks/use-base-color';
|
||||
|
||||
export const MARK_ACTIVATED_ARROW_ID = 'line-marker-arrow-activated';
|
||||
export const MARK_ACTIVATED_ARROW_URL = `url(#${MARK_ACTIVATED_ARROW_ID})`;
|
||||
export const MARK_ACTIVATED_ARROW_ID = '$marker_arrow_activated$';
|
||||
// export const MARK_ACTIVATED_ARROW_URL = `url(#${MARK_ACTIVATED_ARROW_ID})`;
|
||||
|
||||
function MarkerActivatedArrow(): JSX.Element {
|
||||
function MarkerActivatedArrow(props: { id?: string }): JSX.Element {
|
||||
const { baseActivatedColor } = useBaseColor();
|
||||
return (
|
||||
<marker
|
||||
id={MARK_ACTIVATED_ARROW_ID}
|
||||
data-line-id={props.id}
|
||||
id={props.id || MARK_ACTIVATED_ARROW_ID}
|
||||
markerWidth="11"
|
||||
markerHeight="14"
|
||||
refX="10"
|
||||
|
||||
@ -2,13 +2,21 @@ import React from 'react';
|
||||
|
||||
import { useBaseColor } from '../hooks/use-base-color';
|
||||
|
||||
export const MARK_ARROW_ID = 'line-marker-arrow';
|
||||
export const MARK_ARROW_URL = `url(#${MARK_ARROW_ID})`;
|
||||
export const MARK_ARROW_ID = '$marker_arrow$';
|
||||
// export const MARK_ARROW_URL = `url(#${MARK_ARROW_ID})`;
|
||||
|
||||
function MarkerArrow(): JSX.Element {
|
||||
function MarkerArrow(props: { id: string }): JSX.Element {
|
||||
const { baseColor } = useBaseColor();
|
||||
return (
|
||||
<marker id={MARK_ARROW_ID} markerWidth="11" markerHeight="14" refX="10" refY="7" orient="auto">
|
||||
<marker
|
||||
data-line-id={props.id}
|
||||
id={props.id || MARK_ARROW_ID}
|
||||
markerWidth="11"
|
||||
markerHeight="14"
|
||||
refX="10"
|
||||
refY="7"
|
||||
orient="auto"
|
||||
>
|
||||
<path
|
||||
d="M9.6 5.2C10.8 6.1 10.8 7.9 9.6 8.8L3.6 13.3C2.11672 14.4125 0 13.3541 0 11.5L0 2.5C0 0.645898 2.11672 -0.412461 3.6 0.7L9.6 5.2Z"
|
||||
fill={baseColor}
|
||||
|
||||
@ -3,11 +3,13 @@ import React, { useMemo } from 'react';
|
||||
import { isNil } from 'lodash';
|
||||
import { Point } from '@flowgram.ai/utils';
|
||||
import { type FlowTransitionLine } from '@flowgram.ai/document';
|
||||
import { useService } from '@flowgram.ai/core';
|
||||
|
||||
import { useBaseColor } from '../hooks/use-base-color';
|
||||
import { DEFAULT_LINE_ATTRS, DEFAULT_RADIUS, getHorizontalVertices, getVertices } from './utils';
|
||||
import { MARK_ARROW_URL } from './MarkerArrow';
|
||||
import { MARK_ACTIVATED_ARROW_URL } from './MarkerActivatedArrow';
|
||||
import MarkerArrow, { MARK_ARROW_ID } from './MarkerArrow';
|
||||
import MarkerActivatedArrow, { MARK_ACTIVATED_ARROW_ID } from './MarkerActivatedArrow';
|
||||
import { FlowRendererKey, FlowRendererRegistry } from '../flow-renderer-registry';
|
||||
|
||||
interface PropsType extends FlowTransitionLine {
|
||||
radius?: number;
|
||||
@ -16,6 +18,27 @@ interface PropsType extends FlowTransitionLine {
|
||||
yRadius?: number;
|
||||
}
|
||||
|
||||
function MarkerDefs(props: { id: string; activated?: boolean }): JSX.Element {
|
||||
const renderRegistry = useService(FlowRendererRegistry);
|
||||
const ArrowRenderer = renderRegistry?.tryToGetRendererComponent(
|
||||
props.activated ? FlowRendererKey.MARKER_ACTIVATE_ARROW : FlowRendererKey.MARKER_ARROW
|
||||
);
|
||||
if (ArrowRenderer) {
|
||||
return <ArrowRenderer.renderer {...props} />;
|
||||
}
|
||||
if (props.activated) {
|
||||
return (
|
||||
<defs>
|
||||
<MarkerActivatedArrow id={props.id} />
|
||||
</defs>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<defs>
|
||||
<MarkerArrow id={props.id} />
|
||||
</defs>
|
||||
);
|
||||
}
|
||||
/**
|
||||
* 圆角转弯线
|
||||
*/
|
||||
@ -100,19 +123,26 @@ function RoundedTurningLine(props: PropsType): JSX.Element | null {
|
||||
}
|
||||
|
||||
const pathStr = `M ${from.x} ${from.y} ${middleStr} L ${to.x} ${to.y}`;
|
||||
const markerId = activated
|
||||
? `${MARK_ACTIVATED_ARROW_ID}${props.lineId}`
|
||||
: `${MARK_ARROW_ID}${props.lineId}`;
|
||||
|
||||
return (
|
||||
<path
|
||||
d={pathStr}
|
||||
{...DEFAULT_LINE_ATTRS}
|
||||
stroke={activated ? baseActivatedColor : baseColor}
|
||||
{...(arrow
|
||||
? {
|
||||
markerEnd: activated ? MARK_ACTIVATED_ARROW_URL : MARK_ARROW_URL,
|
||||
}
|
||||
: {})}
|
||||
style={style}
|
||||
/>
|
||||
<>
|
||||
{arrow ? <MarkerDefs id={markerId} activated={activated} /> : null}
|
||||
<path
|
||||
data-line-id={props.lineId}
|
||||
d={pathStr}
|
||||
{...DEFAULT_LINE_ATTRS}
|
||||
stroke={activated ? baseActivatedColor : baseColor}
|
||||
{...(arrow
|
||||
? {
|
||||
markerEnd: `url(#${markerId})`,
|
||||
}
|
||||
: {})}
|
||||
style={style}
|
||||
></path>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@ function StraightLine(props: FlowTransitionLine): JSX.Element {
|
||||
|
||||
return (
|
||||
<path
|
||||
data-line-id={props.lineId}
|
||||
d={`M ${from.x} ${from.y} L ${to.x} ${to.y}`}
|
||||
{...DEFAULT_LINE_ATTRS}
|
||||
stroke={activated ? baseActivatedColor : baseColor}
|
||||
|
||||
@ -13,9 +13,7 @@ import {
|
||||
} from '@flowgram.ai/document';
|
||||
import { Layer, observeEntity, observeEntityDatas } from '@flowgram.ai/core';
|
||||
|
||||
import { FlowRendererKey, FlowRendererRegistry } from '../flow-renderer-registry';
|
||||
import MarkerArrow from '../components/MarkerArrow';
|
||||
import MarkerActivatedArrow from '../components/MarkerActivatedArrow';
|
||||
import { FlowRendererRegistry } from '../flow-renderer-registry';
|
||||
import { createLines } from '../components/LinesRenderer';
|
||||
|
||||
@injectable()
|
||||
@ -90,19 +88,6 @@ export class FlowLinesLayer extends Layer {
|
||||
);
|
||||
const resultLines = [...normalLines, ...activateLines];
|
||||
|
||||
const arrowRenderer = this.rendererRegistry.tryToGetRendererComponent(
|
||||
FlowRendererKey.MARKER_ARROW
|
||||
);
|
||||
const activateArrowRenderer = this.rendererRegistry.tryToGetRendererComponent(
|
||||
FlowRendererKey.MARKER_ACTIVATE_ARROW
|
||||
);
|
||||
const arrow = arrowRenderer
|
||||
? React.createElement(arrowRenderer.renderer as () => JSX.Element)
|
||||
: null;
|
||||
const activateArrow = activateArrowRenderer
|
||||
? React.createElement(activateArrowRenderer.renderer as () => JSX.Element)
|
||||
: null;
|
||||
|
||||
return (
|
||||
<svg
|
||||
className="flow-lines-container"
|
||||
@ -112,10 +97,6 @@ export class FlowLinesLayer extends Layer {
|
||||
viewBox={this.viewBox}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<defs>
|
||||
{arrowRenderer ? arrow : <MarkerArrow />}
|
||||
{activateArrow ? activateArrow : <MarkerActivatedArrow />}
|
||||
</defs>
|
||||
{resultLines}
|
||||
</svg>
|
||||
);
|
||||
|
||||
@ -129,6 +129,7 @@ function TryCatchCollapse(props: CustomLabelProps): JSX.Element {
|
||||
}}
|
||||
>
|
||||
<div
|
||||
data-label-id={props.labelId}
|
||||
style={{
|
||||
fontSize: 12,
|
||||
color: hoverActivated ? baseActivatedColor : baseColor,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user