diff options
Diffstat (limited to 'src/client/views/nodes/MapBox')
-rw-r--r-- | src/client/views/nodes/MapBox/AnimationSpeedIcons.tsx | 39 | ||||
-rw-r--r-- | src/client/views/nodes/MapBox/AnimationUtility.ts | 59 | ||||
-rw-r--r-- | src/client/views/nodes/MapBox/DirectionsAnchorMenu.tsx | 18 | ||||
-rw-r--r-- | src/client/views/nodes/MapBox/GeocoderControl.tsx | 7 | ||||
-rw-r--r-- | src/client/views/nodes/MapBox/MapAnchorMenu.tsx | 106 | ||||
-rw-r--r-- | src/client/views/nodes/MapBox/MapBox.tsx | 362 | ||||
-rw-r--r-- | src/client/views/nodes/MapBox/MapBox2.tsx | 6 | ||||
-rw-r--r-- | src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx | 2 | ||||
-rw-r--r-- | src/client/views/nodes/MapBox/MapPushpinBox.tsx | 7 | ||||
-rw-r--r-- | src/client/views/nodes/MapBox/MapboxApiUtility.ts | 76 | ||||
-rw-r--r-- | src/client/views/nodes/MapBox/MarkerIcons.tsx | 3 |
11 files changed, 342 insertions, 343 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 b73898f59..ac8010f11 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,31 +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 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 { 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 { PinDocView, PinProps } from '../../PinFuncs'; import { SidebarAnnos } from '../../SidebarAnnos'; import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm'; import { Colors } from '../../global/globalEnums'; import { DocumentView } from '../DocumentView'; -import { FieldView, FieldViewProps, FocusViewOptions } 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,9 +54,6 @@ import { MarkerIcons } from './MarkerIcons'; */ 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; @@ -111,13 +109,13 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem }; // this list contains pushpins and configs - @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 ? true : false; } //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 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')); } @@ -235,14 +233,13 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem /** * 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 => { + 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)); @@ -250,7 +247,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem 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; @@ -258,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); }; @@ -285,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() @@ -325,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> ); } @@ -354,16 +354,16 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem 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; } }, }); @@ -389,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%'; @@ -401,8 +401,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem 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; @@ -435,7 +435,9 @@ 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))); + return new Promise<Opt<DocumentView>>(res => { + DocumentView.addViewRenderedCb(doc, dv => res(dv)); + }); }; /* @@ -458,7 +460,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem 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; @@ -526,6 +528,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem document.removeEventListener('pointerdown', this.tryHideMapAnchorMenu); }; + // 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); @@ -580,6 +583,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem MapAnchorMenu.Instance.fadeOut(true); return mapRoute; } + return undefined; // TODO: Display error that can't create route to same location }, 'createmaproute'); @@ -652,9 +656,8 @@ 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; @@ -698,7 +701,7 @@ 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; @@ -834,6 +837,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem if (!this._isAnimating) { return this.mapboxMapViewState; } + return undefined; } @action @@ -917,69 +921,73 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem 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)); + 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, + }); + + console.log('Bearing: ', result.bearing); + console.log('Altitude: ', result.altitude); + } - const updateFrameId = (newFrameId: number) => this.setFrameId(newFrameId); - 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 @@ -1008,53 +1016,49 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem } }; - 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 = () => { @@ -1066,7 +1070,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem @action toggleSettings = () => { - if (!this._isAnimating && this._animationPhase == 0) { + if (!this._isAnimating && this._animationPhase === 0) { this._featuresFromGeocodeResults = []; this._settingsOpen = !this._settingsOpen; } @@ -1123,7 +1127,9 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem }; @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) => { @@ -1132,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); @@ -1146,7 +1154,6 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem 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 @@ -1154,15 +1161,12 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem onWheel={e => 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 && ( <div className="mapBox-searchbar" style={{ width: `${100 / scale}%`, zIndex: 1, position: 'relative', background: 'lightGray' }}> <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={e => this.toggleSettings()} /> + <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={e => this.toggleSettings()} /> + <IconButton icon={<FontAwesomeIcon icon={faGear as IconLookup} size="1x" />} type={Type.TERT} onClick={() => this.toggleSettings()} /> </div> </div> )} @@ -1210,22 +1214,21 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem )} {this._featuresFromGeocodeResults.length > 0 && ( <div className="mapbox-geocoding-search-results"> - <> - <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> - ))} - </> + <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> @@ -1252,7 +1255,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem <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 && ( + {!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) && ( @@ -1316,16 +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}/> @@ -1336,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} @@ -1356,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 8ebc90157..f3dc44755 100644 --- a/src/client/views/nodes/MapBox/MapPushpinBox.tsx +++ b/src/client/views/nodes/MapBox/MapPushpinBox.tsx @@ -2,6 +2,8 @@ import * as React from 'react'; import { ViewBoxBaseComponent } from '../../DocComponent'; import { FieldView, FieldViewProps } from '../FieldView'; import { MapBoxContainer } from '../MapboxMapBox/MapboxContainer'; +import { Docs } from '../../../documents/Documents'; +import { DocumentType } from '../../../documents/DocumentTypes'; /** * Map Pushpin doc class @@ -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} />; } |