@mce/bigesj 0.18.4 → 0.19.0
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/convert/image.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { definePlugin, useEditor } from "mce";
|
|
2
2
|
import { onBeforeMount, onScopeDispose, ref } from "vue";
|
|
3
|
-
import { clearUndef, idGenerator, isGradient, isGradientFill, normalizeCRLF, normalizeGradientFill } from "modern-idoc";
|
|
3
|
+
import { clearUndef, idGenerator, isGradient, isGradientFill, normalizeCRLF, normalizeGradientFill, normalizeNumber } from "modern-idoc";
|
|
4
4
|
import { OoxmlNode, parsePresetShapeDefinition } from "modern-openxml";
|
|
5
5
|
import { assets } from "modern-canvas";
|
|
6
6
|
import { gunzipSync } from "fflate";
|
|
@@ -16,6 +16,17 @@ function levenshteinDistance(a, b) {
|
|
|
16
16
|
}
|
|
17
17
|
return matrix[b.length][a.length];
|
|
18
18
|
}
|
|
19
|
+
var indexedFonts;
|
|
20
|
+
var idIndexMap = /* @__PURE__ */ new Map();
|
|
21
|
+
var nameIndexMap = /* @__PURE__ */ new Map();
|
|
22
|
+
var searchCache = /* @__PURE__ */ new Map();
|
|
23
|
+
function ensureFontIndex(fonts) {
|
|
24
|
+
if (indexedFonts === fonts) return;
|
|
25
|
+
indexedFonts = fonts;
|
|
26
|
+
idIndexMap = new Map(fonts.map((item, index) => [item.id, index]));
|
|
27
|
+
nameIndexMap = new Map(fonts.flatMap((item, index) => [...item.en_name.split(","), ...item.name.split(",")].map((name) => [name, index])));
|
|
28
|
+
searchCache.clear();
|
|
29
|
+
}
|
|
19
30
|
function useFonts(editor) {
|
|
20
31
|
const { http, loadFont: baseLoadFont } = editor ?? useEditor();
|
|
21
32
|
async function loadBigeFonts(url, init = false) {
|
|
@@ -30,12 +41,8 @@ function useFonts(editor) {
|
|
|
30
41
|
return result;
|
|
31
42
|
}
|
|
32
43
|
function searchBigeFont(keyword, fonts = bigeFonts.value) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
return [...item.en_name.split(","), ...item.name.split(",")].map((name) => {
|
|
36
|
-
return [name, index];
|
|
37
|
-
});
|
|
38
|
-
}));
|
|
44
|
+
ensureFontIndex(fonts);
|
|
45
|
+
if (searchCache.has(keyword)) return searchCache.get(keyword);
|
|
39
46
|
const fontFamilies = keyword.replace(/"/g, "").split(",");
|
|
40
47
|
let index;
|
|
41
48
|
fontFamilies.forEach((fontFamily) => {
|
|
@@ -50,6 +57,7 @@ function useFonts(editor) {
|
|
|
50
57
|
else if (a.endsWith(" B")) a = `${a.substring(0, a.length - 2)}粗体`;
|
|
51
58
|
const aLen = a.length;
|
|
52
59
|
nameIndexMap.forEach((i, b) => {
|
|
60
|
+
if (Math.abs(aLen - b.length) >= aLen) return;
|
|
53
61
|
const dist = levenshteinDistance(a, b);
|
|
54
62
|
if (aLen <= dist) return;
|
|
55
63
|
const weight = -(dist * .9 + (b.endsWith("常规") ? 0 : 1) * .1);
|
|
@@ -60,7 +68,9 @@ function useFonts(editor) {
|
|
|
60
68
|
});
|
|
61
69
|
});
|
|
62
70
|
}
|
|
63
|
-
|
|
71
|
+
const result = index !== void 0 ? fonts[index] : void 0;
|
|
72
|
+
searchCache.set(keyword, result);
|
|
73
|
+
return result;
|
|
64
74
|
}
|
|
65
75
|
async function loadFont(name) {
|
|
66
76
|
const names = typeof name === "string" ? [name] : name;
|
|
@@ -1138,6 +1148,23 @@ function parseAnimations(el) {
|
|
|
1138
1148
|
}
|
|
1139
1149
|
//#endregion
|
|
1140
1150
|
//#region src/convert/style.ts
|
|
1151
|
+
var NUMERIC_STYLE_KEYS = [
|
|
1152
|
+
"textIndent",
|
|
1153
|
+
"lineHeight",
|
|
1154
|
+
"letterSpacing",
|
|
1155
|
+
"wordSpacing",
|
|
1156
|
+
"fontSize",
|
|
1157
|
+
"textStrokeWidth",
|
|
1158
|
+
"borderRadius",
|
|
1159
|
+
"opacity",
|
|
1160
|
+
"rotate",
|
|
1161
|
+
"scaleX",
|
|
1162
|
+
"scaleY",
|
|
1163
|
+
"skewX",
|
|
1164
|
+
"skewY",
|
|
1165
|
+
"translateX",
|
|
1166
|
+
"translateY"
|
|
1167
|
+
];
|
|
1141
1168
|
function getStyle(el, clone = false) {
|
|
1142
1169
|
let style = el.style ?? el;
|
|
1143
1170
|
if (clone) {
|
|
@@ -1154,6 +1181,11 @@ function getStyle(el, clone = false) {
|
|
|
1154
1181
|
delete style.backgroundUrl;
|
|
1155
1182
|
delete style.elements;
|
|
1156
1183
|
delete style.imageTransform;
|
|
1184
|
+
for (const key of NUMERIC_STYLE_KEYS) if (key in style) {
|
|
1185
|
+
const value = normalizeNumber(style[key]);
|
|
1186
|
+
if (value === void 0) delete style[key];
|
|
1187
|
+
else style[key] = value;
|
|
1188
|
+
}
|
|
1157
1189
|
}
|
|
1158
1190
|
return style;
|
|
1159
1191
|
}
|
|
@@ -1626,7 +1658,7 @@ function signedArea(data, start, end, dim) {
|
|
|
1626
1658
|
return sum;
|
|
1627
1659
|
}
|
|
1628
1660
|
//#endregion
|
|
1629
|
-
//#region ../../node_modules/.pnpm/modern-path2d@1.
|
|
1661
|
+
//#region ../../node_modules/.pnpm/modern-path2d@1.7.0/node_modules/modern-path2d/dist/index.mjs
|
|
1630
1662
|
function drawPoint(ctx, x, y, options = {}) {
|
|
1631
1663
|
const { radius = 1 } = options;
|
|
1632
1664
|
ctx.moveTo(x, y);
|
|
@@ -1732,7 +1764,7 @@ var Vector2 = class Vector2 {
|
|
|
1732
1764
|
return this.set(this._x * x, this._y * y);
|
|
1733
1765
|
}
|
|
1734
1766
|
divide(x = 0, y = x) {
|
|
1735
|
-
return this.set(this._x / x, this._y / y);
|
|
1767
|
+
return this.set(x === 0 ? this._x : this._x / x, y === 0 ? this._y : this._y / y);
|
|
1736
1768
|
}
|
|
1737
1769
|
cross(p) {
|
|
1738
1770
|
return this._x * p.y - this._y * p.x;
|
|
@@ -1910,9 +1942,9 @@ function getIntersectionPoint(p1, p2, q1, q2) {
|
|
|
1910
1942
|
const s = q2.clone().sub(q1);
|
|
1911
1943
|
const q1p1 = q1.clone().sub(p1);
|
|
1912
1944
|
const crossRS = r.cross(s);
|
|
1913
|
-
if (crossRS === 0) return
|
|
1945
|
+
if (crossRS === 0) return null;
|
|
1914
1946
|
const t = q1p1.cross(s) / crossRS;
|
|
1915
|
-
if (Math.abs(t) > 1) return
|
|
1947
|
+
if (Math.abs(t) > 1) return null;
|
|
1916
1948
|
return new Vector2(p1.x + t * r.x, p1.y + t * r.y);
|
|
1917
1949
|
}
|
|
1918
1950
|
var FUNCTIONS_RE = /([\w-]+)\((.+?)\)/g;
|
|
@@ -2118,7 +2150,7 @@ function recursive(points, x1, y1, x2, y2, x3, y3, distanceTolerance, level) {
|
|
|
2118
2150
|
function cross(ax, ay, bx, by, cx, cy) {
|
|
2119
2151
|
return (bx - ax) * (cy - ay) - (by - ay) * (cx - ax);
|
|
2120
2152
|
}
|
|
2121
|
-
function windingNumber(px, py, polygon) {
|
|
2153
|
+
function windingNumber$1(px, py, polygon) {
|
|
2122
2154
|
const polygonLen = polygon.length;
|
|
2123
2155
|
let wn = 0;
|
|
2124
2156
|
for (let i = 0, j = polygonLen - 2; i < polygonLen; j = i, i += 2) {
|
|
@@ -2137,11 +2169,18 @@ function distance(p1, p2) {
|
|
|
2137
2169
|
const dy = p2[1] - p1[1];
|
|
2138
2170
|
return Math.sqrt(dx * dx + dy * dy);
|
|
2139
2171
|
}
|
|
2172
|
+
function aabbIntersects(a, b) {
|
|
2173
|
+
return a.minX <= b.maxX && a.maxX >= b.minX && a.minY <= b.maxY && a.maxY >= b.minY;
|
|
2174
|
+
}
|
|
2140
2175
|
function nonzeroFillRule(paths) {
|
|
2141
2176
|
const results = paths.map((_, i) => ({ index: i }));
|
|
2142
|
-
const
|
|
2177
|
+
const bboxes = [];
|
|
2178
|
+
const testPointsGroups = paths.map((path, pathIndex) => {
|
|
2143
2179
|
const len = path.length;
|
|
2144
|
-
if (!len)
|
|
2180
|
+
if (!len) {
|
|
2181
|
+
bboxes[pathIndex] = null;
|
|
2182
|
+
return [];
|
|
2183
|
+
}
|
|
2145
2184
|
let xMinYAuto = [Number.MAX_SAFE_INTEGER, 0];
|
|
2146
2185
|
let xAutoYMin = [0, Number.MAX_SAFE_INTEGER];
|
|
2147
2186
|
let xMaxYAuto = [Number.MIN_SAFE_INTEGER, 0];
|
|
@@ -2154,6 +2193,12 @@ function nonzeroFillRule(paths) {
|
|
|
2154
2193
|
if (xMaxYAuto[0] < x) xMaxYAuto = [x, y];
|
|
2155
2194
|
if (xAutoYMax[1] < y) xAutoYMax = [x, y];
|
|
2156
2195
|
}
|
|
2196
|
+
bboxes[pathIndex] = {
|
|
2197
|
+
minX: xMinYAuto[0],
|
|
2198
|
+
minY: xAutoYMin[1],
|
|
2199
|
+
maxX: xMaxYAuto[0],
|
|
2200
|
+
maxY: xAutoYMax[1]
|
|
2201
|
+
};
|
|
2157
2202
|
const mid = [(xMinYAuto[0] + xMaxYAuto[0]) / 2, (xAutoYMin[1] + xAutoYMax[1]) / 2];
|
|
2158
2203
|
let xMidYMinDx;
|
|
2159
2204
|
let xMidYMaxDx;
|
|
@@ -2199,13 +2244,16 @@ function nonzeroFillRule(paths) {
|
|
|
2199
2244
|
for (let i = 0, len = paths.length; i < len; i++) {
|
|
2200
2245
|
const _results = [];
|
|
2201
2246
|
const testPoints = testPointsGroups[i];
|
|
2247
|
+
const boxI = bboxes[i];
|
|
2202
2248
|
for (let j = 0; j < len; j++) {
|
|
2203
2249
|
if (i === j) continue;
|
|
2250
|
+
const boxJ = bboxes[j];
|
|
2251
|
+
if (!boxI || !boxJ || !aabbIntersects(boxI, boxJ)) continue;
|
|
2204
2252
|
const wnMap = {};
|
|
2205
2253
|
const wnList = [];
|
|
2206
2254
|
for (let p = 0, pLen = testPoints.length; p < pLen; p++) {
|
|
2207
2255
|
const [x, y] = testPoints[p];
|
|
2208
|
-
const winding = windingNumber(x, y, paths[j]);
|
|
2256
|
+
const winding = windingNumber$1(x, y, paths[j]);
|
|
2209
2257
|
wnMap[winding] = (wnMap[winding] ?? 0) + 1;
|
|
2210
2258
|
wnList.push(winding);
|
|
2211
2259
|
}
|
|
@@ -2223,6 +2271,88 @@ function nonzeroFillRule(paths) {
|
|
|
2223
2271
|
}
|
|
2224
2272
|
return results;
|
|
2225
2273
|
}
|
|
2274
|
+
function isLeft(ax, ay, bx, by, px, py) {
|
|
2275
|
+
return (bx - ax) * (py - ay) - (px - ax) * (by - ay);
|
|
2276
|
+
}
|
|
2277
|
+
function windingNumber(px, py, vertices) {
|
|
2278
|
+
const len = vertices.length;
|
|
2279
|
+
let wn = 0;
|
|
2280
|
+
for (let i = 0; i < len; i += 2) {
|
|
2281
|
+
const ax = vertices[i];
|
|
2282
|
+
const ay = vertices[i + 1];
|
|
2283
|
+
const k = (i + 2) % len;
|
|
2284
|
+
const bx = vertices[k];
|
|
2285
|
+
const by = vertices[k + 1];
|
|
2286
|
+
if (ay <= py) {
|
|
2287
|
+
if (by > py && isLeft(ax, ay, bx, by, px, py) > 0) wn++;
|
|
2288
|
+
} else if (by <= py && isLeft(ax, ay, bx, by, px, py) < 0) wn--;
|
|
2289
|
+
}
|
|
2290
|
+
return wn;
|
|
2291
|
+
}
|
|
2292
|
+
function crossingNumber(px, py, vertices) {
|
|
2293
|
+
const len = vertices.length;
|
|
2294
|
+
let cn = 0;
|
|
2295
|
+
for (let i = 0; i < len; i += 2) {
|
|
2296
|
+
const ax = vertices[i];
|
|
2297
|
+
const ay = vertices[i + 1];
|
|
2298
|
+
const k = (i + 2) % len;
|
|
2299
|
+
const bx = vertices[k];
|
|
2300
|
+
const by = vertices[k + 1];
|
|
2301
|
+
if (ay <= py && by > py || ay > py && by <= py) {
|
|
2302
|
+
if (px < ax + (py - ay) / (by - ay) * (bx - ax)) cn++;
|
|
2303
|
+
}
|
|
2304
|
+
}
|
|
2305
|
+
return cn;
|
|
2306
|
+
}
|
|
2307
|
+
function segmentDistance(px, py, ax, ay, bx, by) {
|
|
2308
|
+
const dx = bx - ax;
|
|
2309
|
+
const dy = by - ay;
|
|
2310
|
+
const lenSq = dx * dx + dy * dy;
|
|
2311
|
+
let t = lenSq === 0 ? 0 : ((px - ax) * dx + (py - ay) * dy) / lenSq;
|
|
2312
|
+
if (t < 0) t = 0;
|
|
2313
|
+
else if (t > 1) t = 1;
|
|
2314
|
+
const cx = ax + t * dx;
|
|
2315
|
+
const cy = ay + t * dy;
|
|
2316
|
+
return Math.hypot(px - cx, py - cy);
|
|
2317
|
+
}
|
|
2318
|
+
function pointInPolygon(point, vertices, fillRule = "nonzero") {
|
|
2319
|
+
if (vertices.length < 6) return false;
|
|
2320
|
+
if (fillRule === "evenodd") return (crossingNumber(point.x, point.y, vertices) & 1) === 1;
|
|
2321
|
+
return windingNumber(point.x, point.y, vertices) !== 0;
|
|
2322
|
+
}
|
|
2323
|
+
function pointInPolygons(point, polygons, fillRule = "nonzero") {
|
|
2324
|
+
const { x, y } = point;
|
|
2325
|
+
if (fillRule === "evenodd") {
|
|
2326
|
+
let cn = 0;
|
|
2327
|
+
for (let i = 0, len = polygons.length; i < len; i++) {
|
|
2328
|
+
const ring = polygons[i];
|
|
2329
|
+
if (ring.length >= 6) cn += crossingNumber(x, y, ring);
|
|
2330
|
+
}
|
|
2331
|
+
return (cn & 1) === 1;
|
|
2332
|
+
}
|
|
2333
|
+
let wn = 0;
|
|
2334
|
+
for (let i = 0, len = polygons.length; i < len; i++) {
|
|
2335
|
+
const ring = polygons[i];
|
|
2336
|
+
if (ring.length >= 6) wn += windingNumber(x, y, ring);
|
|
2337
|
+
}
|
|
2338
|
+
return wn !== 0;
|
|
2339
|
+
}
|
|
2340
|
+
function pointToPolylineDistance(point, vertices, closed = false) {
|
|
2341
|
+
const len = vertices.length;
|
|
2342
|
+
if (len < 2) return Infinity;
|
|
2343
|
+
const { x: px, y: py } = point;
|
|
2344
|
+
if (len === 2) return Math.hypot(px - vertices[0], py - vertices[1]);
|
|
2345
|
+
let min = Infinity;
|
|
2346
|
+
for (let i = 0; i < len - 2; i += 2) {
|
|
2347
|
+
const d = segmentDistance(px, py, vertices[i], vertices[i + 1], vertices[i + 2], vertices[i + 3]);
|
|
2348
|
+
if (d < min) min = d;
|
|
2349
|
+
}
|
|
2350
|
+
if (closed && len >= 6) {
|
|
2351
|
+
const d = segmentDistance(px, py, vertices[len - 2], vertices[len - 1], vertices[0], vertices[1]);
|
|
2352
|
+
if (d < min) min = d;
|
|
2353
|
+
}
|
|
2354
|
+
return min;
|
|
2355
|
+
}
|
|
2226
2356
|
function quadraticBezierP0(t, p) {
|
|
2227
2357
|
const k = 1 - t;
|
|
2228
2358
|
return k * k * p;
|
|
@@ -3728,6 +3858,39 @@ function svgToPath2DSet(svg) {
|
|
|
3728
3858
|
var Curve = class {
|
|
3729
3859
|
arcLengthDivision = 200;
|
|
3730
3860
|
_lengths = [];
|
|
3861
|
+
_adaptiveCache;
|
|
3862
|
+
/**
|
|
3863
|
+
* Parent composite, set lazily when a composite caches its children. Lets
|
|
3864
|
+
* {@link invalidate} propagate up so an ancestor's caches refresh too.
|
|
3865
|
+
*/
|
|
3866
|
+
_owner;
|
|
3867
|
+
_invalidating = false;
|
|
3868
|
+
/**
|
|
3869
|
+
* Drop cached arc lengths and the cached sampled outline used by hit testing, then
|
|
3870
|
+
* bubble up to {@link _owner}. Called automatically by {@link applyTransform} and the
|
|
3871
|
+
* `Path2D` mutators; call it manually after mutating control-point coordinates in place —
|
|
3872
|
+
* the caches cannot observe such mutations.
|
|
3873
|
+
*/
|
|
3874
|
+
invalidate() {
|
|
3875
|
+
if (this._invalidating) return this;
|
|
3876
|
+
this._invalidating = true;
|
|
3877
|
+
this._invalidateSelf();
|
|
3878
|
+
this._owner?.invalidate();
|
|
3879
|
+
this._invalidating = false;
|
|
3880
|
+
return this;
|
|
3881
|
+
}
|
|
3882
|
+
/** Clears this curve's own caches. Composites also clear their children (see override). */
|
|
3883
|
+
_invalidateSelf() {
|
|
3884
|
+
this._lengths.length = 0;
|
|
3885
|
+
this._adaptiveCache = void 0;
|
|
3886
|
+
}
|
|
3887
|
+
/**
|
|
3888
|
+
* Sampled outline cached for repeated hit tests (read-only — do not mutate the result).
|
|
3889
|
+
* Invalidated by {@link invalidate}.
|
|
3890
|
+
*/
|
|
3891
|
+
_getCachedAdaptiveVertices() {
|
|
3892
|
+
return this._adaptiveCache ??= this.getAdaptiveVertices();
|
|
3893
|
+
}
|
|
3731
3894
|
getPointAt(u, output = new Vector2()) {
|
|
3732
3895
|
return this.getPoint(this.getUToTMapping(u), output);
|
|
3733
3896
|
}
|
|
@@ -3743,6 +3906,7 @@ var Curve = class {
|
|
|
3743
3906
|
if (isFunction) transform(p);
|
|
3744
3907
|
else transform.apply(p, p);
|
|
3745
3908
|
});
|
|
3909
|
+
this.invalidate();
|
|
3746
3910
|
return this;
|
|
3747
3911
|
}
|
|
3748
3912
|
getUnevenVertices(count = 5, output = []) {
|
|
@@ -3869,12 +4033,21 @@ var Curve = class {
|
|
|
3869
4033
|
return mid;
|
|
3870
4034
|
}
|
|
3871
4035
|
getMinMax(min = Vector2.MAX, max = Vector2.MIN) {
|
|
3872
|
-
const
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
4036
|
+
const vertices = this.getAdaptiveVertices();
|
|
4037
|
+
let minX = min.x;
|
|
4038
|
+
let minY = min.y;
|
|
4039
|
+
let maxX = max.x;
|
|
4040
|
+
let maxY = max.y;
|
|
4041
|
+
for (let i = 0, len = vertices.length; i < len; i += 2) {
|
|
4042
|
+
const x = vertices[i];
|
|
4043
|
+
const y = vertices[i + 1];
|
|
4044
|
+
if (x < minX) minX = x;
|
|
4045
|
+
if (y < minY) minY = y;
|
|
4046
|
+
if (x > maxX) maxX = x;
|
|
4047
|
+
if (y > maxY) maxY = y;
|
|
3877
4048
|
}
|
|
4049
|
+
min.set(minX, minY);
|
|
4050
|
+
max.set(maxX, maxY);
|
|
3878
4051
|
return {
|
|
3879
4052
|
min: min.finite(),
|
|
3880
4053
|
max: max.finite()
|
|
@@ -3884,6 +4057,42 @@ var Curve = class {
|
|
|
3884
4057
|
const { min, max } = this.getMinMax();
|
|
3885
4058
|
return new BoundingBox(min.x, min.y, max.x - min.x, max.y - min.y);
|
|
3886
4059
|
}
|
|
4060
|
+
/**
|
|
4061
|
+
* Test whether a point lies inside the area enclosed by this curve.
|
|
4062
|
+
*
|
|
4063
|
+
* The curve is sampled via {@link getAdaptiveVertices} into a single implicitly closed
|
|
4064
|
+
* ring. This is purely geometric (it ignores any `fill`/`stroke` style), mirroring
|
|
4065
|
+
* `CanvasRenderingContext2D.isPointInPath`.
|
|
4066
|
+
*
|
|
4067
|
+
* Composites that hold multiple sub-paths (e.g. {@link Path2D}) override this so holes
|
|
4068
|
+
* are honored — a single `Curve` is always one ring.
|
|
4069
|
+
*/
|
|
4070
|
+
isPointInFill(point, options = {}) {
|
|
4071
|
+
return pointInPolygon(point, this._getCachedAdaptiveVertices(), options.fillRule);
|
|
4072
|
+
}
|
|
4073
|
+
/**
|
|
4074
|
+
* Test whether a point lies on this curve's stroke, i.e. within `strokeWidth / 2 + tolerance`
|
|
4075
|
+
* of the sampled outline. The point must be in the same coordinate space as the curve.
|
|
4076
|
+
*
|
|
4077
|
+
* Options: `strokeWidth` (path units, default `1`), `tolerance` (extra hit slack in path
|
|
4078
|
+
* units, default `0` — useful for thin strokes; no coordinate scaling is assumed, so convert
|
|
4079
|
+
* pixel tolerance to path units upstream if your path is normalized), and `closed` (whether
|
|
4080
|
+
* to include the closing edge from the last vertex back to the first).
|
|
4081
|
+
*/
|
|
4082
|
+
isPointInStroke(point, options = {}) {
|
|
4083
|
+
const { strokeWidth = 1, tolerance = 0, closed = false } = options;
|
|
4084
|
+
return pointToPolylineDistance(point, this._getCachedAdaptiveVertices(), closed) <= strokeWidth / 2 + tolerance;
|
|
4085
|
+
}
|
|
4086
|
+
/**
|
|
4087
|
+
* Concise PathKit-style fill containment test: `contains(x, y)` is shorthand for
|
|
4088
|
+
* {@link isPointInFill} with a `{ x, y }` point.
|
|
4089
|
+
*/
|
|
4090
|
+
contains(x, y, options = {}) {
|
|
4091
|
+
return this.isPointInFill({
|
|
4092
|
+
x,
|
|
4093
|
+
y
|
|
4094
|
+
}, options);
|
|
4095
|
+
}
|
|
3887
4096
|
getFillVertices(_options) {
|
|
3888
4097
|
return this.getAdaptiveVertices();
|
|
3889
4098
|
}
|
|
@@ -4013,6 +4222,64 @@ var RoundCurve = class extends Curve {
|
|
|
4013
4222
|
}
|
|
4014
4223
|
return output.set(_x, _y);
|
|
4015
4224
|
}
|
|
4225
|
+
/**
|
|
4226
|
+
* Point on the ellipse at an absolute angle (mirrors {@link getPoint}'s parameterization,
|
|
4227
|
+
* ignoring `_diff`).
|
|
4228
|
+
*/
|
|
4229
|
+
_pointAtAngle(angle, output) {
|
|
4230
|
+
let x = this.cx + this.rx * Math.cos(angle);
|
|
4231
|
+
let y = this.cy + this.ry * Math.sin(angle);
|
|
4232
|
+
if (this.rotate !== 0) {
|
|
4233
|
+
const cos = Math.cos(this.rotate);
|
|
4234
|
+
const sin = Math.sin(this.rotate);
|
|
4235
|
+
const tx = x - this.cx;
|
|
4236
|
+
const ty = y - this.cy;
|
|
4237
|
+
x = tx * cos - ty * sin + this.cx;
|
|
4238
|
+
y = tx * sin + ty * cos + this.cy;
|
|
4239
|
+
}
|
|
4240
|
+
return output.set(x, y);
|
|
4241
|
+
}
|
|
4242
|
+
/**
|
|
4243
|
+
* Analytical bounds of the (elliptical) arc: the start/end points plus the per-axis
|
|
4244
|
+
* extrema angles that fall within the swept interval. Matches {@link getPoint}, so it is
|
|
4245
|
+
* exact for `ArcCurve`/`EllipseCurve`. The `_diff` offset (used only by the legacy
|
|
4246
|
+
* `_getAdaptiveVerticesByCircle` path) is intentionally ignored here.
|
|
4247
|
+
*/
|
|
4248
|
+
getMinMax(min = Vector2.MAX, max = Vector2.MIN) {
|
|
4249
|
+
const { startAngle, rotate } = this;
|
|
4250
|
+
const delta = this._getDeltaAngle();
|
|
4251
|
+
const cosT = Math.cos(rotate);
|
|
4252
|
+
const sinT = Math.sin(rotate);
|
|
4253
|
+
const p = tempV2;
|
|
4254
|
+
let minX = min.x;
|
|
4255
|
+
let minY = min.y;
|
|
4256
|
+
let maxX = max.x;
|
|
4257
|
+
let maxY = max.y;
|
|
4258
|
+
const consider = (angle) => {
|
|
4259
|
+
this._pointAtAngle(angle, p);
|
|
4260
|
+
if (p.x < minX) minX = p.x;
|
|
4261
|
+
if (p.y < minY) minY = p.y;
|
|
4262
|
+
if (p.x > maxX) maxX = p.x;
|
|
4263
|
+
if (p.y > maxY) maxY = p.y;
|
|
4264
|
+
};
|
|
4265
|
+
consider(startAngle);
|
|
4266
|
+
consider(startAngle + delta);
|
|
4267
|
+
const ax = Math.atan2(-this.ry * sinT, this.rx * cosT);
|
|
4268
|
+
const ay = Math.atan2(this.ry * cosT, this.rx * sinT);
|
|
4269
|
+
const bases = [
|
|
4270
|
+
ax,
|
|
4271
|
+
ax + Math.PI,
|
|
4272
|
+
ay,
|
|
4273
|
+
ay + Math.PI
|
|
4274
|
+
];
|
|
4275
|
+
for (let i = 0; i < 4; i++) if (angleInSweep(bases[i], startAngle, delta)) consider(bases[i]);
|
|
4276
|
+
min.set(minX, minY);
|
|
4277
|
+
max.set(maxX, maxY);
|
|
4278
|
+
return {
|
|
4279
|
+
min: min.finite(),
|
|
4280
|
+
max: max.finite()
|
|
4281
|
+
};
|
|
4282
|
+
}
|
|
4016
4283
|
toCommands() {
|
|
4017
4284
|
const { cx, cy, rx, ry, startAngle, endAngle, clockwise, rotate } = this;
|
|
4018
4285
|
const startX = cx + rx * Math.cos(startAngle) * Math.cos(rotate) - ry * Math.sin(startAngle) * Math.sin(rotate);
|
|
@@ -4083,6 +4350,7 @@ var RoundCurve = class extends Curve {
|
|
|
4083
4350
|
this.cy = tempV2.y;
|
|
4084
4351
|
if (isTransformSkewed(transform)) transfEllipseGeneric(this, transform);
|
|
4085
4352
|
else transfEllipseNoSkew(this, transform);
|
|
4353
|
+
this.invalidate();
|
|
4086
4354
|
return this;
|
|
4087
4355
|
}
|
|
4088
4356
|
getControlPointRefs() {
|
|
@@ -4212,6 +4480,18 @@ var RoundCurve = class extends Curve {
|
|
|
4212
4480
|
return this;
|
|
4213
4481
|
}
|
|
4214
4482
|
};
|
|
4483
|
+
function angleInSweep(a, start, delta) {
|
|
4484
|
+
const PI_2 = Math.PI * 2;
|
|
4485
|
+
const eps = 1e-9;
|
|
4486
|
+
if (Math.abs(delta) >= PI_2 - eps) return true;
|
|
4487
|
+
let off = (a - start) % PI_2;
|
|
4488
|
+
if (delta >= 0) {
|
|
4489
|
+
if (off < -1e-9) off += PI_2;
|
|
4490
|
+
return off >= -1e-9 && off <= delta + eps;
|
|
4491
|
+
}
|
|
4492
|
+
if (off > eps) off -= PI_2;
|
|
4493
|
+
return off <= eps && off >= delta - eps;
|
|
4494
|
+
}
|
|
4215
4495
|
function transfEllipseGeneric(curve, m) {
|
|
4216
4496
|
const a = curve.rx;
|
|
4217
4497
|
const b = curve.ry;
|
|
@@ -4412,6 +4692,22 @@ var CompositeCurve = class CompositeCurve extends Curve {
|
|
|
4412
4692
|
super();
|
|
4413
4693
|
this.curves = curves;
|
|
4414
4694
|
}
|
|
4695
|
+
_adaptiveCacheLen = -1;
|
|
4696
|
+
_invalidateSelf() {
|
|
4697
|
+
super._invalidateSelf();
|
|
4698
|
+
this._adaptiveCacheLen = -1;
|
|
4699
|
+
this.curves.forEach((curve) => curve.invalidate());
|
|
4700
|
+
}
|
|
4701
|
+
_getCachedAdaptiveVertices() {
|
|
4702
|
+
if (!this._adaptiveCache || this._adaptiveCacheLen !== this.curves.length) {
|
|
4703
|
+
this.curves.forEach((curve) => {
|
|
4704
|
+
curve._owner = this;
|
|
4705
|
+
});
|
|
4706
|
+
this._adaptiveCache = this.getAdaptiveVertices();
|
|
4707
|
+
this._adaptiveCacheLen = this.curves.length;
|
|
4708
|
+
}
|
|
4709
|
+
return this._adaptiveCache;
|
|
4710
|
+
}
|
|
4415
4711
|
getFlatCurves() {
|
|
4416
4712
|
return this.curves.flatMap((curve) => {
|
|
4417
4713
|
if (curve instanceof CompositeCurve) return curve.getFlatCurves();
|
|
@@ -4446,6 +4742,7 @@ var CompositeCurve = class CompositeCurve extends Curve {
|
|
|
4446
4742
|
updateLengths() {
|
|
4447
4743
|
const lengths = [];
|
|
4448
4744
|
for (let i = 0, sum = 0, len = this.curves.length; i < len; i++) {
|
|
4745
|
+
this.curves[i]._owner = this;
|
|
4449
4746
|
sum += this.curves[i].getLength();
|
|
4450
4747
|
lengths.push(sum);
|
|
4451
4748
|
}
|
|
@@ -4499,7 +4796,10 @@ var CompositeCurve = class CompositeCurve extends Curve {
|
|
|
4499
4796
|
}
|
|
4500
4797
|
}
|
|
4501
4798
|
applyTransform(transform) {
|
|
4799
|
+
this._invalidating = true;
|
|
4502
4800
|
this.curves.forEach((curve) => curve.applyTransform(transform));
|
|
4801
|
+
this._invalidating = false;
|
|
4802
|
+
this.invalidate();
|
|
4503
4803
|
return this;
|
|
4504
4804
|
}
|
|
4505
4805
|
getMinMax(min = Vector2.MAX, max = Vector2.MIN) {
|
|
@@ -4756,7 +5056,7 @@ var RectangleCurve = class extends PolygonCurve {
|
|
|
4756
5056
|
return this;
|
|
4757
5057
|
}
|
|
4758
5058
|
};
|
|
4759
|
-
var RoundRectangleCurve = class extends
|
|
5059
|
+
var RoundRectangleCurve = class extends CompositeCurve {
|
|
4760
5060
|
constructor(x = 0, y = 0, width = 1, height = 1, radius = 1) {
|
|
4761
5061
|
super();
|
|
4762
5062
|
this.x = x;
|
|
@@ -4767,25 +5067,44 @@ var RoundRectangleCurve = class extends RoundCurve {
|
|
|
4767
5067
|
this.update();
|
|
4768
5068
|
}
|
|
4769
5069
|
update() {
|
|
4770
|
-
const { x, y, width, height
|
|
4771
|
-
const
|
|
4772
|
-
const
|
|
4773
|
-
const
|
|
4774
|
-
const
|
|
4775
|
-
const
|
|
4776
|
-
const
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
|
|
5070
|
+
const { x, y, width, height } = this;
|
|
5071
|
+
const r = Math.max(0, Math.min(this.radius, Math.abs(width) / 2, Math.abs(height) / 2));
|
|
5072
|
+
const x0 = x;
|
|
5073
|
+
const x1 = x + r;
|
|
5074
|
+
const x2 = x + width - r;
|
|
5075
|
+
const x3 = x + width;
|
|
5076
|
+
const y0 = y;
|
|
5077
|
+
const y1 = y + r;
|
|
5078
|
+
const y2 = y + height - r;
|
|
5079
|
+
const y3 = y + height;
|
|
5080
|
+
if (r <= 0) this.curves = [
|
|
5081
|
+
LineCurve.from(x0, y0, x3, y0),
|
|
5082
|
+
LineCurve.from(x3, y0, x3, y3),
|
|
5083
|
+
LineCurve.from(x3, y3, x0, y3),
|
|
5084
|
+
LineCurve.from(x0, y3, x0, y0)
|
|
5085
|
+
];
|
|
5086
|
+
else {
|
|
5087
|
+
const HALF_PI = Math.PI / 2;
|
|
5088
|
+
this.curves = [
|
|
5089
|
+
LineCurve.from(x1, y0, x2, y0),
|
|
5090
|
+
new ArcCurve(x2, y1, r, -HALF_PI, 0, true),
|
|
5091
|
+
LineCurve.from(x3, y1, x3, y2),
|
|
5092
|
+
new ArcCurve(x2, y2, r, 0, HALF_PI, true),
|
|
5093
|
+
LineCurve.from(x2, y3, x1, y3),
|
|
5094
|
+
new ArcCurve(x1, y2, r, HALF_PI, Math.PI, true),
|
|
5095
|
+
LineCurve.from(x0, y2, x0, y1),
|
|
5096
|
+
new ArcCurve(x1, y1, r, Math.PI, Math.PI * 1.5, true)
|
|
5097
|
+
];
|
|
5098
|
+
}
|
|
5099
|
+
this.invalidate();
|
|
4780
5100
|
return this;
|
|
4781
5101
|
}
|
|
4782
5102
|
drawTo(ctx) {
|
|
4783
|
-
|
|
4784
|
-
ctx.roundRect(x, y, width, height, radius);
|
|
5103
|
+
ctx.roundRect(this.x, this.y, this.width, this.height, this.radius);
|
|
4785
5104
|
return this;
|
|
4786
5105
|
}
|
|
4787
5106
|
copyFrom(source) {
|
|
4788
|
-
|
|
5107
|
+
this.arcLengthDivision = source.arcLengthDivision;
|
|
4789
5108
|
this.x = source.x;
|
|
4790
5109
|
this.y = source.y;
|
|
4791
5110
|
this.width = source.width;
|
|
@@ -4862,6 +5181,16 @@ var CurvePath = class extends CompositeCurve {
|
|
|
4862
5181
|
getFillVertices(options) {
|
|
4863
5182
|
return this._closeVertices(super.getFillVertices(options));
|
|
4864
5183
|
}
|
|
5184
|
+
/**
|
|
5185
|
+
* Same as {@link Curve.isPointInStroke}, but `closed` defaults to this sub-path's actual
|
|
5186
|
+
* closed-ness: explicitly `autoClose`, or geometrically closed (first vertex === last).
|
|
5187
|
+
*/
|
|
5188
|
+
isPointInStroke(point, options = {}) {
|
|
5189
|
+
const { strokeWidth = 1, tolerance = 0 } = options;
|
|
5190
|
+
const vertices = this._getCachedAdaptiveVertices();
|
|
5191
|
+
const len = vertices.length;
|
|
5192
|
+
return pointToPolylineDistance(point, vertices, options.closed ?? (this.autoClose || len >= 6 && vertices[0] === vertices[len - 2] && vertices[1] === vertices[len - 1])) <= strokeWidth / 2 + tolerance;
|
|
5193
|
+
}
|
|
4865
5194
|
_setCurrentPoint(point) {
|
|
4866
5195
|
this.currentPoint = new Vector2(point.x, point.y);
|
|
4867
5196
|
if (!this.startPoint) this.startPoint = this.currentPoint.clone();
|
|
@@ -4999,6 +5328,8 @@ var CurvePath = class extends CompositeCurve {
|
|
|
4999
5328
|
};
|
|
5000
5329
|
var Path2D = class Path2D extends CompositeCurve {
|
|
5001
5330
|
_meta;
|
|
5331
|
+
_ringsCache;
|
|
5332
|
+
_ringsCacheLen = -1;
|
|
5002
5333
|
currentCurve = new CurvePath();
|
|
5003
5334
|
style;
|
|
5004
5335
|
get startPoint() {
|
|
@@ -5110,6 +5441,7 @@ var Path2D = class Path2D extends CompositeCurve {
|
|
|
5110
5441
|
this.getControlPointRefs().forEach((point) => {
|
|
5111
5442
|
point.scale(sx, sy, target);
|
|
5112
5443
|
});
|
|
5444
|
+
this.invalidate();
|
|
5113
5445
|
return this;
|
|
5114
5446
|
}
|
|
5115
5447
|
skew(ax, ay = 0, target = {
|
|
@@ -5119,6 +5451,7 @@ var Path2D = class Path2D extends CompositeCurve {
|
|
|
5119
5451
|
this.getControlPointRefs().forEach((point) => {
|
|
5120
5452
|
point.skew(ax, ay, target);
|
|
5121
5453
|
});
|
|
5454
|
+
this.invalidate();
|
|
5122
5455
|
return this;
|
|
5123
5456
|
}
|
|
5124
5457
|
rotate(rad, target = {
|
|
@@ -5128,6 +5461,7 @@ var Path2D = class Path2D extends CompositeCurve {
|
|
|
5128
5461
|
this.getControlPointRefs().forEach((point) => {
|
|
5129
5462
|
point.rotate(rad, target);
|
|
5130
5463
|
});
|
|
5464
|
+
this.invalidate();
|
|
5131
5465
|
return this;
|
|
5132
5466
|
}
|
|
5133
5467
|
bold(b) {
|
|
@@ -5173,47 +5507,67 @@ var Path2D = class Path2D extends CompositeCurve {
|
|
|
5173
5507
|
}
|
|
5174
5508
|
});
|
|
5175
5509
|
});
|
|
5510
|
+
this.invalidate();
|
|
5176
5511
|
return this;
|
|
5177
5512
|
}
|
|
5513
|
+
/**
|
|
5514
|
+
* Test whether a point lies inside the filled area of this path.
|
|
5515
|
+
*
|
|
5516
|
+
* Each sub-path ({@link CurvePath}) is sampled into its own ring and all rings are
|
|
5517
|
+
* evaluated together via {@link pointInPolygons}, so holes (donut / hollow shapes) are
|
|
5518
|
+
* honored. This is purely geometric and ignores `style.fill` — for the `fill: 'none'`
|
|
5519
|
+
* fallback, gate the call upstream (see {@link Path2DSet.hitTest}).
|
|
5520
|
+
*
|
|
5521
|
+
* Defaults `fillRule` to `style.fillRule`, then `'nonzero'` (matching SVG/Canvas).
|
|
5522
|
+
*/
|
|
5523
|
+
_invalidateSelf() {
|
|
5524
|
+
super._invalidateSelf();
|
|
5525
|
+
this._ringsCache = void 0;
|
|
5526
|
+
this._ringsCacheLen = -1;
|
|
5527
|
+
}
|
|
5528
|
+
/** Per-sub-path sampled rings, cached for repeated hit tests. */
|
|
5529
|
+
_getRings() {
|
|
5530
|
+
if (!this._ringsCache || this._ringsCacheLen !== this.curves.length) {
|
|
5531
|
+
this._ringsCache = this.curves.map((curve) => {
|
|
5532
|
+
curve._owner = this;
|
|
5533
|
+
return curve.getAdaptiveVertices();
|
|
5534
|
+
});
|
|
5535
|
+
this._ringsCacheLen = this.curves.length;
|
|
5536
|
+
}
|
|
5537
|
+
return this._ringsCache;
|
|
5538
|
+
}
|
|
5539
|
+
isPointInFill(point, options = {}) {
|
|
5540
|
+
const fillRule = options.fillRule ?? this.style.fillRule ?? "nonzero";
|
|
5541
|
+
return pointInPolygons(point, this._getRings(), fillRule);
|
|
5542
|
+
}
|
|
5543
|
+
/**
|
|
5544
|
+
* Test whether a point lies on this path's stroke. A hit on any sub-path counts.
|
|
5545
|
+
*
|
|
5546
|
+
* Defaults `strokeWidth` to this path's own {@link strokeWidth} (which is `0` when
|
|
5547
|
+
* `style.stroke` is `'none'`). Each sub-path infers its own closed-ness unless `closed`
|
|
5548
|
+
* is given explicitly.
|
|
5549
|
+
*/
|
|
5550
|
+
isPointInStroke(point, options = {}) {
|
|
5551
|
+
const strokeWidth = options.strokeWidth ?? this.strokeWidth;
|
|
5552
|
+
const { tolerance = 0, closed } = options;
|
|
5553
|
+
return this.curves.some((curve) => curve.isPointInStroke(point, {
|
|
5554
|
+
strokeWidth,
|
|
5555
|
+
tolerance,
|
|
5556
|
+
closed
|
|
5557
|
+
}));
|
|
5558
|
+
}
|
|
5178
5559
|
getMinMax(min = Vector2.MAX, max = Vector2.MIN, withStyle = true) {
|
|
5179
|
-
const strokeWidth = this.strokeWidth;
|
|
5180
5560
|
this.curves.forEach((curve) => {
|
|
5181
5561
|
curve.getMinMax(min, max);
|
|
5182
|
-
if (withStyle) {
|
|
5183
|
-
if (strokeWidth > 1) {
|
|
5184
|
-
const halfStrokeWidth = strokeWidth / 2;
|
|
5185
|
-
const isClockwise = curve.isClockwise();
|
|
5186
|
-
const points = [];
|
|
5187
|
-
for (let t = 0; t <= 1; t += 1 / curve.arcLengthDivision) {
|
|
5188
|
-
const point = curve.getPoint(t);
|
|
5189
|
-
const normal = curve.getNormal(t);
|
|
5190
|
-
const dist1 = normal.clone().scale(isClockwise ? halfStrokeWidth : -halfStrokeWidth);
|
|
5191
|
-
const dist2 = normal.clone().scale(isClockwise ? -halfStrokeWidth : halfStrokeWidth);
|
|
5192
|
-
points.push(point.clone().add(dist1), point.clone().add(dist2), point.clone().add({
|
|
5193
|
-
x: halfStrokeWidth,
|
|
5194
|
-
y: 0
|
|
5195
|
-
}), point.clone().add({
|
|
5196
|
-
x: -halfStrokeWidth,
|
|
5197
|
-
y: 0
|
|
5198
|
-
}), point.clone().add({
|
|
5199
|
-
x: 0,
|
|
5200
|
-
y: halfStrokeWidth
|
|
5201
|
-
}), point.clone().add({
|
|
5202
|
-
x: 0,
|
|
5203
|
-
y: -halfStrokeWidth
|
|
5204
|
-
}), point.clone().add({
|
|
5205
|
-
x: halfStrokeWidth,
|
|
5206
|
-
y: halfStrokeWidth
|
|
5207
|
-
}), point.clone().add({
|
|
5208
|
-
x: -halfStrokeWidth,
|
|
5209
|
-
y: -halfStrokeWidth
|
|
5210
|
-
}));
|
|
5211
|
-
}
|
|
5212
|
-
min.clampMin(...points);
|
|
5213
|
-
max.clampMax(...points);
|
|
5214
|
-
}
|
|
5215
|
-
}
|
|
5216
5562
|
});
|
|
5563
|
+
if (withStyle) {
|
|
5564
|
+
const strokeWidth = this.strokeWidth;
|
|
5565
|
+
if (strokeWidth > 1 && Number.isFinite(min.x)) {
|
|
5566
|
+
const half = strokeWidth / 2;
|
|
5567
|
+
min.set(min.x - half, min.y - half);
|
|
5568
|
+
max.set(max.x + half, max.y + half);
|
|
5569
|
+
}
|
|
5570
|
+
}
|
|
5217
5571
|
return {
|
|
5218
5572
|
min: min.finite(),
|
|
5219
5573
|
max: max.finite()
|
|
@@ -5352,6 +5706,42 @@ var Path2DSet = class {
|
|
|
5352
5706
|
this.paths = paths;
|
|
5353
5707
|
this.viewBox = viewBox;
|
|
5354
5708
|
}
|
|
5709
|
+
/**
|
|
5710
|
+
* Test whether a point lies inside the filled area of any path in this set.
|
|
5711
|
+
* Purely geometric (ignores `fill: 'none'`); use {@link hitTest} for style-aware hits.
|
|
5712
|
+
*/
|
|
5713
|
+
isPointInFill(point, options = {}) {
|
|
5714
|
+
return this.paths.some((path) => path.isPointInFill(point, options));
|
|
5715
|
+
}
|
|
5716
|
+
/**
|
|
5717
|
+
* Concise PathKit-style fill containment test across the whole set; shorthand for
|
|
5718
|
+
* {@link isPointInFill} with a `{ x, y }` point.
|
|
5719
|
+
*/
|
|
5720
|
+
contains(x, y, options = {}) {
|
|
5721
|
+
return this.isPointInFill({
|
|
5722
|
+
x,
|
|
5723
|
+
y
|
|
5724
|
+
}, options);
|
|
5725
|
+
}
|
|
5726
|
+
/**
|
|
5727
|
+
* Find the topmost path hit by a point, or `undefined` if none.
|
|
5728
|
+
*
|
|
5729
|
+
* Paths are tested top-to-bottom (last drawn first). For each path a fill hit is checked
|
|
5730
|
+
* first (skipped when `style.fill` is `'none'`), then — if `stroke` is enabled — a stroke
|
|
5731
|
+
* hit (skipped when `style.stroke` is `'none'`). This honors the "fill: none falls back to
|
|
5732
|
+
* stroke" rule; the coordinate space of `point` must match the paths (no scaling assumed).
|
|
5733
|
+
*
|
|
5734
|
+
* Options: `stroke` (also test strokes, default `true`), `tolerance` (extra stroke hit slack
|
|
5735
|
+
* in path units, default `0`), and `fillRule` (overrides each path's own fill rule).
|
|
5736
|
+
*/
|
|
5737
|
+
hitTest(point, options = {}) {
|
|
5738
|
+
const { stroke = true, tolerance, fillRule } = options;
|
|
5739
|
+
for (let i = this.paths.length - 1; i >= 0; i--) {
|
|
5740
|
+
const path = this.paths[i];
|
|
5741
|
+
if ((path.style.fill ?? "#000") !== "none" && path.isPointInFill(point, { fillRule })) return path;
|
|
5742
|
+
if (stroke && (path.style.stroke ?? "none") !== "none" && path.isPointInStroke(point, { tolerance })) return path;
|
|
5743
|
+
}
|
|
5744
|
+
}
|
|
5355
5745
|
getBoundingBox(withStyle = true) {
|
|
5356
5746
|
if (!this.paths.length) return;
|
|
5357
5747
|
const min = Vector2.MAX;
|
|
@@ -5655,7 +6045,7 @@ function _createPresetShape(node, options) {
|
|
|
5655
6045
|
var root;
|
|
5656
6046
|
async function getRoot() {
|
|
5657
6047
|
if (!root) {
|
|
5658
|
-
const presetShapeDefinitions = await import("./presetShapeDefinitions-
|
|
6048
|
+
const presetShapeDefinitions = await import("./presetShapeDefinitions-NAoQKZ6z.js").then((rep) => rep.default);
|
|
5659
6049
|
root = OoxmlNode.fromXML(presetShapeDefinitions);
|
|
5660
6050
|
}
|
|
5661
6051
|
return root;
|
|
@@ -5716,6 +6106,221 @@ function convertSvgLinearGradient(value) {
|
|
|
5716
6106
|
}
|
|
5717
6107
|
}
|
|
5718
6108
|
//#endregion
|
|
6109
|
+
//#region src/convert/image.ts
|
|
6110
|
+
function cachedFetchImageBitmap(url) {
|
|
6111
|
+
if (typeof url === "string" && url.startsWith("http")) return assets.loadBy(url).then((blob) => assets.fetchImageBitmap(blob));
|
|
6112
|
+
return assets.fetchImageBitmap(url);
|
|
6113
|
+
}
|
|
6114
|
+
async function convertImageElementToUrl(el) {
|
|
6115
|
+
const { cropping = {}, transform = {}, style = {}, maskUrl, imageEffects = [], imageEffectsRatio = 1 } = el;
|
|
6116
|
+
const url = el.clipUrl || el.url;
|
|
6117
|
+
const { translateX = 0, translateY = 0, zoom = 1 } = transform ?? {};
|
|
6118
|
+
const { scaleX = 1, scaleY = 1, filter } = style;
|
|
6119
|
+
if (translateX === 0 && translateY === 0 && zoom === 1 && scaleX === 1 && scaleY === 1 && !maskUrl && !filter && !imageEffects.length) return url;
|
|
6120
|
+
const img = await cachedFetchImageBitmap(url);
|
|
6121
|
+
const { originWidth = img.width, originHeight = img.height, imageWidth = originWidth, imageHeight = originHeight } = transform;
|
|
6122
|
+
const { width = originWidth, height = originHeight } = style;
|
|
6123
|
+
const dpr = window.devicePixelRatio || 1;
|
|
6124
|
+
const [canvas, ctx] = createCanvas(width, height, dpr);
|
|
6125
|
+
if (filter) ctx.filter = filter;
|
|
6126
|
+
ctx.scale(scaleX, scaleY);
|
|
6127
|
+
ctx.translate(scaleX < 0 ? -width : 0, scaleY < 0 ? -height : 0);
|
|
6128
|
+
if (maskUrl) {
|
|
6129
|
+
const mask = await cachedFetchImageBitmap(maskUrl);
|
|
6130
|
+
ctx.drawImage(mask, 0, 0, cropping?.maskWidth ?? width, cropping?.maskHeight ?? height);
|
|
6131
|
+
ctx.globalCompositeOperation = "source-in";
|
|
6132
|
+
mask.close();
|
|
6133
|
+
}
|
|
6134
|
+
const dw = imageWidth * zoom;
|
|
6135
|
+
const dh = imageHeight * zoom;
|
|
6136
|
+
const dx = -(dw / 2 - imageWidth / 2) + translateX;
|
|
6137
|
+
const dy = -(dh / 2 - imageHeight / 2) + translateY;
|
|
6138
|
+
ctx.drawImage(img, 0, 0, img.width, img.height, dx, dy, dw, dh);
|
|
6139
|
+
img.close();
|
|
6140
|
+
ctx.globalCompositeOperation = "source-over";
|
|
6141
|
+
if (imageEffects.length > 0) {
|
|
6142
|
+
const scale = .9;
|
|
6143
|
+
const center = {
|
|
6144
|
+
x: (width - width * scale) / 2,
|
|
6145
|
+
y: (height - height * scale) / 2
|
|
6146
|
+
};
|
|
6147
|
+
const canvasBitmap = await createImageBitmap(canvas);
|
|
6148
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
6149
|
+
ctx.scale(scale, scale);
|
|
6150
|
+
for (let i = imageEffects.length - 1; i >= 0; i--) {
|
|
6151
|
+
const { filling, offset, stroke } = imageEffects[i];
|
|
6152
|
+
let effectCanvas = canvasBitmap;
|
|
6153
|
+
if (filling) {
|
|
6154
|
+
const [canvas1, ctx1] = createCanvas(width, height, dpr);
|
|
6155
|
+
ctx1.drawImage(effectCanvas, 0, 0, width, height);
|
|
6156
|
+
ctx1.globalCompositeOperation = "source-in";
|
|
6157
|
+
if (filling.color) {
|
|
6158
|
+
const [canvas2, ctx2] = createCanvas(width, height, dpr);
|
|
6159
|
+
ctx2.fillStyle = filling.color;
|
|
6160
|
+
ctx2.fillRect(0, 0, width, height);
|
|
6161
|
+
ctx1.drawImage(canvas2, 0, 0, width, height);
|
|
6162
|
+
} else if (filling.imageContent?.image) {
|
|
6163
|
+
const img2 = await cachedFetchImageBitmap(filling.imageContent.image);
|
|
6164
|
+
ctx1.drawImage(img2, 0, 0, width, height);
|
|
6165
|
+
img2.close();
|
|
6166
|
+
}
|
|
6167
|
+
effectCanvas = canvas1;
|
|
6168
|
+
}
|
|
6169
|
+
stroke?.forEach(({ width, color }) => {
|
|
6170
|
+
effectCanvas = new ImageStroke().use((ctx, image, options) => {
|
|
6171
|
+
const [, ctx1] = createCanvas(image.width, image.height);
|
|
6172
|
+
ctx1.drawImage(image, 0, 0);
|
|
6173
|
+
const paths = getContours(ctx1);
|
|
6174
|
+
const x = options.thickness;
|
|
6175
|
+
const y = options.thickness;
|
|
6176
|
+
ctx.strokeStyle = options.color;
|
|
6177
|
+
ctx.lineWidth = options.thickness * 2;
|
|
6178
|
+
ctx.lineJoin = "round";
|
|
6179
|
+
paths.forEach((path) => {
|
|
6180
|
+
ctx.beginPath();
|
|
6181
|
+
ctx.moveTo(x + path[0].x, y + path[1].y);
|
|
6182
|
+
for (let i = 1; i < path.length; i++) ctx.lineTo(x + path[i].x, y + path[i].y);
|
|
6183
|
+
ctx.closePath();
|
|
6184
|
+
});
|
|
6185
|
+
ctx.stroke();
|
|
6186
|
+
}).make(effectCanvas, {
|
|
6187
|
+
color,
|
|
6188
|
+
thickness: width / 50 * imageEffectsRatio
|
|
6189
|
+
});
|
|
6190
|
+
});
|
|
6191
|
+
if (offset) {
|
|
6192
|
+
let { x, y } = offset;
|
|
6193
|
+
x = x / 50 * imageEffectsRatio * 200;
|
|
6194
|
+
y = y / 50 * imageEffectsRatio * 200;
|
|
6195
|
+
ctx.drawImage(effectCanvas, x + center.x, y + center.y, width, height);
|
|
6196
|
+
} else ctx.drawImage(effectCanvas, center.x, center.y, width, height);
|
|
6197
|
+
}
|
|
6198
|
+
canvasBitmap.close();
|
|
6199
|
+
}
|
|
6200
|
+
return await new Promise((resolve) => {
|
|
6201
|
+
canvas.toBlob((blob) => {
|
|
6202
|
+
try {
|
|
6203
|
+
resolve(URL.createObjectURL(blob));
|
|
6204
|
+
} catch (e) {
|
|
6205
|
+
console.error(`Failed to URL.createObjectURL, url: ${url}`, e);
|
|
6206
|
+
resolve(url);
|
|
6207
|
+
}
|
|
6208
|
+
});
|
|
6209
|
+
});
|
|
6210
|
+
}
|
|
6211
|
+
function createCanvas(width, height, ratio = 1) {
|
|
6212
|
+
const canvas = document.createElement("canvas");
|
|
6213
|
+
canvas.width = width * ratio;
|
|
6214
|
+
canvas.height = height * ratio;
|
|
6215
|
+
canvas.style.width = `${width}px`;
|
|
6216
|
+
canvas.style.height = `${height}px`;
|
|
6217
|
+
const ctx = canvas.getContext("2d");
|
|
6218
|
+
ctx.scale(ratio, ratio);
|
|
6219
|
+
return [canvas, ctx];
|
|
6220
|
+
}
|
|
6221
|
+
var ImageStroke = class {
|
|
6222
|
+
canvas = document.createElement("canvas");
|
|
6223
|
+
method;
|
|
6224
|
+
use(method) {
|
|
6225
|
+
this.method = method;
|
|
6226
|
+
return this;
|
|
6227
|
+
}
|
|
6228
|
+
make(image, options) {
|
|
6229
|
+
const { canvas } = this;
|
|
6230
|
+
const ctx = this.canvas.getContext("2d");
|
|
6231
|
+
const strokeSize = options.thickness * 2;
|
|
6232
|
+
const [resultWidth, resultHeight] = [image.width, image.height].map((val) => val + strokeSize);
|
|
6233
|
+
if (resultWidth !== canvas.width || resultHeight !== canvas.height) {
|
|
6234
|
+
canvas.width = resultWidth;
|
|
6235
|
+
canvas.height = resultHeight;
|
|
6236
|
+
}
|
|
6237
|
+
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
|
6238
|
+
this.method(ctx, image, options);
|
|
6239
|
+
ctx.drawImage(image, options.thickness, options.thickness);
|
|
6240
|
+
return canvas;
|
|
6241
|
+
}
|
|
6242
|
+
};
|
|
6243
|
+
function getContours(ctx) {
|
|
6244
|
+
const cx = 0;
|
|
6245
|
+
const cy = 0;
|
|
6246
|
+
const canvasWidth = ctx.canvas.width;
|
|
6247
|
+
const canvasHeight = ctx.canvas.height;
|
|
6248
|
+
const paths = [];
|
|
6249
|
+
let lastPos = 3;
|
|
6250
|
+
const alpha = 100;
|
|
6251
|
+
const trace = () => {
|
|
6252
|
+
const path = [];
|
|
6253
|
+
const data = new Uint32Array(ctx.getImageData(cx, cy, canvasWidth, canvasHeight).data.buffer);
|
|
6254
|
+
let x;
|
|
6255
|
+
let y;
|
|
6256
|
+
let startX;
|
|
6257
|
+
let startY;
|
|
6258
|
+
let startPos = -1;
|
|
6259
|
+
let step;
|
|
6260
|
+
let prevStep = 9;
|
|
6261
|
+
const steps = [
|
|
6262
|
+
9,
|
|
6263
|
+
0,
|
|
6264
|
+
3,
|
|
6265
|
+
3,
|
|
6266
|
+
2,
|
|
6267
|
+
0,
|
|
6268
|
+
9,
|
|
6269
|
+
3,
|
|
6270
|
+
1,
|
|
6271
|
+
9,
|
|
6272
|
+
1,
|
|
6273
|
+
1,
|
|
6274
|
+
2,
|
|
6275
|
+
0,
|
|
6276
|
+
2,
|
|
6277
|
+
9
|
|
6278
|
+
];
|
|
6279
|
+
let time = 50;
|
|
6280
|
+
function getState(x, y) {
|
|
6281
|
+
return x >= 0 && y >= 0 && x < canvasWidth && y < canvasHeight ? data[y * canvasWidth + x] >>> 24 > alpha : false;
|
|
6282
|
+
}
|
|
6283
|
+
function getNextStep(x, y) {
|
|
6284
|
+
let v = 0;
|
|
6285
|
+
if (getState(x - 1, y - 1)) v += 1;
|
|
6286
|
+
if (getState(x, y - 1)) v += 2;
|
|
6287
|
+
if (getState(x - 1, y)) v += 4;
|
|
6288
|
+
if (getState(x, y)) v += 8;
|
|
6289
|
+
if (time > 50) time += 10;
|
|
6290
|
+
else time += 10;
|
|
6291
|
+
if (v === 6) return prevStep === 0 ? 2 : 3;
|
|
6292
|
+
else if (v === 9) return prevStep === 3 ? 0 : 1;
|
|
6293
|
+
else return steps[v];
|
|
6294
|
+
}
|
|
6295
|
+
for (let i = lastPos; i < data.length; i++) if (data[i] >>> 24 > alpha) {
|
|
6296
|
+
startPos = lastPos = i;
|
|
6297
|
+
break;
|
|
6298
|
+
}
|
|
6299
|
+
if (startPos >= 0) {
|
|
6300
|
+
x = startX = startPos % canvasWidth;
|
|
6301
|
+
y = startY = Math.floor(startPos / canvasWidth);
|
|
6302
|
+
do {
|
|
6303
|
+
step = getNextStep(x, y);
|
|
6304
|
+
if (step === 0) y--;
|
|
6305
|
+
else if (step === 1) y++;
|
|
6306
|
+
else if (step === 2) x--;
|
|
6307
|
+
else if (step === 3) x++;
|
|
6308
|
+
if (step !== prevStep) {
|
|
6309
|
+
path.push({
|
|
6310
|
+
x: x + cx,
|
|
6311
|
+
y: y + cy
|
|
6312
|
+
});
|
|
6313
|
+
prevStep = step;
|
|
6314
|
+
}
|
|
6315
|
+
} while (x !== startX || y !== startY);
|
|
6316
|
+
}
|
|
6317
|
+
paths.push(path);
|
|
6318
|
+
return path;
|
|
6319
|
+
};
|
|
6320
|
+
trace();
|
|
6321
|
+
return paths;
|
|
6322
|
+
}
|
|
6323
|
+
//#endregion
|
|
5719
6324
|
//#region src/convert/svg.ts
|
|
5720
6325
|
async function convertSvgElementToUrl(el) {
|
|
5721
6326
|
const { id, doc, url, style = {}, background = {} } = el;
|
|
@@ -5724,25 +6329,23 @@ async function convertSvgElementToUrl(el) {
|
|
|
5724
6329
|
const svg = new DOMParser().parseFromString(xml.replace(new RegExp(`#el-${id} `, "gi"), "").replace(/data-colors\s/, " ").replace(/[a-z-]+="([^\s<]*<\S*)"/gi, ""), "image/svg+xml").documentElement;
|
|
5725
6330
|
if (!(svg instanceof SVGElement)) throw new TypeError(`Failed to DOMParser, parse svg to DOM error: ${xml}`);
|
|
5726
6331
|
const images = svg.querySelectorAll("image");
|
|
5727
|
-
|
|
5728
|
-
const image = images[i];
|
|
6332
|
+
await Promise.all(Array.from(images).map(async (image) => {
|
|
5729
6333
|
const url = image.href.baseVal;
|
|
5730
|
-
if (!url.startsWith("http"))
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
}
|
|
6334
|
+
if (!url.startsWith("http")) return;
|
|
6335
|
+
const bitmap = await cachedFetchImageBitmap(url);
|
|
6336
|
+
const canvas = document.createElement("canvas");
|
|
6337
|
+
canvas.width = bitmap.width;
|
|
6338
|
+
canvas.height = bitmap.height;
|
|
6339
|
+
canvas.getContext("2d")?.drawImage(bitmap, 0, 0);
|
|
6340
|
+
bitmap.close();
|
|
6341
|
+
image.setAttribute("href", canvas.toDataURL("image/png"));
|
|
6342
|
+
}));
|
|
5740
6343
|
if (background.src) {
|
|
5741
6344
|
const fillId = `#${id}-fill-blip`;
|
|
5742
6345
|
const fillPattern = svg.querySelector(fillId);
|
|
5743
6346
|
const fillImage = fillPattern?.querySelector("image");
|
|
5744
6347
|
if (fillPattern && fillImage) try {
|
|
5745
|
-
const base64Url = await
|
|
6348
|
+
const base64Url = await cachedFetchImageBitmap(background.src).then((bitmap) => {
|
|
5746
6349
|
const canvas = document.createElement("canvas");
|
|
5747
6350
|
canvas.width = bitmap.width;
|
|
5748
6351
|
canvas.height = bitmap.height;
|
|
@@ -6142,217 +6745,6 @@ async function convertDoc(doc, options = {}) {
|
|
|
6142
6745
|
};
|
|
6143
6746
|
}
|
|
6144
6747
|
//#endregion
|
|
6145
|
-
//#region src/convert/image.ts
|
|
6146
|
-
async function convertImageElementToUrl(el) {
|
|
6147
|
-
const { cropping = {}, transform = {}, style = {}, maskUrl, imageEffects = [], imageEffectsRatio = 1 } = el;
|
|
6148
|
-
const url = el.clipUrl || el.url;
|
|
6149
|
-
const { translateX = 0, translateY = 0, zoom = 1 } = transform ?? {};
|
|
6150
|
-
const { scaleX = 1, scaleY = 1, filter } = style;
|
|
6151
|
-
if (translateX === 0 && translateY === 0 && zoom === 1 && scaleX === 1 && scaleY === 1 && !maskUrl && !filter && !imageEffects.length) return url;
|
|
6152
|
-
const img = await assets.fetchImageBitmap(url);
|
|
6153
|
-
const { originWidth = img.width, originHeight = img.height, imageWidth = originWidth, imageHeight = originHeight } = transform;
|
|
6154
|
-
const { width = originWidth, height = originHeight } = style;
|
|
6155
|
-
const dpr = window.devicePixelRatio || 1;
|
|
6156
|
-
const [canvas, ctx] = createCanvas(width, height, dpr);
|
|
6157
|
-
if (filter) ctx.filter = filter;
|
|
6158
|
-
ctx.scale(scaleX, scaleY);
|
|
6159
|
-
ctx.translate(scaleX < 0 ? -width : 0, scaleY < 0 ? -height : 0);
|
|
6160
|
-
if (maskUrl) {
|
|
6161
|
-
const mask = await assets.fetchImageBitmap(maskUrl);
|
|
6162
|
-
ctx.drawImage(mask, 0, 0, cropping?.maskWidth ?? width, cropping?.maskHeight ?? height);
|
|
6163
|
-
ctx.globalCompositeOperation = "source-in";
|
|
6164
|
-
mask.close();
|
|
6165
|
-
}
|
|
6166
|
-
const dw = imageWidth * zoom;
|
|
6167
|
-
const dh = imageHeight * zoom;
|
|
6168
|
-
const dx = -(dw / 2 - imageWidth / 2) + translateX;
|
|
6169
|
-
const dy = -(dh / 2 - imageHeight / 2) + translateY;
|
|
6170
|
-
ctx.drawImage(img, 0, 0, img.width, img.height, dx, dy, dw, dh);
|
|
6171
|
-
img.close();
|
|
6172
|
-
ctx.globalCompositeOperation = "source-over";
|
|
6173
|
-
if (imageEffects.length > 0) {
|
|
6174
|
-
const scale = .9;
|
|
6175
|
-
const center = {
|
|
6176
|
-
x: (width - width * scale) / 2,
|
|
6177
|
-
y: (height - height * scale) / 2
|
|
6178
|
-
};
|
|
6179
|
-
const canvasBitmap = await createImageBitmap(canvas);
|
|
6180
|
-
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
6181
|
-
ctx.scale(scale, scale);
|
|
6182
|
-
for (let i = imageEffects.length - 1; i >= 0; i--) {
|
|
6183
|
-
const { filling, offset, stroke } = imageEffects[i];
|
|
6184
|
-
let effectCanvas = canvasBitmap;
|
|
6185
|
-
if (filling) {
|
|
6186
|
-
const [canvas1, ctx1] = createCanvas(width, height, dpr);
|
|
6187
|
-
ctx1.drawImage(effectCanvas, 0, 0, width, height);
|
|
6188
|
-
ctx1.globalCompositeOperation = "source-in";
|
|
6189
|
-
if (filling.color) {
|
|
6190
|
-
const [canvas2, ctx2] = createCanvas(width, height, dpr);
|
|
6191
|
-
ctx2.fillStyle = filling.color;
|
|
6192
|
-
ctx2.fillRect(0, 0, width, height);
|
|
6193
|
-
ctx1.drawImage(canvas2, 0, 0, width, height);
|
|
6194
|
-
} else if (filling.imageContent?.image) {
|
|
6195
|
-
const img2 = await assets.fetchImageBitmap(filling.imageContent.image);
|
|
6196
|
-
ctx1.drawImage(img2, 0, 0, width, height);
|
|
6197
|
-
img2.close();
|
|
6198
|
-
}
|
|
6199
|
-
effectCanvas = canvas1;
|
|
6200
|
-
}
|
|
6201
|
-
stroke?.forEach(({ width, color }) => {
|
|
6202
|
-
effectCanvas = new ImageStroke().use((ctx, image, options) => {
|
|
6203
|
-
const [, ctx1] = createCanvas(image.width, image.height);
|
|
6204
|
-
ctx1.drawImage(image, 0, 0);
|
|
6205
|
-
const paths = getContours(ctx1);
|
|
6206
|
-
const x = options.thickness;
|
|
6207
|
-
const y = options.thickness;
|
|
6208
|
-
ctx.strokeStyle = options.color;
|
|
6209
|
-
ctx.lineWidth = options.thickness * 2;
|
|
6210
|
-
ctx.lineJoin = "round";
|
|
6211
|
-
paths.forEach((path) => {
|
|
6212
|
-
ctx.beginPath();
|
|
6213
|
-
ctx.moveTo(x + path[0].x, y + path[1].y);
|
|
6214
|
-
for (let i = 1; i < path.length; i++) ctx.lineTo(x + path[i].x, y + path[i].y);
|
|
6215
|
-
ctx.closePath();
|
|
6216
|
-
});
|
|
6217
|
-
ctx.stroke();
|
|
6218
|
-
}).make(effectCanvas, {
|
|
6219
|
-
color,
|
|
6220
|
-
thickness: width / 50 * imageEffectsRatio
|
|
6221
|
-
});
|
|
6222
|
-
});
|
|
6223
|
-
if (offset) {
|
|
6224
|
-
let { x, y } = offset;
|
|
6225
|
-
x = x / 50 * imageEffectsRatio * 200;
|
|
6226
|
-
y = y / 50 * imageEffectsRatio * 200;
|
|
6227
|
-
ctx.drawImage(effectCanvas, x + center.x, y + center.y, width, height);
|
|
6228
|
-
} else ctx.drawImage(effectCanvas, center.x, center.y, width, height);
|
|
6229
|
-
}
|
|
6230
|
-
canvasBitmap.close();
|
|
6231
|
-
}
|
|
6232
|
-
return await new Promise((resolve) => {
|
|
6233
|
-
canvas.toBlob((blob) => {
|
|
6234
|
-
try {
|
|
6235
|
-
resolve(URL.createObjectURL(blob));
|
|
6236
|
-
} catch (e) {
|
|
6237
|
-
console.error(`Failed to URL.createObjectURL, url: ${url}`, e);
|
|
6238
|
-
resolve(url);
|
|
6239
|
-
}
|
|
6240
|
-
});
|
|
6241
|
-
});
|
|
6242
|
-
}
|
|
6243
|
-
function createCanvas(width, height, ratio = 1) {
|
|
6244
|
-
const canvas = document.createElement("canvas");
|
|
6245
|
-
canvas.width = width * ratio;
|
|
6246
|
-
canvas.height = height * ratio;
|
|
6247
|
-
canvas.style.width = `${width}px`;
|
|
6248
|
-
canvas.style.height = `${height}px`;
|
|
6249
|
-
const ctx = canvas.getContext("2d");
|
|
6250
|
-
ctx.scale(ratio, ratio);
|
|
6251
|
-
return [canvas, ctx];
|
|
6252
|
-
}
|
|
6253
|
-
var ImageStroke = class {
|
|
6254
|
-
canvas = document.createElement("canvas");
|
|
6255
|
-
method;
|
|
6256
|
-
use(method) {
|
|
6257
|
-
this.method = method;
|
|
6258
|
-
return this;
|
|
6259
|
-
}
|
|
6260
|
-
make(image, options) {
|
|
6261
|
-
const { canvas } = this;
|
|
6262
|
-
const ctx = this.canvas.getContext("2d");
|
|
6263
|
-
const strokeSize = options.thickness * 2;
|
|
6264
|
-
const [resultWidth, resultHeight] = [image.width, image.height].map((val) => val + strokeSize);
|
|
6265
|
-
if (resultWidth !== canvas.width || resultHeight !== canvas.height) {
|
|
6266
|
-
canvas.width = resultWidth;
|
|
6267
|
-
canvas.height = resultHeight;
|
|
6268
|
-
}
|
|
6269
|
-
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
|
6270
|
-
this.method(ctx, image, options);
|
|
6271
|
-
ctx.drawImage(image, options.thickness, options.thickness);
|
|
6272
|
-
return canvas;
|
|
6273
|
-
}
|
|
6274
|
-
};
|
|
6275
|
-
function getContours(ctx) {
|
|
6276
|
-
const cx = 0;
|
|
6277
|
-
const cy = 0;
|
|
6278
|
-
const canvasWidth = ctx.canvas.width;
|
|
6279
|
-
const canvasHeight = ctx.canvas.height;
|
|
6280
|
-
const paths = [];
|
|
6281
|
-
let lastPos = 3;
|
|
6282
|
-
const alpha = 100;
|
|
6283
|
-
const trace = () => {
|
|
6284
|
-
const path = [];
|
|
6285
|
-
const data = new Uint32Array(ctx.getImageData(cx, cy, canvasWidth, canvasHeight).data.buffer);
|
|
6286
|
-
let x;
|
|
6287
|
-
let y;
|
|
6288
|
-
let startX;
|
|
6289
|
-
let startY;
|
|
6290
|
-
let startPos = -1;
|
|
6291
|
-
let step;
|
|
6292
|
-
let prevStep = 9;
|
|
6293
|
-
const steps = [
|
|
6294
|
-
9,
|
|
6295
|
-
0,
|
|
6296
|
-
3,
|
|
6297
|
-
3,
|
|
6298
|
-
2,
|
|
6299
|
-
0,
|
|
6300
|
-
9,
|
|
6301
|
-
3,
|
|
6302
|
-
1,
|
|
6303
|
-
9,
|
|
6304
|
-
1,
|
|
6305
|
-
1,
|
|
6306
|
-
2,
|
|
6307
|
-
0,
|
|
6308
|
-
2,
|
|
6309
|
-
9
|
|
6310
|
-
];
|
|
6311
|
-
let time = 50;
|
|
6312
|
-
function getState(x, y) {
|
|
6313
|
-
return x >= 0 && y >= 0 && x < canvasWidth && y < canvasHeight ? data[y * canvasWidth + x] >>> 24 > alpha : false;
|
|
6314
|
-
}
|
|
6315
|
-
function getNextStep(x, y) {
|
|
6316
|
-
let v = 0;
|
|
6317
|
-
if (getState(x - 1, y - 1)) v += 1;
|
|
6318
|
-
if (getState(x, y - 1)) v += 2;
|
|
6319
|
-
if (getState(x - 1, y)) v += 4;
|
|
6320
|
-
if (getState(x, y)) v += 8;
|
|
6321
|
-
if (time > 50) time += 10;
|
|
6322
|
-
else time += 10;
|
|
6323
|
-
if (v === 6) return prevStep === 0 ? 2 : 3;
|
|
6324
|
-
else if (v === 9) return prevStep === 3 ? 0 : 1;
|
|
6325
|
-
else return steps[v];
|
|
6326
|
-
}
|
|
6327
|
-
for (let i = lastPos; i < data.length; i++) if (data[i] >>> 24 > alpha) {
|
|
6328
|
-
startPos = lastPos = i;
|
|
6329
|
-
break;
|
|
6330
|
-
}
|
|
6331
|
-
if (startPos >= 0) {
|
|
6332
|
-
x = startX = startPos % canvasWidth;
|
|
6333
|
-
y = startY = Math.floor(startPos / canvasWidth);
|
|
6334
|
-
do {
|
|
6335
|
-
step = getNextStep(x, y);
|
|
6336
|
-
if (step === 0) y--;
|
|
6337
|
-
else if (step === 1) y++;
|
|
6338
|
-
else if (step === 2) x--;
|
|
6339
|
-
else if (step === 3) x++;
|
|
6340
|
-
if (step !== prevStep) {
|
|
6341
|
-
path.push({
|
|
6342
|
-
x: x + cx,
|
|
6343
|
-
y: y + cy
|
|
6344
|
-
});
|
|
6345
|
-
prevStep = step;
|
|
6346
|
-
}
|
|
6347
|
-
} while (x !== startX || y !== startY);
|
|
6348
|
-
}
|
|
6349
|
-
paths.push(path);
|
|
6350
|
-
return path;
|
|
6351
|
-
};
|
|
6352
|
-
trace();
|
|
6353
|
-
return paths;
|
|
6354
|
-
}
|
|
6355
|
-
//#endregion
|
|
6356
6748
|
//#region src/loaders/bidTid.ts
|
|
6357
6749
|
function bidTidLoader(editor, api) {
|
|
6358
6750
|
const { config, http } = editor;
|
|
@@ -6572,4 +6964,4 @@ var options = {
|
|
|
6572
6964
|
//#region src/index.ts
|
|
6573
6965
|
var src_default = plugin;
|
|
6574
6966
|
//#endregion
|
|
6575
|
-
export { bidTidLoader, bigeLoader, clipboardLoader, convertAnimation, convertBackground, convertDoc, convertElement, convertImageElementToUrl, convertLayout, convertSvgElementToUrl, convertTextContent, convertTextEffects, convertTextStyle, croppingToCropRect, src_default as default, getStyle, getTextContents, options, parseAnimations, plugin, transformToCropRect, useFonts };
|
|
6967
|
+
export { bidTidLoader, bigeLoader, cachedFetchImageBitmap, clipboardLoader, convertAnimation, convertBackground, convertDoc, convertElement, convertImageElementToUrl, convertLayout, convertSvgElementToUrl, convertTextContent, convertTextEffects, convertTextStyle, croppingToCropRect, src_default as default, getStyle, getTextContents, options, parseAnimations, plugin, transformToCropRect, useFonts };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mce/bigesj",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.19.0",
|
|
5
5
|
"description": "Plugin for mce",
|
|
6
6
|
"author": "wxm",
|
|
7
7
|
"license": "MIT",
|
|
@@ -46,10 +46,10 @@
|
|
|
46
46
|
],
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"fflate": "^0.8.3",
|
|
49
|
-
"modern-openxml": "^1.
|
|
49
|
+
"modern-openxml": "^1.12.3"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"mce": "0.
|
|
52
|
+
"mce": "0.19.0"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|
|
55
55
|
"mce": "^0"
|
|
File without changes
|