@logicflow/core 2.0.13 → 2.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/.turbo/turbo-build$colon$dev.log +2 -2
  2. package/.turbo/turbo-build.log +6 -6
  3. package/CHANGELOG.md +6 -0
  4. package/__tests__/algorithm/index.test.ts +22 -17
  5. package/__tests__/algorithm/outline.test.ts +9 -9
  6. package/__tests__/event/event.test.ts +18 -18
  7. package/__tests__/history/history.test.ts +23 -23
  8. package/__tests__/logicflow.test.ts +236 -228
  9. package/__tests__/model/graphmodel.test.ts +51 -31
  10. package/__tests__/util/compatible.test.ts +5 -5
  11. package/__tests__/util/geometry.test.ts +10 -10
  12. package/__tests__/util/graph.test.ts +12 -12
  13. package/__tests__/util/matrix.test.ts +26 -26
  14. package/__tests__/util/node.test.ts +22 -22
  15. package/__tests__/util/sampling.test.ts +6 -10
  16. package/__tests__/util/vector.test.ts +36 -36
  17. package/__tests__/util/zIndex.test.ts +6 -6
  18. package/dist/index.min.js +1 -1
  19. package/dist/index.min.js.map +1 -1
  20. package/es/LogicFlow.d.ts +24 -4
  21. package/es/LogicFlow.js +28 -6
  22. package/es/model/GraphModel.d.ts +34 -1
  23. package/es/model/GraphModel.js +36 -5
  24. package/es/model/node/RectNodeModel.js +3 -0
  25. package/es/options.d.ts +1 -0
  26. package/es/util/theme.d.ts +67 -2
  27. package/es/util/theme.js +189 -2
  28. package/es/view/edge/BaseEdge.d.ts +4 -0
  29. package/es/view/edge/BaseEdge.js +45 -3
  30. package/es/view/overlay/Grid.js +3 -2
  31. package/es/view/shape/Polygon.d.ts +8 -0
  32. package/es/view/shape/Polygon.js +50 -3
  33. package/lib/LogicFlow.d.ts +24 -4
  34. package/lib/LogicFlow.js +27 -5
  35. package/lib/model/GraphModel.d.ts +34 -1
  36. package/lib/model/GraphModel.js +34 -3
  37. package/lib/model/node/RectNodeModel.js +3 -0
  38. package/lib/options.d.ts +1 -0
  39. package/lib/util/theme.d.ts +67 -2
  40. package/lib/util/theme.js +192 -2
  41. package/lib/view/edge/BaseEdge.d.ts +4 -0
  42. package/lib/view/edge/BaseEdge.js +45 -3
  43. package/lib/view/overlay/Grid.js +3 -2
  44. package/lib/view/shape/Polygon.d.ts +8 -0
  45. package/lib/view/shape/Polygon.js +52 -4
  46. package/package.json +1 -1
  47. package/src/LogicFlow.tsx +48 -6
  48. package/src/model/GraphModel.ts +48 -3
  49. package/src/model/edge/index.ts +4 -4
  50. package/src/model/index.ts +7 -7
  51. package/src/model/node/RectNodeModel.ts +2 -1
  52. package/src/model/node/index.ts +8 -8
  53. package/src/options.ts +1 -0
  54. package/src/util/theme.ts +198 -3
  55. package/src/view/edge/BaseEdge.tsx +96 -12
  56. package/src/view/overlay/Grid.tsx +2 -1
  57. package/src/view/shape/Polygon.tsx +56 -4
  58. package/stats.html +1 -1
@@ -317,6 +317,31 @@ var BaseEdge = /** @class */ (function (_super) {
317
317
  }
318
318
  return ((0, jsx_runtime_1.jsx)("g", { children: (0, jsx_runtime_1.jsxs)("defs", { children: [(0, jsx_runtime_1.jsx)("marker", { id: "marker-start-".concat(id), refX: -refX, refY: refY, overflow: "visible", orient: "auto", markerUnits: "userSpaceOnUse", children: this.getStartArrow() }), (0, jsx_runtime_1.jsx)("marker", { id: "marker-end-".concat(id), refX: refX, refY: refY, overflow: "visible", orient: theta, markerUnits: "userSpaceOnUse", children: this.getEndArrow() })] }) }));
319
319
  };
