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