Skip to content

Commit

Permalink
feat: add product launch flow graph demo (#2727)
Browse files Browse the repository at this point in the history
* refactor: extract node style calculation into a common function

* feat: add product activation flow graph demo

* docs: add demo

* refactor: rename
  • Loading branch information
yvonneyx authored Oct 17, 2024
1 parent 261828a commit 7787d26
Show file tree
Hide file tree
Showing 8 changed files with 521 additions and 64 deletions.
50 changes: 19 additions & 31 deletions packages/graphs/src/components/indented-tree/options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import React from 'react';
import { CollapseExpandIcon, RCNode, TextNodeProps } from '../../core/base';
import { measureTextSize } from '../../core/utils/measure-text';
import { getNodeSide } from '../../core/utils/node';
import { getBoxedTextNodeStyle, getLinearTextNodeStyle } from '../../core/utils/tree';
import type { IndentedTreeOptions } from './types';

const { ArrowCountIcon } = CollapseExpandIcon;
Expand Down Expand Up @@ -86,17 +87,6 @@ export const getIndentedTreeOptions = ({
const maxWidth = nodeMaxWidth || 300;

if (type === 'boxed') {
const getNodeFont = (depth: number) => {
const fontSize = depth === 0 ? 20 : depth === 1 ? 18 : 16;
return { fontWeight: 'bold', fontSize, fontFamily: 'PingFang SC' };
};

const measureNodeSize = (data: NodeData) => {
const offset = data.depth === 0 ? [24, 36] : [12, 24];
const font = getNodeFont(data.depth!);
return measureTextSize(idOf(data), offset, font, minWidth, maxWidth);
};

options = {
node: {
style: {
Expand All @@ -108,15 +98,16 @@ export const getIndentedTreeOptions = ({
text: idOf(data),
color: depth === 0 ? '#f1f4f5' : color,
maxWidth,
font: getNodeFont(depth),
font: getBoxedTextNodeStyle(idOf(data), minWidth, maxWidth, depth).font,
style: {
textAlign: getNodeTextAlign(this as unknown as Graph, data),
...(depth === 0 ? { color: '#252525' } : {}),
},
};
return <TextNode {...props} />;
},
size: (data: NodeData) => measureNodeSize(data),
size: (data: NodeData) =>
getBoxedTextNodeStyle(idOf(data), minWidth, maxWidth, data.depth as number).size,
},
},
edge: {
Expand All @@ -137,31 +128,25 @@ export const getIndentedTreeOptions = ({
layout: {
type: 'indented',
indent: (node) => getIndent(node, 20),
getWidth: (data) => measureNodeSize(data)[0],
getHeight: (data) => measureNodeSize(data)[1],
getWidth: (data) => getBoxedTextNodeStyle(idOf(data), minWidth, maxWidth, data.depth as number).size[0],
getHeight: (data) =>
getBoxedTextNodeStyle(idOf(data), minWidth, maxWidth, data.depth as number).size[1],
getVGap: () => 14,
},
};
} else if (type === 'linear') {
const getNodeFont = (depth: number) => {
const fontSize = depth === 0 ? 20 : 16;
return { fontWeight: 'bold', fontSize, fontFamily: 'PingFang SC' };
};

const measureNodeSize = (data: NodeData) => {
const { depth } = data.data as { depth: number };
const offset = depth === 0 ? [24, 36] : [12, 12];
const font = getNodeFont(depth);
return measureTextSize(idOf(data), offset, font, minWidth, maxWidth);
};

options = {
node: {
style: {
component: function (data: NodeData) {
const depth = data.depth as number;
const color = data.style?.color as string;
const props = { text: idOf(data), color, maxWidth, font: getNodeFont(depth) } as TextNodeProps;
const props = {
text: idOf(data),
color,
maxWidth,
font: getLinearTextNodeStyle(idOf(data), minWidth, maxWidth, depth).font,
} as TextNodeProps;
Object.assign(
props,
depth === 0
Expand All @@ -173,7 +158,8 @@ export const getIndentedTreeOptions = ({
);
return <TextNode {...props} />;
},
size: (data: NodeData) => measureNodeSize(data),
size: (data: NodeData) =>
getLinearTextNodeStyle(idOf(data), minWidth, maxWidth, data.depth as number).size,
ports: function (data: NodeData) {
const side = getNodeSide(this as unknown as Graph, data);
return side === 'left'
Expand All @@ -195,8 +181,10 @@ export const getIndentedTreeOptions = ({
layout: {
type: 'indented',
indent: (node) => getIndent(node, 20),
getWidth: (data) => measureNodeSize(data)[0],
getHeight: (data) => measureNodeSize(data)[1],
getWidth: (data) =>
getLinearTextNodeStyle(idOf(data), minWidth, maxWidth, data.depth as number).size[0],
getHeight: (data) =>
getLinearTextNodeStyle(idOf(data), minWidth, maxWidth, data.depth as number).size[1],
getVGap: () => 12,
},
transforms: (prev) => [
Expand Down
54 changes: 21 additions & 33 deletions packages/graphs/src/components/mind-map/options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { TextNodeProps } from '../../core/base';
import { CollapseExpandIcon, RCNode } from '../../core/base';
import { measureTextSize } from '../../core/utils/measure-text';
import { getNodeSide } from '../../core/utils/node';
import { getBoxedTextNodeStyle, getLinearTextNodeStyle } from '../../core/utils/tree';
import type { MindMapOptions } from './types';

const { ArrowCountIcon } = CollapseExpandIcon;
Expand Down Expand Up @@ -85,25 +86,18 @@ export function getMindMapOptions({
const minWidth = nodeMinWidth || 120;
const maxWidth = nodeMaxWidth || 300;

const getNodeFont = (depth: number) => {
const fontSize = depth === 0 ? 20 : depth === 1 ? 18 : 16;
return { fontWeight: 'bold', fontSize, fontFamily: 'PingFang SC' };
};

const measureNodeSize = (data: NodeData) => {
const depth = data.depth as number;
const offset = depth === 0 ? [24, 36] : [12, 24];
const font = getNodeFont(depth);
return measureTextSize(idOf(data), offset, font, minWidth, maxWidth);
};

options = {
node: {
style: {
component: (data: NodeData) => {
const depth = data.depth as number;
const color = data.style?.color as string;
const props = { text: idOf(data), color, maxWidth, font: getNodeFont(depth) } as TextNodeProps;
const props = {
text: idOf(data),
color,
maxWidth,
font: getBoxedTextNodeStyle(idOf(data), minWidth, maxWidth, depth).font,
} as TextNodeProps;
Object.assign(
props,
depth === 0
Expand All @@ -114,10 +108,11 @@ export function getMindMapOptions({
);
return <TextNode {...props} />;
},
size: (data: NodeData) => measureNodeSize(data),
size: (data: NodeData) =>
getBoxedTextNodeStyle(idOf(data), minWidth, maxWidth, data.depth as number).size,
dx: function (data: NodeData) {
const side = getNodeSide(this as unknown as Graph, data);
const size = measureNodeSize(data);
const size = getBoxedTextNodeStyle(idOf(data), minWidth, maxWidth, data.depth as number).size;
return side === 'left' ? -size[0] : side === 'center' ? -size[0] / 2 : 0;
},
ports: [{ placement: 'left' }, { placement: 'right' }],
Expand All @@ -139,34 +134,24 @@ export function getMindMapOptions({
],
layout: {
type: 'mindmap',
getHeight: (data) => measureNodeSize(data)[1],
getHeight: (data) =>
getBoxedTextNodeStyle(idOf(data), minWidth, maxWidth, data.depth as number).size[1],
getVGap: () => 14,
},
};
} else if (type === 'linear') {
const minWidth = nodeMinWidth || 0;
const maxWidth = nodeMaxWidth || 300;

const getNodeFont = (depth: number) => {
const fontSize = depth === 0 ? 20 : 16;
return { fontWeight: 'bold', fontSize, fontFamily: 'PingFang SC' };
};

const measureNodeSize = (data: NodeData) => {
const { depth } = data.data as { depth: number };
const offset = depth === 0 ? [24, 36] : [12, 12];
const font = getNodeFont(depth);
return measureTextSize(idOf(data), offset, font, minWidth, maxWidth);
};

options = {
node: {
style: {
component: function (data: NodeData) {
const side = getNodeSide(this as unknown as Graph, data);
const depth = data.depth as number;
const color = data.style?.color as string;
const props = { text: idOf(data), color, maxWidth, font: getNodeFont(depth) } as TextNodeProps;
const { font } = getLinearTextNodeStyle(idOf(data), minWidth, maxWidth, depth);
const props = { text: idOf(data), color, maxWidth, font } as TextNodeProps;
Object.assign(
props,
depth === 0
Expand All @@ -178,10 +163,11 @@ export function getMindMapOptions({
);
return <TextNode {...props} />;
},
size: (data: NodeData) => measureNodeSize(data),
size: (data: NodeData) =>
getLinearTextNodeStyle(idOf(data), minWidth, maxWidth, data.depth as number).size,
dx: function (data: NodeData) {
const side = getNodeSide(this as unknown as Graph, data);
const size = measureNodeSize(data);
const size = getLinearTextNodeStyle(idOf(data), minWidth, maxWidth, data.depth as number).size;
return side === 'left' ? -size[0] : side === 'center' ? -size[0] / 2 : 0;
},
ports: function (data: NodeData) {
Expand All @@ -201,7 +187,8 @@ export function getMindMapOptions({
},
layout: {
type: 'mindmap',
getHeight: (data) => measureNodeSize(data)[1],
getHeight: (data) =>
getLinearTextNodeStyle(idOf(data), minWidth, maxWidth, data.depth as number).size[1],
getVGap: () => 12,
},
transforms: (prev) => [
Expand All @@ -214,7 +201,8 @@ export function getMindMapOptions({
...(prev.find((t) => (t as any).key === 'collapse-expand-react-node') as any),
iconOffsetY: (data) => {
if (data.depth === 0) return 0;
return measureNodeSize(data)[1] / 2;
const size = getLinearTextNodeStyle(idOf(data), minWidth, maxWidth, data.depth as number).size;
return size[1] / 2;
},
},
],
Expand Down
28 changes: 28 additions & 0 deletions packages/graphs/src/core/utils/tree.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { memoize } from 'lodash';
import { measureTextSize } from './measure-text';

export const getLinearTextNodeStyle = memoize(
(text: string, minWidth: number, maxWidth: number, depth: number = 0) => {
const font = {
fontWeight: 'bold',
fontSize: depth === 0 ? 20 : 16,
fontFamily: 'PingFang SC',
};
const offset = depth === 0 ? [24, 36] : [12, 12];
const size = measureTextSize(text, offset, font, minWidth, maxWidth);
return { font, size };
},
);

export const getBoxedTextNodeStyle = memoize(
(text: string, minWidth: number, maxWidth: number, depth: number = 0) => {
const font = {
fontWeight: 'bold',
fontSize: depth === 0 ? 20 : depth === 1 ? 18 : 16,
fontFamily: 'PingFang SC',
};
const offset = depth === 0 ? [24, 36] : [12, 24];
const size = measureTextSize(text, offset, font, minWidth, maxWidth);
return { font, size };
},
);
56 changes: 56 additions & 0 deletions packages/graphs/tests/datasets/product-launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{
"nodes": [
{
"id": "start",
"data": { "name": "流程开始" }
},
{
"id": "submit-agreement",
"data": { "name": "提交协议", "elapsed_time": "11秒" }
},
{
"id": "contract-review",
"data": {
"name": "合约审核",
"elapsed_time": "1.63分",
"status": "running",
"children": [
{ "name": "风控审核", "elapsed_time": "39秒" },
{ "name": "财务审核", "elapsed_time": "0秒" },
{ "name": "法务审核", "elapsed_time": "0秒" },
{ "name": "销售初评", "elapsed_time": "0秒" },
{ "name": "主管审核", "elapsed_time": "0秒" },
{ "name": "销售终审", "elapsed_time": "0秒" }
]
}
},
{
"id": "merchant-confirmation",
"data": { "name": "商户确认", "elapsed_time": "0秒" }
},
{
"id": "end",
"data": { "name": "流程结束" }
}
],
"edges": [
{
"source": "start",
"target": "submit-agreement"
},
{
"source": "submit-agreement",
"target": "contract-review",
"data": { "elapsed_time": "11秒" }
},
{
"source": "contract-review",
"target": "merchant-confirmation",
"data": { "elapsed_time": "0秒" }
},
{
"source": "merchant-confirmation",
"target": "end"
}
]
}
Loading

0 comments on commit 7787d26

Please sign in to comment.