320
+ /**
321
+ * Private helper method to generate arrow path based on type and parameters
322
+ */
323
+ BaseEdge.prototype.getArrowPath = function (arrowType, props) {
324
+ var stroke = props.stroke, _a = props.fill, fill = _a === void 0 ? stroke : _a, strokeWidth = props.strokeWidth, _b = props.offset, offset = _b === void 0 ? 10 : _b, verticalLength = props.verticalLength, strokeLinecap = props.strokeLinecap, strokeLinejoin = props.strokeLinejoin, transform = props.transform;
325
+ var arrowPath = '';
326
+ switch (arrowType) {
327
+ case 'solid':
328
+ arrowPath = "M".concat(-offset / 4, ",0 L").concat((3 * offset) / 4, ",").concat(verticalLength, " L").concat((3 * offset) / 4, ",-").concat(verticalLength, " Z");
329
+ break;
330
+ case 'hollow':
331
+ arrowPath = "M".concat(-offset / 4, ",0 L").concat((3 * offset) / 4, ",").concat(verticalLength, " L").concat(-offset / 4, ",0 L").concat((3 * offset) / 4, ",-").concat(verticalLength, " L").concat(-offset / 4, ",0 Z");
332
+ break;
333
+ case 'diamond':
334
+ arrowPath = "M".concat(-offset / 2, ",0 L0,").concat(verticalLength, " L").concat(offset / 2, ",0 L0,-").concat(verticalLength, " L").concat(-offset / 2, ",0 Z");
335
+ break;
336
+ case 'circle':
337
+ arrowPath = "M".concat(-offset / 2, ",0 A").concat(offset / 4, ",").concat(offset / 4, " 0 1,0 ").concat(offset / 2, ",0 A").concat(offset / 4, ",").concat(offset / 4, " 0 1,0 ").concat(-offset / 2, ",0 Z");
338
+ break;
339
+ default:
340
+ arrowPath = '';
341
+ break;
342
+ }
343
+ return ((0, jsx_runtime_1.jsx)("path", { d: arrowPath, stroke: stroke, fill: fill, strokeWidth: strokeWidth, strokeLinecap: strokeLinecap, strokeLinejoin: strokeLinejoin, transform: transform }));
344
+ };
320
345
  /**
321
346
  * @overridable 可重写,自定义边起点箭头形状。
322
347
  * @example
@@ -331,7 +356,16 @@ var BaseEdge = /** @class */ (function (_super) {
331
356
  * }
332
357
  */
333
358
  BaseEdge.prototype.getStartArrow = function () {
334
- return (0, jsx_runtime_1.jsx)("path", {});
359
+ var model = this.props.model;
360
+ var _a = model.getArrowStyle(), stroke = _a.stroke, strokeWidth = _a.strokeWidth, offset = _a.offset, verticalLength = _a.verticalLength, _b = _a.startArrowType, startArrowType = _b === void 0 ? 'solid' : _b, strokeLinecap = _a.strokeLinecap, strokeLinejoin = _a.strokeLinejoin;
361
+ return this.getArrowPath(startArrowType, {
362
+ stroke: stroke,
363
+ strokeWidth: strokeWidth,
364
+ offset: offset,
365
+ verticalLength: verticalLength,
366
+ strokeLinecap: strokeLinecap,
367
+ strokeLinejoin: strokeLinejoin,
368
+ });
335
369
  };
336
370
  /**
337
371
  * @overridable 可重写,自定义边终点箭头形状。
@@ -348,8 +382,16 @@ var BaseEdge = /** @class */ (function (_super) {
348
382
  */
349
383
  BaseEdge.prototype.getEndArrow = function () {
350
384
  var model = this.props.model;
351
- var _a = model.getArrowStyle(), stroke = _a.stroke, strokeWidth = _a.strokeWidth, offset = _a.offset, verticalLength = _a.verticalLength;
352
- return ((0, jsx_runtime_1.jsx)("path", { stroke: stroke, fill: stroke, strokeWidth: strokeWidth, transform: "rotate(180)", d: "M 0 0 L ".concat(offset, " -").concat(verticalLength, " L ").concat(offset, " ").concat(verticalLength, " Z") }));
385
+ var _a = model.getArrowStyle(), stroke = _a.stroke, strokeWidth = _a.strokeWidth, offset = _a.offset, verticalLength = _a.verticalLength, _b = _a.endArrowType, endArrowType = _b === void 0 ? 'solid' : _b, strokeLinecap = _a.strokeLinecap, strokeLinejoin = _a.strokeLinejoin;
386
+ return this.getArrowPath(endArrowType, {
387
+ stroke: stroke,
388
+ strokeWidth: strokeWidth,
389
+ offset: offset,
390
+ verticalLength: verticalLength,
391
+ strokeLinecap: strokeLinecap,
392
+ strokeLinejoin: strokeLinejoin,
393
+ transform: 'rotate(180)',
394
+ });
353
395
  };
354
396
  /**
355
397
  * @overridable 可重写,自定义调整边连接节点形状。在开启了adjustEdgeStartAndEnd的时候,会显示调整点。
@@ -57,8 +57,9 @@ var Grid = /** @class */ (function (_super) {
57
57
  return ((0, jsx_runtime_1.jsx)("path", { d: d, stroke: color, strokeWidth: strokeWidth / 2, opacity: opacity, fill: "transparent" }));
58
58
  };
59
59
  Grid.prototype.render = function () {
60
- var transformModel = this.props.graphModel.transformModel;
61
- var _a = this.gridOptions, type = _a.type, _b = _a.size, size = _b === void 0 ? 1 : _b;
60
+ var _a = this.props.graphModel, transformModel = _a.transformModel, grid = _a.grid;
61
+ this.gridOptions = grid;
62
+ var _b = this.gridOptions, type = _b.type, _c = _b.size, size = _c === void 0 ? 1 : _c;
62
63
  var SCALE_X = transformModel.SCALE_X, SKEW_Y = transformModel.SKEW_Y, SKEW_X = transformModel.SKEW_X, SCALE_Y = transformModel.SCALE_Y, TRANSLATE_X = transformModel.TRANSLATE_X, TRANSLATE_Y = transformModel.TRANSLATE_Y;
63
64
  var matrixString = [
64
65
  SCALE_X,
@@ -5,6 +5,14 @@ export type IPolygonProps = {
5
5
  x?: number;
6
6
  y?: number;
7
7
  className?: string;
8
+ radius?: number;
8
9
  };
10
+ /**
11
+ * 生成带圆角的多边形路径
12
+ * @param points 多边形顶点坐标数组
13
+ * @param radius 圆角半径
14
+ * @returns SVG 路径字符串
15
+ */
16
+ export declare function createRoundedPolygonPath(points: any, radius: any): string;
9
17
  export declare function Polygon(props: IPolygonProps): h.JSX.Element;
10
18
  export default Polygon;
@@ -27,11 +27,52 @@ var __read = (this && this.__read) || function (o, n) {
27
27
  return ar;
28
28
  };
29
29
  Object.defineProperty(exports, "__esModule", { value: true });
30
- exports.Polygon = void 0;
30
+ exports.Polygon = exports.createRoundedPolygonPath = void 0;
31
31
  var jsx_runtime_1 = require("preact/jsx-runtime");
32
32
  var lodash_es_1 = require("lodash-es");
33
+ /**
34
+ * 生成带圆角的多边形路径
35
+ * @param points 多边形顶点坐标数组
36
+ * @param radius 圆角半径
37
+ * @returns SVG 路径字符串
38
+ */
39
+ function createRoundedPolygonPath(points, radius) {
40
+ var pointList = points.map(function (point) { return ({ x: point[0], y: point[1] }); });
41
+ var len = pointList.length;
42
+ if (len < 3)
43
+ return '';
44
+ var r = Math.abs(radius);
45
+ var path = '';
46
+ for (var i = 0; i < len; i++) {
47
+ var prev = pointList[(i - 1 + len) % len];
48
+ var curr = pointList[i];
49
+ var next = pointList[(i + 1) % len];
50
+ // 向量
51
+ var v1 = { x: curr.x - prev.x, y: curr.y - prev.y };
52
+ var v2 = { x: next.x - curr.x, y: next.y - curr.y };
53
+ // 单位向量
54
+ var len1 = Math.hypot(v1.x, v1.y);
55
+ var len2 = Math.hypot(v2.x, v2.y);
56
+ var u1 = { x: v1.x / len1, y: v1.y / len1 };
57
+ var u2 = { x: v2.x / len2, y: v2.y / len2 };
58
+ // 起点 = curr - u1 * r,终点 = curr + u2 * r
59
+ var start = { x: curr.x - u1.x * r, y: curr.y - u1.y * r };
60
+ var end = { x: curr.x + u2.x * r, y: curr.y + u2.y * r };
61
+ if (i === 0) {
62
+ path += "M ".concat(start.x, " ").concat(start.y, " ");
63
+ }
64
+ else {
65
+ path += "L ".concat(start.x, " ").concat(start.y, " ");
66
+ }
67
+ // Q 控制点是当前拐角点
68
+ path += "Q ".concat(curr.x, " ").concat(curr.y, " ").concat(end.x, " ").concat(end.y, " ");
69
+ }
70
+ path += 'Z';
71
+ return path;
72
+ }
73
+ exports.createRoundedPolygonPath = createRoundedPolygonPath;
33
74
  function Polygon(props) {
34
- var _a = props.points, points = _a === void 0 ? [] : _a, className = props.className;
75
+ var _a = props.points, points = _a === void 0 ? [] : _a, className = props.className, radius = props.radius;
35
76
  var attrs = {
36
77
  fill: 'transparent',
37
78
  fillOpacity: 1,
@@ -52,8 +93,15 @@ function Polygon(props) {
52
93
  else {
53
94
  attrs.className = 'lf-basic-shape';
54
95
  }
55
- attrs.points = points.map(function (point) { return point.join(','); }).join(' ');
56
- return (0, jsx_runtime_1.jsx)("polygon", __assign({}, attrs));
96
+ if (radius) {
97
+ var path = createRoundedPolygonPath(points, radius);
98
+ attrs.d = path;
99
+ return (0, jsx_runtime_1.jsx)("path", __assign({}, attrs));
100
+ }
101
+ else {
102
+ attrs.points = points.map(function (point) { return point.join(','); }).join(' ');
103
+ return (0, jsx_runtime_1.jsx)("polygon", __assign({}, attrs));
104
+ }
57
105
  }
58
106
  exports.Polygon = Polygon;
59
107
  exports.default = Polygon;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@logicflow/core",
3
- "version": "2.0.13",
3
+ "version": "2.0.14",
4
4
  "description": "LogicFlow, help you quickly create flowcharts",
5
5
  "main": "lib/index.js",
6
6
  "module": "es/index.js",
package/src/LogicFlow.tsx CHANGED
@@ -14,7 +14,12 @@ import {
14
14
 
15
15
  import Graph from './view/Graph'
16
16
  import * as _View from './view'
17
- import { formatData } from './util'
17
+ import {
18
+ formatData,
19
+ addThemeMode,
20
+ removeThemeMode,
21
+ clearThemeMode,
22
+ } from './util'
18
23
 
19
24
  import { Dnd, snapline } from './view/behavior'
20
25
  import Tool from './tool'
@@ -22,6 +27,7 @@ import History from './history'
22
27
  import Keyboard, { initDefaultShortcut } from './keyboard'
23
28
  import { EventCallback, CallbackArgs, EventArgs } from './event/eventEmitter'
24
29
  import { ElementType, EventType, SegmentDirection } from './constant'
30
+ import { Grid } from './view/overlay'
25
31
 
26
32
  import Extension = LogicFlow.Extension
27
33
  import ExtensionConfig = LogicFlow.ExtensionConfig
@@ -829,7 +835,7 @@ export class LogicFlow {
829
835
 
830
836
  /**
831
837
  * 设置元素的自定义属性
832
- * @see todo docs link
838
+ * @see http://logicflow.cn/api/detail#setproperties
833
839
  * @param id 元素的id
834
840
  * @param properties 自定义属性
835
841
  */
@@ -889,7 +895,7 @@ export class LogicFlow {
889
895
  /**
890
896
  * 更新流程图编辑相关设置
891
897
  * @param {object} config 编辑配置
892
- * @see todo docs link
898
+ * @see http://logicflow.cn/api/detail#updateeditconfig
893
899
  */
894
900
  updateEditConfig(config: Partial<IEditConfigType>) {
895
901
  const { editConfigModel, transformModel } = this.graphModel
@@ -914,7 +920,7 @@ export class LogicFlow {
914
920
 
915
921
  /**
916
922
  * 获取流程图当前编辑相关设置
917
- * @see todo docs link
923
+ * @see http://logicflow.cn/api/detail#geteditconfig
918
924
  */
919
925
  getEditConfig() {
920
926
  return this.graphModel.editConfigModel.getConfig()
@@ -928,8 +934,18 @@ export class LogicFlow {
928
934
  * @param { object } style 自定义主题样式
929
935
  * todo docs link
930
936
  */
931
- setTheme(style: Partial<LogicFlow.Theme>): void {
932
- this.graphModel.setTheme(style)
937
+ setTheme(
938
+ style: Partial<LogicFlow.Theme>,
939
+ themeMode?: 'radius' | 'dark' | 'colorful' | 'default' | string,
940
+ ): void {
941
+ this.graphModel.setTheme(style, themeMode)
942
+ }
943
+ /**
944
+ * 获取当前主题样式
945
+ * @see todo docs link
946
+ */
947
+ getTheme(): LogicFlow.Theme {
948
+ return this.graphModel.getTheme()
933
949
  }
934
950
 
935
951
  private focusByElement(id: string) {
@@ -1333,6 +1349,23 @@ export class LogicFlow {
1333
1349
  })
1334
1350
  }
1335
1351
 
1352
+ /**
1353
+ * 添加主题模式
1354
+ * @param themeMode 主题模式
1355
+ * @param style 主题样式
1356
+ */
1357
+ static addThemeMode(themeMode: string, style: Partial<LogicFlow.Theme>) {
1358
+ addThemeMode(themeMode, style)
1359
+ }
1360
+
1361
+ static removeThemeMode(themeMode: string) {
1362
+ removeThemeMode(themeMode)
1363
+ }
1364
+
1365
+ static clearThemeMode() {
1366
+ clearThemeMode()
1367
+ }
1368
+
1336
1369
  private installPlugins(disabledPlugins: string[] = []) {
1337
1370
  const extensionsAddByUse = Array.from(
1338
1371
  LogicFlow.extensions,
@@ -1399,6 +1432,7 @@ export class LogicFlow {
1399
1432
  this.graphModel.destroy()
1400
1433
  this.tool.destroy()
1401
1434
  this.history.destroy()
1435
+ this.clearThemeMode()
1402
1436
  for (const extensionName in this.extension) {
1403
1437
  const extensionInstance = this.extension[extensionName]
1404
1438
  if ('destroy' in extensionInstance) {
@@ -1801,6 +1835,10 @@ export namespace LogicFlow {
1801
1835
  refX?: number
1802
1836
  refY?: number
1803
1837
  verticalLength: number
1838
+ endArrowType?: 'solid' | 'hollow' | 'diamond' | 'circle' | 'none' // 结束箭头类型
1839
+ startArrowType?: 'solid' | 'hollow' | 'diamond' | 'circle' | 'none' // 开始箭头类型
1840
+ strokeLinecap?: 'butt' | 'round' | 'square' // 线条的端点样式
1841
+ strokeLinejoin?: 'miter' | 'round' | 'bevel' // 线条的连接样式
1804
1842
  } & CommonTheme
1805
1843
  export type ArrowAttributesType = {
1806
1844
  d: string
@@ -1855,6 +1893,10 @@ export namespace LogicFlow {
1855
1893
  edgeAdjust: CircleTheme
1856
1894
  outline: OutlineTheme // 节点选择状态下外侧的选框样式
1857
1895
  edgeAnimation: EdgeAnimation // 边动画样式
1896
+
1897
+ // 画布背景
1898
+ background?: boolean | Partial<LFOptions.BackgroundConfig>
1899
+ grid?: boolean | Partial<Grid.GridOptions>
1858
1900
  }
1859
1901
  }
1860
1902
 
@@ -5,6 +5,7 @@ import {
5
5
  merge,
6
6
  isBoolean,
7
7
  debounce,
8
+ cloneDeep,
8
9
  isNil,
9
10
  } from 'lodash-es'
10
11
  import { action, computed, observable } from 'mobx'
@@ -42,6 +43,8 @@ import {
42
43
  setupTheme,
43
44
  snapToGrid,
44
45
  updateTheme,
46
+ backgroundModeMap,
47
+ gridModeMap,
45
48
  } from '../util'
46
49
  import EventEmitter from '../event/eventEmitter'
47
50
  import { Grid } from '../view/overlay'
@@ -64,6 +67,8 @@ export class GraphModel {
64
67
 
65
68
  // 流程图主题配置
66
69
  @observable theme: LogicFlow.Theme
70
+ // 初始化样式
71
+ customStyles: object
67
72
  // 网格配置
68
73
  @observable grid: Grid.GridOptions
69
74
  // 事件中心
@@ -165,8 +170,11 @@ export class GraphModel {
165
170
  // TODO:需要让用户设置成 0 吗?后面可以讨论一下
166
171
  this.gridSize = grid.size || 1 // 默认 gridSize 设置为 1
167
172
  }
168
- this.theme = setupTheme(options.style)
173
+ this.customStyles = options.style || {}
169
174
  this.grid = Grid.getGridOptions(grid ?? false)
175
+ this.theme = setupTheme(options.style, options.themeMode)
176
+ this.theme.grid = cloneDeep(this.grid)
177
+ this.theme.background = cloneDeep(this.background)
170
178
  this.edgeType = options.edgeType || 'polyline'
171
179
  this.animation = setupAnimation(animation)
172
180
  this.overlapMode = options.overlapMode || OverlapMode.DEFAULT
@@ -1471,8 +1479,45 @@ export class GraphModel {
1471
1479
  * 设置主题
1472
1480
  * todo docs link
1473
1481
  */
1474
- @action setTheme(style: Partial<LogicFlow.Theme>) {
1475
- this.theme = updateTheme({ ...this.theme, ...style })
1482
+ @action setTheme(
1483
+ style: Partial<LogicFlow.Theme>,
1484
+ themeMode?: 'radius' | 'dark' | 'colorful' | 'default' | string,
1485
+ ) {
1486
+ if (themeMode) {
1487
+ // 修改背景颜色
1488
+ backgroundModeMap[themeMode] &&
1489
+ this.updateBackgroundOptions({
1490
+ ...(typeof this.background === 'object' ? this.background : {}),
1491
+ ...backgroundModeMap[themeMode],
1492
+ })
1493
+ gridModeMap[themeMode] &&
1494
+ this.updateGridOptions(
1495
+ Grid.getGridOptions({ ...this.grid, ...gridModeMap[themeMode] }),
1496
+ )
1497
+ }
1498
+ if (style.background) {
1499
+ this.updateBackgroundOptions(style.background)
1500
+ }
1501
+ if (style.grid) {
1502
+ const formattedGrid = Grid.getGridOptions(style.grid ?? false)
1503
+ this.updateGridOptions(formattedGrid)
1504
+ }
1505
+ this.theme = updateTheme({ ...this.customStyles, ...style }, themeMode)
1506
+ this.customStyles = { ...this.customStyles, ...style }
1507
+ }
1508
+
1509
+ /**
1510
+ * 设置主题
1511
+ * todo docs link
1512
+ */
1513
+ @action getTheme() {
1514
+ const { background, grid } = this
1515
+ const theme = {
1516
+ ...cloneDeep(this.theme),
1517
+ background,
1518
+ grid,
1519
+ }
1520
+ return theme
1476
1521
  }
1477
1522
 
1478
1523
  /**
@@ -1,4 +1,4 @@
1
- export * from './BaseEdgeModel';
2
- export * from './BezierEdgeModel';
3
- export * from './LineEdgeModel';
4
- export * from './PolylineEdgeModel';
1
+ export * from './BaseEdgeModel'
2
+ export * from './BezierEdgeModel'
3
+ export * from './LineEdgeModel'
4
+ export * from './PolylineEdgeModel'
@@ -1,8 +1,8 @@
1
- export * from './edge';
2
- export * from './node';
1
+ export * from './edge'
2
+ export * from './node'
3
3
 
4
- export * from './BaseModel';
5
- export * from './EditConfigModel';
6
- export * from './GraphModel';
7
- export * from './SnaplineModel';
8
- export * from './TransformModel';
4
+ export * from './BaseModel'
5
+ export * from './EditConfigModel'
6
+ export * from './GraphModel'
7
+ export * from './SnaplineModel'
8
+ export * from './TransformModel'
@@ -36,11 +36,12 @@ export class RectNodeModel<
36
36
  super.setAttributes()
37
37
 
38
38
  const { width, height, radius } = this.properties
39
+ const { radius: styleRadius } = this.getNodeStyle()
39
40
  if (!isNil(width)) this.width = width
40
41
  if (!isNil(height)) this.height = height
41
-
42
42
  // 矩形特有
43
43
  if (!isNil(radius)) this.radius = radius
44
+ if (!isNil(styleRadius)) this.radius = styleRadius
44
45
  }
45
46
 
46
47
  getDefaultAnchor() {
@@ -1,8 +1,8 @@
1
- export * from './BaseNodeModel';
2
- export * from './CircleNodeModel';
3
- export * from './DiamondNodeModel';
4
- export * from './EllipseNodeModel';
5
- export * from './PolygonNodeModel';
6
- export * from './RectNodeModel';
7
- export * from './TextNodeModel';
8
- export * from './HtmlNodeModel';
1
+ export * from './BaseNodeModel'
2
+ export * from './CircleNodeModel'
3
+ export * from './DiamondNodeModel'
4
+ export * from './EllipseNodeModel'
5
+ export * from './PolygonNodeModel'
6
+ export * from './RectNodeModel'
7
+ export * from './TextNodeModel'
8
+ export * from './HtmlNodeModel'
package/src/options.ts CHANGED
@@ -102,6 +102,7 @@ export namespace Options {
102
102
  edgeGenerator?: EdgeGeneratorType
103
103
 
104
104
  customTrajectory?: (props: CustomAnchorLineProps) => h.JSX.Element
105
+ themeMode?: 'radius' | 'dark' | 'colorful' // 主题模式
105
106
  [key: string]: unknown
106
107
  }
107
108
 
package/src/util/theme.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { cloneDeep, merge } from 'lodash-es'
1
+ import { cloneDeep, merge, assign } from 'lodash-es'
2
2
  import LogicFlow from '../LogicFlow'
3
3
 
4
4
  export const defaultTheme: LogicFlow.Theme = {
@@ -135,13 +135,178 @@ export const defaultTheme: LogicFlow.Theme = {
135
135
  strokeDasharray: '3,3',
136
136
  },
137
137
  }
138
+ export const radiusMode: any = {
139
+ rect: { radius: 8 },
140
+ diamond: { radius: 8 },
141
+ polygon: { radius: 8 },
142
+ polyline: { radius: 8 },
143
+ arrow: {
144
+ strokeLinecap: 'round',
145
+ strokeLinejoin: 'round',
146
+ offset: 10,
147
+ verticalLength: 5, // 箭头垂直于边的距离
148
+ },
149
+ snapline: {
150
+ strokeLinecap: 'round',
151
+ strokeLinejoin: 'round',
152
+ stroke: '#949494',
153
+ strokeWidth: 1,
154
+ },
155
+ outline: {
156
+ radius: 8,
157
+ fill: 'transparent',
158
+ stroke: '#949494',
159
+ strokeDasharray: '3,3',
160
+ hover: {
161
+ stroke: '#949494',
162
+ },
163
+ },
164
+ resizeOutline: {
165
+ radius: 8,
166
+ fill: 'none',
167
+ stroke: 'transparent', // 矩形默认不显示调整边框
168
+ strokeWidth: 1,
169
+ strokeDasharray: '3,3',
170
+ },
171
+ }
172
+ export const darkMode: any = {
173
+ baseNode: {
174
+ fill: '#23272e',
175
+ stroke: '#fefeff',
176
+ },
177
+ baseEdge: {
178
+ stroke: '#fefeff',
179
+ },
180
+ rect: { radius: 8 },
181
+ diamond: { radius: 8 },
182
+ polygon: { radius: 8 },
183
+ polyline: { radius: 8 },
184
+ nodeText: {
185
+ color: '#fefeff',
186
+ overflowMode: 'default',
187
+ fontSize: 12,
188
+ lineHeight: 1.2,
189
+ },
190
+ arrow: {
191
+ strokeLinecap: 'round',
192
+ strokeLinejoin: 'round',
193
+ offset: 10,
194
+ verticalLength: 5, // 箭头垂直于边的距离
195
+ },
196
+ snapline: {
197
+ strokeLinecap: 'round',
198
+ strokeLinejoin: 'round',
199
+ stroke: '#949494',
200
+ strokeWidth: 1,
201
+ },
202
+ outline: {
203
+ radius: 8,
204
+ fill: 'transparent',
205
+ stroke: '#949494',
206
+ strokeDasharray: '3,3',
207
+ hover: {
208
+ stroke: '#949494',
209
+ },
210
+ },
211
+ resizeOutline: {
212
+ radius: 8,
213
+ fill: 'none',
214
+ stroke: 'transparent', // 矩形默认不显示调整边框
215
+ strokeWidth: 1,
216
+ strokeDasharray: '3,3',
217
+ },
218
+ }
219
+ export const colorfulMode: any = {
220
+ rect: { fill: '#72CBFF', stroke: '#3ABDF9', radius: 8 },
221
+ circle: { fill: '#FFE075', stroke: '#F9CE3A', radius: 8 },
222
+ ellipse: { fill: '#FFA8A8', stroke: '#FF6B66', radius: 8 },
223
+ text: { fill: '#72CBFF', radius: 8 },
224
+ diamond: { fill: '#96F7AF', stroke: '#40EF7E', radius: 8 },
225
+ polygon: { fill: '#E0A8FF', stroke: '#C271FF', radius: 8 },
226
+ polyline: { radius: 8 },
227
+ arrow: {
228
+ strokeLinecap: 'round',
229
+ strokeLinejoin: 'round',
230
+ offset: 10,
231
+ verticalLength: 5, // 箭头垂直于边的距离
232
+ },
233
+ snapline: {
234
+ strokeLinecap: 'round',
235
+ strokeLinejoin: 'round',
236
+ stroke: '#949494',
237
+ strokeWidth: 1,
238
+ },
239
+ outline: {
240
+ radius: 8,
241
+ fill: 'transparent',
242
+ stroke: '#949494',
243
+ strokeDasharray: '3,3',
244
+ hover: {
245
+ stroke: '#949494',
246
+ },
247
+ },
248
+ resizeOutline: {
249
+ radius: 8,
250
+ fill: 'none',
251
+ stroke: 'transparent', // 矩形默认不显示调整边框
252
+ strokeWidth: 1,
253
+ strokeDasharray: '3,3',
254
+ },
255
+ }
256
+
257
+ export const themeModeMap = {
258
+ colorful: colorfulMode,
259
+ dark: darkMode,
260
+ radius: radiusMode,
261
+ default: defaultTheme,
262
+ }
263
+
264
+ // 不同主题的背景色
265
+ export const darkBackground = {
266
+ background: '#23272e',
267
+ }
268
+ export const colorfulBackground = {
269
+ background: '#fefeff',
270
+ }
271
+ export const defaultBackground = {
272
+ background: '#ffffff',
273
+ }
274
+ export const backgroundModeMap = {
275
+ colorful: colorfulBackground,
276
+ dark: darkBackground,
277
+ radius: defaultBackground,
278
+ default: defaultBackground,
279
+ }
280
+
281
+ // 不同主题的网格样式
282
+ export const darkGrid = {
283
+ color: '#66676a',
284
+ thickness: 1,
285
+ }
286
+ export const colorfulGrid = {
287
+ color: '#dadada',
288
+ thickness: 1,
289
+ }
290
+ export const defaultGrid = {
291
+ color: '#acacac',
292
+ thickness: 1,
293
+ }
294
+ export const gridModeMap = {
295
+ colorful: colorfulGrid,
296
+ dark: darkGrid,
297
+ radius: defaultGrid,
298
+ default: defaultGrid,
299
+ }
138
300
 
139
301
  /* 主题(全局样式)相关工具方法 */
140
302
  export const setupTheme = (
141
303
  customTheme?: Partial<LogicFlow.Theme>,
304
+ themeMode?: 'radius' | 'dark' | 'colorful' | 'default' | string,
142
305
  ): LogicFlow.Theme => {
143
306
  let theme = cloneDeep(defaultTheme)
144
-
307
+ if (themeMode) {
308
+ theme = merge(theme, themeModeMap[themeMode])
309
+ }
145
310
  if (customTheme) {
146
311
  /**
147
312
  * 为了不让默认样式被覆盖,使用 merge 方法
@@ -172,9 +337,39 @@ export const setupTheme = (
172
337
  */
173
338
  theme = merge(theme, customTheme)
174
339
  }
175
-
176
340
  return theme
177
341
  }
178
342
 
343
+ export const addThemeMode = (
344
+ themeMode: string,
345
+ style: Partial<LogicFlow.Theme>,
346
+ ): void => {
347
+ if (themeModeMap[themeMode]) {
348
+ console.warn(`theme mode ${themeMode} already exists`)
349
+ return
350
+ }
351
+ themeModeMap[themeMode] = style
352
+ backgroundModeMap[themeMode] = style.background || defaultBackground
353
+ gridModeMap[themeMode] = style.grid || defaultGrid
354
+ }
355
+
356
+ export const removeThemeMode = (themeMode: string): void => {
357
+ delete themeModeMap[themeMode]
358
+ delete backgroundModeMap[themeMode]
359
+ delete gridModeMap[themeMode]
360
+ }
361
+
362
+ export const clearThemeMode = (): void => {
363
+ const resetTheme = {
364
+ colorful: {},
365
+ dark: {},
366
+ radius: {},
367
+ default: {},
368
+ }
369
+ assign(themeModeMap, resetTheme)
370
+ assign(backgroundModeMap, resetTheme)
371
+ assign(gridModeMap, resetTheme)
372
+ }
373
+
179
374
  /* 更新 theme 方法 */
180
375
  export const updateTheme = setupTheme