@tsparticles/plugin-polygon-mask 3.0.0-alpha.1 → 3.0.0-beta.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.
Files changed (41) hide show
  1. package/README.md +15 -11
  2. package/browser/Options/Classes/PolygonMask.js +2 -8
  3. package/browser/Options/Classes/PolygonMaskDraw.js +1 -18
  4. package/browser/Options/Classes/PolygonMaskDrawStroke.js +3 -4
  5. package/browser/PolygonMaskInstance.js +297 -305
  6. package/browser/index.js +7 -8
  7. package/browser/pathseg.js +1 -1
  8. package/browser/utils.js +3 -5
  9. package/cjs/Options/Classes/PolygonMask.js +2 -8
  10. package/cjs/Options/Classes/PolygonMaskDraw.js +1 -18
  11. package/cjs/Options/Classes/PolygonMaskDrawStroke.js +2 -3
  12. package/cjs/PolygonMaskInstance.js +309 -332
  13. package/cjs/index.js +7 -19
  14. package/cjs/pathseg.js +1 -1
  15. package/cjs/utils.js +4 -6
  16. package/esm/Options/Classes/PolygonMask.js +2 -8
  17. package/esm/Options/Classes/PolygonMaskDraw.js +1 -18
  18. package/esm/Options/Classes/PolygonMaskDrawStroke.js +3 -4
  19. package/esm/PolygonMaskInstance.js +297 -305
  20. package/esm/index.js +7 -8
  21. package/esm/pathseg.js +1 -1
  22. package/esm/utils.js +3 -5
  23. package/package.json +8 -5
  24. package/report.html +4 -4
  25. package/tsparticles.plugin.polygon-mask.js +336 -362
  26. package/tsparticles.plugin.polygon-mask.min.js +1 -1
  27. package/tsparticles.plugin.polygon-mask.min.js.LICENSE.txt +1 -8
  28. package/types/Options/Classes/PolygonMask.d.ts +1 -4
  29. package/types/Options/Classes/PolygonMaskDraw.d.ts +1 -6
  30. package/types/Options/Classes/PolygonMaskDrawStroke.d.ts +1 -2
  31. package/types/Options/Interfaces/IPolygonMaskDraw.d.ts +0 -3
  32. package/types/PolygonMaskInstance.d.ts +13 -15
  33. package/types/index.d.ts +1 -1
  34. package/types/utils.d.ts +1 -2
  35. package/umd/Options/Classes/PolygonMask.js +3 -9
  36. package/umd/Options/Classes/PolygonMaskDraw.js +2 -19
  37. package/umd/Options/Classes/PolygonMaskDrawStroke.js +2 -3
  38. package/umd/PolygonMaskInstance.js +298 -306
  39. package/umd/index.js +7 -8
  40. package/umd/pathseg.js +1 -1
  41. package/umd/utils.js +3 -5
@@ -4,7 +4,7 @@
4
4
  * Demo / Generator : https://particles.js.org/
5
5
  * GitHub : https://www.github.com/matteobruni/tsparticles
6
6
  * How to use? : Check the GitHub README
7
- * v3.0.0-alpha.1
7
+ * v3.0.0-beta.0
8
8
  */
