From bc23855777633dfd1caf7237b75c1e8fee88dff4 Mon Sep 17 00:00:00 2001 From: zaultavangar Date: Mon, 11 Dec 2023 20:37:52 -0500 Subject: new updates to map feature --- src/client/views/nodes/MapBox/MarkerIcons.tsx | 87 +++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 src/client/views/nodes/MapBox/MarkerIcons.tsx (limited to 'src/client/views/nodes/MapBox/MarkerIcons.tsx') diff --git a/src/client/views/nodes/MapBox/MarkerIcons.tsx b/src/client/views/nodes/MapBox/MarkerIcons.tsx new file mode 100644 index 000000000..cf50109ac --- /dev/null +++ b/src/client/views/nodes/MapBox/MarkerIcons.tsx @@ -0,0 +1,87 @@ +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 { 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 ( + + + + + + + + + + + + + + + + ) + } + + static getFontAwesomeIcon(key: string, color?: string): JSX.Element | undefined { + const icon: IconProp = MarkerIcons.FAMarkerIconsMap[key]; + + if (icon) { + const iconProps: any = { icon }; + + if (color) { + iconProps.color = color; + } + + return (); + } + + return undefined; + } + + static FAMarkerIconsMap: {[key: string]: IconProp} = { + 'RESTAURANT_ICON': faUtensils, + 'HOTEL_ICON': faHotel, + 'HOUSE_ICON': faHouse, + 'AIRPLANE_ICON': faPlane, + 'CAR_ICON': faCar, + 'BUS_ICON': faBus, + 'TRAIN_ICON': faTrainSubway, + 'BICYCLE_ICON': faBicycle, + 'PARKING_ICON': faSquareParking, + 'PHOTO_ICON': faCameraRetro, + 'CAFE_ICON': faMugSaucer, + 'STAR_ICON': faStar, + 'SHOPPING_CART_ICON': faCartShopping, + 'SHOPIFY_ICON': faShopify, + 'SHOP_ICON': faShop, + 'SHIRT_ICON': faShirt, + 'FOOD_ICON': faBowlFood, + 'LANDMARK_ICON': faLandmark, + 'HOSPITAL_ICON': faHospital, + 'NATURE_ICON': faTree, + 'HIKING_ICON': faPersonHiking, + 'SOCCER_ICON': faFutbol, + 'VOLLEYBALL_ICON': faVolleyball, + 'BASKETBALL_ICON': faBasketball, + 'HOCKEY_ICON': faHockeyPuck, + 'FOOTBALL_ICON': faFootball, + 'SCHOOL_ICON': faSchool, + 'THEATER_ICON': faMasksTheater, + 'FILM_ICON': faFilm + } + + +} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From e9b59a2790006af60206af7f676ad4a0ccceee13 Mon Sep 17 00:00:00 2001 From: zaultavangar Date: Thu, 14 Dec 2023 12:43:40 -0500 Subject: adding animation functionality --- package-lock.json | 1433 +++++++++++++++++++- package.json | 9 +- .../views/nodes/MapBox/AnimationSpeedIcons.tsx | 35 + src/client/views/nodes/MapBox/AnimationUtility.ts | 429 ++++++ src/client/views/nodes/MapBox/MapAnchorMenu.tsx | 118 +- src/client/views/nodes/MapBox/MapBox.scss | 50 + src/client/views/nodes/MapBox/MapBox.tsx | 776 +++++++++-- src/client/views/nodes/MapBox/MarkerIcons.tsx | 69 +- 8 files changed, 2714 insertions(+), 205 deletions(-) create mode 100644 src/client/views/nodes/MapBox/AnimationSpeedIcons.tsx create mode 100644 src/client/views/nodes/MapBox/AnimationUtility.ts (limited to 'src/client/views/nodes/MapBox/MarkerIcons.tsx') 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 = ( + + + + + + + +); + +export const mediumSpeedIcon: JSX.Element = ( + + + + + + + +); + +export const fastSpeedIcon: JSX.Element = ( + + + + + +); + 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; + 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, + // startBearing: number, + // startAltitude: number, + // pitch: number, + currentAnimationPhase: number, + updateAnimationPhase: ( + newAnimationPhase: number, + ) => void, + updateFrameId: (newFrameId: number) => void; + + }) => { + return new Promise(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=> { + 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 { @@ -61,17 +61,28 @@ export class MapAnchorMenu extends AntimodeMenu { public DisplayRoute: (routeInfoMap: Record | 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 { 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 { // 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 { } } + @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 { 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 { 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 { /> } - {this.menuType === 'route' && + {this.menuType === 'routeCreation' && <> { icon={} color={SettingsManager.userColor} /> + + } + {this.menuType === 'route' && + <> + } + color={SettingsManager.userColor} + /> this.OpenAnimationPanel(this.routeDoc)} /**TODO: fix */ icon={} color={SettingsManager.userColor} /> +
+ } + color={SettingsManager.userColor} + /> +
} color={SettingsManager.userColor} /> + + } {this.menuType === 'customize' && <> @@ -351,7 +403,7 @@ export class MapAnchorMenu extends AntimodeMenu { /> this.revertToOriginalMarker()} icon={} color={SettingsManager.userColor} /> @@ -386,7 +438,7 @@ export class MapAnchorMenu extends AntimodeMenu { {this.menuType === 'standard' &&
{this.title}
} - {this.menuType === 'route' && + {this.menuType === 'routeCreation' &&
{ circleSize={15} circleSpacing={7} width='100%' - onChange={(color) => console.log(color.hex)} + onChange={(color) => this.onMarkerColorChange(color)} />
- {Object.keys(MarkerIcons.FAMarkerIconsMap).map((iconKey) => { - const icon = MarkerIcons.getFontAwesomeIcon(iconKey); - if (icon){ - return ( -
- {}} - icon={MarkerIcons.getFontAwesomeIcon(iconKey, 'white')} - /> -
- ) - } - return null; - })} + {Object.keys(MarkerIcons.FAMarkerIconsMap).map((iconKey) => ( +
+ this.onMarkerIconChange(iconKey)} + icon={MarkerIcons.getFontAwesomeIcon(iconKey, '1x', 'white')} + /> +
+ ))}
+ } + {this.menuType === 'route' && this.routeDoc && +
+ {StrCast(this.routeDoc.title)} +
+ } {buttons} 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 anno.type === DocumentType.MAPROUTE); } + @computed get updatedRouteCoordinates(): Feature { + 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[] = this.allRoutes.map(route => { - console.log("Route coords: ", route.coordinates); + const features: Feature[] = 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 this._disposers[key]?.()); } @@ -199,7 +273,7 @@ export class MapBox extends ViewBoxAnnotatableComponent { - 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 { 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 { 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 { - 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 { if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) this.toggleSidebar(); return new Promise>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv))); @@ -444,22 +520,22 @@ export class MapBox extends ViewBoxAnnotatableComponent { - 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 { 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 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 { - 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 { - 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 { - 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 { 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 { + 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, 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 { + 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 = { + type: 'Feature', + properties: {}, + geometry: { + type: 'LineString', + coordinates: [] + } + }; + + + @observable + path: turf.helpers.Feature = { + type: 'Feature', + geometry: { + type: 'LineString', + coordinates: [] + }, + properties: {} + }; + + getFeatureFromRouteDoc = (routeDoc: Doc): Feature => { + 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(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 ( + <> + { + 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 ? + + : + + } + color='black' + size={Size.MEDIUM} + /> + {this.isAnimating && this.finishedFlyTo && + this.playAnimation(AnimationStatus.RESTART)} + icon={} + color='black' + size={Size.MEDIUM} + /> + + } + } + color='black' + size={Size.MEDIUM} + /> + } + color='black' + size={Size.MEDIUM} + /> + {!this.isAnimating && + <> +
+
|
+ + } + /> +
|
+ +
+ + } + + ) + } + @action hideRoute = () => { this.temporaryRouteSource = { @@ -1015,8 +1491,10 @@ export class MapBox extends ViewBoxAnnotatableComponent { - 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 { + 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{renderAnnotations(this.transparentFilter)} {renderAnnotations(this.opaqueFilter)} {SnappingManager.GetIsDragging() ? null : renderAnnotations()} + {!this.routeToAnimate && +
+ this.handleSearchChange(e.target.value)} + /> + } + type={Type.TERT} + onClick={(e) => this.toggleSettings()} -
- this.handleSearchChange(e.target.value)} - /> - } - type={Type.TERT} - onClick={(e) => this.toggleSettings()} - - /> -
- {this.settingsOpen && + /> +
+ } + {this.settingsOpen && !this.routeToAnimate &&
@@ -1151,45 +1640,52 @@ export class MapBox extends ViewBoxAnnotatableComponent
} - -
- {this.featuresFromGeocodeResults.length > 0 && ( + {this.routeToAnimate && +
+
+ {StrCast(this.routeToAnimate.title)} +
+
+ {this.getRouteAnimationOptions()} +
+
+ } + {this.featuresFromGeocodeResults.length > 0 && ( +
-

Choose a location for your pin:

- {this.featuresFromGeocodeResults - .filter(feature => feature.place_name) - .map((feature, idx) => ( -
{ - this.handleSearchChange(""); - this.addMarkerForFeature(feature); - }} - > -
- {feature.place_name} +

Choose a location for your pin:

+ {this.featuresFromGeocodeResults + .filter(feature => feature.place_name) + .map((feature, idx) => ( +
{ + this.handleSearchChange(""); + this.addMarkerForFeature(feature); + }} + > +
+ {feature.place_name} +
-
))} - )} -
+ +
+ )} + {!this.isAnimating && this.animationPhase == 0 && + } + {this.routeToAnimate && (this.isAnimating || this.animationPhase > 0) && + <> + {!this.isStreetViewAnimation && + <> + + + + } + + + + + + + + + + + } + <> - {this.allPushpins + {!this.isAnimating && this.animationPhase == 0 && this.allPushpins // .filter(anno => !anno.layout_unrendered) .map((pushpin, idx) => ( ) => this.handleMarkerClick(e, pushpin)} - /> + > + {this.getMarkerIcon(pushpin)} + ))} 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 ( - - - - - - - - - - - - - - - - ) - } + // static getMapboxIcon = (color: string) => { + // return ( + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // ) + // } - 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 (); - } + if (color) { + iconProps.color = color; + } + + return (); + - return undefined; } static FAMarkerIconsMap: {[key: string]: IconProp} = { + 'MAP_PIN': faLocationDot, 'RESTAURANT_ICON': faUtensils, 'HOTEL_ICON': faHotel, 'HOUSE_ICON': faHouse, -- cgit v1.2.3-70-g09d2