aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--package-lock.json1433
-rw-r--r--package.json9
-rw-r--r--src/client/views/nodes/MapBox/AnimationSpeedIcons.tsx35
-rw-r--r--src/client/views/nodes/MapBox/AnimationUtility.ts429
-rw-r--r--src/client/views/nodes/MapBox/MapAnchorMenu.tsx118
-rw-r--r--src/client/views/nodes/MapBox/MapBox.scss50
-rw-r--r--src/client/views/nodes/MapBox/MapBox.tsx776
-rw-r--r--src/client/views/nodes/MapBox/MarkerIcons.tsx69
8 files changed, 2714 insertions, 205 deletions
diff --git a/package-lock.json b/package-lock.json
index 58b3d9eae..311eb9281 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5329,6 +5329,1294 @@
}
}
},
+ "@turf/along": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/along/-/along-6.5.0.tgz",
+ "integrity": "sha512-LLyWQ0AARqJCmMcIEAXF4GEu8usmd4Kbz3qk1Oy5HoRNpZX47+i5exQtmIWKdqJ1MMhW26fCTXgpsEs5zgJ5gw==",
+ "requires": {
+ "@turf/bearing": "^6.5.0",
+ "@turf/destination": "^6.5.0",
+ "@turf/distance": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0"
+ }
+ },
+ "@turf/angle": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/angle/-/angle-6.5.0.tgz",
+ "integrity": "sha512-4pXMbWhFofJJAOvTMCns6N4C8CMd5Ih4O2jSAG9b3dDHakj3O4yN1+Zbm+NUei+eVEZ9gFeVp9svE3aMDenIkw==",
+ "requires": {
+ "@turf/bearing": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "@turf/rhumb-bearing": "^6.5.0"
+ }
+ },
+ "@turf/area": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/area/-/area-6.5.0.tgz",
+ "integrity": "sha512-xCZdiuojokLbQ+29qR6qoMD89hv+JAgWjLrwSEWL+3JV8IXKeNFl6XkEJz9HGkVpnXvQKJoRz4/liT+8ZZ5Jyg==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/meta": "^6.5.0"
+ }
+ },
+ "@turf/bbox": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/bbox/-/bbox-6.5.0.tgz",
+ "integrity": "sha512-RBbLaao5hXTYyyg577iuMtDB8ehxMlUqHEJiMs8jT1GHkFhr6sYre3lmLsPeYEi/ZKj5TP5tt7fkzNdJ4GIVyw==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/meta": "^6.5.0"
+ }
+ },
+ "@turf/bbox-clip": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/bbox-clip/-/bbox-clip-6.5.0.tgz",
+ "integrity": "sha512-F6PaIRF8WMp8EmgU/Ke5B1Y6/pia14UAYB5TiBC668w5rVVjy5L8rTm/m2lEkkDMHlzoP9vNY4pxpNthE7rLcQ==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0"
+ }
+ },
+ "@turf/bbox-polygon": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/bbox-polygon/-/bbox-polygon-6.5.0.tgz",
+ "integrity": "sha512-+/r0NyL1lOG3zKZmmf6L8ommU07HliP4dgYToMoTxqzsWzyLjaj/OzgQ8rBmv703WJX+aS6yCmLuIhYqyufyuw==",
+ "requires": {
+ "@turf/helpers": "^6.5.0"
+ }
+ },
+ "@turf/bearing": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/bearing/-/bearing-6.5.0.tgz",
+ "integrity": "sha512-dxINYhIEMzgDOztyMZc20I7ssYVNEpSv04VbMo5YPQsqa80KO3TFvbuCahMsCAW5z8Tncc8dwBlEFrmRjJG33A==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0"
+ }
+ },
+ "@turf/bezier-spline": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/bezier-spline/-/bezier-spline-6.5.0.tgz",
+ "integrity": "sha512-vokPaurTd4PF96rRgGVm6zYYC5r1u98ZsG+wZEv9y3kJTuJRX/O3xIY2QnTGTdbVmAJN1ouOsD0RoZYaVoXORQ==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0"
+ }
+ },
+ "@turf/boolean-clockwise": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/boolean-clockwise/-/boolean-clockwise-6.5.0.tgz",
+ "integrity": "sha512-45+C7LC5RMbRWrxh3Z0Eihsc8db1VGBO5d9BLTOAwU4jR6SgsunTfRWR16X7JUwIDYlCVEmnjcXJNi/kIU3VIw==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0"
+ }
+ },
+ "@turf/boolean-contains": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/boolean-contains/-/boolean-contains-6.5.0.tgz",
+ "integrity": "sha512-4m8cJpbw+YQcKVGi8y0cHhBUnYT+QRfx6wzM4GI1IdtYH3p4oh/DOBJKrepQyiDzFDaNIjxuWXBh0ai1zVwOQQ==",
+ "requires": {
+ "@turf/bbox": "^6.5.0",
+ "@turf/boolean-point-in-polygon": "^6.5.0",
+ "@turf/boolean-point-on-line": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0"
+ }
+ },
+ "@turf/boolean-crosses": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/boolean-crosses/-/boolean-crosses-6.5.0.tgz",
+ "integrity": "sha512-gvshbTPhAHporTlQwBJqyfW+2yV8q/mOTxG6PzRVl6ARsqNoqYQWkd4MLug7OmAqVyBzLK3201uAeBjxbGw0Ng==",
+ "requires": {
+ "@turf/boolean-point-in-polygon": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "@turf/line-intersect": "^6.5.0",
+ "@turf/polygon-to-line": "^6.5.0"
+ }
+ },
+ "@turf/boolean-disjoint": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/boolean-disjoint/-/boolean-disjoint-6.5.0.tgz",
+ "integrity": "sha512-rZ2ozlrRLIAGo2bjQ/ZUu4oZ/+ZjGvLkN5CKXSKBcu6xFO6k2bgqeM8a1836tAW+Pqp/ZFsTA5fZHsJZvP2D5g==",
+ "requires": {
+ "@turf/boolean-point-in-polygon": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/line-intersect": "^6.5.0",
+ "@turf/meta": "^6.5.0",
+ "@turf/polygon-to-line": "^6.5.0"
+ }
+ },
+ "@turf/boolean-equal": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/boolean-equal/-/boolean-equal-6.5.0.tgz",
+ "integrity": "sha512-cY0M3yoLC26mhAnjv1gyYNQjn7wxIXmL2hBmI/qs8g5uKuC2hRWi13ydufE3k4x0aNRjFGlg41fjoYLwaVF+9Q==",
+ "requires": {
+ "@turf/clean-coords": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "geojson-equality": "0.1.6"
+ }
+ },
+ "@turf/boolean-intersects": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/boolean-intersects/-/boolean-intersects-6.5.0.tgz",
+ "integrity": "sha512-nIxkizjRdjKCYFQMnml6cjPsDOBCThrt+nkqtSEcxkKMhAQj5OO7o2CecioNTaX8EayqwMGVKcsz27oP4mKPTw==",
+ "requires": {
+ "@turf/boolean-disjoint": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/meta": "^6.5.0"
+ }
+ },
+ "@turf/boolean-overlap": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/boolean-overlap/-/boolean-overlap-6.5.0.tgz",
+ "integrity": "sha512-8btMIdnbXVWUa1M7D4shyaSGxLRw6NjMcqKBcsTXcZdnaixl22k7ar7BvIzkaRYN3SFECk9VGXfLncNS3ckQUw==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "@turf/line-intersect": "^6.5.0",
+ "@turf/line-overlap": "^6.5.0",
+ "@turf/meta": "^6.5.0",
+ "geojson-equality": "0.1.6"
+ }
+ },
+ "@turf/boolean-parallel": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/boolean-parallel/-/boolean-parallel-6.5.0.tgz",
+ "integrity": "sha512-aSHJsr1nq9e5TthZGZ9CZYeXklJyRgR5kCLm5X4urz7+MotMOp/LsGOsvKvK9NeUl9+8OUmfMn8EFTT8LkcvIQ==",
+ "requires": {
+ "@turf/clean-coords": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/line-segment": "^6.5.0",
+ "@turf/rhumb-bearing": "^6.5.0"
+ }
+ },
+ "@turf/boolean-point-in-polygon": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/boolean-point-in-polygon/-/boolean-point-in-polygon-6.5.0.tgz",
+ "integrity": "sha512-DtSuVFB26SI+hj0SjrvXowGTUCHlgevPAIsukssW6BG5MlNSBQAo70wpICBNJL6RjukXg8d2eXaAWuD/CqL00A==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0"
+ }
+ },
+ "@turf/boolean-point-on-line": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/boolean-point-on-line/-/boolean-point-on-line-6.5.0.tgz",
+ "integrity": "sha512-A1BbuQ0LceLHvq7F/P7w3QvfpmZqbmViIUPHdNLvZimFNLo4e6IQunmzbe+8aSStH9QRZm3VOflyvNeXvvpZEQ==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0"
+ }
+ },
+ "@turf/boolean-within": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/boolean-within/-/boolean-within-6.5.0.tgz",
+ "integrity": "sha512-YQB3oU18Inx35C/LU930D36RAVe7LDXk1kWsQ8mLmuqYn9YdPsDQTMTkLJMhoQ8EbN7QTdy333xRQ4MYgToteQ==",
+ "requires": {
+ "@turf/bbox": "^6.5.0",
+ "@turf/boolean-point-in-polygon": "^6.5.0",
+ "@turf/boolean-point-on-line": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0"
+ }
+ },
+ "@turf/buffer": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/buffer/-/buffer-6.5.0.tgz",
+ "integrity": "sha512-qeX4N6+PPWbKqp1AVkBVWFerGjMYMUyencwfnkCesoznU6qvfugFHNAngNqIBVnJjZ5n8IFyOf+akcxnrt9sNg==",
+ "requires": {
+ "@turf/bbox": "^6.5.0",
+ "@turf/center": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/meta": "^6.5.0",
+ "@turf/projection": "^6.5.0",
+ "d3-geo": "1.7.1",
+ "turf-jsts": "*"
+ },
+ "dependencies": {
+ "d3-array": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz",
+ "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw=="
+ },
+ "d3-geo": {
+ "version": "1.7.1",
+ "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.7.1.tgz",
+ "integrity": "sha512-O4AempWAr+P5qbk2bC2FuN/sDW4z+dN2wDf9QV3bxQt4M5HfOEeXLgJ/UKQW0+o1Dj8BE+L5kiDbdWUMjsmQpw==",
+ "requires": {
+ "d3-array": "1"
+ }
+ }
+ }
+ },
+ "@turf/center": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/center/-/center-6.5.0.tgz",
+ "integrity": "sha512-T8KtMTfSATWcAX088rEDKjyvQCBkUsLnK/Txb6/8WUXIeOZyHu42G7MkdkHRoHtwieLdduDdmPLFyTdG5/e7ZQ==",
+ "requires": {
+ "@turf/bbox": "^6.5.0",
+ "@turf/helpers": "^6.5.0"
+ }
+ },
+ "@turf/center-mean": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/center-mean/-/center-mean-6.5.0.tgz",
+ "integrity": "sha512-AAX6f4bVn12pTVrMUiB9KrnV94BgeBKpyg3YpfnEbBpkN/znfVhL8dG8IxMAxAoSZ61Zt9WLY34HfENveuOZ7Q==",
+ "requires": {
+ "@turf/bbox": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/meta": "^6.5.0"
+ }
+ },
+ "@turf/center-median": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/center-median/-/center-median-6.5.0.tgz",
+ "integrity": "sha512-dT8Ndu5CiZkPrj15PBvslpuf01ky41DEYEPxS01LOxp5HOUHXp1oJxsPxvc+i/wK4BwccPNzU1vzJ0S4emd1KQ==",
+ "requires": {
+ "@turf/center-mean": "^6.5.0",
+ "@turf/centroid": "^6.5.0",
+ "@turf/distance": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/meta": "^6.5.0"
+ }
+ },
+ "@turf/center-of-mass": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/center-of-mass/-/center-of-mass-6.5.0.tgz",
+ "integrity": "sha512-EWrriU6LraOfPN7m1jZi+1NLTKNkuIsGLZc2+Y8zbGruvUW+QV7K0nhf7iZWutlxHXTBqEXHbKue/o79IumAsQ==",
+ "requires": {
+ "@turf/centroid": "^6.5.0",
+ "@turf/convex": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "@turf/meta": "^6.5.0"
+ }
+ },
+ "@turf/centroid": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/centroid/-/centroid-6.5.0.tgz",
+ "integrity": "sha512-MwE1oq5E3isewPprEClbfU5pXljIK/GUOMbn22UM3IFPDJX0KeoyLNwghszkdmFp/qMGL/M13MMWvU+GNLXP/A==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/meta": "^6.5.0"
+ }
+ },
+ "@turf/circle": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/circle/-/circle-6.5.0.tgz",
+ "integrity": "sha512-oU1+Kq9DgRnoSbWFHKnnUdTmtcRUMmHoV9DjTXu9vOLNV5OWtAAh1VZ+mzsioGGzoDNT/V5igbFOkMfBQc0B6A==",
+ "requires": {
+ "@turf/destination": "^6.5.0",
+ "@turf/helpers": "^6.5.0"
+ }
+ },
+ "@turf/clean-coords": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/clean-coords/-/clean-coords-6.5.0.tgz",
+ "integrity": "sha512-EMX7gyZz0WTH/ET7xV8MyrExywfm9qUi0/MY89yNffzGIEHuFfqwhcCqZ8O00rZIPZHUTxpmsxQSTfzJJA1CPw==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0"
+ }
+ },
+ "@turf/clone": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/clone/-/clone-6.5.0.tgz",
+ "integrity": "sha512-mzVtTFj/QycXOn6ig+annKrM6ZlimreKYz6f/GSERytOpgzodbQyOgkfwru100O1KQhhjSudKK4DsQ0oyi9cTw==",
+ "requires": {
+ "@turf/helpers": "^6.5.0"
+ }
+ },
+ "@turf/clusters": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/clusters/-/clusters-6.5.0.tgz",
+ "integrity": "sha512-Y6gfnTJzQ1hdLfCsyd5zApNbfLIxYEpmDibHUqR5z03Lpe02pa78JtgrgUNt1seeO/aJ4TG1NLN8V5gOrHk04g==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/meta": "^6.5.0"
+ }
+ },
+ "@turf/clusters-dbscan": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/clusters-dbscan/-/clusters-dbscan-6.5.0.tgz",
+ "integrity": "sha512-SxZEE4kADU9DqLRiT53QZBBhu8EP9skviSyl+FGj08Y01xfICM/RR9ACUdM0aEQimhpu+ZpRVcUK+2jtiCGrYQ==",
+ "requires": {
+ "@turf/clone": "^6.5.0",
+ "@turf/distance": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/meta": "^6.5.0",
+ "density-clustering": "1.3.0"
+ }
+ },
+ "@turf/clusters-kmeans": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/clusters-kmeans/-/clusters-kmeans-6.5.0.tgz",
+ "integrity": "sha512-DwacD5+YO8kwDPKaXwT9DV46tMBVNsbi1IzdajZu1JDSWoN7yc7N9Qt88oi+p30583O0UPVkAK+A10WAQv4mUw==",
+ "requires": {
+ "@turf/clone": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "@turf/meta": "^6.5.0",
+ "skmeans": "0.9.7"
+ }
+ },
+ "@turf/collect": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/collect/-/collect-6.5.0.tgz",
+ "integrity": "sha512-4dN/T6LNnRg099m97BJeOcTA5fSI8cu87Ydgfibewd2KQwBexO69AnjEFqfPX3Wj+Zvisj1uAVIZbPmSSrZkjg==",
+ "requires": {
+ "@turf/bbox": "^6.5.0",
+ "@turf/boolean-point-in-polygon": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "rbush": "2.x"
+ },
+ "dependencies": {
+ "quickselect": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-1.1.1.tgz",
+ "integrity": "sha512-qN0Gqdw4c4KGPsBOQafj6yj/PA6c/L63f6CaZ/DCF/xF4Esu3jVmKLUDYxghFx8Kb/O7y9tI7x2RjTSXwdK1iQ=="
+ },
+ "rbush": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/rbush/-/rbush-2.0.2.tgz",
+ "integrity": "sha512-XBOuALcTm+O/H8G90b6pzu6nX6v2zCKiFG4BJho8a+bY6AER6t8uQUZdi5bomQc0AprCWhEGa7ncAbbRap0bRA==",
+ "requires": {
+ "quickselect": "^1.0.1"
+ }
+ }
+ }
+ },
+ "@turf/combine": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/combine/-/combine-6.5.0.tgz",
+ "integrity": "sha512-Q8EIC4OtAcHiJB3C4R+FpB4LANiT90t17uOd851qkM2/o6m39bfN5Mv0PWqMZIHWrrosZqRqoY9dJnzz/rJxYQ==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/meta": "^6.5.0"
+ }
+ },
+ "@turf/concave": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/concave/-/concave-6.5.0.tgz",
+ "integrity": "sha512-I/sUmUC8TC5h/E2vPwxVht+nRt+TnXIPRoztDFvS8/Y0+cBDple9inLSo9nnPXMXidrBlGXZ9vQx/BjZUJgsRQ==",
+ "requires": {
+ "@turf/clone": "^6.5.0",
+ "@turf/distance": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "@turf/meta": "^6.5.0",
+ "@turf/tin": "^6.5.0",
+ "topojson-client": "3.x",
+ "topojson-server": "3.x"
+ }
+ },
+ "@turf/convex": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/convex/-/convex-6.5.0.tgz",
+ "integrity": "sha512-x7ZwC5z7PJB0SBwNh7JCeCNx7Iu+QSrH7fYgK0RhhNop13TqUlvHMirMLRgf2db1DqUetrAO2qHJeIuasquUWg==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/meta": "^6.5.0",
+ "concaveman": "*"
+ }
+ },
+ "@turf/destination": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/destination/-/destination-6.5.0.tgz",
+ "integrity": "sha512-4cnWQlNC8d1tItOz9B4pmJdWpXqS0vEvv65bI/Pj/genJnsL7evI0/Xw42RvEGROS481MPiU80xzvwxEvhQiMQ==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0"
+ }
+ },
+ "@turf/difference": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/difference/-/difference-6.5.0.tgz",
+ "integrity": "sha512-l8iR5uJqvI+5Fs6leNbhPY5t/a3vipUF/3AeVLpwPQcgmedNXyheYuy07PcMGH5Jdpi5gItOiTqwiU/bUH4b3A==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "polygon-clipping": "^0.15.3"
+ }
+ },
+ "@turf/dissolve": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/dissolve/-/dissolve-6.5.0.tgz",
+ "integrity": "sha512-WBVbpm9zLTp0Bl9CE35NomTaOL1c4TQCtEoO43YaAhNEWJOOIhZMFJyr8mbvYruKl817KinT3x7aYjjCMjTAsQ==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "@turf/meta": "^6.5.0",
+ "polygon-clipping": "^0.15.3"
+ }
+ },
+ "@turf/distance": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/distance/-/distance-6.5.0.tgz",
+ "integrity": "sha512-xzykSLfoURec5qvQJcfifw/1mJa+5UwByZZ5TZ8iaqjGYN0vomhV9aiSLeYdUGtYRESZ+DYC/OzY+4RclZYgMg==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0"
+ }
+ },
+ "@turf/distance-weight": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/distance-weight/-/distance-weight-6.5.0.tgz",
+ "integrity": "sha512-a8qBKkgVNvPKBfZfEJZnC3DV7dfIsC3UIdpRci/iap/wZLH41EmS90nM+BokAJflUHYy8PqE44wySGWHN1FXrQ==",
+ "requires": {
+ "@turf/centroid": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "@turf/meta": "^6.5.0"
+ }
+ },
+ "@turf/ellipse": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/ellipse/-/ellipse-6.5.0.tgz",
+ "integrity": "sha512-kuXtwFviw/JqnyJXF1mrR/cb496zDTSbGKtSiolWMNImYzGGkbsAsFTjwJYgD7+4FixHjp0uQPzo70KDf3AIBw==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "@turf/rhumb-destination": "^6.5.0",
+ "@turf/transform-rotate": "^6.5.0"
+ }
+ },
+ "@turf/envelope": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/envelope/-/envelope-6.5.0.tgz",
+ "integrity": "sha512-9Z+FnBWvOGOU4X+fMZxYFs1HjFlkKqsddLuMknRaqcJd6t+NIv5DWvPtDL8ATD2GEExYDiFLwMdckfr1yqJgHA==",
+ "requires": {
+ "@turf/bbox": "^6.5.0",
+ "@turf/bbox-polygon": "^6.5.0",
+ "@turf/helpers": "^6.5.0"
+ }
+ },
+ "@turf/explode": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/explode/-/explode-6.5.0.tgz",
+ "integrity": "sha512-6cSvMrnHm2qAsace6pw9cDmK2buAlw8+tjeJVXMfMyY+w7ZUi1rprWMsY92J7s2Dar63Bv09n56/1V7+tcj52Q==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/meta": "^6.5.0"
+ }
+ },
+ "@turf/flatten": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/flatten/-/flatten-6.5.0.tgz",
+ "integrity": "sha512-IBZVwoNLVNT6U/bcUUllubgElzpMsNoCw8tLqBw6dfYg9ObGmpEjf9BIYLr7a2Yn5ZR4l7YIj2T7kD5uJjZADQ==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/meta": "^6.5.0"
+ }
+ },
+ "@turf/flip": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/flip/-/flip-6.5.0.tgz",
+ "integrity": "sha512-oyikJFNjt2LmIXQqgOGLvt70RgE2lyzPMloYWM7OR5oIFGRiBvqVD2hA6MNw6JewIm30fWZ8DQJw1NHXJTJPbg==",
+ "requires": {
+ "@turf/clone": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/meta": "^6.5.0"
+ }
+ },
+ "@turf/great-circle": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/great-circle/-/great-circle-6.5.0.tgz",
+ "integrity": "sha512-7ovyi3HaKOXdFyN7yy1yOMa8IyOvV46RC1QOQTT+RYUN8ke10eyqExwBpL9RFUPvlpoTzoYbM/+lWPogQlFncg==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0"
+ }
+ },
+ "@turf/helpers": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-6.5.0.tgz",
+ "integrity": "sha512-VbI1dV5bLFzohYYdgqwikdMVpe7pJ9X3E+dlr425wa2/sMJqYDhTO++ec38/pcPvPE6oD9WEEeU3Xu3gza+VPw=="
+ },
+ "@turf/hex-grid": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/hex-grid/-/hex-grid-6.5.0.tgz",
+ "integrity": "sha512-Ln3tc2tgZT8etDOldgc6e741Smg1CsMKAz1/Mlel+MEL5Ynv2mhx3m0q4J9IB1F3a4MNjDeVvm8drAaf9SF33g==",
+ "requires": {
+ "@turf/distance": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/intersect": "^6.5.0",
+ "@turf/invariant": "^6.5.0"
+ }
+ },
+ "@turf/interpolate": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/interpolate/-/interpolate-6.5.0.tgz",
+ "integrity": "sha512-LSH5fMeiGyuDZ4WrDJNgh81d2DnNDUVJtuFryJFup8PV8jbs46lQGfI3r1DJ2p1IlEJIz3pmAZYeTfMMoeeohw==",
+ "requires": {
+ "@turf/bbox": "^6.5.0",
+ "@turf/centroid": "^6.5.0",
+ "@turf/clone": "^6.5.0",
+ "@turf/distance": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/hex-grid": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "@turf/meta": "^6.5.0",
+ "@turf/point-grid": "^6.5.0",
+ "@turf/square-grid": "^6.5.0",
+ "@turf/triangle-grid": "^6.5.0"
+ }
+ },
+ "@turf/intersect": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/intersect/-/intersect-6.5.0.tgz",
+ "integrity": "sha512-2legGJeKrfFkzntcd4GouPugoqPUjexPZnOvfez+3SfIMrHvulw8qV8u7pfVyn2Yqs53yoVCEjS5sEpvQ5YRQg==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "polygon-clipping": "^0.15.3"
+ }
+ },
+ "@turf/invariant": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-6.5.0.tgz",
+ "integrity": "sha512-Wv8PRNCtPD31UVbdJE/KVAWKe7l6US+lJItRR/HOEW3eh+U/JwRCSUl/KZ7bmjM/C+zLNoreM2TU6OoLACs4eg==",
+ "requires": {
+ "@turf/helpers": "^6.5.0"
+ }
+ },
+ "@turf/isobands": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/isobands/-/isobands-6.5.0.tgz",
+ "integrity": "sha512-4h6sjBPhRwMVuFaVBv70YB7eGz+iw0bhPRnp+8JBdX1UPJSXhoi/ZF2rACemRUr0HkdVB/a1r9gC32vn5IAEkw==",
+ "requires": {
+ "@turf/area": "^6.5.0",
+ "@turf/bbox": "^6.5.0",
+ "@turf/boolean-point-in-polygon": "^6.5.0",
+ "@turf/explode": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "@turf/meta": "^6.5.0",
+ "object-assign": "*"
+ }
+ },
+ "@turf/isolines": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/isolines/-/isolines-6.5.0.tgz",
+ "integrity": "sha512-6ElhiLCopxWlv4tPoxiCzASWt/jMRvmp6mRYrpzOm3EUl75OhHKa/Pu6Y9nWtCMmVC/RcWtiiweUocbPLZLm0A==",
+ "requires": {
+ "@turf/bbox": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "@turf/meta": "^6.5.0",
+ "object-assign": "*"
+ }
+ },
+ "@turf/kinks": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/kinks/-/kinks-6.5.0.tgz",
+ "integrity": "sha512-ViCngdPt1eEL7hYUHR2eHR662GvCgTc35ZJFaNR6kRtr6D8plLaDju0FILeFFWSc+o8e3fwxZEJKmFj9IzPiIQ==",
+ "requires": {
+ "@turf/helpers": "^6.5.0"
+ }
+ },
+ "@turf/length": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/length/-/length-6.5.0.tgz",
+ "integrity": "sha512-5pL5/pnw52fck3oRsHDcSGrj9HibvtlrZ0QNy2OcW8qBFDNgZ4jtl6U7eATVoyWPKBHszW3dWETW+iLV7UARig==",
+ "requires": {
+ "@turf/distance": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/meta": "^6.5.0"
+ }
+ },
+ "@turf/line-arc": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/line-arc/-/line-arc-6.5.0.tgz",
+ "integrity": "sha512-I6c+V6mIyEwbtg9P9zSFF89T7QPe1DPTG3MJJ6Cm1MrAY0MdejwQKOpsvNl8LDU2ekHOlz2kHpPVR7VJsoMllA==",
+ "requires": {
+ "@turf/circle": "^6.5.0",
+ "@turf/destination": "^6.5.0",
+ "@turf/helpers": "^6.5.0"
+ }
+ },
+ "@turf/line-chunk": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/line-chunk/-/line-chunk-6.5.0.tgz",
+ "integrity": "sha512-i1FGE6YJaaYa+IJesTfyRRQZP31QouS+wh/pa6O3CC0q4T7LtHigyBSYjrbjSLfn2EVPYGlPCMFEqNWCOkC6zg==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/length": "^6.5.0",
+ "@turf/line-slice-along": "^6.5.0",
+ "@turf/meta": "^6.5.0"
+ }
+ },
+ "@turf/line-intersect": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/line-intersect/-/line-intersect-6.5.0.tgz",
+ "integrity": "sha512-CS6R1tZvVQD390G9Ea4pmpM6mJGPWoL82jD46y0q1KSor9s6HupMIo1kY4Ny+AEYQl9jd21V3Scz20eldpbTVA==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "@turf/line-segment": "^6.5.0",
+ "@turf/meta": "^6.5.0",
+ "geojson-rbush": "3.x"
+ }
+ },
+ "@turf/line-offset": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/line-offset/-/line-offset-6.5.0.tgz",
+ "integrity": "sha512-CEXZbKgyz8r72qRvPchK0dxqsq8IQBdH275FE6o4MrBkzMcoZsfSjghtXzKaz9vvro+HfIXal0sTk2mqV1lQTw==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "@turf/meta": "^6.5.0"
+ }
+ },
+ "@turf/line-overlap": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/line-overlap/-/line-overlap-6.5.0.tgz",
+ "integrity": "sha512-xHOaWLd0hkaC/1OLcStCpfq55lPHpPNadZySDXYiYjEz5HXr1oKmtMYpn0wGizsLwrOixRdEp+j7bL8dPt4ojQ==",
+ "requires": {
+ "@turf/boolean-point-on-line": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "@turf/line-segment": "^6.5.0",
+ "@turf/meta": "^6.5.0",
+ "@turf/nearest-point-on-line": "^6.5.0",
+ "deep-equal": "1.x",
+ "geojson-rbush": "3.x"
+ }
+ },
+ "@turf/line-segment": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/line-segment/-/line-segment-6.5.0.tgz",
+ "integrity": "sha512-jI625Ho4jSuJESNq66Mmi290ZJ5pPZiQZruPVpmHkUw257Pew0alMmb6YrqYNnLUuiVVONxAAKXUVeeUGtycfw==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "@turf/meta": "^6.5.0"
+ }
+ },
+ "@turf/line-slice": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/line-slice/-/line-slice-6.5.0.tgz",
+ "integrity": "sha512-vDqJxve9tBHhOaVVFXqVjF5qDzGtKWviyjbyi2QnSnxyFAmLlLnBfMX8TLQCAf2GxHibB95RO5FBE6I2KVPRuw==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "@turf/nearest-point-on-line": "^6.5.0"
+ }
+ },
+ "@turf/line-slice-along": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/line-slice-along/-/line-slice-along-6.5.0.tgz",
+ "integrity": "sha512-KHJRU6KpHrAj+BTgTNqby6VCTnDzG6a1sJx/I3hNvqMBLvWVA2IrkR9L9DtsQsVY63IBwVdQDqiwCuZLDQh4Ng==",
+ "requires": {
+ "@turf/bearing": "^6.5.0",
+ "@turf/destination": "^6.5.0",
+ "@turf/distance": "^6.5.0",
+ "@turf/helpers": "^6.5.0"
+ }
+ },
+ "@turf/line-split": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/line-split/-/line-split-6.5.0.tgz",
+ "integrity": "sha512-/rwUMVr9OI2ccJjw7/6eTN53URtGThNSD5I0GgxyFXMtxWiloRJ9MTff8jBbtPWrRka/Sh2GkwucVRAEakx9Sw==",
+ "requires": {
+ "@turf/bbox": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "@turf/line-intersect": "^6.5.0",
+ "@turf/line-segment": "^6.5.0",
+ "@turf/meta": "^6.5.0",
+ "@turf/nearest-point-on-line": "^6.5.0",
+ "@turf/square": "^6.5.0",
+ "@turf/truncate": "^6.5.0",
+ "geojson-rbush": "3.x"
+ }
+ },
+ "@turf/line-to-polygon": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/line-to-polygon/-/line-to-polygon-6.5.0.tgz",
+ "integrity": "sha512-qYBuRCJJL8Gx27OwCD1TMijM/9XjRgXH/m/TyuND4OXedBpIWlK5VbTIO2gJ8OCfznBBddpjiObLBrkuxTpN4Q==",
+ "requires": {
+ "@turf/bbox": "^6.5.0",
+ "@turf/clone": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0"
+ }
+ },
+ "@turf/mask": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/mask/-/mask-6.5.0.tgz",
+ "integrity": "sha512-RQha4aU8LpBrmrkH8CPaaoAfk0Egj5OuXtv6HuCQnHeGNOQt3TQVibTA3Sh4iduq4EPxnZfDjgsOeKtrCA19lg==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "polygon-clipping": "^0.15.3"
+ }
+ },
+ "@turf/meta": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-6.5.0.tgz",
+ "integrity": "sha512-RrArvtsV0vdsCBegoBtOalgdSOfkBrTJ07VkpiCnq/491W67hnMWmDu7e6Ztw0C3WldRYTXkg3SumfdzZxLBHA==",
+ "requires": {
+ "@turf/helpers": "^6.5.0"
+ }
+ },
+ "@turf/midpoint": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/midpoint/-/midpoint-6.5.0.tgz",
+ "integrity": "sha512-MyTzV44IwmVI6ec9fB2OgZ53JGNlgOpaYl9ArKoF49rXpL84F9rNATndbe0+MQIhdkw8IlzA6xVP4lZzfMNVCw==",
+ "requires": {
+ "@turf/bearing": "^6.5.0",
+ "@turf/destination": "^6.5.0",
+ "@turf/distance": "^6.5.0",
+ "@turf/helpers": "^6.5.0"
+ }
+ },
+ "@turf/moran-index": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/moran-index/-/moran-index-6.5.0.tgz",
+ "integrity": "sha512-ItsnhrU2XYtTtTudrM8so4afBCYWNaB0Mfy28NZwLjB5jWuAsvyV+YW+J88+neK/ougKMTawkmjQqodNJaBeLQ==",
+ "requires": {
+ "@turf/distance-weight": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/meta": "^6.5.0"
+ }
+ },
+ "@turf/nearest-point": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/nearest-point/-/nearest-point-6.5.0.tgz",
+ "integrity": "sha512-fguV09QxilZv/p94s8SMsXILIAMiaXI5PATq9d7YWijLxWUj6Q/r43kxyoi78Zmwwh1Zfqz9w+bCYUAxZ5+euA==",
+ "requires": {
+ "@turf/clone": "^6.5.0",
+ "@turf/distance": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/meta": "^6.5.0"
+ }
+ },
+ "@turf/nearest-point-on-line": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/nearest-point-on-line/-/nearest-point-on-line-6.5.0.tgz",
+ "integrity": "sha512-WthrvddddvmymnC+Vf7BrkHGbDOUu6Z3/6bFYUGv1kxw8tiZ6n83/VG6kHz4poHOfS0RaNflzXSkmCi64fLBlg==",
+ "requires": {
+ "@turf/bearing": "^6.5.0",
+ "@turf/destination": "^6.5.0",
+ "@turf/distance": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "@turf/line-intersect": "^6.5.0",
+ "@turf/meta": "^6.5.0"
+ }
+ },
+ "@turf/nearest-point-to-line": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/nearest-point-to-line/-/nearest-point-to-line-6.5.0.tgz",
+ "integrity": "sha512-PXV7cN0BVzUZdjj6oeb/ESnzXSfWmEMrsfZSDRgqyZ9ytdiIj/eRsnOXLR13LkTdXVOJYDBuf7xt1mLhM4p6+Q==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "@turf/meta": "^6.5.0",
+ "@turf/point-to-line-distance": "^6.5.0",
+ "object-assign": "*"
+ }
+ },
+ "@turf/planepoint": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/planepoint/-/planepoint-6.5.0.tgz",
+ "integrity": "sha512-R3AahA6DUvtFbka1kcJHqZ7DMHmPXDEQpbU5WaglNn7NaCQg9HB0XM0ZfqWcd5u92YXV+Gg8QhC8x5XojfcM4Q==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0"
+ }
+ },
+ "@turf/point-grid": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/point-grid/-/point-grid-6.5.0.tgz",
+ "integrity": "sha512-Iq38lFokNNtQJnOj/RBKmyt6dlof0yhaHEDELaWHuECm1lIZLY3ZbVMwbs+nXkwTAHjKfS/OtMheUBkw+ee49w==",
+ "requires": {
+ "@turf/boolean-within": "^6.5.0",
+ "@turf/distance": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0"
+ }
+ },
+ "@turf/point-on-feature": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/point-on-feature/-/point-on-feature-6.5.0.tgz",
+ "integrity": "sha512-bDpuIlvugJhfcF/0awAQ+QI6Om1Y1FFYE8Y/YdxGRongivix850dTeXCo0mDylFdWFPGDo7Mmh9Vo4VxNwW/TA==",
+ "requires": {
+ "@turf/boolean-point-in-polygon": "^6.5.0",
+ "@turf/center": "^6.5.0",
+ "@turf/explode": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/nearest-point": "^6.5.0"
+ }
+ },
+ "@turf/point-to-line-distance": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/point-to-line-distance/-/point-to-line-distance-6.5.0.tgz",
+ "integrity": "sha512-opHVQ4vjUhNBly1bob6RWy+F+hsZDH9SA0UW36pIRzfpu27qipU18xup0XXEePfY6+wvhF6yL/WgCO2IbrLqEA==",
+ "requires": {
+ "@turf/bearing": "^6.5.0",
+ "@turf/distance": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "@turf/meta": "^6.5.0",
+ "@turf/projection": "^6.5.0",
+ "@turf/rhumb-bearing": "^6.5.0",
+ "@turf/rhumb-distance": "^6.5.0"
+ }
+ },
+ "@turf/points-within-polygon": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/points-within-polygon/-/points-within-polygon-6.5.0.tgz",
+ "integrity": "sha512-YyuheKqjliDsBDt3Ho73QVZk1VXX1+zIA2gwWvuz8bR1HXOkcuwk/1J76HuFMOQI3WK78wyAi+xbkx268PkQzQ==",
+ "requires": {
+ "@turf/boolean-point-in-polygon": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/meta": "^6.5.0"
+ }
+ },
+ "@turf/polygon-smooth": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/polygon-smooth/-/polygon-smooth-6.5.0.tgz",
+ "integrity": "sha512-LO/X/5hfh/Rk4EfkDBpLlVwt3i6IXdtQccDT9rMjXEP32tRgy0VMFmdkNaXoGlSSKf/1mGqLl4y4wHd86DqKbg==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/meta": "^6.5.0"
+ }
+ },
+ "@turf/polygon-tangents": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/polygon-tangents/-/polygon-tangents-6.5.0.tgz",
+ "integrity": "sha512-sB4/IUqJMYRQH9jVBwqS/XDitkEfbyqRy+EH/cMRJURTg78eHunvJ708x5r6umXsbiUyQU4eqgPzEylWEQiunw==",
+ "requires": {
+ "@turf/bbox": "^6.5.0",
+ "@turf/boolean-within": "^6.5.0",
+ "@turf/explode": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "@turf/nearest-point": "^6.5.0"
+ }
+ },
+ "@turf/polygon-to-line": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/polygon-to-line/-/polygon-to-line-6.5.0.tgz",
+ "integrity": "sha512-5p4n/ij97EIttAq+ewSnKt0ruvuM+LIDzuczSzuHTpq4oS7Oq8yqg5TQ4nzMVuK41r/tALCk7nAoBuw3Su4Gcw==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0"
+ }
+ },
+ "@turf/polygonize": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/polygonize/-/polygonize-6.5.0.tgz",
+ "integrity": "sha512-a/3GzHRaCyzg7tVYHo43QUChCspa99oK4yPqooVIwTC61npFzdrmnywMv0S+WZjHZwK37BrFJGFrZGf6ocmY5w==",
+ "requires": {
+ "@turf/boolean-point-in-polygon": "^6.5.0",
+ "@turf/envelope": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "@turf/meta": "^6.5.0"
+ }
+ },
+ "@turf/projection": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/projection/-/projection-6.5.0.tgz",
+ "integrity": "sha512-/Pgh9mDvQWWu8HRxqpM+tKz8OzgauV+DiOcr3FCjD6ubDnrrmMJlsf6fFJmggw93mtVPrZRL6yyi9aYCQBOIvg==",
+ "requires": {
+ "@turf/clone": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/meta": "^6.5.0"
+ }
+ },
+ "@turf/random": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/random/-/random-6.5.0.tgz",
+ "integrity": "sha512-8Q25gQ/XbA7HJAe+eXp4UhcXM9aOOJFaxZ02+XSNwMvY8gtWSCBLVqRcW4OhqilgZ8PeuQDWgBxeo+BIqqFWFQ==",
+ "requires": {
+ "@turf/helpers": "^6.5.0"
+ }
+ },
+ "@turf/rectangle-grid": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/rectangle-grid/-/rectangle-grid-6.5.0.tgz",
+ "integrity": "sha512-yQZ/1vbW68O2KsSB3OZYK+72aWz/Adnf7m2CMKcC+aq6TwjxZjAvlbCOsNUnMAuldRUVN1ph6RXMG4e9KEvKvg==",
+ "requires": {
+ "@turf/boolean-intersects": "^6.5.0",
+ "@turf/distance": "^6.5.0",
+ "@turf/helpers": "^6.5.0"
+ }
+ },
+ "@turf/rewind": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/rewind/-/rewind-6.5.0.tgz",
+ "integrity": "sha512-IoUAMcHWotBWYwSYuYypw/LlqZmO+wcBpn8ysrBNbazkFNkLf3btSDZMkKJO/bvOzl55imr/Xj4fi3DdsLsbzQ==",
+ "requires": {
+ "@turf/boolean-clockwise": "^6.5.0",
+ "@turf/clone": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "@turf/meta": "^6.5.0"
+ }
+ },
+ "@turf/rhumb-bearing": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/rhumb-bearing/-/rhumb-bearing-6.5.0.tgz",
+ "integrity": "sha512-jMyqiMRK4hzREjQmnLXmkJ+VTNTx1ii8vuqRwJPcTlKbNWfjDz/5JqJlb5NaFDcdMpftWovkW5GevfnuzHnOYA==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0"
+ }
+ },
+ "@turf/rhumb-destination": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/rhumb-destination/-/rhumb-destination-6.5.0.tgz",
+ "integrity": "sha512-RHNP1Oy+7xTTdRrTt375jOZeHceFbjwohPHlr9Hf68VdHHPMAWgAKqiX2YgSWDcvECVmiGaBKWus1Df+N7eE4Q==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0"
+ }
+ },
+ "@turf/rhumb-distance": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/rhumb-distance/-/rhumb-distance-6.5.0.tgz",
+ "integrity": "sha512-oKp8KFE8E4huC2Z1a1KNcFwjVOqa99isxNOwfo4g3SUABQ6NezjKDDrnvC4yI5YZ3/huDjULLBvhed45xdCrzg==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0"
+ }
+ },
+ "@turf/sample": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/sample/-/sample-6.5.0.tgz",
+ "integrity": "sha512-kSdCwY7el15xQjnXYW520heKUrHwRvnzx8ka4eYxX9NFeOxaFITLW2G7UtXb6LJK8mmPXI8Aexv23F2ERqzGFg==",
+ "requires": {
+ "@turf/helpers": "^6.5.0"
+ }
+ },
+ "@turf/sector": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/sector/-/sector-6.5.0.tgz",
+ "integrity": "sha512-cYUOkgCTWqa23SOJBqxoFAc/yGCUsPRdn/ovbRTn1zNTm/Spmk6hVB84LCKOgHqvSF25i0d2kWqpZDzLDdAPbw==",
+ "requires": {
+ "@turf/circle": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "@turf/line-arc": "^6.5.0",
+ "@turf/meta": "^6.5.0"
+ }
+ },
+ "@turf/shortest-path": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/shortest-path/-/shortest-path-6.5.0.tgz",
+ "integrity": "sha512-4de5+G7+P4hgSoPwn+SO9QSi9HY5NEV/xRJ+cmoFVRwv2CDsuOPDheHKeuIAhKyeKDvPvPt04XYWbac4insJMg==",
+ "requires": {
+ "@turf/bbox": "^6.5.0",
+ "@turf/bbox-polygon": "^6.5.0",
+ "@turf/boolean-point-in-polygon": "^6.5.0",
+ "@turf/clean-coords": "^6.5.0",
+ "@turf/distance": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "@turf/meta": "^6.5.0",
+ "@turf/transform-scale": "^6.5.0"
+ }
+ },
+ "@turf/simplify": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/simplify/-/simplify-6.5.0.tgz",
+ "integrity": "sha512-USas3QqffPHUY184dwQdP8qsvcVH/PWBYdXY5am7YTBACaQOMAlf6AKJs9FT8jiO6fQpxfgxuEtwmox+pBtlOg==",
+ "requires": {
+ "@turf/clean-coords": "^6.5.0",
+ "@turf/clone": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/meta": "^6.5.0"
+ }
+ },
+ "@turf/square": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/square/-/square-6.5.0.tgz",
+ "integrity": "sha512-BM2UyWDmiuHCadVhHXKIx5CQQbNCpOxB6S/aCNOCLbhCeypKX5Q0Aosc5YcmCJgkwO5BERCC6Ee7NMbNB2vHmQ==",
+ "requires": {
+ "@turf/distance": "^6.5.0",
+ "@turf/helpers": "^6.5.0"
+ }
+ },
+ "@turf/square-grid": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/square-grid/-/square-grid-6.5.0.tgz",
+ "integrity": "sha512-mlR0ayUdA+L4c9h7p4k3pX6gPWHNGuZkt2c5II1TJRmhLkW2557d6b/Vjfd1z9OVaajb1HinIs1FMSAPXuuUrA==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/rectangle-grid": "^6.5.0"
+ }
+ },
+ "@turf/standard-deviational-ellipse": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/standard-deviational-ellipse/-/standard-deviational-ellipse-6.5.0.tgz",
+ "integrity": "sha512-02CAlz8POvGPFK2BKK8uHGUk/LXb0MK459JVjKxLC2yJYieOBTqEbjP0qaWhiBhGzIxSMaqe8WxZ0KvqdnstHA==",
+ "requires": {
+ "@turf/center-mean": "^6.5.0",
+ "@turf/ellipse": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "@turf/meta": "^6.5.0",
+ "@turf/points-within-polygon": "^6.5.0"
+ }
+ },
+ "@turf/tag": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/tag/-/tag-6.5.0.tgz",
+ "integrity": "sha512-XwlBvrOV38CQsrNfrxvBaAPBQgXMljeU0DV8ExOyGM7/hvuGHJw3y8kKnQ4lmEQcmcrycjDQhP7JqoRv8vFssg==",
+ "requires": {
+ "@turf/boolean-point-in-polygon": "^6.5.0",
+ "@turf/clone": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/meta": "^6.5.0"
+ }
+ },
+ "@turf/tesselate": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/tesselate/-/tesselate-6.5.0.tgz",
+ "integrity": "sha512-M1HXuyZFCfEIIKkglh/r5L9H3c5QTEsnMBoZOFQiRnGPGmJWcaBissGb7mTFX2+DKE7FNWXh4TDnZlaLABB0dQ==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "earcut": "^2.0.0"
+ }
+ },
+ "@turf/tin": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/tin/-/tin-6.5.0.tgz",
+ "integrity": "sha512-YLYikRzKisfwj7+F+Tmyy/LE3d2H7D4kajajIfc9mlik2+esG7IolsX/+oUz1biguDYsG0DUA8kVYXDkobukfg==",
+ "requires": {
+ "@turf/helpers": "^6.5.0"
+ }
+ },
+ "@turf/transform-rotate": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/transform-rotate/-/transform-rotate-6.5.0.tgz",
+ "integrity": "sha512-A2Ip1v4246ZmpssxpcL0hhiVBEf4L8lGnSPWTgSv5bWBEoya2fa/0SnFX9xJgP40rMP+ZzRaCN37vLHbv1Guag==",
+ "requires": {
+ "@turf/centroid": "^6.5.0",
+ "@turf/clone": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "@turf/meta": "^6.5.0",
+ "@turf/rhumb-bearing": "^6.5.0",
+ "@turf/rhumb-destination": "^6.5.0",
+ "@turf/rhumb-distance": "^6.5.0"
+ }
+ },
+ "@turf/transform-scale": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/transform-scale/-/transform-scale-6.5.0.tgz",
+ "integrity": "sha512-VsATGXC9rYM8qTjbQJ/P7BswKWXHdnSJ35JlV4OsZyHBMxJQHftvmZJsFbOqVtQnIQIzf2OAly6rfzVV9QLr7g==",
+ "requires": {
+ "@turf/bbox": "^6.5.0",
+ "@turf/center": "^6.5.0",
+ "@turf/centroid": "^6.5.0",
+ "@turf/clone": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "@turf/meta": "^6.5.0",
+ "@turf/rhumb-bearing": "^6.5.0",
+ "@turf/rhumb-destination": "^6.5.0",
+ "@turf/rhumb-distance": "^6.5.0"
+ }
+ },
+ "@turf/transform-translate": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/transform-translate/-/transform-translate-6.5.0.tgz",
+ "integrity": "sha512-NABLw5VdtJt/9vSstChp93pc6oel4qXEos56RBMsPlYB8hzNTEKYtC146XJvyF4twJeeYS8RVe1u7KhoFwEM5w==",
+ "requires": {
+ "@turf/clone": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "@turf/meta": "^6.5.0",
+ "@turf/rhumb-destination": "^6.5.0"
+ }
+ },
+ "@turf/triangle-grid": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/triangle-grid/-/triangle-grid-6.5.0.tgz",
+ "integrity": "sha512-2jToUSAS1R1htq4TyLQYPTIsoy6wg3e3BQXjm2rANzw4wPQCXGOxrur1Fy9RtzwqwljlC7DF4tg0OnWr8RjmfA==",
+ "requires": {
+ "@turf/distance": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/intersect": "^6.5.0"
+ }
+ },
+ "@turf/truncate": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/truncate/-/truncate-6.5.0.tgz",
+ "integrity": "sha512-pFxg71pLk+eJj134Z9yUoRhIi8vqnnKvCYwdT4x/DQl/19RVdq1tV3yqOT3gcTQNfniteylL5qV1uTBDV5sgrg==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/meta": "^6.5.0"
+ }
+ },
+ "@turf/turf": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/turf/-/turf-6.5.0.tgz",
+ "integrity": "sha512-ipMCPnhu59bh92MNt8+pr1VZQhHVuTMHklciQURo54heoxRzt1neNYZOBR6jdL+hNsbDGAECMuIpAutX+a3Y+w==",
+ "requires": {
+ "@turf/along": "^6.5.0",
+ "@turf/angle": "^6.5.0",
+ "@turf/area": "^6.5.0",
+ "@turf/bbox": "^6.5.0",
+ "@turf/bbox-clip": "^6.5.0",
+ "@turf/bbox-polygon": "^6.5.0",
+ "@turf/bearing": "^6.5.0",
+ "@turf/bezier-spline": "^6.5.0",
+ "@turf/boolean-clockwise": "^6.5.0",
+ "@turf/boolean-contains": "^6.5.0",
+ "@turf/boolean-crosses": "^6.5.0",
+ "@turf/boolean-disjoint": "^6.5.0",
+ "@turf/boolean-equal": "^6.5.0",
+ "@turf/boolean-intersects": "^6.5.0",
+ "@turf/boolean-overlap": "^6.5.0",
+ "@turf/boolean-parallel": "^6.5.0",
+ "@turf/boolean-point-in-polygon": "^6.5.0",
+ "@turf/boolean-point-on-line": "^6.5.0",
+ "@turf/boolean-within": "^6.5.0",
+ "@turf/buffer": "^6.5.0",
+ "@turf/center": "^6.5.0",
+ "@turf/center-mean": "^6.5.0",
+ "@turf/center-median": "^6.5.0",
+ "@turf/center-of-mass": "^6.5.0",
+ "@turf/centroid": "^6.5.0",
+ "@turf/circle": "^6.5.0",
+ "@turf/clean-coords": "^6.5.0",
+ "@turf/clone": "^6.5.0",
+ "@turf/clusters": "^6.5.0",
+ "@turf/clusters-dbscan": "^6.5.0",
+ "@turf/clusters-kmeans": "^6.5.0",
+ "@turf/collect": "^6.5.0",
+ "@turf/combine": "^6.5.0",
+ "@turf/concave": "^6.5.0",
+ "@turf/convex": "^6.5.0",
+ "@turf/destination": "^6.5.0",
+ "@turf/difference": "^6.5.0",
+ "@turf/dissolve": "^6.5.0",
+ "@turf/distance": "^6.5.0",
+ "@turf/distance-weight": "^6.5.0",
+ "@turf/ellipse": "^6.5.0",
+ "@turf/envelope": "^6.5.0",
+ "@turf/explode": "^6.5.0",
+ "@turf/flatten": "^6.5.0",
+ "@turf/flip": "^6.5.0",
+ "@turf/great-circle": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/hex-grid": "^6.5.0",
+ "@turf/interpolate": "^6.5.0",
+ "@turf/intersect": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "@turf/isobands": "^6.5.0",
+ "@turf/isolines": "^6.5.0",
+ "@turf/kinks": "^6.5.0",
+ "@turf/length": "^6.5.0",
+ "@turf/line-arc": "^6.5.0",
+ "@turf/line-chunk": "^6.5.0",
+ "@turf/line-intersect": "^6.5.0",
+ "@turf/line-offset": "^6.5.0",
+ "@turf/line-overlap": "^6.5.0",
+ "@turf/line-segment": "^6.5.0",
+ "@turf/line-slice": "^6.5.0",
+ "@turf/line-slice-along": "^6.5.0",
+ "@turf/line-split": "^6.5.0",
+ "@turf/line-to-polygon": "^6.5.0",
+ "@turf/mask": "^6.5.0",
+ "@turf/meta": "^6.5.0",
+ "@turf/midpoint": "^6.5.0",
+ "@turf/moran-index": "^6.5.0",
+ "@turf/nearest-point": "^6.5.0",
+ "@turf/nearest-point-on-line": "^6.5.0",
+ "@turf/nearest-point-to-line": "^6.5.0",
+ "@turf/planepoint": "^6.5.0",
+ "@turf/point-grid": "^6.5.0",
+ "@turf/point-on-feature": "^6.5.0",
+ "@turf/point-to-line-distance": "^6.5.0",
+ "@turf/points-within-polygon": "^6.5.0",
+ "@turf/polygon-smooth": "^6.5.0",
+ "@turf/polygon-tangents": "^6.5.0",
+ "@turf/polygon-to-line": "^6.5.0",
+ "@turf/polygonize": "^6.5.0",
+ "@turf/projection": "^6.5.0",
+ "@turf/random": "^6.5.0",
+ "@turf/rewind": "^6.5.0",
+ "@turf/rhumb-bearing": "^6.5.0",
+ "@turf/rhumb-destination": "^6.5.0",
+ "@turf/rhumb-distance": "^6.5.0",
+ "@turf/sample": "^6.5.0",
+ "@turf/sector": "^6.5.0",
+ "@turf/shortest-path": "^6.5.0",
+ "@turf/simplify": "^6.5.0",
+ "@turf/square": "^6.5.0",
+ "@turf/square-grid": "^6.5.0",
+ "@turf/standard-deviational-ellipse": "^6.5.0",
+ "@turf/tag": "^6.5.0",
+ "@turf/tesselate": "^6.5.0",
+ "@turf/tin": "^6.5.0",
+ "@turf/transform-rotate": "^6.5.0",
+ "@turf/transform-scale": "^6.5.0",
+ "@turf/transform-translate": "^6.5.0",
+ "@turf/triangle-grid": "^6.5.0",
+ "@turf/truncate": "^6.5.0",
+ "@turf/union": "^6.5.0",
+ "@turf/unkink-polygon": "^6.5.0",
+ "@turf/voronoi": "^6.5.0"
+ }
+ },
+ "@turf/union": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/union/-/union-6.5.0.tgz",
+ "integrity": "sha512-igYWCwP/f0RFHIlC2c0SKDuM/ObBaqSljI3IdV/x71805QbIvY/BYGcJdyNcgEA6cylIGl/0VSlIbpJHZ9ldhw==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "polygon-clipping": "^0.15.3"
+ }
+ },
+ "@turf/unkink-polygon": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/unkink-polygon/-/unkink-polygon-6.5.0.tgz",
+ "integrity": "sha512-8QswkzC0UqKmN1DT6HpA9upfa1HdAA5n6bbuzHy8NJOX8oVizVAqfEPY0wqqTgboDjmBR4yyImsdPGUl3gZ8JQ==",
+ "requires": {
+ "@turf/area": "^6.5.0",
+ "@turf/boolean-point-in-polygon": "^6.5.0",
+ "@turf/helpers": "^6.5.0",
+ "@turf/meta": "^6.5.0",
+ "rbush": "^2.0.1"
+ },
+ "dependencies": {
+ "quickselect": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-1.1.1.tgz",
+ "integrity": "sha512-qN0Gqdw4c4KGPsBOQafj6yj/PA6c/L63f6CaZ/DCF/xF4Esu3jVmKLUDYxghFx8Kb/O7y9tI7x2RjTSXwdK1iQ=="
+ },
+ "rbush": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/rbush/-/rbush-2.0.2.tgz",
+ "integrity": "sha512-XBOuALcTm+O/H8G90b6pzu6nX6v2zCKiFG4BJho8a+bY6AER6t8uQUZdi5bomQc0AprCWhEGa7ncAbbRap0bRA==",
+ "requires": {
+ "quickselect": "^1.0.1"
+ }
+ }
+ }
+ },
+ "@turf/voronoi": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/voronoi/-/voronoi-6.5.0.tgz",
+ "integrity": "sha512-C/xUsywYX+7h1UyNqnydHXiun4UPjK88VDghtoRypR9cLlb7qozkiLRphQxxsCM0KxyxpVPHBVQXdAL3+Yurow==",
+ "requires": {
+ "@turf/helpers": "^6.5.0",
+ "@turf/invariant": "^6.5.0",
+ "d3-voronoi": "1.1.2"
+ }
+ },
"@types/adm-zip": {
"version": "0.4.34",
"resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.4.34.tgz",
@@ -9921,11 +11209,6 @@
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.9.1.tgz",
"integrity": "sha512-Ro2JbLmvg83gXF5F4sniaQ+lTbSv18E+TIf2cOeiH1Iqd2PGFOtem+DUufMZsCJwFE7ywPOpfXFBwRTGq7dh6w=="
},
- "cheap-ruler": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/cheap-ruler/-/cheap-ruler-3.0.2.tgz",
- "integrity": "sha512-02T332h1/HTN6cDSufLP8x4JzDs2+VC+8qZ/N0kWIVPyc2xUkWwWh3B2fJxR7raXkL4Mq7k554mfuM9ofv/vGg=="
- },
"check-error": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
@@ -10539,6 +11822,24 @@
}
}
},
+ "concaveman": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/concaveman/-/concaveman-1.2.1.tgz",
+ "integrity": "sha512-PwZYKaM/ckQSa8peP5JpVr7IMJ4Nn/MHIaWUjP4be+KoZ7Botgs8seAZGpmaOM+UZXawcdYRao/px9ycrCihHw==",
+ "requires": {
+ "point-in-polygon": "^1.1.0",
+ "rbush": "^3.0.1",
+ "robust-predicates": "^2.0.4",
+ "tinyqueue": "^2.0.3"
+ },
+ "dependencies": {
+ "robust-predicates": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-2.0.4.tgz",
+ "integrity": "sha512-l4NwboJM74Ilm4VKfbAtFeGq7aEjWL+5kVFcmgFA2MrdnQWx9iE/tUGvxY5HyMI7o/WpSIUFLbC5fbeaHgSCYg=="
+ }
+ }
+ },
"configstore": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.5.tgz",
@@ -11205,9 +12506,9 @@
}
},
"d3": {
- "version": "7.8.4",
- "resolved": "https://registry.npmjs.org/d3/-/d3-7.8.4.tgz",
- "integrity": "sha512-q2WHStdhiBtD8DMmhDPyJmXUxr6VWRngKyiJ5EfXMxPw+tqT6BhNjhJZ4w3BHsNm3QoVfZLY8Orq/qPFczwKRA==",
+ "version": "7.8.5",
+ "resolved": "https://registry.npmjs.org/d3/-/d3-7.8.5.tgz",
+ "integrity": "sha512-JgoahDG51ncUfJu6wX/1vWQEqOflgXyl4MaHqlcSruTez7yhaRKR9i8VjjcQGeS2en/jnFivXuaIMnseMMt0XA==",
"requires": {
"d3-array": "3",
"d3-axis": "3",
@@ -11462,6 +12763,11 @@
"d3-timer": "1 - 3"
}
},
+ "d3-voronoi": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.1.2.tgz",
+ "integrity": "sha512-RhGS1u2vavcO7ay7ZNAPo4xeDh/VYeGof3x5ZLJBQgYhLegxr3s5IykvWmJ94FTU6mcbtp4sloqZ54mP6R4Utw=="
+ },
"d3-zoom": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz",
@@ -11826,6 +13132,11 @@
"resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz",
"integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw=="
},
+ "density-clustering": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/density-clustering/-/density-clustering-1.3.0.tgz",
+ "integrity": "sha512-icpmBubVTwLnsaor9qH/4tG5+7+f61VcqMN3V3pm9sxxSCt2Jcs0zWOgwZW9ARJYaKD3FumIgHiMOcIMRRAzFQ=="
+ },
"depcheck": {
"version": "0.9.2",
"resolved": "https://registry.npmjs.org/depcheck/-/depcheck-0.9.2.tgz",
@@ -15290,6 +16601,33 @@
"resolved": "https://registry.npmjs.org/geojson/-/geojson-0.5.0.tgz",
"integrity": "sha512-/Bx5lEn+qRF4TfQ5aLu6NH+UKtvIv7Lhc487y/c8BdludrCTpiWf9wyI0RTyqg49MFefIAvFDuEi5Dfd/zgNxQ=="
},
+ "geojson-equality": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/geojson-equality/-/geojson-equality-0.1.6.tgz",
+ "integrity": "sha512-TqG8YbqizP3EfwP5Uw4aLu6pKkg6JQK9uq/XZ1lXQntvTHD1BBKJWhNpJ2M0ax6TuWMP3oyx6Oq7FCIfznrgpQ==",
+ "requires": {
+ "deep-equal": "^1.0.0"
+ }
+ },
+ "geojson-rbush": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/geojson-rbush/-/geojson-rbush-3.2.0.tgz",
+ "integrity": "sha512-oVltQTXolxvsz1sZnutlSuLDEcQAKYC/uXt9zDzJJ6bu0W+baTI8LZBaTup5afzibEH4N3jlq2p+a152wlBJ7w==",
+ "requires": {
+ "@turf/bbox": "*",
+ "@turf/helpers": "6.x",
+ "@turf/meta": "6.x",
+ "@types/geojson": "7946.0.8",
+ "rbush": "^3.0.1"
+ },
+ "dependencies": {
+ "@types/geojson": {
+ "version": "7946.0.8",
+ "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.8.tgz",
+ "integrity": "sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA=="
+ }
+ }
+ },
"geojson-vt": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-3.2.1.tgz",
@@ -18715,9 +20053,9 @@
}
},
"mapbox-gl": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-3.0.1.tgz",
- "integrity": "sha512-o7C6sAlj6Hkdd4xQVEgQflgJYNYyZOAtYahhIOb9m8chI8umtWcCp8Ie0iGLYJvce1WHRMa3WGzs69ggwuWlDA==",
+ "version": "2.15.0",
+ "resolved": "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-2.15.0.tgz",
+ "integrity": "sha512-fjv+aYrd5TIHiL7wRa+W7KjtUqKWziJMZUkK5hm8TvJ3OLeNPx4NmW/DgfYhd/jHej8wWL+QJBDbdMMAKvNC0A==",
"requires": {
"@mapbox/geojson-rewind": "^0.5.2",
"@mapbox/jsonlint-lines-primitives": "^2.0.2",
@@ -18727,7 +20065,6 @@
"@mapbox/unitbezier": "^0.0.1",
"@mapbox/vector-tile": "^1.3.1",
"@mapbox/whoots-js": "^3.1.0",
- "cheap-ruler": "^3.0.1",
"csscolorparser": "~1.0.3",
"earcut": "^2.2.4",
"geojson-vt": "^3.2.1",
@@ -25366,6 +26703,19 @@
"integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==",
"dev": true
},
+ "point-in-polygon": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/point-in-polygon/-/point-in-polygon-1.1.0.tgz",
+ "integrity": "sha512-3ojrFwjnnw8Q9242TzgXuTD+eKiutbzyslcq1ydfu82Db2y+Ogbmyrkpv0Hgj31qwT3lbS9+QAAO/pIQM35XRw=="
+ },
+ "polygon-clipping": {
+ "version": "0.15.3",
+ "resolved": "https://registry.npmjs.org/polygon-clipping/-/polygon-clipping-0.15.3.tgz",
+ "integrity": "sha512-ho0Xx5DLkgxRx/+n4O74XyJ67DcyN3Tu9bGYKsnTukGAW6ssnuak6Mwcyb1wHy9MZc9xsUWqIoiazkZB5weECg==",
+ "requires": {
+ "splaytree": "^3.1.0"
+ }
+ },
"popper.js": {
"version": "1.16.1",
"resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz",
@@ -26218,6 +27568,14 @@
"schema-utils": "^1.0.0"
}
},
+ "rbush": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/rbush/-/rbush-3.0.1.tgz",
+ "integrity": "sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==",
+ "requires": {
+ "quickselect": "^2.0.0"
+ }
+ },
"rc": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
@@ -27649,9 +29007,9 @@
}
},
"robust-predicates": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.1.tgz",
- "integrity": "sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g=="
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz",
+ "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg=="
},
"rope-sequence": {
"version": "1.3.3",
@@ -28341,6 +29699,11 @@
}
}
},
+ "skmeans": {
+ "version": "0.9.7",
+ "resolved": "https://registry.npmjs.org/skmeans/-/skmeans-0.9.7.tgz",
+ "integrity": "sha512-hNj1/oZ7ygsfmPZ7ZfN5MUBRoGg1gtpnImuJBgLO0ljQ67DtJuiQaiYdS4lUA6s0KCwnPhGivtC/WRwIZLkHyg=="
+ },
"slash": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
@@ -28852,6 +30215,11 @@
}
}
},
+ "splaytree": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/splaytree/-/splaytree-3.1.2.tgz",
+ "integrity": "sha512-4OM2BJgC5UzrhVnnJA4BkHKGtjXNzzUfpQjCO8I05xYPsfS/VuQDwjCGGMi8rYQilHEV4j8NBqTFbls/PZEE7A=="
+ },
"split-on-first": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
@@ -29652,6 +31020,36 @@
"resolved": "https://registry.npmjs.org/token-stream/-/token-stream-0.0.1.tgz",
"integrity": "sha1-zu78cXp2xDFvEm0LnbqlXX598Bo="
},
+ "topojson-client": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/topojson-client/-/topojson-client-3.1.0.tgz",
+ "integrity": "sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw==",
+ "requires": {
+ "commander": "2"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
+ }
+ }
+ },
+ "topojson-server": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/topojson-server/-/topojson-server-3.0.1.tgz",
+ "integrity": "sha512-/VS9j/ffKr2XAOjlZ9CgyyeLmgJ9dMwq6Y0YEON8O7p/tGGk+dCWnrE03zEdu7i4L7YsFZLEPZPzCvcB7lEEXw==",
+ "requires": {
+ "commander": "2"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
+ }
+ }
+ },
"touch": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
@@ -30107,6 +31505,11 @@
"safe-buffer": "^5.0.1"
}
},
+ "turf-jsts": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/turf-jsts/-/turf-jsts-1.2.3.tgz",
+ "integrity": "sha512-Ja03QIJlPuHt4IQ2FfGex4F4JAr8m3jpaHbFbQrgwr7s7L6U8ocrHiF3J1+wf9jzhGKxvDeaCAnGDot8OjGFyA=="
+ },
"tweetnacl": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
diff --git a/package.json b/package.json
index 42d43e758..9a9e7675d 100644
--- a/package.json
+++ b/package.json
@@ -46,7 +46,7 @@
"@types/jquery": "^3.5.14",
"@types/libxmljs": "^0.18.7",
"@types/lodash": "^4.14.179",
- "@types/mapbox-gl": "^2.7.19",
+ "@types/mapbox-gl": "^2.7.17",
"@types/mobile-detect": "^1.3.4",
"@types/mocha": "^5.2.6",
"@types/mongodb": "^3.6.20",
@@ -151,6 +151,7 @@
"@octokit/core": "^4.0.4",
"@react-google-maps/api": "^2.7.0",
"@react-three/fiber": "^6.2.3",
+ "@turf/turf": "^6.5.0",
"@types/bezier-js": "^4.1.0",
"@types/cors": "^2.8.12",
"@types/d3-axis": "^2.1.3",
@@ -199,7 +200,7 @@
"cors": "^2.8.5",
"csv-parser": "^3.0.0",
"csv-stringify": "^6.3.0",
- "d3": "^7.6.1",
+ "d3": "^7.8.5",
"debounce": "^2.0.0",
"depcheck": "^0.9.2",
"equation-editor-react": "github:bobzel/equation-editor-react#useLocally",
@@ -243,7 +244,7 @@
"jsonschema": "^1.4.0",
"jszip": "^3.7.1",
"lodash": "^4.17.21",
- "mapbox-gl": "^3.0.1",
+ "mapbox-gl": "^2.15.0",
"material-ui": "^0.20.2",
"md5-file": "^5.0.0",
"memorystream": "^0.3.1",
@@ -302,7 +303,7 @@
"react-jsx-parser": "^1.29.0",
"react-loader-spinner": "^5.3.4",
"react-loading": "^2.0.3",
- "react-map-gl": "^7.1.0",
+ "react-map-gl": "^7.1.6",
"react-markdown": "^8.0.3",
"react-measure": "^2.5.2",
"react-refresh-typescript": "^2.0.7",
diff --git a/src/client/views/nodes/MapBox/AnimationSpeedIcons.tsx b/src/client/views/nodes/MapBox/AnimationSpeedIcons.tsx
new file mode 100644
index 000000000..d54a175b2
--- /dev/null
+++ b/src/client/views/nodes/MapBox/AnimationSpeedIcons.tsx
@@ -0,0 +1,35 @@
+import * as React from "react";
+
+export const slowSpeedIcon: JSX.Element = (
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 435.62">
+ <defs>
+ <style type="text/css">
+ {`
+ .fil0 { fill: black; fill-rule: nonzero; }
+ .fil1 { fill: #FE0000; fill-rule: nonzero; }
+ `}
+ </style>
+ </defs>
+ <path className="fil0" d="M174.84 343.06c-7.31,-13.12 -13.03,-27.28 -16.89,-42.18 -3.76,-14.56 -5.77,-29.71 -5.77,-45.17 0,-11.94 1.19,-23.66 3.43,-35.03 2.29,-11.57 5.74,-22.83 10.2,-33.63 13.7,-33.14 37.01,-61.29 66.42,-80.96 25.38,-16.96 55.28,-27.66 87.45,-29.87l0 -30.17c0,-0.46 0.02,-0.92 0.06,-1.37l-33.7 0c-5.53,0 -10.05,-4.52 -10.05,-10.04l0 -24.59c0,-5.53 4.52,-10.05 10.05,-10.05l101.27 0c5.53,0 10.05,4.52 10.05,10.05l0 24.59c0,5.52 -4.52,10.04 -10.05,10.04l-33.69 0c0.03,0.45 0.05,0.91 0.05,1.37l0 31.03 -0.1 0c41.1,4.89 77.94,23.63 105.73,51.42 32.56,32.55 52.7,77.54 52.7,127.21 0,49.67 -20.14,94.66 -52.7,127.21 -32.55,32.55 -77.54,52.7 -127.21,52.7 -33.16,0 -64.29,-9.04 -91.05,-24.78 -27.66,-16.27 -50.59,-39.73 -66.2,-67.78zm148.42 -36.62l-80.33 0 0 -25.71 28.6 0 0 -42.57 -28.6 1.93 0 -25.71 36.95 -8.35 25.38 0 0 74.7 18 0 0 25.71zm44.34 -100.41l11.08 26.83 1.61 0 11.09 -26.83 34.86 0 -22.33 48.52 22.33 51.89 -35.67 0 -12.05 -28.92 -1.44 0 -11.89 28.92 -34.06 0 21.85 -50.93 -21.85 -49.48 36.47 0zm126.08 -74.6c6.98,-16.66 6.15,-34.13 -3.84,-45.82 -12,-14.03 -33.67,-15.64 -53.8,-5.77 21.32,14.62 40.68,31.63 57.64,51.59zm-323.17 0c-6.98,-16.66 -6.16,-34.13 3.84,-45.82 11.99,-14.03 33.67,-15.64 53.79,-5.77 -21.32,14.62 -40.68,31.63 -57.63,51.59zm15.31 162.23c3.23,12.5 8.04,24.39 14.18,35.42 13.13,23.58 32.39,43.29 55.6,56.94 22.37,13.16 48.52,20.71 76.49,20.71 41.71,0 79.47,-16.9 106.8,-44.23 27.32,-27.32 44.23,-65.08 44.23,-106.79 0,-41.71 -16.91,-79.47 -44.23,-106.8 -27.33,-27.32 -65.09,-44.23 -106.8,-44.23 -31.07,0 -59.91,9.34 -83.84,25.33 -24.74,16.54 -44.33,40.19 -55.82,67.98 -3.68,8.91 -6.56,18.35 -8.5,28.22 -1.87,9.49 -2.86,19.36 -2.86,29.5 0,13.24 1.65,25.96 4.75,37.95z"/>
+ <path className="fil1" d="M55.23 188.52c-7.98,0 -14.45,-6.47 -14.45,-14.44 0,-7.98 6.47,-14.45 14.45,-14.45l63.94 0c7.98,0 14.45,6.47 14.45,14.45 0,7.97 -6.47,14.44 -14.45,14.44l-63.94 0zm0.72 167.68c-7.97,0 -14.44,-6.47 -14.44,-14.45 0,-7.97 6.47,-14.45 14.44,-14.45l64.58 0c7.97,0 14.45,6.48 14.45,14.45 0,7.98 -6.48,14.45 -14.45,14.45l-64.58 0zm-41.5 -84.94c-7.98,0 -14.45,-6.47 -14.45,-14.45 0,-7.97 6.47,-14.44 14.45,-14.44l89.12 0c7.98,0 14.45,6.47 14.45,14.44 0,7.98 -6.47,14.45 -14.45,14.45l-89.12 0z"/>
+ </svg>
+);
+
+export const mediumSpeedIcon: JSX.Element = (
+ <svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" data-name="Layer 1" viewBox="0 0 122.88 104.55">
+ <defs><style>{`.cls-1{fill:#fe0000;}`}</style></defs>
+ <path d="M42,82.34a42.82,42.82,0,0,1-4.05-10.13A43.2,43.2,0,0,1,76.72,18.29V11.05c0-.11,0-.22,0-.33H68.65a2.41,2.41,0,0,1-2.41-2.41V2.41A2.41,2.41,0,0,1,68.65,0H93a2.42,2.42,0,0,1,2.42,2.41v5.9A2.42,2.42,0,0,1,93,10.72H84.87c0,.11,0,.22,0,.33V18.5h0A43.17,43.17,0,1,1,42,82.34ZM88.22,49.45l2.66,6.44h.39l2.66-6.44h8.37L96.94,61.09l5.36,12.45H93.74L90.85,66.6H90.5l-2.85,6.94H79.47l5.25-12.22L79.47,49.45ZM58.65,56.08l-1-5.75a33.58,33.58,0,0,1,9.68-1.46c1.28,0,2.35,0,3.22.11a11.77,11.77,0,0,1,2.67.58,5.41,5.41,0,0,1,2.2,1.28c1.24,1.23,1.85,3.12,1.85,5.66s-.72,4.42-2.16,5.63S70.64,64.73,66,66.3v1.08H76.89v6.16H57.11V68.72a10.73,10.73,0,0,1,.81-4.12,8.4,8.4,0,0,1,2.43-2.7,12.13,12.13,0,0,1,2.79-1.7l3.32-1.52c1-.47,1.88-.87,2.52-1.17V55.42a28.59,28.59,0,0,0-3.2-.19,30.66,30.66,0,0,0-7.13.85Zm59.83-24.54c1.68-4,1.48-8.19-.92-11-2.88-3.37-8.08-3.76-12.91-1.39a69.74,69.74,0,0,1,13.83,12.38Zm-77.56,0c-1.67-4-1.48-8.19.92-11,2.88-3.37,8.08-3.76,12.91-1.39A70,70,0,0,0,40.92,31.54ZM44.6,70.48A36,36,0,0,0,48,79a35.91,35.91,0,1,0-3.4-8.5Z"/>
+ <path className="cls-1" d="M13.25,45.25a3.47,3.47,0,0,1,0-6.94H28.6a3.47,3.47,0,0,1,0,6.94Z"/>
+ <path className="cls-1" d="M3.47,65.1a3.47,3.47,0,1,1,0-6.93H24.86a3.47,3.47,0,0,1,0,6.93Z"/>
+ <path className="cls-1" d="M13.43,85.49a3.47,3.47,0,1,1,0-6.94h15.5a3.47,3.47,0,0,1,0,6.94Z"/>
+ </svg>
+);
+
+export const fastSpeedIcon: JSX.Element = (
+ <svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" data-name="Layer 1" viewBox="0 0 122.88 104.55">
+ <defs><style>{`.cls-1{fill:#fe0000;`}</style></defs>
+ <path d="M42,82.34a42.82,42.82,0,0,1-4.05-10.13A43.2,43.2,0,0,1,76.72,18.29V11.05c0-.11,0-.22,0-.33H68.65a2.41,2.41,0,0,1-2.41-2.41V2.41A2.41,2.41,0,0,1,68.65,0H93a2.42,2.42,0,0,1,2.42,2.41v5.9A2.42,2.42,0,0,1,93,10.72H84.87c0,.11,0,.22,0,.33V18.5h0A43.17,43.17,0,1,1,42,82.34ZM88.22,49.61l2.66,6.44h.39l2.66-6.44h8.37L96.94,61.26l5.36,12.45H93.74l-2.9-6.94H90.5l-2.86,6.94H79.47l5.24-12.22L79.47,49.61Zm-19,8.48v-2.5a24.92,24.92,0,0,0-3.74-.2A33.25,33.25,0,0,0,59,56.2l-1-5.7A30.47,30.47,0,0,1,67.13,49a22.86,22.86,0,0,1,5.48.47,6.91,6.91,0,0,1,2.5,1.11,5.62,5.62,0,0,1,1.78,4.55,5.84,5.84,0,0,1-3.2,5.56v.19a5.73,5.73,0,0,1,3.81,5.74,8.67,8.67,0,0,1-.63,3.49,6,6,0,0,1-1.6,2.24,7.15,7.15,0,0,1-2.55,1.25,25.64,25.64,0,0,1-6.61.66,37.78,37.78,0,0,1-8.54-1l1.08-6.37a27.22,27.22,0,0,0,6.21.89,35.79,35.79,0,0,0,4.35-.23V65.11l-6.63-.65V58.87l6.63-.78Zm49.27-26.55c1.68-4,1.48-8.19-.92-11-2.88-3.37-8.08-3.76-12.91-1.39a69.74,69.74,0,0,1,13.83,12.38Zm-77.56,0c-1.67-4-1.48-8.19.92-11,2.88-3.37,8.08-3.76,12.91-1.39A70,70,0,0,0,40.92,31.54ZM44.6,70.48A36,36,0,0,0,48,79a35.91,35.91,0,1,0-3.4-8.5Z"/>
+ <path className="cls-1" d="M13.25,45.25a3.47,3.47,0,0,1,0-6.94H28.6a3.47,3.47,0,0,1,0,6.94Zm.18,40.24a3.47,3.47,0,1,1,0-6.94h15.5a3.47,3.47,0,0,1,0,6.94ZM3.47,65.1a3.47,3.47,0,1,1,0-6.93H24.86a3.47,3.47,0,0,1,0,6.93Z"/>
+ </svg>
+);
+
diff --git a/src/client/views/nodes/MapBox/AnimationUtility.ts b/src/client/views/nodes/MapBox/AnimationUtility.ts
new file mode 100644
index 000000000..256acbf13
--- /dev/null
+++ b/src/client/views/nodes/MapBox/AnimationUtility.ts
@@ -0,0 +1,429 @@
+import mapboxgl from "mapbox-gl";
+import { MercatorCoordinate } from "mapbox-gl";
+import { MapRef } from "react-map-gl";
+import * as React from 'react';
+import * as d3 from "d3";
+import * as turf from '@turf/turf';
+import { Position } from "@turf/turf";
+import { Feature, FeatureCollection, GeoJsonProperties, Geometry } from "geojson";
+import { observer } from "mobx-react";
+import { action, computed, observable } from "mobx";
+
+export enum AnimationStatus {
+ START = 'start',
+ RESUME = 'resume',
+ RESTART = 'restart',
+}
+
+export enum AnimationSpeed {
+ SLOW = '1x',
+ MEDIUM = '2x',
+ FAST = '3x',
+}
+
+@observer
+export class AnimationUtility {
+ private SMOOTH_FACTOR = 0.95
+ private ROUTE_COORDINATES: Position[] = [];
+ private PATH: turf.helpers.Feature<turf.helpers.LineString, turf.helpers.Properties>;
+ private FLY_IN_START_PITCH = 40;
+ private FIRST_LNG_LAT: {lng: number, lat: number};
+ private START_ALTITUDE = 3_000_000;
+
+ @observable private isStreetViewAnimation: boolean;
+ @observable private animationSpeed: AnimationSpeed;
+
+
+ private previousLngLat: {lng: number, lat: number};
+
+ private currentStreetViewBearing: number = 0;
+
+ @computed get flyInEndBearing() {
+ return this.isStreetViewAnimation ?
+ this.calculateBearing(
+ {
+ lng: this.ROUTE_COORDINATES[0][0],
+ lat: this.ROUTE_COORDINATES[0][1]
+ },
+ {
+ lng: this.ROUTE_COORDINATES[1][0],
+ lat: this.ROUTE_COORDINATES[1][1]
+ }
+ )
+ : -20;
+ }
+
+ @computed get flyInStartBearing() {
+ return Math.max(0, Math.min(this.flyInEndBearing + 20, 360)); // between 0 and 360
+ }
+
+ @computed get flyInEndAltitude() {
+ return this.isStreetViewAnimation ? 70 : 10000;
+ }
+
+ @computed get flyInEndPitch() {
+ return this.isStreetViewAnimation ? 80 : 50;
+ }
+
+ @computed get flyToDuration() {
+ switch (this.animationSpeed) {
+ case AnimationSpeed.SLOW:
+ return 4000;
+ case AnimationSpeed.MEDIUM:
+ return 2500;
+ case AnimationSpeed.FAST:
+ return 1250;
+ default:
+ return 2500;
+ }
+ }
+
+ @computed get animationDuration(): number {
+ return 20_000;
+ // compute path distance for a standard speed
+ // get animation speed
+ // get isStreetViewAnimation (should be slower if so)
+ }
+
+ @action
+ public updateAnimationSpeed(speed: AnimationSpeed) {
+ // calculate new flyToDuration and animationDuration
+ this.animationSpeed = speed;
+ }
+
+ @action
+ public updateIsStreetViewAnimation(isStreetViewAnimation: boolean) {
+ this.isStreetViewAnimation = isStreetViewAnimation;
+ }
+
+
+ constructor(
+ firstLngLat: {lng: number, lat: number},
+ routeCoordinates: Position[],
+ isStreetViewAnimation: boolean,
+ animationSpeed: AnimationSpeed
+ ) {
+ this.FIRST_LNG_LAT = firstLngLat;
+ this.previousLngLat = firstLngLat;
+ this.ROUTE_COORDINATES = routeCoordinates;
+ this.PATH = turf.lineString(routeCoordinates);
+
+ const bearing = this.calculateBearing(
+ {
+ lng: routeCoordinates[0][0],
+ lat: routeCoordinates[0][1]
+ },
+ {
+ lng: routeCoordinates[1][0],
+ lat: routeCoordinates[1][1]
+ }
+ );
+ this.currentStreetViewBearing = bearing;
+ // if (isStreetViewAnimation){
+ // this.flyInEndBearing = bearing;
+ // }
+ this.isStreetViewAnimation = isStreetViewAnimation;
+ this.animationSpeed = animationSpeed;
+ // calculate animation duration based on speed
+ // this.animationDuration = animationDuration;
+ }
+
+ public animatePath = async ({
+ map,
+ // path,
+ // startBearing,
+ // startAltitude,
+ // pitch,
+ currentAnimationPhase,
+ updateAnimationPhase,
+ updateFrameId,
+ }: {
+ map: MapRef,
+ // path: turf.helpers.Feature<turf.helpers.LineString, turf.helpers.Properties>,
+ // startBearing: number,
+ // startAltitude: number,
+ // pitch: number,
+ currentAnimationPhase: number,
+ updateAnimationPhase: (
+ newAnimationPhase: number,
+ ) => void,
+ updateFrameId: (newFrameId: number) => void;
+
+ }) => {
+ return new Promise<void>(async (resolve) => {
+ const pathDistance = turf.lineDistance(this.PATH);
+ console.log("PATH DISTANCE: ", pathDistance);
+ let startTime: number | null = null;
+
+ const frame = async (currentTime: number) => {
+ if (!startTime) startTime = currentTime;
+ const elapsedSinceLastFrame = currentTime - startTime;
+ const phaseIncrement = elapsedSinceLastFrame / this.animationDuration;
+ const animationPhase = currentAnimationPhase + phaseIncrement;
+
+ // when the duration is complete, resolve the promise and stop iterating
+ if (animationPhase > 1) {
+ resolve();
+ return;
+ }
+
+
+ // calculate the distance along the path based on the animationPhase
+ const alongPath = turf.along(this.PATH, pathDistance * animationPhase).geometry
+ .coordinates;
+
+ const lngLat = {
+ lng: alongPath[0],
+ lat: alongPath[1],
+ };
+
+ let bearing: number;
+ if (this.isStreetViewAnimation){
+ bearing = this.lerp(
+ this.currentStreetViewBearing,
+ this.calculateBearing(this.previousLngLat, lngLat),
+ 0.028 // Adjust the transition speed as needed
+ );
+ this.currentStreetViewBearing = bearing;
+ // bearing = this.calculateBearing(this.previousLngLat, lngLat); // TODO: Calculate actual bearing
+ } else {
+ // slowly rotate the map at a constant rate
+ bearing = this.flyInEndBearing - animationPhase * 200.0;
+ // bearing = startBearing - animationPhase * 200.0;
+ }
+
+ this.previousLngLat = lngLat;
+
+ updateAnimationPhase(animationPhase);
+
+ // compute corrected camera ground position, so that he leading edge of the path is in view
+ var correctedPosition = this.computeCameraPosition(
+ this.isStreetViewAnimation,
+ this.flyInEndPitch,
+ bearing,
+ lngLat,
+ this.flyInEndAltitude,
+ true // smooth
+ );
+
+ // set the pitch and bearing of the camera
+ const camera = map.getFreeCameraOptions();
+ camera.setPitchBearing(this.flyInEndPitch, bearing);
+
+ console.log("Corrected pos: ", correctedPosition);
+ console.log("Start altitude: ", this.flyInEndAltitude);
+ // set the position and altitude of the camera
+ camera.position = MercatorCoordinate.fromLngLat(
+ correctedPosition,
+ this.flyInEndAltitude
+ );
+
+
+ // apply the new camera options
+ map.setFreeCameraOptions(camera);
+
+ // repeat!
+ const innerFrameId = await window.requestAnimationFrame(frame);
+ updateFrameId(innerFrameId);
+ };
+
+ const outerFrameId = await window.requestAnimationFrame(frame);
+ updateFrameId(outerFrameId);
+ });
+ };
+
+ public flyInAndRotate = async ({
+ map,
+ updateFrameId
+ }:
+ {
+ map: MapRef,
+ updateFrameId: (newFrameId: number) => void
+ }
+ ) => {
+ return new Promise<{bearing: number, altitude: number}>(async (resolve) => {
+ let start: number | null;
+
+ var currentAltitude;
+ var currentBearing;
+ var currentPitch;
+
+ // the animation frame will run as many times as necessary until the duration has been reached
+ const frame = async (time: number) => {
+ if (!start) {
+ start = time;
+ }
+
+ // otherwise, use the current time to determine how far along in the duration we are
+ let animationPhase = (time - start) / this.flyToDuration;
+
+ // because the phase calculation is imprecise, the final zoom can vary
+ // if it ended up greater than 1, set it to 1 so that we get the exact endAltitude that was requested
+ if (animationPhase > 1) {
+ animationPhase = 1;
+ }
+
+ currentAltitude = this.START_ALTITUDE + (this.flyInEndAltitude - this.START_ALTITUDE) * d3.easeCubicOut(animationPhase)
+ // rotate the camera between startBearing and endBearing
+ currentBearing = this.flyInStartBearing + (this.flyInEndBearing - this.flyInStartBearing) * d3.easeCubicOut(animationPhase)
+
+ currentPitch = this.FLY_IN_START_PITCH + (this.flyInEndPitch - this.FLY_IN_START_PITCH) * d3.easeCubicOut(animationPhase)
+
+ // compute corrected camera ground position, so the start of the path is always in view
+ var correctedPosition = this.computeCameraPosition(
+ false,
+ currentPitch,
+ currentBearing,
+ this.FIRST_LNG_LAT,
+ currentAltitude
+ );
+
+ // set the pitch and bearing of the camera
+ const camera = map.getFreeCameraOptions();
+ camera.setPitchBearing(currentPitch, currentBearing);
+
+ // set the position and altitude of the camera
+ camera.position = MercatorCoordinate.fromLngLat(
+ correctedPosition,
+ currentAltitude
+ );
+
+ // apply the new camera options
+ map.setFreeCameraOptions(camera);
+
+ // when the animationPhase is done, resolve the promise so the parent function can move on to the next step in the sequence
+ if (animationPhase === 1) {
+ resolve({
+ bearing: currentBearing,
+ altitude: currentAltitude,
+ });
+
+ // return so there are no further iterations of this frame
+ return;
+ }
+
+ const innerFrameId = await window.requestAnimationFrame(frame);
+ updateFrameId(innerFrameId);
+
+ };
+
+ const outerFrameId = await window.requestAnimationFrame(frame);
+ updateFrameId(outerFrameId);
+ });
+ };
+
+ previousCameraPosition: {lng: number, lat: number} | null = null;
+
+ lerp = (start: number, end: number, amt: number) => {
+ return (1 - amt) * start + amt * end;
+ }
+
+ computeCameraPosition = (
+ isStreetViewAnimation: boolean,
+ pitch: number,
+ bearing: number,
+ targetPosition: {lng: number, lat: number},
+ altitude: number,
+ smooth = false
+ ) => {
+ const bearingInRadian = (bearing * Math.PI) / 180;
+ const pitchInRadian = ((90 - pitch)* Math.PI) / 180;
+
+ let correctedLng = targetPosition.lng;
+ let correctedLat = targetPosition.lat;
+
+ if (!isStreetViewAnimation) {
+ const lngDiff =
+ ((altitude / Math.tan(pitchInRadian)) *
+ Math.sin(-bearingInRadian)) /
+ 70000; // ~70km/degree longitude
+ const latDiff =
+ ((altitude / Math.tan(pitchInRadian)) *
+ Math.cos(-bearingInRadian)) /
+ 110000 // 110km/degree latitude
+
+ correctedLng = targetPosition.lng + lngDiff;
+ correctedLat = targetPosition.lat - latDiff;
+
+ }
+
+ const newCameraPosition = {
+ lng: correctedLng,
+ lat: correctedLat
+ };
+
+ if (smooth) {
+ if (this.previousCameraPosition) {
+ newCameraPosition.lng = this.lerp(newCameraPosition.lng, this.previousCameraPosition.lng, this.SMOOTH_FACTOR);
+ newCameraPosition.lat = this.lerp(newCameraPosition.lat, this.previousCameraPosition.lat, this.SMOOTH_FACTOR);
+ }
+ }
+
+ this.previousCameraPosition = newCameraPosition
+
+ return newCameraPosition;
+ };
+
+ public static createGeoJSONCircle = (center: number[], radiusInKm: number, points = 64): Feature<Geometry, GeoJsonProperties>=> {
+ const coords = {
+ latitude: center[1],
+ longitude: center[0],
+ };
+ const km = radiusInKm;
+ const ret = [];
+ const distanceX = km / (111.320 * Math.cos((coords.latitude * Math.PI) / 180));
+ const distanceY = km / 110.574;
+ let theta;
+ let x;
+ let y;
+ for (let i = 0; i < points; i += 1) {
+ theta = (i / points) * (2 * Math.PI);
+ x = distanceX * Math.cos(theta);
+ y = distanceY * Math.sin(theta);
+ ret.push([coords.longitude + x, coords.latitude + y]);
+ }
+ ret.push(ret[0]);
+ return {
+ type: 'Feature',
+ geometry: {
+ type: 'Polygon',
+ coordinates: [ret],
+ },
+ properties: {}
+ };
+ }
+
+ private calculateBearing(
+ from: { lng: number; lat: number },
+ to: { lng: number; lat: number }
+ ): number {
+ const lon1 = from.lng;
+ const lat1 = from.lat;
+ const lon2 = to.lng;
+ const lat2 = to.lat;
+
+ const lon1Rad = (lon1 * Math.PI) / 180;
+ const lon2Rad = (lon2 * Math.PI) / 180;
+ const lat1Rad = (lat1 * Math.PI) / 180;
+ const lat2Rad = (lat2 * Math.PI) / 180;
+
+ const y = Math.sin(lon2Rad - lon1Rad) * Math.cos(lat2Rad);
+ const x =
+ Math.cos(lat1Rad) * Math.sin(lat2Rad) -
+ Math.sin(lat1Rad) * Math.cos(lat2Rad) * Math.cos(lon2Rad - lon1Rad);
+
+ let bearing = Math.atan2(y,x);
+
+ // Convert bearing from radians to degrees
+ bearing = (bearing * 180) / Math.PI;
+
+ // Ensure the bearing is within [0, 360)
+ if (bearing < 0) {
+ bearing += 360;
+ }
+
+ return bearing;
+ }
+
+
+} \ No newline at end of file
diff --git a/src/client/views/nodes/MapBox/MapAnchorMenu.tsx b/src/client/views/nodes/MapBox/MapAnchorMenu.tsx
index 2c2879900..f4e24d9c1 100644
--- a/src/client/views/nodes/MapBox/MapAnchorMenu.tsx
+++ b/src/client/views/nodes/MapBox/MapAnchorMenu.tsx
@@ -32,11 +32,11 @@ import { Autocomplete, Checkbox, FormControlLabel, TextField } from '@mui/materi
import { MapboxApiUtility, TransportationType } from './MapboxApiUtility';
import { MapBox } from './MapBox';
import { List } from '../../../../fields/List';
-import { MapboxColor, MarkerIcons } from './MarkerIcons';
-import { CirclePicker } from 'react-color';
+import { MarkerIcons } from './MarkerIcons';
+import { CirclePicker, ColorState } from 'react-color';
import { Position } from 'geojson';
-type MapAnchorMenuType = 'standard' | 'route' | 'calendar' | 'customize';
+type MapAnchorMenuType = 'standard' | 'routeCreation' | 'calendar' | 'customize' | 'route';
@observer
export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
@@ -61,17 +61,28 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
public DisplayRoute: (routeInfoMap: Record<TransportationType, any> | undefined, type: TransportationType) => void = unimplementedFunction;
public HideRoute: () => void = unimplementedFunction;
- public AddNewRouteToMap: (coordinates: Position[], origin: string, destination: string) => void = unimplementedFunction;
+ public AddNewRouteToMap: (coordinates: Position[], origin: string, destination: any, createPinForDestination: boolean) => void = unimplementedFunction;
public CreatePin: (feature: any) => void = unimplementedFunction;
public UpdateMarkerColor: (color: string) => void = unimplementedFunction;
public UpdateMarkerIcon: (iconKey: string) => void = unimplementedFunction;
+ public OpenAnimationPanel: (routeDoc: Doc | undefined) => void = unimplementedFunction;
+
+ @observable
+ menuType: MapAnchorMenuType = 'standard';
+
+ @action
+ public setMenuType = (menuType: MapAnchorMenuType) => {
+ this.menuType = menuType;
+ }
private allMapPinDocs: Doc[] = [];
- private pinDoc: Doc | undefined = undefined
+ private pinDoc: Doc | undefined = undefined;
+
+ private routeDoc: Doc | undefined = undefined;
private title: string | undefined = undefined;
@@ -81,6 +92,11 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
this.title = StrCast(pinDoc.title ? pinDoc.title : `${NumCast(pinDoc.longitude)}, ${NumCast(pinDoc.latitude)}`) ;
}
+ public setRouteDoc(routeDoc: Doc){
+ this.routeDoc = routeDoc;
+ this.title = StrCast(routeDoc.title ?? 'Map route')
+ }
+
public setAllMapboxPins(pinDocs: Doc[]) {
this.allMapPinDocs = pinDocs;
pinDocs.forEach((p, idx) => {
@@ -148,12 +164,11 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
// return this.top
// }
- @observable
- menuType: MapAnchorMenuType = 'standard';
+
@action
DirectionsClick = () => {
- this.menuType = 'route';
+ this.menuType = 'routeCreation';
}
@action
@@ -175,6 +190,26 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
}
}
+ @action
+ onMarkerColorChange = (color: ColorState) => {
+ if (this.pinDoc){
+ this.pinDoc.markerColor = color.hex;
+ }
+ }
+
+ revertToOriginalMarker = () => {
+ if (this.pinDoc) {
+ this.pinDoc.markerType = "MAP_PIN";
+ this.pinDoc.markerColor = "#ff5722";
+ }
+ }
+
+ onMarkerIconChange = (iconKey: string) => {
+ if (this.pinDoc) {
+ this.pinDoc.markerType = iconKey;
+ }
+ }
+
@observable
destinationFeatures: any[] = []
@@ -248,7 +283,8 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
if (this.currentRouteInfoMap && this.selectedTransportationType && this.selectedDestinationFeature){
const coordinates = this.currentRouteInfoMap[this.selectedTransportationType].coordinates;
console.log(coordinates);
- this.AddNewRouteToMap(coordinates, this.title ?? "", this.selectedDestinationFeature.place_name);
+ console.log(this.selectedDestinationFeature);
+ this.AddNewRouteToMap(coordinates, this.title ?? "", this.selectedDestinationFeature, this.createPinForDestination);
this.HideRoute();
}
}
@@ -258,11 +294,7 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
const markerType = StrCast(this.pinDoc.markerType);
const markerColor = StrCast(this.pinDoc.markerColor);
- if (markerType.startsWith("MAPBOX")){
- return MarkerIcons.getMapboxIcon(markerColor as MapboxColor);
- } else { // font awesome icon
- return MarkerIcons.getFontAwesomeIcon(markerType, markerColor);
- }
+ return MarkerIcons.getFontAwesomeIcon(markerType, '2x', markerColor);
}
return undefined;
}
@@ -313,7 +345,7 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
/>
</>
}
- {this.menuType === 'route' &&
+ {this.menuType === 'routeCreation' &&
<>
<IconButton
tooltip="Go back" //
@@ -327,19 +359,39 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
icon={<FontAwesomeIcon icon={faAdd as IconLookup} />}
color={SettingsManager.userColor}
/>
+ </>
+ }
+ {this.menuType === 'route' &&
+ <>
+ <IconButton
+ tooltip="Delete Route" //
+ onPointerDown={this.Delete}
+ icon={<FontAwesomeIcon icon="trash-alt" />}
+ color={SettingsManager.userColor}
+ />
<IconButton
tooltip='Animate route'
- onPointerDown={this.Delete} /**TODO: fix */
+ onPointerDown={() => this.OpenAnimationPanel(this.routeDoc)} /**TODO: fix */
icon={<FontAwesomeIcon icon={faRoute as IconLookup}/>}
color={SettingsManager.userColor}
/>
+ <div ref={this._commentRef}>
+ <IconButton
+ tooltip="Link Note to Pin" //
+ onPointerDown={this.notePointerDown}
+ icon={<FontAwesomeIcon icon="sticky-note" />}
+ color={SettingsManager.userColor}
+ />
+ </div>
<IconButton
tooltip='Add to calendar'
onPointerDown={this.Delete} /**TODO: fix */
icon={<FontAwesomeIcon icon={faCalendarDays as IconLookup}/>}
color={SettingsManager.userColor}
/>
+
</>
+
}
{this.menuType === 'customize' &&
<>
@@ -351,7 +403,7 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
/>
<IconButton
tooltip="Revert to original" //
- onPointerDown={this.BackClick}
+ onPointerDown={() => this.revertToOriginalMarker()}
icon={<FontAwesomeIcon icon={faArrowsRotate as IconLookup} />}
color={SettingsManager.userColor}
/>
@@ -386,7 +438,7 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
{this.menuType === 'standard' &&
<div>{this.title}</div>
}
- {this.menuType === 'route' &&
+ {this.menuType === 'routeCreation' &&
<div className='direction-inputs' style={{display: 'flex', flexDirection: 'column'}}>
<TextField
fullWidth
@@ -493,28 +545,28 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
circleSize={15}
circleSpacing={7}
width='100%'
- onChange={(color) => console.log(color.hex)}
+ onChange={(color) => this.onMarkerColorChange(color)}
/>
</div>
<div className='all-markers-container'>
- {Object.keys(MarkerIcons.FAMarkerIconsMap).map((iconKey) => {
- const icon = MarkerIcons.getFontAwesomeIcon(iconKey);
- if (icon){
- return (
- <div key={iconKey} className='marker-icon'>
- <IconButton
- onPointerDown={() => {}}
- icon={MarkerIcons.getFontAwesomeIcon(iconKey, 'white')}
- />
- </div>
- )
- }
- return null;
- })}
+ {Object.keys(MarkerIcons.FAMarkerIconsMap).map((iconKey) => (
+ <div key={iconKey} className='marker-icon'>
+ <IconButton
+ onPointerDown={() => this.onMarkerIconChange(iconKey)}
+ icon={MarkerIcons.getFontAwesomeIcon(iconKey, '1x', 'white')}
+ />
+ </div>
+ ))}
</div>
<div style={{width: '100%', height:'3px', color: 'white'}}></div>
</div>
}
+ {this.menuType === 'route' && this.routeDoc &&
+ <div>
+ {StrCast(this.routeDoc.title)}
+ </div>
+
+ }
{buttons}
</div>
, true);
diff --git a/src/client/views/nodes/MapBox/MapBox.scss b/src/client/views/nodes/MapBox/MapBox.scss
index bc2f90fbd..d3c6bb14e 100644
--- a/src/client/views/nodes/MapBox/MapBox.scss
+++ b/src/client/views/nodes/MapBox/MapBox.scss
@@ -82,6 +82,56 @@
}
+ .animation-panel {
+ z-index: 900;
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-start;
+ align-items: flex-start;
+ position: absolute;
+ background-color: rgb(187, 187, 187);
+ padding: 10px;
+ border-top-right-radius: 5px;
+ border-bottom-right-radius: 5px;
+ width: 100%;
+
+ #route-to-animate-title {
+ font-size: 1.25em;
+ font-weight: bold;
+ }
+
+ .route-animation-options {
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ gap: 7px;
+
+ .animation-suboptions{
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ gap: 7px;
+
+ label{
+ margin-bottom: 0;
+ }
+
+ .speed-label{
+ margin-right: 5px;
+ }
+
+ #last-divider{
+ margin-left: 10px;
+ margin-right: 10px;
+ }
+ }
+
+
+ }
+
+ }
+
+
.mapBox-topbar {
display: flex;
flex-direction: row;
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index ac926e1fb..cde68a2e6 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -2,7 +2,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import BingMapsReact from 'bingmaps-react';
// import 'mapbox-gl/dist/mapbox-gl.css';
-import { Button, EditableText, IconButton, Type } from 'browndash-components';
+import { Button, EditableText, IconButton, Size, Type } from 'browndash-components';
import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, flow, toJS} from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
@@ -51,14 +51,20 @@ import debounce from 'debounce';
import './MapBox.scss';
import { NumberLiteralType } from 'typescript';
// import { GeocoderControl } from './GeocoderControl';
-import mapboxgl, { LngLat, MapLayerMouseEvent } from 'mapbox-gl';
+import mapboxgl, { LngLat, LngLatBoundsLike, MapLayerMouseEvent, MercatorCoordinate } from 'mapbox-gl';
import { Feature, FeatureCollection, GeoJsonProperties, Geometry, LineString, MultiLineString, Position } from 'geojson';
import { MarkerEvent } from 'react-map-gl/dist/esm/types';
import { MapboxApiUtility, TransportationType} from './MapboxApiUtility';
import { Autocomplete, Checkbox, FormControlLabel, TextField } from '@mui/material';
import { List } from '../../../../fields/List';
import { listSpec } from '../../../../fields/Schema';
-import { IconLookup, faGear } from '@fortawesome/free-solid-svg-icons';
+import { IconLookup, faCircleXmark, faFileExport, faGear, faPause, faPlay, faRotate } from '@fortawesome/free-solid-svg-icons';
+import { MarkerIcons } from './MarkerIcons';
+import { SettingsManager } from '../../../util/SettingsManager';
+import * as turf from '@turf/turf';
+import * as d3 from "d3";
+import { AnimationSpeed, AnimationStatus, AnimationUtility } from './AnimationUtility';
+import { fastSpeedIcon, mediumSpeedIcon, slowSpeedIcon } from './AnimationSpeedIcons';
// amongus
/**
@@ -142,25 +148,93 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
@computed get allRoutes() {
return this.allAnnotations.filter(anno => anno.type === DocumentType.MAPROUTE);
}
+ @computed get updatedRouteCoordinates(): Feature<Geometry, GeoJsonProperties> {
+ if (this.routeToAnimate?.routeCoordinates) {
+ const originalCoordinates: Position[] = JSON.parse(StrCast(this.routeToAnimate.routeCoordinates));
+ // const index = Math.floor(this.animationPhase * originalCoordinates.length);
+ const index = this.animationPhase * (originalCoordinates.length - 1); // Calculate the fractional index
+ const startIndex = Math.floor(index);
+ const endIndex = Math.ceil(index);
+
+ if (startIndex === endIndex) {
+ // AnimationPhase is at a whole number (no interpolation needed)
+ const coordinates = [originalCoordinates[startIndex]];
+ const geometry: LineString = {
+ type: 'LineString',
+ coordinates,
+ };
+ return {
+ type: 'Feature',
+ properties: {
+ 'routeTitle': StrCast(this.routeToAnimate.title)
+ },
+ geometry: geometry,
+ };
+ } else {
+ // Interpolate between two coordinates
+ const startCoord = originalCoordinates[startIndex];
+ const endCoord = originalCoordinates[endIndex];
+ const fraction = index - startIndex;
+
+ // Interpolate the coordinates
+ const interpolatedCoord = [
+ startCoord[0] + fraction * (endCoord[0] - startCoord[0]),
+ startCoord[1] + fraction * (endCoord[1] - startCoord[1]),
+ ];
+
+ const coordinates = originalCoordinates.slice(0, startIndex + 1).concat([interpolatedCoord]);
+
+ const geometry: LineString = {
+ type: 'LineString',
+ coordinates,
+ };
+ return {
+ type: 'Feature',
+ properties: {
+ 'routeTitle': StrCast(this.routeToAnimate.title)
+ },
+ geometry: geometry,
+ };
+ }
+ }
+ return {
+ type: 'Feature',
+ properties: {},
+ geometry: {
+ type: 'LineString',
+ coordinates: []
+ },
+ };
+ }
+ @computed get selectedRouteCoordinates(): Position[] {
+ let coordinates: Position[] = [];
+ if (this.routeToAnimate?.routeCoordinates){
+ coordinates = JSON.parse(StrCast(this.routeToAnimate.routeCoordinates));
+ }
+ return coordinates;
+ }
+
@computed get allRoutesGeoJson(): FeatureCollection {
- const features: Feature<Geometry, GeoJsonProperties>[] = this.allRoutes.map(route => {
- console.log("Route coords: ", route.coordinates);
+ const features: Feature<Geometry, GeoJsonProperties>[] = this.allRoutes.map((routeDoc: Doc) => {
+ console.log('Route coords: ', routeDoc.routeCoordinates);
const geometry: LineString = {
type: 'LineString',
- coordinates: JSON.parse(StrCast(route.coordinates))
- }
+ coordinates: JSON.parse(StrCast(routeDoc.routeCoordinates)),
+ };
return {
- type: 'Feature',
- properties: {},
- geometry: geometry
+ type: 'Feature',
+ properties: {
+ 'routeTitle': routeDoc.title},
+ geometry: geometry,
};
- });
-
- return {
+ });
+
+ return {
type: 'FeatureCollection',
- features: features
- };
+ features: features,
+ };
}
+
@computed get SidebarShown() {
return this.layoutDoc._layout_showSidebar ? true : false;
}
@@ -184,7 +258,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
_unmounting = false;
componentWillUnmount(): void {
this._unmounting = true;
- this.deselectPin();
+ this.deselectPinOrRoute();
this._rerenderTimeout && clearTimeout(this._rerenderTimeout);
Object.keys(this._disposers).forEach(key => this._disposers[key]?.());
}
@@ -199,7 +273,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
if (!this.layoutDoc._layout_showSidebar) this.toggleSidebar();
const docs = doc instanceof Doc ? [doc] : doc;
docs.forEach(doc => {
- let existingPin = this.allPushpins.find(pin => pin.latitude === doc.latitude && pin.longitude === doc.longitude) ?? this.selectedPin;
+ let existingPin = this.allPushpins.find(pin => pin.latitude === doc.latitude && pin.longitude === doc.longitude) ?? this.selectedPinOrRoute;
if (doc.latitude !== undefined && doc.longitude !== undefined && !existingPin) {
existingPin = this.createPushpin(NumCast(doc.latitude), NumCast(doc.longitude), StrCast(doc.map));
}
@@ -300,10 +374,10 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
const sourceAnchorCreator = action(() => {
const note = this.getAnchor(true);
- if (note && this.selectedPin) {
- note.latitude = this.selectedPin.latitude;
- note.longitude = this.selectedPin.longitude;
- note.map = this.selectedPin.map;
+ if (note && this.selectedPinOrRoute) {
+ note.latitude = this.selectedPinOrRoute.latitude;
+ note.longitude = this.selectedPinOrRoute.longitude;
+ note.map = this.selectedPinOrRoute.map;
}
return note as Doc;
});
@@ -329,10 +403,10 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
const createFunc = undoable(
action(() => {
const note = this._sidebarRef.current?.anchorMenuClick(this.getAnchor(true), ['latitude', 'longitude', LinkedTo]);
- if (note && this.selectedPin) {
- note.latitude = this.selectedPin.latitude;
- note.longitude = this.selectedPin.longitude;
- note.map = this.selectedPin.map;
+ if (note && this.selectedPinOrRoute) {
+ note.latitude = this.selectedPinOrRoute.latitude;
+ note.longitude = this.selectedPinOrRoute.longitude;
+ note.map = this.selectedPinOrRoute.map;
}
}),
'create note annotation'
@@ -410,11 +484,12 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
};
// The pin that is selected
- @observable selectedPin: Doc | undefined;
+ @observable selectedPinOrRoute: Doc | undefined;
+
@action
- deselectPin = () => {
- if (this.selectedPin) {
+ deselectPinOrRoute = () => {
+ if (this.selectedPinOrRoute) {
// // Removes filter
// Doc.setDocFilter(this.rootDoc, 'latitude', this.selectedPin.latitude, 'remove');
// Doc.setDocFilter(this.rootDoc, 'longitude', this.selectedPin.longitude, 'remove');
@@ -435,6 +510,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
}
};
+
getView = async (doc: Doc) => {
if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) this.toggleSidebar();
return new Promise<Opt<DocumentView>>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv)));
@@ -444,22 +520,22 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
*/
@action
pushpinClicked = (pinDoc: Doc) => {
- this.deselectPin();
- this.selectedPin = pinDoc;
+ this.deselectPinOrRoute();
+ this.selectedPinOrRoute = pinDoc;
this.bingSearchBarContents = pinDoc.map;
// Doc.setDocFilter(this.rootDoc, 'latitude', this.selectedPin.latitude, 'match');
// Doc.setDocFilter(this.rootDoc, 'longitude', this.selectedPin.longitude, 'match');
- Doc.setDocFilter(this.rootDoc, LinkedTo, `mapPin=${Field.toScriptString(this.selectedPin)}`, 'check');
+ Doc.setDocFilter(this.rootDoc, LinkedTo, `mapPin=${Field.toScriptString(this.selectedPinOrRoute)}`, 'check');
- this.recolorPin(this.selectedPin, 'green');
+ this.recolorPin(this.selectedPinOrRoute, 'green');
- MapAnchorMenu.Instance.Delete = this.deleteSelectedPin;
+ MapAnchorMenu.Instance.Delete = this.deleteSelectedPinOrRoute;
MapAnchorMenu.Instance.Center = this.centerOnSelectedPin;
MapAnchorMenu.Instance.OnClick = this.createNoteAnnotation;
MapAnchorMenu.Instance.StartDrag = this.startAnchorDrag;
- const point = this._bingMap.current.tryLocationToPixel(new this.MicrosoftMaps.Location(this.selectedPin.latitude, this.selectedPin.longitude));
+ const point = this._bingMap.current.tryLocationToPixel(new this.MicrosoftMaps.Location(this.selectedPinOrRoute.latitude, this.selectedPinOrRoute.longitude));
const x = point.x + (this.props.PanelWidth() - this.sidebarWidth()) / 2;
const y = point.y + this.props.PanelHeight() / 2 + 32;
const cpt = this.props.ScreenToLocalTransform().inverse().transformPoint(x, y);
@@ -474,7 +550,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
@action
mapOnClick = (e: { location: { latitude: any; longitude: any } }) => {
this.props.select(false);
- this.deselectPin();
+ this.deselectPinOrRoute();
};
/*
* Updates values of layout doc to match the current map
@@ -520,14 +596,14 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
/// this should use SELECTED pushpin for lat/long if there is a selection, otherwise CENTER
const anchor = Docs.Create.ConfigDocument({
title: 'MapAnchor:' + this.rootDoc.title,
- text: StrCast(this.selectedPin?.map) || StrCast(this.rootDoc.map) || 'map location',
- config_latitude: NumCast((existingPin ?? this.selectedPin)?.latitude ?? this.dataDoc.latitude),
- config_longitude: NumCast((existingPin ?? this.selectedPin)?.longitude ?? this.dataDoc.longitude),
+ text: StrCast(this.selectedPinOrRoute?.map) || StrCast(this.rootDoc.map) || 'map location',
+ config_latitude: NumCast((existingPin ?? this.selectedPinOrRoute)?.latitude ?? this.dataDoc.latitude),
+ config_longitude: NumCast((existingPin ?? this.selectedPinOrRoute)?.longitude ?? this.dataDoc.longitude),
config_map_zoom: NumCast(this.dataDoc.map_zoom),
config_map_type: StrCast(this.dataDoc.map_type),
- config_map: StrCast((existingPin ?? this.selectedPin)?.map) || StrCast(this.dataDoc.map),
+ config_map: StrCast((existingPin ?? this.selectedPinOrRoute)?.map) || StrCast(this.dataDoc.map),
layout_unrendered: true,
- mapPin: existingPin ?? this.selectedPin,
+ mapPin: existingPin ?? this.selectedPinOrRoute,
annotationOn: this.rootDoc,
});
if (anchor) {
@@ -566,7 +642,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
* Removes pin from annotations
*/
@action
- removePushpin = (pinDoc: Doc) => this.removeMapDocument(pinDoc, this.annotationKey);
+ removePushpinOrRoute = (pinOrRouteDoc: Doc) => this.removeMapDocument(pinOrRouteDoc, this.annotationKey);
/*
* Removes pushpin from map render
@@ -576,23 +652,25 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
this._bingMap.current.entities.remove(this.map_docToPinMap.get(pinDoc));
}
this.map_docToPinMap.delete(pinDoc);
- this.selectedPin = undefined;
+ this.selectedPinOrRoute = undefined;
};
@action
- deleteSelectedPin = undoable(() => {
- if (this.selectedPin) {
+ deleteSelectedPinOrRoute = undoable(() => {
+ if (this.selectedPinOrRoute) {
// Removes filter
- Doc.setDocFilter(this.rootDoc, 'latitude', this.selectedPin.latitude, 'remove');
- Doc.setDocFilter(this.rootDoc, 'longitude', this.selectedPin.longitude, 'remove');
- Doc.setDocFilter(this.rootDoc, LinkedTo, `mapPin=${Field.toScriptString(DocCast(this.selectedPin))}`, 'remove');
+ Doc.setDocFilter(this.rootDoc, 'latitude', this.selectedPinOrRoute.latitude, 'remove');
+ Doc.setDocFilter(this.rootDoc, 'longitude', this.selectedPinOrRoute.longitude, 'remove');
+ Doc.setDocFilter(this.rootDoc, LinkedTo, `mapPin=${Field.toScriptString(DocCast(this.selectedPinOrRoute))}`, 'remove');
- this.removePushpin(this.selectedPin);
+ this.removePushpinOrRoute(this.selectedPinOrRoute);
}
MapAnchorMenu.Instance.fadeOut(true);
document.removeEventListener('pointerdown', this.tryHideMapAnchorMenu, true);
}, 'delete pin');
+
+
tryHideMapAnchorMenu = (e: PointerEvent) => {
let target = document.elementFromPoint(e.x, e.y);
while (target) {
@@ -608,9 +686,9 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
@action
centerOnSelectedPin = () => {
- if (this.selectedPin) {
+ if (this.selectedPinOrRoute) {
this._mapRef.current?.flyTo({
- center: [NumCast(this.selectedPin.longitude), NumCast(this.selectedPin.latitude)]
+ center: [NumCast(this.selectedPinOrRoute.longitude), NumCast(this.selectedPinOrRoute.latitude)]
})
}
// if (this.selectedPin) {
@@ -776,12 +854,12 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
false,
[],
{
- title: location ?? `lat=${latitude},lng=${longitude}`,
+ title: location ?? `lat=${NumCast(latitude)},lng=${NumCast(longitude)}`,
map: location,
description: "",
wikiData: wikiData,
- markerType: 'MAPBOX_MARKER',
- markerColor: '#3FB1CE'
+ markerType: 'MAP_PIN',
+ markerColor: '#ff5722'
},
// { title: map ?? `lat=${latitude},lng=${longitude}`, map: map },
// ,'pushpinIDamongus'+ this.incrementer++
@@ -794,14 +872,16 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
}, 'createpin');
@action
- createMapRoute = undoable((coordinates: Position[], origin: string, destination: string) => {
- console.log(coordinates);
+ createMapRoute = undoable((coordinates: Position[], origin: string, destination: any, createPinForDestination: boolean) => {
const mapRoute = Docs.Create.MapRouteDocument(
false,
[],
- {title: `${origin} -> ${destination}`, routeCoordinates: JSON.stringify(coordinates)},
+ {title: `${origin} --> ${destination.place_name}`, routeCoordinates: JSON.stringify(coordinates)},
);
this.addDocument(mapRoute, this.annotationKey);
+ if (createPinForDestination) {
+ this.createPushpin(destination.center[1], destination.center[0], destination.place_name);
+ }
return mapRoute;
// mapMarker.infoWindowOpen = true;
@@ -853,10 +933,11 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
*/
handleSearchChange = async (searchText: string) => {
const features = await MapboxApiUtility.forwardGeocodeForFeatures(searchText);
- if (features){
+ if (features && !this.isAnimating){
runInAction(() => {
this.settingsOpen= false;
this.featuresFromGeocodeResults = features;
+ this.routeToAnimate = undefined;
})
}
// try {
@@ -874,12 +955,65 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
// @action
// debouncedCall = React.useCallback(debounce(this.debouncedOnSearchBarChange, 300), []);
+
+ @action
+ handleMapClick = (e: MapLayerMouseEvent) => {
+ if (this._mapRef.current){
+ const features = this._mapRef.current.queryRenderedFeatures(
+ e.point, {
+ layers: ['map-routes-layer']
+ }
+ );
+
+ console.error(features);
+ if (features && features.length > 0 && features[0].properties && features[0].geometry) {
+ const geometry = features[0].geometry as LineString;
+ const routeTitle: string = features[0].properties['routeTitle'];
+ const routeDoc: Doc | undefined = this.allRoutes.find((routeDoc) => routeDoc.title === routeTitle);
+ this.deselectPinOrRoute(); // TODO: Also deselect route if selected
+ if (routeDoc){
+ this.selectedPinOrRoute = routeDoc;
+ Doc.setDocFilter(this.rootDoc, LinkedTo, `mapRoute=${Field.toScriptString(this.selectedPinOrRoute)}`, 'check');
+
+ // TODO: Recolor route
+
+ MapAnchorMenu.Instance.Delete = this.deleteSelectedPinOrRoute;
+ MapAnchorMenu.Instance.Center = this.centerOnSelectedPin;
+ MapAnchorMenu.Instance.OnClick = this.createNoteAnnotation;
+ MapAnchorMenu.Instance.StartDrag = this.startAnchorDrag;
+
+ MapAnchorMenu.Instance.setRouteDoc(routeDoc);
+
+ // TODO: Subject to change
+ MapAnchorMenu.Instance.setAllMapboxPins(
+ this.allAnnotations.filter(anno => !anno.layout_unrendered)
+ )
+
+ MapAnchorMenu.Instance.DisplayRoute = this.displayRoute;
+ MapAnchorMenu.Instance.HideRoute = this.hideRoute;
+ MapAnchorMenu.Instance.AddNewRouteToMap = this.createMapRoute;
+ MapAnchorMenu.Instance.CreatePin = this.addMarkerForFeature;
+ MapAnchorMenu.Instance.OpenAnimationPanel = this.openAnimationPanel;
+
+ // this.selectedRouteCoordinates = geometry.coordinates;
+
+ MapAnchorMenu.Instance.setMenuType('route');
+
+ MapAnchorMenu.Instance.jumpTo(e.originalEvent.clientX, e.originalEvent.clientY, true);
+
+ document.addEventListener('pointerdown', this.tryHideMapAnchorMenu, true);
+ }
+ }
+ }
+ }
+
+
/**
* Makes a reverse geocoding API call to retrieve features corresponding to a map click (based on longitude
* and latitude). Sets the search results accordingly.
* @param e
*/
- handleMapClick = async (e: MapLayerMouseEvent) => {
+ handleMapDblClick = async (e: MapLayerMouseEvent) => {
e.preventDefault();
const lngLat: LngLat = e.lngLat;
const longitude: number = lngLat.lng;
@@ -914,18 +1048,18 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
@action
handleMarkerClick = (e: MarkerEvent<mapboxgl.Marker, MouseEvent>, pinDoc: Doc) => {
this.featuresFromGeocodeResults = [];
- this.deselectPin(); // TODO: check this method
- this.selectedPin = pinDoc;
+ this.deselectPinOrRoute(); // TODO: check this method
+ this.selectedPinOrRoute = pinDoc;
// this.bingSearchBarContents = pinDoc.map;
// Doc.setDocFilter(this.rootDoc, 'latitude', this.selectedPin.latitude, 'match');
// Doc.setDocFilter(this.rootDoc, 'longitude', this.selectedPin.longitude, 'match');
- Doc.setDocFilter(this.rootDoc, LinkedTo, `mapPin=${Field.toScriptString(this.selectedPin)}`, 'check');
+ Doc.setDocFilter(this.rootDoc, LinkedTo, `mapPin=${Field.toScriptString(this.selectedPinOrRoute)}`, 'check');
- this.recolorPin(this.selectedPin, 'green'); // TODO: check this method
+ this.recolorPin(this.selectedPinOrRoute, 'green'); // TODO: check this method
- MapAnchorMenu.Instance.Delete = this.deleteSelectedPin;
+ MapAnchorMenu.Instance.Delete = this.deleteSelectedPinOrRoute;
MapAnchorMenu.Instance.Center = this.centerOnSelectedPin;
MapAnchorMenu.Instance.OnClick = this.createNoteAnnotation;
MapAnchorMenu.Instance.StartDrag = this.startAnchorDrag;
@@ -941,11 +1075,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
MapAnchorMenu.Instance.AddNewRouteToMap = this.createMapRoute;
MapAnchorMenu.Instance.CreatePin = this.addMarkerForFeature;
- // const longitude = NumCast(pinDoc.longitude);
- // const latitude = NumCast(pinDoc.longitude);
- // const x = longitude + (this.props.PanelWidth() - this.sidebarWidth()) / 2;
- // const y = latitude + this.props.PanelHeight() / 2 + 20;
- // const cpt = this.props.ScreenToLocalTransform().inverse().transformPoint(x, y);
+ MapAnchorMenu.Instance.setMenuType('standard');
+
MapAnchorMenu.Instance.jumpTo(e.originalEvent.clientX, e.originalEvent.clientY, true);
document.addEventListener('pointerdown', this.tryHideMapAnchorMenu, true);
@@ -979,6 +1110,351 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
}
}
+ @observable
+ isAnimating: boolean = false;
+
+ @observable
+ isPaused: boolean = false;
+
+ @observable
+ routeToAnimate: Doc | undefined = undefined;
+
+ @observable
+ animationPhase: number = 0;
+
+ @observable
+ finishedFlyTo: boolean = false;
+
+ @action
+ setAnimationPhase = (newValue: number) => {
+ this.animationPhase = newValue;
+ };
+
+ @observable
+ frameId: number | null = null;
+
+ @action
+ setFrameId = (frameId: number) => {
+ this.frameId = frameId;
+ }
+
+ @action
+ openAnimationPanel = (routeDoc: Doc | undefined) => {
+ if (routeDoc){
+ MapAnchorMenu.Instance.fadeOut(true);
+ document.removeEventListener('pointerdown', this.tryHideMapAnchorMenu, true);
+ this.routeToAnimate = routeDoc;
+ }
+ }
+
+ @observable
+ animationDuration = 40000;
+
+ @observable
+ animationAltitude = 12800;
+
+ @observable
+ pathDistance = 0;
+
+ @observable
+ isStreetViewAnimation: boolean = false;
+
+ @observable
+ animationSpeed: AnimationSpeed = AnimationSpeed.MEDIUM;
+
+ @action
+ updateAnimationSpeed = () => {
+ switch (this.animationSpeed){
+ case AnimationSpeed.SLOW:
+ this.animationSpeed = AnimationSpeed.MEDIUM;
+ break;
+ case AnimationSpeed.MEDIUM:
+ this.animationSpeed = AnimationSpeed.FAST;
+ break;
+ case AnimationSpeed.FAST:
+ this.animationSpeed = AnimationSpeed.SLOW;
+ break;
+ default:
+ this.animationSpeed = AnimationSpeed.MEDIUM;
+ break;
+ }
+ }
+ @computed get animationSpeedTooltipText(): string {
+ switch (this.animationSpeed) {
+ case AnimationSpeed.SLOW:
+ return '1x speed';
+ case AnimationSpeed.MEDIUM:
+ return '2x speed';
+ case AnimationSpeed.FAST:
+ return '3x speed';
+ default:
+ return '2x speed';
+ }
+ }
+ @computed get animationSpeedIcon(): JSX.Element{
+ switch (this.animationSpeed) {
+ case AnimationSpeed.SLOW:
+ return slowSpeedIcon;
+ case AnimationSpeed.MEDIUM:
+ return mediumSpeedIcon;
+ case AnimationSpeed.FAST:
+ return fastSpeedIcon;
+ default:
+ return mediumSpeedIcon;
+ }
+ }
+
+ @action
+ toggleIsStreetViewAnimation = () => {
+ this.isStreetViewAnimation = !this.isStreetViewAnimation;
+ }
+
+ @observable
+ dynamicRouteFeature: Feature<Geometry, GeoJsonProperties> = {
+ type: 'Feature',
+ properties: {},
+ geometry: {
+ type: 'LineString',
+ coordinates: []
+ }
+ };
+
+
+ @observable
+ path: turf.helpers.Feature<turf.helpers.LineString, turf.helpers.Properties> = {
+ type: 'Feature',
+ geometry: {
+ type: 'LineString',
+ coordinates: []
+ },
+ properties: {}
+ };
+
+ getFeatureFromRouteDoc = (routeDoc: Doc): Feature<Geometry, GeoJsonProperties> => {
+ const geometry: LineString = {
+ type: 'LineString',
+ coordinates: JSON.parse(StrCast(routeDoc.routeCoordinates)),
+ };
+ return {
+ type: 'Feature',
+ properties: {
+ 'routeTitle': routeDoc.title},
+ geometry: geometry,
+ };
+ }
+
+ @action
+ playAnimation = (status: AnimationStatus) => {
+ if (!this._mapRef.current || !this.routeToAnimate){
+ return;
+ }
+
+ if (this.isAnimating){
+ return;
+ }
+ this.animationPhase = status === AnimationStatus.RESUME ? this.animationPhase : 0;
+ this.frameId = AnimationStatus.RESUME ? this.frameId : null;
+ this.finishedFlyTo = AnimationStatus.RESUME ? this.finishedFlyTo : false;
+
+ const path = turf.lineString(this.selectedRouteCoordinates);
+
+ this.settingsOpen = false;
+ this.path = path;
+ this.pathDistance = turf.lineDistance(path);
+ this.isAnimating = true;
+ runInAction(() => {
+ return new Promise<void>(async (resolve) => {
+ let animationUtil;
+ try {
+ const targetLngLat = {
+ lng: this.selectedRouteCoordinates[0][0],
+ lat: this.selectedRouteCoordinates[0][1],
+ };
+
+ animationUtil = new AnimationUtility(
+ targetLngLat,
+ this.selectedRouteCoordinates,
+ this.isStreetViewAnimation,
+ this.animationSpeed
+ );
+
+
+ const updateFrameId = (newFrameId: number) => {
+ this.setFrameId(newFrameId);
+ }
+
+ const updateAnimationPhase = (
+ newAnimationPhase: number,
+ ) => {
+ this.setAnimationPhase(newAnimationPhase);
+ };
+
+ if (status !== AnimationStatus.RESUME) {
+
+ const result = await animationUtil.flyInAndRotate({
+ map: this._mapRef.current!,
+ // targetLngLat,
+ // duration 3000
+ // startAltitude: 3000000,
+ // endAltitude: this.isStreetViewAnimation ? 80 : 12000,
+ // startBearing: 0,
+ // endBearing: -20,
+ // startPitch: 40,
+ // endPitch: this.isStreetViewAnimation ? 80 : 50,
+ updateFrameId,
+ });
+
+ console.log("Bearing: ", result.bearing);
+ console.log("Altitude: ", result.altitude);
+
+ }
+
+ runInAction(() => {
+ this.finishedFlyTo = true;
+ })
+
+ // follow the path while slowly rotating the camera, passing in the camera bearing and altitude from the previous animation
+ await animationUtil.animatePath({
+ map: this._mapRef.current!,
+ // path: this.path,
+ // startBearing: -20,
+ // startAltitude: this.isStreetViewAnimation ? 80 : 12000,
+ // pitch: this.isStreetViewAnimation ? 80: 50,
+ currentAnimationPhase: this.animationPhase,
+ updateAnimationPhase,
+ updateFrameId,
+ });
+
+ // get the bounds of the linestring, use fitBounds() to animate to a final view
+ const bbox3d = turf.bbox(this.path);
+
+ const bbox2d: LngLatBoundsLike = [bbox3d[0], bbox3d[1], bbox3d[2], bbox3d[3]];
+
+ this._mapRef.current!.fitBounds(bbox2d, {
+ duration: 3000,
+ pitch: 30,
+ bearing: 0,
+ padding: 120,
+ });
+
+ setTimeout(() => {
+ resolve();
+ }, 10000);
+ } catch (error: any){
+ console.log(error);
+ console.log('animation util: ', animationUtil);
+ }});
+
+ })
+
+
+ }
+
+
+ @action
+ pauseAnimation = () => {
+ if (this.frameId && this.animationPhase > 0){
+ window.cancelAnimationFrame(this.frameId);
+ this.frameId = null;
+ this.isAnimating = false;
+ }
+ }
+
+ @action
+ stopAndCloseAnimation = () => {
+ if (this.frameId){
+ window.cancelAnimationFrame(this.frameId);
+ this.frameId = null;
+ this.finishedFlyTo = false;
+ this.isAnimating = false;
+ this.animationPhase = 0;
+ this.routeToAnimate = undefined;
+ // this.selectedRouteCoordinates = [];
+ }
+ // reset bearing and pitch to original, zoom out
+ }
+
+ @action
+ exportAnimationToVideo = () => {
+
+ }
+
+ getRouteAnimationOptions = (): JSX.Element => {
+ return (
+ <>
+ <IconButton
+ tooltip={this.isAnimating && this.finishedFlyTo ? 'Pause Animation' : 'Play Animation'}
+ onPointerDown={() => {
+ if (this.isAnimating && this.finishedFlyTo) {
+ this.pauseAnimation();
+ } else if (this.animationPhase > 0) {
+ this.playAnimation(AnimationStatus.RESUME); // Resume from the current phase
+ } else {
+ this.playAnimation(AnimationStatus.START); // Play from the beginning
+ }
+ }}
+ icon={this.isAnimating && this.finishedFlyTo ?
+ <FontAwesomeIcon icon={faPause as IconLookup}/>
+ :
+ <FontAwesomeIcon icon={faPlay as IconLookup}/>
+ }
+ color='black'
+ size={Size.MEDIUM}
+ />
+ {this.isAnimating && this.finishedFlyTo &&
+ <IconButton
+ tooltip='Restart animation'
+ onPointerDown={() => this.playAnimation(AnimationStatus.RESTART)}
+ icon={<FontAwesomeIcon icon={faRotate as IconLookup}/>}
+ color='black'
+ size={Size.MEDIUM}
+ />
+
+ }
+ <IconButton
+ tooltip='Stop and close animation'
+ onPointerDown={this.stopAndCloseAnimation}
+ icon={<FontAwesomeIcon icon={faCircleXmark as IconLookup}/>}
+ color='black'
+ size={Size.MEDIUM}
+ />
+ <IconButton
+ style={{marginRight: '10px'}}
+ tooltip='Export to video'
+ onPointerDown={this.exportAnimationToVideo}
+ icon={<FontAwesomeIcon icon={faFileExport as IconLookup}/>}
+ color='black'
+ size={Size.MEDIUM}
+ />
+ {!this.isAnimating &&
+ <>
+ <div className='animation-suboptions'>
+ <div>|</div>
+ <FormControlLabel
+ label='Street view animation'
+ labelPlacement='start'
+ control={
+ <Checkbox
+ color='success'
+ checked={this.isStreetViewAnimation}
+ onChange={this.toggleIsStreetViewAnimation}
+ />
+ }
+ />
+ <div id='last-divider'>|</div>
+ <IconButton
+ tooltip={this.animationSpeedTooltipText}
+ onPointerDown={this.updateAnimationSpeed}
+ icon={this.animationSpeedIcon}
+ size={Size.MEDIUM}
+ />
+ </div>
+ </>
+ }
+ </>
+ )
+ }
+
@action
hideRoute = () => {
this.temporaryRouteSource = {
@@ -1015,8 +1491,10 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
@action
toggleSettings = () => {
- this.featuresFromGeocodeResults = [];
- this.settingsOpen = !this.settingsOpen;
+ if (!this.isAnimating && this.animationPhase == 0) {
+ this.featuresFromGeocodeResults = [];
+ this.settingsOpen = !this.settingsOpen;
+ }
}
@action
@@ -1056,6 +1534,16 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
}
}
+ getMarkerIcon = (pinDoc: Doc): JSX.Element | null => {
+ const markerType = StrCast(pinDoc.markerType);
+ const markerColor = StrCast(pinDoc.markerColor);
+
+ return MarkerIcons.getFontAwesomeIcon(markerType, '2x', markerColor) ?? null;
+
+ }
+
+
+
@@ -1092,21 +1580,22 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
<div style={{ mixBlendMode: 'multiply' }}>{renderAnnotations(this.transparentFilter)}</div>
{renderAnnotations(this.opaqueFilter)}
{SnappingManager.GetIsDragging() ? null : renderAnnotations()}
+ {!this.routeToAnimate &&
+ <div className="mapBox-searchbar">
+ <TextField
+ fullWidth
+ placeholder='Enter a location'
+ onChange={(e) => this.handleSearchChange(e.target.value)}
+ />
+ <IconButton
+ icon={<FontAwesomeIcon icon={faGear as IconLookup} size='1x'/>}
+ type={Type.TERT}
+ onClick={(e) => this.toggleSettings()}
- <div className="mapBox-searchbar">
- <TextField
- fullWidth
- placeholder='Enter a location'
- onChange={(e) => this.handleSearchChange(e.target.value)}
- />
- <IconButton
- icon={<FontAwesomeIcon icon={faGear as IconLookup} size='1x'/>}
- type={Type.TERT}
- onClick={(e) => this.toggleSettings()}
-
- />
- </div>
- {this.settingsOpen &&
+ />
+ </div>
+ }
+ {this.settingsOpen && !this.routeToAnimate &&
<div className='mapbox-settings-panel' style={{right: `${0+ this.sidebarWidth()}px`}}>
<div className='mapbox-style-select'>
<div>
@@ -1151,45 +1640,52 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
</div>
</div>
}
-
- <div className='mapbox-geocoding-search-results'>
- {this.featuresFromGeocodeResults.length > 0 && (
+ {this.routeToAnimate &&
+ <div className='animation-panel'>
+ <div id='route-to-animate-title'>
+ {StrCast(this.routeToAnimate.title)}
+ </div>
+ <div className='route-animation-options'>
+ {this.getRouteAnimationOptions()}
+ </div>
+ </div>
+ }
+ {this.featuresFromGeocodeResults.length > 0 && (
+ <div className='mapbox-geocoding-search-results'>
<React.Fragment>
- <h4>Choose a location for your pin: </h4>
- {this.featuresFromGeocodeResults
- .filter(feature => feature.place_name)
- .map((feature, idx) => (
- <div
- key={idx}
- className='search-result-container'
- onClick={() => {
- this.handleSearchChange("");
- this.addMarkerForFeature(feature);
- }}
- >
- <div className='search-result-place-name'>
- {feature.place_name}
+ <h4>Choose a location for your pin: </h4>
+ {this.featuresFromGeocodeResults
+ .filter(feature => feature.place_name)
+ .map((feature, idx) => (
+ <div
+ key={idx}
+ className='search-result-container'
+ onClick={() => {
+ this.handleSearchChange("");
+ this.addMarkerForFeature(feature);
+ }}
+ >
+ <div className='search-result-place-name'>
+ {feature.place_name}
+ </div>
</div>
- </div>
))}
</React.Fragment>
- )}
- </div>
+
+ </div>
+ )}
<MapProvider>
<MapboxMap
ref={this._mapRef}
- initialViewState={{
- longitude: -100,
- latitude: 40,
- zoom: 3.5
- }}
mapboxAccessToken={MAPBOX_ACCESS_TOKEN}
id="mapbox-map"
mapStyle={this.mapStyle}
style={{height: '100%', width: '100%'}}
- {...this.mapboxMapViewState}
+ initialViewState={this.isAnimating ? undefined : this.mapboxMapViewState}
+ // {...this.mapboxMapViewState}
onMove={this.onMapMove}
- onDblClick={this.handleMapClick}
+ onClick={this.handleMapClick}
+ onDblClick={this.handleMapDblClick}
terrain={this.showTerrain ? { source: 'mapbox-dem', exaggeration: 2.0 } : undefined}
@@ -1210,6 +1706,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
layout={{"line-join": "round", "line-cap": "round"}}
paint={{"line-color": "#36454F", "line-width": 4, "line-dasharray": [1,1]}}
/>
+ {!this.isAnimating && this.animationPhase == 0 &&
<Layer
id='map-routes-layer'
type='line'
@@ -1217,9 +1714,60 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
layout={{"line-join": "round", "line-cap": "round"}}
paint={{"line-color": "#FF0000", "line-width": 4}}
/>
+ }
+ {this.routeToAnimate && (this.isAnimating || this.animationPhase > 0) &&
+ <>
+ {!this.isStreetViewAnimation &&
+ <>
+ <Source id='animated-route' type='geojson' data={this.updatedRouteCoordinates}/>
+ <Layer
+ id='dynamic-animation-line'
+ type='line'
+ source='animated-route'
+ paint={{
+ 'line-color': 'yellow',
+ 'line-width': 4,
+ }}
+ />
+ </>
+ }
+ <Source id='start-pin-base' type='geojson' data={AnimationUtility.createGeoJSONCircle(this.selectedRouteCoordinates[0], 0.04)}/>
+ <Source id='start-pin-top' type='geojson' data={AnimationUtility.createGeoJSONCircle(this.selectedRouteCoordinates[0], 0.25)}/>
+ <Source id='end-pin-base' type='geojson' data={AnimationUtility.createGeoJSONCircle(this.selectedRouteCoordinates.slice(-1)[0], 0.04)}/>
+ <Source id='end-pin-top' type='geojson' data={AnimationUtility.createGeoJSONCircle(this.selectedRouteCoordinates.slice(-1)[0], 0.25)}/>
+ <Layer id='start-fill-pin-base' type='fill-extrusion' source='start-pin-base'
+ paint={{
+ 'fill-extrusion-color': '#0bfc03',
+ 'fill-extrusion-height': 1000
+ }}
+ />
+ <Layer id='start-fill-pin-top' type='fill-extrusion' source='start-pin-top'
+ paint={{
+ 'fill-extrusion-color': '#0bfc03',
+ 'fill-extrusion-base': 1000,
+ 'fill-extrusion-height': 1200
+ }}
+ />
+ <Layer id='end-fill-pin-base' type='fill-extrusion' source='end-pin-base'
+ paint={{
+ 'fill-extrusion-color': '#eb1c1c',
+ 'fill-extrusion-height': 1000
+ }}
+ />
+ <Layer id='end-fill-pin-top' type='fill-extrusion' source='end-pin-top'
+ paint={{
+ 'fill-extrusion-color': '#eb1c1c',
+ 'fill-extrusion-base': 1000,
+ 'fill-extrusion-height': 1200
+ }}
+ />
+
+ </>
+ }
+
<>
- {this.allPushpins
+ {!this.isAnimating && this.animationPhase == 0 && this.allPushpins
// .filter(anno => !anno.layout_unrendered)
.map((pushpin, idx) => (
<Marker
@@ -1228,7 +1776,9 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
latitude={NumCast(pushpin.latitude)}
anchor='bottom'
onClick={(e: MarkerEvent<mapboxgl.Marker, MouseEvent>) => this.handleMarkerClick(e, pushpin)}
- />
+ >
+ {this.getMarkerIcon(pushpin)}
+ </Marker>
))}
</>
diff --git a/src/client/views/nodes/MapBox/MarkerIcons.tsx b/src/client/views/nodes/MapBox/MarkerIcons.tsx
index cf50109ac..146f296c1 100644
--- a/src/client/views/nodes/MapBox/MarkerIcons.tsx
+++ b/src/client/views/nodes/MapBox/MarkerIcons.tsx
@@ -1,57 +1,46 @@
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { faShopify } from '@fortawesome/free-brands-svg-icons';
-import { IconLookup, faBasketball, faBicycle, faBowlFood, faBus, faCameraRetro, faCar, faCartShopping, faFilm, faFootball, faFutbol, faHockeyPuck, faHospital, faHotel, faHouse, faLandmark, faMasksTheater, faMugSaucer, faPersonHiking, faPlane, faSchool, faShirt, faShop, faSquareParking, faStar, faTrainSubway, faTree, faUtensils, faVolleyball } from '@fortawesome/free-solid-svg-icons';
+import { faBasketball, faBicycle, faBowlFood, faBus, faCameraRetro, faCar, faCartShopping, faFilm, faFootball, faFutbol, faHockeyPuck, faHospital, faHotel, faHouse, faLandmark, faLocationDot, faLocationPin, faMapPin, faMasksTheater, faMugSaucer, faPersonHiking, faPlane, faSchool, faShirt, faShop, faSquareParking, faStar, faTrainSubway, faTree, faUtensils, faVolleyball } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import React = require('react');
-export type MapboxColor = 'yellow' | 'red' | 'orange' | 'purple' | 'pink' | 'blue' | 'green';
-type ColorProperties = {
- fill: string,
- stroke: string
-}
-type ColorsMap = {
- [key in MapboxColor]: ColorProperties;
-}
-
export class MarkerIcons {
- static getMapboxIcon = (color: string) => {
- return (
- <svg xmlns="http://www.w3.org/2000/svg" id="marker" data-name="marker" width="20" height="48" viewBox="0 0 20 35">
- <g id="mapbox-marker-icon">
- <g id="icon">
- <ellipse id="shadow" cx="10" cy="27" rx="9" ry="5" fill="#c4c4c4" opacity="0.3" />
- <g id="mask" opacity="0.3">
- <g id="group">
- <path id="shadow-2" data-name="shadow" fill="#bfbfbf" d="M10,32c5,0,9-2.2,9-5s-4-5-9-5-9,2.2-9,5S5,32,10,32Z" fillRule="evenodd"/>
- </g>
- </g>
- <path id="color" fill={color} strokeWidth="0.5" d="M19.25,10.4a13.0663,13.0663,0,0,1-1.4607,5.2235,41.5281,41.5281,0,0,1-3.2459,5.5483c-1.1829,1.7369-2.3662,3.2784-3.2541,4.3859-.4438.5536-.8135.9984-1.0721,1.3046-.0844.1-.157.1852-.2164.2545-.06-.07-.1325-.1564-.2173-.2578-.2587-.3088-.6284-.7571-1.0723-1.3147-.8879-1.1154-2.0714-2.6664-3.2543-4.41a42.2677,42.2677,0,0,1-3.2463-5.5535A12.978,12.978,0,0,1,.75,10.4,9.4659,9.4659,0,0,1,10,.75,9.4659,9.4659,0,0,1,19.25,10.4Z"/>
- <path id="circle" fill="#fff" stroke='white' strokeWidth="0.5" d="M13.55,10A3.55,3.55,0,1,1,10,6.45,3.5484,3.5484,0,0,1,13.55,10Z"/>
- </g>
- </g>
- <rect width="20" height="48" fill="none"/>
- </svg>
- )
- }
+ // static getMapboxIcon = (color: string) => {
+ // return (
+ // <svg xmlns="http://www.w3.org/2000/svg" id="marker" data-name="marker" width="20" height="48" viewBox="0 0 20 35">
+ // <g id="mapbox-marker-icon">
+ // <g id="icon">
+ // <ellipse id="shadow" cx="10" cy="27" rx="9" ry="5" fill="#c4c4c4" opacity="0.3" />
+ // <g id="mask" opacity="0.3">
+ // <g id="group">
+ // <path id="shadow-2" data-name="shadow" fill="#bfbfbf" d="M10,32c5,0,9-2.2,9-5s-4-5-9-5-9,2.2-9,5S5,32,10,32Z" fillRule="evenodd"/>
+ // </g>
+ // </g>
+ // <path id="color" fill={color} strokeWidth="0.5" d="M19.25,10.4a13.0663,13.0663,0,0,1-1.4607,5.2235,41.5281,41.5281,0,0,1-3.2459,5.5483c-1.1829,1.7369-2.3662,3.2784-3.2541,4.3859-.4438.5536-.8135.9984-1.0721,1.3046-.0844.1-.157.1852-.2164.2545-.06-.07-.1325-.1564-.2173-.2578-.2587-.3088-.6284-.7571-1.0723-1.3147-.8879-1.1154-2.0714-2.6664-3.2543-4.41a42.2677,42.2677,0,0,1-3.2463-5.5535A12.978,12.978,0,0,1,.75,10.4,9.4659,9.4659,0,0,1,10,.75,9.4659,9.4659,0,0,1,19.25,10.4Z"/>
+ // <path id="circle" fill="#fff" stroke='white' strokeWidth="0.5" d="M13.55,10A3.55,3.55,0,1,1,10,6.45,3.5484,3.5484,0,0,1,13.55,10Z"/>
+ // </g>
+ // </g>
+ // <rect width="20" height="48" fill="none"/>
+ // </svg>
+ // )
+ // }
- static getFontAwesomeIcon(key: string, color?: string): JSX.Element | undefined {
+ static getFontAwesomeIcon(key: string, size: string, color?: string): JSX.Element {
const icon: IconProp = MarkerIcons.FAMarkerIconsMap[key];
+ const iconProps: any = { icon };
- if (icon) {
- const iconProps: any = { icon };
-
- if (color) {
- iconProps.color = color;
- }
-
- return (<FontAwesomeIcon {...iconProps} size='1x' />);
- }
+ if (color) {
+ iconProps.color = color;
+ }
+
+ return (<FontAwesomeIcon {...iconProps} size={size} />);
+
- return undefined;
}
static FAMarkerIconsMap: {[key: string]: IconProp} = {
+ 'MAP_PIN': faLocationDot,
'RESTAURANT_ICON': faUtensils,
'HOTEL_ICON': faHotel,
'HOUSE_ICON': faHouse,