9
9
  (function webpackUniversalModuleDefinition(root, factory) {
10
10
  if(typeof exports === 'object' && typeof module === 'object')
@@ -20,7 +20,7 @@ return /******/ (() => { // webpackBootstrap
20
20
  /******/ "use strict";
21
21
  /******/ var __webpack_modules__ = ({
22
22
 
23
- /***/ 505:
23
+ /***/ 448:
24
24
  /***/ (() => {
25
25
 
26
26
 
@@ -1085,7 +1085,7 @@ return /******/ (() => { // webpackBootstrap
1085
1085
  this._pathElement.setAttribute("d", window.SVGPathSegList._pathSegArrayAsString(this._list));
1086
1086
  this._pathElementMutationObserver.observe(this._pathElement, this._mutationObserverConfig);
1087
1087
  };
1088
- window.SVGPathSegList.prototype.segmentChanged = function (pathSeg) {
1088
+ window.SVGPathSegList.prototype.segmentChanged = function () {
1089
1089
  this._writeListToPath();
1090
1090
  };
1091
1091
  window.SVGPathSegList.prototype.clear = function () {
@@ -1529,11 +1529,11 @@ __webpack_require__.r(__webpack_exports__);
1529
1529
 
1530
1530
  // EXPORTS
1531
1531
  __webpack_require__.d(__webpack_exports__, {
1532
- "loadPolygonMaskPlugin": () => (/* binding */ loadPolygonMaskPlugin)
1532
+ loadPolygonMaskPlugin: () => (/* binding */ loadPolygonMaskPlugin)
1533
1533
  });
1534
1534
 
1535
1535
  // EXTERNAL MODULE: ./dist/browser/pathseg.js
1536
- var pathseg = __webpack_require__(505);
1536
+ var pathseg = __webpack_require__(448);
1537
1537
  // EXTERNAL MODULE: external {"commonjs":"@tsparticles/engine","commonjs2":"@tsparticles/engine","amd":"@tsparticles/engine","root":"window"}
1538
1538
  var engine_root_window_ = __webpack_require__(533);
1539
1539
  ;// CONCATENATED MODULE: ./dist/browser/Options/Classes/PolygonMaskDrawStroke.js
@@ -1545,13 +1545,12 @@ class PolygonMaskDrawStroke {
1545
1545
  this.opacity = 1;
1546
1546
  }
1547
1547
  load(data) {
1548
- var _a;
1549
1548
  if (!data) {
1550
1549
  return;
1551
1550
  }
1552
1551
  this.color = engine_root_window_.OptionsColor.create(this.color, data.color);
1553
- if (typeof this.color.value === "string") {
1554
- this.opacity = (_a = (0,engine_root_window_.stringToAlpha)(this.color.value)) !== null && _a !== void 0 ? _a : this.opacity;
1552
+ if ((0,engine_root_window_.isString)(this.color.value)) {
1553
+ this.opacity = (0,engine_root_window_.stringToAlpha)(this.color.value) ?? this.opacity;
1555
1554
  }
1556
1555
  if (data.opacity !== undefined) {
1557
1556
  this.opacity = data.opacity;
@@ -1563,36 +1562,19 @@ class PolygonMaskDrawStroke {
1563
1562
  }
1564
1563
  ;// CONCATENATED MODULE: ./dist/browser/Options/Classes/PolygonMaskDraw.js
1565
1564
 
1566
-
1567
1565
  class PolygonMaskDraw {
1568
1566
  constructor() {
1569
1567
  this.enable = false;
1570
1568
  this.stroke = new PolygonMaskDrawStroke();
1571
1569
  }
1572
- get lineColor() {
1573
- return this.stroke.color;
1574
- }
1575
- set lineColor(value) {
1576
- this.stroke.color = engine_root_window_.OptionsColor.create(this.stroke.color, value);
1577
- }
1578
- get lineWidth() {
1579
- return this.stroke.width;
1580
- }
1581
- set lineWidth(value) {
1582
- this.stroke.width = value;
1583
- }
1584
1570
  load(data) {
1585
- var _a;
1586
1571
  if (!data) {
1587
1572
  return;
1588
1573
  }
1589
1574
  if (data.enable !== undefined) {
1590
1575
  this.enable = data.enable;
1591
1576
  }
1592
- const stroke = (_a = data.stroke) !== null && _a !== void 0 ? _a : {
1593
- color: data.lineColor,
1594
- width: data.lineWidth
1595
- };
1577
+ const stroke = data.stroke;
1596
1578
  this.stroke.load(stroke);
1597
1579
  }
1598
1580
  }
@@ -1669,12 +1651,6 @@ class PolygonMask {
1669
1651
  this.scale = 1;
1670
1652
  this.type = "none";
1671
1653
  }
1672
- get inlineArrangement() {
1673
- return this.inline.arrangement;
1674
- }
1675
- set inlineArrangement(value) {
1676
- this.inline.arrangement = value;
1677
- }
1678
1654
  load(data) {
1679
1655
  if (!data) {
1680
1656
  return;
@@ -1697,7 +1673,7 @@ class PolygonMask {
1697
1673
  this.url = data.url;
1698
1674
  }
1699
1675
  if (data.data !== undefined) {
1700
- if (typeof data.data === "string") {
1676
+ if ((0,engine_root_window_.isString)(data.data)) {
1701
1677
  this.data = data.data;
1702
1678
  } else {
1703
1679
  this.data = new PolygonMaskLocalSvg();
@@ -1738,19 +1714,18 @@ function drawPolygonMaskPath(context, path, stroke, position) {
1738
1714
  context.setTransform(1, 0, 0, 1, 0, 0);
1739
1715
  }
1740
1716
  function parsePaths(paths, scale, offset) {
1741
- var _a;
1742
1717
  const res = [];
1743
1718
  for (const path of paths) {
1744
1719
  const segments = path.element.pathSegList,
1745
- len = (_a = segments === null || segments === void 0 ? void 0 : segments.numberOfItems) !== null && _a !== void 0 ? _a : 0,
1720
+ len = segments?.numberOfItems ?? 0,
1746
1721
  p = {
1747
1722
  x: 0,
1748
1723
  y: 0
1749
1724
  };
1750
1725
  for (let i = 0; i < len; i++) {
1751
- const segment = segments === null || segments === void 0 ? void 0 : segments.getItem(i);
1752
- const svgPathSeg = window.SVGPathSeg;
1753
- switch (segment === null || segment === void 0 ? void 0 : segment.pathSegType) {
1726
+ const segment = segments?.getItem(i),
1727
+ svgPathSeg = window.SVGPathSeg;
1728
+ switch (segment?.pathSegType) {
1754
1729
  case svgPathSeg.PATHSEG_MOVETO_ABS:
1755
1730
  case svgPathSeg.PATHSEG_LINETO_ABS:
1756
1731
  case svgPathSeg.PATHSEG_CURVETO_CUBIC_ABS:
@@ -1839,10 +1814,314 @@ function segmentBounce(start, stop, velocity) {
1839
1814
  ;// CONCATENATED MODULE: ./dist/browser/PolygonMaskInstance.js
1840
1815
 
1841
1816
 
1842
- const noPolygonDataLoaded = "No polygon data loaded.",
1843
- noPolygonFound = "No polygon found, you need to specify SVG url in config.";
1817
+ const noPolygonDataLoaded = `${engine_root_window_.errorPrefix} No polygon data loaded.`,
1818
+ noPolygonFound = `${engine_root_window_.errorPrefix} No polygon found, you need to specify SVG url in config.`;
1844
1819
  class PolygonMaskInstance {
1845
1820
  constructor(container, engine) {
1821
+ this._checkInsidePolygon = position => {
1822
+ const container = this._container,
1823
+ options = container.actualOptions.polygon;
1824
+ if (!options?.enable || options.type === "none" || options.type === "inline") {
1825
+ return true;
1826
+ }
1827
+ if (!this.raw) {
1828
+ throw new Error(noPolygonFound);
1829
+ }
1830
+ const canvasSize = container.canvas.size,
1831
+ x = position?.x ?? (0,engine_root_window_.getRandom)() * canvasSize.width,
1832
+ y = position?.y ?? (0,engine_root_window_.getRandom)() * canvasSize.height;
1833
+ let inside = false;
1834
+ for (let i = 0, j = this.raw.length - 1; i < this.raw.length; j = i++) {
1835
+ const pi = this.raw[i],
1836
+ pj = this.raw[j],
1837
+ intersect = pi.y > y !== pj.y > y && x < (pj.x - pi.x) * (y - pi.y) / (pj.y - pi.y) + pi.x;
1838
+ if (intersect) {
1839
+ inside = !inside;
1840
+ }
1841
+ }
1842
+ return options.type === "inside" ? inside : options.type === "outside" ? !inside : false;
1843
+ };
1844
+ this._createPath2D = () => {
1845
+ const container = this._container,
1846
+ options = container.actualOptions.polygon;
1847
+ if (!options || !this.paths?.length) {
1848
+ return;
1849
+ }
1850
+ for (const path of this.paths) {
1851
+ const pathData = path.element?.getAttribute("d");
1852
+ if (pathData) {
1853
+ const path2d = new Path2D(pathData),
1854
+ matrix = document.createElementNS("http://www.w3.org/2000/svg", "svg").createSVGMatrix(),
1855
+ finalPath = new Path2D(),
1856
+ transform = matrix.scale(this._scale);
1857
+ if (finalPath.addPath) {
1858
+ finalPath.addPath(path2d, transform);
1859
+ path.path2d = finalPath;
1860
+ } else {
1861
+ delete path.path2d;
1862
+ }
1863
+ } else {
1864
+ delete path.path2d;
1865
+ }
1866
+ if (path.path2d || !this.raw) {
1867
+ continue;
1868
+ }
1869
+ path.path2d = new Path2D();
1870
+ path.path2d.moveTo(this.raw[0].x, this.raw[0].y);
1871
+ this.raw.forEach((pos, i) => {
1872
+ if (i > 0) {
1873
+ path.path2d?.lineTo(pos.x, pos.y);
1874
+ }
1875
+ });
1876
+ path.path2d.closePath();
1877
+ }
1878
+ };
1879
+ this._downloadSvgPath = async (svgUrl, force) => {
1880
+ const options = this._container.actualOptions.polygon;
1881
+ if (!options) {
1882
+ return;
1883
+ }
1884
+ const url = svgUrl || options.url,
1885
+ forceDownload = force ?? false;
1886
+ if (!url || this.paths !== undefined && !forceDownload) {
1887
+ return this.raw;
1888
+ }
1889
+ const req = await fetch(url);
1890
+ if (!req.ok) {
1891
+ throw new Error(`${engine_root_window_.errorPrefix} occurred during polygon mask download`);
1892
+ }
1893
+ return this._parseSvgPath(await req.text(), force);
1894
+ };
1895
+ this._drawPoints = () => {
1896
+ if (!this.raw) {
1897
+ return;
1898
+ }
1899
+ for (const item of this.raw) {
1900
+ this._container.particles.addParticle({
1901
+ x: item.x,
1902
+ y: item.y
1903
+ });
1904
+ }
1905
+ };
1906
+ this._getEquidistantPointByIndex = index => {
1907
+ const container = this._container,
1908
+ options = container.actualOptions,
1909
+ polygonMaskOptions = options.polygon;
1910
+ if (!polygonMaskOptions) {
1911
+ return;
1912
+ }
1913
+ if (!this.raw || !this.raw.length || !this.paths?.length) {
1914
+ throw new Error(noPolygonDataLoaded);
1915
+ }
1916
+ let offset = 0,
1917
+ point;
1918
+ const totalLength = this.paths.reduce((tot, path) => tot + path.length, 0),
1919
+ distance = totalLength / options.particles.number.value;
1920
+ for (const path of this.paths) {
1921
+ const pathDistance = distance * index - offset;
1922
+ if (pathDistance <= path.length) {
1923
+ point = path.element.getPointAtLength(pathDistance);
1924
+ break;
1925
+ } else {
1926
+ offset += path.length;
1927
+ }
1928
+ }
1929
+ const scale = this._scale;
1930
+ return {
1931
+ x: (point?.x ?? 0) * scale + (this.offset?.x ?? 0),
1932
+ y: (point?.y ?? 0) * scale + (this.offset?.y ?? 0)
1933
+ };
1934
+ };
1935
+ this._getPointByIndex = index => {
1936
+ if (!this.raw || !this.raw.length) {
1937
+ throw new Error(noPolygonDataLoaded);
1938
+ }
1939
+ const coords = this.raw[index % this.raw.length];
1940
+ return {
1941
+ x: coords.x,
1942
+ y: coords.y
1943
+ };
1944
+ };
1945
+ this._getRandomPoint = () => {
1946
+ if (!this.raw || !this.raw.length) {
1947
+ throw new Error(noPolygonDataLoaded);
1948
+ }
1949
+ const coords = (0,engine_root_window_.itemFromArray)(this.raw);
1950
+ return {
1951
+ x: coords.x,
1952
+ y: coords.y
1953
+ };
1954
+ };
1955
+ this._getRandomPointByLength = () => {
1956
+ const container = this._container,
1957
+ options = container.actualOptions.polygon;
1958
+ if (!options) {
1959
+ return;
1960
+ }
1961
+ if (!this.raw || !this.raw.length || !this.paths?.length) {
1962
+ throw new Error(noPolygonDataLoaded);
1963
+ }
1964
+ const path = (0,engine_root_window_.itemFromArray)(this.paths),
1965
+ distance = Math.floor((0,engine_root_window_.getRandom)() * path.length) + 1,
1966
+ point = path.element.getPointAtLength(distance),
1967
+ scale = this._scale;
1968
+ return {
1969
+ x: point.x * scale + (this.offset?.x || 0),
1970
+ y: point.y * scale + (this.offset?.y || 0)
1971
+ };
1972
+ };
1973
+ this._initRawData = async force => {
1974
+ const options = this._container.actualOptions.polygon;
1975
+ if (!options) {
1976
+ return;
1977
+ }
1978
+ if (options.url) {
1979
+ this.raw = await this._downloadSvgPath(options.url, force);
1980
+ } else if (options.data) {
1981
+ const data = options.data;
1982
+ let svg;
1983
+ if ((0,engine_root_window_.isString)(data)) {
1984
+ svg = data;
1985
+ } else {
1986
+ const getPath = p => `<path d="${p}" />`,
1987
+ path = (0,engine_root_window_.isArray)(data.path) ? data.path.map(getPath).join("") : getPath(data.path);
1988
+ const namespaces = 'xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"';
1989
+ svg = `<svg ${namespaces} width="${data.size.width}" height="${data.size.height}">${path}</svg>`;
1990
+ }
1991
+ this.raw = this._parseSvgPath(svg, force);
1992
+ }
1993
+ this._createPath2D();
1994
+ this._engine.dispatchEvent("polygonMaskLoaded", {
1995
+ container: this._container
1996
+ });
1997
+ };
1998
+ this._parseSvgPath = (xml, force) => {
1999
+ const forceDownload = force ?? false;
2000
+ if (this.paths !== undefined && !forceDownload) {
2001
+ return this.raw;
2002
+ }
2003
+ const container = this._container,
2004
+ options = container.actualOptions.polygon;
2005
+ if (!options) {
2006
+ return;
2007
+ }
2008
+ const parser = new DOMParser(),
2009
+ doc = parser.parseFromString(xml, "image/svg+xml"),
2010
+ svg = doc.getElementsByTagName("svg")[0];
2011
+ let svgPaths = svg.getElementsByTagName("path");
2012
+ if (!svgPaths.length) {
2013
+ svgPaths = doc.getElementsByTagName("path");
2014
+ }
2015
+ this.paths = [];
2016
+ for (let i = 0; i < svgPaths.length; i++) {
2017
+ const path = svgPaths.item(i);
2018
+ if (path) {
2019
+ this.paths.push({
2020
+ element: path,
2021
+ length: path.getTotalLength()
2022
+ });
2023
+ }
2024
+ }
2025
+ const scale = this._scale;
2026
+ this.dimension.width = parseFloat(svg.getAttribute("width") ?? "0") * scale;
2027
+ this.dimension.height = parseFloat(svg.getAttribute("height") ?? "0") * scale;
2028
+ const position = options.position ?? {
2029
+ x: 50,
2030
+ y: 50
2031
+ },
2032
+ canvasSize = container.canvas.size;
2033
+ this.offset = {
2034
+ x: canvasSize.width * position.x / 100 - this.dimension.width / 2,
2035
+ y: canvasSize.height * position.y / 100 - this.dimension.height / 2
2036
+ };
2037
+ return parsePaths(this.paths, scale, this.offset);
2038
+ };
2039
+ this._polygonBounce = (particle, _delta, direction) => {
2040
+ const options = this._container.actualOptions.polygon;
2041
+ if (!this.raw || !options?.enable || direction !== "top") {
2042
+ return false;
2043
+ }
2044
+ if (options.type === "inside" || options.type === "outside") {
2045
+ let closest, dx, dy;
2046
+ const pos = particle.getPosition(),
2047
+ radius = particle.getRadius();
2048
+ for (let i = 0, j = this.raw.length - 1; i < this.raw.length; j = i++) {
2049
+ const pi = this.raw[i],
2050
+ pj = this.raw[j];
2051
+ closest = calcClosestPtOnSegment(pi, pj, pos);
2052
+ const dist = (0,engine_root_window_.getDistances)(pos, closest);
2053
+ [dx, dy] = [dist.dx, dist.dy];
2054
+ if (dist.distance < radius) {
2055
+ segmentBounce(pi, pj, particle.velocity);
2056
+ return true;
2057
+ }
2058
+ }
2059
+ if (closest && dx !== undefined && dy !== undefined && !this._checkInsidePolygon(pos)) {
2060
+ const factor = {
2061
+ x: 1,
2062
+ y: 1
2063
+ },
2064
+ diameter = radius * 2;
2065
+ if (pos.x >= closest.x) {
2066
+ factor.x = -1;
2067
+ }
2068
+ if (pos.y >= closest.y) {
2069
+ factor.y = -1;
2070
+ }
2071
+ particle.position.x = closest.x + diameter * factor.x;
2072
+ particle.position.y = closest.y + diameter * factor.y;
2073
+ particle.velocity.mult(-1);
2074
+ return true;
2075
+ }
2076
+ } else if (options.type === "inline" && particle.initialPosition) {
2077
+ const dist = (0,engine_root_window_.getDistance)(particle.initialPosition, particle.getPosition()),
2078
+ {
2079
+ velocity
2080
+ } = particle;
2081
+ if (dist > this._moveRadius) {
2082
+ velocity.x = velocity.y / 2 - velocity.x;
2083
+ velocity.y = velocity.x / 2 - velocity.y;
2084
+ return true;
2085
+ }
2086
+ }
2087
+ return false;
2088
+ };
2089
+ this._randomPoint = () => {
2090
+ const container = this._container,
2091
+ options = container.actualOptions.polygon;
2092
+ if (!options) {
2093
+ return;
2094
+ }
2095
+ let position;
2096
+ if (options.type === "inline") {
2097
+ switch (options.inline.arrangement) {
2098
+ case "random-point":
2099
+ position = this._getRandomPoint();
2100
+ break;
2101
+ case "random-length":
2102
+ position = this._getRandomPointByLength();
2103
+ break;
2104
+ case "equidistant":
2105
+ position = this._getEquidistantPointByIndex(container.particles.count);
2106
+ break;
2107
+ case "one-per-point":
2108
+ case "per-point":
2109
+ default:
2110
+ position = this._getPointByIndex(container.particles.count);
2111
+ }
2112
+ } else {
2113
+ const canvasSize = container.canvas.size;
2114
+ position = {
2115
+ x: (0,engine_root_window_.getRandom)() * canvasSize.width,
2116
+ y: (0,engine_root_window_.getRandom)() * canvasSize.height
2117
+ };
2118
+ }
2119
+ if (this._checkInsidePolygon(position)) {
2120
+ return position;
2121
+ } else {
2122
+ return this._randomPoint();
2123
+ }
2124
+ };
1846
2125
  this._container = container;
1847
2126
  this._engine = engine;
1848
2127
  this.dimension = {
@@ -1854,15 +2133,14 @@ class PolygonMaskInstance {
1854
2133
  }
1855
2134
  clickPositionValid(position) {
1856
2135
  const options = this._container.actualOptions.polygon;
1857
- return !!(options === null || options === void 0 ? void 0 : options.enable) && options.type !== "none" && options.type !== "inline" && this.checkInsidePolygon(position);
2136
+ return !!options?.enable && options.type !== "none" && options.type !== "inline" && this._checkInsidePolygon(position);
1858
2137
  }
1859
2138
  draw(context) {
1860
- var _a;
1861
- if (!((_a = this.paths) === null || _a === void 0 ? void 0 : _a.length)) {
2139
+ if (!this.paths?.length) {
1862
2140
  return;
1863
2141
  }
1864
2142
  const options = this._container.actualOptions.polygon;
1865
- if (!(options === null || options === void 0 ? void 0 : options.enable)) {
2143
+ if (!options?.enable) {
1866
2144
  return;
1867
2145
  }
1868
2146
  const polygonDraw = options.draw;
@@ -1892,24 +2170,23 @@ class PolygonMaskInstance {
1892
2170
  this._moveRadius = polygonMaskOptions.move.radius * pxRatio;
1893
2171
  this._scale = polygonMaskOptions.scale * pxRatio;
1894
2172
  if (polygonMaskOptions.enable) {
1895
- await this.initRawData();
2173
+ await this._initRawData();
1896
2174
  }
1897
2175
  }
1898
2176
  particleBounce(particle, delta, direction) {
1899
- return this.polygonBounce(particle, delta, direction);
2177
+ return this._polygonBounce(particle, delta, direction);
1900
2178
  }
1901
2179
  particlePosition(position) {
1902
- var _a, _b;
1903
2180
  const options = this._container.actualOptions.polygon;
1904
- 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)) {
2181
+ if (!(options?.enable && (this.raw?.length ?? 0) > 0)) {
1905
2182
  return;
1906
2183
  }
1907
- return (0,engine_root_window_.deepExtend)({}, position ? position : this.randomPoint());
2184
+ return (0,engine_root_window_.deepExtend)({}, position ? position : this._randomPoint());
1908
2185
  }
1909
2186
  particlesInitialization() {
1910
2187
  const options = this._container.actualOptions.polygon;
1911
- if ((options === null || options === void 0 ? void 0 : options.enable) && options.type === "inline" && (options.inline.arrangement === "one-per-point" || options.inline.arrangement === "per-point")) {
1912
- this.drawPoints();
2188
+ if (options?.enable && options.type === "inline" && (options.inline.arrangement === "one-per-point" || options.inline.arrangement === "per-point")) {
2189
+ this._drawPoints();
1913
2190
  return true;
1914
2191
  }
1915
2192
  return false;
@@ -1917,14 +2194,14 @@ class PolygonMaskInstance {
1917
2194
  resize() {
1918
2195
  const container = this._container,
1919
2196
  options = container.actualOptions.polygon;
1920
- if (!((options === null || options === void 0 ? void 0 : options.enable) && options.type !== "none")) {
2197
+ if (!(options?.enable && options.type !== "none")) {
1921
2198
  return;
1922
2199
  }
1923
2200
  if (this.redrawTimeout) {
1924
2201
  clearTimeout(this.redrawTimeout);
1925
2202
  }
1926
2203
  this.redrawTimeout = window.setTimeout(async () => {
1927
- await this.initRawData(true);
2204
+ await this._initRawData(true);
1928
2205
  await container.particles.redraw();
1929
2206
  }, 250);
1930
2207
  }
@@ -1932,307 +2209,6 @@ class PolygonMaskInstance {
1932
2209
  delete this.raw;
1933
2210
  delete this.paths;
1934
2211
  }
1935
- checkInsidePolygon(position) {
1936
- var _a, _b;
1937
- const container = this._container,
1938
- options = container.actualOptions.polygon;
1939
- if (!(options === null || options === void 0 ? void 0 : options.enable) || options.type === "none" || options.type === "inline") {
1940
- return true;
1941
- }
1942
- if (!this.raw) {
1943
- throw new Error(noPolygonFound);
1944
- }
1945
- const canvasSize = container.canvas.size,
1946
- x = (_a = position === null || position === void 0 ? void 0 : position.x) !== null && _a !== void 0 ? _a : (0,engine_root_window_.getRandom)() * canvasSize.width,
1947
- y = (_b = position === null || position === void 0 ? void 0 : position.y) !== null && _b !== void 0 ? _b : (0,engine_root_window_.getRandom)() * canvasSize.height;
1948
- let inside = false;
1949
- for (let i = 0, j = this.raw.length - 1; i < this.raw.length; j = i++) {
1950
- const pi = this.raw[i],
1951
- pj = this.raw[j],
1952
- intersect = pi.y > y !== pj.y > y && x < (pj.x - pi.x) * (y - pi.y) / (pj.y - pi.y) + pi.x;
1953
- if (intersect) {
1954
- inside = !inside;
1955
- }
1956
- }
1957
- return options.type === "inside" ? inside : options.type === "outside" ? !inside : false;
1958
- }
1959
- createPath2D() {
1960
- var _a, _b;
1961
- const container = this._container,
1962
- options = container.actualOptions.polygon;
1963
- if (!options || !((_a = this.paths) === null || _a === void 0 ? void 0 : _a.length)) {
1964
- return;
1965
- }
1966
- for (const path of this.paths) {
1967
- const pathData = (_b = path.element) === null || _b === void 0 ? void 0 : _b.getAttribute("d");
1968
- if (pathData) {
1969
- const path2d = new Path2D(pathData),
1970
- matrix = document.createElementNS("http://www.w3.org/2000/svg", "svg").createSVGMatrix(),
1971
- finalPath = new Path2D(),
1972
- transform = matrix.scale(this._scale);
1973
- if (finalPath.addPath) {
1974
- finalPath.addPath(path2d, transform);
1975
- path.path2d = finalPath;
1976
- } else {
1977
- delete path.path2d;
1978
- }
1979
- } else {
1980
- delete path.path2d;
1981
- }
1982
- if (path.path2d || !this.raw) {
1983
- continue;
1984
- }
1985
- path.path2d = new Path2D();
1986
- path.path2d.moveTo(this.raw[0].x, this.raw[0].y);
1987
- this.raw.forEach((pos, i) => {
1988
- var _a;
1989
- if (i > 0) {
1990
- (_a = path.path2d) === null || _a === void 0 ? void 0 : _a.lineTo(pos.x, pos.y);
1991
- }
1992
- });
1993
- path.path2d.closePath();
1994
- }
1995
- }
1996
- async downloadSvgPath(svgUrl, force) {
1997
- const options = this._container.actualOptions.polygon;
1998
- if (!options) {
1999
- return;
2000
- }
2001
- const url = svgUrl || options.url,
2002
- forceDownload = force !== null && force !== void 0 ? force : false;
2003
- if (!url || this.paths !== undefined && !forceDownload) {
2004
- return this.raw;
2005
- }
2006
- const req = await fetch(url);
2007
- if (!req.ok) {
2008
- throw new Error("tsParticles Error - Error occurred during polygon mask download");
2009
- }
2010
- return this.parseSvgPath(await req.text(), force);
2011
- }
2012
- drawPoints() {
2013
- if (!this.raw) {
2014
- return;
2015
- }
2016
- for (const item of this.raw) {
2017
- this._container.particles.addParticle({
2018
- x: item.x,
2019
- y: item.y
2020
- });
2021
- }
2022
- }
2023
- getEquidistantPointByIndex(index) {
2024
- var _a, _b, _c, _d, _e, _f, _g;
2025
- const container = this._container,
2026
- options = container.actualOptions,
2027
- polygonMaskOptions = options.polygon;
2028
- if (!polygonMaskOptions) {
2029
- return;
2030
- }
2031
- if (!this.raw || !this.raw.length || !((_a = this.paths) === null || _a === void 0 ? void 0 : _a.length)) throw new Error(noPolygonDataLoaded);
2032
- let offset = 0,
2033
- point;
2034
- const totalLength = this.paths.reduce((tot, path) => tot + path.length, 0),
2035
- distance = totalLength / options.particles.number.value;
2036
- for (const path of this.paths) {
2037
- const pathDistance = distance * index - offset;
2038
- if (pathDistance <= path.length) {
2039
- point = path.element.getPointAtLength(pathDistance);
2040
- break;
2041
- } else {
2042
- offset += path.length;
2043
- }
2044
- }
2045
- const scale = this._scale;
2046
- return {
2047
- 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),
2048
- 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)
2049
- };
2050
- }
2051
- getPointByIndex(index) {
2052
- if (!this.raw || !this.raw.length) {
2053
- throw new Error(noPolygonDataLoaded);
2054
- }
2055
- const coords = this.raw[index % this.raw.length];
2056
- return {
2057
- x: coords.x,
2058
- y: coords.y
2059
- };
2060
- }
2061
- getRandomPoint() {
2062
- if (!this.raw || !this.raw.length) {
2063
- throw new Error(noPolygonDataLoaded);
2064
- }
2065
- const coords = (0,engine_root_window_.itemFromArray)(this.raw);
2066
- return {
2067
- x: coords.x,
2068
- y: coords.y
2069
- };
2070
- }
2071
- getRandomPointByLength() {
2072
- var _a, _b, _c;
2073
- const container = this._container,
2074
- options = container.actualOptions.polygon;
2075
- if (!options) {
2076
- return;
2077
- }
2078
- if (!this.raw || !this.raw.length || !((_a = this.paths) === null || _a === void 0 ? void 0 : _a.length)) {
2079
- throw new Error(noPolygonDataLoaded);
2080
- }
2081
- const path = (0,engine_root_window_.itemFromArray)(this.paths),
2082
- distance = Math.floor((0,engine_root_window_.getRandom)() * path.length) + 1,
2083
- point = path.element.getPointAtLength(distance),
2084
- scale = this._scale;
2085
- return {
2086
- x: point.x * scale + (((_b = this.offset) === null || _b === void 0 ? void 0 : _b.x) || 0),
2087
- y: point.y * scale + (((_c = this.offset) === null || _c === void 0 ? void 0 : _c.y) || 0)
2088
- };
2089
- }
2090
- async initRawData(force) {
2091
- const options = this._container.actualOptions.polygon;
2092
- if (!options) {
2093
- return;
2094
- }
2095
- if (options.url) {
2096
- this.raw = await this.downloadSvgPath(options.url, force);
2097
- } else if (options.data) {
2098
- const data = options.data;
2099
- let svg;
2100
- if (typeof data !== "string") {
2101
- const path = data.path instanceof Array ? data.path.map(t => `<path d="${t}" />`).join("") : `<path d="${data.path}" />`;
2102
- const namespaces = 'xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"';
2103
- svg = `<svg ${namespaces} width="${data.size.width}" height="${data.size.height}">${path}</svg>`;
2104
- } else {
2105
- svg = data;
2106
- }
2107
- this.raw = this.parseSvgPath(svg, force);
2108
- }
2109
- this.createPath2D();
2110
- this._engine.dispatchEvent("polygonMaskLoaded", {
2111
- container: this._container
2112
- });
2113
- }
2114
- parseSvgPath(xml, force) {
2115
- var _a, _b, _c;
2116
- const forceDownload = force !== null && force !== void 0 ? force : false;
2117
- if (this.paths !== undefined && !forceDownload) {
2118
- return this.raw;
2119
- }
2120
- const container = this._container,
2121
- options = container.actualOptions.polygon;
2122
- if (!options) {
2123
- return;
2124
- }
2125
- const parser = new DOMParser(),
2126
- doc = parser.parseFromString(xml, "image/svg+xml"),
2127
- svg = doc.getElementsByTagName("svg")[0];
2128
- let svgPaths = svg.getElementsByTagName("path");
2129
- if (!svgPaths.length) {
2130
- svgPaths = doc.getElementsByTagName("path");
2131
- }
2132
- this.paths = [];
2133
- for (let i = 0; i < svgPaths.length; i++) {
2134
- const path = svgPaths.item(i);
2135
- if (path) {
2136
- this.paths.push({
2137
- element: path,
2138
- length: path.getTotalLength()
2139
- });
2140
- }
2141
- }
2142
- const scale = this._scale;
2143
- this.dimension.width = parseFloat((_a = svg.getAttribute("width")) !== null && _a !== void 0 ? _a : "0") * scale;
2144
- this.dimension.height = parseFloat((_b = svg.getAttribute("height")) !== null && _b !== void 0 ? _b : "0") * scale;
2145
- const position = (_c = options.position) !== null && _c !== void 0 ? _c : {
2146
- x: 50,
2147
- y: 50
2148
- };
2149
- this.offset = {
2150
- x: container.canvas.size.width * position.x / 100 - this.dimension.width / 2,
2151
- y: container.canvas.size.height * position.y / 100 - this.dimension.height / 2
2152
- };
2153
- return parsePaths(this.paths, scale, this.offset);
2154
- }
2155
- polygonBounce(particle, _delta, direction) {
2156
- const options = this._container.actualOptions.polygon;
2157
- if (!this.raw || !(options === null || options === void 0 ? void 0 : options.enable) || direction !== "top") {
2158
- return false;
2159
- }
2160
- if (options.type === "inside" || options.type === "outside") {
2161
- let closest, dx, dy;
2162
- const pos = particle.getPosition(),
2163
- radius = particle.getRadius();
2164
- for (let i = 0, j = this.raw.length - 1; i < this.raw.length; j = i++) {
2165
- const pi = this.raw[i],
2166
- pj = this.raw[j];
2167
- closest = calcClosestPtOnSegment(pi, pj, pos);
2168
- const dist = (0,engine_root_window_.getDistances)(pos, closest);
2169
- [dx, dy] = [dist.dx, dist.dy];
2170
- if (dist.distance < radius) {
2171
- segmentBounce(pi, pj, particle.velocity);
2172
- return true;
2173
- }
2174
- }
2175
- if (closest && dx !== undefined && dy !== undefined && !this.checkInsidePolygon(pos)) {
2176
- const factor = {
2177
- x: 1,
2178
- y: 1
2179
- };
2180
- if (particle.position.x >= closest.x) {
2181
- factor.x = -1;
2182
- }
2183
- if (particle.position.y >= closest.y) {
2184
- factor.y = -1;
2185
- }
2186
- particle.position.x = closest.x + radius * 2 * factor.x;
2187
- particle.position.y = closest.y + radius * 2 * factor.y;
2188
- particle.velocity.mult(-1);
2189
- return true;
2190
- }
2191
- } else if (options.type === "inline" && particle.initialPosition) {
2192
- const dist = (0,engine_root_window_.getDistance)(particle.initialPosition, particle.getPosition());
2193
- if (dist > this._moveRadius) {
2194
- particle.velocity.x = particle.velocity.y / 2 - particle.velocity.x;
2195
- particle.velocity.y = particle.velocity.x / 2 - particle.velocity.y;
2196
- return true;
2197
- }
2198
- }
2199
- return false;
2200
- }
2201
- randomPoint() {
2202
- const container = this._container,
2203
- options = container.actualOptions.polygon;
2204
- if (!options) {
2205
- return;
2206
- }
2207
- let position;
2208
- if (options.type === "inline") {
2209
- switch (options.inline.arrangement) {
2210
- case "random-point":
2211
- position = this.getRandomPoint();
2212
- break;
2213
- case "random-length":
2214
- position = this.getRandomPointByLength();
2215
- break;
2216
- case "equidistant":
2217
- position = this.getEquidistantPointByIndex(container.particles.count);
2218
- break;
2219
- case "one-per-point":
2220
- case "per-point":
2221
- default:
2222
- position = this.getPointByIndex(container.particles.count);
2223
- }
2224
- } else {
2225
- position = {
2226
- x: (0,engine_root_window_.getRandom)() * container.canvas.size.width,
2227
- y: (0,engine_root_window_.getRandom)() * container.canvas.size.height
2228
- };
2229
- }
2230
- if (this.checkInsidePolygon(position)) {
2231
- return position;
2232
- } else {
2233
- return this.randomPoint();
2234
- }
2235
- }
2236
2212
  }
2237
2213
  ;// CONCATENATED MODULE: ./dist/browser/index.js
2238
2214
 
@@ -2247,23 +2223,21 @@ class PolygonMaskPlugin {
2247
2223
  return new PolygonMaskInstance(container, this._engine);
2248
2224
  }
2249
2225
  loadOptions(options, source) {
2250
- if (!this.needsPlugin(source)) {
2226
+ if (!this.needsPlugin(options) && !this.needsPlugin(source)) {
2251
2227
  return;
2252
2228
  }
2253
2229
  let polygonOptions = options.polygon;
2254
- if ((polygonOptions === null || polygonOptions === void 0 ? void 0 : polygonOptions.load) === undefined) {
2230
+ if (polygonOptions?.load === undefined) {
2255
2231
  options.polygon = polygonOptions = new PolygonMask();
2256
2232
  }
2257
- polygonOptions.load(source === null || source === void 0 ? void 0 : source.polygon);
2233
+ polygonOptions.load(source?.polygon);
2258
2234
  }
2259
2235
  needsPlugin(options) {
2260
- var _a, _b, _c;
2261
- return (_b = (_a = options === null || options === void 0 ? void 0 : options.polygon) === null || _a === void 0 ? void 0 : _a.enable) !== null && _b !== void 0 ? _b : ((_c = options === null || options === void 0 ? void 0 : options.polygon) === null || _c === void 0 ? void 0 : _c.type) !== undefined && options.polygon.type !== "none";
2236
+ return options?.polygon?.enable ?? (options?.polygon?.type !== undefined && options.polygon.type !== "none");
2262
2237
  }
2263
2238
  }
2264
- async function loadPolygonMaskPlugin(engine) {
2265
- const plugin = new PolygonMaskPlugin(engine);
2266
- await engine.addPlugin(plugin);
2239
+ async function loadPolygonMaskPlugin(engine, refresh = true) {
2240
+ await engine.addPlugin(new PolygonMaskPlugin(engine), refresh);
2267
2241
  }
2268
2242
 
2269
2243