@meta2d/core 1.0.56 → 1.0.58

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 (299) hide show
  1. package/{index.ts → index.d.ts} +9 -9
  2. package/index.js +10 -0
  3. package/index.js.map +1 -0
  4. package/package.json +38 -39
  5. package/src/canvas/canvas.d.ts +456 -0
  6. package/src/canvas/canvas.js +7584 -0
  7. package/src/canvas/canvas.js.map +1 -0
  8. package/src/canvas/canvasImage.d.ts +27 -0
  9. package/src/canvas/canvasImage.js +441 -0
  10. package/src/canvas/canvasImage.js.map +1 -0
  11. package/src/canvas/canvasTemplate.d.ts +18 -0
  12. package/src/canvas/canvasTemplate.js +209 -0
  13. package/src/canvas/canvasTemplate.js.map +1 -0
  14. package/src/canvas/{index.ts → index.d.ts} +2 -2
  15. package/src/canvas/index.js +3 -0
  16. package/src/canvas/index.js.map +1 -0
  17. package/src/canvas/magnifierCanvas.d.ts +19 -0
  18. package/src/canvas/magnifierCanvas.js +102 -0
  19. package/src/canvas/magnifierCanvas.js.map +1 -0
  20. package/src/canvas/offscreen.d.ts +1 -0
  21. package/src/canvas/offscreen.js +14 -0
  22. package/src/canvas/offscreen.js.map +1 -0
  23. package/src/core.d.ts +479 -0
  24. package/src/core.js +4609 -0
  25. package/src/core.js.map +1 -0
  26. package/src/data.d.ts +34 -0
  27. package/src/data.js +85 -0
  28. package/src/data.js.map +1 -0
  29. package/src/diagrams/arrow.d.ts +4 -0
  30. package/src/diagrams/arrow.js +47 -0
  31. package/src/diagrams/arrow.js.map +1 -0
  32. package/src/diagrams/circle.d.ts +2 -0
  33. package/src/diagrams/circle.js +9 -0
  34. package/src/diagrams/circle.js.map +1 -0
  35. package/src/diagrams/cloud.d.ts +2 -0
  36. package/src/diagrams/cloud.js +12 -0
  37. package/src/diagrams/cloud.js.map +1 -0
  38. package/src/diagrams/cube.d.ts +2 -0
  39. package/src/diagrams/cube.js +68 -0
  40. package/src/diagrams/cube.js.map +1 -0
  41. package/src/diagrams/diamond.d.ts +2 -0
  42. package/src/diagrams/diamond.js +13 -0
  43. package/src/diagrams/diamond.js.map +1 -0
  44. package/src/diagrams/file.d.ts +2 -0
  45. package/src/diagrams/file.js +18 -0
  46. package/src/diagrams/file.js.map +1 -0
  47. package/src/diagrams/gif.d.ts +5 -0
  48. package/src/diagrams/gif.js +89 -0
  49. package/src/diagrams/gif.js.map +1 -0
  50. package/src/diagrams/hexagon.d.ts +2 -0
  51. package/src/diagrams/{hexagon.ts → hexagon.js} +55 -60
  52. package/src/diagrams/hexagon.js.map +1 -0
  53. package/src/diagrams/iframe.d.ts +2 -0
  54. package/src/diagrams/iframe.js +338 -0
  55. package/src/diagrams/iframe.js.map +1 -0
  56. package/src/diagrams/index.d.ts +71 -0
  57. package/src/diagrams/{index.ts → index.js} +77 -79
  58. package/src/diagrams/index.js.map +1 -0
  59. package/src/diagrams/line/arrow.d.ts +2 -0
  60. package/src/diagrams/line/arrow.js +128 -0
  61. package/src/diagrams/line/arrow.js.map +1 -0
  62. package/src/diagrams/line/curve.d.ts +16 -0
  63. package/src/diagrams/line/curve.js +227 -0
  64. package/src/diagrams/line/curve.js.map +1 -0
  65. package/src/diagrams/line/{index.ts → index.d.ts} +5 -5
  66. package/src/diagrams/line/index.js +6 -0
  67. package/src/diagrams/line/index.js.map +1 -0
  68. package/src/diagrams/line/line.d.ts +42 -0
  69. package/src/diagrams/line/line.js +375 -0
  70. package/src/diagrams/line/line.js.map +1 -0
  71. package/src/diagrams/line/polyline.d.ts +10 -0
  72. package/src/diagrams/line/polyline.js +627 -0
  73. package/src/diagrams/line/polyline.js.map +1 -0
  74. package/src/diagrams/line/smooth.d.ts +3 -0
  75. package/src/diagrams/line/smooth.js +136 -0
  76. package/src/diagrams/line/smooth.js.map +1 -0
  77. package/src/diagrams/message.d.ts +2 -0
  78. package/src/diagrams/message.js +15 -0
  79. package/src/diagrams/message.js.map +1 -0
  80. package/src/diagrams/mindLine.d.ts +3 -0
  81. package/src/diagrams/mindLine.js +30 -0
  82. package/src/diagrams/mindLine.js.map +1 -0
  83. package/src/diagrams/mindNode.d.ts +3 -0
  84. package/src/diagrams/mindNode.js +161 -0
  85. package/src/diagrams/mindNode.js.map +1 -0
  86. package/src/diagrams/panel.d.ts +2 -0
  87. package/src/diagrams/panel.js +131 -0
  88. package/src/diagrams/panel.js.map +1 -0
  89. package/src/diagrams/pentagon.d.ts +3 -0
  90. package/src/diagrams/pentagon.js +45 -0
  91. package/src/diagrams/pentagon.js.map +1 -0
  92. package/src/diagrams/pentagram.d.ts +3 -0
  93. package/src/diagrams/pentagram.js +51 -0
  94. package/src/diagrams/pentagram.js.map +1 -0
  95. package/src/diagrams/people.d.ts +2 -0
  96. package/src/diagrams/people.js +19 -0
  97. package/src/diagrams/people.js.map +1 -0
  98. package/src/diagrams/rectangle.d.ts +3 -0
  99. package/src/diagrams/rectangle.js +27 -0
  100. package/src/diagrams/rectangle.js.map +1 -0
  101. package/src/diagrams/svg/parse.d.ts +15 -0
  102. package/src/diagrams/svg/parse.js +279 -0
  103. package/src/diagrams/svg/parse.js.map +1 -0
  104. package/src/diagrams/svgPath.d.ts +2 -0
  105. package/src/diagrams/svgPath.js +29 -0
  106. package/src/diagrams/svgPath.js.map +1 -0
  107. package/src/diagrams/triangle.d.ts +3 -0
  108. package/src/diagrams/triangle.js +40 -0
  109. package/src/diagrams/triangle.js.map +1 -0
  110. package/src/diagrams/video.d.ts +5 -0
  111. package/src/diagrams/video.js +184 -0
  112. package/src/diagrams/video.js.map +1 -0
  113. package/src/dialog/dialog.d.ts +21 -0
  114. package/src/dialog/dialog.js +157 -0
  115. package/src/dialog/dialog.js.map +1 -0
  116. package/src/dialog/{index.ts → index.d.ts} +1 -1
  117. package/src/dialog/index.js +2 -0
  118. package/src/dialog/index.js.map +1 -0
  119. package/src/event/event.d.ts +102 -0
  120. package/src/event/event.js +22 -0
  121. package/src/event/event.js.map +1 -0
  122. package/src/event/{index.ts → index.d.ts} +1 -1
  123. package/src/event/index.js +2 -0
  124. package/src/event/index.js.map +1 -0
  125. package/src/map/{index.ts → index.d.ts} +1 -1
  126. package/src/map/index.js +2 -0
  127. package/src/map/index.js.map +1 -0
  128. package/src/map/map.d.ts +21 -0
  129. package/src/map/map.js +212 -0
  130. package/src/map/map.js.map +1 -0
  131. package/src/options.d.ts +130 -0
  132. package/src/options.js +80 -0
  133. package/src/options.js.map +1 -0
  134. package/src/pen/arrow.d.ts +4 -0
  135. package/src/pen/arrow.js +188 -0
  136. package/src/pen/arrow.js.map +1 -0
  137. package/src/pen/{index.ts → index.d.ts} +6 -6
  138. package/src/pen/index.js +7 -0
  139. package/src/pen/index.js.map +1 -0
  140. package/src/pen/math.d.ts +28 -0
  141. package/src/pen/math.js +213 -0
  142. package/src/pen/math.js.map +1 -0
  143. package/src/pen/model.d.ts +514 -0
  144. package/src/pen/model.js +210 -0
  145. package/src/pen/model.js.map +1 -0
  146. package/src/pen/plugin.d.ts +5 -0
  147. package/src/pen/plugin.js +58 -0
  148. package/src/pen/plugin.js.map +1 -0
  149. package/src/pen/render.d.ts +146 -0
  150. package/src/pen/render.js +3234 -0
  151. package/src/pen/render.js.map +1 -0
  152. package/src/pen/text.d.ts +8 -0
  153. package/src/pen/text.js +314 -0
  154. package/src/pen/text.js.map +1 -0
  155. package/src/pen/utils.d.ts +2 -0
  156. package/src/pen/utils.js +19 -0
  157. package/src/pen/utils.js.map +1 -0
  158. package/src/point/{index.ts → index.d.ts} +1 -1
  159. package/src/point/index.js +2 -0
  160. package/src/point/index.js.map +1 -0
  161. package/src/point/point.d.ts +65 -0
  162. package/src/point/point.js +178 -0
  163. package/src/point/point.js.map +1 -0
  164. package/src/rect/{index.ts → index.d.ts} +1 -1
  165. package/src/rect/index.js +2 -0
  166. package/src/rect/index.js.map +1 -0
  167. package/src/rect/rect.d.ts +52 -0
  168. package/src/rect/rect.js +427 -0
  169. package/src/rect/rect.js.map +1 -0
  170. package/src/rect/triangle.d.ts +2 -0
  171. package/src/rect/triangle.js +10 -0
  172. package/src/rect/triangle.js.map +1 -0
  173. package/src/scroll/{index.ts → index.d.ts} +1 -1
  174. package/src/scroll/index.js +2 -0
  175. package/src/scroll/index.js.map +1 -0
  176. package/src/scroll/scroll.d.ts +35 -0
  177. package/src/scroll/scroll.js +234 -0
  178. package/src/scroll/scroll.js.map +1 -0
  179. package/src/store/global.d.ts +25 -0
  180. package/src/store/global.js +18 -0
  181. package/src/store/global.js.map +1 -0
  182. package/src/store/{index.ts → index.d.ts} +2 -2
  183. package/src/store/index.js +3 -0
  184. package/src/store/index.js.map +1 -0
  185. package/src/store/store.d.ts +228 -0
  186. package/src/store/store.js +87 -0
  187. package/src/store/store.js.map +1 -0
  188. package/src/theme.d.ts +13 -0
  189. package/src/theme.js +23 -0
  190. package/src/theme.js.map +1 -0
  191. package/src/title/{index.ts → index.d.ts} +1 -1
  192. package/src/title/index.js +2 -0
  193. package/src/title/index.js.map +1 -0
  194. package/src/title/title.d.ts +30 -0
  195. package/src/title/title.js +99 -0
  196. package/src/title/title.js.map +1 -0
  197. package/src/tooltip/{index.ts → index.d.ts} +1 -1
  198. package/src/tooltip/index.js +2 -0
  199. package/src/tooltip/index.js.map +1 -0
  200. package/src/tooltip/tooltip.d.ts +40 -0
  201. package/src/tooltip/tooltip.js +172 -0
  202. package/src/tooltip/tooltip.js.map +1 -0
  203. package/src/utils/clone.d.ts +8 -0
  204. package/src/utils/clone.js +84 -0
  205. package/src/utils/clone.js.map +1 -0
  206. package/src/utils/color.d.ts +3 -0
  207. package/src/utils/color.js +110 -0
  208. package/src/utils/color.js.map +1 -0
  209. package/src/utils/error.d.ts +2 -0
  210. package/src/utils/error.js +6 -0
  211. package/src/utils/error.js.map +1 -0
  212. package/src/utils/file.d.ts +3 -0
  213. package/src/utils/file.js +40 -0
  214. package/src/utils/file.js.map +1 -0
  215. package/src/utils/{index.ts → index.d.ts} +9 -9
  216. package/src/utils/index.js +10 -0
  217. package/src/utils/index.js.map +1 -0
  218. package/src/utils/math.d.ts +18 -0
  219. package/src/utils/math.js +114 -0
  220. package/src/utils/math.js.map +1 -0
  221. package/src/utils/object.d.ts +2 -0
  222. package/src/utils/object.js +21 -0
  223. package/src/utils/object.js.map +1 -0
  224. package/src/utils/padding.d.ts +7 -0
  225. package/src/utils/padding.js +47 -0
  226. package/src/utils/padding.js.map +1 -0
  227. package/src/utils/time.d.ts +1 -0
  228. package/src/utils/time.js +17 -0
  229. package/src/utils/time.js.map +1 -0
  230. package/src/utils/url.d.ts +4 -0
  231. package/src/utils/url.js +27 -0
  232. package/src/utils/url.js.map +1 -0
  233. package/src/utils/uuid.d.ts +4 -0
  234. package/src/utils/uuid.js +13 -0
  235. package/src/utils/uuid.js.map +1 -0
  236. package/README.md +0 -13
  237. package/package.build.json +0 -39
  238. package/src/canvas/canvas.ts +0 -8639
  239. package/src/canvas/canvasImage.ts +0 -525
  240. package/src/canvas/canvasTemplate.ts +0 -257
  241. package/src/canvas/magnifierCanvas.ts +0 -142
  242. package/src/canvas/offscreen.ts +0 -14
  243. package/src/core.ts +0 -5128
  244. package/src/data.ts +0 -86
  245. package/src/diagrams/arrow.ts +0 -50
  246. package/src/diagrams/circle.ts +0 -19
  247. package/src/diagrams/cloud.ts +0 -34
  248. package/src/diagrams/cube.ts +0 -94
  249. package/src/diagrams/diamond.ts +0 -14
  250. package/src/diagrams/file.ts +0 -19
  251. package/src/diagrams/gif.ts +0 -105
  252. package/src/diagrams/iframe.ts +0 -365
  253. package/src/diagrams/line/arrow.ts +0 -175
  254. package/src/diagrams/line/curve.ts +0 -260
  255. package/src/diagrams/line/line.ts +0 -409
  256. package/src/diagrams/line/polyline.ts +0 -676
  257. package/src/diagrams/line/smooth.ts +0 -133
  258. package/src/diagrams/message.ts +0 -17
  259. package/src/diagrams/mindLine.ts +0 -31
  260. package/src/diagrams/mindNode.ts +0 -177
  261. package/src/diagrams/panel.ts +0 -149
  262. package/src/diagrams/pentagon.ts +0 -48
  263. package/src/diagrams/pentagram.ts +0 -63
  264. package/src/diagrams/people.ts +0 -23
  265. package/src/diagrams/rectangle.ts +0 -29
  266. package/src/diagrams/svg/parse.ts +0 -319
  267. package/src/diagrams/svgPath.ts +0 -53
  268. package/src/diagrams/triangle.ts +0 -43
  269. package/src/diagrams/video.ts +0 -202
  270. package/src/dialog/dialog.ts +0 -177
  271. package/src/event/event.ts +0 -142
  272. package/src/map/map.ts +0 -239
  273. package/src/options.ts +0 -205
  274. package/src/pen/arrow.ts +0 -259
  275. package/src/pen/math.ts +0 -253
  276. package/src/pen/model.ts +0 -785
  277. package/src/pen/plugin.ts +0 -57
  278. package/src/pen/render.ts +0 -3725
  279. package/src/pen/text.ts +0 -341
  280. package/src/pen/utils.ts +0 -21
  281. package/src/point/point.ts +0 -232
  282. package/src/rect/rect.ts +0 -507
  283. package/src/rect/triangle.ts +0 -16
  284. package/src/scroll/scroll.ts +0 -277
  285. package/src/store/global.ts +0 -38
  286. package/src/store/store.ts +0 -293
  287. package/src/theme.ts +0 -35
  288. package/src/title/title.ts +0 -115
  289. package/src/tooltip/tooltip.ts +0 -199
  290. package/src/utils/clone.ts +0 -79
  291. package/src/utils/color.ts +0 -126
  292. package/src/utils/error.ts +0 -7
  293. package/src/utils/file.ts +0 -46
  294. package/src/utils/math.ts +0 -120
  295. package/src/utils/object.ts +0 -23
  296. package/src/utils/padding.ts +0 -48
  297. package/src/utils/time.ts +0 -25
  298. package/src/utils/url.ts +0 -30
  299. package/src/utils/uuid.ts +0 -15
