@tsparticles/plugin-polygon-mask 3.0.0-alpha.1 → 3.0.0-beta.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.
Files changed (52) hide show
  1. package/README.md +15 -11
  2. package/browser/Options/Classes/PolygonMask.js +6 -12
  3. package/browser/Options/Classes/PolygonMaskDraw.js +2 -19
  4. package/browser/Options/Classes/PolygonMaskDrawStroke.js +3 -4
  5. package/browser/PolygonMaskInstance.js +298 -306
  6. package/browser/index.js +13 -14
  7. package/browser/package.json +1 -0
  8. package/browser/pathseg.js +1 -1
  9. package/browser/utils.js +3 -5
  10. package/cjs/Options/Classes/PolygonMask.js +9 -15
  11. package/cjs/Options/Classes/PolygonMaskDraw.js +3 -20
  12. package/cjs/Options/Classes/PolygonMaskDrawStroke.js +2 -3
  13. package/cjs/PolygonMaskInstance.js +311 -334
  14. package/cjs/index.js +15 -27
  15. package/cjs/package.json +1 -0
  16. package/cjs/pathseg.js +1 -1
  17. package/cjs/utils.js +4 -6
  18. package/esm/Options/Classes/PolygonMask.js +6 -12
  19. package/esm/Options/Classes/PolygonMaskDraw.js +2 -19
  20. package/esm/Options/Classes/PolygonMaskDrawStroke.js +3 -4
  21. package/esm/PolygonMaskInstance.js +298 -306
  22. package/esm/index.js +13 -14
  23. package/esm/package.json +1 -0
  24. package/esm/pathseg.js +1 -1
  25. package/esm/utils.js +3 -5
  26. package/package.json +21 -6
  27. package/report.html +4 -4
  28. package/tsparticles.plugin.polygon-mask.js +336 -362
  29. package/tsparticles.plugin.polygon-mask.min.js +1 -1
  30. package/tsparticles.plugin.polygon-mask.min.js.LICENSE.txt +1 -8
  31. package/types/Interfaces/ISvgPath.d.ts +1 -1
  32. package/types/Options/Classes/PolygonMask.d.ts +7 -10
  33. package/types/Options/Classes/PolygonMaskDraw.d.ts +3 -8
  34. package/types/Options/Classes/PolygonMaskDrawStroke.d.ts +2 -3
  35. package/types/Options/Classes/PolygonMaskInline.d.ts +3 -3
  36. package/types/Options/Classes/PolygonMaskLocalSvg.d.ts +1 -1
  37. package/types/Options/Classes/PolygonMaskMove.d.ts +2 -2
  38. package/types/Options/Interfaces/IPolygonMask.d.ts +5 -5
  39. package/types/Options/Interfaces/IPolygonMaskDraw.d.ts +1 -4
  40. package/types/Options/Interfaces/IPolygonMaskInline.d.ts +1 -1
  41. package/types/Options/Interfaces/IPolygonMaskMove.d.ts +1 -1
  42. package/types/PolygonMaskInstance.d.ts +15 -17
  43. package/types/index.d.ts +5 -5
  44. package/types/types.d.ts +3 -3
  45. package/types/utils.d.ts +3 -4
  46. package/umd/Options/Classes/PolygonMask.js +10 -16
  47. package/umd/Options/Classes/PolygonMaskDraw.js +4 -21
  48. package/umd/Options/Classes/PolygonMaskDrawStroke.js +2 -3
  49. package/umd/PolygonMaskInstance.js +300 -308
  50. package/umd/index.js +16 -17
  51. package/umd/pathseg.js +1 -1
  52. package/umd/utils.js +3 -5
