aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/MapBox
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2024-05-19 01:01:02 -0400
committerbobzel <zzzman@gmail.com>2024-05-19 01:01:02 -0400
commit6e72f969029c22fe797397a6437836a0482260b6 (patch)
treee8ccde75702e557b2226c9069263e1bc3bd21a4b /src/client/views/nodes/MapBox
parent5ff0bef5d3c4825aa7210a26c98aae3b24f4a835 (diff)
parent13dc6de0e0099f699ad0d2bb54401e6a0aa25018 (diff)
Merge branch 'restoringEslint' into alyssa-starter
Diffstat (limited to 'src/client/views/nodes/MapBox')
-rw-r--r--src/client/views/nodes/MapBox/AnimationSpeedIcons.tsx39
-rw-r--r--src/client/views/nodes/MapBox/AnimationUtility.ts59
-rw-r--r--src/client/views/nodes/MapBox/DirectionsAnchorMenu.tsx18
-rw-r--r--src/client/views/nodes/MapBox/GeocoderControl.tsx7
-rw-r--r--src/client/views/nodes/MapBox/MapAnchorMenu.tsx106
-rw-r--r--src/client/views/nodes/MapBox/MapBox.tsx1096
-rw-r--r--src/client/views/nodes/MapBox/MapBox2.tsx6
-rw-r--r--src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx2
-rw-r--r--src/client/views/nodes/MapBox/MapPushpinBox.tsx11
-rw-r--r--src/client/views/nodes/MapBox/MapboxApiUtility.ts76
-rw-r--r--src/client/views/nodes/MapBox/MarkerIcons.tsx3
11 files changed, 508 insertions, 915 deletions
diff --git a/src/client/views/nodes/MapBox/AnimationSpeedIcons.tsx b/src/client/views/nodes/MapBox/AnimationSpeedIcons.tsx
index d54a175b2..f4ece627f 100644
--- a/src/client/views/nodes/MapBox/AnimationSpeedIcons.tsx
+++ b/src/client/views/nodes/MapBox/AnimationSpeedIcons.tsx
@@ -1,35 +1,44 @@
-import * as React from "react";
+import * as React from 'react';
export const slowSpeedIcon: JSX.Element = (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 435.62">
<defs>
- <style type="text/css">
- {`
+ <style type="text/css">
+ {`
.fil0 { fill: black; fill-rule: nonzero; }
.fil1 { fill: #FE0000; fill-rule: nonzero; }
`}
- </style>
+ </style>
</defs>
- <path className="fil0" d="M174.84 343.06c-7.31,-13.12 -13.03,-27.28 -16.89,-42.18 -3.76,-14.56 -5.77,-29.71 -5.77,-45.17 0,-11.94 1.19,-23.66 3.43,-35.03 2.29,-11.57 5.74,-22.83 10.2,-33.63 13.7,-33.14 37.01,-61.29 66.42,-80.96 25.38,-16.96 55.28,-27.66 87.45,-29.87l0 -30.17c0,-0.46 0.02,-0.92 0.06,-1.37l-33.7 0c-5.53,0 -10.05,-4.52 -10.05,-10.04l0 -24.59c0,-5.53 4.52,-10.05 10.05,-10.05l101.27 0c5.53,0 10.05,4.52 10.05,10.05l0 24.59c0,5.52 -4.52,10.04 -10.05,10.04l-33.69 0c0.03,0.45 0.05,0.91 0.05,1.37l0 31.03 -0.1 0c41.1,4.89 77.94,23.63 105.73,51.42 32.56,32.55 52.7,77.54 52.7,127.21 0,49.67 -20.14,94.66 -52.7,127.21 -32.55,32.55 -77.54,52.7 -127.21,52.7 -33.16,0 -64.29,-9.04 -91.05,-24.78 -27.66,-16.27 -50.59,-39.73 -66.2,-67.78zm148.42 -36.62l-80.33 0 0 -25.71 28.6 0 0 -42.57 -28.6 1.93 0 -25.71 36.95 -8.35 25.38 0 0 74.7 18 0 0 25.71zm44.34 -100.41l11.08 26.83 1.61 0 11.09 -26.83 34.86 0 -22.33 48.52 22.33 51.89 -35.67 0 -12.05 -28.92 -1.44 0 -11.89 28.92 -34.06 0 21.85 -50.93 -21.85 -49.48 36.47 0zm126.08 -74.6c6.98,-16.66 6.15,-34.13 -3.84,-45.82 -12,-14.03 -33.67,-15.64 -53.8,-5.77 21.32,14.62 40.68,31.63 57.64,51.59zm-323.17 0c-6.98,-16.66 -6.16,-34.13 3.84,-45.82 11.99,-14.03 33.67,-15.64 53.79,-5.77 -21.32,14.62 -40.68,31.63 -57.63,51.59zm15.31 162.23c3.23,12.5 8.04,24.39 14.18,35.42 13.13,23.58 32.39,43.29 55.6,56.94 22.37,13.16 48.52,20.71 76.49,20.71 41.71,0 79.47,-16.9 106.8,-44.23 27.32,-27.32 44.23,-65.08 44.23,-106.79 0,-41.71 -16.91,-79.47 -44.23,-106.8 -27.33,-27.32 -65.09,-44.23 -106.8,-44.23 -31.07,0 -59.91,9.34 -83.84,25.33 -24.74,16.54 -44.33,40.19 -55.82,67.98 -3.68,8.91 -6.56,18.35 -8.5,28.22 -1.87,9.49 -2.86,19.36 -2.86,29.5 0,13.24 1.65,25.96 4.75,37.95z"/>
- <path className="fil1" d="M55.23 188.52c-7.98,0 -14.45,-6.47 -14.45,-14.44 0,-7.98 6.47,-14.45 14.45,-14.45l63.94 0c7.98,0 14.45,6.47 14.45,14.45 0,7.97 -6.47,14.44 -14.45,14.44l-63.94 0zm0.72 167.68c-7.97,0 -14.44,-6.47 -14.44,-14.45 0,-7.97 6.47,-14.45 14.44,-14.45l64.58 0c7.97,0 14.45,6.48 14.45,14.45 0,7.98 -6.48,14.45 -14.45,14.45l-64.58 0zm-41.5 -84.94c-7.98,0 -14.45,-6.47 -14.45,-14.45 0,-7.97 6.47,-14.44 14.45,-14.44l89.12 0c7.98,0 14.45,6.47 14.45,14.44 0,7.98 -6.47,14.45 -14.45,14.45l-89.12 0z"/>
+ <path
+ className="fil0"
+ d="M174.84 343.06c-7.31,-13.12 -13.03,-27.28 -16.89,-42.18 -3.76,-14.56 -5.77,-29.71 -5.77,-45.17 0,-11.94 1.19,-23.66 3.43,-35.03 2.29,-11.57 5.74,-22.83 10.2,-33.63 13.7,-33.14 37.01,-61.29 66.42,-80.96 25.38,-16.96 55.28,-27.66 87.45,-29.87l0 -30.17c0,-0.46 0.02,-0.92 0.06,-1.37l-33.7 0c-5.53,0 -10.05,-4.52 -10.05,-10.04l0 -24.59c0,-5.53 4.52,-10.05 10.05,-10.05l101.27 0c5.53,0 10.05,4.52 10.05,10.05l0 24.59c0,5.52 -4.52,10.04 -10.05,10.04l-33.69 0c0.03,0.45 0.05,0.91 0.05,1.37l0 31.03 -0.1 0c41.1,4.89 77.94,23.63 105.73,51.42 32.56,32.55 52.7,77.54 52.7,127.21 0,49.67 -20.14,94.66 -52.7,127.21 -32.55,32.55 -77.54,52.7 -127.21,52.7 -33.16,0 -64.29,-9.04 -91.05,-24.78 -27.66,-16.27 -50.59,-39.73 -66.2,-67.78zm148.42 -36.62l-80.33 0 0 -25.71 28.6 0 0 -42.57 -28.6 1.93 0 -25.71 36.95 -8.35 25.38 0 0 74.7 18 0 0 25.71zm44.34 -100.41l11.08 26.83 1.61 0 11.09 -26.83 34.86 0 -22.33 48.52 22.33 51.89 -35.67 0 -12.05 -28.92 -1.44 0 -11.89 28.92 -34.06 0 21.85 -50.93 -21.85 -49.48 36.47 0zm126.08 -74.6c6.98,-16.66 6.15,-34.13 -3.84,-45.82 -12,-14.03 -33.67,-15.64 -53.8,-5.77 21.32,14.62 40.68,31.63 57.64,51.59zm-323.17 0c-6.98,-16.66 -6.16,-34.13 3.84,-45.82 11.99,-14.03 33.67,-15.64 53.79,-5.77 -21.32,14.62 -40.68,31.63 -57.63,51.59zm15.31 162.23c3.23,12.5 8.04,24.39 14.18,35.42 13.13,23.58 32.39,43.29 55.6,56.94 22.37,13.16 48.52,20.71 76.49,20.71 41.71,0 79.47,-16.9 106.8,-44.23 27.32,-27.32 44.23,-65.08 44.23,-106.79 0,-41.71 -16.91,-79.47 -44.23,-106.8 -27.33,-27.32 -65.09,-44.23 -106.8,-44.23 -31.07,0 -59.91,9.34 -83.84,25.33 -24.74,16.54 -44.33,40.19 -55.82,67.98 -3.68,8.91 -6.56,18.35 -8.5,28.22 -1.87,9.49 -2.86,19.36 -2.86,29.5 0,13.24 1.65,25.96 4.75,37.95z"
+ />
+ <path
+ className="fil1"
+ d="M55.23 188.52c-7.98,0 -14.45,-6.47 -14.45,-14.44 0,-7.98 6.47,-14.45 14.45,-14.45l63.94 0c7.98,0 14.45,6.47 14.45,14.45 0,7.97 -6.47,14.44 -14.45,14.44l-63.94 0zm0.72 167.68c-7.97,0 -14.44,-6.47 -14.44,-14.45 0,-7.97 6.47,-14.45 14.44,-14.45l64.58 0c7.97,0 14.45,6.48 14.45,14.45 0,7.98 -6.48,14.45 -14.45,14.45l-64.58 0zm-41.5 -84.94c-7.98,0 -14.45,-6.47 -14.45,-14.45 0,-7.97 6.47,-14.44 14.45,-14.44l89.12 0c7.98,0 14.45,6.47 14.45,14.44 0,7.98 -6.47,14.45 -14.45,14.45l-89.12 0z"
+ />
</svg>
);
export const mediumSpeedIcon: JSX.Element = (
<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" data-name="Layer 1" viewBox="0 0 122.88 104.55">
- <defs><style>{`.cls-1{fill:#fe0000;}`}</style></defs>
- <path d="M42,82.34a42.82,42.82,0,0,1-4.05-10.13A43.2,43.2,0,0,1,76.72,18.29V11.05c0-.11,0-.22,0-.33H68.65a2.41,2.41,0,0,1-2.41-2.41V2.41A2.41,2.41,0,0,1,68.65,0H93a2.42,2.42,0,0,1,2.42,2.41v5.9A2.42,2.42,0,0,1,93,10.72H84.87c0,.11,0,.22,0,.33V18.5h0A43.17,43.17,0,1,1,42,82.34ZM88.22,49.45l2.66,6.44h.39l2.66-6.44h8.37L96.94,61.09l5.36,12.45H93.74L90.85,66.6H90.5l-2.85,6.94H79.47l5.25-12.22L79.47,49.45ZM58.65,56.08l-1-5.75a33.58,33.58,0,0,1,9.68-1.46c1.28,0,2.35,0,3.22.11a11.77,11.77,0,0,1,2.67.58,5.41,5.41,0,0,1,2.2,1.28c1.24,1.23,1.85,3.12,1.85,5.66s-.72,4.42-2.16,5.63S70.64,64.73,66,66.3v1.08H76.89v6.16H57.11V68.72a10.73,10.73,0,0,1,.81-4.12,8.4,8.4,0,0,1,2.43-2.7,12.13,12.13,0,0,1,2.79-1.7l3.32-1.52c1-.47,1.88-.87,2.52-1.17V55.42a28.59,28.59,0,0,0-3.2-.19,30.66,30.66,0,0,0-7.13.85Zm59.83-24.54c1.68-4,1.48-8.19-.92-11-2.88-3.37-8.08-3.76-12.91-1.39a69.74,69.74,0,0,1,13.83,12.38Zm-77.56,0c-1.67-4-1.48-8.19.92-11,2.88-3.37,8.08-3.76,12.91-1.39A70,70,0,0,0,40.92,31.54ZM44.6,70.48A36,36,0,0,0,48,79a35.91,35.91,0,1,0-3.4-8.5Z"/>
- <path className="cls-1" d="M13.25,45.25a3.47,3.47,0,0,1,0-6.94H28.6a3.47,3.47,0,0,1,0,6.94Z"/>
- <path className="cls-1" d="M3.47,65.1a3.47,3.47,0,1,1,0-6.93H24.86a3.47,3.47,0,0,1,0,6.93Z"/>
- <path className="cls-1" d="M13.43,85.49a3.47,3.47,0,1,1,0-6.94h15.5a3.47,3.47,0,0,1,0,6.94Z"/>
+ <defs>
+ <style>{`.cls-1{fill:#fe0000;}`}</style>
+ </defs>
+ <path d="M42,82.34a42.82,42.82,0,0,1-4.05-10.13A43.2,43.2,0,0,1,76.72,18.29V11.05c0-.11,0-.22,0-.33H68.65a2.41,2.41,0,0,1-2.41-2.41V2.41A2.41,2.41,0,0,1,68.65,0H93a2.42,2.42,0,0,1,2.42,2.41v5.9A2.42,2.42,0,0,1,93,10.72H84.87c0,.11,0,.22,0,.33V18.5h0A43.17,43.17,0,1,1,42,82.34ZM88.22,49.45l2.66,6.44h.39l2.66-6.44h8.37L96.94,61.09l5.36,12.45H93.74L90.85,66.6H90.5l-2.85,6.94H79.47l5.25-12.22L79.47,49.45ZM58.65,56.08l-1-5.75a33.58,33.58,0,0,1,9.68-1.46c1.28,0,2.35,0,3.22.11a11.77,11.77,0,0,1,2.67.58,5.41,5.41,0,0,1,2.2,1.28c1.24,1.23,1.85,3.12,1.85,5.66s-.72,4.42-2.16,5.63S70.64,64.73,66,66.3v1.08H76.89v6.16H57.11V68.72a10.73,10.73,0,0,1,.81-4.12,8.4,8.4,0,0,1,2.43-2.7,12.13,12.13,0,0,1,2.79-1.7l3.32-1.52c1-.47,1.88-.87,2.52-1.17V55.42a28.59,28.59,0,0,0-3.2-.19,30.66,30.66,0,0,0-7.13.85Zm59.83-24.54c1.68-4,1.48-8.19-.92-11-2.88-3.37-8.08-3.76-12.91-1.39a69.74,69.74,0,0,1,13.83,12.38Zm-77.56,0c-1.67-4-1.48-8.19.92-11,2.88-3.37,8.08-3.76,12.91-1.39A70,70,0,0,0,40.92,31.54ZM44.6,70.48A36,36,0,0,0,48,79a35.91,35.91,0,1,0-3.4-8.5Z" />
+ <path className="cls-1" d="M13.25,45.25a3.47,3.47,0,0,1,0-6.94H28.6a3.47,3.47,0,0,1,0,6.94Z" />
+ <path className="cls-1" d="M3.47,65.1a3.47,3.47,0,1,1,0-6.93H24.86a3.47,3.47,0,0,1,0,6.93Z" />
+ <path className="cls-1" d="M13.43,85.49a3.47,3.47,0,1,1,0-6.94h15.5a3.47,3.47,0,0,1,0,6.94Z" />
</svg>
);
export const fastSpeedIcon: JSX.Element = (
<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" data-name="Layer 1" viewBox="0 0 122.88 104.55">
- <defs><style>{`.cls-1{fill:#fe0000;`}</style></defs>
- <path d="M42,82.34a42.82,42.82,0,0,1-4.05-10.13A43.2,43.2,0,0,1,76.72,18.29V11.05c0-.11,0-.22,0-.33H68.65a2.41,2.41,0,0,1-2.41-2.41V2.41A2.41,2.41,0,0,1,68.65,0H93a2.42,2.42,0,0,1,2.42,2.41v5.9A2.42,2.42,0,0,1,93,10.72H84.87c0,.11,0,.22,0,.33V18.5h0A43.17,43.17,0,1,1,42,82.34ZM88.22,49.61l2.66,6.44h.39l2.66-6.44h8.37L96.94,61.26l5.36,12.45H93.74l-2.9-6.94H90.5l-2.86,6.94H79.47l5.24-12.22L79.47,49.61Zm-19,8.48v-2.5a24.92,24.92,0,0,0-3.74-.2A33.25,33.25,0,0,0,59,56.2l-1-5.7A30.47,30.47,0,0,1,67.13,49a22.86,22.86,0,0,1,5.48.47,6.91,6.91,0,0,1,2.5,1.11,5.62,5.62,0,0,1,1.78,4.55,5.84,5.84,0,0,1-3.2,5.56v.19a5.73,5.73,0,0,1,3.81,5.74,8.67,8.67,0,0,1-.63,3.49,6,6,0,0,1-1.6,2.24,7.15,7.15,0,0,1-2.55,1.25,25.64,25.64,0,0,1-6.61.66,37.78,37.78,0,0,1-8.54-1l1.08-6.37a27.22,27.22,0,0,0,6.21.89,35.79,35.79,0,0,0,4.35-.23V65.11l-6.63-.65V58.87l6.63-.78Zm49.27-26.55c1.68-4,1.48-8.19-.92-11-2.88-3.37-8.08-3.76-12.91-1.39a69.74,69.74,0,0,1,13.83,12.38Zm-77.56,0c-1.67-4-1.48-8.19.92-11,2.88-3.37,8.08-3.76,12.91-1.39A70,70,0,0,0,40.92,31.54ZM44.6,70.48A36,36,0,0,0,48,79a35.91,35.91,0,1,0-3.4-8.5Z"/>
- <path className="cls-1" d="M13.25,45.25a3.47,3.47,0,0,1,0-6.94H28.6a3.47,3.47,0,0,1,0,6.94Zm.18,40.24a3.47,3.47,0,1,1,0-6.94h15.5a3.47,3.47,0,0,1,0,6.94ZM3.47,65.1a3.47,3.47,0,1,1,0-6.93H24.86a3.47,3.47,0,0,1,0,6.93Z"/>
+ <defs>
+ <style>{`.cls-1{fill:#fe0000;`}</style>
+ </defs>
+ <path d="M42,82.34a42.82,42.82,0,0,1-4.05-10.13A43.2,43.2,0,0,1,76.72,18.29V11.05c0-.11,0-.22,0-.33H68.65a2.41,2.41,0,0,1-2.41-2.41V2.41A2.41,2.41,0,0,1,68.65,0H93a2.42,2.42,0,0,1,2.42,2.41v5.9A2.42,2.42,0,0,1,93,10.72H84.87c0,.11,0,.22,0,.33V18.5h0A43.17,43.17,0,1,1,42,82.34ZM88.22,49.61l2.66,6.44h.39l2.66-6.44h8.37L96.94,61.26l5.36,12.45H93.74l-2.9-6.94H90.5l-2.86,6.94H79.47l5.24-12.22L79.47,49.61Zm-19,8.48v-2.5a24.92,24.92,0,0,0-3.74-.2A33.25,33.25,0,0,0,59,56.2l-1-5.7A30.47,30.47,0,0,1,67.13,49a22.86,22.86,0,0,1,5.48.47,6.91,6.91,0,0,1,2.5,1.11,5.62,5.62,0,0,1,1.78,4.55,5.84,5.84,0,0,1-3.2,5.56v.19a5.73,5.73,0,0,1,3.81,5.74,8.67,8.67,0,0,1-.63,3.49,6,6,0,0,1-1.6,2.24,7.15,7.15,0,0,1-2.55,1.25,25.64,25.64,0,0,1-6.61.66,37.78,37.78,0,0,1-8.54-1l1.08-6.37a27.22,27.22,0,0,0,6.21.89,35.79,35.79,0,0,0,4.35-.23V65.11l-6.63-.65V58.87l6.63-.78Zm49.27-26.55c1.68-4,1.48-8.19-.92-11-2.88-3.37-8.08-3.76-12.91-1.39a69.74,69.74,0,0,1,13.83,12.38Zm-77.56,0c-1.67-4-1.48-8.19.92-11,2.88-3.37,8.08-3.76,12.91-1.39A70,70,0,0,0,40.92,31.54ZM44.6,70.48A36,36,0,0,0,48,79a35.91,35.91,0,1,0-3.4-8.5Z" />
+ <path className="cls-1" d="M13.25,45.25a3.47,3.47,0,0,1,0-6.94H28.6a3.47,3.47,0,0,1,0,6.94Zm.18,40.24a3.47,3.47,0,1,1,0-6.94h15.5a3.47,3.47,0,0,1,0,6.94ZM3.47,65.1a3.47,3.47,0,1,1,0-6.93H24.86a3.47,3.47,0,0,1,0,6.93Z" />
</svg>
);
-
diff --git a/src/client/views/nodes/MapBox/AnimationUtility.ts b/src/client/views/nodes/MapBox/AnimationUtility.ts
index 35153f439..f4bae66bb 100644
--- a/src/client/views/nodes/MapBox/AnimationUtility.ts
+++ b/src/client/views/nodes/MapBox/AnimationUtility.ts
@@ -87,25 +87,24 @@ export class AnimationUtility {
@computed get currentPitch(): number {
if (!this.isStreetViewAnimation) return 50;
if (!this.terrainDisplayed) return 80;
- else {
- // const groundElevation = 0;
- const heightAboveGround = this.currentAnimationAltitude;
- const horizontalDistance = 500;
-
- let pitch;
- if (heightAboveGround >= 0) {
- pitch = 90 - Math.atan(heightAboveGround / horizontalDistance) * (180 / Math.PI);
- } else {
- pitch = 80;
- }
- console.log(Math.max(50, Math.min(pitch, 85)));
+ // const groundElevation = 0;
+ const heightAboveGround = this.currentAnimationAltitude;
+ const horizontalDistance = 500;
- if (this.previousPitch) {
- return this.lerp(Math.max(50, Math.min(pitch, 85)), this.previousPitch, 0.02);
- }
- return Math.max(50, Math.min(pitch, 85));
+ let pitch;
+ if (heightAboveGround >= 0) {
+ pitch = 90 - Math.atan(heightAboveGround / horizontalDistance) * (180 / Math.PI);
+ } else {
+ pitch = 80;
+ }
+
+ console.log(Math.max(50, Math.min(pitch, 85)));
+
+ if (this.previousPitch) {
+ return this.lerp(Math.max(50, Math.min(pitch, 85)), this.previousPitch, 0.02);
}
+ return Math.max(50, Math.min(pitch, 85));
}
@computed get flyInEndPitch() {
@@ -214,8 +213,9 @@ export class AnimationUtility {
currentAnimationPhase: number;
updateAnimationPhase: (newAnimationPhase: number) => void;
updateFrameId: (newFrameId: number) => void;
- }) => {
- return new Promise<void>(async resolve => {
+ }) =>
+ // eslint-disable-next-line no-async-promise-executor
+ new Promise<void>(async resolve => {
let startTime: number | null = null;
const frame = async (currentTime: number) => {
@@ -257,7 +257,7 @@ export class AnimationUtility {
updateAnimationPhase(animationPhase);
// compute corrected camera ground position, so that he leading edge of the path is in view
- var correctedPosition = this.computeCameraPosition(
+ const correctedPosition = this.computeCameraPosition(
this.isStreetViewAnimation,
this.currentPitch,
bearing,
@@ -277,7 +277,7 @@ export class AnimationUtility {
map.setFreeCameraOptions(camera);
this.previousAltitude = this.currentAnimationAltitude;
- this.previousPitch = this.previousPitch;
+ // this.previousPitch = this.previousPitch;
// repeat!
const innerFrameId = await window.requestAnimationFrame(frame);
@@ -287,15 +287,15 @@ export class AnimationUtility {
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 => {
+ public flyInAndRotate = async ({ map, updateFrameId }: { map: MapRef; updateFrameId: (newFrameId: number) => void }) =>
+ // eslint-disable-next-line no-async-promise-executor
+ new Promise<{ bearing: number; altitude: number }>(async resolve => {
let start: number | null;
- var currentAltitude;
- var currentBearing;
- var currentPitch;
+ let currentAltitude;
+ let currentBearing;
+ let currentPitch;
// the animation frame will run as many times as necessary until the duration has been reached
const frame = async (time: number) => {
@@ -319,7 +319,7 @@ export class AnimationUtility {
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);
+ const correctedPosition = this.computeCameraPosition(false, currentPitch, currentBearing, this.FIRST_LNG_LAT, currentAltitude);
// set the pitch and bearing of the camera
const camera = map.getFreeCameraOptions();
@@ -349,13 +349,10 @@ export class AnimationUtility {
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;
- };
+ lerp = (start: number, end: number, amt: number) => (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;
diff --git a/src/client/views/nodes/MapBox/DirectionsAnchorMenu.tsx b/src/client/views/nodes/MapBox/DirectionsAnchorMenu.tsx
index 7e99795b5..b8fd8ac6a 100644
--- a/src/client/views/nodes/MapBox/DirectionsAnchorMenu.tsx
+++ b/src/client/views/nodes/MapBox/DirectionsAnchorMenu.tsx
@@ -4,15 +4,17 @@ import { IconButton } from 'browndash-components';
import { IReactionDisposer, ObservableMap, reaction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { returnFalse, unimplementedFunction } from '../../../../Utils';
+import { returnFalse } from '../../../../ClientUtils';
+import { unimplementedFunction } from '../../../../Utils';
import { Doc, Opt } from '../../../../fields/Doc';
import { NumCast, StrCast } from '../../../../fields/Types';
-import { SelectionManager } from '../../../util/SelectionManager';
import { SettingsManager } from '../../../util/SettingsManager';
import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu';
+import { DocumentView } from '../DocumentView';
@observer
export class DirectionsAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
+ // eslint-disable-next-line no-use-before-define
static Instance: DirectionsAnchorMenu;
private _disposer: IReactionDisposer | undefined;
@@ -23,8 +25,8 @@ export class DirectionsAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
public OnClick: (e: PointerEvent) => void = unimplementedFunction;
// public OnAudio: (e: PointerEvent) => void = unimplementedFunction;
public StartDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction;
- public Highlight: (color: string, isTargetToggler: boolean, savedAnnotations?: ObservableMap<number, HTMLDivElement[]>, addAsAnnotation?: boolean) => Opt<Doc> = (color: string, isTargetToggler: boolean) => undefined;
- public GetAnchor: (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => Opt<Doc> = (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => undefined;
+ public Highlight: (color: string, isTargetToggler: boolean, savedAnnotations?: ObservableMap<number, HTMLDivElement[]>, addAsAnnotation?: boolean) => Opt<Doc> = () => undefined;
+ public GetAnchor: (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => Opt<Doc> = () => undefined;
public Delete: () => void = unimplementedFunction;
// public MakeTargetToggle: () => void = unimplementedFunction;
// public ShowTargetTrail: () => void = unimplementedFunction;
@@ -54,8 +56,8 @@ export class DirectionsAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
componentDidMount() {
this._disposer = reaction(
- () => SelectionManager.Views.slice(),
- sel => DirectionsAnchorMenu.Instance.fadeOut(true)
+ () => DocumentView.Selected().slice(),
+ () => DirectionsAnchorMenu.Instance.fadeOut(true)
);
}
// audioDown = (e: React.PointerEvent) => {
@@ -103,8 +105,8 @@ export class DirectionsAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
color={SettingsManager.userColor}
/>
- <IconButton tooltip="Animate route" onPointerDown={this.Delete} /**TODO: fix */ icon={<FontAwesomeIcon icon={faRoute as IconLookup} />} color={SettingsManager.userColor} />
- <IconButton tooltip="Add to calendar" onPointerDown={this.Delete} /**TODO: fix */ icon={<FontAwesomeIcon icon={faCalendarDays as IconLookup} />} color={SettingsManager.userColor} />
+ <IconButton tooltip="Animate route" onPointerDown={this.Delete} /* *TODO: fix */ icon={<FontAwesomeIcon icon={faRoute as IconLookup} />} color={SettingsManager.userColor} />
+ <IconButton tooltip="Add to calendar" onPointerDown={this.Delete} /* *TODO: fix */ icon={<FontAwesomeIcon icon={faCalendarDays as IconLookup} />} color={SettingsManager.userColor} />
</div>
);
diff --git a/src/client/views/nodes/MapBox/GeocoderControl.tsx b/src/client/views/nodes/MapBox/GeocoderControl.tsx
index e4ba51316..e118c57d9 100644
--- a/src/client/views/nodes/MapBox/GeocoderControl.tsx
+++ b/src/client/views/nodes/MapBox/GeocoderControl.tsx
@@ -3,8 +3,6 @@
// import { ControlPosition, MarkerProps, useControl } from "react-map-gl";
// import '@mapbox/mapbox-gl-geocoder/dist/mapbox-gl-geocoder.css'
-
-
// export type GeocoderControlProps = Omit<GeocoderOptions, 'accessToken' | 'mapboxgl' | 'marker'> & {
// mapboxAccessToken: string;
// marker?: Omit<MarkerProps, 'longitude' | 'latitude'>;
@@ -31,7 +29,6 @@
// ctrl.on('results', props.onResults);
// ctrl.on('result', evt => {
// props.onResult(evt);
-
// // const {result} = evt;
// // const location =
// // result &&
@@ -49,8 +46,6 @@
// position: props.position
// }
// );
-
-
// // @ts-ignore (TS2339) private member
// if (geocoder._map) {
// if (geocoder.getProximity() !== props.proximity && props.proximity !== undefined) {
@@ -104,4 +99,4 @@
// onLoading: noop,
// onResults: noop,
// onError: noop
-// }; \ 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 08bea5d9d..103a35434 100644
--- a/src/client/views/nodes/MapBox/MapAnchorMenu.tsx
+++ b/src/client/views/nodes/MapBox/MapAnchorMenu.tsx
@@ -1,3 +1,4 @@
+/* eslint-disable react/button-has-type */
import { IconLookup, faAdd, faArrowDown, faArrowLeft, faArrowsRotate, faBicycle, faCalendarDays, faCar, faDiamondTurnRight, faEdit, faPersonWalking, faRoute } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Autocomplete, Checkbox, FormControlLabel, TextField } from '@mui/material';
@@ -7,13 +8,14 @@ import { IReactionDisposer, ObservableMap, action, makeObservable, observable, r
import { observer } from 'mobx-react';
import * as React from 'react';
import { CirclePicker, ColorResult } from 'react-color';
-import { returnFalse, setupMoveUpEvents, unimplementedFunction } from '../../../../Utils';
+import { returnFalse, setupMoveUpEvents } from '../../../../ClientUtils';
+import { unimplementedFunction } from '../../../../Utils';
import { Doc, Opt } from '../../../../fields/Doc';
import { NumCast, StrCast } from '../../../../fields/Types';
import { CalendarManager } from '../../../util/CalendarManager';
-import { SelectionManager } from '../../../util/SelectionManager';
import { SettingsManager } from '../../../util/SettingsManager';
import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu';
+import { DocumentView } from '../DocumentView';
import './MapAnchorMenu.scss';
import { MapboxApiUtility, TransportationType } from './MapboxApiUtility';
import { MarkerIcons } from './MarkerIcons';
@@ -23,6 +25,7 @@ type MapAnchorMenuType = 'standard' | 'routeCreation' | 'calendar' | 'customize'
@observer
export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
+ // eslint-disable-next-line no-use-before-define
static Instance: MapAnchorMenu;
private _disposer: IReactionDisposer | undefined;
@@ -35,8 +38,8 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
public OnClick: (e: PointerEvent) => void = unimplementedFunction;
// public OnAudio: (e: PointerEvent) => void = unimplementedFunction;
public StartDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction;
- public Highlight: (color: string, isTargetToggler: boolean, savedAnnotations?: ObservableMap<number, HTMLDivElement[]>, addAsAnnotation?: boolean) => Opt<Doc> = (color: string, isTargetToggler: boolean) => undefined;
- public GetAnchor: (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => Opt<Doc> = (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => undefined;
+ public Highlight: (color: string, isTargetToggler: boolean, savedAnnotations?: ObservableMap<number, HTMLDivElement[]>, addAsAnnotation?: boolean) => Opt<Doc> = () => undefined;
+ public GetAnchor: (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => Opt<Doc> = () => undefined;
public Delete: () => void = unimplementedFunction;
// public MakeTargetToggle: () => void = unimplementedFunction;
// public ShowTargetTrail: () => void = unimplementedFunction;
@@ -123,8 +126,8 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
componentDidMount() {
this._disposer = reaction(
- () => SelectionManager.Views.slice(),
- sel => MapAnchorMenu.Instance.fadeOut(true)
+ () => DocumentView.Selected().slice(),
+ () => MapAnchorMenu.Instance.fadeOut(true)
);
}
// audioDown = (e: React.PointerEvent) => {
@@ -147,12 +150,12 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
setupMoveUpEvents(
this,
e,
- (e: PointerEvent) => {
- this.StartDrag(e, this._commentRef.current!);
+ moveEv => {
+ this.StartDrag(moveEv, this._commentRef.current!);
return true;
},
returnFalse,
- e => this.OnClick(e)
+ clickEv => this.OnClick(clickEv)
);
};
@@ -274,7 +277,7 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
HandleAddRouteClick = () => {
if (this.currentRouteInfoMap && this.selectedTransportationType && this.selectedDestinationFeature) {
- const coordinates = this.currentRouteInfoMap[this.selectedTransportationType].coordinates;
+ const { coordinates } = this.currentRouteInfoMap[this.selectedTransportationType];
console.log(coordinates);
console.log(this.selectedDestinationFeature);
this.AddNewRouteToMap(coordinates, this.title ?? '', this.selectedDestinationFeature, this.createPinForDestination);
@@ -293,34 +296,30 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
getDirectionsButton: JSX.Element = (<IconButton tooltip="Get directions" onPointerDown={this.DirectionsClick} icon={<FontAwesomeIcon icon={faDiamondTurnRight as IconLookup} />} color={SettingsManager.userColor} />);
- getAddToCalendarButton = (docType: string): JSX.Element => {
- return (
- <IconButton
- tooltip="Add to calendar"
- onPointerDown={() => {
- CalendarManager.Instance.open(undefined, docType === 'pin' ? this.pinDoc : this.routeDoc);
- }}
- icon={<FontAwesomeIcon icon={faCalendarDays as IconLookup} />}
- color={SettingsManager.userColor}
- />
- );
- };
+ getAddToCalendarButton = (docType: string): JSX.Element => (
+ <IconButton
+ tooltip="Add to calendar"
+ onPointerDown={() => {
+ CalendarManager.Instance.open(undefined, docType === 'pin' ? this.pinDoc : this.routeDoc);
+ }}
+ icon={<FontAwesomeIcon icon={faCalendarDays as IconLookup} />}
+ color={SettingsManager.userColor}
+ />
+ );
addToCalendarButton: JSX.Element = (
<IconButton tooltip="Add to calendar" onPointerDown={() => CalendarManager.Instance.open(undefined, this.pinDoc)} icon={<FontAwesomeIcon icon={faCalendarDays as IconLookup} />} color={SettingsManager.userColor} />
);
- getLinkNoteToDocButton = (docType: string): JSX.Element => {
- return (
- <div ref={this._commentRef}>
- <IconButton
- tooltip={`Link Note to ${docType === 'pin' ? 'Pin' : 'Route'}`} //
- onPointerDown={this.notePointerDown}
- icon={<FontAwesomeIcon icon="sticky-note" />}
- color={SettingsManager.userColor}
- />
- </div>
- );
- };
+ getLinkNoteToDocButton = (docType: string): JSX.Element => (
+ <div ref={this._commentRef}>
+ <IconButton
+ tooltip={`Link Note to ${docType === 'pin' ? 'Pin' : 'Route'}`} //
+ onPointerDown={this.notePointerDown}
+ icon={<FontAwesomeIcon icon="sticky-note" />}
+ color={SettingsManager.userColor}
+ />
+ </div>
+ );
linkNoteToPinOrRoutenButton: JSX.Element = (
<div ref={this._commentRef}>
@@ -362,16 +361,14 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
/>
);
- getDeleteButton = (type: string) => {
- return (
- <IconButton
- tooltip={`Delete ${type === 'pin' ? 'Pin' : 'Route'}`} //
- onPointerDown={this.Delete}
- icon={<FontAwesomeIcon icon="trash-alt" />}
- color={SettingsManager.userColor}
- />
- );
- };
+ getDeleteButton = (type: string) => (
+ <IconButton
+ tooltip={`Delete ${type === 'pin' ? 'Pin' : 'Route'}`} //
+ onPointerDown={this.Delete}
+ icon={<FontAwesomeIcon icon="trash-alt" />}
+ color={SettingsManager.userColor}
+ />
+ );
animateRouteButton: JSX.Element = (<IconButton tooltip="Animate route" onPointerDown={() => this.OpenAnimationPanel(this.routeDoc)} icon={<FontAwesomeIcon icon={faRoute as IconLookup} />} color={SettingsManager.userColor} />);
@@ -452,18 +449,17 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
}}
options={this.destinationFeatures.filter(feature => feature.place_name).map(feature => feature)}
getOptionLabel={(feature: any) => feature.place_name}
+ // eslint-disable-next-line react/jsx-props-no-spreading
renderInput={(params: any) => <TextField {...params} placeholder="Enter a destination" />}
/>
- {this.selectedDestinationFeature && (
- <>
- {!this.allMapPinDocs.some(pinDoc => pinDoc.title === this.selectedDestinationFeature.place_name) && (
- <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '5px' }}>
- <FormControlLabel label="Create pin for destination?" control={<Checkbox color="success" checked={this.createPinForDestination} onChange={this.toggleCreatePinForDestinationCheckbox} />} />
- </div>
- )}
- </>
- )}
- <button id="get-routes-button" disabled={this.selectedDestinationFeature ? false : true} onClick={() => this.getRoutes(this.selectedDestinationFeature)}>
+ {!this.selectedDestinationFeature
+ ? null
+ : !this.allMapPinDocs.some(pinDoc => pinDoc.title === this.selectedDestinationFeature.place_name) && (
+ <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '5px' }}>
+ <FormControlLabel label="Create pin for destination?" control={<Checkbox color="success" checked={this.createPinForDestination} onChange={this.toggleCreatePinForDestinationCheckbox} />} />
+ </div>
+ )}
+ <button id="get-routes-button" disabled={!this.selectedDestinationFeature} onClick={() => this.getRoutes(this.selectedDestinationFeature)}>
Get routes
</button>
@@ -516,7 +512,7 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
</div>
))}
</div>
- <div style={{ width: '100%', height: '3px', color: 'white' }}></div>
+ <div style={{ width: '100%', height: '3px', color: 'white' }} />
</div>
)}
{this.menuType === 'route' && this.routeDoc && <div>{StrCast(this.routeDoc.title)}</div>}
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index 927e6fad4..d7687e03e 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -1,3 +1,5 @@
+/* eslint-disable jsx-a11y/no-static-element-interactions */
+/* eslint-disable jsx-a11y/click-events-have-key-events */
import { IconLookup, faCircleXmark, faGear, faPause, faPlay, faRotate } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Checkbox, FormControlLabel, TextField } from '@mui/material';
@@ -5,32 +7,30 @@ import * as turf from '@turf/turf';
import { IconButton, Size, Type } from 'browndash-components';
import * as d3 from 'd3';
import { Feature, FeatureCollection, GeoJsonProperties, Geometry, LineString, Position } from 'geojson';
-import mapboxgl, { LngLat, LngLatBoundsLike, MapLayerMouseEvent } from 'mapbox-gl';
-import { IReactionDisposer, ObservableMap, action, autorun, computed, makeObservable, observable, reaction, runInAction } from 'mobx';
+import mapboxgl, { LngLatBoundsLike, MapLayerMouseEvent } from 'mapbox-gl';
+import { IReactionDisposer, ObservableMap, action, autorun, computed, makeObservable, observable, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { CirclePicker, ColorResult } from 'react-color';
import { Layer, MapProvider, MapRef, Map as MapboxMap, Marker, Source, ViewState, ViewStateChangeEvent } from 'react-map-gl';
import { MarkerEvent } from 'react-map-gl/dist/esm/types';
-import { Utils, emptyFunction, setupMoveUpEvents } from '../../../../Utils';
+import { ClientUtils, setupMoveUpEvents } from '../../../../ClientUtils';
+import { emptyFunction } from '../../../../Utils';
import { Doc, DocListCast, Field, LinkedTo, Opt } from '../../../../fields/Doc';
-import { DocCss, Highlight } from '../../../../fields/DocSymbols';
-import { DocCast, NumCast, StrCast } from '../../../../fields/Types';
+import { DocCast, NumCast, StrCast, toList } from '../../../../fields/Types';
+import { DocUtils } from '../../../documents/DocUtils';
import { DocumentType } from '../../../documents/DocumentTypes';
-import { DocUtils, Docs } from '../../../documents/Documents';
-import { DocumentManager } from '../../../util/DocumentManager';
+import { Docs } from '../../../documents/Documents';
import { DragManager } from '../../../util/DragManager';
-import { LinkManager } from '../../../util/LinkManager';
-import { SnappingManager } from '../../../util/SnappingManager';
import { UndoManager, undoable } from '../../../util/UndoManager';
-import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../../DocComponent';
+import { ViewBoxAnnotatableComponent } from '../../DocComponent';
+import { PinDocView, PinProps } from '../../PinFuncs';
import { SidebarAnnos } from '../../SidebarAnnos';
import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm';
import { Colors } from '../../global/globalEnums';
import { DocumentView } from '../DocumentView';
-import { FocusViewOptions, FieldView, FieldViewProps } from '../FieldView';
-import { FormattedTextBox } from '../formattedText/FormattedTextBox';
-import { PinProps, PresBox } from '../trails';
+import { FieldView, FieldViewProps } from '../FieldView';
+import { FocusViewOptions } from '../FocusViewOptions';
import { fastSpeedIcon, mediumSpeedIcon, slowSpeedIcon } from './AnimationSpeedIcons';
import { AnimationSpeed, AnimationStatus, AnimationUtility } from './AnimationUtility';
import { MapAnchorMenu } from './MapAnchorMenu';
@@ -53,11 +53,7 @@ import { MarkerIcons } from './MarkerIcons';
* A map marker is considered a document that contains a collection with stacking view of documents, it has a lat, lng location, which is passed to Maps API's custom marker (red pin) to be rendered on the google maps
*/
-const bingApiKey = process.env.BING_MAPS; // if you're running local, get a Bing Maps api key here: https://www.bingmapsportal.com/ and then add it to the .env file in the Dash-Web root directory as: _CLIENT_BING_MAPS=<your apikey>
const MAPBOX_ACCESS_TOKEN = 'pk.eyJ1IjoiemF1bHRhdmFuZ2FyIiwiYSI6ImNscHgwNDd1MDA3MXIydm92ODdianp6cGYifQ.WFAqbhwxtMHOWSPtu0l2uQ';
-const MAPBOX_FORWARD_GEOCODE_BASE_URL = 'https://api.mapbox.com/geocoding/v5/mapbox.places/';
-
-const MAPBOX_REVERSE_GEOCODE_BASE_URL = 'https://api.mapbox.com/geocoding/v5/mapbox.places/';
type PopupInfo = {
longitude: number;
@@ -66,72 +62,69 @@ type PopupInfo = {
description: string;
};
-// export type GeocoderControlProps = Omit<GeocoderOptions, 'accessToken' | 'mapboxgl' | 'marker'> & {
-// mapboxAccessToken: string;
-// marker?: Omit<MarkerProps, 'longitude' | 'latitude'>;
-// position: ControlPosition;
-
-// onResult: (...args: any[]) => void;
-// };
-
-type MapMarker = {
- longitude: number;
- latitude: number;
-};
-
-/**
- * Consider integrating later: allows for drawing, circling, making shapes on map
- */
-// const drawingManager = new window.google.maps.drawing.DrawingManager({
-// drawingControl: true,
-// drawingControlOptions: {
-// position: google.maps.ControlPosition.TOP_RIGHT,
-// drawingModes: [
-// google.maps.drawing.OverlayType.MARKER,
-// // currently we are not supporting the following drawing mode on map, a thought for future development
-// google.maps.drawing.OverlayType.CIRCLE,
-// google.maps.drawing.OverlayType.POLYLINE,
-// ],
-// },
-// });
-
@observer
-export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implements ViewBoxInterface {
+export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(MapBox, fieldKey);
}
- private _dragRef = React.createRef<HTMLDivElement>();
+ private _unmounting = false;
private _sidebarRef = React.createRef<SidebarAnnos>();
private _ref: React.RefObject<HTMLDivElement> = React.createRef();
private _mapRef: React.RefObject<MapRef> = React.createRef();
private _disposers: { [key: string]: IReactionDisposer } = {};
- private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean, doc: Opt<Doc>) => void);
constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
}
- @observable private _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>();
- @computed get allSidebarDocs() {
- return DocListCast(this.dataDoc[this.SidebarKey]);
- }
+ @observable _featuresFromGeocodeResults: any[] = [];
+ @observable _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>();
+ @observable _selectedPinOrRoute: Doc | undefined = undefined; // The pin that is selected
+ @observable _mapReady = false;
+ @observable _isAnimating: boolean = false;
+ @observable _routeToAnimate: Doc | undefined = undefined;
+ @observable _animationPhase: number = 0;
+ @observable _finishedFlyTo: boolean = false;
+ @observable _frameId: number | null = null;
+ @observable _animationUtility: AnimationUtility | null = null;
+ @observable _settingsOpen: boolean = false;
+ @observable _mapStyle: string = 'mapbox://styles/mapbox/standard';
+ @observable _showTerrain: boolean = true;
+ @observable _currentPopup: PopupInfo | undefined = undefined;
+ @observable _isStreetViewAnimation: boolean = false;
+ @observable _animationSpeed: AnimationSpeed = AnimationSpeed.MEDIUM;
+ @observable _animationLineColor: string = '#ffff00';
+ @observable _temporaryRouteSource: FeatureCollection = { type: 'FeatureCollection', features: [] };
+ @observable _dynamicRouteFeature: Feature<Geometry, GeoJsonProperties> = {
+ type: 'Feature',
+ properties: {},
+ geometry: { type: 'LineString', coordinates: [] },
+ };
+
+ @observable path: turf.helpers.Feature<turf.helpers.LineString, turf.helpers.Properties> = {
+ type: 'Feature',
+ geometry: { type: 'LineString', coordinates: [] },
+ properties: {},
+ };
+
// this list contains pushpins and configs
- @computed get allAnnotations() {
- return DocListCast(this.dataDoc[this.annotationKey]);
- }
- @computed get allPushpins() {
- return this.allAnnotations.filter(anno => anno.type === DocumentType.PUSHPIN);
- }
- @computed get allRoutes() {
- return this.allAnnotations.filter(anno => anno.type === DocumentType.MAPROUTE);
+ @computed get allAnnotations() { return DocListCast(this.dataDoc[this.annotationKey]); } // prettier-ignore
+ @computed get allSidebarDocs() { return DocListCast(this.dataDoc[this.SidebarKey]); } // prettier-ignore
+ @computed get allPushpins() { return this.allAnnotations.filter(anno => anno.type === DocumentType.PUSHPIN); } // prettier-ignore
+ @computed get allRoutes() { return this.allAnnotations.filter(anno => anno.type === DocumentType.MAPROUTE); } // prettier-ignore
+ @computed get SidebarShown() { return !!this.layoutDoc._layout_showSidebar; } // prettier-ignore
+ @computed get sidebarWidthPercent() { return StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%'); } // prettier-ignore
+ @computed get SidebarKey() { return this.fieldKey + '_sidebar'; } // prettier-ignore
+ @computed get sidebarColor() {
+ return StrCast(this.layoutDoc.sidebar_color, StrCast(this.layoutDoc[this._props.fieldKey + '_backgroundColor'], '#e4e4e4'));
}
@computed get updatedRouteCoordinates(): Feature<Geometry, GeoJsonProperties> {
- if (this.routeToAnimate?.routeCoordinates) {
- const originalCoordinates: Position[] = JSON.parse(StrCast(this.routeToAnimate.routeCoordinates));
+ 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
- console.log('Animation phase', this.animationPhase);
+ const index = this._animationPhase * (originalCoordinates.length - 1); // Calculate the fractional index
+ console.log('Animation phase', this._animationPhase);
const startIndex = Math.floor(index);
const endIndex = Math.ceil(index);
let feature: Feature<Geometry, GeoJsonProperties>;
@@ -147,7 +140,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
feature = {
type: 'Feature',
properties: {
- routeTitle: StrCast(this.routeToAnimate.title),
+ routeTitle: StrCast(this._routeToAnimate.title),
},
geometry: geometry,
};
@@ -158,9 +151,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
const fraction = index - startIndex;
const interpolator = d3.interpolateArray(startCoord, endCoord);
-
const interpolatedCoord = interpolator(fraction);
-
const coordinates = originalCoordinates.slice(0, startIndex + 1).concat([interpolatedCoord]);
geometry = {
@@ -170,14 +161,14 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
feature = {
type: 'Feature',
properties: {
- routeTitle: StrCast(this.routeToAnimate.title),
+ routeTitle: StrCast(this._routeToAnimate.title),
},
geometry: geometry,
};
}
autorun(() => {
- const animationUtil = this.animationUtility;
+ const animationUtil = this._animationUtility;
const concattedCoordinates = geometry.coordinates.concat(originalCoordinates.slice(endIndex));
const newFeature: Feature<LineString, turf.Properties> = {
type: 'Feature',
@@ -204,11 +195,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
};
}
@computed get selectedRouteCoordinates(): Position[] {
- let coordinates: Position[] = [];
- if (this.routeToAnimate?.routeCoordinates) {
- coordinates = JSON.parse(StrCast(this.routeToAnimate.routeCoordinates));
- }
- return coordinates;
+ return !this._routeToAnimate?.routeCoordinates ? [] : JSON.parse(StrCast(this._routeToAnimate.routeCoordinates));
}
@computed get allRoutesGeoJson(): FeatureCollection {
@@ -233,50 +220,34 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
};
}
- @computed get SidebarShown() {
- return this.layoutDoc._layout_showSidebar ? true : false;
- }
- @computed get sidebarWidthPercent() {
- return StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%');
- }
- @computed get sidebarColor() {
- return StrCast(this.layoutDoc.sidebar_color, StrCast(this.layoutDoc[this._props.fieldKey + '_backgroundColor'], '#e4e4e4'));
- }
- @computed get SidebarKey() {
- return this.fieldKey + '_sidebar';
- }
-
componentDidMount() {
this._unmounting = false;
this._props.setContentViewBox?.(this);
}
- _unmounting = false;
- componentWillUnmount(): void {
+ componentWillUnmount() {
this._unmounting = true;
this.deselectPinOrRoute();
- this._rerenderTimeout && clearTimeout(this._rerenderTimeout);
Object.keys(this._disposers).forEach(key => this._disposers[key]?.());
}
/**
* Called when dragging documents into map sidebar or directly into infowindow; to create a map marker, ref to MapMarkerDocument in Documents.ts
- * @param doc
+ * @param docs
* @param sidebarKey
* @returns
*/
- sidebarAddDocument = (doc: Doc | Doc[], sidebarKey?: string) => {
+ sidebarAddDocument = (docs: Doc | Doc[], sidebarKey?: string) => {
if (!this.layoutDoc._layout_showSidebar) this.toggleSidebar();
- const docs = doc instanceof Doc ? [doc] : doc;
- docs.forEach(doc => {
- let existingPin = this.allPushpins.find(pin => pin.latitude === doc.latitude && pin.longitude === doc.longitude) ?? this.selectedPinOrRoute;
+ toList(docs).forEach(doc => {
+ 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));
}
if (existingPin) {
setTimeout(() => {
// we use a timeout in case this is called from the sidebar which may have just added a link that hasn't made its way into th elink manager yet
- if (!LinkManager.Instance.getAllRelatedLinks(doc).some(link => DocCast(link.link_anchor_1)?.mapPin === existingPin || DocCast(link.link_anchor_2)?.mapPin === existingPin)) {
+ if (!Doc.Links(doc).some(link => DocCast(link.link_anchor_1)?.mapPin === existingPin || DocCast(link.link_anchor_2)?.mapPin === existingPin)) {
const anchor = this.getAnchor(true, undefined, existingPin);
anchor && DocUtils.MakeLink(anchor, doc, { link_relationship: 'link to map location' });
doc.latitude = existingPin?.latitude;
@@ -284,14 +255,17 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
}
});
}
- }); //add to annotation list
+ }); // add to annotation list
- return this.addDocument(doc, sidebarKey); // add to sidebar list
+ return this.addDocument(docs, sidebarKey); // add to sidebar list
};
removeMapDocument = (doc: Doc | Doc[], annotationKey?: string) => {
- const docs = doc instanceof Doc ? [doc] : doc;
- this.allAnnotations.filter(anno => docs.includes(DocCast(anno.mapPin))).forEach(anno => (anno.mapPin = undefined));
+ this.allAnnotations
+ .filter(anno => toList(doc).includes(DocCast(anno.mapPin)))
+ .forEach(anno => {
+ anno.mapPin = undefined;
+ });
return this.removeDocument(doc, annotationKey, undefined);
};
@@ -311,7 +285,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
setupMoveUpEvents(
this,
e,
- (e, down, delta) =>
+ (moveEv, down, delta) =>
runInAction(() => {
const localDelta = this._props
.ScreenToLocalTransform()
@@ -351,7 +325,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
backgroundColor: this.SidebarShown ? Colors.MEDIUM_BLUE : Colors.BLACK,
}}
onPointerDown={this.sidebarBtnDown}>
- <FontAwesomeIcon style={{ color: Colors.WHITE }} icon={'comment-alt'} size="sm" />
+ <FontAwesomeIcon style={{ color: Colors.WHITE }} icon="comment-alt" size="sm" />
</div>
);
}
@@ -370,26 +344,26 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
const sourceAnchorCreator = action(() => {
const note = this.getAnchor(true);
- if (note && this.selectedPinOrRoute) {
- note.latitude = this.selectedPinOrRoute.latitude;
- note.longitude = this.selectedPinOrRoute.longitude;
- note.map = this.selectedPinOrRoute.map;
+ if (note && this._selectedPinOrRoute) {
+ note.latitude = this._selectedPinOrRoute.latitude;
+ note.longitude = this._selectedPinOrRoute.longitude;
+ note.map = this._selectedPinOrRoute.map;
}
return note as Doc;
});
const targetCreator = (annotationOn: Doc | undefined) => {
const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, annotationOn, 'yellow');
- FormattedTextBox.SetSelectOnLoad(target);
+ Doc.SetSelectOnLoad(target);
return target;
};
const docView = this.DocumentView?.();
docView &&
DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(docView, sourceAnchorCreator, targetCreator), e.pageX, e.pageY, {
- dragComplete: e => {
- if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) {
- e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.Document;
- e.annoDragData.linkSourceDoc.followLinkZoom = false;
+ dragComplete: dragEv => {
+ if (!dragEv.aborted && dragEv.annoDragData && dragEv.annoDragData.linkSourceDoc && dragEv.annoDragData.dropDocument && dragEv.linkDocument) {
+ dragEv.annoDragData.linkSourceDoc.followLinkToggle = dragEv.annoDragData.dropDocument.annotationOn === this.Document;
+ dragEv.annoDragData.linkSourceDoc.followLinkZoom = false;
}
},
});
@@ -399,10 +373,10 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
const createFunc = undoable(
action(() => {
const note = this._sidebarRef.current?.anchorMenuClick(this.getAnchor(true), ['latitude', 'longitude', LinkedTo]);
- if (note && this.selectedPinOrRoute) {
- note.latitude = this.selectedPinOrRoute.latitude;
- note.longitude = this.selectedPinOrRoute.longitude;
- note.map = this.selectedPinOrRoute.map;
+ if (note && this._selectedPinOrRoute) {
+ note.latitude = this._selectedPinOrRoute.latitude;
+ note.longitude = this._selectedPinOrRoute.longitude;
+ note.map = this._selectedPinOrRoute.map;
}
}),
'create note annotation'
@@ -415,7 +389,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
sidebarDown = (e: React.PointerEvent) => {
setupMoveUpEvents(this, e, this.sidebarMove, emptyFunction, () => setTimeout(this.toggleSidebar), true);
};
- sidebarMove = (e: PointerEvent, down: number[], delta: number[]) => {
+ sidebarMove = (e: PointerEvent) => {
const bounds = this._ref.current!.getBoundingClientRect();
this.layoutDoc._layout_sidebarWidthPercent = '' + 100 * Math.max(0, 1 - (e.clientX - bounds.left) / bounds.width) + '%';
this.layoutDoc._layout_showSidebar = this.layoutDoc._layout_sidebarWidthPercent !== '0%';
@@ -423,68 +397,20 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
return false;
};
- setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean, doc: Opt<Doc>) => void) => (this._setPreviewCursor = func);
-
- addDocumentWrapper = (doc: Doc | Doc[], annotationKey?: string) => this.addDocument(doc, annotationKey);
-
pointerEvents = () => (this._props.isContentActive() && !MarqueeOptionsMenu.Instance.isShown() ? 'all' : 'none');
-
panelWidth = () => this._props.PanelWidth() / (this._props.NativeDimScaling?.() || 1) - this.sidebarWidth();
panelHeight = () => this._props.PanelHeight() / (this._props.NativeDimScaling?.() || 1);
scrollXf = () => this.ScreenToLocalBoxXf().translate(0, NumCast(this.layoutDoc._layout_scrollTop));
- transparentFilter = () => [...this._props.childFilters(), Utils.TransparentBackgroundFilter];
- opaqueFilter = () => [...this._props.childFilters(), Utils.OpaqueBackgroundFilter];
+ transparentFilter = () => [...this._props.childFilters(), ClientUtils.TransparentBackgroundFilter];
+ opaqueFilter = () => [...this._props.childFilters(), ClientUtils.OpaqueBackgroundFilter];
infoWidth = () => this._props.PanelWidth() / 5;
infoHeight = () => this._props.PanelHeight() / 5;
anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick;
savedAnnotations = () => this._savedAnnotations;
- _bingSearchManager: any;
- _bingMap: any;
- get MicrosoftMaps() {
- return (window as any).Microsoft.Maps;
- }
- // uses Bing Search to retrieve lat/lng for a location. eg.,
- // const results = this.geocodeQuery(map.map, 'Philadelphia, PA');
- // to move the map to that location:
- // const location = await this.geocodeQuery(this._bingMap, 'Philadelphia, PA');
- // this._bingMap.current.setView({
- // mapTypeId: this.MicrosoftMaps.MapTypeId.aerial,
- // center: new this.MicrosoftMaps.Location(loc.latitude, loc.longitude),
- // });
- //
- bingGeocode = (map: any, query: string) => {
- return new Promise<{ latitude: number; longitude: number }>((res, reject) => {
- //If search manager is not defined, load the search module.
- if (!this._bingSearchManager) {
- //Create an instance of the search manager and call the geocodeQuery function again.
- this.MicrosoftMaps.loadModule('Microsoft.Maps.Search', () => {
- this._bingSearchManager = new this.MicrosoftMaps.Search.SearchManager(map.current);
- res(this.bingGeocode(map, query));
- });
- } else {
- this._bingSearchManager.geocode({
- where: query,
- callback: action((r: any) => res(r.results[0].location)),
- errorCallback: (e: any) => reject(),
- });
- }
- });
- };
-
- @observable
- bingSearchBarContents: any = this.Document.map; // For Bing Maps: The contents of the Bing search bar (string)
-
- geoDataRequestOptions = {
- entityType: 'PopulatedPlace',
- };
-
- // The pin that is selected
- @observable selectedPinOrRoute: Doc | undefined = undefined;
-
@action
deselectPinOrRoute = () => {
- if (this.selectedPinOrRoute) {
+ if (this._selectedPinOrRoute) {
// // Removes filter
// Doc.setDocFilter(this.Document, 'latitude', this.selectedPin.latitude, 'remove');
// Doc.setDocFilter(this.Document, 'longitude', this.selectedPin.longitude, 'remove');
@@ -509,79 +435,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
this.toggleSidebar();
options.didMove = true;
}
- return new Promise<Opt<DocumentView>>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv)));
- };
- /*
- * Pushpin onclick
- */
- @action
- pushpinClicked = (pinDoc: Doc) => {
- this.deselectPinOrRoute();
- this.selectedPinOrRoute = pinDoc;
- this.bingSearchBarContents = pinDoc.map;
-
- // Doc.setDocFilter(this.Document, 'latitude', this.selectedPin.latitude, 'match');
- // Doc.setDocFilter(this.Document, 'longitude', this.selectedPin.longitude, 'match');
- Doc.setDocFilter(this.Document, LinkedTo, `mapPin=${Field.toScriptString(this.selectedPinOrRoute)}`, 'check');
-
- this.recolorPin(this.selectedPinOrRoute, 'green');
-
- 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.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.ScreenToLocalBoxXf().inverse().transformPoint(x, y);
- MapAnchorMenu.Instance.jumpTo(cpt[0], cpt[1], true);
-
- document.addEventListener('pointerdown', this.tryHideMapAnchorMenu, true);
- };
-
- /**
- * Map OnClick
- */
- @action
- mapOnClick = (e: { location: { latitude: any; longitude: any } }) => {
- this._props.select(false);
- this.deselectPinOrRoute();
- };
- /*
- * Updates values of layout doc to match the current map
- */
- @action
- mapRecentered = () => {
- if (
- Math.abs(NumCast(this.dataDoc.latitude) - this._bingMap.current.getCenter().latitude) > 1e-7 || //
- Math.abs(NumCast(this.dataDoc.longitude) - this._bingMap.current.getCenter().longitude) > 1e-7
- ) {
- this.dataDoc.latitude = this._bingMap.current.getCenter().latitude;
- this.dataDoc.longitude = this._bingMap.current.getCenter().longitude;
- this.dataDoc.map = '';
- this.bingSearchBarContents = '';
- }
- this.dataDoc.map_zoom = this._bingMap.current.getZoom();
- };
- /*
- * Updates maptype
- */
- @action
- updateMapType = () => (this.dataDoc.map_type = this._bingMap.current.getMapTypeId());
-
- /*
- * For Bing Maps
- * Called by search button's onClick
- * Finds the geocode of the searched contents and sets location to that location
- **/
- @action
- bingSearch = () => {
- return this.bingGeocode(this._bingMap, this.bingSearchBarContents).then(location => {
- this.dataDoc.latitude = location.latitude;
- this.dataDoc.longitude = location.longitude;
- this.dataDoc.map_zoom = this._bingMap.current.getZoom();
- this.dataDoc.map = this.bingSearchBarContents;
+ return new Promise<Opt<DocumentView>>(res => {
+ DocumentView.addViewRenderedCb(doc, dv => res(dv));
});
};
@@ -592,20 +447,20 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
/// this should use SELECTED pushpin for lat/long if there is a selection, otherwise CENTER
const anchor = Docs.Create.ConfigDocument({
title: 'MapAnchor:' + this.Document.title,
- text: (StrCast(this.selectedPinOrRoute?.map) || StrCast(this.Document.map) || 'map location') as any,
- config_latitude: NumCast((existingPin ?? this.selectedPinOrRoute)?.latitude ?? this.dataDoc.latitude),
- config_longitude: NumCast((existingPin ?? this.selectedPinOrRoute)?.longitude ?? this.dataDoc.longitude),
+ text: (StrCast(this._selectedPinOrRoute?.map) || StrCast(this.Document.map) || 'map location') as any,
+ config_latitude: NumCast((existingPin ?? this._selectedPinOrRoute)?.latitude ?? this.dataDoc.latitude),
+ config_longitude: NumCast((existingPin ?? this._selectedPinOrRoute)?.longitude ?? this.dataDoc.longitude),
config_map_zoom: NumCast(this.dataDoc.map_zoom),
// config_map_type: StrCast(this.dataDoc.map_type),
- config_map: StrCast((existingPin ?? this.selectedPinOrRoute)?.map) || StrCast(this.dataDoc.map),
+ config_map: StrCast((existingPin ?? this._selectedPinOrRoute)?.map) || StrCast(this.dataDoc.map),
layout_unrendered: true,
- mapPin: existingPin ?? this.selectedPinOrRoute,
+ mapPin: existingPin ?? this._selectedPinOrRoute,
annotationOn: this.Document,
});
if (anchor) {
if (!addAsAnnotation) anchor.backgroundColor = 'transparent';
addAsAnnotation && this.addDocument(anchor);
- PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), map: true } }, this.Document);
+ PinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), map: true } }, this.Document);
return anchor;
}
return this.Document;
@@ -613,25 +468,6 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
map_docToPinMap = new Map<Doc, any>();
map_pinHighlighted = new Map<Doc, boolean>();
- /*
- * Input: pin doc
- * Adds MicrosoftMaps Pushpin to the map (render)
- */
- @action
- addPushpin = (pin: Doc) => {
- const pushPin = pin.infoWindowOpen
- ? new this.MicrosoftMaps.Pushpin(new this.MicrosoftMaps.Location(pin.latitude, pin.longitude), {})
- : new this.MicrosoftMaps.Pushpin(
- new this.MicrosoftMaps.Location(pin.latitude, pin.longitude)
- // {icon: 'http://icons.iconarchive.com/icons/icons-land/vista-map-markers/24/Map-Marker-Marker-Outside-Chartreuse-icon.png'}
- );
-
- this._bingMap.current.entities.push(pushPin);
-
- this.MicrosoftMaps.Events.addHandler(pushPin, 'click', (e: any) => this.pushpinClicked(pin));
- // this.MicrosoftMaps.Events.addHandler(pushPin, 'dblclick', (e: any) => this.pushpinDblClicked(pushPin, pin));
- this.map_docToPinMap.set(pin, pushPin);
- };
/*
* Input: pin doc
@@ -640,27 +476,16 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
@action
removePushpinOrRoute = (pinOrRouteDoc: Doc) => this.removeMapDocument(pinOrRouteDoc, this.annotationKey);
- /*
- * Removes pushpin from map render
- */
- deletePushpin = (pinDoc: Doc) => {
- if (!this._unmounting) {
- this._bingMap.current.entities.remove(this.map_docToPinMap.get(pinDoc));
- }
- this.map_docToPinMap.delete(pinDoc);
- this.selectedPinOrRoute = undefined;
- };
-
@action
deleteSelectedPinOrRoute = undoable(() => {
console.log('deleting');
- if (this.selectedPinOrRoute) {
+ if (this._selectedPinOrRoute) {
// Removes filter
- Doc.setDocFilter(this.Document, 'latitude', this.selectedPinOrRoute.latitude, 'remove');
- Doc.setDocFilter(this.Document, 'longitude', this.selectedPinOrRoute.longitude, 'remove');
- Doc.setDocFilter(this.Document, LinkedTo, `mapPin=${Field.toScriptString(DocCast(this.selectedPinOrRoute))}`, 'remove');
+ Doc.setDocFilter(this.Document, 'latitude', this._selectedPinOrRoute.latitude, 'remove');
+ Doc.setDocFilter(this.Document, 'longitude', this._selectedPinOrRoute.longitude, 'remove');
+ Doc.setDocFilter(this.Document, LinkedTo, `mapPin=${Field.toScriptString(DocCast(this._selectedPinOrRoute))}`, 'remove');
- this.removePushpinOrRoute(this.selectedPinOrRoute);
+ this.removePushpinOrRoute(this._selectedPinOrRoute);
}
MapAnchorMenu.Instance.fadeOut(true);
document.removeEventListener('pointerdown', this.tryHideMapAnchorMenu, true);
@@ -677,7 +502,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
e.preventDefault();
MapAnchorMenu.Instance.fadeOut(true);
runInAction(() => {
- this.temporaryRouteSource = {
+ this._temporaryRouteSource = {
type: 'FeatureCollection',
features: [],
};
@@ -688,9 +513,9 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
@action
centerOnSelectedPin = () => {
- if (this.selectedPinOrRoute) {
+ if (this._selectedPinOrRoute) {
this._mapRef.current?.flyTo({
- center: [NumCast(this.selectedPinOrRoute.longitude), NumCast(this.selectedPinOrRoute.latitude)],
+ center: [NumCast(this._selectedPinOrRoute.longitude), NumCast(this._selectedPinOrRoute.latitude)],
});
}
// if (this.selectedPin) {
@@ -703,33 +528,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
document.removeEventListener('pointerdown', this.tryHideMapAnchorMenu);
};
- /**
- * View options for bing maps
- */
- bingViewOptions = {
- // center: { latitude: this.dataDoc.latitude ?? defaultCenter.lat, longitude: this.dataDoc.longitude ?? defaultCenter.lng },
- zoom: this.dataDoc.latitude ?? 10,
- mapTypeId: 'grayscale',
- };
-
- /**
- * Map options
- */
- bingMapOptions = {
- navigationBarMode: 'square',
- backgroundColor: '#f1f3f4',
- enableInertia: true,
- supportedMapTypes: ['grayscale', 'canvasLight'],
- disableMapTypeSelectorMouseOver: true,
- // showScalebar:true
- // disableRoadView:true,
- // disableBirdseye:true
- streetsideOptions: {
- showProblemReporting: false,
- showCurrentAddress: false,
- },
- };
-
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
recolorPin = (pin: Doc, color?: string) => {
// this._bingMap.current.entities.remove(this.map_docToPinMap.get(pin));
// this.map_docToPinMap.delete(pin);
@@ -739,109 +538,6 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
// this.map_docToPinMap.set(pin, newpin);
};
- /*
- * Called when BingMap is first rendered
- * Initializes starting values
- */
- @observable _mapReady = false;
- @action
- bingMapReady = (map: any) => {
- this._mapReady = true;
- this._bingMap = map.map;
- if (!this._bingMap.current) {
- alert('NO Map!?');
- }
- this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'click', this.mapOnClick);
- this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'viewchangeend', undoable(this.mapRecentered, 'Map Layout Change'));
- this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'maptypechanged', undoable(this.updateMapType, 'Map ViewType Change'));
-
- this._disposers.mapLocation = reaction(
- () => this.Document.map,
- mapLoc => (this.bingSearchBarContents = mapLoc),
- { fireImmediately: true }
- );
- this._disposers.highlight = reaction(
- () => this.allAnnotations.map(doc => doc[Highlight]),
- () => {
- const allConfigPins = this.allAnnotations.map(doc => ({ doc, pushpin: DocCast(doc.mapPin) })).filter(pair => pair.pushpin);
- allConfigPins.forEach(({ doc, pushpin }) => {
- if (!pushpin[Highlight] && this.map_pinHighlighted.get(pushpin)) {
- this.recolorPin(pushpin);
- this.map_pinHighlighted.delete(pushpin);
- }
- });
- allConfigPins.forEach(({ doc, pushpin }) => {
- if (doc[Highlight] && !this.map_pinHighlighted.get(pushpin)) {
- this.recolorPin(pushpin, 'orange');
- this.map_pinHighlighted.set(pushpin, true);
- }
- });
- },
- { fireImmediately: true }
- );
-
- this._disposers.location = reaction(
- () => ({ lat: this.Document.latitude, lng: this.Document.longitude, zoom: this.Document.map_zoom, mapType: this.Document.map_type }),
- locationObject => {
- // if (this._bingMap.current)
- try {
- locationObject?.zoom &&
- this._bingMap.current?.setView({
- mapTypeId: locationObject.mapType,
- zoom: locationObject.zoom,
- center: new this.MicrosoftMaps.Location(locationObject.lat, locationObject.lng),
- });
- } catch (e) {
- console.log(e);
- }
- },
- { fireImmediately: true }
- );
- };
-
- dragToggle = (e: React.PointerEvent) => {
- let dragClone: HTMLDivElement | undefined;
-
- setupMoveUpEvents(
- e,
- e,
- e => {
- // move event
- if (!dragClone) {
- dragClone = this._dragRef.current?.cloneNode(true) as HTMLDivElement; // copy draggable pin
- dragClone.style.position = 'absolute';
- dragClone.style.zIndex = '10000';
- DragManager.Root().appendChild(dragClone); // add clone to root
- }
- dragClone.style.transform = `translate(${e.clientX - 15}px, ${e.clientY - 15}px)`;
- return false;
- },
- e => {
- // up event
- if (!dragClone) return;
- DragManager.Root().removeChild(dragClone);
- let target = document.elementFromPoint(e.x, e.y); // element for specified x and y coordinates
- while (target) {
- if (target === this._ref.current) {
- const cpt = this.ScreenToLocalBoxXf().transformPoint(e.clientX, e.clientY);
- const x = cpt[0] - (this._props.PanelWidth() - this.sidebarWidth()) / 2;
- const y = cpt[1] - 20 /* height of search bar */ - this._props.PanelHeight() / 2;
- const location = this._bingMap.current.tryPixelToLocation(new this.MicrosoftMaps.Point(x, y));
- this.createPushpin(location.latitude, location.longitude);
- break;
- }
- target = target.parentElement;
- }
- },
- e => {
- const createPin = () => this.createPushpin(this.Document.latitude, this.Document.longitude, this.Document.map);
- if (this.bingSearchBarContents) {
- this.bingSearch().then(createPin);
- } else createPin();
- }
- );
- };
-
// incrementer: number = 0;
/*
* Creates Pushpin doc and adds it to the list of annotations
@@ -880,20 +576,25 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
if (createPinForDestination) {
this.createPushpin(destination.center[1], destination.center[0], destination.place_name);
}
- this.temporaryRouteSource = {
+ this._temporaryRouteSource = {
type: 'FeatureCollection',
features: [],
};
MapAnchorMenu.Instance.fadeOut(true);
return mapRoute;
}
+ return undefined;
// TODO: Display error that can't create route to same location
}, 'createmaproute');
- searchbarKeyDown = (e: any) => e.key === 'Enter' && this.bingSearch();
-
- @observable
- featuresFromGeocodeResults: any[] = [];
+ @action
+ searchbarKeyDown = (e: any) => {
+ if (e.key === 'Enter' && this._featuresFromGeocodeResults) {
+ const center = this._featuresFromGeocodeResults[0]?.center;
+ this._featuresFromGeocodeResults = [];
+ setTimeout(() => center && this._mapRef.current?.flyTo({ center }));
+ }
+ };
@action
addMarkerForFeature = (feature: any) => {
@@ -910,7 +611,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
center: feature.center,
});
}
- this.featuresFromGeocodeResults = [];
+ this._featuresFromGeocodeResults = [];
} else {
// TODO: handle error
}
@@ -922,11 +623,11 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
*/
handleSearchChange = async (searchText: string) => {
const features = await MapboxApiUtility.forwardGeocodeForFeatures(searchText);
- if (features && !this.isAnimating) {
+ if (features && !this._isAnimating) {
runInAction(() => {
- this.settingsOpen = false;
- this.featuresFromGeocodeResults = features;
- this.routeToAnimate = undefined;
+ this._settingsOpen = false;
+ this._featuresFromGeocodeResults = features;
+ this._routeToAnimate = undefined;
});
}
// try {
@@ -946,8 +647,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
@action
handleMapClick = (e: MapLayerMouseEvent) => {
- this.featuresFromGeocodeResults = [];
- this.settingsOpen = false;
+ this._featuresFromGeocodeResults = [];
+ this._settingsOpen = false;
if (this._mapRef.current) {
const features = this._mapRef.current.queryRenderedFeatures(e.point, {
layers: ['map-routes-layer'],
@@ -955,13 +656,12 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
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);
+ const { routeTitle } = features[0].properties;
+ const routeDoc: Doc | undefined = this.allRoutes.find(rtDoc => rtDoc.title === routeTitle);
this.deselectPinOrRoute(); // TODO: Also deselect route if selected
if (routeDoc) {
- this.selectedPinOrRoute = routeDoc;
- Doc.setDocFilter(this.Document, LinkedTo, `mapRoute=${Field.toScriptString(this.selectedPinOrRoute)}`, 'check');
+ this._selectedPinOrRoute = routeDoc;
+ Doc.setDocFilter(this.Document, LinkedTo, `mapRoute=${Field.toScriptString(this._selectedPinOrRoute)}`, 'check');
// TODO: Recolor route
@@ -1001,14 +701,14 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
*/
handleMapDblClick = async (e: MapLayerMouseEvent) => {
e.preventDefault();
- const lngLat: LngLat = e.lngLat;
+ const { lngLat } = e;
const longitude: number = lngLat.lng;
const latitude: number = lngLat.lat;
const features = await MapboxApiUtility.reverseGeocodeForFeatures(longitude, latitude);
if (features) {
runInAction(() => {
- this.featuresFromGeocodeResults = features;
+ this._featuresFromGeocodeResults = features;
});
}
@@ -1028,21 +728,18 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
// }
};
- @observable
- currentPopup: PopupInfo | undefined = undefined;
-
@action
handleMarkerClick = (e: MarkerEvent<mapboxgl.Marker, MouseEvent>, pinDoc: Doc) => {
- this.featuresFromGeocodeResults = [];
+ this._featuresFromGeocodeResults = [];
this.deselectPinOrRoute(); // TODO: check this method
- this.selectedPinOrRoute = pinDoc;
+ this._selectedPinOrRoute = pinDoc;
// this.bingSearchBarContents = pinDoc.map;
// Doc.setDocFilter(this.Document, 'latitude', this.selectedPin.latitude, 'match');
// Doc.setDocFilter(this.Document, 'longitude', this.selectedPin.longitude, 'match');
- Doc.setDocFilter(this.Document, LinkedTo, `mapPin=${Field.toScriptString(this.selectedPinOrRoute)}`, 'check');
+ Doc.setDocFilter(this.Document, LinkedTo, `mapPin=${Field.toScriptString(this._selectedPinOrRoute)}`, 'check');
- this.recolorPin(this.selectedPinOrRoute, 'green'); // TODO: check this method
+ this.recolorPin(this._selectedPinOrRoute, 'green'); // TODO: check this method
MapAnchorMenu.Instance.Delete = this.deleteSelectedPinOrRoute;
MapAnchorMenu.Instance.Center = this.centerOnSelectedPin;
@@ -1072,12 +769,6 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
// })
};
- @observable
- temporaryRouteSource: FeatureCollection = {
- type: 'FeatureCollection',
- features: [],
- };
-
@action
displayRoute = (routeInfoMap: Record<TransportationType, any> | undefined, type: TransportationType) => {
if (routeInfoMap) {
@@ -1096,41 +787,23 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
};
// TODO: Create pin for destination
// TODO: Fly to point where full route will be shown
- this.temporaryRouteSource = newTempRouteSource;
+ this._temporaryRouteSource = newTempRouteSource;
}
};
- @observable
- isAnimating: boolean = false;
-
- @observable
- routeToAnimate: Doc | undefined = undefined;
-
- @observable
- animationPhase: number = 0;
-
- @observable
- finishedFlyTo: boolean = false;
-
@action
setAnimationPhase = (newValue: number) => {
- this.animationPhase = newValue;
+ this._animationPhase = newValue;
};
- @observable
- frameId: number | null = null;
-
@action
setFrameId = (frameId: number) => {
- this.frameId = frameId;
+ this._frameId = frameId;
};
- @observable
- animationUtility: AnimationUtility | null = null;
-
@action
setAnimationUtility = (util: AnimationUtility) => {
- this.animationUtility = util;
+ this._animationUtility = util;
};
@action
@@ -1138,8 +811,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
if (routeDoc) {
MapAnchorMenu.Instance.fadeOut(true);
document.removeEventListener('pointerdown', this.tryHideMapAnchorMenu, true);
- this.featuresFromGeocodeResults = [];
- this.routeToAnimate = routeDoc;
+ this._featuresFromGeocodeResults = [];
+ this._routeToAnimate = routeDoc;
}
};
@@ -1161,29 +834,21 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
@computed
get preAnimationViewState() {
- if (!this.isAnimating) {
+ if (!this._isAnimating) {
return this.mapboxMapViewState;
}
+ return undefined;
}
- @observable
- isStreetViewAnimation: boolean = false;
-
- @observable
- animationSpeed: AnimationSpeed = AnimationSpeed.MEDIUM;
-
- @observable
- animationLineColor: string = '#ffff00';
-
@action
setAnimationLineColor = (color: ColorResult) => {
- this.animationLineColor = color.hex;
+ this._animationLineColor = color.hex;
};
@action
updateAnimationSpeed = () => {
let newAnimationSpeed: AnimationSpeed;
- switch (this.animationSpeed) {
+ switch (this._animationSpeed) {
case AnimationSpeed.SLOW:
newAnimationSpeed = AnimationSpeed.MEDIUM;
break;
@@ -1197,63 +862,33 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
newAnimationSpeed = AnimationSpeed.MEDIUM;
break;
}
- this.animationSpeed = newAnimationSpeed;
- if (this.animationUtility) {
- this.animationUtility.updateAnimationSpeed(newAnimationSpeed);
+ this._animationSpeed = newAnimationSpeed;
+ if (this._animationUtility) {
+ this._animationUtility.updateAnimationSpeed(newAnimationSpeed);
}
};
@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';
- }
+ 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';
+ } // prettier-ignore
}
@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;
- }
+ switch (this._animationSpeed) {
+ case AnimationSpeed.SLOW: return slowSpeedIcon;
+ case AnimationSpeed.MEDIUM: return mediumSpeedIcon;
+ case AnimationSpeed.FAST: return fastSpeedIcon;
+ default: return mediumSpeedIcon;
+ } // prettier-ignore
}
@action
toggleIsStreetViewAnimation = () => {
- const newVal = !this.isStreetViewAnimation;
- this.isStreetViewAnimation = newVal;
- if (this.animationUtility) {
- this.animationUtility.updateIsStreetViewAnimation(newVal);
- }
- };
-
- @observable
- dynamicRouteFeature: Feature<Geometry, GeoJsonProperties> = {
- type: 'Feature',
- properties: {},
- geometry: {
- type: 'LineString',
- coordinates: [],
- },
- };
-
- @observable
- path: turf.helpers.Feature<turf.helpers.LineString, turf.helpers.Properties> = {
- type: 'Feature',
- geometry: {
- type: 'LineString',
- coordinates: [],
- },
- properties: {},
+ const newVal = !this._isStreetViewAnimation;
+ this._isStreetViewAnimation = newVal;
+ this._animationUtility?.updateIsStreetViewAnimation(newVal);
};
getFeatureFromRouteDoc = (routeDoc: Doc): Feature<Geometry, GeoJsonProperties> => {
@@ -1272,190 +907,172 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
@action
playAnimation = (status: AnimationStatus) => {
- if (!this._mapRef.current || !this.routeToAnimate) {
+ if (!this._mapRef.current || !this._routeToAnimate) {
return;
}
- this.animationPhase = status === AnimationStatus.RESUME ? this.animationPhase : 0;
- this.frameId = AnimationStatus.RESUME ? this.frameId : null;
- this.finishedFlyTo = AnimationStatus.RESUME ? this.finishedFlyTo : false;
+ 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._settingsOpen = false;
this.path = path;
- this.isAnimating = true;
-
- runInAction(() => {
- return new Promise<void>(async resolve => {
- const targetLngLat = {
- lng: this.selectedRouteCoordinates[0][0],
- lat: this.selectedRouteCoordinates[0][1],
- };
-
- const animationUtil = new AnimationUtility(targetLngLat, this.selectedRouteCoordinates, this.isStreetViewAnimation, this.animationSpeed, this.showTerrain, this._mapRef.current);
- runInAction(() => {
- this.setAnimationUtility(animationUtil);
- });
+ this._isAnimating = true;
+
+ runInAction(
+ () =>
+ // eslint-disable-next-line no-async-promise-executor
+ new Promise<void>(async resolve => {
+ const targetLngLat = {
+ lng: this.selectedRouteCoordinates[0][0],
+ lat: this.selectedRouteCoordinates[0][1],
+ };
+
+ const animationUtil = new AnimationUtility(targetLngLat, this.selectedRouteCoordinates, this._isStreetViewAnimation, this._animationSpeed, this._showTerrain, this._mapRef.current);
+ runInAction(() => this.setAnimationUtility(animationUtil));
+
+ 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,
+ });
- const updateFrameId = (newFrameId: number) => {
- this.setFrameId(newFrameId);
- };
+ console.log('Bearing: ', result.bearing);
+ console.log('Altitude: ', result.altitude);
+ }
- const updateAnimationPhase = (newAnimationPhase: number) => {
- this.setAnimationPhase(newAnimationPhase);
- };
+ runInAction(() => {
+ this._finishedFlyTo = true;
+ });
- if (status !== AnimationStatus.RESUME) {
- const result = await animationUtil.flyInAndRotate({
+ // 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!,
- // targetLngLat,
- // duration 3000
- // startAltitude: 3000000,
- // endAltitude: this.isStreetViewAnimation ? 80 : 12000,
- // startBearing: 0,
- // endBearing: -20,
- // startPitch: 40,
- // endPitch: this.isStreetViewAnimation ? 80 : 50,
+ // path: this.path,
+ // startBearing: -20,
+ // startAltitude: this.isStreetViewAnimation ? 80 : 12000,
+ // pitch: this.isStreetViewAnimation ? 80: 50,
+ currentAnimationPhase: this._animationPhase,
+ updateAnimationPhase,
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);
+ // 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]];
+ const bbox2d: LngLatBoundsLike = [bbox3d[0], bbox3d[1], bbox3d[2], bbox3d[3]];
- this._mapRef.current!.fitBounds(bbox2d, {
- duration: 3000,
- pitch: 30,
- bearing: 0,
- padding: 120,
- });
+ this._mapRef.current!.fitBounds(bbox2d, {
+ duration: 3000,
+ pitch: 30,
+ bearing: 0,
+ padding: 120,
+ });
- setTimeout(() => {
- this.isStreetViewAnimation = false;
- resolve();
- }, 10000);
- });
- });
+ setTimeout(() => {
+ this._isStreetViewAnimation = false;
+ resolve();
+ }, 10000);
+ })
+ );
};
@action
pauseAnimation = () => {
- if (this.frameId && this.animationPhase > 0) {
- window.cancelAnimationFrame(this.frameId);
- this.frameId = null;
- this.isAnimating = false;
+ if (this._frameId && this._animationPhase > 0) {
+ window.cancelAnimationFrame(this._frameId);
+ this._frameId = null;
+ this._isAnimating = false;
}
};
@action
stopAnimation = (close: boolean) => {
- if (this.frameId) {
- window.cancelAnimationFrame(this.frameId);
+ if (this._frameId) {
+ window.cancelAnimationFrame(this._frameId);
}
- this.animationPhase = 0;
- this.frameId = null;
- this.finishedFlyTo = false;
- this.isAnimating = false;
+ this._animationPhase = 0;
+ this._frameId = null;
+ this._finishedFlyTo = false;
+ this._isAnimating = false;
if (close) {
- this.animationSpeed = AnimationSpeed.MEDIUM;
- this.isStreetViewAnimation = false;
- this.routeToAnimate = undefined;
- this.animationUtility = null;
+ this._animationSpeed = AnimationSpeed.MEDIUM;
+ this._isStreetViewAnimation = false;
+ this._routeToAnimate = undefined;
+ this._animationUtility = null;
}
};
- getRouteAnimationOptions = (): JSX.Element => {
- return (
- <>
+ getRouteAnimationOptions = (): JSX.Element => (
+ <>
+ <IconButton
+ tooltip={this._isAnimating && this._finishedFlyTo ? 'Pause Animation' : 'Play Animation'}
+ onPointerDown={() => {
+ if (this._isAnimating && this._finishedFlyTo) {
+ this.pauseAnimation();
+ } else if (this._animationPhase > 0) {
+ this.playAnimation(AnimationStatus.RESUME); // Resume from the current phase
+ } else {
+ this.playAnimation(AnimationStatus.START); // Play from the beginning
+ }
+ }}
+ icon={this._isAnimating && this._finishedFlyTo ? <FontAwesomeIcon icon={faPause as IconLookup} /> : <FontAwesomeIcon icon={faPlay as IconLookup} />}
+ color="black"
+ size={Size.MEDIUM}
+ />
+ {this._isAnimating && this._finishedFlyTo && (
<IconButton
- tooltip={this.isAnimating && this.finishedFlyTo ? 'Pause Animation' : 'Play Animation'}
+ tooltip="Restart animation"
onPointerDown={() => {
- if (this.isAnimating && this.finishedFlyTo) {
- this.pauseAnimation();
- } else if (this.animationPhase > 0) {
- this.playAnimation(AnimationStatus.RESUME); // Resume from the current phase
- } else {
- this.playAnimation(AnimationStatus.START); // Play from the beginning
- }
+ this.stopAnimation(false);
+ this.playAnimation(AnimationStatus.START);
}}
- icon={this.isAnimating && this.finishedFlyTo ? <FontAwesomeIcon icon={faPause as IconLookup} /> : <FontAwesomeIcon icon={faPlay as IconLookup} />}
+ icon={<FontAwesomeIcon icon={faRotate as IconLookup} />}
color="black"
size={Size.MEDIUM}
/>
- {this.isAnimating && this.finishedFlyTo && (
- <IconButton
- tooltip="Restart animation"
- onPointerDown={() => {
- this.stopAnimation(false);
- this.playAnimation(AnimationStatus.START);
- }}
- icon={<FontAwesomeIcon icon={faRotate as IconLookup} />}
- color="black"
- size={Size.MEDIUM}
- />
- )}
- <IconButton style={{ marginRight: '10px' }} tooltip="Stop and close animation" onPointerDown={() => this.stopAnimation(true)} icon={<FontAwesomeIcon icon={faCircleXmark as IconLookup} />} color="black" size={Size.MEDIUM} />
- <>
- <div className="animation-suboptions">
- <div>|</div>
- <FormControlLabel className="first-person-label" label="1st person animation:" labelPlacement="start" control={<Checkbox color="success" checked={this.isStreetViewAnimation} onChange={this.toggleIsStreetViewAnimation} />} />
- <div id="divider">|</div>
- <IconButton tooltip={this.animationSpeedTooltipText} onPointerDown={this.updateAnimationSpeed} icon={this.animationSpeedIcon} size={Size.MEDIUM} />
- <div id="divider">|</div>
- <div style={{ display: 'flex', alignItems: 'center' }}>
- <div>Select Line Color: </div>
- <CirclePicker circleSize={12} circleSpacing={5} width="100%" colors={['#ffff00', '#03a9f4', '#ff0000', '#ff5722', '#000000', '#673ab7']} onChange={(color: any) => this.setAnimationLineColor(color)} />
- </div>
- </div>
- </>
- </>
- );
- };
+ )}
+ <IconButton style={{ marginRight: '10px' }} tooltip="Stop and close animation" onPointerDown={() => this.stopAnimation(true)} icon={<FontAwesomeIcon icon={faCircleXmark as IconLookup} />} color="black" size={Size.MEDIUM} />
+ <div className="animation-suboptions">
+ <div>|</div>
+ <FormControlLabel className="first-person-label" label="1st person animation:" labelPlacement="start" control={<Checkbox color="success" checked={this._isStreetViewAnimation} onChange={this.toggleIsStreetViewAnimation} />} />
+ <div id="divider">|</div>
+ <IconButton tooltip={this.animationSpeedTooltipText} onPointerDown={this.updateAnimationSpeed} icon={this.animationSpeedIcon} size={Size.MEDIUM} />
+ <div id="divider">|</div>
+ <div style={{ display: 'flex', alignItems: 'center' }}>
+ <div>Select Line Color: </div>
+ <CirclePicker circleSize={12} circleSpacing={5} width="100%" colors={['#ffff00', '#03a9f4', '#ff0000', '#ff5722', '#000000', '#673ab7']} onChange={(color: any) => this.setAnimationLineColor(color)} />
+ </div>
+ </div>
+ </>
+ );
@action
hideRoute = () => {
- this.temporaryRouteSource = {
+ this._temporaryRouteSource = {
type: 'FeatureCollection',
features: [],
};
};
- @observable
- settingsOpen: boolean = false;
-
- @observable
- mapStyle: string = 'mapbox://styles/mapbox/standard';
-
- @observable
- showTerrain: boolean = true;
-
@action
toggleSettings = () => {
- if (!this.isAnimating && this.animationPhase == 0) {
- this.featuresFromGeocodeResults = [];
- this.settingsOpen = !this.settingsOpen;
+ if (!this._isAnimating && this._animationPhase === 0) {
+ this._featuresFromGeocodeResults = [];
+ this._settingsOpen = !this._settingsOpen;
}
};
@@ -1500,21 +1117,19 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
@action
onStepZoomChange = (increment: boolean) => {
if (this._mapRef.current) {
- let newZoom: number;
- if (increment) {
- console.log('inc');
- newZoom = Math.min(16, this.mapboxMapViewState.zoom + 1);
- } else {
- console.log('dec');
- newZoom = Math.max(0, this.mapboxMapViewState.zoom - 1);
- }
+ const newZoom = increment //
+ ? Math.min(16, this.mapboxMapViewState.zoom + 1)
+ : Math.max(0, this.mapboxMapViewState.zoom - 1);
+
this._mapRef.current.setZoom(newZoom);
this.dataDoc.map_zoom = newZoom;
}
};
@action
- onMapZoom = (e: ViewStateChangeEvent) => (this.dataDoc.map_zoom = e.viewState.zoom);
+ onMapZoom = (e: ViewStateChangeEvent) => {
+ this.dataDoc.map_zoom = e.viewState.zoom;
+ };
@action
onMapMove = (e: ViewStateChangeEvent) => {
@@ -1523,7 +1138,9 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
};
@action
- toggleShowTerrain = () => (this.showTerrain = !this.showTerrain);
+ toggleShowTerrain = () => {
+ this._showTerrain = !this._showTerrain;
+ };
getMarkerIcon = (pinDoc: Doc): JSX.Element | null => {
const markerType = StrCast(pinDoc.markerType);
@@ -1532,48 +1149,28 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
return MarkerIcons.getFontAwesomeIcon(markerType, '2x', markerColor) ?? null;
};
- static _firstRender = true;
- static _rerenderDelay = 500;
- _rerenderTimeout: any;
+ _textRef = React.createRef<any>();
render() {
- // bcz: no idea what's going on here, but bings maps have some kind of bug
- // such that we need to delay rendering a second map on startup until the first map is rendered.
- this.Document[DocCss];
- if (MapBox._rerenderDelay) {
- // prettier-ignore
- this._rerenderTimeout = this._rerenderTimeout ??
- setTimeout(action(() => {
- if ((window as any).Microsoft?.Maps?.Internal._WorkDispatcher) {
- MapBox._rerenderDelay = 0;
- }
- this._rerenderTimeout = undefined;
- this.Document[DocCss] = this.Document[DocCss] + 1;
- }), MapBox._rerenderDelay);
- return null;
- }
const scale = this._props.NativeDimScaling?.() || 1;
const parscale = scale === 1 ? 1 : this.ScreenToLocalBoxXf().Scale ?? 1;
- const renderAnnotations = (childFilters?: () => string[]) => null;
return (
<div className="mapBox" ref={this._ref}>
<div
className="mapBox-wrapper"
onWheel={e => e.stopPropagation()}
- onPointerDown={async e => {
- e.button === 0 && !e.ctrlKey && e.stopPropagation();
- }}
+ onPointerDown={e => e.button === 0 && !e.ctrlKey && e.stopPropagation()}
style={{ transformOrigin: 'top left', transform: `scale(${scale})`, width: `calc(100% - ${this.sidebarWidthPercent})`, pointerEvents: this.pointerEvents() }}>
- <div style={{ mixBlendMode: 'multiply' }}>{renderAnnotations(this.transparentFilter)}</div>
- {renderAnnotations(this.opaqueFilter)}
- {SnappingManager.IsDragging ? null : renderAnnotations()}
- {!this.routeToAnimate && (
+ {!this._routeToAnimate && (
<div className="mapBox-searchbar" style={{ width: `${100 / scale}%`, zIndex: 1, position: 'relative', background: 'lightGray' }}>
- <TextField fullWidth placeholder="Enter a location" onChange={(e: any) => this.handleSearchChange(e.target.value)} />
- <IconButton icon={<FontAwesomeIcon icon={faGear as IconLookup} size="1x" />} type={Type.TERT} onClick={e => this.toggleSettings()} />
+ <TextField ref={this._textRef} fullWidth placeholder="Enter a location" onKeyDown={this.searchbarKeyDown} onChange={(e: any) => this.handleSearchChange(e.target.value)} />
+ <IconButton icon={<FontAwesomeIcon icon={faGear as IconLookup} size="1x" />} type={Type.TERT} onClick={() => this.toggleSettings()} />
+ <div style={{ opacity: 0 }}>
+ <IconButton icon={<FontAwesomeIcon icon={faGear as IconLookup} size="1x" />} type={Type.TERT} onClick={() => this.toggleSettings()} />
+ </div>
</div>
)}
- {this.settingsOpen && !this.routeToAnimate && (
+ {this._settingsOpen && !this._routeToAnimate && (
<div className="mapbox-settings-panel" style={{ right: `${0 + this.sidebarWidth()}px` }}>
<div className="mapbox-style-select">
<div>Map Style:</div>
@@ -1605,41 +1202,40 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
</div>
<div className="mapbox-terrain-selection">
<div>Show terrain: </div>
- <input type="checkbox" checked={this.showTerrain} onChange={this.toggleShowTerrain} />
+ <input type="checkbox" checked={this._showTerrain} onChange={this.toggleShowTerrain} />
</div>
</div>
)}
- {this.routeToAnimate && (
+ {this._routeToAnimate && (
<div className="animation-panel" style={{ width: this.sidebarWidth() === 0 ? '100%' : `calc(100% - ${this.sidebarWidth()}px)` }}>
- <div id="route-to-animate-title">{StrCast(this.routeToAnimate.title)}</div>
+ <div id="route-to-animate-title">{StrCast(this._routeToAnimate.title)}</div>
<div className="route-animation-options">{this.getRouteAnimationOptions()}</div>
</div>
)}
- {this.featuresFromGeocodeResults.length > 0 && (
+ {this._featuresFromGeocodeResults.length > 0 && (
<div className="mapbox-geocoding-search-results">
- <React.Fragment>
- <h4>Choose a location for your pin: </h4>
- {this.featuresFromGeocodeResults
- .filter(feature => feature.place_name)
- .map((feature, idx) => (
- <div
- key={idx}
- className="search-result-container"
- onClick={() => {
- this.handleSearchChange('');
- this.addMarkerForFeature(feature);
- }}>
- <div className="search-result-place-name">{feature.place_name}</div>
- </div>
- ))}
- </React.Fragment>
+ <h4>Choose a location for your pin: </h4>
+ {this._featuresFromGeocodeResults
+ .filter(feature => feature.place_name)
+ .map((feature, idx) => (
+ <div
+ // eslint-disable-next-line react/no-array-index-key
+ key={idx}
+ className="search-result-container"
+ onClick={() => {
+ this.handleSearchChange('');
+ this.addMarkerForFeature(feature);
+ }}>
+ <div className="search-result-place-name">{feature.place_name}</div>
+ </div>
+ ))}
</div>
)}
<MapProvider>
<MapboxMap
ref={this._mapRef}
mapboxAccessToken={MAPBOX_ACCESS_TOKEN}
- viewState={this.isAnimating || this.routeToAnimate ? undefined : { ...this.mapboxMapViewState, width: NumCast(this.layoutDoc._width), height: NumCast(this.layoutDoc._height) }}
+ viewState={this._isAnimating || this._routeToAnimate ? undefined : { ...this.mapboxMapViewState, width: NumCast(this.layoutDoc._width), height: NumCast(this.layoutDoc._height) }}
mapStyle={this.dataDoc.map_style ? StrCast(this.dataDoc.map_style) : 'mapbox://styles/mapbox/streets-v11'}
style={{
position: 'absolute',
@@ -1649,20 +1245,22 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
width: NumCast(this.layoutDoc._width) * parscale,
height: NumCast(this.layoutDoc._height) * parscale,
}}
- initialViewState={this.isAnimating ? undefined : this.mapboxMapViewState}
+ initialViewState={this._isAnimating ? undefined : this.mapboxMapViewState}
onZoom={this.onMapZoom}
onMove={this.onMapMove}
onClick={this.handleMapClick}
onDblClick={this.handleMapDblClick}
- terrain={this.showTerrain ? { source: 'mapbox-dem', exaggeration: 2.0 } : undefined}>
+ terrain={this._showTerrain ? { source: 'mapbox-dem', exaggeration: 2.0 } : undefined}>
<Source id="mapbox-dem" type="raster-dem" url="mapbox://mapbox.mapbox-terrain-dem-v1" tileSize={512} maxzoom={14} />
- <Source id="temporary-route" type="geojson" data={this.temporaryRouteSource} />
+ <Source id="temporary-route" type="geojson" data={this._temporaryRouteSource} />
<Source id="map-routes" type="geojson" data={this.allRoutesGeoJson} />
<Layer id="temporary-route-layer" type="line" source="temporary-route" layout={{ 'line-join': 'round', 'line-cap': 'round' }} paint={{ 'line-color': '#36454F', 'line-width': 4, 'line-dasharray': [1, 1] }} />
- {!this.isAnimating && this.animationPhase == 0 && <Layer id="map-routes-layer" type="line" source="map-routes" layout={{ 'line-join': 'round', 'line-cap': 'round' }} paint={{ 'line-color': '#FF0000', 'line-width': 4 }} />}
- {this.routeToAnimate && (this.isAnimating || this.animationPhase > 0) && (
+ {!this._isAnimating && this._animationPhase === 0 && (
+ <Layer id="map-routes-layer" type="line" source="map-routes" layout={{ 'line-join': 'round', 'line-cap': 'round' }} paint={{ 'line-color': '#FF0000', 'line-width': 4 }} />
+ )}
+ {this._routeToAnimate && (this._isAnimating || this._animationPhase > 0) && (
<>
- {!this.isStreetViewAnimation && (
+ {!this._isStreetViewAnimation && (
<>
<Source id="animated-route" type="geojson" data={this.updatedRouteCoordinates} />
<Layer
@@ -1670,7 +1268,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
type="line"
source="animated-route"
paint={{
- 'line-color': this.animationLineColor,
+ 'line-color': this._animationLineColor,
'line-width': 5,
}}
/>
@@ -1721,17 +1319,15 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
</>
)}
- <>
- {!this.isAnimating &&
- this.animationPhase == 0 &&
- this.allPushpins
- // .filter(anno => !anno.layout_unrendered)
- .map((pushpin, idx) => (
- <Marker key={idx} longitude={NumCast(pushpin.longitude)} latitude={NumCast(pushpin.latitude)} anchor="bottom" onClick={(e: MarkerEvent<mapboxgl.Marker, MouseEvent>) => this.handleMarkerClick(e, pushpin)}>
- {this.getMarkerIcon(pushpin)}
- </Marker>
- ))}
- </>
+ {!this._isAnimating &&
+ this._animationPhase === 0 &&
+ this.allPushpins // .filter(anno => !anno.layout_unrendered)
+ .map((pushpin, idx) => (
+ // eslint-disable-next-line react/no-array-index-key
+ <Marker key={idx} longitude={NumCast(pushpin.longitude)} latitude={NumCast(pushpin.latitude)} anchor="bottom" onClick={(e: MarkerEvent<mapboxgl.Marker, MouseEvent>) => this.handleMarkerClick(e, pushpin)}>
+ {this.getMarkerIcon(pushpin)}
+ </Marker>
+ ))}
{/* {this.mapMarkers.length > 0 && this.mapMarkers.map((marker, idx) => (
<Marker key={idx} longitude={marker.longitude} latitude={marker.latitude}/>
@@ -1742,12 +1338,13 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
<div className="mapBox-sidebar" style={{ width: `${this.sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
<SidebarAnnos
ref={this._sidebarRef}
+ // eslint-disable-next-line react/jsx-props-no-spreading
{...this._props}
fieldKey={this.fieldKey}
Document={this.Document}
layoutDoc={this.layoutDoc}
dataDoc={this.dataDoc}
- usePanelWidth={true}
+ usePanelWidth
showSidebar={this.SidebarShown}
nativeWidth={NumCast(this.layoutDoc._nativeWidth)}
whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
@@ -1762,3 +1359,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
);
}
}
+
+Docs.Prototypes.TemplateMap.set(DocumentType.MAP, {
+ layout: { view: MapBox, dataField: 'data' },
+ options: { acl: '', map: '', _height: 600, _width: 800, _layout_reflowHorizontal: true, _layout_reflowVertical: true, _layout_nativeDimEditable: true, systemIcon: 'BsFillPinMapFill' },
+});
diff --git a/src/client/views/nodes/MapBox/MapBox2.tsx b/src/client/views/nodes/MapBox/MapBox2.tsx
index 9825824bd..7697fd295 100644
--- a/src/client/views/nodes/MapBox/MapBox2.tsx
+++ b/src/client/views/nodes/MapBox/MapBox2.tsx
@@ -509,9 +509,9 @@
// // TODO: auto center on select a document in the sidebar
// private handleMapCenter = (map: google.maps.Map) => {
-// // console.log("print the selected views in selectionManager:")
-// // if (SelectionManager.Views.lastElement()) {
-// // console.log(SelectionManager.Views.lastElement());
+// // console.log("print the selected views in Document.Selected:")
+// // if (DocumentView.Selected().lastElement()) {
+// // console.log(DocumentView.Selected().lastElement());
// // }
// };
diff --git a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
index 6ccbbbe1c..c69cd8e89 100644
--- a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
+++ b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
@@ -32,7 +32,7 @@
// addNoteClick = (e: React.PointerEvent) => {
// setupMoveUpEvents(this, e, returnFalse, emptyFunction, e => {
// const newDoc = Docs.Create.TextDocument('Note', { _layout_autoHeight: true });
-// FormattedTextBox.SetSelectOnLoad(newDoc); // track the new text box so we can give it a prop that tells it to focus itself when it's displayed
+// Doc.SetSelectOnLoad(newDoc); // track the new text box so we can give it a prop that tells it to focus itself when it's displayed
// Doc.AddDocToList(this.props.place, 'data', newDoc);
// this._stack?.scrollToBottom();
// e.stopPropagation();
diff --git a/src/client/views/nodes/MapBox/MapPushpinBox.tsx b/src/client/views/nodes/MapBox/MapPushpinBox.tsx
index fc5b4dd18..f3dc44755 100644
--- a/src/client/views/nodes/MapBox/MapPushpinBox.tsx
+++ b/src/client/views/nodes/MapBox/MapPushpinBox.tsx
@@ -1,7 +1,9 @@
import * as React from 'react';
import { ViewBoxBaseComponent } from '../../DocComponent';
import { FieldView, FieldViewProps } from '../FieldView';
-import { MapBox } from './MapBox';
+import { MapBoxContainer } from '../MapboxMapBox/MapboxContainer';
+import { Docs } from '../../../documents/Documents';
+import { DocumentType } from '../../../documents/DocumentTypes';
/**
* Map Pushpin doc class
@@ -18,7 +20,7 @@ export class MapPushpinBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
get mapBoxView() {
- return this.DocumentView?.()?.containerViewPath?.().lastElement()?.ComponentView as MapBox;
+ return this.DocumentView?.()?.containerViewPath?.().lastElement()?.ComponentView as MapBoxContainer;
}
get mapBox() {
return this.DocumentView?.().containerViewPath?.().lastElement()?.Document;
@@ -28,3 +30,8 @@ export class MapPushpinBox extends ViewBoxBaseComponent<FieldViewProps>() {
return <div />;
}
}
+
+Docs.Prototypes.TemplateMap.set(DocumentType.PUSHPIN, {
+ layout: { view: MapPushpinBox, dataField: 'data' },
+ options: { acl: '' },
+});
diff --git a/src/client/views/nodes/MapBox/MapboxApiUtility.ts b/src/client/views/nodes/MapBox/MapboxApiUtility.ts
index 592330ac2..5c5192372 100644
--- a/src/client/views/nodes/MapBox/MapboxApiUtility.ts
+++ b/src/client/views/nodes/MapBox/MapboxApiUtility.ts
@@ -1,4 +1,3 @@
-
const MAPBOX_FORWARD_GEOCODE_BASE_URL = 'https://api.mapbox.com/geocoding/v5/mapbox.places/';
const MAPBOX_REVERSE_GEOCODE_BASE_URL = 'https://api.mapbox.com/geocoding/v5/mapbox.places/';
const MAPBOX_DIRECTIONS_BASE_URL = 'https://api.mapbox.com/directions/v5/mapbox';
@@ -7,92 +6,79 @@ const MAPBOX_ACCESS_TOKEN = 'pk.eyJ1IjoiemF1bHRhdmFuZ2FyIiwiYSI6ImNscHgwNDd1MDA3
export type TransportationType = 'driving' | 'cycling' | 'walking';
export class MapboxApiUtility {
-
static forwardGeocodeForFeatures = async (searchText: string) => {
try {
- const url = MAPBOX_FORWARD_GEOCODE_BASE_URL + encodeURI(searchText) +'.json' +`?access_token=${MAPBOX_ACCESS_TOKEN}`;
+ const url = MAPBOX_FORWARD_GEOCODE_BASE_URL + encodeURI(searchText) + `.json?access_token=${MAPBOX_ACCESS_TOKEN}`;
const response = await fetch(url);
const data = await response.json();
return data.features;
- } catch (error: any){
- // TODO: handle error in better way
+ } catch (error: any) {
+ // TODO: handle error in better way
return null;
}
- }
+ };
static reverseGeocodeForFeatures = async (longitude: number, latitude: number) => {
try {
- const url = MAPBOX_REVERSE_GEOCODE_BASE_URL + encodeURI(longitude.toString() + "," + latitude.toString()) + '.json' +
- `?access_token=${MAPBOX_ACCESS_TOKEN}`;
+ const url = MAPBOX_REVERSE_GEOCODE_BASE_URL + encodeURI(longitude.toString() + ',' + latitude.toString()) + `.json?access_token=${MAPBOX_ACCESS_TOKEN}`;
const response = await fetch(url);
const data = await response.json();
return data.features;
- } catch (error: any){
+ } catch (error: any) {
return null;
}
- }
+ };
static getDirections = async (origin: number[], destination: number[]): Promise<Record<TransportationType, any> | undefined> => {
try {
-
const directionsPromises: Promise<any>[] = [];
const transportationTypes: TransportationType[] = ['driving', 'cycling', 'walking'];
- transportationTypes.forEach((type) => {
- directionsPromises.push(
- fetch(
- `${MAPBOX_DIRECTIONS_BASE_URL}/${type}/${origin[0]},${origin[1]};${destination[0]},${destination[1]}?steps=true&geometries=geojson&access_token=${MAPBOX_ACCESS_TOKEN}`
- ).then((response) => response.json())
- );
- });
+ transportationTypes.forEach(type => {
+ directionsPromises.push(fetch(`${MAPBOX_DIRECTIONS_BASE_URL}/${type}/${origin[0]},${origin[1]};${destination[0]},${destination[1]}?steps=true&geometries=geojson&access_token=${MAPBOX_ACCESS_TOKEN}`).then(response => response.json()));
+ });
const results = await Promise.all(directionsPromises);
const routeInfoMap: Record<TransportationType, any> = {
- 'driving': {},
- 'cycling': {},
- 'walking': {},
+ driving: {},
+ cycling: {},
+ walking: {},
};
transportationTypes.forEach((type, index) => {
const routeData = results[index].routes[0];
if (routeData) {
- const geometry = routeData.geometry;
- const coordinates = geometry.coordinates;
-
- routeInfoMap[type] = {
- duration: this.secondsToMinutesHours(routeData.duration),
- distance: this.metersToMiles(routeData.distance),
- coordinates: coordinates,
- };
+ const { geometry } = routeData;
+ const { coordinates } = geometry;
+
+ routeInfoMap[type] = {
+ duration: this.secondsToMinutesHours(routeData.duration),
+ distance: this.metersToMiles(routeData.distance),
+ coordinates: coordinates,
+ };
}
- });
+ });
return routeInfoMap;
- // return current route info, and the temporary route
-
- } catch (error: any){
+ // return current route info, and the temporary route
+ } catch (error: any) {
return undefined;
- console.log("Error: ", error);
}
- }
+ };
private static secondsToMinutesHours = (seconds: number) => {
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60).toFixed(2);
- if (hours === 0){
- return `${minutes} min`
- } else {
- return `${hours} hr ${minutes} min`
+ if (hours === 0) {
+ return `${minutes} min`;
}
- }
-
- private static metersToMiles = (meters: number) => {
- return `${parseFloat((meters/1609.34).toFixed(2))} mi`;
- }
+ return `${hours} hr ${minutes} min`;
+ };
+ private static metersToMiles = (meters: number) => `${parseFloat((meters / 1609.34).toFixed(2))} mi`;
}
// const drivingQuery = await fetch(
@@ -136,4 +122,4 @@ export class MapboxApiUtility {
// distance: this.metersToMiles(routeData.distance),
// coordinates: coordinates
// }
-// }) \ No newline at end of file
+// })
diff --git a/src/client/views/nodes/MapBox/MarkerIcons.tsx b/src/client/views/nodes/MapBox/MarkerIcons.tsx
index a580fcaa0..087472112 100644
--- a/src/client/views/nodes/MapBox/MarkerIcons.tsx
+++ b/src/client/views/nodes/MapBox/MarkerIcons.tsx
@@ -17,8 +17,6 @@ import {
faHouse,
faLandmark,
faLocationDot,
- faLocationPin,
- faMapPin,
faMasksTheater,
faMugSaucer,
faPersonHiking,
@@ -65,6 +63,7 @@ export class MarkerIcons {
iconProps.color = color;
}
+ // eslint-disable-next-line react/jsx-props-no-spreading
return <FontAwesomeIcon {...iconProps} size={size} />;
}