@idraw/util 0.4.2 → 1.0.0-alpha.1
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.
- package/dist/esm/converter/data-svg.d.ts +2 -0
- package/dist/esm/converter/data-svg.js +19 -0
- package/dist/esm/converter/material-svg.d.ts +2 -0
- package/dist/esm/converter/material-svg.js +63 -0
- package/dist/esm/converter/svg-material.d.ts +2 -0
- package/dist/esm/converter/svg-material.js +188 -0
- package/dist/esm/index.d.ts +32 -21
- package/dist/esm/index.js +32 -21
- package/dist/esm/static.d.ts +1 -0
- package/dist/esm/static.js +1 -0
- package/dist/esm/tool/file.js +2 -2
- package/dist/esm/tool/html.js +27 -27
- package/dist/esm/tool/id.d.ts +1 -0
- package/dist/esm/tool/id.js +4 -0
- package/dist/esm/tool/image.js +6 -6
- package/dist/esm/tool/path-to-box.d.ts +3 -0
- package/dist/esm/tool/path-to-box.js +353 -0
- package/dist/esm/tool/path-to-command.d.ts +4 -0
- package/dist/esm/tool/path-to-command.js +392 -0
- package/dist/esm/tool/path.d.ts +18 -0
- package/dist/esm/tool/path.js +421 -0
- package/dist/esm/tool/svg-path.d.ts +3 -0
- package/dist/esm/{view → tool}/svg-path.js +4 -16
- package/dist/esm/tool/time.d.ts +2 -2
- package/dist/esm/tool/time.js +4 -4
- package/dist/esm/tool/uuid.d.ts +1 -1
- package/dist/esm/tool/uuid.js +6 -6
- package/dist/esm/view/box.d.ts +0 -2
- package/dist/esm/view/box.js +1 -173
- package/dist/esm/view/canvas.js +3 -3
- package/dist/esm/view/check.d.ts +8 -7
- package/dist/esm/view/check.js +34 -34
- package/dist/esm/view/config.d.ts +0 -9
- package/dist/esm/view/config.js +1 -71
- package/dist/esm/view/context2d.d.ts +10 -3
- package/dist/esm/view/context2d.js +39 -18
- package/dist/esm/view/controller.d.ts +5 -5
- package/dist/esm/view/controller.js +105 -102
- package/dist/esm/view/data.d.ts +2 -2
- package/dist/esm/view/data.js +65 -65
- package/dist/esm/view/dom.d.ts +23 -0
- package/dist/esm/view/dom.js +190 -0
- package/dist/esm/view/flat.d.ts +2 -2
- package/dist/esm/view/flat.js +53 -53
- package/dist/esm/view/group.d.ts +3 -3
- package/dist/esm/view/group.js +25 -28
- package/dist/esm/view/handle-material.d.ts +24 -0
- package/dist/esm/view/{handle-element.js → handle-material.js} +98 -75
- package/dist/esm/view/is.d.ts +10 -12
- package/dist/esm/view/is.js +15 -19
- package/dist/esm/view/load.d.ts +2 -2
- package/dist/esm/view/load.js +7 -7
- package/dist/esm/view/material.d.ts +40 -0
- package/dist/esm/view/material.js +476 -0
- package/dist/esm/view/middleware.d.ts +1 -0
- package/dist/esm/view/middleware.js +14 -2
- package/dist/esm/view/modify-record.d.ts +4 -4
- package/dist/esm/view/modify-record.js +2 -2
- package/dist/esm/view/parser.d.ts +2 -2
- package/dist/esm/view/parser.js +3 -3
- package/dist/esm/view/path.d.ts +2 -0
- package/dist/esm/view/path.js +30 -0
- package/dist/esm/view/point-move-material.d.ts +5 -0
- package/dist/esm/view/{point-move-element.js → point-move-material.js} +6 -6
- package/dist/esm/view/point.d.ts +3 -8
- package/dist/esm/view/point.js +1 -21
- package/dist/esm/view/position.d.ts +9 -9
- package/dist/esm/view/position.js +1 -1
- package/dist/esm/view/rect.d.ts +2 -2
- package/dist/esm/view/rect.js +4 -4
- package/dist/esm/view/resize-material.d.ts +4 -0
- package/dist/esm/view/resize-material.js +266 -0
- package/dist/esm/view/rotate.d.ts +11 -11
- package/dist/esm/view/rotate.js +24 -24
- package/dist/esm/view/static.d.ts +13 -0
- package/dist/esm/view/static.js +89 -0
- package/dist/esm/view/styles.d.ts +11 -0
- package/dist/esm/view/styles.js +78 -0
- package/dist/esm/view/vertex.d.ts +8 -8
- package/dist/esm/view/vertex.js +28 -28
- package/dist/esm/view/view-box.d.ts +2 -6
- package/dist/esm/view/view-box.js +8 -64
- package/dist/esm/view/view-calc.d.ts +23 -20
- package/dist/esm/view/view-calc.js +104 -93
- package/dist/esm/view/view-content.d.ts +2 -2
- package/dist/esm/view/view-content.js +34 -34
- package/dist/index.global.js +3144 -1548
- package/dist/index.global.min.js +1 -1
- package/package.json +1 -1
- package/dist/esm/view/element.d.ts +0 -35
- package/dist/esm/view/element.js +0 -471
- package/dist/esm/view/handle-element.d.ts +0 -24
- package/dist/esm/view/point-move-element.d.ts +0 -5
- package/dist/esm/view/resize-element.d.ts +0 -4
- package/dist/esm/view/resize-element.js +0 -255
- package/dist/esm/view/svg-path.d.ts +0 -10
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
import { parseSVGPath, createId } from '@idraw/util';
|
|
2
|
+
const isRelative = (type) => type === type.toLowerCase();
|
|
3
|
+
function getPoint(cmd, xIndex, yIndex, currentPoint) {
|
|
4
|
+
const { type, params = [] } = cmd;
|
|
5
|
+
return {
|
|
6
|
+
x: isRelative(type) ? currentPoint.x + params[xIndex] : params[xIndex],
|
|
7
|
+
y: isRelative(type) ? currentPoint.y + params[yIndex] : params[yIndex],
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
function lineToCubic(start, end) {
|
|
11
|
+
return {
|
|
12
|
+
c1: {
|
|
13
|
+
x: start.x + (end.x - start.x) / 3,
|
|
14
|
+
y: start.y + (end.y - start.y) / 3,
|
|
15
|
+
},
|
|
16
|
+
c2: {
|
|
17
|
+
x: start.x + (2 * (end.x - start.x)) / 3,
|
|
18
|
+
y: start.y + (2 * (end.y - start.y)) / 3,
|
|
19
|
+
},
|
|
20
|
+
end: Object.assign({}, end),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function quadToCubic(p0, cp, p2) {
|
|
24
|
+
return {
|
|
25
|
+
c1: {
|
|
26
|
+
x: p0.x + (2 / 3) * (cp.x - p0.x),
|
|
27
|
+
y: p0.y + (2 / 3) * (cp.y - p0.y),
|
|
28
|
+
},
|
|
29
|
+
c2: {
|
|
30
|
+
x: p2.x + (2 / 3) * (cp.x - p2.x),
|
|
31
|
+
y: p2.y + (2 / 3) * (cp.y - p2.y),
|
|
32
|
+
},
|
|
33
|
+
end: Object.assign({}, p2),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function convertSvgArcToCanvasEllipse(start, end, rx, ry, xAxisRotation, largeArcFlag, sweepFlag) {
|
|
37
|
+
rx = Math.abs(rx);
|
|
38
|
+
ry = Math.abs(ry);
|
|
39
|
+
if (Math.abs(start.x - end.x) < 1e-6 && Math.abs(start.y - end.y) < 1e-6) {
|
|
40
|
+
return {
|
|
41
|
+
centerX: start.x,
|
|
42
|
+
centerY: start.y,
|
|
43
|
+
radiusX: rx,
|
|
44
|
+
radiusY: ry,
|
|
45
|
+
rotation: (xAxisRotation * Math.PI) / 180,
|
|
46
|
+
startRadian: 0,
|
|
47
|
+
endRadian: 0,
|
|
48
|
+
anticlockwise: sweepFlag === 0,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
if (rx < 1e-6 || ry < 1e-6) {
|
|
52
|
+
return {
|
|
53
|
+
centerX: (start.x + end.x) / 2,
|
|
54
|
+
centerY: (start.y + end.y) / 2,
|
|
55
|
+
radiusX: 0,
|
|
56
|
+
radiusY: 0,
|
|
57
|
+
rotation: 0,
|
|
58
|
+
startRadian: 0,
|
|
59
|
+
endRadian: 0,
|
|
60
|
+
anticlockwise: false,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
const phi = (xAxisRotation * Math.PI) / 180;
|
|
64
|
+
const cosPhi = Math.cos(phi);
|
|
65
|
+
const sinPhi = Math.sin(phi);
|
|
66
|
+
const mid = {
|
|
67
|
+
x: (start.x - end.x) / 2,
|
|
68
|
+
y: (start.y - end.y) / 2,
|
|
69
|
+
};
|
|
70
|
+
const x1p = cosPhi * mid.x + sinPhi * mid.y;
|
|
71
|
+
const y1p = -sinPhi * mid.x + cosPhi * mid.y;
|
|
72
|
+
const lambda = (x1p * x1p) / (rx * rx) + (y1p * y1p) / (ry * ry);
|
|
73
|
+
if (lambda > 1) {
|
|
74
|
+
const sqrtLambda = Math.sqrt(lambda);
|
|
75
|
+
rx *= sqrtLambda;
|
|
76
|
+
ry *= sqrtLambda;
|
|
77
|
+
}
|
|
78
|
+
const sign = largeArcFlag === sweepFlag ? -1 : 1;
|
|
79
|
+
let factor = Math.sqrt(Math.abs((rx * rx * ry * ry - rx * rx * y1p * y1p - ry * ry * x1p * x1p) / (rx * rx * y1p * y1p + ry * ry * x1p * x1p)));
|
|
80
|
+
if (isNaN(factor))
|
|
81
|
+
factor = 0;
|
|
82
|
+
const cxp = (sign * factor * (rx * y1p)) / ry;
|
|
83
|
+
const cyp = (sign * factor * (-ry * x1p)) / rx;
|
|
84
|
+
const cx = cosPhi * cxp - sinPhi * cyp + (start.x + end.x) / 2;
|
|
85
|
+
const cy = sinPhi * cxp + cosPhi * cyp + (start.y + end.y) / 2;
|
|
86
|
+
const ux = (x1p - cxp) / rx;
|
|
87
|
+
const uy = (y1p - cyp) / ry;
|
|
88
|
+
const vx = (-x1p - cxp) / rx;
|
|
89
|
+
const vy = (-y1p - cyp) / ry;
|
|
90
|
+
const theta = Math.atan2(uy, ux);
|
|
91
|
+
let delta = Math.atan2(vy, vx) - theta;
|
|
92
|
+
if (sweepFlag === 0 && delta > 0) {
|
|
93
|
+
delta -= 2 * Math.PI;
|
|
94
|
+
}
|
|
95
|
+
else if (sweepFlag === 1 && delta < 0) {
|
|
96
|
+
delta += 2 * Math.PI;
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
centerX: cx,
|
|
100
|
+
centerY: cy,
|
|
101
|
+
radiusX: rx,
|
|
102
|
+
radiusY: ry,
|
|
103
|
+
rotation: phi,
|
|
104
|
+
startRadian: theta,
|
|
105
|
+
endRadian: theta + delta,
|
|
106
|
+
anticlockwise: sweepFlag === 0,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
export function convertSVGPathToContext2DCommands(d) {
|
|
110
|
+
const svgPathCmds = parseSVGPath(d);
|
|
111
|
+
const ctx2dCmds = convertPathCommandsToContext2DCommands(svgPathCmds);
|
|
112
|
+
return ctx2dCmds;
|
|
113
|
+
}
|
|
114
|
+
export function convertPathCommandsToContext2DCommands(svgPathCmds) {
|
|
115
|
+
let currentPoint = { x: 0, y: 0 };
|
|
116
|
+
let startPoint = { x: 0, y: 0 };
|
|
117
|
+
let prevControlPoint = null;
|
|
118
|
+
const ctx2dCmds = [];
|
|
119
|
+
const handleMove = (cmd) => {
|
|
120
|
+
const end = getPoint(cmd, 0, 1, currentPoint);
|
|
121
|
+
currentPoint = Object.assign({}, end);
|
|
122
|
+
startPoint = Object.assign({}, end);
|
|
123
|
+
ctx2dCmds.push({
|
|
124
|
+
id: createId(),
|
|
125
|
+
name: 'moveTo',
|
|
126
|
+
params: { x: end.x, y: end.y },
|
|
127
|
+
});
|
|
128
|
+
prevControlPoint = null;
|
|
129
|
+
};
|
|
130
|
+
const handleLine = (cmd) => {
|
|
131
|
+
const end = getPoint(cmd, 0, 1, currentPoint);
|
|
132
|
+
const curve = lineToCubic(currentPoint, end);
|
|
133
|
+
ctx2dCmds.push({
|
|
134
|
+
id: createId(),
|
|
135
|
+
name: 'bezierCurveTo',
|
|
136
|
+
params: {
|
|
137
|
+
cp1x: curve.c1.x,
|
|
138
|
+
cp1y: curve.c1.y,
|
|
139
|
+
cp2x: curve.c2.x,
|
|
140
|
+
cp2y: curve.c2.y,
|
|
141
|
+
x: curve.end.x,
|
|
142
|
+
y: curve.end.y,
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
currentPoint = Object.assign({}, end);
|
|
146
|
+
prevControlPoint = curve.c2;
|
|
147
|
+
};
|
|
148
|
+
const handleHorizontal = (cmd) => {
|
|
149
|
+
const x = isRelative(cmd.type) ? currentPoint.x + cmd.params[0] : cmd.params[0];
|
|
150
|
+
const end = { x, y: currentPoint.y };
|
|
151
|
+
const curve = lineToCubic(currentPoint, end);
|
|
152
|
+
ctx2dCmds.push({
|
|
153
|
+
id: createId(),
|
|
154
|
+
name: 'bezierCurveTo',
|
|
155
|
+
params: {
|
|
156
|
+
cp1x: curve.c1.x,
|
|
157
|
+
cp1y: curve.c1.y,
|
|
158
|
+
cp2x: curve.c2.x,
|
|
159
|
+
cp2y: curve.c2.y,
|
|
160
|
+
x: curve.end.x,
|
|
161
|
+
y: curve.end.y,
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
currentPoint = Object.assign({}, end);
|
|
165
|
+
prevControlPoint = curve.c2;
|
|
166
|
+
};
|
|
167
|
+
const handleVertical = (cmd) => {
|
|
168
|
+
const y = isRelative(cmd.type) ? currentPoint.y + cmd.params[0] : cmd.params[0];
|
|
169
|
+
const end = { x: currentPoint.x, y };
|
|
170
|
+
const curve = lineToCubic(currentPoint, end);
|
|
171
|
+
ctx2dCmds.push({
|
|
172
|
+
id: createId(),
|
|
173
|
+
name: 'bezierCurveTo',
|
|
174
|
+
params: {
|
|
175
|
+
cp1x: curve.c1.x,
|
|
176
|
+
cp1y: curve.c1.y,
|
|
177
|
+
cp2x: curve.c2.x,
|
|
178
|
+
cp2y: curve.c2.y,
|
|
179
|
+
x: curve.end.x,
|
|
180
|
+
y: curve.end.y,
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
currentPoint = Object.assign({}, end);
|
|
184
|
+
prevControlPoint = curve.c2;
|
|
185
|
+
};
|
|
186
|
+
const handleCubic = (cmd) => {
|
|
187
|
+
const c1 = getPoint(cmd, 0, 1, currentPoint);
|
|
188
|
+
const c2 = getPoint(cmd, 2, 3, currentPoint);
|
|
189
|
+
const end = getPoint(cmd, 4, 5, currentPoint);
|
|
190
|
+
ctx2dCmds.push({
|
|
191
|
+
id: createId(),
|
|
192
|
+
name: 'bezierCurveTo',
|
|
193
|
+
params: { cp1x: c1.x, cp1y: c1.y, cp2x: c2.x, cp2y: c2.y, x: end.x, y: end.y },
|
|
194
|
+
});
|
|
195
|
+
currentPoint = Object.assign({}, end);
|
|
196
|
+
prevControlPoint = c2;
|
|
197
|
+
};
|
|
198
|
+
const handleShortCubic = (cmd) => {
|
|
199
|
+
const prevC2 = prevControlPoint || currentPoint;
|
|
200
|
+
const c1 = {
|
|
201
|
+
x: 2 * currentPoint.x - prevC2.x,
|
|
202
|
+
y: 2 * currentPoint.y - prevC2.y,
|
|
203
|
+
};
|
|
204
|
+
const c2 = getPoint(cmd, 0, 1, currentPoint);
|
|
205
|
+
const end = getPoint(cmd, 2, 3, currentPoint);
|
|
206
|
+
ctx2dCmds.push({
|
|
207
|
+
id: createId(),
|
|
208
|
+
name: 'bezierCurveTo',
|
|
209
|
+
params: { cp1x: c1.x, cp1y: c1.y, cp2x: c2.x, cp2y: c2.y, x: end.x, y: end.y },
|
|
210
|
+
});
|
|
211
|
+
currentPoint = Object.assign({}, end);
|
|
212
|
+
prevControlPoint = c2;
|
|
213
|
+
};
|
|
214
|
+
const handleQuadratic = (cmd) => {
|
|
215
|
+
const cp = getPoint(cmd, 0, 1, currentPoint);
|
|
216
|
+
const end = getPoint(cmd, 2, 3, currentPoint);
|
|
217
|
+
const curve = quadToCubic(currentPoint, cp, end);
|
|
218
|
+
ctx2dCmds.push({
|
|
219
|
+
id: createId(),
|
|
220
|
+
name: 'bezierCurveTo',
|
|
221
|
+
params: {
|
|
222
|
+
cp1x: curve.c1.x,
|
|
223
|
+
cp1y: curve.c1.y,
|
|
224
|
+
cp2x: curve.c2.x,
|
|
225
|
+
cp2y: curve.c2.y,
|
|
226
|
+
x: curve.end.x,
|
|
227
|
+
y: curve.end.y,
|
|
228
|
+
},
|
|
229
|
+
});
|
|
230
|
+
currentPoint = Object.assign({}, end);
|
|
231
|
+
prevControlPoint = curve.c2;
|
|
232
|
+
};
|
|
233
|
+
const handleShortQuadratic = (cmd) => {
|
|
234
|
+
const prevCP = prevControlPoint
|
|
235
|
+
? {
|
|
236
|
+
x: 2 * currentPoint.x - prevControlPoint.x,
|
|
237
|
+
y: 2 * currentPoint.y - prevControlPoint.y,
|
|
238
|
+
}
|
|
239
|
+
: currentPoint;
|
|
240
|
+
const end = getPoint(cmd, 0, 1, currentPoint);
|
|
241
|
+
const curve = quadToCubic(currentPoint, prevCP, end);
|
|
242
|
+
ctx2dCmds.push({
|
|
243
|
+
id: createId(),
|
|
244
|
+
name: 'bezierCurveTo',
|
|
245
|
+
params: {
|
|
246
|
+
cp1x: curve.c1.x,
|
|
247
|
+
cp1y: curve.c1.y,
|
|
248
|
+
cp2x: curve.c2.x,
|
|
249
|
+
cp2y: curve.c2.y,
|
|
250
|
+
x: curve.end.x,
|
|
251
|
+
y: curve.end.y,
|
|
252
|
+
},
|
|
253
|
+
});
|
|
254
|
+
currentPoint = Object.assign({}, end);
|
|
255
|
+
prevControlPoint = curve.c2;
|
|
256
|
+
};
|
|
257
|
+
const handleArc = (cmd) => {
|
|
258
|
+
const [rx, ry, rotationDeg, largeFlag, sweepFlag, x, y] = cmd.params;
|
|
259
|
+
const end = {
|
|
260
|
+
x: isRelative(cmd.type) ? currentPoint.x + x : x,
|
|
261
|
+
y: isRelative(cmd.type) ? currentPoint.y + y : y,
|
|
262
|
+
};
|
|
263
|
+
const ellipseParams = convertSvgArcToCanvasEllipse(currentPoint, end, rx, ry, (rotationDeg * Math.PI) / 180, largeFlag, sweepFlag);
|
|
264
|
+
ctx2dCmds.push({
|
|
265
|
+
id: createId(),
|
|
266
|
+
name: 'ellipse',
|
|
267
|
+
params: ellipseParams,
|
|
268
|
+
});
|
|
269
|
+
currentPoint = Object.assign({}, end);
|
|
270
|
+
};
|
|
271
|
+
const handleClose = (cmd) => {
|
|
272
|
+
if (currentPoint.x !== startPoint.x || currentPoint.y !== startPoint.y) {
|
|
273
|
+
const curve = lineToCubic(currentPoint, startPoint);
|
|
274
|
+
ctx2dCmds.push({
|
|
275
|
+
id: createId(),
|
|
276
|
+
name: 'bezierCurveTo',
|
|
277
|
+
params: {
|
|
278
|
+
cp1x: curve.c1.x,
|
|
279
|
+
cp1y: curve.c1.y,
|
|
280
|
+
cp2x: curve.c2.x,
|
|
281
|
+
cp2y: curve.c2.y,
|
|
282
|
+
x: curve.end.x,
|
|
283
|
+
y: curve.end.y,
|
|
284
|
+
},
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
ctx2dCmds.push({
|
|
288
|
+
id: createId(),
|
|
289
|
+
name: 'closePath',
|
|
290
|
+
params: null,
|
|
291
|
+
});
|
|
292
|
+
currentPoint = Object.assign({}, startPoint);
|
|
293
|
+
prevControlPoint = null;
|
|
294
|
+
};
|
|
295
|
+
ctx2dCmds.push({
|
|
296
|
+
id: createId(),
|
|
297
|
+
name: 'beginPath',
|
|
298
|
+
params: null,
|
|
299
|
+
});
|
|
300
|
+
for (const command of svgPathCmds) {
|
|
301
|
+
const { id, type, params = [] } = command;
|
|
302
|
+
const cmd = { id, type, params };
|
|
303
|
+
switch (cmd.type.toUpperCase()) {
|
|
304
|
+
case 'M':
|
|
305
|
+
handleMove(cmd);
|
|
306
|
+
break;
|
|
307
|
+
case 'L':
|
|
308
|
+
handleLine(cmd);
|
|
309
|
+
break;
|
|
310
|
+
case 'H':
|
|
311
|
+
handleHorizontal(cmd);
|
|
312
|
+
break;
|
|
313
|
+
case 'V':
|
|
314
|
+
handleVertical(cmd);
|
|
315
|
+
break;
|
|
316
|
+
case 'C':
|
|
317
|
+
handleCubic(cmd);
|
|
318
|
+
break;
|
|
319
|
+
case 'S':
|
|
320
|
+
handleShortCubic(cmd);
|
|
321
|
+
break;
|
|
322
|
+
case 'Q':
|
|
323
|
+
handleQuadratic(cmd);
|
|
324
|
+
break;
|
|
325
|
+
case 'T':
|
|
326
|
+
handleShortQuadratic(cmd);
|
|
327
|
+
break;
|
|
328
|
+
case 'A':
|
|
329
|
+
handleArc(cmd);
|
|
330
|
+
break;
|
|
331
|
+
case 'Z':
|
|
332
|
+
handleClose(cmd);
|
|
333
|
+
break;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
return ctx2dCmds;
|
|
337
|
+
}
|
|
338
|
+
function convertCanvasEllipseToSvgArc(ellipseParams) {
|
|
339
|
+
const { centerX, centerY, radiusX, radiusY, rotation, startRadian, endRadian, anticlockwise } = ellipseParams;
|
|
340
|
+
const endPoint = calculatePointOnEllipse(centerX, centerY, radiusX, radiusY, rotation, endRadian);
|
|
341
|
+
let sweepAngle = endRadian - startRadian;
|
|
342
|
+
if (anticlockwise) {
|
|
343
|
+
if (sweepAngle > 0) {
|
|
344
|
+
sweepAngle -= 2 * Math.PI;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
if (sweepAngle < 0) {
|
|
349
|
+
sweepAngle += 2 * Math.PI;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
const largeArcFlag = Math.abs(sweepAngle) > Math.PI ? 1 : 0;
|
|
353
|
+
const sweepFlag = anticlockwise ? 0 : 1;
|
|
354
|
+
return {
|
|
355
|
+
rx: radiusX,
|
|
356
|
+
ry: radiusY,
|
|
357
|
+
xAxisRotation: (rotation * 180) / Math.PI,
|
|
358
|
+
largeArcFlag,
|
|
359
|
+
sweepFlag,
|
|
360
|
+
endPoint,
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
function calculatePointOnEllipse(centerX, centerY, radiusX, radiusY, rotation, radian) {
|
|
364
|
+
const cosPhi = Math.cos(rotation);
|
|
365
|
+
const sinPhi = Math.sin(rotation);
|
|
366
|
+
const x = centerX + radiusX * Math.cos(radian) * cosPhi - radiusY * Math.sin(radian) * sinPhi;
|
|
367
|
+
const y = centerY + radiusX * Math.cos(radian) * sinPhi + radiusY * Math.sin(radian) * cosPhi;
|
|
368
|
+
return { x, y };
|
|
369
|
+
}
|
|
370
|
+
export function convertContext2DCommandsToSVGPath(cmds) {
|
|
371
|
+
const paths = [];
|
|
372
|
+
cmds.forEach((cmd) => {
|
|
373
|
+
if (cmd.name === 'moveTo') {
|
|
374
|
+
paths.push(`M ${cmd.params.x}, ${cmd.params.y}`);
|
|
375
|
+
}
|
|
376
|
+
else if (cmd.name === 'bezierCurveTo') {
|
|
377
|
+
paths.push(`C ${cmd.params.cp1x},${cmd.params.cp1y} ${cmd.params.cp2x},${cmd.params.cp2y} ${cmd.params.x},${cmd.params.y}`);
|
|
378
|
+
}
|
|
379
|
+
else if (cmd.name === 'ellipse') {
|
|
380
|
+
const arcParams = convertCanvasEllipseToSvgArc(cmd.params);
|
|
381
|
+
const { rx, ry, xAxisRotation, largeArcFlag, sweepFlag, endPoint } = arcParams;
|
|
382
|
+
paths.push(`A ${rx} ${ry} ${xAxisRotation} ${largeArcFlag} ${sweepFlag} ${endPoint.x} ${endPoint.y}`);
|
|
383
|
+
}
|
|
384
|
+
else if (cmd.name === 'beginPath') {
|
|
385
|
+
paths.push('');
|
|
386
|
+
}
|
|
387
|
+
else if (cmd.name === 'closePath') {
|
|
388
|
+
paths.push('Z');
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
return paths.join(' ');
|
|
392
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { PathCommand, PathAnchorCommand, Point } from '@idraw/types';
|
|
2
|
+
export declare function shiftPathCommand<T extends PathCommand | PathAnchorCommand = PathCommand>(command: T, x: number, y: number): T;
|
|
3
|
+
export declare function shiftPathCommands<T extends PathCommand | PathAnchorCommand = PathCommand>(commands: T[], x: number, y: number): T[];
|
|
4
|
+
export declare function scalePathCommands<T extends PathCommand | PathAnchorCommand = PathCommand>(path: T[], scaleX: number, scaleY: number): T[];
|
|
5
|
+
export declare function convertPathCommandsToACLMZ(commands: PathCommand[]): PathAnchorCommand[];
|
|
6
|
+
export declare function moveInAnchorCommands(acmds: PathAnchorCommand[], opts: {
|
|
7
|
+
index: number;
|
|
8
|
+
type: 'start' | 'end';
|
|
9
|
+
moveX: number;
|
|
10
|
+
moveY: number;
|
|
11
|
+
}): PathAnchorCommand[];
|
|
12
|
+
export declare function moveCurveCtrlInAnchorCommands(acmds: PathAnchorCommand[], opts: {
|
|
13
|
+
index: number;
|
|
14
|
+
type: 'curve-ctrl1' | 'curve-ctrl2';
|
|
15
|
+
moveX: number;
|
|
16
|
+
moveY: number;
|
|
17
|
+
}): PathAnchorCommand[];
|
|
18
|
+
export declare function convertLineToExactCurveCommand(startPoint: Point, endPoint: Point): PathCommand;
|