@@ -0,0 +1,3234 @@
1
+ import { CanvasLayer, LineAnimateType, LockState, } from './model';
2
+ import { drawArrow, getLineRect, getSplitAnchor } from '../diagrams';
3
+ import { Direction, inheritanceProps } from '../data';
4
+ import { calcRotate, distance, facePoint, rotatePoint, scalePoint, translatePoint, TwoWay, } from '../point';
5
+ import { calcCenter, calcRightBottom, calcRelativePoint, calcRelativeRect, rectInRect, scaleRect, translateRect, calcPivot, } from '../rect';
6
+ import { globalStore } from '../store';
7
+ import { calcTextLines, calcTextDrawRect, calcTextRect } from './text';
8
+ import { deepClone } from '../utils/clone';
9
+ import { renderFromArrow, renderToArrow } from './arrow';
10
+ import { Gradient, PenType } from '../pen';
11
+ import { pSBC, rgba } from '../utils';
12
+ /**
13
+ * ancestor 是否是 pen 的祖先
14
+ * @param pen 当前画笔
15
+ * @param ancestor 祖先画笔
16
+ */
17
+ export function isAncestor(pen, ancestor) {
18
+ if (!pen || !ancestor) {
19
+ return false;
20
+ }
21
+ let parent = getParent(pen);
22
+ while (parent) {
23
+ if (parent.id === ancestor.id) {
24
+ return true;
25
+ }
26
+ parent = getParent(parent);
27
+ }
28
+ return false;
29
+ }
30
+ export function getParent(pen, root) {
31
+ if (!pen || !pen.parentId || !pen.calculative) {
32
+ return undefined;
33
+ }
34
+ const store = pen.calculative.canvas.store;
35
+ const parent = store.pens[pen.parentId];
36
+ if (!root) {
37
+ return parent;
38
+ }
39
+ return getParent(parent, root) || parent;
40
+ }
41
+ export function getAllChildren(pen, store) {
42
+ if (!pen || !pen.children) {
43
+ return [];
44
+ }
45
+ const children = [];
46
+ pen.children.forEach((id) => {
47
+ const child = store.pens[id];
48
+ if (child) {
49
+ children.push(child);
50
+ children.push(...getAllChildren(child, store));
51
+ }
52
+ });
53
+ return children;
54
+ }
55
+ export function getAllFollowers(pen, store) {
56
+ if (!pen || !pen.followers) {
57
+ return [];
58
+ }
59
+ const followers = [];
60
+ pen.followers.forEach((id) => {
61
+ const follower = store.pens[id];
62
+ if (follower && !follower.parentId) {
63
+ followers.push(follower);
64
+ followers.push(...getAllFollowers(follower, store));
65
+ }
66
+ });
67
+ return followers;
68
+ }
69
+ function drawBkLinearGradient(ctx, pen) {
70
+ const { worldRect, gradientFromColor, gradientToColor, gradientAngle } = pen.calculative;
71
+ return linearGradient(ctx, worldRect, gradientFromColor, gradientToColor, gradientAngle);
72
+ }
73
+ /**
74
+ * 避免副作用,把创建好后的径向渐变对象返回出来
75
+ * @param ctx 画布绘制对象
76
+ * @param pen 当前画笔
77
+ * @returns 径向渐变
78
+ */
79
+ function drawBkRadialGradient(ctx, pen) {
80
+ const { worldRect, gradientFromColor, gradientToColor, gradientRadius } = pen.calculative;
81
+ if (!gradientFromColor || !gradientToColor) {
82
+ return;
83
+ }
84
+ const { width, height, center } = worldRect;
85
+ const { x: centerX, y: centerY } = center;
86
+ let r = width;
87
+ if (r < height) {
88
+ r = height;
89
+ }
90
+ r *= 0.5;
91
+ const grd = ctx.createRadialGradient(centerX, centerY, r * (gradientRadius || 0), centerX, centerY, r);
92
+ grd.addColorStop(0, gradientFromColor);
93
+ grd.addColorStop(1, gradientToColor);
94
+ return grd;
95
+ }
96
+ function getLinearGradientPoints(x1, y1, x2, y2, r) {
97
+ let slantAngle = 0;
98
+ slantAngle = Math.PI / 2 - Math.atan2(y2 - y1, x2 - x1);
99
+ const originX = (x1 + x2) / 2;
100
+ const originY = (y1 + y2) / 2;
101
+ const perpX1 = originX + r * Math.sin((90 * Math.PI) / 180 - slantAngle);
102
+ const perpY1 = originY + r * -Math.cos((90 * Math.PI) / 180 - slantAngle);
103
+ const perpX2 = originX + r * Math.sin((270 * Math.PI) / 180 - slantAngle);
104
+ const perpY2 = originY + r * -Math.cos((270 * Math.PI) / 180 - slantAngle);
105
+ return [perpX1, perpY1, perpX2, perpY2];
106
+ }
107
+ function getBkRadialGradient(ctx, pen) {
108
+ const { worldRect, gradientColors, gradientRadius } = pen.calculative;
109
+ if (!gradientColors) {
110
+ return;
111
+ }
112
+ const { width, height, center } = worldRect;
113
+ const { x: centerX, y: centerY } = center;
114
+ let r = width;
115
+ if (r < height) {
116
+ r = height;
117
+ }
118
+ r *= 0.5;
119
+ const { colors } = formatGradient(gradientColors);
120
+ const grd = ctx.createRadialGradient(centerX, centerY, r * (gradientRadius || 0), centerX, centerY, r);
121
+ colors.forEach((stop) => {
122
+ grd.addColorStop(stop.i, stop.color);
123
+ });
124
+ return grd;
125
+ }
126
+ function getBkGradient(ctx, pen) {
127
+ const { x, y, ex, width, height, center } = pen.calculative.worldRect;
128
+ let points = [
129
+ { x: ex, y: y + height / 2 },
130
+ { x: x, y: y + height / 2 },
131
+ ];
132
+ const { angle, colors } = formatGradient(pen.calculative.gradientColors);
133
+ let r = getGradientR(angle, width, height);
134
+ points.forEach((point) => {
135
+ rotatePoint(point, angle, center);
136
+ });
137
+ return getLinearGradient(ctx, points, colors, r);
138
+ }
139
+ function getTextRadialGradient(ctx, pen) {
140
+ const { worldRect, textGradientColors } = pen.calculative;
141
+ if (!textGradientColors) {
142
+ return;
143
+ }
144
+ const { width, height, center } = worldRect;
145
+ const { x: centerX, y: centerY } = center;
146
+ let r = width;
147
+ if (r < height) {
148
+ r = height;
149
+ }
150
+ r *= 0.5;
151
+ const { colors } = formatGradient(textGradientColors);
152
+ const grd = ctx.createRadialGradient(centerX, centerY, 0, centerX, centerY, r);
153
+ colors.forEach((stop) => {
154
+ grd.addColorStop(stop.i, stop.color);
155
+ });
156
+ return grd;
157
+ }
158
+ function getTextGradient(ctx, pen) {
159
+ const { x, y, ex, width, height, center } = pen.calculative.worldRect;
160
+ let points = [
161
+ { x: ex, y: y + height / 2 },
162
+ { x: x, y: y + height / 2 },
163
+ ];
164
+ const { angle, colors } = formatGradient(pen.calculative.textGradientColors);
165
+ let r = getGradientR(angle, width, height);
166
+ points.forEach((point) => {
167
+ rotatePoint(point, angle, center);
168
+ });
169
+ return getLinearGradient(ctx, points, colors, r);
170
+ }
171
+ function getGradientR(angle, width, height) {
172
+ const dividAngle = (Math.atan(height / width) / Math.PI) * 180;
173
+ let calculateAngle = (angle - 90) % 360;
174
+ let r = 0;
175
+ if ((calculateAngle > dividAngle && calculateAngle < 180 - dividAngle) ||
176
+ (calculateAngle > 180 + dividAngle && calculateAngle < 360 - dividAngle) ||
177
+ calculateAngle < 0) {
178
+ //根据高计算
179
+ if (calculateAngle > 270) {
180
+ calculateAngle = 360 - calculateAngle;
181
+ }
182
+ else if (calculateAngle > 180) {
183
+ calculateAngle = calculateAngle - 180;
184
+ }
185
+ else if (calculateAngle > 90) {
186
+ calculateAngle = 180 - calculateAngle;
187
+ }
188
+ r = Math.abs(height / Math.sin((calculateAngle / 180) * Math.PI) / 2);
189
+ }
190
+ else {
191
+ //根据宽计算
192
+ if (calculateAngle > 270) {
193
+ calculateAngle = 360 - calculateAngle;
194
+ }
195
+ else if (calculateAngle > 180) {
196
+ calculateAngle = calculateAngle - 180;
197
+ }
198
+ else if (calculateAngle > 90) {
199
+ calculateAngle = 180 - calculateAngle;
200
+ }
201
+ r = Math.abs(width / Math.cos((calculateAngle / 180) * Math.PI) / 2);
202
+ }
203
+ return r;
204
+ }
205
+ function formatGradient(color) {
206
+ if (typeof color == 'string' && color.startsWith('linear-gradient')) {
207
+ let arr = color.slice(16, -2).split('deg,');
208
+ if (arr.length > 1) {
209
+ let _arr = arr[1].split('%,');
210
+ const colors = [];
211
+ _arr.forEach((stap) => {
212
+ if (/rgba?/.test(stap)) {
213
+ let _arr = stap.split(') ');
214
+ colors.push({
215
+ color: rgbaToHex(_arr[0] + ')'),
216
+ i: parseFloat(_arr[1]) / 100,
217
+ });
218
+ }
219
+ else {
220
+ let _arr = stap.split(' ');
221
+ if (_arr.length > 2) {
222
+ colors.push({
223
+ color: _arr[1],
224
+ i: parseFloat(_arr[2]) / 100,
225
+ });
226
+ }
227
+ else {
228
+ colors.push({
229
+ color: _arr[0],
230
+ i: parseFloat(_arr[1]) / 100,
231
+ });
232
+ }
233
+ }
234
+ });
235
+ return {
236
+ angle: parseFloat(arr[0]),
237
+ colors,
238
+ };
239
+ }
240
+ else {
241
+ return {
242
+ angle: parseFloat(arr[0]),
243
+ colors: [],
244
+ };
245
+ }
246
+ }
247
+ else {
248
+ return {
249
+ angle: 0,
250
+ colors: [],
251
+ };
252
+ }
253
+ }
254
+ function rgbaToHex(value) {
255
+ if (/rgba?/.test(value)) {
256
+ let array = value.split(',');
257
+ //不符合rgb或rgb规则直接return
258
+ if (array.length < 3)
259
+ return '';
260
+ value = '#';
261
+ for (let i = 0, color; (color = array[i++]);) {
262
+ if (i < 4) {
263
+ //前三位转换成16进制
264
+ color = parseInt(color.replace(/[^\d]/gi, ''), 10).toString(16);
265
+ value += color.length == 1 ? '0' + color : color;
266
+ }
267
+ else {
268
+ //rgba的透明度转换成16进制
269
+ color = color.replace(')', '');
270
+ let colorA = parseInt(color * 255 + '');
271
+ let colorAHex = colorA.toString(16);
272
+ colorAHex = colorAHex.length === 2 ? colorAHex : '0' + colorAHex;
273
+ value += colorAHex;
274
+ }
275
+ }
276
+ value = value.toUpperCase();
277
+ }
278
+ return value;
279
+ }
280
+ function getLineGradient(ctx, pen) {
281
+ const { x, y, ex, width, height, center } = pen.calculative.worldRect;
282
+ let points = [
283
+ { x: ex, y: y + height / 2 },
284
+ { x: x, y: y + height / 2 },
285
+ ];
286
+ const { angle, colors } = formatGradient(pen.calculative.lineGradientColors);
287
+ let r = getGradientR(angle, width, height);
288
+ points.forEach((point) => {
289
+ rotatePoint(point, angle, center);
290
+ });
291
+ return getLinearGradient(ctx, points, colors, r);
292
+ }
293
+ function getLinearGradient(ctx, points, colors, radius) {
294
+ let arr = getLinearGradientPoints(points[0].x, points[0].y, points[1].x, points[1].y, radius);
295
+ let gradient = ctx.createLinearGradient(arr[0], arr[1], arr[2], arr[3]);
296
+ colors.forEach((stop) => {
297
+ gradient.addColorStop(stop.i, stop.color);
298
+ });
299
+ return gradient;
300
+ }
301
+ function drawLinearGradientLine(ctx, pen, points) {
302
+ let colors = [];
303
+ if (pen.calculative.gradientColorStop) {
304
+ colors = pen.calculative.gradientColorStop;
305
+ }
306
+ else {
307
+ colors = formatGradient(pen.calculative.lineGradientColors).colors;
308
+ pen.calculative.gradientColorStop = colors;
309
+ }
310
+ ctx.strokeStyle = getLinearGradient(ctx, points, colors, pen.calculative.lineWidth / 2);
311
+ ctx.beginPath();
312
+ ctx.moveTo(points[0].x, points[0].y);
313
+ ctx.lineTo(points[1].x, points[1].y);
314
+ ctx.stroke();
315
+ }
316
+ function ctxDrawLinearGradientPath(ctx, pen) {
317
+ const anchors = pen.calculative.worldAnchors;
318
+ let smoothLenth = pen.calculative.lineWidth *
319
+ (pen.calculative.gradientSmooth || pen.calculative.lineSmooth || 0);
320
+ for (let i = 0; i < anchors.length - 1; i++) {
321
+ if ((pen.lineName === 'curve' || pen.lineName === 'mind') &&
322
+ anchors[i].curvePoints) {
323
+ if (i > 0) {
324
+ let lastCurvePoints = anchors[i - 1].curvePoints;
325
+ if (lastCurvePoints) {
326
+ //上一个存在锚点
327
+ smoothTransition(ctx, pen, smoothLenth, lastCurvePoints[lastCurvePoints.length - 1], anchors[i], anchors[i].curvePoints[0]);
328
+ }
329
+ else {
330
+ smoothTransition(ctx, pen, smoothLenth, anchors[i - 1], anchors[i], anchors[i].curvePoints[0]);
331
+ }
332
+ //获取当前相对于0的位置
333
+ let next = getSmoothAdjacent(smoothLenth, anchors[i], anchors[i].curvePoints[0]);
334
+ drawLinearGradientLine(ctx, pen, [next, anchors[i].curvePoints[1]]);
335
+ }
336
+ else {
337
+ drawLinearGradientLine(ctx, pen, [
338
+ anchors[i],
339
+ anchors[i].curvePoints[0],
340
+ ]);
341
+ drawLinearGradientLine(ctx, pen, [
342
+ anchors[i].curvePoints[0],
343
+ anchors[i].curvePoints[1],
344
+ ]);
345
+ }
346
+ let len = anchors[i].curvePoints.length - 1;
347
+ for (let j = 1; j < len; j++) {
348
+ drawLinearGradientLine(ctx, pen, [
349
+ anchors[i].curvePoints[j],
350
+ anchors[i].curvePoints[j + 1],
351
+ ]);
352
+ }
353
+ let last = getSmoothAdjacent(smoothLenth, anchors[i + 1], anchors[i].curvePoints[len]);
354
+ drawLinearGradientLine(ctx, pen, [anchors[i].curvePoints[len], last]);
355
+ }
356
+ else {
357
+ let _next = anchors[i];
358
+ let _last = anchors[i + 1];
359
+ if (i > 0 && i < anchors.length - 1) {
360
+ //有突兀的地方
361
+ let lastCurvePoints = anchors[i - 1].curvePoints;
362
+ if (lastCurvePoints) {
363
+ smoothTransition(ctx, pen, smoothLenth, lastCurvePoints[lastCurvePoints.length - 1], anchors[i], anchors[i + 1]);
364
+ }
365
+ else {
366
+ smoothTransition(ctx, pen, smoothLenth, anchors[i - 1], anchors[i], anchors[i + 1]);
367
+ }
368
+ }
369
+ if (i > 0 && i < anchors.length - 1) {
370
+ _next = getSmoothAdjacent(smoothLenth, anchors[i], anchors[i + 1]);
371
+ }
372
+ if (i < anchors.length - 2) {
373
+ _last = getSmoothAdjacent(smoothLenth, anchors[i + 1], anchors[i]);
374
+ }
375
+ let flag = false;
376
+ if (i === 0) {
377
+ if (pen.fromLineCap && pen.fromLineCap !== 'butt') {
378
+ ctx.save();
379
+ flag = true;
380
+ ctx.lineCap = pen.fromLineCap;
381
+ }
382
+ }
383
+ if (i !== 0 && i === anchors.length - 2) {
384
+ if (pen.toLineCap && pen.toLineCap !== 'butt') {
385
+ ctx.save();
386
+ flag = true;
387
+ ctx.lineCap = pen.toLineCap;
388
+ }
389
+ }
390
+ drawLinearGradientLine(ctx, pen, [_next, _last]);
391
+ if (flag) {
392
+ ctx.restore();
393
+ }
394
+ if (anchors.length === 2 && i === 0) {
395
+ ctx.save();
396
+ flag = true;
397
+ ctx.lineCap = pen.toLineCap;
398
+ let _y = 0.1;
399
+ let _x = 0.1;
400
+ if (_next.x - _last.x === 0) {
401
+ _x = 0;
402
+ }
403
+ else {
404
+ _y = ((_next.y - _last.y) / (_next.x - _last.x)) * 0.1;
405
+ }
406
+ drawLinearGradientLine(ctx, pen, [
407
+ { x: _last.x - _x, y: _last.y - _y },
408
+ _last,
409
+ ]);
410
+ ctx.restore();
411
+ }
412
+ }
413
+ }
414
+ }
415
+ function getSmoothAdjacent(smoothLenth, p1, p2) {
416
+ let nexLength = Math.sqrt((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y));
417
+ if (nexLength === 0) {
418
+ return {
419
+ x: p1.x,
420
+ y: p1.y,
421
+ };
422
+ }
423
+ if (smoothLenth < nexLength) {
424
+ return {
425
+ x: p1.x + ((p2.x - p1.x) * smoothLenth) / nexLength,
426
+ y: p1.y + ((p2.y - p1.y) * smoothLenth) / nexLength,
427
+ };
428
+ }
429
+ else {
430
+ return {
431
+ x: p1.x + (p2.x - p1.x) / nexLength / 2,
432
+ y: p1.y + (p2.y - p1.y) / nexLength / 2,
433
+ };
434
+ }
435
+ }
436
+ function smoothTransition(ctx, pen, smoothLenth, p1, p2, p3) {
437
+ let last = getSmoothAdjacent(smoothLenth, p2, p1);
438
+ let next = getSmoothAdjacent(smoothLenth, p2, p3);
439
+ let contrlPoint = { x: p2.x, y: p2.y };
440
+ let points = getBezierPoints(pen.calculative.canvas.store.data.smoothNum || 20, last, contrlPoint, next);
441
+ for (let k = 0; k < points.length - 1; k++) {
442
+ drawLinearGradientLine(ctx, pen, [
443
+ {
444
+ x: points[k].x,
445
+ y: points[k].y,
446
+ },
447
+ {
448
+ x: points[k + 1].x,
449
+ y: points[k + 1].y,
450
+ },
451
+ ]);
452
+ }
453
+ }
454
+ function smoothAnimateTransition(ctx, smoothLenth, p2, p3) {
455
+ let next = getSmoothAdjacent(smoothLenth, p2, p3);
456
+ let contrlPoint = { x: p2.x, y: p2.y };
457
+ ctx.quadraticCurveTo(contrlPoint.x, contrlPoint.y, next.x, next.y);
458
+ }
459
+ export function getGradientAnimatePath(pen) {
460
+ const anchors = pen.calculative.worldAnchors;
461
+ let smoothLenth = pen.calculative.lineWidth *
462
+ (pen.calculative.gradientSmooth || pen.calculative.lineSmooth || 0);
463
+ //只创建一次
464
+ const _path = new Path2D();
465
+ for (let i = 0; i < anchors.length - 1; i++) {
466
+ let _next = anchors[i];
467
+ let _last = anchors[i + 1];
468
+ if (i == 0) {
469
+ _path.moveTo(anchors[i].x, anchors[i].y);
470
+ }
471
+ if (i > 0 && i < anchors.length - 1) {
472
+ //有突兀的地方
473
+ let lastCurvePoints = anchors[i - 1].curvePoints;
474
+ // const path = new Path2D();
475
+ if (lastCurvePoints) {
476
+ smoothAnimateTransition(_path, smoothLenth, anchors[i], anchors[i + 1]);
477
+ }
478
+ else {
479
+ smoothAnimateTransition(_path, smoothLenth, anchors[i], anchors[i + 1]);
480
+ }
481
+ }
482
+ if (i > 0 && i < anchors.length - 1) {
483
+ _next = getSmoothAdjacent(smoothLenth, anchors[i], anchors[i + 1]);
484
+ }
485
+ if (i < anchors.length - 2) {
486
+ _last = getSmoothAdjacent(smoothLenth, anchors[i + 1], anchors[i]);
487
+ }
488
+ _path.lineTo(_last.x, _last.y);
489
+ }
490
+ return _path;
491
+ }
492
+ function getAngle(p1, p2, p3) {
493
+ let a = { x: 0, y: 0 }, b = { x: 0, y: 0 };
494
+ a.x = p1.x - p2.x;
495
+ a.y = p1.y - p2.y;
496
+ b.x = p3.x - p2.x;
497
+ b.y = p3.y - p2.y;
498
+ return ((Math.acos((a.x * b.x + a.y * b.y) /
499
+ (Math.sqrt(a.x * a.x + a.y * a.y) * Math.sqrt(b.x * b.x + b.y * b.y))) /
500
+ Math.PI) *
501
+ 180);
502
+ }
503
+ function getBezierPoints(num = 100, p1, p2, p3, p4) {
504
+ let func = null;
505
+ const points = [];
506
+ if (!p3 && !p4) {
507
+ func = oneBezier;
508
+ }
509
+ else if (p3 && !p4) {
510
+ func = twoBezier;
511
+ }
512
+ else if (p3 && p4) {
513
+ func = threeBezier;
514
+ }
515
+ for (let i = 0; i < num; i++) {
516
+ points.push(func(i / num, p1, p2, p3, p4));
517
+ }
518
+ if (p4) {
519
+ points.push(p4);
520
+ }
521
+ else if (p3) {
522
+ points.push(p3);
523
+ }
524
+ return points;
525
+ }
526
+ /**
527
+ * @desc 一阶贝塞尔
528
+ * @param t 当前百分比
529
+ * @param p1 起点坐标
530
+ * @param p2 终点坐标
531
+ */
532
+ function oneBezier(t, p1, p2) {
533
+ const { x: x1, y: y1 } = p1;
534
+ const { x: x2, y: y2 } = p2;
535
+ let x = x1 + (x2 - x1) * t;
536
+ let y = y1 + (y2 - y1) * t;
537
+ return { x, y };
538
+ }
539
+ /**
540
+ * @desc 二阶贝塞尔
541
+ * @param t 当前百分比
542
+ * @param p1 起点坐标
543
+ * @param p2 终点坐标
544
+ * @param cp 控制点
545
+ */
546
+ function twoBezier(t, p1, cp, p2) {
547
+ const { x: x1, y: y1 } = p1;
548
+ const { x: cx, y: cy } = cp;
549
+ const { x: x2, y: y2 } = p2;
550
+ let x = (1 - t) * (1 - t) * x1 + 2 * t * (1 - t) * cx + t * t * x2;
551
+ let y = (1 - t) * (1 - t) * y1 + 2 * t * (1 - t) * cy + t * t * y2;
552
+ return { x, y };
553
+ }
554
+ /**
555
+ * @desc 三阶贝塞尔
556
+ * @param t 当前百分比
557
+ * @param p1 起点坐标
558
+ * @param p2 终点坐标
559
+ * @param cp1 控制点1
560
+ * @param cp2 控制点2
561
+ */
562
+ function threeBezier(t, p1, cp1, cp2, p2) {
563
+ const { x: x1, y: y1 } = p1;
564
+ const { x: x2, y: y2 } = p2;
565
+ const { x: cx1, y: cy1 } = cp1;
566
+ const { x: cx2, y: cy2 } = cp2;
567
+ let x = x1 * (1 - t) * (1 - t) * (1 - t) +
568
+ 3 * cx1 * t * (1 - t) * (1 - t) +
569
+ 3 * cx2 * t * t * (1 - t) +
570
+ x2 * t * t * t;
571
+ let y = y1 * (1 - t) * (1 - t) * (1 - t) +
572
+ 3 * cy1 * t * (1 - t) * (1 - t) +
573
+ 3 * cy2 * t * t * (1 - t) +
574
+ y2 * t * t * t;
575
+ return { x, y };
576
+ }
577
+ function strokeLinearGradient(ctx, pen) {
578
+ const { worldRect, lineGradientFromColor, lineGradientToColor, lineGradientAngle, } = pen.calculative;
579
+ return linearGradient(ctx, worldRect, lineGradientFromColor, lineGradientToColor, lineGradientAngle);
580
+ }
581
+ /**
582
+ * 避免副作用,把创建好后的线性渐变对象返回出来
583
+ * @param ctx 画布绘制对象
584
+ * @param worldRect 世界坐标
585
+ * @returns 线性渐变
586
+ */
587
+ function linearGradient(ctx, worldRect, fromColor, toColor, angle) {
588
+ if (!fromColor || !toColor) {
589
+ return;
590
+ }
591
+ const { x, y, center, ex, ey } = worldRect;
592
+ const from = {
593
+ x,
594
+ y: center.y,
595
+ };
596
+ const to = {
597
+ x: ex,
598
+ y: center.y,
599
+ };
600
+ if (angle % 90 === 0 && angle % 180) {
601
+ from.x = center.x;
602
+ to.x = center.x;
603
+ if (angle % 270) {
604
+ from.y = y;
605
+ to.y = ey;
606
+ }
607
+ else {
608
+ from.y = ey;
609
+ to.y = y;
610
+ }
611
+ }
612
+ else if (angle) {
613
+ rotatePoint(from, angle, worldRect.center);
614
+ rotatePoint(to, angle, worldRect.center);
615
+ }
616
+ // contributor: https://github.com/sunnyguohua/meta2d
617
+ const grd = ctx.createLinearGradient(from.x, from.y, to.x, to.y);
618
+ grd.addColorStop(0, fromColor);
619
+ grd.addColorStop(1, toColor);
620
+ return grd;
621
+ }
622
+ /**
623
+ * 根据图片的宽高, imageRatio iconAlign 来获取图片的实际位置
624
+ * @param pen 画笔
625
+ */
626
+ function getImagePosition(pen) {
627
+ const { worldIconRect: rect, iconWidth, iconHeight, imgNaturalWidth, imgNaturalHeight, } = pen.calculative;
628
+ let { x, y, width: w, height: h } = rect;
629
+ if (iconWidth) {
630
+ w = iconWidth;
631
+ }
632
+ if (iconHeight) {
633
+ h = iconHeight;
634
+ }
635
+ if (imgNaturalWidth && imgNaturalHeight && pen.imageRatio) {
636
+ const scaleW = rect.width / imgNaturalWidth;
637
+ const scaleH = rect.height / imgNaturalHeight;
638
+ const scaleMin = Math.min(scaleW, scaleH);
639
+ const wDivideH = imgNaturalWidth / imgNaturalHeight;
640
+ if (iconWidth) {
641
+ h = iconWidth / wDivideH;
642
+ }
643
+ else if (iconHeight) {
644
+ w = iconHeight * wDivideH;
645
+ }
646
+ else {
647
+ w = scaleMin * imgNaturalWidth;
648
+ h = scaleMin * imgNaturalHeight;
649
+ }
650
+ }
651
+ x += (rect.width - w) / 2;
652
+ y += (rect.height - h) / 2;
653
+ switch (pen.iconAlign) {
654
+ case 'top':
655
+ y = rect.y;
656
+ break;
657
+ case 'bottom':
658
+ y = rect.ey - h;
659
+ break;
660
+ case 'left':
661
+ x = rect.x;
662
+ break;
663
+ case 'right':
664
+ x = rect.ex - w;
665
+ break;
666
+ case 'left-top':
667
+ x = rect.x;
668
+ y = rect.y;
669
+ break;
670
+ case 'right-top':
671
+ x = rect.ex - w;
672
+ y = rect.y;
673
+ break;
674
+ case 'left-bottom':
675
+ x = rect.x;
676
+ y = rect.ey - h;
677
+ break;
678
+ case 'right-bottom':
679
+ x = rect.ex - w;
680
+ y = rect.ey - h;
681
+ break;
682
+ }
683
+ return {
684
+ x,
685
+ y,
686
+ width: w,
687
+ height: h,
688
+ };
689
+ }
690
+ export function drawImage(ctx, pen) {
691
+ const { x, y, width, height } = getImagePosition(pen);
692
+ const { worldIconRect, iconRotate, img } = pen.calculative;
693
+ if (iconRotate) {
694
+ const { x: centerX, y: centerY } = worldIconRect.center;
695
+ ctx.translate(centerX, centerY);
696
+ ctx.rotate((iconRotate * Math.PI) / 180);
697
+ ctx.translate(-centerX, -centerY);
698
+ }
699
+ if (pen.imageRadius) {
700
+ ctx.save();
701
+ let wr = pen.calculative.imageRadius || 0, hr = wr;
702
+ const { x: _x, y: _y, width: w, height: h, ex, ey, } = pen.calculative.worldRect;
703
+ if (wr < 1) {
704
+ wr = w * wr;
705
+ hr = h * hr;
706
+ }
707
+ let r = wr < hr ? wr : hr;
708
+ if (w < 2 * r) {
709
+ r = w / 2;
710
+ }
711
+ if (h < 2 * r) {
712
+ r = h / 2;
713
+ }
714
+ ctx.beginPath();
715
+ ctx.moveTo(_x + r, _y);
716
+ ctx.arcTo(ex, _y, ex, ey, r);
717
+ ctx.arcTo(ex, ey, _x, ey, r);
718
+ ctx.arcTo(_x, ey, _x, _y, r);
719
+ ctx.arcTo(_x, _y, ex, _y, r);
720
+ ctx.clip();
721
+ ctx.drawImage(img, x, y, width, height);
722
+ ctx.restore();
723
+ }
724
+ else {
725
+ ctx.drawImage(img, x, y, width, height);
726
+ }
727
+ }
728
+ /**
729
+ * 获取文字颜色, textColor 优先其次 color
730
+ */
731
+ export function getTextColor(pen, store) {
732
+ const { textColor, color } = pen.calculative;
733
+ const { data, options } = store;
734
+ return (textColor ||
735
+ color ||
736
+ data.textColor ||
737
+ data.color ||
738
+ options.textColor ||
739
+ options.color);
740
+ }
741
+ function drawText(ctx, pen) {
742
+ const { fontStyle, fontWeight, fontSize, fontFamily, lineHeight, text, hiddenText, canvas, textHasShadow, textBackground, textType, } = pen.calculative;
743
+ if (text == undefined || hiddenText) {
744
+ return;
745
+ }
746
+ const store = canvas.store;
747
+ ctx.save();
748
+ if (!textHasShadow) {
749
+ ctx.shadowBlur = 0;
750
+ ctx.shadowOffsetX = 0;
751
+ ctx.shadowOffsetY = 0;
752
+ }
753
+ let fill = undefined;
754
+ if (pen.calculative.disabled) {
755
+ fill =
756
+ pen.disabledTextColor ||
757
+ pen.disabledColor ||
758
+ pSBC(0.4, getTextColor(pen, store));
759
+ }
760
+ else if (pen.calculative.hover) {
761
+ fill = pen.hoverTextColor || pen.hoverColor || store.options.hoverColor;
762
+ }
763
+ else if (pen.calculative.active) {
764
+ fill = pen.activeTextColor || pen.activeColor || store.options.activeColor;
765
+ }
766
+ let gradient = undefined;
767
+ if (textType === Gradient.Linear) {
768
+ gradient = getTextGradient(ctx, pen);
769
+ }
770
+ else if (textType === Gradient.Radial) {
771
+ gradient = getTextRadialGradient(ctx, pen);
772
+ }
773
+ ctx.fillStyle = fill || gradient || getTextColor(pen, store);
774
+ ctx.font = getFont({
775
+ fontStyle,
776
+ fontWeight,
777
+ fontFamily: fontFamily || store.options.fontFamily,
778
+ fontSize,
779
+ lineHeight,
780
+ });
781
+ !pen.calculative.textDrawRect && calcTextDrawRect(ctx, pen);
782
+ const { x: drawRectX, y: drawRectY, width, height, } = pen.calculative.textDrawRect;
783
+ if (textBackground) {
784
+ ctx.save();
785
+ ctx.fillStyle = textBackground;
786
+ ctx.fillRect(drawRectX, drawRectY, width, height);
787
+ ctx.restore();
788
+ }
789
+ const y = 0.55;
790
+ const textAlign = pen.textAlign || store.options.textAlign;
791
+ const oneRowHeight = fontSize * lineHeight;
792
+ pen.calculative.textLines.forEach((text, i) => {
793
+ const textLineWidth = pen.calculative.textLineWidths[i];
794
+ let x = 0;
795
+ if (textAlign === 'center') {
796
+ x = (width - textLineWidth) / 2;
797
+ }
798
+ else if (textAlign === 'right') {
799
+ x = width - textLineWidth;
800
+ }
801
+ // 下划线
802
+ ctx.fillText(text, drawRectX + x, drawRectY + (i + y) * oneRowHeight);
803
+ const { textDecorationColor, textDecorationDash, textDecoration } = pen;
804
+ if (textDecoration) {
805
+ drawUnderLine(ctx, {
806
+ x: drawRectX + x,
807
+ y: drawRectY + (i + y) * oneRowHeight,
808
+ width: textLineWidth,
809
+ }, { textDecorationColor, textDecorationDash, fontSize });
810
+ }
811
+ // 删除线
812
+ const { textStrickoutColor, textStrickoutDash, textStrickout } = pen;
813
+ if (textStrickout) {
814
+ drawStrickout(ctx, {
815
+ x: drawRectX + x,
816
+ y: drawRectY + (i + y) * oneRowHeight,
817
+ width: textLineWidth,
818
+ }, { textStrickoutColor, textStrickoutDash, fontSize });
819
+ }
820
+ });
821
+ ctx.restore();
822
+ }
823
+ function drawUnderLine(ctx, location, config) {
824
+ const { textDecorationColor, textDecorationDash, fontSize } = config;
825
+ let { x, y, width } = location;
826
+ switch (ctx.textBaseline) {
827
+ case 'top':
828
+ y += fontSize;
829
+ break;
830
+ case 'middle':
831
+ y += fontSize / 2;
832
+ break;
833
+ }
834
+ ctx.save();
835
+ ctx.beginPath();
836
+ ctx.strokeStyle = textDecorationColor ? textDecorationColor : ctx.fillStyle;
837
+ ctx.lineWidth = 1;
838
+ ctx.moveTo(x, y);
839
+ ctx.setLineDash(textDecorationDash || []);
840
+ ctx.lineTo(x + width, y);
841
+ ctx.stroke();
842
+ ctx.restore();
843
+ }
844
+ function drawStrickout(ctx, location, config) {
845
+ const { textStrickoutColor, textStrickoutDash, fontSize } = config;
846
+ let { x, y, width } = location;
847
+ switch (ctx.textBaseline) {
848
+ case 'top':
849
+ y += fontSize / 2;
850
+ break;
851
+ case 'bottom':
852
+ y -= fontSize / 2;
853
+ break;
854
+ }
855
+ ctx.save();
856
+ ctx.beginPath();
857
+ ctx.strokeStyle = textStrickoutColor ? textStrickoutColor : ctx.fillStyle;
858
+ ctx.lineWidth = 1;
859
+ ctx.moveTo(x, y);
860
+ ctx.setLineDash(textStrickoutDash || []);
861
+ ctx.lineTo(x + width, y);
862
+ ctx.stroke();
863
+ ctx.restore();
864
+ }
865
+ function drawFillText(ctx, pen, text) {
866
+ if (text == undefined) {
867
+ return;
868
+ }
869
+ const { fontStyle, fontWeight, fontSize, fontFamily, lineHeight, canvas } = pen.calculative;
870
+ const store = canvas.store;
871
+ ctx.save();
872
+ let fill = undefined;
873
+ if (pen.calculative.hover) {
874
+ fill = pen.hoverTextColor || pen.hoverColor || store.options.hoverColor;
875
+ }
876
+ else if (pen.calculative.active) {
877
+ fill = pen.activeTextColor || pen.activeColor || store.options.activeColor;
878
+ }
879
+ ctx.fillStyle = fill || getTextColor(pen, store);
880
+ ctx.font = getFont({
881
+ fontStyle,
882
+ fontWeight,
883
+ fontFamily: fontFamily || store.options.fontFamily,
884
+ fontSize,
885
+ lineHeight,
886
+ });
887
+ const w = ctx.measureText(text).width;
888
+ let t;
889
+ let prev;
890
+ for (const anchor of pen.calculative.worldAnchors) {
891
+ if (!prev) {
892
+ prev = anchor;
893
+ continue;
894
+ }
895
+ const dis = distance(prev, anchor);
896
+ const n = Math.floor(dis / w);
897
+ t = '';
898
+ for (let i = 0; i < n; i++) {
899
+ t += text;
900
+ }
901
+ const angle = calcRotate(prev, anchor) - 270;
902
+ ctx.save();
903
+ if (angle % 360 !== 0) {
904
+ const { x, y } = prev;
905
+ ctx.translate(x, y);
906
+ let rotate = (angle * Math.PI) / 180;
907
+ ctx.rotate(rotate);
908
+ ctx.translate(-x, -y);
909
+ }
910
+ ctx.fillText(t, prev.x, prev.y + lineHeight / 2);
911
+ ctx.restore();
912
+ prev = anchor;
913
+ }
914
+ ctx.restore();
915
+ }
916
+ export function drawIcon(ctx, pen) {
917
+ const store = pen.calculative.canvas.store;
918
+ ctx.save();
919
+ ctx.shadowColor = '';
920
+ ctx.shadowBlur = 0;
921
+ ctx.shadowOffsetX = 0;
922
+ ctx.shadowOffsetY = 0;
923
+ ctx.textAlign = 'center';
924
+ ctx.textBaseline = 'middle';
925
+ const iconRect = pen.calculative.worldIconRect;
926
+ let x = iconRect.x + iconRect.width / 2;
927
+ let y = iconRect.y + iconRect.height / 2;
928
+ switch (pen.iconAlign) {
929
+ case 'top':
930
+ y = iconRect.y;
931
+ ctx.textBaseline = 'top';
932
+ break;
933
+ case 'bottom':
934
+ y = iconRect.ey;
935
+ ctx.textBaseline = 'bottom';
936
+ break;
937
+ case 'left':
938
+ x = iconRect.x;
939
+ ctx.textAlign = 'left';
940
+ break;
941
+ case 'right':
942
+ x = iconRect.ex;
943
+ ctx.textAlign = 'right';
944
+ break;
945
+ case 'left-top':
946
+ x = iconRect.x;
947
+ y = iconRect.y;
948
+ ctx.textAlign = 'left';
949
+ ctx.textBaseline = 'top';
950
+ break;
951
+ case 'right-top':
952
+ x = iconRect.ex;
953
+ y = iconRect.y;
954
+ ctx.textAlign = 'right';
955
+ ctx.textBaseline = 'top';
956
+ break;
957
+ case 'left-bottom':
958
+ x = iconRect.x;
959
+ y = iconRect.ey;
960
+ ctx.textAlign = 'left';
961
+ ctx.textBaseline = 'bottom';
962
+ break;
963
+ case 'right-bottom':
964
+ x = iconRect.ex;
965
+ y = iconRect.ey;
966
+ ctx.textAlign = 'right';
967
+ ctx.textBaseline = 'bottom';
968
+ break;
969
+ }
970
+ const fontWeight = pen.calculative.iconWeight;
971
+ let fontSize = undefined;
972
+ const fontFamily = pen.calculative.iconFamily;
973
+ if (pen.calculative.iconSize > 0) {
974
+ fontSize = pen.calculative.iconSize;
975
+ }
976
+ else if (iconRect.width > iconRect.height) {
977
+ fontSize = iconRect.height;
978
+ }
979
+ else {
980
+ fontSize = iconRect.width;
981
+ }
982
+ ctx.font = getFont({
983
+ fontSize,
984
+ fontWeight,
985
+ fontFamily,
986
+ });
987
+ ctx.fillStyle = pen.calculative.iconColor || getTextColor(pen, store);
988
+ if (pen.calculative.iconRotate) {
989
+ ctx.translate(iconRect.center.x, iconRect.center.y);
990
+ ctx.rotate((pen.calculative.iconRotate * Math.PI) / 180);
991
+ ctx.translate(-iconRect.center.x, -iconRect.center.y);
992
+ }
993
+ ctx.beginPath();
994
+ ctx.fillText(pen.calculative.icon, x, y);
995
+ ctx.restore();
996
+ }
997
+ /**
998
+ * canvas2svg 中对 font 的解析规则比 canvas 中简单,能识别的类型很少
999
+ * @returns ctx.font
1000
+ */
1001
+ export function getFont({ fontStyle = 'normal', textDecoration = 'normal', fontWeight = 'normal', fontSize = 12, fontFamily = 'Arial', lineHeight = 1, // TODO: lineHeight 默认值待测试
1002
+ } = {}) {
1003
+ return `${fontStyle} ${textDecoration} ${fontWeight} ${fontSize}px/${lineHeight} ${fontFamily}`;
1004
+ }
1005
+ // TODO: 0.5 偏移量在 图片中可能存在问题
1006
+ export function ctxFlip(ctx, pen) {
1007
+ // worldRect 可能为 undefined
1008
+ const { x, ex, y, ey } = pen.calculative.worldRect || {};
1009
+ if (pen.calculative.flipX) {
1010
+ ctx.translate(x + ex + 0.5, 0.5);
1011
+ ctx.scale(-1, 1);
1012
+ }
1013
+ if (pen.calculative.flipY) {
1014
+ ctx.translate(0.5, y + ey + 0.5);
1015
+ ctx.scale(1, -1);
1016
+ }
1017
+ }
1018
+ export function ctxRotate(ctx, pen, noFlip = false) {
1019
+ const { x, y } = pen.calculative.worldRect.pivot || pen.calculative.worldRect.center;
1020
+ ctx.translate(x, y);
1021
+ let rotate = (pen.calculative.rotate * Math.PI) / 180;
1022
+ // 目前只有水平和垂直翻转,都需要 * -1
1023
+ if (!noFlip) {
1024
+ if (pen.calculative.flipX) {
1025
+ rotate *= -1;
1026
+ }
1027
+ if (pen.calculative.flipY) {
1028
+ rotate *= -1;
1029
+ }
1030
+ }
1031
+ ctx.rotate(rotate);
1032
+ ctx.translate(-x, -y);
1033
+ }
1034
+ export function renderPen(ctx, pen, download) {
1035
+ ctx.save();
1036
+ ctx.translate(0.5, 0.5);
1037
+ ctx.beginPath();
1038
+ const store = pen.calculative.canvas.store;
1039
+ const textFlip = pen.textFlip || store.options.textFlip;
1040
+ const textRotate = pen.textRotate || store.options.textRotate;
1041
+ if (!textFlip || !textRotate) {
1042
+ ctx.save();
1043
+ }
1044
+ ctxFlip(ctx, pen);
1045
+ if (pen.calculative.rotate && pen.name !== 'line') {
1046
+ ctxRotate(ctx, pen);
1047
+ }
1048
+ if (pen.calculative.lineWidth > 1 || download) {
1049
+ ctx.lineWidth = pen.calculative.lineWidth;
1050
+ }
1051
+ inspectRect(ctx, store, pen); // 审查 rect
1052
+ let fill;
1053
+ // 该变量控制在 hover active 状态下的节点是否设置填充颜色
1054
+ // let setBack = true;
1055
+ let lineGradientFlag = false;
1056
+ let _stroke = undefined;
1057
+ if (pen.calculative.disabled) {
1058
+ _stroke =
1059
+ pen.disabledColor ||
1060
+ store.options.disabledColor ||
1061
+ pSBC(0.4, pen.calculative.color || getGlobalColor(store));
1062
+ fill =
1063
+ pen.disabledBackground ||
1064
+ store.options.disabledBackground ||
1065
+ pSBC(0.4, pen.calculative.background || store.data.penBackground);
1066
+ }
1067
+ else if (pen.mouseDownValid && pen.calculative.mouseDown) {
1068
+ _stroke =
1069
+ pen.mouseDownColor ||
1070
+ pSBC(-0.4, pen.calculative.color || getGlobalColor(store));
1071
+ fill =
1072
+ pen.mouseDownBackground ||
1073
+ pSBC(-0.4, pen.calculative.background || store.data.penBackground);
1074
+ }
1075
+ else if (pen.calculative.hover) {
1076
+ _stroke = pen.hoverColor || store.options.hoverColor;
1077
+ fill = pen.hoverBackground || store.options.hoverBackground;
1078
+ // ctx.fillStyle = fill;
1079
+ // fill && (setBack = false);
1080
+ }
1081
+ else if (pen.calculative.active) {
1082
+ _stroke = pen.activeColor || store.options.activeColor;
1083
+ fill = pen.activeBackground || store.options.activeBackground;
1084
+ // ctx.fillStyle = fill;
1085
+ // fill && (setBack = false);
1086
+ }
1087
+ else if (pen.calculative.isDock) {
1088
+ if (pen.type === PenType.Line) {
1089
+ _stroke = store.options.dockPenColor;
1090
+ }
1091
+ else {
1092
+ fill = rgba(store.options.dockPenColor, 0.2);
1093
+ // ctx.fillStyle = fill;
1094
+ // fill && (setBack = false);
1095
+ }
1096
+ }
1097
+ // else {
1098
+ const strokeImg = pen.calculative.strokeImg;
1099
+ if (pen.calculative.strokeImage && strokeImg) {
1100
+ ctx.strokeStyle = _stroke || ctx.createPattern(strokeImg, 'repeat');
1101
+ // fill = true;
1102
+ }
1103
+ else {
1104
+ let stroke;
1105
+ // TODO: 线只有线性渐变
1106
+ if (pen.calculative.strokeType) {
1107
+ if (pen.calculative.lineGradientColors) {
1108
+ if (pen.name === 'line') {
1109
+ lineGradientFlag = true;
1110
+ }
1111
+ else {
1112
+ if (pen.calculative.lineGradient) {
1113
+ stroke = pen.calculative.lineGradient;
1114
+ }
1115
+ else {
1116
+ stroke = getLineGradient(ctx, pen);
1117
+ pen.calculative.lineGradient = stroke;
1118
+ }
1119
+ }
1120
+ }
1121
+ else {
1122
+ stroke = strokeLinearGradient(ctx, pen);
1123
+ }
1124
+ }
1125
+ else {
1126
+ stroke = pen.calculative.color || getGlobalColor(store);
1127
+ }
1128
+ ctx.strokeStyle = _stroke || stroke;
1129
+ }
1130
+ // }
1131
+ //if (setBack) {
1132
+ const backgroundImg = pen.calculative.backgroundImg;
1133
+ if (pen.calculative.backgroundImage && backgroundImg) {
1134
+ ctx.fillStyle = fill || ctx.createPattern(backgroundImg, 'repeat');
1135
+ fill = true;
1136
+ }
1137
+ else {
1138
+ let back;
1139
+ if (pen.calculative.bkType === Gradient.Linear) {
1140
+ if (pen.calculative.gradientColors) {
1141
+ // if (!pen.type) {
1142
+ //连线不考虑渐进背景
1143
+ if (pen.calculative.gradient) {
1144
+ //位置变化/放大缩小操作不会触发重新计算
1145
+ back = pen.calculative.gradient;
1146
+ }
1147
+ else {
1148
+ back = getBkGradient(ctx, pen);
1149
+ pen.calculative.gradient = back;
1150
+ }
1151
+ // }
1152
+ }
1153
+ else {
1154
+ back = drawBkLinearGradient(ctx, pen);
1155
+ }
1156
+ }
1157
+ else if (pen.calculative.bkType === Gradient.Radial) {
1158
+ if (pen.calculative.gradientColors) {
1159
+ if (pen.calculative.radialGradient) {
1160
+ back = pen.calculative.radialGradient;
1161
+ }
1162
+ else {
1163
+ back = getBkRadialGradient(ctx, pen);
1164
+ pen.calculative.radialGradient = back;
1165
+ }
1166
+ }
1167
+ else {
1168
+ back = drawBkRadialGradient(ctx, pen);
1169
+ }
1170
+ }
1171
+ else {
1172
+ back = pen.calculative.background || store.data.penBackground;
1173
+ }
1174
+ ctx.fillStyle = fill || back;
1175
+ fill = !!back;
1176
+ }
1177
+ // }
1178
+ setLineCap(ctx, pen);
1179
+ setLineJoin(ctx, pen);
1180
+ setGlobalAlpha(ctx, pen);
1181
+ if (pen.calculative.lineDash) {
1182
+ ctx.setLineDash(pen.calculative.lineDash.map((item) => item * pen.calculative.canvas.store.data.scale));
1183
+ }
1184
+ if (pen.calculative.lineDashOffset) {
1185
+ ctx.lineDashOffset = pen.calculative.lineDashOffset;
1186
+ }
1187
+ if (pen.calculative.shadowColor) {
1188
+ ctx.shadowColor = pen.calculative.shadowColor;
1189
+ ctx.shadowOffsetX = pen.calculative.shadowOffsetX;
1190
+ ctx.shadowOffsetY = pen.calculative.shadowOffsetY;
1191
+ ctx.shadowBlur = pen.calculative.shadowBlur;
1192
+ }
1193
+ if (lineGradientFlag) {
1194
+ ctxDrawLinearGradientPath(ctx, pen);
1195
+ ctxDrawLinePath(true, ctx, pen, store);
1196
+ }
1197
+ else {
1198
+ ctxDrawPath(true, ctx, pen, store, fill);
1199
+ ctxDrawCanvas(ctx, pen);
1200
+ }
1201
+ if (!(pen.image && pen.calculative.img) && pen.calculative.icon) {
1202
+ drawIcon(ctx, pen);
1203
+ }
1204
+ if (!textFlip || !textRotate) {
1205
+ ctx.restore();
1206
+ }
1207
+ if (textFlip && !textRotate) {
1208
+ ctxFlip(ctx, pen);
1209
+ }
1210
+ if (!textFlip && textRotate) {
1211
+ if (pen.calculative.rotate && pen.name !== 'line') {
1212
+ ctxRotate(ctx, pen, true);
1213
+ }
1214
+ }
1215
+ drawText(ctx, pen);
1216
+ if (pen.type === PenType.Line && pen.fillTexts) {
1217
+ for (const text of pen.fillTexts) {
1218
+ drawFillText(ctx, pen, text);
1219
+ }
1220
+ }
1221
+ ctx.restore();
1222
+ }
1223
+ /**
1224
+ * 更改 ctx 的 lineCap 属性
1225
+ */
1226
+ export function setLineCap(ctx, pen) {
1227
+ const lineCap = pen.lineCap || (pen.type ? 'round' : 'square');
1228
+ if (lineCap) {
1229
+ ctx.lineCap = lineCap;
1230
+ }
1231
+ else if (pen.type) {
1232
+ ctx.lineCap = 'round';
1233
+ }
1234
+ }
1235
+ /**
1236
+ * 更改 ctx 的 lineJoin 属性
1237
+ */
1238
+ export function setLineJoin(ctx, pen) {
1239
+ const lineJoin = pen.lineJoin;
1240
+ if (lineJoin) {
1241
+ ctx.lineJoin = lineJoin;
1242
+ }
1243
+ else if (pen.type) {
1244
+ ctx.lineJoin = 'round';
1245
+ }
1246
+ }
1247
+ /**
1248
+ * 通常用在下载 svg
1249
+ * canvas2svg 与 canvas ctx 设置 strokeStyle 表现不同
1250
+ * 若设置值为 undefined ,canvas2svg 为空, canvas ctx 为上一个值
1251
+ */
1252
+ export function renderPenRaw(ctx, pen, rect, download) {
1253
+ ctx.save();
1254
+ if (rect) {
1255
+ ctx.translate(-rect.x, -rect.y);
1256
+ }
1257
+ // for canvas2svg
1258
+ ctx.setAttrs?.(pen);
1259
+ // end
1260
+ let lineGradientFlag = false;
1261
+ const store = pen.calculative.canvas.store;
1262
+ const textFlip = pen.textFlip || store.options.textFlip;
1263
+ const textRotate = pen.textRotate || store.options.textRotate;
1264
+ ctx.beginPath();
1265
+ if (!textFlip || !textRotate) {
1266
+ ctx.save();
1267
+ }
1268
+ if (pen.calculative.flipX) {
1269
+ if (rect) {
1270
+ ctx.translate(pen.calculative.worldRect.x + pen.calculative.worldRect.ex, 0);
1271
+ }
1272
+ else {
1273
+ ctx.translate(pen.calculative.worldRect.x + pen.calculative.worldRect.ex, 0);
1274
+ }
1275
+ ctx.scale(-1, 1);
1276
+ }
1277
+ if (pen.calculative.flipY) {
1278
+ if (rect) {
1279
+ ctx.translate(0, pen.calculative.worldRect.y + pen.calculative.worldRect.ey);
1280
+ }
1281
+ else {
1282
+ ctx.translate(0, pen.calculative.worldRect.y + pen.calculative.worldRect.ey);
1283
+ }
1284
+ ctx.scale(1, -1);
1285
+ }
1286
+ if (pen.calculative.rotate && pen.name !== 'line') {
1287
+ ctxRotate(ctx, pen);
1288
+ }
1289
+ if (pen.calculative.lineWidth > 1 || download) {
1290
+ ctx.lineWidth = pen.calculative.lineWidth;
1291
+ }
1292
+ let fill;
1293
+ if (pen.calculative.hover) {
1294
+ ctx.strokeStyle = pen.hoverColor || store.options.hoverColor;
1295
+ ctx.fillStyle = pen.hoverBackground || store.options.hoverBackground;
1296
+ fill = pen.hoverBackground || store.options.hoverBackground;
1297
+ }
1298
+ else if (pen.calculative.active) {
1299
+ ctx.strokeStyle = pen.activeColor || store.options.activeColor;
1300
+ ctx.fillStyle = pen.activeBackground || store.options.activeBackground;
1301
+ fill = pen.activeBackground || store.options.activeBackground;
1302
+ }
1303
+ else {
1304
+ if (pen.strokeImage) {
1305
+ if (pen.calculative.strokeImg) {
1306
+ ctx.strokeStyle = ctx.createPattern(pen.calculative.strokeImg, 'repeat');
1307
+ fill = true;
1308
+ }
1309
+ }
1310
+ else {
1311
+ let stroke;
1312
+ if (pen.calculative.strokeType &&
1313
+ pen.calculative.lineGradientColors &&
1314
+ pen.name === 'line') {
1315
+ lineGradientFlag = true;
1316
+ }
1317
+ else {
1318
+ stroke = pen.calculative.color || getGlobalColor(store);
1319
+ }
1320
+ ctx.strokeStyle = stroke;
1321
+ }
1322
+ if (pen.backgroundImage) {
1323
+ if (pen.calculative.backgroundImg) {
1324
+ ctx.fillStyle = ctx.createPattern(pen.calculative.backgroundImg, 'repeat');
1325
+ fill = true;
1326
+ }
1327
+ }
1328
+ else {
1329
+ ctx.fillStyle = pen.background;
1330
+ fill = !!pen.background;
1331
+ }
1332
+ }
1333
+ setLineCap(ctx, pen);
1334
+ setLineJoin(ctx, pen);
1335
+ setGlobalAlpha(ctx, pen);
1336
+ if (pen.calculative.lineDash) {
1337
+ ctx.setLineDash(pen.calculative.lineDash);
1338
+ }
1339
+ if (pen.calculative.lineDashOffset) {
1340
+ ctx.lineDashOffset = pen.calculative.lineDashOffset;
1341
+ }
1342
+ if (pen.calculative.shadowColor) {
1343
+ ctx.shadowColor = pen.calculative.shadowColor;
1344
+ ctx.shadowOffsetX = pen.calculative.shadowOffsetX;
1345
+ ctx.shadowOffsetY = pen.calculative.shadowOffsetY;
1346
+ ctx.shadowBlur = pen.calculative.shadowBlur;
1347
+ }
1348
+ if (lineGradientFlag) {
1349
+ ctxDrawLinearGradientPath(ctx, pen);
1350
+ ctxDrawLinePath(true, ctx, pen, store);
1351
+ }
1352
+ else {
1353
+ ctxDrawPath(false, ctx, pen, store, fill);
1354
+ ctxDrawCanvas(ctx, pen);
1355
+ }
1356
+ // renderPenRaw 用在 downloadPng svg , echarts 等图形需要
1357
+ if (pen.calculative.img) {
1358
+ ctx.save();
1359
+ ctx.shadowColor = '';
1360
+ ctx.shadowBlur = 0;
1361
+ ctx.shadowOffsetX = 0;
1362
+ ctx.shadowOffsetY = 0;
1363
+ drawImage(ctx, pen);
1364
+ ctx.restore();
1365
+ }
1366
+ else if (pen.calculative.icon) {
1367
+ drawIcon(ctx, pen);
1368
+ }
1369
+ if (!textFlip || !textRotate) {
1370
+ ctx.restore();
1371
+ }
1372
+ if (textFlip && !textRotate) {
1373
+ if (pen.calculative.flipX) {
1374
+ if (rect) {
1375
+ ctx.translate(pen.calculative.worldRect.x + pen.calculative.worldRect.ex, 0);
1376
+ }
1377
+ else {
1378
+ ctx.translate(pen.calculative.worldRect.x + pen.calculative.worldRect.ex, 0);
1379
+ }
1380
+ ctx.scale(-1, 1);
1381
+ }
1382
+ if (pen.calculative.flipY) {
1383
+ if (rect) {
1384
+ ctx.translate(0, pen.calculative.worldRect.y + pen.calculative.worldRect.ey);
1385
+ }
1386
+ else {
1387
+ ctx.translate(0, pen.calculative.worldRect.y + pen.calculative.worldRect.ey);
1388
+ }
1389
+ ctx.scale(1, -1);
1390
+ }
1391
+ }
1392
+ if (!textFlip && textRotate) {
1393
+ if (pen.calculative.rotate && pen.name !== 'line') {
1394
+ ctxRotate(ctx, pen, true);
1395
+ }
1396
+ }
1397
+ drawText(ctx, pen);
1398
+ if (pen.type === PenType.Line && pen.fillTexts) {
1399
+ for (const text of pen.fillTexts) {
1400
+ drawFillText(ctx, pen, text);
1401
+ }
1402
+ }
1403
+ ctx.restore();
1404
+ }
1405
+ /**
1406
+ * 根据 path2D 绘制 path
1407
+ * @param canUsePath 是否可使用 Path2D, downloadSvg 不可使用 path2D
1408
+ */
1409
+ export function ctxDrawPath(canUsePath = true, ctx, pen, store, fill) {
1410
+ const path = canUsePath
1411
+ ? store.path2dMap.get(pen)
1412
+ : globalStore.path2dDraws[pen.name];
1413
+ let path_from = null;
1414
+ let path_to = null;
1415
+ if (pen.type === PenType.Line) {
1416
+ //线段的起始和结束线帽 分别配置
1417
+ if (pen.fromLineCap && pen.fromLineCap !== 'butt') {
1418
+ ctx.lineCap = 'butt';
1419
+ path_from = new Path2D();
1420
+ path_from.moveTo(pen.calculative.worldAnchors[0].x, pen.calculative.worldAnchors[0].y);
1421
+ path_from.lineTo(pen.calculative.worldAnchors[0].x, pen.calculative.worldAnchors[0].y);
1422
+ }
1423
+ if (pen.toLineCap && pen.toLineCap !== 'butt') {
1424
+ ctx.lineCap = 'butt';
1425
+ path_to = new Path2D();
1426
+ path_to.moveTo(pen.calculative.worldAnchors[pen.calculative.worldAnchors.length - 1].x, pen.calculative.worldAnchors[pen.calculative.worldAnchors.length - 1].y);
1427
+ path_to.lineTo(pen.calculative.worldAnchors[pen.calculative.worldAnchors.length - 1].x, pen.calculative.worldAnchors[pen.calculative.worldAnchors.length - 1].y);
1428
+ }
1429
+ }
1430
+ if (path) {
1431
+ if (pen.type === PenType.Line && pen.borderWidth) {
1432
+ ctx.save();
1433
+ ctx.beginPath();
1434
+ const lineWidth = pen.calculative.lineWidth + pen.calculative.borderWidth;
1435
+ ctx.lineWidth = lineWidth;
1436
+ ctx.strokeStyle = pen.borderColor;
1437
+ if (path_from) {
1438
+ ctx.save();
1439
+ ctx.lineCap = pen.fromLineCap;
1440
+ ctx.stroke(path_from);
1441
+ ctx.restore();
1442
+ }
1443
+ if (path instanceof Path2D) {
1444
+ fill && ctx.fill(path);
1445
+ lineWidth && ctx.stroke(path);
1446
+ }
1447
+ else {
1448
+ path(pen, ctx);
1449
+ fill && ctx.fill();
1450
+ lineWidth && ctx.stroke();
1451
+ }
1452
+ if (path_to) {
1453
+ ctx.save();
1454
+ ctx.lineCap = pen.toLineCap;
1455
+ ctx.stroke(path_to);
1456
+ ctx.restore();
1457
+ }
1458
+ ctx.restore();
1459
+ }
1460
+ if (path instanceof Path2D) {
1461
+ if (pen.type) {
1462
+ if (pen.close) {
1463
+ fill && ctx.fill(path);
1464
+ }
1465
+ }
1466
+ else {
1467
+ //svgPath
1468
+ fill && ctx.fill(path);
1469
+ }
1470
+ }
1471
+ else {
1472
+ ctx.save();
1473
+ path(pen, ctx);
1474
+ fill && ctx.fill();
1475
+ ctx.restore();
1476
+ }
1477
+ const progress = pen.calculative.progress;
1478
+ if (progress != null) {
1479
+ // 从左往右 x, y, x + width * progress, y
1480
+ // 从右往左 ex, y, x + width * (1-progress), y
1481
+ // 从下往上 x, y, x, y + height * progress
1482
+ // 从上往下 x, ey, x, y + height * (1 - progress)
1483
+ ctx.save();
1484
+ const { ex, x, y, width, height, ey } = pen.calculative.worldRect;
1485
+ let grd = null;
1486
+ if (!pen.verticalProgress) {
1487
+ grd = !pen.reverseProgress
1488
+ ? ctx.createLinearGradient(x, y, x + width * progress, y)
1489
+ : ctx.createLinearGradient(ex, y, x + width * (1 - progress), y);
1490
+ }
1491
+ else {
1492
+ grd = !pen.reverseProgress
1493
+ ? ctx.createLinearGradient(x, ey, x, y + height * (1 - progress))
1494
+ : ctx.createLinearGradient(x, y, x, y + height * progress);
1495
+ }
1496
+ if (pen.calculative.progressGradientColors) {
1497
+ const { colors } = formatGradient(pen.calculative.progressGradientColors);
1498
+ colors.forEach((stop) => {
1499
+ grd.addColorStop(stop.i, stop.color);
1500
+ });
1501
+ }
1502
+ else {
1503
+ const color = pen.calculative.progressColor ||
1504
+ pen.calculative.color ||
1505
+ store.options.activeColor;
1506
+ grd.addColorStop(0, color);
1507
+ grd.addColorStop(1, color);
1508
+ }
1509
+ grd.addColorStop(1, 'transparent');
1510
+ ctx.fillStyle = grd;
1511
+ if (path instanceof Path2D) {
1512
+ ctx.fill(path);
1513
+ }
1514
+ else {
1515
+ path(pen, ctx);
1516
+ ctx.fill();
1517
+ }
1518
+ ctx.restore();
1519
+ }
1520
+ if (pen.calculative.lineWidth) {
1521
+ if (path instanceof Path2D) {
1522
+ if (store.options.svgPathStroke || pen.name !== 'svgPath') {
1523
+ if (path_from) {
1524
+ ctx.save();
1525
+ ctx.lineCap = pen.fromLineCap;
1526
+ ctx.stroke(path_from);
1527
+ ctx.restore();
1528
+ }
1529
+ ctx.stroke(path);
1530
+ if (path_to) {
1531
+ ctx.save();
1532
+ ctx.lineCap = pen.toLineCap;
1533
+ ctx.stroke(path_to);
1534
+ ctx.restore();
1535
+ }
1536
+ }
1537
+ }
1538
+ else {
1539
+ path(pen, ctx);
1540
+ ctx.stroke();
1541
+ }
1542
+ }
1543
+ if (pen.type) {
1544
+ if (pen.calculative.animatePos) {
1545
+ ctx.save();
1546
+ setCtxLineAnimate(ctx, pen, store);
1547
+ if (pen.lineAnimateType === LineAnimateType.Arrow ||
1548
+ pen.lineAnimateType === LineAnimateType.WaterDrop) {
1549
+ //箭头动画
1550
+ let _path = drawArrow(pen, ctx);
1551
+ if (_path instanceof Path2D) {
1552
+ ctx.stroke(_path);
1553
+ ctx.fill(_path);
1554
+ }
1555
+ else {
1556
+ ctx.stroke();
1557
+ ctx.fill();
1558
+ }
1559
+ }
1560
+ else {
1561
+ if (path instanceof Path2D) {
1562
+ if (path_from && !pen.lineAnimateType) {
1563
+ ctx.save();
1564
+ ctx.lineCap = pen.fromLineCap;
1565
+ ctx.stroke(path_from);
1566
+ ctx.restore();
1567
+ }
1568
+ ctx.lineCap = pen.lineCap;
1569
+ ctx.stroke(path);
1570
+ }
1571
+ else {
1572
+ path(pen, ctx);
1573
+ ctx.stroke();
1574
+ }
1575
+ }
1576
+ ctx.restore();
1577
+ }
1578
+ pen.fromArrow && renderFromArrow(ctx, pen, store);
1579
+ pen.toArrow && renderToArrow(ctx, pen, store);
1580
+ if (pen.calculative.active &&
1581
+ !pen.calculative.pencil &&
1582
+ !store.options.disableAnchor &&
1583
+ !store.data.locked) {
1584
+ renderLineAnchors(ctx, pen);
1585
+ }
1586
+ }
1587
+ }
1588
+ }
1589
+ /**
1590
+ * 连线配置线条渐进后,动画效果、起始点、终点的绘制
1591
+ */
1592
+ export function ctxDrawLinePath(canUsePath = true, ctx, pen, store) {
1593
+ const path = canUsePath
1594
+ ? store.path2dMap.get(pen)
1595
+ : globalStore.path2dDraws[pen.name];
1596
+ if (path) {
1597
+ if (pen.type) {
1598
+ if (pen.calculative.animatePos) {
1599
+ ctx.save();
1600
+ setCtxLineAnimate(ctx, pen, store);
1601
+ ctx.beginPath();
1602
+ if (path instanceof Path2D) {
1603
+ if (pen.lineName === 'polyline' || pen.lineName === 'line') {
1604
+ if (pen.lineAnimateType === LineAnimateType.Arrow ||
1605
+ pen.lineAnimateType === LineAnimateType.WaterDrop) {
1606
+ //箭头动画
1607
+ const _path = drawArrow(pen);
1608
+ ctx.stroke(_path);
1609
+ ctx.fill(_path);
1610
+ }
1611
+ else {
1612
+ if (pen.calculative.gradientSmooth ||
1613
+ pen.calculative.lineSmooth) {
1614
+ if (!pen.calculative.gradientAnimatePath) {
1615
+ pen.calculative.gradientAnimatePath =
1616
+ getGradientAnimatePath(pen);
1617
+ }
1618
+ if (pen.calculative.gradientAnimatePath instanceof Path2D) {
1619
+ ctx.stroke(pen.calculative.gradientAnimatePath);
1620
+ }
1621
+ }
1622
+ else {
1623
+ ctx.stroke(path);
1624
+ }
1625
+ }
1626
+ }
1627
+ else {
1628
+ ctx.stroke(path);
1629
+ }
1630
+ }
1631
+ else {
1632
+ path(pen, ctx);
1633
+ ctx.stroke();
1634
+ }
1635
+ ctx.restore();
1636
+ }
1637
+ pen.fromArrow && renderFromArrow(ctx, pen, store);
1638
+ pen.toArrow && renderToArrow(ctx, pen, store);
1639
+ //TODO 锚点处渐进色的过渡
1640
+ if (pen.calculative.active &&
1641
+ !pen.calculative.pencil &&
1642
+ !store.options.disableAnchor &&
1643
+ !store.data.locked) {
1644
+ renderLineAnchors(ctx, pen);
1645
+ }
1646
+ }
1647
+ }
1648
+ }
1649
+ /**
1650
+ * 设置线条动画,ctx 的 strokeStyle lineDash 等属性更改
1651
+ */
1652
+ export function setCtxLineAnimate(ctx, pen, store) {
1653
+ ctx.strokeStyle = pen.animateColor || store.options.animateColor;
1654
+ if (pen.animateShadow) {
1655
+ ctx.shadowBlur = pen.animateShadowBlur || pen.animateLineWidth || 6;
1656
+ ctx.shadowColor =
1657
+ pen.animateShadowColor || pen.animateColor || store.options.animateColor;
1658
+ }
1659
+ pen.calculative.animateLineWidth &&
1660
+ (ctx.lineWidth = pen.calculative.animateLineWidth * store.data.scale);
1661
+ let len = 0;
1662
+ switch (pen.lineAnimateType) {
1663
+ case LineAnimateType.Beads:
1664
+ if (pen.animateReverse) {
1665
+ ctx.lineDashOffset = pen.calculative.animatePos;
1666
+ }
1667
+ else {
1668
+ ctx.lineDashOffset = pen.length - pen.calculative.animatePos;
1669
+ }
1670
+ len = pen.calculative.lineWidth || 5;
1671
+ if (len < 5) {
1672
+ len = 5;
1673
+ }
1674
+ const dash = pen.animateLineDash &&
1675
+ pen.animateLineDash.map((item) => (item * len) / 5);
1676
+ ctx.setLineDash(dash || [len, len * 2]);
1677
+ break;
1678
+ case LineAnimateType.Dot:
1679
+ if (pen.animateReverse) {
1680
+ ctx.lineDashOffset = pen.calculative.animatePos;
1681
+ }
1682
+ else {
1683
+ ctx.lineDashOffset = pen.length - pen.calculative.animatePos;
1684
+ }
1685
+ len =
1686
+ pen.calculative.animateDotSize || pen.calculative.lineWidth * 2 || 6;
1687
+ if (len < 6) {
1688
+ len = 6;
1689
+ }
1690
+ if (len > 40) {
1691
+ len = 40;
1692
+ }
1693
+ ctx.lineWidth =
1694
+ (pen.calculative.animateLineWidth || len) * store.data.scale;
1695
+ ctx.setLineDash([0.1, pen.length]);
1696
+ break;
1697
+ case LineAnimateType.Arrow:
1698
+ ctx.fillStyle = pen.animateColor || store.options.animateColor;
1699
+ ctx.lineWidth = 1;
1700
+ break;
1701
+ case LineAnimateType.WaterDrop:
1702
+ ctx.fillStyle = pen.animateColor || store.options.animateColor;
1703
+ ctx.lineWidth = 1;
1704
+ break;
1705
+ default:
1706
+ if (pen.animateReverse) {
1707
+ ctx.lineDashOffset = Number.EPSILON; //防止在执行动画时会绘制多余的远点
1708
+ ctx.setLineDash([
1709
+ 0,
1710
+ pen.length - pen.calculative.animatePos + 1,
1711
+ pen.calculative.animatePos,
1712
+ ]);
1713
+ }
1714
+ else {
1715
+ ctx.setLineDash([
1716
+ pen.calculative.animatePos,
1717
+ pen.length + 0.01 - pen.calculative.animatePos, //避免在缩放时,精度问题绘制多余圆点
1718
+ ]);
1719
+ }
1720
+ break;
1721
+ }
1722
+ }
1723
+ /**
1724
+ * 全局 color
1725
+ */
1726
+ export function getGlobalColor(store) {
1727
+ const { data, options } = store;
1728
+ return data.color || options.color;
1729
+ }
1730
+ export function renderLineAnchors(ctx, pen) {
1731
+ const store = pen.calculative.canvas.store;
1732
+ ctx.save();
1733
+ ctx.lineWidth = 1;
1734
+ ctx.fillStyle = pen.activeColor || store.options.activeColor;
1735
+ pen.calculative.worldAnchors.forEach((pt) => {
1736
+ !pt.hidden && !pt.isTemp && renderAnchor(ctx, pt, pen);
1737
+ });
1738
+ ctx.restore();
1739
+ }
1740
+ export function renderAnchor(ctx, pt, pen) {
1741
+ if (!pt) {
1742
+ return;
1743
+ }
1744
+ const active = pen.calculative.canvas.store.activeAnchor ===
1745
+ pen.calculative.activeAnchor && pen.calculative.activeAnchor === pt;
1746
+ let r = 3;
1747
+ if (pen.calculative.lineWidth > 3) {
1748
+ r = pen.calculative.lineWidth;
1749
+ }
1750
+ if (pen.anchorRadius) {
1751
+ r = pen.anchorRadius;
1752
+ }
1753
+ if (pt.radius) {
1754
+ r = pt.radius;
1755
+ }
1756
+ if (active) {
1757
+ if (pt.prev) {
1758
+ ctx.save();
1759
+ ctx.strokeStyle = '#4dffff';
1760
+ ctx.beginPath();
1761
+ ctx.moveTo(pt.prev.x, pt.prev.y);
1762
+ ctx.lineTo(pt.x, pt.y);
1763
+ ctx.stroke();
1764
+ ctx.restore();
1765
+ ctx.save();
1766
+ ctx.fillStyle = '#ffffff';
1767
+ ctx.beginPath();
1768
+ ctx.arc(pt.prev.x, pt.prev.y, r, 0, Math.PI * 2);
1769
+ ctx.fill();
1770
+ ctx.stroke();
1771
+ ctx.restore();
1772
+ }
1773
+ if (pt.next) {
1774
+ ctx.save();
1775
+ ctx.strokeStyle = '#4dffff';
1776
+ ctx.beginPath();
1777
+ ctx.moveTo(pt.x, pt.y);
1778
+ ctx.lineTo(pt.next.x, pt.next.y);
1779
+ ctx.stroke();
1780
+ ctx.restore();
1781
+ ctx.save();
1782
+ ctx.fillStyle = '#ffffff';
1783
+ ctx.beginPath();
1784
+ ctx.arc(pt.next.x, pt.next.y, r, 0, Math.PI * 2);
1785
+ ctx.fill();
1786
+ ctx.stroke();
1787
+ ctx.restore();
1788
+ ctx.beginPath();
1789
+ ctx.arc(pt.x, pt.y, r, 0, Math.PI * 2);
1790
+ ctx.fill();
1791
+ ctx.stroke();
1792
+ }
1793
+ ctx.beginPath();
1794
+ ctx.arc(pt.x, pt.y, r, 0, Math.PI * 2);
1795
+ ctx.fill();
1796
+ ctx.stroke();
1797
+ }
1798
+ else {
1799
+ ctx.save();
1800
+ ctx.fillStyle = '#ffffff';
1801
+ ctx.beginPath();
1802
+ ctx.arc(pt.x, pt.y, r, 0, Math.PI * 2);
1803
+ ctx.fill();
1804
+ ctx.stroke();
1805
+ ctx.restore();
1806
+ }
1807
+ }
1808
+ export function calcWorldRects(pen) {
1809
+ const store = pen.calculative.canvas.store;
1810
+ let rect = {
1811
+ x: pen.x,
1812
+ y: pen.y,
1813
+ };
1814
+ if (!pen.parentId || (pen.parentId && !store.pens[pen.parentId])) {
1815
+ pen.parentId = undefined;
1816
+ rect.width = pen.width;
1817
+ rect.height = pen.height;
1818
+ rect.rotate = pen.rotate;
1819
+ calcRightBottom(rect);
1820
+ calcCenter(rect);
1821
+ if (pen.pivot) {
1822
+ calcPivot(rect, pen.pivot);
1823
+ }
1824
+ }
1825
+ else {
1826
+ const parent = store.pens[pen.parentId];
1827
+ let parentRect = parent.calculative.worldRect;
1828
+ if (!parentRect) {
1829
+ parentRect = calcWorldRects(parent);
1830
+ }
1831
+ rect.x = parentRect.x + parentRect.width * pen.x;
1832
+ rect.y = parentRect.y + parentRect.height * pen.y;
1833
+ rect.width = parentRect.width * pen.width;
1834
+ rect.height = parentRect.height * pen.height;
1835
+ if (parent.flipX) {
1836
+ rect.x =
1837
+ parentRect.width - (rect.x - parentRect.x + rect.width) + parentRect.x;
1838
+ }
1839
+ if (parent.flipY) {
1840
+ rect.y =
1841
+ parentRect.height -
1842
+ (rect.y - parentRect.y + rect.height) +
1843
+ parentRect.y;
1844
+ }
1845
+ calcRightBottom(rect);
1846
+ rect.rotate = parentRect.rotate + pen.rotate;
1847
+ calcCenter(rect);
1848
+ if (pen.pivot) {
1849
+ calcPivot(rect, pen.pivot);
1850
+ }
1851
+ }
1852
+ pen.calculative.worldRect = rect;
1853
+ // 这里的 rect 均是绝对值
1854
+ calcPadding(pen, rect);
1855
+ return rect;
1856
+ }
1857
+ export function calcPadding(pen, rect) {
1858
+ !pen.paddingTop && (pen.calculative.paddingTop = 0);
1859
+ !pen.paddingBottom && (pen.calculative.paddingBottom = 0);
1860
+ !pen.paddingLeft && (pen.calculative.paddingLeft = 0);
1861
+ !pen.paddingRight && (pen.calculative.paddingRight = 0);
1862
+ Math.abs(pen.calculative.paddingTop) < 1 &&
1863
+ (pen.calculative.paddingTop *= rect.height);
1864
+ Math.abs(pen.calculative.paddingBottom) < 1 &&
1865
+ (pen.calculative.paddingBottom *= rect.height);
1866
+ Math.abs(pen.calculative.paddingLeft) < 1 &&
1867
+ (pen.calculative.paddingLeft *= rect.width);
1868
+ Math.abs(pen.calculative.paddingRight) < 1 &&
1869
+ (pen.calculative.paddingRight *= rect.width);
1870
+ }
1871
+ export function calcPenRect(pen) {
1872
+ const worldRect = deepClone(pen.calculative.worldRect);
1873
+ delete worldRect.pivot;
1874
+ if (!pen.parentId) {
1875
+ Object.assign(pen, worldRect);
1876
+ return;
1877
+ }
1878
+ const store = pen.calculative.canvas.store;
1879
+ const parentRect = store.pens[pen.parentId].calculative.worldRect;
1880
+ Object.assign(pen, calcRelativeRect(worldRect, parentRect));
1881
+ }
1882
+ export function calcWorldAnchors(pen) {
1883
+ const store = pen.calculative.canvas.store;
1884
+ let anchors = [];
1885
+ if (pen.anchors) {
1886
+ let _anchors = deepClone(pen.anchors);
1887
+ if (pen.flipX) {
1888
+ _anchors.forEach((anchor) => {
1889
+ anchor.x = 0.5 - (anchor.x - 0.5);
1890
+ });
1891
+ }
1892
+ if (pen.flipY) {
1893
+ _anchors.forEach((anchor) => {
1894
+ anchor.y = 0.5 - (anchor.y - 0.5);
1895
+ });
1896
+ }
1897
+ _anchors.forEach((anchor) => {
1898
+ anchors.push(calcWorldPointOfPen(pen, anchor));
1899
+ });
1900
+ }
1901
+ // Default anchors of node
1902
+ if (!anchors.length &&
1903
+ !pen.type &&
1904
+ !pen.calculative.canvas.parent.isCombine(pen)) {
1905
+ const { x, y, width, height } = pen.calculative.worldRect;
1906
+ anchors = store.options.defaultAnchors.map((anchor, index) => {
1907
+ return {
1908
+ id: `${index}`,
1909
+ penId: pen.id,
1910
+ x: x + width * anchor.x,
1911
+ y: y + height * anchor.y,
1912
+ };
1913
+ });
1914
+ }
1915
+ if (pen.calculative.rotate) {
1916
+ anchors.forEach((anchor) => {
1917
+ rotatePoint(anchor, pen.calculative.rotate, pen.calculative.worldRect.pivot || pen.calculative.worldRect.center);
1918
+ });
1919
+ }
1920
+ if (!pen.type || pen.anchors) {
1921
+ pen.calculative.worldAnchors = anchors;
1922
+ }
1923
+ if (pen.calculative.activeAnchor && anchors.length) {
1924
+ pen.calculative.activeAnchor = anchors.find((a) => {
1925
+ a.id === pen.calculative.activeAnchor.id;
1926
+ });
1927
+ }
1928
+ pen.calculative.gradientAnimatePath = undefined;
1929
+ }
1930
+ export function calcChildrenInitRect(pen) {
1931
+ // 重新计算子节点初始化坐标
1932
+ if (pen.children?.length) {
1933
+ let parentRect = pen.calculative.worldRect;
1934
+ pen.children.forEach((id) => {
1935
+ const child = pen.calculative.canvas.store.pens[id];
1936
+ if (child.calculative.initRect && child.calculative.initRelativeRect) {
1937
+ child.calculative.initRect.x =
1938
+ parentRect.x +
1939
+ parentRect.width * child.calculative.initRelativeRect.x;
1940
+ child.calculative.initRect.y =
1941
+ parentRect.y +
1942
+ parentRect.height * child.calculative.initRelativeRect.y;
1943
+ child.calculative.initRect.ex =
1944
+ child.calculative.initRect.x +
1945
+ parentRect.width * child.calculative.initRelativeRect.width;
1946
+ child.calculative.initRect.ey =
1947
+ child.calculative.initRect.y +
1948
+ parentRect.height +
1949
+ child.calculative.initRelativeRect.height;
1950
+ calcCenter(child.calculative.initRect);
1951
+ }
1952
+ calcChildrenInitRect(child);
1953
+ });
1954
+ }
1955
+ }
1956
+ export function calcWorldPointOfPen(pen, pt) {
1957
+ const p = { ...pt };
1958
+ const { x, y, width, height } = pen.calculative.worldRect;
1959
+ p.x = x + width * pt.x;
1960
+ p.y = y + height * pt.y;
1961
+ if (pt.prev) {
1962
+ p.prev = {
1963
+ penId: pen.id,
1964
+ connectTo: pt.prev.connectTo,
1965
+ x: x + width * pt.prev.x,
1966
+ y: y + height * pt.prev.y,
1967
+ };
1968
+ }
1969
+ if (pt.next) {
1970
+ p.next = {
1971
+ penId: pen.id,
1972
+ connectTo: pt.next.connectTo,
1973
+ x: x + width * pt.next.x,
1974
+ y: y + height * pt.next.y,
1975
+ };
1976
+ }
1977
+ return p;
1978
+ }
1979
+ export function calcIconRect(pens, pen) {
1980
+ const { paddingTop, paddingBottom, paddingLeft, paddingRight } = pen.calculative;
1981
+ let x = paddingLeft;
1982
+ let y = paddingTop;
1983
+ let width = pen.calculative.worldRect.width - paddingLeft - paddingRight;
1984
+ let height = pen.calculative.worldRect.height - paddingTop - paddingBottom;
1985
+ let iconLeft = pen.calculative.iconLeft;
1986
+ let iconTop = pen.calculative.iconTop;
1987
+ if (iconLeft && Math.abs(iconLeft) < 1) {
1988
+ iconLeft = pen.calculative.worldRect.width * iconLeft;
1989
+ }
1990
+ if (iconTop && Math.abs(iconTop) < 1) {
1991
+ iconTop = pen.calculative.worldRect.height * iconTop;
1992
+ }
1993
+ x += iconLeft || 0;
1994
+ y += iconTop || 0;
1995
+ width -= iconLeft || 0;
1996
+ height -= iconTop || 0;
1997
+ let rotate = pen.calculative.iconRotate || 0;
1998
+ if (pen.parentId) {
1999
+ const parentPen = pens[pen.parentId].calculative;
2000
+ if (parentPen) {
2001
+ rotate += parentPen.rotate;
2002
+ rotate %= 360;
2003
+ }
2004
+ }
2005
+ x = pen.calculative.worldRect.x + x;
2006
+ y = pen.calculative.worldRect.y + y;
2007
+ pen.calculative.worldIconRect = {
2008
+ x,
2009
+ y,
2010
+ width,
2011
+ height,
2012
+ rotate,
2013
+ };
2014
+ calcRightBottom(pen.calculative.worldIconRect);
2015
+ calcCenter(pen.calculative.worldIconRect);
2016
+ }
2017
+ export function scalePen(pen, scale, center) {
2018
+ scaleRect(pen.calculative.worldRect, scale, center, pen.pivot);
2019
+ if (pen.calculative.initRect) {
2020
+ scaleRect(pen.calculative.initRect, scale, center, pen.pivot);
2021
+ }
2022
+ scaleChildrenInitRect(pen, scale, center);
2023
+ if (pen.calculative.x) {
2024
+ scalePoint(pen.calculative, scale, center);
2025
+ }
2026
+ if (pen.type) {
2027
+ calcWorldAnchors(pen);
2028
+ }
2029
+ }
2030
+ export function scaleChildrenInitRect(pen, scale, center) {
2031
+ if (!pen) {
2032
+ return;
2033
+ }
2034
+ if (pen.children?.length) {
2035
+ pen.children.forEach((id) => {
2036
+ const child = pen.calculative.canvas.store.pens[id];
2037
+ if (child) {
2038
+ if (child.calculative.initRect) {
2039
+ scaleRect(child.calculative.initRect, scale, center);
2040
+ }
2041
+ scaleChildrenInitRect(child, scale, center);
2042
+ }
2043
+ });
2044
+ }
2045
+ }
2046
+ export function pushPenAnchor(pen, pt) {
2047
+ if (!pen.anchors) {
2048
+ pen.anchors = [];
2049
+ }
2050
+ if (!pen.calculative.worldAnchors) {
2051
+ pen.calculative.worldAnchors = [];
2052
+ }
2053
+ const worldAnchor = {
2054
+ id: pt.id,
2055
+ penId: pen.id,
2056
+ x: pt.x,
2057
+ y: pt.y,
2058
+ };
2059
+ pen.calculative.worldAnchors.push(worldAnchor);
2060
+ if (pen.calculative.worldRect) {
2061
+ if (pen.rotate % 360) {
2062
+ rotatePoint(pt, -pen.rotate, pen.calculative.worldRect.center);
2063
+ }
2064
+ const anchor = {
2065
+ id: pt.id,
2066
+ penId: pen.id,
2067
+ x: (pt.x - pen.calculative.worldRect.x) / pen.calculative.worldRect.width,
2068
+ y: (pt.y - pen.calculative.worldRect.y) / pen.calculative.worldRect.height,
2069
+ };
2070
+ pen.anchors.push(anchor);
2071
+ }
2072
+ return worldAnchor;
2073
+ }
2074
+ export function addLineAnchor(pen, pt, index) {
2075
+ if (!pen.anchors) {
2076
+ pen.anchors = [];
2077
+ }
2078
+ if (!pen.calculative.worldAnchors) {
2079
+ pen.calculative.worldAnchors = [];
2080
+ }
2081
+ const worldAnchor = getSplitAnchor(pen, pt, index);
2082
+ pen.calculative.worldAnchors.splice(index + 1, 0, worldAnchor);
2083
+ pen.anchors.splice(index + 1, 0, calcRelativePoint(worldAnchor, pen.calculative.worldRect));
2084
+ pen.calculative.activeAnchor = worldAnchor;
2085
+ return worldAnchor;
2086
+ }
2087
+ export function removePenAnchor(pen, anchor) {
2088
+ if (!pen || !pen.calculative.worldAnchors) {
2089
+ return;
2090
+ }
2091
+ let i = pen.calculative.worldAnchors.findIndex((a) => a.id === anchor.id);
2092
+ if (i > -1) {
2093
+ pen.calculative.worldAnchors.splice(i, 1);
2094
+ }
2095
+ i = pen.anchors.findIndex((a) => a.id === anchor.id);
2096
+ if (i > -1) {
2097
+ pen.anchors.splice(i, 1);
2098
+ }
2099
+ }
2100
+ export function facePen(pt, pen) {
2101
+ if (!pen || !pen.calculative || !pen.calculative.worldRect.center) {
2102
+ return Direction.None;
2103
+ }
2104
+ if (pt.anchorId) {
2105
+ let anchor = pen.anchors.filter((_anchor) => _anchor.id === pt.anchorId);
2106
+ if (anchor.length) {
2107
+ if (anchor[0].direction > -1) {
2108
+ return anchor[0].direction;
2109
+ }
2110
+ }
2111
+ }
2112
+ return facePoint(pt, pen.calculative.worldRect.center);
2113
+ }
2114
+ export function nearestAnchor(pen, pt) {
2115
+ let dis = Infinity;
2116
+ let anchor;
2117
+ pen.calculative.worldAnchors.forEach((a) => {
2118
+ const d = distance(pt, a);
2119
+ if (dis > d) {
2120
+ dis = d;
2121
+ anchor = a;
2122
+ }
2123
+ });
2124
+ return anchor;
2125
+ }
2126
+ export function translateLine(pen, x, y) {
2127
+ pen.x += x;
2128
+ pen.y += y;
2129
+ if (pen.anchors) {
2130
+ pen.anchors.forEach((a) => {
2131
+ translatePoint(a, x, y);
2132
+ });
2133
+ }
2134
+ if (pen.calculative.worldAnchors) {
2135
+ pen.calculative.worldAnchors.forEach((a) => {
2136
+ translatePoint(a, x, y);
2137
+ });
2138
+ }
2139
+ }
2140
+ export function deleteTempAnchor(pen) {
2141
+ if (pen && pen.calculative && pen.calculative.worldAnchors.length) {
2142
+ let to = getToAnchor(pen);
2143
+ // 第一次画线
2144
+ if (!pen.anchors || !pen.anchors.length) {
2145
+ while (pen.calculative.worldAnchors.length &&
2146
+ to !== pen.calculative.activeAnchor) {
2147
+ pen.calculative.worldAnchors.pop();
2148
+ to = getToAnchor(pen);
2149
+ }
2150
+ }
2151
+ // 拖拽终点
2152
+ else if (to === pen.calculative.activeAnchor) {
2153
+ pen.calculative.worldAnchors = [pen.calculative.worldAnchors[0]];
2154
+ }
2155
+ // 拖拽起点
2156
+ else if (pen.calculative.worldAnchors[0] === pen.calculative.activeAnchor) {
2157
+ pen.calculative.worldAnchors = [
2158
+ pen.calculative.worldAnchors[pen.calculative.worldAnchors.length - 1],
2159
+ ];
2160
+ }
2161
+ }
2162
+ }
2163
+ /**
2164
+ * 添加line到pen的connectedLines中,并关联相关属性
2165
+ * 不添加连线到画布中,请确保画布中已经有该连线。
2166
+ * */
2167
+ export function connectLine(pen, anchor, line, lineAnchor) {
2168
+ if (!pen ||
2169
+ !anchor ||
2170
+ !line ||
2171
+ !lineAnchor ||
2172
+ anchor.twoWay === TwoWay.DisableConnected ||
2173
+ anchor.twoWay === TwoWay.Disable ||
2174
+ lineAnchor.twoWay === TwoWay.DisableConnectTo ||
2175
+ lineAnchor.twoWay === TwoWay.Disable) {
2176
+ return;
2177
+ }
2178
+ if (anchor.twoWay === TwoWay.In) {
2179
+ if (line.calculative.worldAnchors.length === 1) {
2180
+ return;
2181
+ }
2182
+ const to = getToAnchor(line);
2183
+ if (lineAnchor.id !== to.id) {
2184
+ return;
2185
+ }
2186
+ }
2187
+ if (anchor.twoWay === TwoWay.Out) {
2188
+ const from = getFromAnchor(line);
2189
+ if (lineAnchor.id !== from.id) {
2190
+ return;
2191
+ }
2192
+ }
2193
+ if (lineAnchor.connectTo === pen.id && lineAnchor.anchorId === anchor.id) {
2194
+ return;
2195
+ }
2196
+ if (lineAnchor.connectTo) {
2197
+ const p = pen.calculative.canvas.store.pens[lineAnchor.connectTo];
2198
+ disconnectLine(p, getAnchor(p, lineAnchor.anchorId), line, lineAnchor);
2199
+ }
2200
+ if (!pen.connectedLines) {
2201
+ pen.connectedLines = [];
2202
+ }
2203
+ const i = pen.connectedLines.findIndex((item) => item.lineId === line.id &&
2204
+ item.lineAnchor === lineAnchor.id &&
2205
+ item.anchor === anchor.id);
2206
+ if (i < 0) {
2207
+ pen.connectedLines.push({
2208
+ lineId: line.id,
2209
+ lineAnchor: lineAnchor.id,
2210
+ anchor: anchor.id,
2211
+ });
2212
+ }
2213
+ lineAnchor.connectTo = pen.id;
2214
+ lineAnchor.anchorId = anchor.id;
2215
+ // 如果两条连线,则相互关联
2216
+ if (pen.type) {
2217
+ connectLine(line, lineAnchor, pen, anchor);
2218
+ }
2219
+ pen.calculative.canvas.store.emitter.emit('connectLine', {
2220
+ line,
2221
+ lineAnchor,
2222
+ pen,
2223
+ anchor,
2224
+ });
2225
+ // 新增连线生命周期
2226
+ let fromPen = line.calculative.worldAnchors?.length >= 2
2227
+ ? line.calculative.worldAnchors?.[0].connectTo
2228
+ : undefined;
2229
+ let fromAnchor = line.calculative.worldAnchors?.length >= 2
2230
+ ? line.calculative.canvas.store.pens[line.calculative.worldAnchors?.[0].connectTo]?.anchors.find((i) => i.id === line.calculative.worldAnchors?.[0].anchorId)
2231
+ : undefined; // num
2232
+ pen.onConnectLine?.(pen, {
2233
+ line,
2234
+ lineAnchor,
2235
+ pen,
2236
+ anchor,
2237
+ fromPen,
2238
+ fromAnchor,
2239
+ });
2240
+ return true;
2241
+ }
2242
+ /**
2243
+ * 从 pen.connectedLines 中删除 lineId 和 lineAnchor
2244
+ */
2245
+ export function disconnectLine(pen, anchor, line, lineAnchor) {
2246
+ if (!pen || !anchor || !line || !lineAnchor) {
2247
+ return;
2248
+ }
2249
+ if (!pen.connectedLines || !pen.connectedLines.length) {
2250
+ return;
2251
+ }
2252
+ if (!line.lastConnected) {
2253
+ line.lastConnected = {};
2254
+ }
2255
+ if (!line.lastConnected[pen.id]) {
2256
+ line.lastConnected[pen.id] = deepClone(pen.connectedLines);
2257
+ }
2258
+ pen.connectedLines.forEach((item, index, arr) => {
2259
+ if ((item.lineId === line.id || item.lineId === line.id) &&
2260
+ item.lineAnchor === lineAnchor.id &&
2261
+ item.anchor === anchor.id) {
2262
+ arr.splice(index, 1);
2263
+ }
2264
+ });
2265
+ lineAnchor.connectTo = undefined;
2266
+ lineAnchor.anchorId = undefined;
2267
+ // 如果两条连线相互关联,则都取消关联
2268
+ if (pen.type &&
2269
+ anchor.connectTo === line.id &&
2270
+ anchor.anchorId === lineAnchor.id) {
2271
+ disconnectLine(line, lineAnchor, pen, anchor);
2272
+ }
2273
+ pen.calculative.canvas.store.emitter.emit('disconnectLine', {
2274
+ line,
2275
+ lineAnchor,
2276
+ pen,
2277
+ anchor,
2278
+ });
2279
+ return true;
2280
+ }
2281
+ export function getAnchor(pen, anchorId) {
2282
+ if (!pen || !anchorId) {
2283
+ return;
2284
+ }
2285
+ return pen.calculative.worldAnchors?.find((item) => item.id === anchorId);
2286
+ }
2287
+ export function getFromAnchor(pen) {
2288
+ if (!pen || !pen.calculative.worldAnchors) {
2289
+ return;
2290
+ }
2291
+ return pen.calculative.worldAnchors[0];
2292
+ }
2293
+ export function getToAnchor(pen) {
2294
+ if (!pen || !pen.calculative.worldAnchors) {
2295
+ return;
2296
+ }
2297
+ return pen.calculative.worldAnchors[pen.calculative.worldAnchors.length - 1];
2298
+ }
2299
+ export function setNodeAnimate(pen, now) {
2300
+ if (pen.calculative.start === 0 || !pen.frames || !pen.frames.length) {
2301
+ pen.calculative.start = undefined;
2302
+ return 0;
2303
+ }
2304
+ if (!pen.calculative.duration) {
2305
+ pen.calculative.duration = 0;
2306
+ for (const f of pen.frames) {
2307
+ pen.calculative.duration += f.duration;
2308
+ for (const k in f) {
2309
+ if (k !== 'duration' && !pen[k]) {
2310
+ if (k === 'scale') {
2311
+ pen[k] = 1;
2312
+ }
2313
+ }
2314
+ }
2315
+ }
2316
+ }
2317
+ if (!pen.animateCycle) {
2318
+ pen.animateCycle = Infinity;
2319
+ }
2320
+ if (!pen.calculative.start) {
2321
+ pen.calculative.start = now;
2322
+ pen.calculative.frameIndex = 0;
2323
+ pen.calculative.frameStart = pen.calculative.start;
2324
+ pen.calculative.frameDuration = pen.frames[0].duration;
2325
+ pen.calculative.frameEnd =
2326
+ pen.calculative.frameStart + pen.calculative.frameDuration;
2327
+ pen.calculative.cycleIndex = 1;
2328
+ pen.calculative.x = pen.calculative.worldRect.x;
2329
+ pen.calculative.y = pen.calculative.worldRect.y;
2330
+ pen.calculative.initRect = deepClone(pen.calculative.worldRect);
2331
+ if (pen.parentId) {
2332
+ pen.calculative.initRelativeRect = {
2333
+ x: pen.x,
2334
+ y: pen.y,
2335
+ width: pen.width,
2336
+ height: pen.height,
2337
+ };
2338
+ }
2339
+ if (pen.children?.length) {
2340
+ const store = pen.calculative.canvas.store;
2341
+ pen.calculative.childrenVisible = {};
2342
+ pen.children.forEach((id) => {
2343
+ pen.calculative.childrenVisible[id] = store.pens[id].visible;
2344
+ });
2345
+ }
2346
+ pen.calculative.initRect.rotate = pen.calculative.rotate || 0;
2347
+ initPrevFrame(pen);
2348
+ }
2349
+ else {
2350
+ let frameIndex = 0;
2351
+ const cycleIndex = Math.ceil((now - pen.calculative.start) / pen.calculative.duration);
2352
+ // 播放结束
2353
+ if (cycleIndex > pen.animateCycle) {
2354
+ pen.currentAnimation = undefined;
2355
+ pen.calculative.start = undefined;
2356
+ setNodeAnimateProcess(pen, 1);
2357
+ return 0;
2358
+ }
2359
+ const pos = (now - pen.calculative.start) % pen.calculative.duration;
2360
+ let d = 0;
2361
+ for (const frame of pen.frames) {
2362
+ d += frame.duration;
2363
+ if (pos > d) {
2364
+ ++frameIndex;
2365
+ }
2366
+ else {
2367
+ break;
2368
+ }
2369
+ }
2370
+ // 帧超出
2371
+ if (!pen.frames[frameIndex]) {
2372
+ return true;
2373
+ }
2374
+ pen.calculative.frameDuration = pen.frames[frameIndex].duration;
2375
+ pen.calculative.frameStart =
2376
+ pen.calculative.start + pen.calculative.duration * (cycleIndex - 1);
2377
+ pen.calculative.frameEnd =
2378
+ pen.calculative.frameStart + pen.calculative.frameDuration;
2379
+ // 换帧
2380
+ const frameChanged = frameIndex !== pen.calculative.frameIndex;
2381
+ // 新循环播放
2382
+ const cycleChanged = cycleIndex > pen.calculative.cycleIndex;
2383
+ frameChanged && (pen.calculative.frameIndex = frameIndex);
2384
+ cycleChanged && (pen.calculative.cycleIndex = cycleIndex);
2385
+ if (frameChanged || cycleChanged) {
2386
+ // 以初始位置为参考点。因为网页在后台时,不执行动画帧,网页恢复显示时,位置不确定
2387
+ pen.calculative.x = pen.calculative.initRect.x;
2388
+ pen.calculative.y = pen.calculative.initRect.y;
2389
+ if (pen.children?.length && !pen.parentId) {
2390
+ pen.calculative.canvas.rotatePen(pen, (pen.calculative.initRect.rotate || 0) -
2391
+ (pen.calculative.rotate || 0), pen.calculative.initRect);
2392
+ }
2393
+ else {
2394
+ pen.calculative.rotate = pen.calculative.initRect.rotate || 0;
2395
+ }
2396
+ if (frameIndex > 0) {
2397
+ pen.prevFrame = {};
2398
+ const prevFrame = pen.frames[frameIndex - 1];
2399
+ for (const k in prevFrame) {
2400
+ pen.prevFrame[k] = prevFrame[k];
2401
+ }
2402
+ Object.assign(pen.prevFrame, {
2403
+ rotate: prevFrame.rotate || 0,
2404
+ x: prevFrame.x || 0,
2405
+ y: prevFrame.y || 0,
2406
+ scale: prevFrame.scale || 1,
2407
+ });
2408
+ }
2409
+ else {
2410
+ initPrevFrame(pen);
2411
+ }
2412
+ }
2413
+ }
2414
+ const process = ((now - pen.calculative.frameStart) / pen.calculative.frameDuration) % 1;
2415
+ setNodeAnimateProcess(pen, process);
2416
+ return true;
2417
+ }
2418
+ // 把前一个动画帧初始化为播放前状态
2419
+ export function initPrevFrame(pen) {
2420
+ pen.prevFrame = {};
2421
+ for (const k in pen) {
2422
+ if (typeof pen[k] !== 'object' || k === 'lineDash') {
2423
+ pen.prevFrame[k] = pen[k];
2424
+ }
2425
+ }
2426
+ pen.prevFrame.rotate = 0;
2427
+ pen.prevFrame.x = 0;
2428
+ pen.prevFrame.y = 0;
2429
+ pen.prevFrame.scale = 1;
2430
+ }
2431
+ // 根据process进度值(纯小数),计算节点动画属性
2432
+ export function setNodeAnimateProcess(pen, process) {
2433
+ if (process < 0) {
2434
+ return;
2435
+ }
2436
+ if (process > 1) {
2437
+ process = 1;
2438
+ }
2439
+ const frame = pen.frames[pen.calculative.frameIndex];
2440
+ for (const k in frame) {
2441
+ if (k === 'duration') {
2442
+ continue;
2443
+ }
2444
+ else if (k === 'scale') {
2445
+ pen.calculative.worldRect = deepClone(pen.calculative.initRect);
2446
+ scaleRect(pen.calculative.worldRect, pen.prevFrame.scale, pen.calculative.worldRect.center);
2447
+ const newScale = pen.prevFrame.scale + (frame[k] - pen.prevFrame.scale) * process;
2448
+ scaleRect(pen.calculative.worldRect, newScale / pen.prevFrame.scale, pen.calculative.worldRect.center);
2449
+ pen.calculative.patchFlags = true;
2450
+ }
2451
+ else if (k === 'x') {
2452
+ const lastVal = getFrameValue(pen, k, pen.calculative.frameIndex);
2453
+ pen.calculative.worldRect.x = pen.calculative.initRect.x + lastVal;
2454
+ pen.calculative.worldRect.ex = pen.calculative.initRect.ex + lastVal;
2455
+ translateRect(pen.calculative.worldRect, frame[k] * process * pen.calculative.canvas.store.data.scale, 0);
2456
+ pen.calculative.patchFlags = true;
2457
+ }
2458
+ else if (k === 'y') {
2459
+ const lastVal = getFrameValue(pen, k, pen.calculative.frameIndex);
2460
+ pen.calculative.worldRect.y = pen.calculative.initRect.y + lastVal;
2461
+ pen.calculative.worldRect.ey = pen.calculative.initRect.ey + lastVal;
2462
+ translateRect(pen.calculative.worldRect, 0, frame[k] * process * pen.calculative.canvas.store.data.scale);
2463
+ pen.calculative.patchFlags = true;
2464
+ }
2465
+ else if (k === 'rotate') {
2466
+ if (pen.prevFrame[k] >= 360) {
2467
+ pen.prevFrame[k] %= 360;
2468
+ }
2469
+ const lastVal = getFrameValue(pen, k, pen.calculative.frameIndex);
2470
+ const offsetRotate = ((pen.calculative.initRect.rotate + lastVal + frame[k] * process) %
2471
+ 360) -
2472
+ (pen.calculative.rotate || 0);
2473
+ if (pen.children?.length) {
2474
+ pen.calculative.canvas.rotatePen(pen, offsetRotate, pen.calculative.initRect);
2475
+ }
2476
+ else {
2477
+ pen.calculative.rotate =
2478
+ (pen.calculative.initRect.rotate + lastVal + frame[k] * process) %
2479
+ 360;
2480
+ }
2481
+ pen.calculative.patchFlags = true;
2482
+ }
2483
+ else if (k === 'image') {
2484
+ pen.image = frame['image'];
2485
+ pen.calculative.image = undefined;
2486
+ pen.calculative.canvas.loadImage(pen);
2487
+ // if (pen.isBottom) {
2488
+ // pen.calculative.canvas.canvasImageBottom.init();
2489
+ // } else {
2490
+ // pen.calculative.canvas.canvasImage.init();
2491
+ // }
2492
+ if (pen.canvasLayer === CanvasLayer.CanvasImageBottom) {
2493
+ pen.calculative.canvas.canvasImageBottom.init();
2494
+ }
2495
+ else if (pen.canvasLayer === CanvasLayer.CanvasImage) {
2496
+ pen.calculative.canvas.canvasImage.init();
2497
+ }
2498
+ }
2499
+ else if (isLinear(frame[k], k, pen)) {
2500
+ if (pen.prevFrame[k] == null) {
2501
+ if (k === 'globalAlpha') {
2502
+ pen.prevFrame[k] = 1;
2503
+ }
2504
+ else {
2505
+ pen.prevFrame[k] = 0;
2506
+ }
2507
+ }
2508
+ const current = pen.prevFrame[k] + (frame[k] - pen.prevFrame[k]) * process;
2509
+ pen.calculative[k] = Math.round(current * 100) / 100;
2510
+ }
2511
+ else {
2512
+ if (k === 'visible') {
2513
+ if (pen.calculative.image) {
2514
+ // if (pen.isBottom) {
2515
+ // pen.calculative.canvas.canvasImageBottom.init();
2516
+ // } else {
2517
+ // pen.calculative.canvas.canvasImage.init();
2518
+ // }
2519
+ if (pen.canvasLayer === CanvasLayer.CanvasImageBottom) {
2520
+ pen.calculative.canvas.canvasImageBottom.init();
2521
+ }
2522
+ else if (pen.canvasLayer === CanvasLayer.CanvasImage) {
2523
+ pen.calculative.canvas.canvasImage.init();
2524
+ }
2525
+ }
2526
+ else if (pen.children?.length) {
2527
+ const childs = getAllChildren(pen, pen.calculative.canvas.store);
2528
+ pen.calculative.canvas.initImageCanvas(childs);
2529
+ }
2530
+ }
2531
+ pen.calculative[k] = frame[k];
2532
+ const v = {};
2533
+ v[k] = frame[k];
2534
+ setChildValue(pen, v);
2535
+ }
2536
+ if (k === 'text') {
2537
+ calcTextLines(pen);
2538
+ }
2539
+ }
2540
+ }
2541
+ /**
2542
+ * 值类型为 number , pen.linear 为 false 时,且 key 不属于 noLinear 时,返回 true
2543
+ * @param value 值
2544
+ * @param key 键值
2545
+ * @param pen 画笔
2546
+ * @returns
2547
+ */
2548
+ function isLinear(value, key, pen) {
2549
+ // 不线性变化的属性
2550
+ const noLinear = ['strokeType', 'bkType', 'showChild'];
2551
+ return (typeof value === 'number' &&
2552
+ pen.linear !== false &&
2553
+ !noLinear.includes(key));
2554
+ }
2555
+ export function setLineAnimate(pen, now) {
2556
+ if (pen.calculative.start === 0) {
2557
+ pen.calculative.start = undefined;
2558
+ return 0;
2559
+ }
2560
+ if (!pen.animateCycle) {
2561
+ pen.animateCycle = Infinity;
2562
+ }
2563
+ if (!pen.animateSpan) {
2564
+ pen.animateSpan = 1;
2565
+ }
2566
+ pen.calculative.animatePos +=
2567
+ pen.animateSpan * (pen.calculative.canvas.store.data.scale || 1);
2568
+ if (!pen.calculative.start) {
2569
+ pen.calculative.start = Date.now();
2570
+ pen.calculative.animatePos =
2571
+ pen.animateSpan * (pen.calculative.canvas.store.data.scale || 1);
2572
+ pen.calculative.cycleIndex = 1;
2573
+ }
2574
+ else if (pen.calculative.animatePos > pen.length) {
2575
+ // 播放到尾了
2576
+ ++pen.calculative.cycleIndex;
2577
+ // 播放结束
2578
+ if (pen.calculative.cycleIndex > pen.animateCycle) {
2579
+ pen.currentAnimation = undefined;
2580
+ pen.calculative.start = undefined;
2581
+ return 0;
2582
+ }
2583
+ pen.calculative.animatePos = pen.animateSpan;
2584
+ }
2585
+ return true;
2586
+ }
2587
+ export function setChildrenActive(pen, active = true) {
2588
+ if (!pen.children || pen.childActive === false) {
2589
+ return;
2590
+ }
2591
+ const store = pen.calculative.canvas.store;
2592
+ pen.children.forEach((id) => {
2593
+ const child = store.pens[id];
2594
+ if (child) {
2595
+ child.calculative.active = active;
2596
+ setChildrenActive(child, active);
2597
+ }
2598
+ });
2599
+ }
2600
+ export function setHover(pen, hover = true) {
2601
+ if (!pen) {
2602
+ return;
2603
+ }
2604
+ const store = pen.calculative.canvas.store;
2605
+ pen.calculative.hover = hover;
2606
+ if (pen.childHover === false) {
2607
+ return;
2608
+ }
2609
+ if (pen.children) {
2610
+ pen.children.forEach((id) => {
2611
+ // 子节点没有自己的独立hover,继承父节点hover
2612
+ if (store.pens[id]?.hoverColor == undefined &&
2613
+ store.pens[id]?.hoverBackground == undefined) {
2614
+ setHover(store.pens[id], hover);
2615
+ }
2616
+ });
2617
+ }
2618
+ }
2619
+ export function setElemPosition(pen, elem) {
2620
+ if (!elem) {
2621
+ return;
2622
+ }
2623
+ const store = pen.calculative.canvas.store;
2624
+ const worldRect = pen.calculative.worldRect;
2625
+ elem.style.opacity = pen.globalAlpha + '';
2626
+ elem.style.position = 'absolute';
2627
+ elem.style.outline = 'none';
2628
+ elem.style.left = worldRect.x + store.data.x + 'px';
2629
+ elem.style.top = worldRect.y + store.data.y + 'px';
2630
+ elem.style.width = worldRect.width + 'px';
2631
+ elem.style.height = worldRect.height + 'px';
2632
+ elem.style.display =
2633
+ pen.calculative.inView != false
2634
+ ? pen.calculative.cssDisplay || 'inline'
2635
+ : 'none'; // 是否隐藏元素
2636
+ !pen.calculative.rotate && (pen.calculative.rotate = 0);
2637
+ elem.style.transform = `rotate(${pen.calculative.rotate}deg)`;
2638
+ if (!pen.calculative.rotate) {
2639
+ if (pen.calculative.flipX) {
2640
+ elem.style.transform = `rotateY(180deg)`;
2641
+ }
2642
+ if (pen.calculative.flipY) {
2643
+ elem.style.transform = `rotateX(180deg)`;
2644
+ }
2645
+ if (pen.calculative.flipX && pen.calculative.flipY) {
2646
+ elem.style.transform = `rotateZ(180deg)`;
2647
+ }
2648
+ }
2649
+ elem.style.zIndex =
2650
+ pen.calculative.zIndex !== undefined ? pen.calculative.zIndex + '' : '5';
2651
+ if (pen.calculative.zIndex > pen.calculative.canvas.maxZindex) {
2652
+ pen.calculative.canvas.maxZindex = pen.calculative.zIndex;
2653
+ }
2654
+ if (pen.locked === LockState.DisableEdit ||
2655
+ pen.locked === LockState.DisableMove ||
2656
+ store.data.locked) {
2657
+ // gif 组合后,作为子节点可通过 lockedOnCombine 来决定自身的 locked 状态
2658
+ elem.style.userSelect = 'initial';
2659
+ elem.style.pointerEvents = 'initial';
2660
+ if (pen.name === 'gif') {
2661
+ elem.style.userSelect = 'none';
2662
+ elem.style.pointerEvents = 'none';
2663
+ }
2664
+ }
2665
+ else {
2666
+ // pen.locked LockState.Disable 不响应鼠标
2667
+ elem.style.userSelect = 'none';
2668
+ elem.style.pointerEvents = 'none';
2669
+ }
2670
+ }
2671
+ export function setElemImg(pen, elem) {
2672
+ if (!elem) {
2673
+ return;
2674
+ }
2675
+ //https://github.com/niklasvh/html2canvas
2676
+ globalThis.html2canvas &&
2677
+ globalThis.html2canvas(elem).then(function (canvas) {
2678
+ // document.body.appendChild(canvas);
2679
+ const img = new Image();
2680
+ img.src = canvas.toDataURL('image/png', 0.1);
2681
+ if (img.src.length > 10) {
2682
+ pen.calculative.img = img;
2683
+ }
2684
+ });
2685
+ }
2686
+ /**
2687
+ * 每个画笔 locked
2688
+ * @param pens 画笔
2689
+ * @returns
2690
+ */
2691
+ export function getPensLock(pens) {
2692
+ return pens.every((pen) => pen.locked);
2693
+ }
2694
+ /**
2695
+ * 画笔们的 disabledRotate = true
2696
+ * 即 全部禁止旋转 返回 true
2697
+ * @param pens 画笔
2698
+ * @returns
2699
+ */
2700
+ export function getPensDisableRotate(pens) {
2701
+ return pens.every((pen) => pen.disableRotate);
2702
+ }
2703
+ export function rotatePen(pen, angle, rect) {
2704
+ if (pen.type) {
2705
+ pen.calculative.worldAnchors.forEach((anchor) => {
2706
+ rotatePoint(anchor, angle, rect.center);
2707
+ });
2708
+ initLineRect(pen);
2709
+ calcPenRect(pen);
2710
+ }
2711
+ else {
2712
+ if (pen.calculative.rotate) {
2713
+ pen.calculative.rotate += angle;
2714
+ }
2715
+ else {
2716
+ pen.calculative.rotate = angle;
2717
+ }
2718
+ rotatePoint(pen.calculative.worldRect.center, angle, rect.center);
2719
+ if (pen.parentId) {
2720
+ pen.calculative.worldRect.x =
2721
+ pen.calculative.worldRect.center.x -
2722
+ pen.calculative.worldRect.width / 2;
2723
+ pen.calculative.worldRect.y =
2724
+ pen.calculative.worldRect.center.y -
2725
+ pen.calculative.worldRect.height / 2;
2726
+ pen.x = (pen.calculative.worldRect.x - rect.x) / rect.width;
2727
+ pen.y = (pen.calculative.worldRect.y - rect.y) / rect.height;
2728
+ }
2729
+ }
2730
+ pen.children?.forEach((id) => {
2731
+ const child = pen.calculative.canvas.store.pens[id];
2732
+ rotatePen(child, angle, rect);
2733
+ });
2734
+ }
2735
+ function initLineRect(pen) {
2736
+ if (!pen.calculative.worldAnchors?.length) {
2737
+ return;
2738
+ }
2739
+ if (!isFinite(pen.x) || !isFinite(pen.x)) {
2740
+ return;
2741
+ }
2742
+ if (pen.x == null || pen.y == null) {
2743
+ return;
2744
+ }
2745
+ const rect = getLineRect(pen);
2746
+ if (!pen.parentId) {
2747
+ Object.assign(pen, rect);
2748
+ }
2749
+ const { fontSize, lineHeight } = pen.calculative.canvas.store.options;
2750
+ if (!pen.fontSize) {
2751
+ pen.fontSize = fontSize >= 0 ? fontSize : 12;
2752
+ pen.calculative.fontSize =
2753
+ pen.fontSize * pen.calculative.canvas.store.data.scale;
2754
+ }
2755
+ else if (pen.fontSize < 0) {
2756
+ pen.fontSize = 0;
2757
+ pen.calculative.fontSize = 0;
2758
+ }
2759
+ if (!pen.lineHeight) {
2760
+ pen.lineHeight = lineHeight;
2761
+ pen.calculative.lineHeight = pen.lineHeight;
2762
+ }
2763
+ calcCenter(rect);
2764
+ pen.calculative.worldRect = rect;
2765
+ calcPadding(pen, rect);
2766
+ calcTextRect(pen);
2767
+ if (pen.calculative.worldAnchors) {
2768
+ pen.anchors = pen.calculative.worldAnchors.map((pt) => {
2769
+ return calcRelativePoint(pt, pen.calculative.worldRect);
2770
+ });
2771
+ }
2772
+ }
2773
+ /**
2774
+ * 画笔们的 disableSize = true
2775
+ * 即 全部不允许改变大小 返回 true
2776
+ * @param pens 画笔
2777
+ * @returns
2778
+ */
2779
+ export function getPensDisableResize(pens) {
2780
+ return pens.every((pen) => pen.disableSize || pen.pivot); //旋转中心点图元不允许改变大小
2781
+ }
2782
+ export function getFrameValue(pen, prop, frameIndex) {
2783
+ if (!pen.frames || !prop) {
2784
+ return 0;
2785
+ }
2786
+ let v = 0;
2787
+ for (let i = 0; i < frameIndex; i++) {
2788
+ if (pen.frames[i]) {
2789
+ v += pen.frames[i][prop] || 0;
2790
+ }
2791
+ }
2792
+ return v;
2793
+ }
2794
+ /**
2795
+ * 判断该画笔 是否是组合为状态中 展示的画笔
2796
+ */
2797
+ export function isShowChild(pen, store) {
2798
+ let selfPen = pen;
2799
+ while (selfPen && selfPen.parentId) {
2800
+ const oldPen = selfPen;
2801
+ selfPen = store.pens[selfPen.parentId];
2802
+ const showChildIndex = selfPen?.calculative?.showChild;
2803
+ if (showChildIndex != undefined) {
2804
+ const showChildId = selfPen.children[showChildIndex];
2805
+ if (showChildId !== oldPen.id) {
2806
+ // toPng 不展示它
2807
+ return false;
2808
+ }
2809
+ }
2810
+ }
2811
+ return true;
2812
+ }
2813
+ /**
2814
+ * 计算画笔的 inView
2815
+ * @param pen 画笔
2816
+ * @param calcChild 是否计算子画笔
2817
+ */
2818
+ export function calcInView(pen, calcChild = false) {
2819
+ const { store, canvasRect } = pen.calculative.canvas;
2820
+ if (calcChild) {
2821
+ pen.children?.forEach((id) => {
2822
+ const child = store.pens[id];
2823
+ child && calcInView(child, true);
2824
+ });
2825
+ }
2826
+ pen.calculative.inView = true;
2827
+ if (!isShowChild(pen, store) ||
2828
+ pen.visible == false ||
2829
+ pen.calculative.visible == false) {
2830
+ pen.calculative.inView = false;
2831
+ }
2832
+ else {
2833
+ const { x, y, width, height, rotate } = pen.calculative.worldRect;
2834
+ const penRect = {
2835
+ x: x + store.data.x,
2836
+ y: y + store.data.y,
2837
+ width,
2838
+ height,
2839
+ rotate,
2840
+ };
2841
+ calcRightBottom(penRect);
2842
+ if (!rectInRect(penRect, canvasRect)) {
2843
+ pen.calculative.inView = false;
2844
+ }
2845
+ }
2846
+ // TODO: 语义化上,用 onValue 更合适,但 onValue 会触发 echarts 图形的重绘,没有必要
2847
+ // 更改 view 后,修改 dom 节点的显示隐藏
2848
+ // pen.onMove?.(pen);
2849
+ pen.calculative.singleton?.div &&
2850
+ setElemPosition(pen, pen.calculative.singleton.div);
2851
+ }
2852
+ /**
2853
+ * 绘制 rect ,上线后可查看 rect 位置
2854
+ */
2855
+ function inspectRect(ctx, store, pen) {
2856
+ if (store.fillWorldTextRect) {
2857
+ ctx.save();
2858
+ ctx.fillStyle = '#c3deb7';
2859
+ const { x, y, width, height } = pen.calculative.worldTextRect;
2860
+ ctx.fillRect(x, y, width, height);
2861
+ ctx.restore();
2862
+ }
2863
+ }
2864
+ export function setGlobalAlpha(ctx, pen) {
2865
+ const globalAlpha = pen.calculative.globalAlpha;
2866
+ if (typeof globalAlpha === 'number' &&
2867
+ globalAlpha < 1 &&
2868
+ !isNaN(globalAlpha)) {
2869
+ ctx.globalAlpha = globalAlpha;
2870
+ }
2871
+ }
2872
+ /**
2873
+ * ctx 绘制图纸,并非 Path2D
2874
+ * @param ctx 画布上下文
2875
+ * @param pen 画笔
2876
+ */
2877
+ function ctxDrawCanvas(ctx, pen) {
2878
+ const canvasDraw = drawFuncGenerator(ctx, pen) || globalStore.canvasDraws[pen.name];
2879
+ if (canvasDraw) {
2880
+ // TODO: 后续考虑优化 save / restore
2881
+ ctx.save();
2882
+ // TODO: 原有 return 终止后续操作,必要性不大
2883
+ canvasDraw(ctx, pen);
2884
+ ctx.restore();
2885
+ }
2886
+ }
2887
+ function drawFuncGenerator(ctx, pen) {
2888
+ // 进行数据的预处理
2889
+ const drawCommand = pen.drawCommand;
2890
+ if (!drawCommand || pen.name === 'line')
2891
+ return;
2892
+ // 单位转换 将其他单位转换为px
2893
+ // 执行自定义绘画函数
2894
+ return (ctx, pen) => {
2895
+ // TODO 绘制命令的转换 (能否兼容多种指令??)
2896
+ drawCommand.forEach((command) => {
2897
+ try {
2898
+ command.steps = command.steps.flat(Infinity);
2899
+ command.steps.reduce((calculate, step) => {
2900
+ const cs = commandTransfer(step, pen, calculate.x, calculate.y);
2901
+ // 应当保证顺序的正确
2902
+ try {
2903
+ if (cs.c) {
2904
+ if (cs.c.startsWith('_')) {
2905
+ const prop = cs.c.split('_')[1];
2906
+ if (typeof cs.v.value === "number")
2907
+ cs.v.value *= pen.calculative.canvas.store.data.scale;
2908
+ // debugger;
2909
+ (cs.p || ctx)[prop] = cs.v.value;
2910
+ return { x: calculate.x, y: calculate.y };
2911
+ }
2912
+ let l = [];
2913
+ for (const csKey in cs.v) {
2914
+ l.push(cs.v[csKey]);
2915
+ }
2916
+ // ctx.beginPath();
2917
+ (cs.p || ctx)[cs.c](...l);
2918
+ // ctx.moveTo(cs.startX || cs.v.x,cs.startY || cs.v.y);
2919
+ // command.prop.NoFill === '0'?ctx.fill():'';
2920
+ return { x: cs.startX || cs.v.x, y: cs.startY || cs.v.y };
2921
+ }
2922
+ return { x: calculate.x, y: calculate.y };
2923
+ }
2924
+ catch (e) {
2925
+ // pass
2926
+ console.log(e, 'error', cs);
2927
+ }
2928
+ }, {});
2929
+ }
2930
+ catch (e) {
2931
+ }
2932
+ });
2933
+ ctx.stroke();
2934
+ };
2935
+ }
2936
+ function commandTransfer(command, pen, startX, startY) {
2937
+ // TODO 是否支持扩展更多的命令?用于兼容未来的其他解析格式?
2938
+ //1. 进行简单的命令解析
2939
+ // VISIO
2940
+ const map = {
2941
+ 'visio': dealWithVisio,
2942
+ 'dxf': dealWithDXF
2943
+ };
2944
+ // CAD
2945
+ return map[pen.parseType](command, pen, startX, startY);
2946
+ }
2947
+ function dealWithDXF(command, pen, startX, startY) {
2948
+ const { x, y, width, height } = pen.calculative.worldRect;
2949
+ const { originWidth, originHeight } = pen.dxfOrigin;
2950
+ switch (command.c) {
2951
+ case "beginPath":
2952
+ return {
2953
+ c: 'beginPath',
2954
+ v: {}
2955
+ };
2956
+ case "closePath":
2957
+ return {
2958
+ c: 'closePath',
2959
+ v: {}
2960
+ };
2961
+ case "moveTo":
2962
+ return {
2963
+ c: 'moveTo',
2964
+ v: {
2965
+ x: command.v.x * (width / originWidth) + x,
2966
+ y: command.v.y * (height / originHeight) + y
2967
+ }
2968
+ };
2969
+ case "lineTo":
2970
+ return {
2971
+ c: 'lineTo',
2972
+ v: {
2973
+ x: command.v.x * (width / originWidth) + x,
2974
+ y: command.v.y * (height / originHeight) + y
2975
+ }
2976
+ };
2977
+ case "arc":
2978
+ return {
2979
+ c: 'ellipse',
2980
+ v: {
2981
+ x: command.v.x * (width / originWidth) + x,
2982
+ y: (command.v.y * (height / originHeight)) + y,
2983
+ rx: command.v.xr * (width / originWidth),
2984
+ ry: command.v.yr * (height / originHeight),
2985
+ rotation: command.v.rotation || 0,
2986
+ startAngle: command.v.startAngle,
2987
+ endAngle: command.v.endAngle,
2988
+ a: command.v.aclockwise ?? true
2989
+ }
2990
+ };
2991
+ case "ellipse":
2992
+ return {
2993
+ c: 'ellipse',
2994
+ v: {
2995
+ x: command.v.x * (width / originWidth) + x,
2996
+ y: (command.v.y * (height / originHeight)) + y,
2997
+ rx: command.v.xr * (width / originWidth),
2998
+ ry: command.v.yr * (height / originHeight),
2999
+ rotation: command.v.rotation || 0,
3000
+ startAngle: command.v.startAngle,
3001
+ endAngle: command.v.endAngle,
3002
+ a: command.v.aclockwise ?? true
3003
+ }
3004
+ };
3005
+ case "_font":
3006
+ return {
3007
+ c: '_font',
3008
+ v: {
3009
+ value: command.v.fontSize * pen.calculative.canvas.store.data.scale + 'px ' + (command.v.fontFamily || pen.calculative.canvas.store.options.fontFamily)
3010
+ }
3011
+ };
3012
+ case "_fillStyle":
3013
+ return {
3014
+ c: '_fillStyle',
3015
+ v: {
3016
+ value: pen.color || command.v.value
3017
+ }
3018
+ };
3019
+ default:
3020
+ const c = {
3021
+ c: command.c,
3022
+ v: {
3023
+ ...command.v,
3024
+ }
3025
+ };
3026
+ if ((c.v.x) !== undefined)
3027
+ c.v.x = command.v.x * (width / originWidth) + x;
3028
+ if (c.v.y !== undefined)
3029
+ c.v.y = (command.v.y * (height / originHeight)) + y;
3030
+ return c;
3031
+ }
3032
+ }
3033
+ function dealWithVisio(command, pen, startX, startY) {
3034
+ const { x, y, width, height } = pen.calculative.worldRect;
3035
+ const { width: originWidth, height: originHeight } = pen.origin;
3036
+ switch (command.c) {
3037
+ case 'MoveTo':
3038
+ return {
3039
+ c: 'moveTo',
3040
+ v: {
3041
+ x: +command.v.X * 100 * (width / originWidth) + x,
3042
+ y: +command.v.Y * 100 * (height / originHeight) + y,
3043
+ },
3044
+ };
3045
+ case 'RelMoveTo':
3046
+ return {
3047
+ c: 'moveTo',
3048
+ v: {
3049
+ x: +command.v.X * originWidth * (width / originWidth) + x,
3050
+ y: +command.v.Y * originHeight * (height / originHeight) + y,
3051
+ },
3052
+ };
3053
+ case 'LineTo':
3054
+ return {
3055
+ c: 'lineTo',
3056
+ v: {
3057
+ x: +command.v.X * 100 * (width / originWidth) + x,
3058
+ y: +command.v.Y * 100 * (height / originHeight) + y,
3059
+ },
3060
+ };
3061
+ case 'RelLineTo':
3062
+ return {
3063
+ c: 'lineTo',
3064
+ v: {
3065
+ x: +command.v.X * originWidth * (width / originWidth) + x,
3066
+ y: +command.v.Y * originHeight * (height / originHeight) + y,
3067
+ },
3068
+ };
3069
+ case 'Ellipse':
3070
+ let centerX1 = command.v.X;
3071
+ let centerY1 = command.v.Y;
3072
+ let longAxis = Math.abs(command.v.A - command.v.C);
3073
+ let shortAxis = Math.abs(command.v.B - command.v.D);
3074
+ return {
3075
+ c: 'ellipse',
3076
+ v: {
3077
+ x: centerX1 * 100 * (width / originWidth) + x,
3078
+ y: centerY1 * 100 * (height / originHeight) + y,
3079
+ radiuX: longAxis * 100 * (width / originWidth),
3080
+ radiuY: shortAxis * 100 * (height / originHeight),
3081
+ rotation: 0,
3082
+ startAngle: 0,
3083
+ endAngle: Math.PI * 2,
3084
+ anticlockwise: true,
3085
+ },
3086
+ };
3087
+ case 'EllipticalArcTo':
3088
+ const endX = command.v.X * 100 * (width / originWidth) + x; // 弧上结束顶点的 x 坐标
3089
+ const endY = command.v.Y * 100 * (height / originHeight) + y; // 弧上结束顶点的 y 坐标
3090
+ const ctrlX = command.v.A * 100 * (width / originWidth) + x; // 控制点的 x 坐标
3091
+ const ctrlY = command.v.B * 100 * (height / originHeight) + y; // 控制点的 y 坐标
3092
+ const angleDeg = command.v.C; // 主轴相对于 x 轴的角度 (度)
3093
+ const axisRatio = command.v.D * (width / height) * (originHeight / originWidth); // 长轴和短轴的比率
3094
+ //
3095
+ const params = calculateEllipseParameters(startX, startY, endX, endY, ctrlX, ctrlY, axisRatio);
3096
+ // 开始绘制路径
3097
+ !command.orign && (command.orign = {});
3098
+ !command.orign.startA &&
3099
+ (command.orign.startA = calculateAngleInRadians(params.x0, params.y0, startX, startY));
3100
+ !command.orign.endA &&
3101
+ (command.orign.endA = calculateAngleInRadians(params.x0, params.y0, endX, endY));
3102
+ return {
3103
+ c: 'ellipse',
3104
+ v: {
3105
+ centerX: params.x0,
3106
+ centerY: params.y0,
3107
+ radiuX: params.a,
3108
+ radiuY: params.b,
3109
+ // rotation:radiansToDegrees(angleDeg),
3110
+ rotation: 0,
3111
+ startAngle: command.orign.startA,
3112
+ endAngle: command.orign.endA,
3113
+ // startAngle: 0,
3114
+ // endAngle: Math.PI * 2,
3115
+ // anticlockwise: startA > 0 && startA>endA
3116
+ anticlockwise: +angleDeg < 0,
3117
+ // anticlockwise: Math.abs(endA - startA) < Math.PI
3118
+ },
3119
+ startX: endX,
3120
+ startY: endY,
3121
+ };
3122
+ case 'ArcTo':
3123
+ let endX2 = (command.v.X * 100 * width) / originWidth + x;
3124
+ let endY2 = (command.v.Y * 100 * height) / originHeight + y;
3125
+ let h = command.v.A * 100 * (width / height) * (originHeight / originWidth);
3126
+ // 计算弦的中点
3127
+ let xm = (startX + endX2) / 2;
3128
+ let ym = (startY + endY2) / 2;
3129
+ // 计算弦的长度
3130
+ let d = Math.sqrt((endX2 - startX) ** 2 + (endY2 - startY) ** 2);
3131
+ // 计算圆弧的半径
3132
+ let R = d ** 2 / (8 * h) + h / 2;
3133
+ // 计算单位垂直向量
3134
+ let ux = -(endY2 - startY) / d;
3135
+ let uy = (endX2 - startX) / d;
3136
+ // 计算两个可能的圆心
3137
+ let xc1 = xm + ux * R;
3138
+ let yc1 = ym + uy * R;
3139
+ let xc2 = xm - ux * R;
3140
+ let yc2 = ym - uy * R;
3141
+ // 选择一个圆心
3142
+ let xc = xc1;
3143
+ let yc = yc1;
3144
+ // 计算起点和终点到圆心的角度
3145
+ let startAngle = Math.atan2(startY - yc, startX - xc);
3146
+ let endAngle = Math.atan2(endY2 - yc, endX2 - xc);
3147
+ return {
3148
+ c: 'arc',
3149
+ v: {
3150
+ x: xc,
3151
+ y: yc,
3152
+ radius: R,
3153
+ startAngle: startAngle,
3154
+ endAngle: endAngle,
3155
+ aclockwise: true,
3156
+ },
3157
+ };
3158
+ // case "RelCubBezTo":
3159
+ // return {
3160
+ // c:"bezierCurveTo",
3161
+ // v:{
3162
+ //
3163
+ // }
3164
+ // };
3165
+ default:
3166
+ // console.log(command.c);
3167
+ return {};
3168
+ }
3169
+ }
3170
+ export function setChildValue(pen, data) {
3171
+ for (const k in data) {
3172
+ if (inheritanceProps.includes(k)) {
3173
+ if (k == 'fontSize' && data[k] < 0) {
3174
+ data[k] = 0;
3175
+ }
3176
+ pen[k] = data[k];
3177
+ if (['fontSize', 'lineWidth'].includes(k)) {
3178
+ pen.calculative[k] = data[k] * pen.calculative.canvas.store.data.scale;
3179
+ calcTextRect(pen);
3180
+ }
3181
+ else {
3182
+ pen.calculative[k] = data[k];
3183
+ }
3184
+ }
3185
+ }
3186
+ if (pen.calculative.canvas.parent.isCombine(pen)
3187
+ //&& pen.showChild === undefined
3188
+ ) {
3189
+ const children = pen.children;
3190
+ children?.forEach((childId) => {
3191
+ let _data = deepClone(data);
3192
+ if (pen.calculative.childrenVisible) {
3193
+ if (pen.calculative.childrenVisible[childId] === false) {
3194
+ delete _data.visible;
3195
+ }
3196
+ }
3197
+ const child = pen.calculative.canvas.store.pens[childId];
3198
+ child && setChildValue(child, _data);
3199
+ });
3200
+ }
3201
+ }
3202
+ function calculateEllipseParameters(x1, y1, x2, y2, x3, y3, D) {
3203
+ // Calculate x₀ using equation ⑥
3204
+ let numeratorX0 = (x1 - x2) * (x1 + x2) * (y2 - y3) -
3205
+ (x2 - x3) * (x2 + x3) * (y1 - y2) +
3206
+ D * D * (y1 - y2) * (y2 - y3) * (y1 - y3);
3207
+ let denominatorX0 = 2 * ((x1 - x2) * (y2 - y3) - (x2 - x3) * (y1 - y2));
3208
+ let x0 = numeratorX0 / denominatorX0;
3209
+ // Calculate y₀ using equation ⑦
3210
+ let numeratorY0 = (x1 - x2) * (x2 - x3) * (x1 - x3) +
3211
+ D *
3212
+ D *
3213
+ ((x2 - x3) * (y1 - y2) * (y1 + y2) - (x1 - x2) * (y2 - y3) * (y2 + y3));
3214
+ let denominatorY0 = 2 * D * D * ((x2 - x3) * (y1 - y2) - (x1 - x2) * (y2 - y3));
3215
+ let y0 = numeratorY0 / denominatorY0;
3216
+ // Calculate 'a' using equation ⑧, substituting x₀ and y₀
3217
+ let a = Math.sqrt(Math.pow(x1 - x0, 2) + Math.pow(D * (y1 - y0), 2));
3218
+ // Calculate 'b' using equation ⑨
3219
+ let b = a / D;
3220
+ return { x0, y0, a, b };
3221
+ }
3222
+ function calculateAngleInRadians(x1, y1, x2, y2) {
3223
+ // 计算两个点的差值
3224
+ let dx = x2 - x1;
3225
+ let dy = y2 - y1;
3226
+ // 使用 atan2 计算角度,结果为弧度
3227
+ let angleRadians = Math.atan2(dy, dx);
3228
+ // 如果角度为负值,加上2π
3229
+ if (angleRadians < 0) {
3230
+ angleRadians += 2 * Math.PI;
3231
+ }
3232
+ return angleRadians;
3233
+ }
3234
+ //# sourceMappingURL=render.js.map