@@ -1,8 +1,291 @@
1
- import { calcClosestPtOnSegment, drawPolygonMask, drawPolygonMaskPath, parsePaths, segmentBounce } from "./utils";
2
- import { deepExtend, getDistance, getDistances, getRandom, itemFromArray } from "@tsparticles/engine";
3
- const noPolygonDataLoaded = "No polygon data loaded.", noPolygonFound = "No polygon found, you need to specify SVG url in config.";
1
+ import { deepExtend, errorPrefix, getDistance, getDistances, getRandom, isArray, isString, itemFromArray, } from "@tsparticles/engine";
2
+ import { calcClosestPtOnSegment, drawPolygonMask, drawPolygonMaskPath, parsePaths, segmentBounce } from "./utils.js";
3
+ const noPolygonDataLoaded = `${errorPrefix} No polygon data loaded.`, noPolygonFound = `${errorPrefix} No polygon found, you need to specify SVG url in config.`;
4
4
  export class PolygonMaskInstance {
5
5
  constructor(container, engine) {
6
+ this._checkInsidePolygon = (position) => {
7
+ const container = this._container, options = container.actualOptions.polygon;
8
+ if (!options?.enable || options.type === "none" || options.type === "inline") {
9
+ return true;
10
+ }
11
+ if (!this.raw) {
12
+ throw new Error(noPolygonFound);
13
+ }
14
+ const canvasSize = container.canvas.size, x = position?.x ?? getRandom() * canvasSize.width, y = position?.y ?? getRandom() * canvasSize.height;
15
+ let inside = false;
16
+ for (let i = 0, j = this.raw.length - 1; i < this.raw.length; j = i++) {
17
+ const pi = this.raw[i], pj = this.raw[j], intersect = pi.y > y !== pj.y > y && x < ((pj.x - pi.x) * (y - pi.y)) / (pj.y - pi.y) + pi.x;
18
+ if (intersect) {
19
+ inside = !inside;
20
+ }
21
+ }
22
+ return options.type === "inside"
23
+ ? inside
24
+ : options.type === "outside"
25
+ ? !inside
26
+ : false;
27
+ };
28
+ this._createPath2D = () => {
29
+ const container = this._container, options = container.actualOptions.polygon;
30
+ if (!options || !this.paths?.length) {
31
+ return;
32
+ }
33
+ for (const path of this.paths) {
34
+ const pathData = path.element?.getAttribute("d");
35
+ if (pathData) {
36
+ const path2d = new Path2D(pathData), matrix = document.createElementNS("http://www.w3.org/2000/svg", "svg").createSVGMatrix(), finalPath = new Path2D(), transform = matrix.scale(this._scale);
37
+ if (finalPath.addPath) {
38
+ finalPath.addPath(path2d, transform);
39
+ path.path2d = finalPath;
40
+ }
41
+ else {
42
+ delete path.path2d;
43
+ }
44
+ }
45
+ else {
46
+ delete path.path2d;
47
+ }
48
+ if (path.path2d || !this.raw) {
49
+ continue;
50
+ }
51
+ path.path2d = new Path2D();
52
+ path.path2d.moveTo(this.raw[0].x, this.raw[0].y);
53
+ this.raw.forEach((pos, i) => {
54
+ if (i > 0) {
55
+ path.path2d?.lineTo(pos.x, pos.y);
56
+ }
57
+ });
58
+ path.path2d.closePath();
59
+ }
60
+ };
61
+ this._downloadSvgPath = async (svgUrl, force) => {
62
+ const options = this._container.actualOptions.polygon;
63
+ if (!options) {
64
+ return;
65
+ }
66
+ const url = svgUrl || options.url, forceDownload = force ?? false;
67
+ if (!url || (this.paths !== undefined && !forceDownload)) {
68
+ return this.raw;
69
+ }
70
+ const req = await fetch(url);
71
+ if (!req.ok) {
72
+ throw new Error(`${errorPrefix} occurred during polygon mask download`);
73
+ }
74
+ return this._parseSvgPath(await req.text(), force);
75
+ };
76
+ this._drawPoints = () => {
77
+ if (!this.raw) {
78
+ return;
79
+ }
80
+ for (const item of this.raw) {
81
+ this._container.particles.addParticle({
82
+ x: item.x,
83
+ y: item.y,
84
+ });
85
+ }
86
+ };
87
+ this._getEquidistantPointByIndex = (index) => {
88
+ const container = this._container, options = container.actualOptions, polygonMaskOptions = options.polygon;
89
+ if (!polygonMaskOptions) {
90
+ return;
91
+ }
92
+ if (!this.raw || !this.raw.length || !this.paths?.length) {
93
+ throw new Error(noPolygonDataLoaded);
94
+ }
95
+ let offset = 0, point;
96
+ const totalLength = this.paths.reduce((tot, path) => tot + path.length, 0), distance = totalLength / options.particles.number.value;
97
+ for (const path of this.paths) {
98
+ const pathDistance = distance * index - offset;
99
+ if (pathDistance <= path.length) {
100
+ point = path.element.getPointAtLength(pathDistance);
101
+ break;
102
+ }
103
+ else {
104
+ offset += path.length;
105
+ }
106
+ }
107
+ const scale = this._scale;
108
+ return {
109
+ x: (point?.x ?? 0) * scale + (this.offset?.x ?? 0),
110
+ y: (point?.y ?? 0) * scale + (this.offset?.y ?? 0),
111
+ };
112
+ };
113
+ this._getPointByIndex = (index) => {
114
+ if (!this.raw || !this.raw.length) {
115
+ throw new Error(noPolygonDataLoaded);
116
+ }
117
+ const coords = this.raw[index % this.raw.length];
118
+ return {
119
+ x: coords.x,
120
+ y: coords.y,
121
+ };
122
+ };
123
+ this._getRandomPoint = () => {
124
+ if (!this.raw || !this.raw.length) {
125
+ throw new Error(noPolygonDataLoaded);
126
+ }
127
+ const coords = itemFromArray(this.raw);
128
+ return {
129
+ x: coords.x,
130
+ y: coords.y,
131
+ };
132
+ };
133
+ this._getRandomPointByLength = () => {
134
+ const container = this._container, options = container.actualOptions.polygon;
135
+ if (!options) {
136
+ return;
137
+ }
138
+ if (!this.raw || !this.raw.length || !this.paths?.length) {
139
+ throw new Error(noPolygonDataLoaded);
140
+ }
141
+ const path = itemFromArray(this.paths), distance = Math.floor(getRandom() * path.length) + 1, point = path.element.getPointAtLength(distance), scale = this._scale;
142
+ return {
143
+ x: point.x * scale + (this.offset?.x || 0),
144
+ y: point.y * scale + (this.offset?.y || 0),
145
+ };
146
+ };
147
+ this._initRawData = async (force) => {
148
+ const options = this._container.actualOptions.polygon;
149
+ if (!options) {
150
+ return;
151
+ }
152
+ if (options.url) {
153
+ this.raw = await this._downloadSvgPath(options.url, force);
154
+ }
155
+ else if (options.data) {
156
+ const data = options.data;
157
+ let svg;
158
+ if (isString(data)) {
159
+ svg = data;
160
+ }
161
+ else {
162
+ const getPath = (p) => `<path d="${p}" />`, path = isArray(data.path) ? data.path.map(getPath).join("") : getPath(data.path);
163
+ const namespaces = 'xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"';
164
+ svg = `<svg ${namespaces} width="${data.size.width}" height="${data.size.height}">${path}</svg>`;
165
+ }
166
+ this.raw = this._parseSvgPath(svg, force);
167
+ }
168
+ this._createPath2D();
169
+ this._engine.dispatchEvent("polygonMaskLoaded", {
170
+ container: this._container,
171
+ });
172
+ };
173
+ this._parseSvgPath = (xml, force) => {
174
+ const forceDownload = force ?? false;
175
+ if (this.paths !== undefined && !forceDownload) {
176
+ return this.raw;
177
+ }
178
+ const container = this._container, options = container.actualOptions.polygon;
179
+ if (!options) {
180
+ return;
181
+ }
182
+ const parser = new DOMParser(), doc = parser.parseFromString(xml, "image/svg+xml"), svg = doc.getElementsByTagName("svg")[0];
183
+ let svgPaths = svg.getElementsByTagName("path");
184
+ if (!svgPaths.length) {
185
+ svgPaths = doc.getElementsByTagName("path");
186
+ }
187
+ this.paths = [];
188
+ for (let i = 0; i < svgPaths.length; i++) {
189
+ const path = svgPaths.item(i);
190
+ if (path) {
191
+ this.paths.push({
192
+ element: path,
193
+ length: path.getTotalLength(),
194
+ });
195
+ }
196
+ }
197
+ const scale = this._scale;
198
+ this.dimension.width = parseFloat(svg.getAttribute("width") ?? "0") * scale;
199
+ this.dimension.height = parseFloat(svg.getAttribute("height") ?? "0") * scale;
200
+ const position = options.position ?? {
201
+ x: 50,
202
+ y: 50,
203
+ }, canvasSize = container.canvas.size;
204
+ this.offset = {
205
+ x: (canvasSize.width * position.x) / 100 - this.dimension.width / 2,
206
+ y: (canvasSize.height * position.y) / 100 - this.dimension.height / 2,
207
+ };
208
+ return parsePaths(this.paths, scale, this.offset);
209
+ };
210
+ this._polygonBounce = (particle, _delta, direction) => {
211
+ const options = this._container.actualOptions.polygon;
212
+ if (!this.raw || !options?.enable || direction !== "top") {
213
+ return false;
214
+ }
215
+ if (options.type === "inside" || options.type === "outside") {
216
+ let closest, dx, dy;
217
+ const pos = particle.getPosition(), radius = particle.getRadius();
218
+ for (let i = 0, j = this.raw.length - 1; i < this.raw.length; j = i++) {
219
+ const pi = this.raw[i], pj = this.raw[j];
220
+ closest = calcClosestPtOnSegment(pi, pj, pos);
221
+ const dist = getDistances(pos, closest);
222
+ [dx, dy] = [dist.dx, dist.dy];
223
+ if (dist.distance < radius) {
224
+ segmentBounce(pi, pj, particle.velocity);
225
+ return true;
226
+ }
227
+ }
228
+ if (closest && dx !== undefined && dy !== undefined && !this._checkInsidePolygon(pos)) {
229
+ const factor = { x: 1, y: 1 }, diameter = radius * 2;
230
+ if (pos.x >= closest.x) {
231
+ factor.x = -1;
232
+ }
233
+ if (pos.y >= closest.y) {
234
+ factor.y = -1;
235
+ }
236
+ particle.position.x = closest.x + diameter * factor.x;
237
+ particle.position.y = closest.y + diameter * factor.y;
238
+ particle.velocity.mult(-1);
239
+ return true;
240
+ }
241
+ }
242
+ else if (options.type === "inline" && particle.initialPosition) {
243
+ const dist = getDistance(particle.initialPosition, particle.getPosition()), { velocity } = particle;
244
+ if (dist > this._moveRadius) {
245
+ velocity.x = velocity.y / 2 - velocity.x;
246
+ velocity.y = velocity.x / 2 - velocity.y;
247
+ return true;
248
+ }
249
+ }
250
+ return false;
251
+ };
252
+ this._randomPoint = () => {
253
+ const container = this._container, options = container.actualOptions.polygon;
254
+ if (!options) {
255
+ return;
256
+ }
257
+ let position;
258
+ if (options.type === "inline") {
259
+ switch (options.inline.arrangement) {
260
+ case "random-point":
261
+ position = this._getRandomPoint();
262
+ break;
263
+ case "random-length":
264
+ position = this._getRandomPointByLength();
265
+ break;
266
+ case "equidistant":
267
+ position = this._getEquidistantPointByIndex(container.particles.count);
268
+ break;
269
+ case "one-per-point":
270
+ case "per-point":
271
+ default:
272
+ position = this._getPointByIndex(container.particles.count);
273
+ }
274
+ }
275
+ else {
276
+ const canvasSize = container.canvas.size;
277
+ position = {
278
+ x: getRandom() * canvasSize.width,
279
+ y: getRandom() * canvasSize.height,
280
+ };
281
+ }
282
+ if (this._checkInsidePolygon(position)) {
283
+ return position;
284
+ }
285
+ else {
286
+ return this._randomPoint();
287
+ }
288
+ };
6
289
  this._container = container;
7
290
  this._engine = engine;
8
291
  this.dimension = {
@@ -14,18 +297,17 @@ export class PolygonMaskInstance {
14
297
  }
15
298
  clickPositionValid(position) {
16
299
  const options = this._container.actualOptions.polygon;
17
- return (!!(options === null || options === void 0 ? void 0 : options.enable) &&
300
+ return (!!options?.enable &&
18
301
  options.type !== "none" &&
19
302
  options.type !== "inline" &&
20
- this.checkInsidePolygon(position));
303
+ this._checkInsidePolygon(position));
21
304
  }
22
305
  draw(context) {
23
- var _a;
24
- if (!((_a = this.paths) === null || _a === void 0 ? void 0 : _a.length)) {
306
+ if (!this.paths?.length) {
25
307
  return;
26
308
  }
27
309
  const options = this._container.actualOptions.polygon;
28
- if (!(options === null || options === void 0 ? void 0 : options.enable)) {
310
+ if (!options?.enable) {
29
311
  return;
30
312
  }
31
313
  const polygonDraw = options.draw;
@@ -54,41 +336,40 @@ export class PolygonMaskInstance {
54
336
  this._moveRadius = polygonMaskOptions.move.radius * pxRatio;
55
337
  this._scale = polygonMaskOptions.scale * pxRatio;
56
338
  if (polygonMaskOptions.enable) {
57
- await this.initRawData();
339
+ await this._initRawData();
58
340
  }
59
341
  }
60
342
  particleBounce(particle, delta, direction) {
61
- return this.polygonBounce(particle, delta, direction);
343
+ return this._polygonBounce(particle, delta, direction);
62
344
  }
63
345
  particlePosition(position) {
64
- var _a, _b;
65
346
  const options = this._container.actualOptions.polygon;
66
- if (!((options === null || options === void 0 ? void 0 : options.enable) && ((_b = (_a = this.raw) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) > 0)) {
347
+ if (!(options?.enable && (this.raw?.length ?? 0) > 0)) {
67
348
  return;
68
349
  }
69
- return deepExtend({}, position ? position : this.randomPoint());
350
+ return deepExtend({}, position ? position : this._randomPoint());
70
351
  }
71
352
  particlesInitialization() {
72
353
  const options = this._container.actualOptions.polygon;
73
- if ((options === null || options === void 0 ? void 0 : options.enable) &&
354
+ if (options?.enable &&
74
355
  options.type === "inline" &&
75
356
  (options.inline.arrangement === "one-per-point" ||
76
357
  options.inline.arrangement === "per-point")) {
77
- this.drawPoints();
358
+ this._drawPoints();
78
359
  return true;
79
360
  }
80
361
  return false;
81
362
  }
82
363
  resize() {
83
364
  const container = this._container, options = container.actualOptions.polygon;
84
- if (!((options === null || options === void 0 ? void 0 : options.enable) && options.type !== "none")) {
365
+ if (!(options?.enable && options.type !== "none")) {
85
366
  return;
86
367
  }
87
368
  if (this.redrawTimeout) {
88
369
  clearTimeout(this.redrawTimeout);
89
370
  }
90
371
  this.redrawTimeout = window.setTimeout(async () => {
91
- await this.initRawData(true);
372
+ await this._initRawData(true);
92
373
  await container.particles.redraw();
93
374
  }, 250);
94
375
  }
@@ -96,293 +377,4 @@ export class PolygonMaskInstance {
96
377
  delete this.raw;
97
378
  delete this.paths;
98
379
  }
99
- checkInsidePolygon(position) {
100
- var _a, _b;
101
- const container = this._container, options = container.actualOptions.polygon;
102
- if (!(options === null || options === void 0 ? void 0 : options.enable) || options.type === "none" || options.type === "inline") {
103
- return true;
104
- }
105
- if (!this.raw) {
106
- throw new Error(noPolygonFound);
107
- }
108
- const canvasSize = container.canvas.size, x = (_a = position === null || position === void 0 ? void 0 : position.x) !== null && _a !== void 0 ? _a : getRandom() * canvasSize.width, y = (_b = position === null || position === void 0 ? void 0 : position.y) !== null && _b !== void 0 ? _b : getRandom() * canvasSize.height;
109
- let inside = false;
110
- for (let i = 0, j = this.raw.length - 1; i < this.raw.length; j = i++) {
111
- const pi = this.raw[i], pj = this.raw[j], intersect = pi.y > y !== pj.y > y && x < ((pj.x - pi.x) * (y - pi.y)) / (pj.y - pi.y) + pi.x;
112
- if (intersect) {
113
- inside = !inside;
114
- }
115
- }
116
- return options.type === "inside"
117
- ? inside
118
- : options.type === "outside"
119
- ? !inside
120
- : false;
121
- }
122
- createPath2D() {
123
- var _a, _b;
124
- const container = this._container, options = container.actualOptions.polygon;
125
- if (!options || !((_a = this.paths) === null || _a === void 0 ? void 0 : _a.length)) {
126
- return;
127
- }
128
- for (const path of this.paths) {
129
- const pathData = (_b = path.element) === null || _b === void 0 ? void 0 : _b.getAttribute("d");
130
- if (pathData) {
131
- const path2d = new Path2D(pathData), matrix = document.createElementNS("http://www.w3.org/2000/svg", "svg").createSVGMatrix(), finalPath = new Path2D(), transform = matrix.scale(this._scale);
132
- if (finalPath.addPath) {
133
- finalPath.addPath(path2d, transform);
134
- path.path2d = finalPath;
135
- }
136
- else {
137
- delete path.path2d;
138
- }
139
- }
140
- else {
141
- delete path.path2d;
142
- }
143
- if (path.path2d || !this.raw) {
144
- continue;
145
- }
146
- path.path2d = new Path2D();
147
- path.path2d.moveTo(this.raw[0].x, this.raw[0].y);
148
- this.raw.forEach((pos, i) => {
149
- var _a;
150
- if (i > 0) {
151
- (_a = path.path2d) === null || _a === void 0 ? void 0 : _a.lineTo(pos.x, pos.y);
152
- }
153
- });
154
- path.path2d.closePath();
155
- }
156
- }
157
- async downloadSvgPath(svgUrl, force) {
158
- const options = this._container.actualOptions.polygon;
159
- if (!options) {
160
- return;
161
- }
162
- const url = svgUrl || options.url, forceDownload = force !== null && force !== void 0 ? force : false;
163
- if (!url || (this.paths !== undefined && !forceDownload)) {
164
- return this.raw;
165
- }
166
- const req = await fetch(url);
167
- if (!req.ok) {
168
- throw new Error("tsParticles Error - Error occurred during polygon mask download");
169
- }
170
- return this.parseSvgPath(await req.text(), force);
171
- }
172
- drawPoints() {
173
- if (!this.raw) {
174
- return;
175
- }
176
- for (const item of this.raw) {
177
- this._container.particles.addParticle({
178
- x: item.x,
179
- y: item.y,
180
- });
181
- }
182
- }
183
- getEquidistantPointByIndex(index) {
184
- var _a, _b, _c, _d, _e, _f, _g;
185
- const container = this._container, options = container.actualOptions, polygonMaskOptions = options.polygon;
186
- if (!polygonMaskOptions) {
187
- return;
188
- }
189
- if (!this.raw || !this.raw.length || !((_a = this.paths) === null || _a === void 0 ? void 0 : _a.length))
190
- throw new Error(noPolygonDataLoaded);
191
- let offset = 0, point;
192
- const totalLength = this.paths.reduce((tot, path) => tot + path.length, 0), distance = totalLength / options.particles.number.value;
193
- for (const path of this.paths) {
194
- const pathDistance = distance * index - offset;
195
- if (pathDistance <= path.length) {
196
- point = path.element.getPointAtLength(pathDistance);
197
- break;
198
- }
199
- else {
200
- offset += path.length;
201
- }
202
- }
203
- const scale = this._scale;
204
- return {
205
- x: ((_b = point === null || point === void 0 ? void 0 : point.x) !== null && _b !== void 0 ? _b : 0) * scale + ((_d = (_c = this.offset) === null || _c === void 0 ? void 0 : _c.x) !== null && _d !== void 0 ? _d : 0),
206
- y: ((_e = point === null || point === void 0 ? void 0 : point.y) !== null && _e !== void 0 ? _e : 0) * scale + ((_g = (_f = this.offset) === null || _f === void 0 ? void 0 : _f.y) !== null && _g !== void 0 ? _g : 0),
207
- };
208
- }
209
- getPointByIndex(index) {
210
- if (!this.raw || !this.raw.length) {
211
- throw new Error(noPolygonDataLoaded);
212
- }
213
- const coords = this.raw[index % this.raw.length];
214
- return {
215
- x: coords.x,
216
- y: coords.y,
217
- };
218
- }
219
- getRandomPoint() {
220
- if (!this.raw || !this.raw.length) {
221
- throw new Error(noPolygonDataLoaded);
222
- }
223
- const coords = itemFromArray(this.raw);
224
- return {
225
- x: coords.x,
226
- y: coords.y,
227
- };
228
- }
229
- getRandomPointByLength() {
230
- var _a, _b, _c;
231
- const container = this._container, options = container.actualOptions.polygon;
232
- if (!options) {
233
- return;
234
- }
235
- if (!this.raw || !this.raw.length || !((_a = this.paths) === null || _a === void 0 ? void 0 : _a.length)) {
236
- throw new Error(noPolygonDataLoaded);
237
- }
238
- const path = itemFromArray(this.paths), distance = Math.floor(getRandom() * path.length) + 1, point = path.element.getPointAtLength(distance), scale = this._scale;
239
- return {
240
- x: point.x * scale + (((_b = this.offset) === null || _b === void 0 ? void 0 : _b.x) || 0),
241
- y: point.y * scale + (((_c = this.offset) === null || _c === void 0 ? void 0 : _c.y) || 0),
242
- };
243
- }
244
- async initRawData(force) {
245
- const options = this._container.actualOptions.polygon;
246
- if (!options) {
247
- return;
248
- }
249
- if (options.url) {
250
- this.raw = await this.downloadSvgPath(options.url, force);
251
- }
252
- else if (options.data) {
253
- const data = options.data;
254
- let svg;
255
- if (typeof data !== "string") {
256
- const path = data.path instanceof Array
257
- ? data.path.map((t) => `<path d="${t}" />`).join("")
258
- : `<path d="${data.path}" />`;
259
- const namespaces = 'xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"';
260
- svg = `<svg ${namespaces} width="${data.size.width}" height="${data.size.height}">${path}</svg>`;
261
- }
262
- else {
263
- svg = data;
264
- }
265
- this.raw = this.parseSvgPath(svg, force);
266
- }
267
- this.createPath2D();
268
- this._engine.dispatchEvent("polygonMaskLoaded", {
269
- container: this._container,
270
- });
271
- }
272
- parseSvgPath(xml, force) {
273
- var _a, _b, _c;
274
- const forceDownload = force !== null && force !== void 0 ? force : false;
275
- if (this.paths !== undefined && !forceDownload) {
276
- return this.raw;
277
- }
278
- const container = this._container, options = container.actualOptions.polygon;
279
- if (!options) {
280
- return;
281
- }
282
- const parser = new DOMParser(), doc = parser.parseFromString(xml, "image/svg+xml"), svg = doc.getElementsByTagName("svg")[0];
283
- let svgPaths = svg.getElementsByTagName("path");
284
- if (!svgPaths.length) {
285
- svgPaths = doc.getElementsByTagName("path");
286
- }
287
- this.paths = [];
288
- for (let i = 0; i < svgPaths.length; i++) {
289
- const path = svgPaths.item(i);
290
- if (path) {
291
- this.paths.push({
292
- element: path,
293
- length: path.getTotalLength(),
294
- });
295
- }
296
- }
297
- const scale = this._scale;
298
- this.dimension.width = parseFloat((_a = svg.getAttribute("width")) !== null && _a !== void 0 ? _a : "0") * scale;
299
- this.dimension.height = parseFloat((_b = svg.getAttribute("height")) !== null && _b !== void 0 ? _b : "0") * scale;
300
- const position = (_c = options.position) !== null && _c !== void 0 ? _c : {
301
- x: 50,
302
- y: 50,
303
- };
304
- this.offset = {
305
- x: (container.canvas.size.width * position.x) / 100 - this.dimension.width / 2,
306
- y: (container.canvas.size.height * position.y) / 100 - this.dimension.height / 2,
307
- };
308
- return parsePaths(this.paths, scale, this.offset);
309
- }
310
- polygonBounce(particle, _delta, direction) {
311
- const options = this._container.actualOptions.polygon;
312
- if (!this.raw || !(options === null || options === void 0 ? void 0 : options.enable) || direction !== "top") {
313
- return false;
314
- }
315
- if (options.type === "inside" || options.type === "outside") {
316
- let closest, dx, dy;
317
- const pos = particle.getPosition(), radius = particle.getRadius();
318
- for (let i = 0, j = this.raw.length - 1; i < this.raw.length; j = i++) {
319
- const pi = this.raw[i], pj = this.raw[j];
320
- closest = calcClosestPtOnSegment(pi, pj, pos);
321
- const dist = getDistances(pos, closest);
322
- [dx, dy] = [dist.dx, dist.dy];
323
- if (dist.distance < radius) {
324
- segmentBounce(pi, pj, particle.velocity);
325
- return true;
326
- }
327
- }
328
- if (closest && dx !== undefined && dy !== undefined && !this.checkInsidePolygon(pos)) {
329
- const factor = { x: 1, y: 1 };
330
- if (particle.position.x >= closest.x) {
331
- factor.x = -1;
332
- }
333
- if (particle.position.y >= closest.y) {
334
- factor.y = -1;
335
- }
336
- particle.position.x = closest.x + radius * 2 * factor.x;
337
- particle.position.y = closest.y + radius * 2 * factor.y;
338
- particle.velocity.mult(-1);
339
- return true;
340
- }
341
- }
342
- else if (options.type === "inline" && particle.initialPosition) {
343
- const dist = getDistance(particle.initialPosition, particle.getPosition());
344
- if (dist > this._moveRadius) {
345
- particle.velocity.x = particle.velocity.y / 2 - particle.velocity.x;
346
- particle.velocity.y = particle.velocity.x / 2 - particle.velocity.y;
347
- return true;
348
- }
349
- }
350
- return false;
351
- }
352
- randomPoint() {
353
- const container = this._container, options = container.actualOptions.polygon;
354
- if (!options) {
355
- return;
356
- }
357
- let position;
358
- if (options.type === "inline") {
359
- switch (options.inline.arrangement) {
360
- case "random-point":
361
- position = this.getRandomPoint();
362
- break;
363
- case "random-length":
364
- position = this.getRandomPointByLength();
365
- break;
366
- case "equidistant":
367
- position = this.getEquidistantPointByIndex(container.particles.count);
368
- break;
369
- case "one-per-point":
370
- case "per-point":
371
- default:
372
- position = this.getPointByIndex(container.particles.count);
373
- }
374
- }
375
- else {
376
- position = {
377
- x: getRandom() * container.canvas.size.width,
378
- y: getRandom() * container.canvas.size.height,
379
- };
380
- }
381
- if (this.checkInsidePolygon(position)) {
382
- return position;
383
- }
384
- else {
385
- return this.randomPoint();
386
- }
387
- }
388
380
  }