diff options
author | bobzel <zzzman@gmail.com> | 2023-12-15 11:20:43 -0500 |
---|---|---|
committer | bobzel <zzzman@gmail.com> | 2023-12-15 11:20:43 -0500 |
commit | 0f2a9cce8286ca069ce7a7bf20fd05abc50acf22 (patch) | |
tree | 01938235d5a461be9a0157d50ce617669aeeee10 /src/client/views/nodes/MapBox/MapBox.tsx | |
parent | adf56d455ab0e429b7eac3430890ba7677cce8d9 (diff) | |
parent | ceb9ff8f2495bfeddb7bc0ab73fd5ddc3a6924fa (diff) |
Merge remote-tracking branch 'origin/zaul-new-branch' into moreUpgrading
Diffstat (limited to 'src/client/views/nodes/MapBox/MapBox.tsx')
-rw-r--r-- | src/client/views/nodes/MapBox/MapBox.tsx | 1228 |
1 files changed, 750 insertions, 478 deletions
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index 8b5858e28..724c1a770 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -3,66 +3,72 @@ import BingMapsReact from 'bingmaps-react'; // import 'mapbox-gl/dist/mapbox-gl.css'; import { Button, EditableText, IconButton, Size, Type } from 'browndash-components'; -import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, makeObservable, flow, toJS } from 'mobx'; +import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, flow, toJS, autorun} from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Utils, emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, setupMoveUpEvents } from '../../../../Utils'; import { Doc, DocListCast, Field, LinkedTo, Opt } from '../../../../fields/Doc'; import { DocCss, Highlight } from '../../../../fields/DocSymbols'; import { Id } from '../../../../fields/FieldSymbols'; import { Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types'; +import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../../Utils'; import { Docs, DocUtils } from '../../../documents/Documents'; import { DocumentType } from '../../../documents/DocumentTypes'; import { DocumentManager } from '../../../util/DocumentManager'; import { DragManager } from '../../../util/DragManager'; import { LinkManager } from '../../../util/LinkManager'; +import { SnappingManager } from '../../../util/SnappingManager'; import { Transform } from '../../../util/Transform'; -import { UndoManager, undoable } from '../../../util/UndoManager'; -import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocComponent'; -import { SidebarAnnos } from '../../SidebarAnnos'; +import { undoable, UndoManager } from '../../../util/UndoManager'; import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm'; +import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocComponent'; import { Colors } from '../../global/globalEnums'; +import { SidebarAnnos } from '../../SidebarAnnos'; import { DocumentView } from '../DocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; import { FormattedTextBox } from '../formattedText/FormattedTextBox'; import { PinProps, PresBox } from '../trails'; import { MapAnchorMenu } from './MapAnchorMenu'; -import { +import * as HME from "h264-mp4-encoder"; +import {simd} from 'wasm-feature-detect'; + +import { Map as MapboxMap, MapRef, - Marker, - ControlPosition, - FullscreenControl, - MapProvider, - MarkerProps, - NavigationControl, - ScaleControl, - ViewState, + Marker, + ControlPosition, + FullscreenControl, + MapProvider, + MarkerProps, + NavigationControl, + ScaleControl, + ViewState, ViewStateChangeEvent, useControl, GeolocateControl, Popup, MapEvent, Source, - Layer, -} from 'react-map-gl'; + Layer} from 'react-map-gl'; +import MapboxGeocoder, {GeocoderOptions} from '@mapbox/mapbox-gl-geocoder'; +import debounce from 'debounce'; import './MapBox.scss'; import { NumberLiteralType } from 'typescript'; // import { GeocoderControl } from './GeocoderControl'; -import mapboxgl, { LngLat, LngLatBoundsLike, MapLayerMouseEvent, MercatorCoordinate } from 'mapbox-gl!'; +import mapboxgl, { LngLat, LngLatBoundsLike, LngLatLike, MapLayerMouseEvent, MercatorCoordinate } from 'mapbox-gl'; import { Feature, FeatureCollection, GeoJsonProperties, Geometry, LineString, MultiLineString, Position } from 'geojson'; import { MarkerEvent } from 'react-map-gl/dist/esm/types'; -import { MapboxApiUtility, TransportationType } from './MapboxApiUtility'; +import { MapboxApiUtility, TransportationType} from './MapboxApiUtility'; import { Autocomplete, Checkbox, FormControlLabel, TextField } from '@mui/material'; import { List } from '../../../../fields/List'; import { listSpec } from '../../../../fields/Schema'; -import { IconLookup, faCircleXmark, faFileExport, faGear, faPause, faPlay, faRotate } from '@fortawesome/free-solid-svg-icons'; +import { IconLookup, faCircleXmark, faFileExport, faGear, faMinus, faPause, faPlay, faPlus, faRotate } from '@fortawesome/free-solid-svg-icons'; import { MarkerIcons } from './MarkerIcons'; import { SettingsManager } from '../../../util/SettingsManager'; import * as turf from '@turf/turf'; -import * as d3 from 'd3'; +import * as d3 from "d3"; import { AnimationSpeed, AnimationStatus, AnimationUtility } from './AnimationUtility'; import { fastSpeedIcon, mediumSpeedIcon, slowSpeedIcon } from './AnimationSpeedIcons'; +import { CirclePicker, ColorState } from 'react-color'; // amongus /** @@ -85,24 +91,24 @@ const MAPBOX_FORWARD_GEOCODE_BASE_URL = 'https://api.mapbox.com/geocoding/v5/map const MAPBOX_REVERSE_GEOCODE_BASE_URL = 'https://api.mapbox.com/geocoding/v5/mapbox.places/'; type PopupInfo = { - longitude: number; - latitude: number; - title: string; - description: string; -}; + longitude: number, + latitude: number, + title: string, + description: string +} -// export type GeocoderControlProps = Omit<GeocoderOptions, 'accessToken' | 'mapboxgl' | 'marker'> & { -// mapboxAccessToken: string; -// marker?: Omit<MarkerProps, 'longitude' | 'latitude'>; -// position: ControlPosition; +export type GeocoderControlProps = Omit<GeocoderOptions, 'accessToken' | 'mapboxgl' | 'marker'> & { + mapboxAccessToken: string, + marker?: Omit<MarkerProps, 'longitude' | 'latitude'>; + position: ControlPosition; -// onResult: (...args: any[]) => void; -// }; + onResult: (...args: any[]) => void; +} type MapMarker = { - longitude: number; - latitude: number; -}; + longitude: number, + latitude: number +} /** * Consider integrating later: allows for drawing, circling, making shapes on map @@ -130,13 +136,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps private _ref: React.RefObject<HTMLDivElement> = React.createRef(); private _mapRef: React.RefObject<MapRef> = React.createRef(); private _disposers: { [key: string]: IReactionDisposer } = {}; - - constructor(props: any) { - super(props); - makeObservable(this); - } - - _unmounting = false; + private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean, doc: Opt<Doc>) => void); @observable private _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>(); @computed get allSidebarDocs() { @@ -157,20 +157,23 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps 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 startIndex = Math.floor(index); const endIndex = Math.ceil(index); + let feature: Feature<Geometry, GeoJsonProperties>; + let geometry: LineString; if (startIndex === endIndex) { // AnimationPhase is at a whole number (no interpolation needed) const coordinates = [originalCoordinates[startIndex]]; - const geometry: LineString = { + geometry = { type: 'LineString', coordinates, }; - return { + feature = { type: 'Feature', properties: { - routeTitle: StrCast(this.routeToAnimate.title), + 'routeTitle': StrCast(this.routeToAnimate.title) }, geometry: geometry, }; @@ -180,36 +183,55 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps const endCoord = originalCoordinates[endIndex]; const fraction = index - startIndex; - // Interpolate the coordinates - const interpolatedCoord = [startCoord[0] + fraction * (endCoord[0] - startCoord[0]), startCoord[1] + fraction * (endCoord[1] - startCoord[1])]; + const interpolator = d3.interpolateArray(startCoord, endCoord); + const interpolatedCoord = interpolator(fraction); + const coordinates = originalCoordinates.slice(0, startIndex + 1).concat([interpolatedCoord]); - const geometry: LineString = { + geometry = { type: 'LineString', coordinates, }; - return { + feature = { type: 'Feature', properties: { - routeTitle: StrCast(this.routeToAnimate.title), + 'routeTitle': StrCast(this.routeToAnimate.title) }, geometry: geometry, }; } + + autorun(() => { + const animationUtil = this.animationUtility; + const concattedCoordinates = geometry.coordinates.concat(originalCoordinates.slice(endIndex)); + const newFeature: Feature<LineString, turf.Properties> = { + type: 'Feature', + properties: {}, + geometry: { + type: 'LineString', + coordinates: concattedCoordinates + } + } + if (animationUtil){ + animationUtil.setPath(newFeature) + } + }) + return feature; } + console.log("ERROR"); return { type: 'Feature', properties: {}, geometry: { type: 'LineString', - coordinates: [], + coordinates: [] }, }; } @computed get selectedRouteCoordinates(): Position[] { let coordinates: Position[] = []; - if (this.routeToAnimate?.routeCoordinates) { + if (this.routeToAnimate?.routeCoordinates){ coordinates = JSON.parse(StrCast(this.routeToAnimate.routeCoordinates)); } return coordinates; @@ -225,8 +247,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps return { type: 'Feature', properties: { - routeTitle: routeDoc.title, - }, + 'routeTitle': routeDoc.title}, geometry: geometry, }; }); @@ -244,7 +265,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps return StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%'); } @computed get sidebarColor() { - return StrCast(this.layoutDoc.sidebar_color, StrCast(this.layoutDoc[this._props.fieldKey + '_backgroundColor'], '#e4e4e4')); + return StrCast(this.layoutDoc.sidebar_color, StrCast(this.layoutDoc[this.props.fieldKey + '_backgroundColor'], '#e4e4e4')); } @computed get SidebarKey() { return this.fieldKey + '_sidebar'; @@ -252,9 +273,12 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps componentDidMount() { this._unmounting = false; - this._props.setContentView?.(this); + this.props.setContentView?.(this); + } + + _unmounting = false; componentWillUnmount(): void { this._unmounting = true; this.deselectPinOrRoute(); @@ -316,9 +340,9 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps e, (e, down, delta) => runInAction(() => { - const localDelta = this._props + const localDelta = this.props .ScreenToLocalTransform() - .scale(this._props.NativeDimScaling?.() || 1) + .scale(this.props.NativeDimScaling?.() || 1) .transformDirection(delta[0], delta[1]); const fullWidth = NumCast(this.layoutDoc._width); const mapWidth = fullWidth - this.sidebarWidth(); @@ -337,7 +361,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps () => UndoManager.RunInBatch(this.toggleSidebar, 'toggle sidebar map') ); }; - sidebarWidth = () => (Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100) * this._props.PanelWidth(); + sidebarWidth = () => (Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100) * this.props.PanelWidth(); /** * Handles toggle of sidebar on click the little comment button @@ -349,8 +373,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps key="sidebar" title="Toggle Sidebar" style={{ - display: !this._props.isContentActive() ? 'none' : undefined, - top: StrCast(this.layoutDoc._layout_showTitle) === 'title' ? 20 : 5, + display: !this.props.isContentActive() ? 'none' : undefined, + top: StrCast(this.rootDoc._layout_showTitle) === 'title' ? 20 : 5, backgroundColor: this.SidebarShown ? Colors.MEDIUM_BLUE : Colors.BLACK, }} onPointerDown={this.sidebarBtnDown}> @@ -382,16 +406,16 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps }); const targetCreator = (annotationOn: Doc | undefined) => { - const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, undefined, annotationOn, undefined, 'yellow'); - FormattedTextBox.SetSelectOnLoad(target); + const target = DocUtils.GetNewTextDoc('Note linked to ' + this.rootDoc.title, 0, 0, 100, 100, undefined, annotationOn, undefined, 'yellow'); + FormattedTextBox.SelectOnLoad = target[Id]; return target; }; - const docView = this._props.DocumentView?.(); + const docView = this.props.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.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.props.Document; e.annoDragData.linkSourceDoc.followLinkZoom = false; } }, @@ -426,17 +450,19 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps 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'); + 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._props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop)); - transparentFilter = () => [...this._props.childFilters(), Utils.TransparentBackgroundFilter]; - opaqueFilter = () => [...this._props.childFilters(), Utils.OpaqueBackgroundFilter]; - infoWidth = () => this._props.PanelWidth() / 5; - infoHeight = () => this._props.PanelHeight() / 5; + panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1) - this.sidebarWidth(); + panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1); + scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop)); + transparentFilter = () => [...this.props.childFilters(), Utils.TransparentBackgroundFilter]; + opaqueFilter = () => [...this.props.childFilters(), Utils.OpaqueBackgroundFilter]; + infoWidth = () => this.props.PanelWidth() / 5; + infoHeight = () => this.props.PanelHeight() / 5; anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick; savedAnnotations = () => this._savedAnnotations; @@ -474,7 +500,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps }; @observable - bingSearchBarContents: any = this.dataDoc.map; // For Bing Maps: The contents of the Bing search bar (string) + bingSearchBarContents: any = this.rootDoc.map; // For Bing Maps: The contents of the Bing search bar (string) geoDataRequestOptions = { entityType: 'PopulatedPlace', @@ -483,13 +509,15 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps // The pin that is selected @observable selectedPinOrRoute: Doc | undefined; + @action deselectPinOrRoute = () => { if (this.selectedPinOrRoute) { // // Removes filter - // Doc.setDocFilter(this.Document, 'latitude', this.selectedPin.latitude, 'remove'); - // Doc.setDocFilter(this.Document, 'longitude', this.selectedPin.longitude, 'remove'); - // Doc.setDocFilter(this.Document, LinkedTo, `mapPin=${Field.toScriptString(DocCast(this.selectedPin))}`, 'remove'); + // Doc.setDocFilter(this.rootDoc, 'latitude', this.selectedPin.latitude, 'remove'); + // Doc.setDocFilter(this.rootDoc, 'longitude', this.selectedPin.longitude, 'remove'); + // Doc.setDocFilter(this.rootDoc, LinkedTo, `mapPin=${Field.toScriptString(DocCast(this.selectedPin))}`, 'remove'); + // const temp = this.selectedPin; // if (!this._unmounting) { // this._bingMap.current.entities.remove(this.map_docToPinMap.get(temp)); @@ -501,10 +529,11 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps // } // this.map_docToPinMap.set(temp, newpin); // this.selectedPin = undefined; - // this.bingSearchBarContents = this.Document.map; + // this.bingSearchBarContents = this.rootDoc.map; } }; + getView = async (doc: Doc) => { if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) this.toggleSidebar(); return new Promise<Opt<DocumentView>>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv))); @@ -518,9 +547,9 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps 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.rootDoc, 'latitude', this.selectedPin.latitude, 'match'); + // Doc.setDocFilter(this.rootDoc, 'longitude', this.selectedPin.longitude, 'match'); + Doc.setDocFilter(this.rootDoc, LinkedTo, `mapPin=${Field.toScriptString(this.selectedPinOrRoute)}`, 'check'); this.recolorPin(this.selectedPinOrRoute, 'green'); @@ -530,9 +559,9 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps 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._props.ScreenToLocalTransform().inverse().transformPoint(x, y); + const x = point.x + (this.props.PanelWidth() - this.sidebarWidth()) / 2; + const y = point.y + this.props.PanelHeight() / 2 + 32; + const cpt = this.props.ScreenToLocalTransform().inverse().transformPoint(x, y); MapAnchorMenu.Instance.jumpTo(cpt[0], cpt[1], true); document.addEventListener('pointerdown', this.tryHideMapAnchorMenu, true); @@ -543,7 +572,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps */ @action mapOnClick = (e: { location: { latitude: any; longitude: any } }) => { - this._props.select(false); + this.props.select(false); this.deselectPinOrRoute(); }; /* @@ -586,28 +615,27 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps /* * Returns doc w/ relevant info */ - getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps, existingPin?: Doc) => { /// 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', + title: 'MapAnchor:' + this.rootDoc.title, + text: StrCast(this.selectedPinOrRoute?.map) || StrCast(this.rootDoc.map) || 'map location', config_latitude: NumCast((existingPin ?? this.selectedPinOrRoute)?.latitude ?? this.dataDoc.latitude), config_longitude: NumCast((existingPin ?? this.selectedPinOrRoute)?.longitude ?? this.dataDoc.longitude), config_map_zoom: NumCast(this.dataDoc.map_zoom), - config_map_type: StrCast(this.dataDoc.map_type), + // config_map_type: StrCast(this.dataDoc.map_type), config_map: StrCast((existingPin ?? this.selectedPinOrRoute)?.map) || StrCast(this.dataDoc.map), layout_unrendered: true, mapPin: existingPin ?? this.selectedPinOrRoute, - annotationOn: this.Document, + annotationOn: this.rootDoc, }); if (anchor) { if (!addAsAnnotation) anchor.backgroundColor = 'transparent'; addAsAnnotation && this.addDocument(anchor); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), map: true } }, this.Document); + PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), map: true } }, this.rootDoc); return anchor; } - return this.Document; + return this.rootDoc; }; map_docToPinMap = new Map<Doc, any>(); @@ -654,9 +682,9 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps deleteSelectedPinOrRoute = undoable(() => { 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.rootDoc, 'latitude', this.selectedPinOrRoute.latitude, 'remove'); + Doc.setDocFilter(this.rootDoc, 'longitude', this.selectedPinOrRoute.longitude, 'remove'); + Doc.setDocFilter(this.rootDoc, LinkedTo, `mapPin=${Field.toScriptString(DocCast(this.selectedPinOrRoute))}`, 'remove'); this.removePushpinOrRoute(this.selectedPinOrRoute); } @@ -664,6 +692,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps document.removeEventListener('pointerdown', this.tryHideMapAnchorMenu, true); }, 'delete pin'); + + tryHideMapAnchorMenu = (e: PointerEvent) => { let target = document.elementFromPoint(e.x, e.y); while (target) { @@ -681,8 +711,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps centerOnSelectedPin = () => { 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) { // this.dataDoc.latitude = this.selectedPin.latitude; @@ -703,6 +733,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps mapTypeId: 'grayscale', }; + /** * Map options */ @@ -721,6 +752,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps }, }; + + recolorPin = (pin: Doc, color?: string) => { // this._bingMap.current.entities.remove(this.map_docToPinMap.get(pin)); // this.map_docToPinMap.delete(pin); @@ -735,7 +768,6 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps * Initializes starting values */ @observable _mapReady = false; - @action bingMapReady = (map: any) => { this._mapReady = true; @@ -748,7 +780,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'maptypechanged', undoable(this.updateMapType, 'Map ViewType Change')); this._disposers.mapLocation = reaction( - () => this.dataDoc.map, + () => this.rootDoc.map, mapLoc => (this.bingSearchBarContents = mapLoc), { fireImmediately: true } ); @@ -773,7 +805,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps ); this._disposers.location = reaction( - () => ({ lat: this.dataDoc.latitude, lng: this.dataDoc.longitude, zoom: this.dataDoc.map_zoom, mapType: this.dataDoc.map_type }), + () => ({ lat: this.rootDoc.latitude, lng: this.rootDoc.longitude, zoom: this.rootDoc.map_zoom, mapType: this.rootDoc.map_type }), locationObject => { // if (this._bingMap.current) try { @@ -797,27 +829,25 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps setupMoveUpEvents( e, e, - e => { - // move event + e => { // move event if (!dragClone) { - dragClone = this._dragRef.current?.cloneNode(true) as HTMLDivElement; // copy draggable pin + 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 + 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 + 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._props.ScreenToLocalTransform().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; + if (target === this._ref.current) { + const cpt = this.props.ScreenToLocalTransform().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; @@ -826,7 +856,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps } }, e => { - const createPin = () => this.createPushpin(this.dataDoc.latitude, this.dataDoc.longitude, this.dataDoc.map); + const createPin = () => this.createPushpin(this.rootDoc.latitude, this.rootDoc.longitude, this.rootDoc.map); if (this.bingSearchBarContents) { this.bingSearch().then(createPin); } else createPin(); @@ -834,7 +864,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps ); }; - // incrementer: number = 0; + // incrementer: number = 0; /* * Creates Pushpin doc and adds it to the list of annotations */ @@ -847,13 +877,13 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps false, [], { - title: location ?? `lat=${NumCast(latitude)},lng=${NumCast(longitude)}`, - map: location, - description: '', + title: location ?? `lat=${NumCast(latitude)},lng=${NumCast(longitude)}`, + map: location, + description: "", wikiData: wikiData, markerType: 'MAP_PIN', - markerColor: '#ff5722', - } + markerColor: '#ff5722' + }, // { title: map ?? `lat=${latitude},lng=${longitude}`, map: map }, // ,'pushpinIDamongus'+ this.incrementer++ ); @@ -866,7 +896,11 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps @action createMapRoute = undoable((coordinates: Position[], origin: string, destination: any, createPinForDestination: boolean) => { - const mapRoute = Docs.Create.MapRouteDocument(false, [], { title: `${origin} --> ${destination.place_name}`, routeCoordinates: JSON.stringify(coordinates) }); + const mapRoute = Docs.Create.MapRouteDocument( + false, + [], + {title: `${origin} --> ${destination.place_name}`, routeCoordinates: JSON.stringify(coordinates)}, + ); this.addDocument(mapRoute, this.annotationKey); if (createPinForDestination) { this.createPushpin(destination.center[1], destination.center[0], destination.place_name); @@ -878,29 +912,43 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps searchbarKeyDown = (e: any) => e.key === 'Enter' && this.bingSearch(); + + + + + @observable featuresFromGeocodeResults: any[] = []; + @action addMarkerForFeature = (feature: any) => { const location = feature.place_name; - if (feature.center) { + if (feature.center){ const longitude = feature.center[0]; const latitude = feature.center[1]; const wikiData = feature.properties?.wikiData; - - this.createPushpin(latitude, longitude, location, wikiData); - - if (this._mapRef.current) { + + this.createPushpin( + latitude, + longitude, + location, + wikiData + ) + + if (this._mapRef.current){ this._mapRef.current.flyTo({ - center: feature.center, + center: feature.center }); } this.featuresFromGeocodeResults = []; + } else { // TODO: handle error } - }; + } + + /** * Makes a forward geocoding API call to Mapbox to retrieve locations based on the search input @@ -908,12 +956,12 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps */ handleSearchChange = async (searchText: string) => { const features = await MapboxApiUtility.forwardGeocodeForFeatures(searchText); - if (features && !this.isAnimating) { + if (features && !this.isAnimating){ runInAction(() => { - this.settingsOpen = false; + this.settingsOpen= false; this.featuresFromGeocodeResults = features; this.routeToAnimate = undefined; - }); + }) } // try { // const url = MAPBOX_FORWARD_GEOCODE_BASE_URL + encodeURI(searchText) +'.json' +`?access_token=${MAPBOX_ACCESS_TOKEN}`; @@ -923,31 +971,34 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps // this.featuresFromGeocodeResults = data.features; // }) // } catch (error: any){ - // // TODO: handle error in better way + // // TODO: handle error in better way // console.log(error); // } - }; + } // @action // debouncedCall = React.useCallback(debounce(this.debouncedOnSearchBarChange, 300), []); + @action handleMapClick = (e: MapLayerMouseEvent) => { - if (this._mapRef.current) { - const features = this._mapRef.current.queryRenderedFeatures(e.point, { - layers: ['map-routes-layer'], - }); + if (this._mapRef.current){ + const features = this._mapRef.current.queryRenderedFeatures( + e.point, { + layers: ['map-routes-layer'] + } + ); console.error(features); if (features && features.length > 0 && features[0].properties && features[0].geometry) { const geometry = features[0].geometry as LineString; const routeTitle: string = features[0].properties['routeTitle']; - const routeDoc: Doc | undefined = this.allRoutes.find(routeDoc => routeDoc.title === routeTitle); + const routeDoc: Doc | undefined = this.allRoutes.find((routeDoc) => routeDoc.title === routeTitle); this.deselectPinOrRoute(); // TODO: Also deselect route if selected - if (routeDoc) { + if (routeDoc){ this.selectedPinOrRoute = routeDoc; - Doc.setDocFilter(this.Document, LinkedTo, `mapRoute=${Field.toScriptString(this.selectedPinOrRoute)}`, 'check'); + Doc.setDocFilter(this.rootDoc, LinkedTo, `mapRoute=${Field.toScriptString(this.selectedPinOrRoute)}`, 'check'); - // TODO: Recolor route + // TODO: Recolor route MapAnchorMenu.Instance.Delete = this.deleteSelectedPinOrRoute; MapAnchorMenu.Instance.Center = this.centerOnSelectedPin; @@ -957,7 +1008,9 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps MapAnchorMenu.Instance.setRouteDoc(routeDoc); // TODO: Subject to change - MapAnchorMenu.Instance.setAllMapboxPins(this.allAnnotations.filter(anno => !anno.layout_unrendered)); + MapAnchorMenu.Instance.setAllMapboxPins( + this.allAnnotations.filter(anno => !anno.layout_unrendered) + ) MapAnchorMenu.Instance.DisplayRoute = this.displayRoute; MapAnchorMenu.Instance.HideRoute = this.hideRoute; @@ -972,15 +1025,16 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps MapAnchorMenu.Instance.jumpTo(e.originalEvent.clientX, e.originalEvent.clientY, true); document.addEventListener('pointerdown', this.tryHideMapAnchorMenu, true); - } + } } } - }; + } + /** * Makes a reverse geocoding API call to retrieve features corresponding to a map click (based on longitude - * and latitude). Sets the search results accordingly. - * @param e + * and latitude). Sets the search results accordingly. + * @param e */ handleMapDblClick = async (e: MapLayerMouseEvent) => { e.preventDefault(); @@ -989,13 +1043,13 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps const latitude: number = lngLat.lat; const features = await MapboxApiUtility.reverseGeocodeForFeatures(longitude, latitude); - if (features) { + if (features){ runInAction(() => { this.featuresFromGeocodeResults = features; - }); + }) } - // // REVERSE GEOCODE TO GET LOCATION DETAILS + // // REVERSE GEOCODE TO GET LOCATION DETAILS // try { // const url = MAPBOX_REVERSE_GEOCODE_BASE_URL + encodeURI(longitude.toString() + "," + latitude.toString()) + '.json' + // `?access_token=${MAPBOX_ACCESS_TOKEN}`; @@ -1009,9 +1063,9 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps // // TODO: handle error in better way // console.log(error); // } - }; + } - @observable + @observable currentPopup: PopupInfo | undefined = undefined; @action @@ -1021,20 +1075,23 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps 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.rootDoc, 'latitude', this.selectedPin.latitude, 'match'); + // Doc.setDocFilter(this.rootDoc, 'longitude', this.selectedPin.longitude, 'match'); + Doc.setDocFilter(this.rootDoc, LinkedTo, `mapPin=${Field.toScriptString(this.selectedPinOrRoute)}`, 'check'); this.recolorPin(this.selectedPinOrRoute, 'green'); // TODO: check this method - + + MapAnchorMenu.Instance.Delete = this.deleteSelectedPinOrRoute; MapAnchorMenu.Instance.Center = this.centerOnSelectedPin; MapAnchorMenu.Instance.OnClick = this.createNoteAnnotation; MapAnchorMenu.Instance.StartDrag = this.startAnchorDrag; - // pass in the pinDoc + // pass in the pinDoc MapAnchorMenu.Instance.setPinDoc(pinDoc); - MapAnchorMenu.Instance.setAllMapboxPins(this.allAnnotations.filter(anno => !anno.layout_unrendered)); + MapAnchorMenu.Instance.setAllMapboxPins( + this.allAnnotations.filter(anno => !anno.layout_unrendered) + ) MapAnchorMenu.Instance.DisplayRoute = this.displayRoute; MapAnchorMenu.Instance.HideRoute = this.hideRoute; @@ -1043,20 +1100,28 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps MapAnchorMenu.Instance.setMenuType('standard'); + // MapAnchorMenu.Instance.jumpTo(NumCast(pinDoc.longitude), NumCast(pinDoc.latitude)-3, true); + MapAnchorMenu.Instance.jumpTo(e.originalEvent.clientX, e.originalEvent.clientY, true); document.addEventListener('pointerdown', this.tryHideMapAnchorMenu, true); + + + // this._mapRef.current.flyTo({ + // center: [NumCast(pinDoc.longitude), NumCast(pinDoc.latitude)-3] + // }) + }; @observable temporaryRouteSource: FeatureCollection = { type: 'FeatureCollection', - features: [], - }; + features: [] + } @action displayRoute = (routeInfoMap: Record<TransportationType, any> | undefined, type: TransportationType) => { - if (routeInfoMap) { + if (routeInfoMap){ const newTempRouteSource: FeatureCollection = { type: 'FeatureCollection', features: [ @@ -1065,30 +1130,27 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps properties: {}, geometry: { type: 'LineString', - coordinates: routeInfoMap[type].coordinates, - }, - }, - ], - }; - // TODO: Create pin for destination - // TODO: Fly to point where full route will be shown + coordinates: routeInfoMap[type].coordinates + } + } + ] + } + // TODO: Create pin for destination + // TODO: Fly to point where full route will be shown this.temporaryRouteSource = newTempRouteSource; } - }; + } @observable isAnimating: boolean = false; @observable - isPaused: boolean = false; - - @observable routeToAnimate: Doc | undefined = undefined; - @observable + @observable animationPhase: number = 0; - @observable + @observable finishedFlyTo: boolean = false; @action @@ -1096,103 +1158,144 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps this.animationPhase = newValue; }; - @observable + @observable frameId: number | null = null; @action setFrameId = (frameId: number) => { this.frameId = frameId; - }; + } + + @observable + animationUtility: AnimationUtility | null = null; + + @action + setAnimationUtility = (util: AnimationUtility) => { + this.animationUtility = util; + } @action openAnimationPanel = (routeDoc: Doc | undefined) => { - if (routeDoc) { + if (routeDoc){ MapAnchorMenu.Instance.fadeOut(true); document.removeEventListener('pointerdown', this.tryHideMapAnchorMenu, true); this.routeToAnimate = routeDoc; } - }; + } @observable - animationDuration = 40000; + mapboxMapViewState: ViewState = { + zoom: this.dataDoc.map_zoom ? NumCast(this.dataDoc.map_zoom) : 8, + longitude: this.dataDoc.longitude ? NumCast(this.dataDoc.longitude) : -71.4128, + latitude: this.dataDoc.latitude ? NumCast(this.dataDoc.latitude) : 41.8240, + pitch: this.dataDoc.map_pitch ? NumCast(this.dataDoc.map_pitch) : 0, + bearing: this.dataDoc.map_bearing ? NumCast(this.dataDoc.map_bearing) : 0, + padding: { + top: 0, + bottom: 0, + left: 0, + right: 0 + }, + } - @observable - animationAltitude = 12800; + @computed + get preAnimationViewState() { + if (!this.isAnimating){ + return this.mapboxMapViewState; + } + } - @observable - pathDistance = 0; - @observable + @observable isStreetViewAnimation: boolean = false; - @observable + @observable animationSpeed: AnimationSpeed = AnimationSpeed.MEDIUM; + + @observable + animationLineColor: string = '#ffff00'; + + @action + setAnimationLineColor = (color: ColorState) => { + this.animationLineColor = color.hex; + } + @action updateAnimationSpeed = () => { - switch (this.animationSpeed) { + let newAnimationSpeed: AnimationSpeed; + switch (this.animationSpeed){ case AnimationSpeed.SLOW: - this.animationSpeed = AnimationSpeed.MEDIUM; + newAnimationSpeed = AnimationSpeed.MEDIUM; break; case AnimationSpeed.MEDIUM: - this.animationSpeed = AnimationSpeed.FAST; + newAnimationSpeed = AnimationSpeed.FAST; break; case AnimationSpeed.FAST: - this.animationSpeed = AnimationSpeed.SLOW; + newAnimationSpeed = AnimationSpeed.SLOW; break; default: - this.animationSpeed = AnimationSpeed.MEDIUM; + newAnimationSpeed = AnimationSpeed.MEDIUM; break; } - }; + 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'; + case AnimationSpeed.SLOW: + return '1x speed'; + case AnimationSpeed.MEDIUM: + return '2x speed'; + case AnimationSpeed.FAST: + return '3x speed'; + default: + return '2x speed'; } } - @computed get animationSpeedIcon(): JSX.Element { + @computed get animationSpeedIcon(): JSX.Element{ switch (this.animationSpeed) { case AnimationSpeed.SLOW: - return slowSpeedIcon; + return slowSpeedIcon; case AnimationSpeed.MEDIUM: - return mediumSpeedIcon; + return mediumSpeedIcon; case AnimationSpeed.FAST: - return fastSpeedIcon; + return fastSpeedIcon; default: - return mediumSpeedIcon; - } + return mediumSpeedIcon; + } } @action toggleIsStreetViewAnimation = () => { - this.isStreetViewAnimation = !this.isStreetViewAnimation; - }; + const newVal = !this.isStreetViewAnimation; + this.isStreetViewAnimation = newVal; + if (this.animationUtility){ + this.animationUtility.updateIsStreetViewAnimation(newVal) + } + } - @observable + @observable dynamicRouteFeature: Feature<Geometry, GeoJsonProperties> = { type: 'Feature', properties: {}, geometry: { type: 'LineString', - coordinates: [], - }, + coordinates: [] + } }; - @observable + + @observable path: turf.helpers.Feature<turf.helpers.LineString, turf.helpers.Properties> = { type: 'Feature', geometry: { type: 'LineString', - coordinates: [], + coordinates: [] }, - properties: {}, + properties: {} }; getFeatureFromRouteDoc = (routeDoc: Doc): Feature<Geometry, GeoJsonProperties> => { @@ -1203,137 +1306,157 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps return { type: 'Feature', properties: { - routeTitle: routeDoc.title, - }, + 'routeTitle': routeDoc.title}, geometry: geometry, }; - }; + } - @action + @action playAnimation = (status: AnimationStatus) => { - if (!this._mapRef.current || !this.routeToAnimate) { + if (!this._mapRef.current || !this.routeToAnimate){ return; } - if (this.isAnimating) { - return; - } this.animationPhase = status === AnimationStatus.RESUME ? this.animationPhase : 0; this.frameId = AnimationStatus.RESUME ? this.frameId : null; this.finishedFlyTo = AnimationStatus.RESUME ? this.finishedFlyTo : false; const path = turf.lineString(this.selectedRouteCoordinates); - + this.settingsOpen = false; this.path = path; - this.pathDistance = turf.lineDistance(path); this.isAnimating = true; + runInAction(() => { - return new Promise<void>(async resolve => { - let animationUtil; - try { - const targetLngLat = { - lng: this.selectedRouteCoordinates[0][0], - lat: this.selectedRouteCoordinates[0][1], - }; - - animationUtil = new AnimationUtility(targetLngLat, this.selectedRouteCoordinates, this.isStreetViewAnimation, this.animationSpeed); - - const updateFrameId = (newFrameId: number) => { - this.setFrameId(newFrameId); - }; - - const updateAnimationPhase = (newAnimationPhase: number) => { - this.setAnimationPhase(newAnimationPhase); - }; - - if (status !== AnimationStatus.RESUME) { - const result = await animationUtil.flyInAndRotate({ - map: this._mapRef.current!, - // targetLngLat, - // duration 3000 - // startAltitude: 3000000, - // endAltitude: this.isStreetViewAnimation ? 80 : 12000, - // startBearing: 0, - // endBearing: -20, - // startPitch: 40, - // endPitch: this.isStreetViewAnimation ? 80 : 50, - updateFrameId, - }); + return new Promise<void>(async (resolve) => { + const targetLngLat = { + lng: this.selectedRouteCoordinates[0][0], + lat: this.selectedRouteCoordinates[0][1], + }; - console.log('Bearing: ', result.bearing); - console.log('Altitude: ', result.altitude); - } + const animationUtil = new AnimationUtility( + targetLngLat, + this.selectedRouteCoordinates, + this.isStreetViewAnimation, + this.animationSpeed, + this.showTerrain, + this._mapRef.current + ); + runInAction(() => { + this.setAnimationUtility(animationUtil); + }) - 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({ + 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!, - // path: this.path, - // startBearing: -20, - // startAltitude: this.isStreetViewAnimation ? 80 : 12000, - // pitch: this.isStreetViewAnimation ? 80: 50, - currentAnimationPhase: this.animationPhase, - updateAnimationPhase, + // targetLngLat, + // duration 3000 + // startAltitude: 3000000, + // endAltitude: this.isStreetViewAnimation ? 80 : 12000, + // startBearing: 0, + // endBearing: -20, + // startPitch: 40, + // endPitch: this.isStreetViewAnimation ? 80 : 50, updateFrameId, }); - // get the bounds of the linestring, use fitBounds() to animate to a final view - const bbox3d = turf.bbox(this.path); + console.log("Bearing: ", result.bearing); + console.log("Altitude: ", result.altitude); - const bbox2d: LngLatBoundsLike = [bbox3d[0], bbox3d[1], bbox3d[2], bbox3d[3]]; + } - this._mapRef.current!.fitBounds(bbox2d, { - duration: 3000, - pitch: 30, - bearing: 0, - padding: 120, - }); - - setTimeout(() => { - resolve(); - }, 10000); - } catch (error: any) { - console.log(error); - console.log('animation util: ', animationUtil); - } + runInAction(() => { + this.finishedFlyTo = true; + }) + + // follow the path while slowly rotating the camera, passing in the camera bearing and altitude from the previous animation + await animationUtil.animatePath({ + map: this._mapRef.current!, + // path: this.path, + // startBearing: -20, + // startAltitude: this.isStreetViewAnimation ? 80 : 12000, + // pitch: this.isStreetViewAnimation ? 80: 50, + currentAnimationPhase: this.animationPhase, + updateAnimationPhase, + updateFrameId, + }); + + // get the bounds of the linestring, use fitBounds() to animate to a final view + const bbox3d = turf.bbox(this.path); + + const bbox2d: LngLatBoundsLike = [bbox3d[0], bbox3d[1], bbox3d[2], bbox3d[3]]; + + this._mapRef.current!.fitBounds(bbox2d, { + duration: 3000, + pitch: 30, + bearing: 0, + padding: 120, + }); + + setTimeout(() => { + this.isStreetViewAnimation = false; + resolve(); + }, 10000); }); - }); - }; + + }) + - @action + } + + + @action pauseAnimation = () => { - if (this.frameId && this.animationPhase > 0) { + if (this.frameId && this.animationPhase > 0){ window.cancelAnimationFrame(this.frameId); this.frameId = null; this.isAnimating = false; } - }; + } @action - stopAndCloseAnimation = () => { - if (this.frameId) { + stopAnimation = (close: boolean) => { + if (this.frameId){ window.cancelAnimationFrame(this.frameId); - this.frameId = null; - this.finishedFlyTo = false; - this.isAnimating = false; - this.animationPhase = 0; + } + 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.selectedRouteCoordinates = []; + this.animationUtility = null; } - // reset bearing and pitch to original, zoom out - }; + if (this.preAnimationViewState){ + this.mapboxMapViewState = this.preAnimationViewState; + } + + + } @action - exportAnimationToVideo = () => {}; + exportAnimationToVideo = () => { + + } getRouteAnimationOptions = (): JSX.Element => { return ( <> - <IconButton + <IconButton tooltip={this.isAnimating && this.finishedFlyTo ? 'Pause Animation' : 'Play Animation'} onPointerDown={() => { if (this.isAnimating && this.finishedFlyTo) { @@ -1344,60 +1467,90 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps 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" + icon={this.isAnimating && this.finishedFlyTo ? + <FontAwesomeIcon icon={faPause as IconLookup}/> + : + <FontAwesomeIcon icon={faPlay as IconLookup}/> + } + color='black' size={Size.MEDIUM} /> - {this.isAnimating && this.finishedFlyTo && ( - <IconButton tooltip="Restart animation" onPointerDown={() => this.playAnimation(AnimationStatus.RESTART)} icon={<FontAwesomeIcon icon={faRotate as IconLookup} />} color="black" size={Size.MEDIUM} /> - )} - <IconButton tooltip="Stop and close animation" onPointerDown={this.stopAndCloseAnimation} icon={<FontAwesomeIcon icon={faCircleXmark as IconLookup} />} color="black" size={Size.MEDIUM} /> - <IconButton style={{ marginRight: '10px' }} tooltip="Export to video" onPointerDown={this.exportAnimationToVideo} icon={<FontAwesomeIcon icon={faFileExport as IconLookup} />} color="black" size={Size.MEDIUM} /> - {!this.isAnimating && ( - <> - <div className="animation-suboptions"> - <div>|</div> - <FormControlLabel label="Street view animation" labelPlacement="start" control={<Checkbox color="success" checked={this.isStreetViewAnimation} onChange={this.toggleIsStreetViewAnimation} />} /> - <div id="last-divider">|</div> - <IconButton tooltip={this.animationSpeedTooltipText} onPointerDown={this.updateAnimationSpeed} icon={this.animationSpeedIcon} size={Size.MEDIUM} /> - </div> - </> - )} + {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' + style={{width: '130px'}} + 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={{width: '230px'}}>Select Line Color: </div> + <CirclePicker + circleSize={12} + circleSpacing={5} + width='100%' + colors={['#ffff00', '#03a9f4', '#ff0000', '#ff5722', '#000000', '#673ab7']} + onChange={(color) => this.setAnimationLineColor(color)} + /> + </div> + </> </> - ); - }; + ) + } @action hideRoute = () => { this.temporaryRouteSource = { type: 'FeatureCollection', - features: [], - }; - }; + features: [] + } + } - @observable - mapboxMapViewState: ViewState = { - zoom: 9, - longitude: -71.45, - latitude: 41.82, - pitch: 0, - bearing: 0, - padding: { - top: 0, - bottom: 0, - left: 0, - right: 0, - }, - }; - @observable + @observable settingsOpen: boolean = false; - @observable - mapStyle: string = 'mapbox://styles/mapbox/streets-v12'; + @observable + mapStyle: string = 'mapbox://styles/mapbox/streets-v12' @observable - showTerrain: boolean = false; + showTerrain: boolean = true; @action toggleSettings = () => { @@ -1405,51 +1558,103 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps this.featuresFromGeocodeResults = []; this.settingsOpen = !this.settingsOpen; } - }; + } @action changeMapStyle = (e: React.ChangeEvent<HTMLSelectElement>) => { - this.mapStyle = `mapbox://styles/mapbox/${e.target.value}`; - }; + this.dataDoc.map_style = `mapbox://styles/mapbox/${e.target.value}`; + // this.mapStyle = `mapbox://styles/mapbox/${e.target.value}` + } - @action - onMapMove = (e: ViewStateChangeEvent) => { - this.mapboxMapViewState = e.viewState; - }; + @action + onBearingChange = (e: React.ChangeEvent<HTMLInputElement>) => { + const bearing = parseInt(e.target.value); + if (!isNaN(bearing) && this._mapRef.current){ + const fixedBearing = Math.max(0, Math.min(360, bearing)); + this._mapRef.current.setBearing(fixedBearing); + this.dataDoc.map_bearing = fixedBearing; + this.mapboxMapViewState = { + ...this.mapboxMapViewState, + bearing: fixedBearing + } + } + } - @action - toggleShowTerrain = () => { - this.showTerrain = !this.showTerrain; - }; + @action + onPitchChange = (e: React.ChangeEvent<HTMLInputElement>) => { + const pitch = parseInt(e.target.value); + if (!isNaN(pitch) && this._mapRef.current){ + const fixedPitch = Math.max(0, Math.min(85, pitch)); + this._mapRef.current.setPitch(fixedPitch); + this.dataDoc.map_pitch = fixedPitch; + this.mapboxMapViewState = { + ...this.mapboxMapViewState, + pitch: fixedPitch + } + } + } - @action - onBearingChange = (e: React.ChangeEvent<HTMLInputElement>) => { - const newVal = parseInt(e.target.value); - if (!isNaN(newVal) && newVal >= 0) { + @action + onZoomChange = (e: React.ChangeEvent<HTMLInputElement>) => { + const zoom = parseInt(e.target.value); + if (!isNaN(zoom) && this._mapRef.current){ + const fixedZoom = Math.max(0, Math.min(16, zoom)); + this._mapRef.current.setZoom(fixedZoom); + this.dataDoc.map_zoom = fixedZoom; this.mapboxMapViewState = { ...this.mapboxMapViewState, - bearing: parseInt(e.target.value), - }; + zoom: fixedZoom + } } - }; + } @action - onPitchChange = (e: React.ChangeEvent<HTMLInputElement>) => { - const newVal = parseInt(e.target.value); - if (!isNaN(newVal) && newVal >= 0) { + onStepZoomChange = (increment: boolean) => { + if (this._mapRef.current) { + let newZoom: number; + if (increment) { + console.log('inc') + newZoom = this.mapboxMapViewState.zoom + 1; + + } else { + console.log('dec') + newZoom = this.mapboxMapViewState.zoom - 1; + } + this._mapRef.current.setZoom(newZoom); + this.dataDoc.map_zoom = newZoom; this.mapboxMapViewState = { ...this.mapboxMapViewState, - pitch: parseInt(e.target.value), - }; + zoom: increment ? Math.min(16, newZoom) : Math.max(0, newZoom) + } } - }; + + } + + + @action + onMapMove = (e: ViewStateChangeEvent) => { + this.mapboxMapViewState = e.viewState; + this.dataDoc.longitude = e.viewState.longitude; + this.dataDoc.latitude = e.viewState.latitude; + } + + @action + toggleShowTerrain = () => { + this.showTerrain = !this.showTerrain; + } getMarkerIcon = (pinDoc: Doc): JSX.Element | null => { const markerType = StrCast(pinDoc.markerType); const markerColor = StrCast(pinDoc.markerColor); return MarkerIcons.getFontAwesomeIcon(markerType, '2x', markerColor) ?? null; - }; + + } + + + + + static _firstRender = true; static _rerenderDelay = 500; @@ -1457,7 +1662,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps 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]; + this.rootDoc[DocCss]; if (MapBox._rerenderDelay) { // prettier-ignore this._rerenderTimeout = this._rerenderTimeout ?? @@ -1466,12 +1671,14 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps MapBox._rerenderDelay = 0; } this._rerenderTimeout = undefined; - this.Document[DocCss] = this.Document[DocCss] + 1; + this.rootDoc[DocCss] = this.rootDoc[DocCss] + 1; }), MapBox._rerenderDelay); return null; } const scale = this.props.NativeDimScaling?.() || 1; + + const renderAnnotations = (childFilters?: () => string[]) => null; return ( <div className="mapBox" ref={this._ref}> <div @@ -1480,164 +1687,235 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps onPointerDown={async e => { e.button === 0 && !e.ctrlKey && e.stopPropagation(); }} - style={{ transformOrigin: 'top left', transform: `scale(${scale})`, width: `${100 / scale}%`, height: `${100 / scale}%`, pointerEvents: this.pointerEvents() }}> - {!this.routeToAnimate && ( + style={{ transformOrigin: "top left", transform: `scale(${scale})`, width: `${100 / scale}%`, height: `${100 / scale}%`, pointerEvents: this.pointerEvents() }}> + <div style={{ mixBlendMode: 'multiply' }}>{renderAnnotations(this.transparentFilter)}</div> + {renderAnnotations(this.opaqueFilter)} + {SnappingManager.GetIsDragging() ? null : renderAnnotations()} + {!this.routeToAnimate && <div className="mapBox-searchbar"> - <TextField fullWidth placeholder="Enter a location" onChange={(e: any) => this.handleSearchChange(e.target.value)} /> - <IconButton icon={<FontAwesomeIcon icon={faGear as IconLookup} size="1x" />} type={Type.TERT} onClick={e => this.toggleSettings()} /> - </div> - )} - {this.settingsOpen && !this.routeToAnimate && ( - <div className="mapbox-settings-panel" style={{ right: `${0 + this.sidebarWidth()}px` }}> - <div className="mapbox-style-select"> - <div>Map Style:</div> + <TextField + fullWidth + placeholder='Enter a location' + onChange={(e) => this.handleSearchChange(e.target.value)} + /> + <IconButton + icon={<FontAwesomeIcon icon={faGear as IconLookup} size='1x'/>} + type={Type.TERT} + onClick={(e) => this.toggleSettings()} + + /> + </div> + } + {this.settingsOpen && !this.routeToAnimate && + <div className='mapbox-settings-panel' style={{right: `${0+ this.sidebarWidth()}px`}}> + <div className='mapbox-style-select'> + <div> + Map Style: + </div> <div> <select onChange={this.changeMapStyle}> - <option value="streets-v12">Streets</option> - <option value="outdoors-v12">Outdoors</option> - <option value="light-v11">Light</option> - <option value="dark-v11">Dark</option> - <option value="satellite-v9">Satellite</option> - <option value="satellite-streets-v12">Satellite Streets</option> - <option value="navigation-day-v1">Navigation Day</option> - <option value="navigation-night-v1">Navigation Night</option> + <option value='streets-v11'>Streets</option> + <option value='outdoors-v12'>Outdoors</option> + <option value='light-v11'>Light</option> + <option value='dark-v11'>Dark</option> + <option value='satellite-v9'>Satellite</option> + <option value='satellite-streets-v12'>Satellite Streets</option> + <option value='navigation-day-v1'>Navigation Day</option> + <option value='navigation-night-v1'>Navigation Night</option> </select> </div> </div> - <div className="mapbox-bearing-selection"> + <div className='mapbox-bearing-selection'> <div>Bearing: </div> - <input value={this.mapboxMapViewState.bearing} min={0} type="number" onChange={this.onBearingChange} /> + <input + value={NumCast(this.mapboxMapViewState.bearing).toFixed(2)} + type='number' + onChange={this.onBearingChange}/> </div> - <div className="mapbox-pitch-selection"> + <div className='mapbox-pitch-selection'> <div>Pitch: </div> - <input value={this.mapboxMapViewState.pitch} min={0} type="number" onChange={this.onPitchChange} /> + <input + value={NumCast(this.mapboxMapViewState.pitch).toFixed(2)} + type='number' + onChange={this.onPitchChange}/> + </div> + <div className='mapbox-pitch-selection'> + <div>Zoom: </div> + <input + value={NumCast(this.mapboxMapViewState.zoom).toFixed(2)} + type='number' + onChange={this.onZoomChange}/> </div> - <div className="mapbox-terrain-selection"> + <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 && ( - <div className="animation-panel"> - <div id="route-to-animate-title">{StrCast(this.routeToAnimate.title)}</div> - <div className="route-animation-options">{this.getRouteAnimationOptions()}</div> + } + {this.routeToAnimate && + <div className='animation-panel'> + <div id='route-to-animate-title'> + {StrCast(this.routeToAnimate.title)} + </div> + <div className='route-animation-options'> + {this.getRouteAnimationOptions()} + </div> </div> - )} + } {this.featuresFromGeocodeResults.length > 0 && ( - <div className="mapbox-geocoding-search-results"> + <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 + 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> - </div> + + </div> )} + {/* <div className='zoom-box'> + <IconButton // increment + style={{borderBottom: '1px', borderBottomColor: 'white'}} + onPointerDown={() => this.onStepZoomChange(true)} + icon={<FontAwesomeIcon icon={faPlus as IconLookup} color='black'/>} + size={Size.SMALL} + color={SettingsManager.userColor} + /> + <IconButton // decrement + onPointerDown={() => this.onStepZoomChange(false)} + icon={<FontAwesomeIcon icon={faMinus as IconLookup} color='black'/>} + size={Size.SMALL} + color={SettingsManager.userColor} + /> + </div> */} <MapProvider> <MapboxMap ref={this._mapRef} mapboxAccessToken={MAPBOX_ACCESS_TOKEN} id="mapbox-map" - mapStyle={this.mapStyle} - style={{ height: '100%', width: '100%' }} + mapStyle={this.dataDoc.map_style ? StrCast(this.dataDoc.map_style) : 'mapbox://styles/mapbox/streets-v11'} + style={{height: NumCast(this.layoutDoc._height), width: NumCast(this.layoutDoc._width)}} initialViewState={this.isAnimating ? undefined : this.mapboxMapViewState} - // {...this.mapboxMapViewState} onMove={this.onMapMove} onClick={this.handleMapClick} onDblClick={this.handleMapDblClick} - 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="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) && ( + 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='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.isStreetViewAnimation && ( + {!this.isStreetViewAnimation && <> - <Source id="animated-route" type="geojson" data={this.updatedRouteCoordinates} /> - <Layer - id="dynamic-animation-line" - type="line" - source="animated-route" - paint={{ - 'line-color': 'yellow', - 'line-width': 4, - }} + <Source id='animated-route' type='geojson' data={this.updatedRouteCoordinates}/> + <Layer + id='dynamic-animation-line' + type='line' + source='animated-route' + paint={{ + 'line-color': this.animationLineColor, + 'line-width': 5, + }} /> </> - )} - <Source id="start-pin-base" type="geojson" data={AnimationUtility.createGeoJSONCircle(this.selectedRouteCoordinates[0], 0.04)} /> - <Source id="start-pin-top" type="geojson" data={AnimationUtility.createGeoJSONCircle(this.selectedRouteCoordinates[0], 0.25)} /> - <Source id="end-pin-base" type="geojson" data={AnimationUtility.createGeoJSONCircle(this.selectedRouteCoordinates.slice(-1)[0], 0.04)} /> - <Source id="end-pin-top" type="geojson" data={AnimationUtility.createGeoJSONCircle(this.selectedRouteCoordinates.slice(-1)[0], 0.25)} /> - <Layer - id="start-fill-pin-base" - type="fill-extrusion" - source="start-pin-base" + } + <Source id='start-pin-base' type='geojson' data={AnimationUtility.createGeoJSONCircle(this.selectedRouteCoordinates[0], 0.04)}/> + <Source id='start-pin-top' type='geojson' data={AnimationUtility.createGeoJSONCircle(this.selectedRouteCoordinates[0], 0.25)}/> + <Source id='end-pin-base' type='geojson' data={AnimationUtility.createGeoJSONCircle(this.selectedRouteCoordinates.slice(-1)[0], 0.04)}/> + <Source id='end-pin-top' type='geojson' data={AnimationUtility.createGeoJSONCircle(this.selectedRouteCoordinates.slice(-1)[0], 0.25)}/> + <Layer id='start-fill-pin-base' type='fill-extrusion' source='start-pin-base' paint={{ 'fill-extrusion-color': '#0bfc03', - 'fill-extrusion-height': 1000, + 'fill-extrusion-height': 1000 }} /> - <Layer - id="start-fill-pin-top" - type="fill-extrusion" - source="start-pin-top" + <Layer id='start-fill-pin-top' type='fill-extrusion' source='start-pin-top' paint={{ 'fill-extrusion-color': '#0bfc03', 'fill-extrusion-base': 1000, - 'fill-extrusion-height': 1200, + 'fill-extrusion-height': 1200 }} /> - <Layer - id="end-fill-pin-base" - type="fill-extrusion" - source="end-pin-base" + <Layer id='end-fill-pin-base' type='fill-extrusion' source='end-pin-base' paint={{ 'fill-extrusion-color': '#eb1c1c', - 'fill-extrusion-height': 1000, + 'fill-extrusion-height': 1000 }} /> - <Layer - id="end-fill-pin-top" - type="fill-extrusion" - source="end-pin-top" + <Layer id='end-fill-pin-top' type='fill-extrusion' source='end-pin-top' paint={{ 'fill-extrusion-color': '#eb1c1c', 'fill-extrusion-base': 1000, - 'fill-extrusion-height': 1200, + 'fill-extrusion-height': 1200 }} /> + </> - )} + } + <> - {!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) => ( + <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}/> ))} */} + </MapboxMap> </MapProvider> @@ -1657,10 +1935,10 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps .map((pushpin, i) => ( <DocumentView key={i} - {...this._props} - renderDepth={this._props.renderDepth + 1} + {...this.props} + renderDepth={this.props.renderDepth + 1} Document={pushpin} - TemplateDataDocument={undefined} + DataDoc={undefined} PanelWidth={returnOne} PanelHeight={returnOne} NativeWidth={returnOne} @@ -1682,7 +1960,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps </div> */} {/* <MapBoxInfoWindow key={Docs.Create.MapMarkerDocument(NumCast(40), NumCast(40), false, [], {})[Id]} - {...OmitKeys(this._props, ['NativeWidth', 'NativeHeight', 'setContentView']).omit} + {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight', 'setContentView']).omit} place={Docs.Create.MapMarkerDocument(NumCast(40), NumCast(40), false, [], {})} markerMap={this.markerMap} PanelWidth={this.infoWidth} @@ -1696,9 +1974,9 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps <div className="mapBox-sidebar" style={{ width: `${this.sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}> <SidebarAnnos ref={this._sidebarRef} - {...this._props} + {...this.props} fieldKey={this.fieldKey} - Document={this.Document} + rootDoc={this.rootDoc} layoutDoc={this.layoutDoc} dataDoc={this.dataDoc} usePanelWidth={true} @@ -1717,8 +1995,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps } } -{ - /* <Autocomplete +{/* <Autocomplete fullWidth id="map-location-searcher" freeSolo @@ -1737,10 +2014,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps placeholder='Enter a location' /> )} - /> */ -} -{ - /* <EditableText + /> */} + {/* <EditableText // editing setVal={(newText: string | number) => typeof newText === 'string' && this.handleSearchChange(newText)} // onEnter={e => this.bingSearch()} @@ -1749,10 +2024,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps // placeholder={this.bingSearchBarContents || 'Enter a location'} placeholder='Enter a location' textAlign="center" - /> */ -} -{ - /* <IconButton + /> */} + {/* <IconButton icon={ <svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="magnifying-glass" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" color="#DFDFDF"> <path @@ -1765,5 +2038,4 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps /> <div style={{ width: 30, height: 30 }} ref={this._dragRef} onPointerDown={this.dragToggle}> <Button tooltip="drag to place a pushpin" icon={<FontAwesomeIcon size={'lg'} icon={'bullseye'} />} /> - </div> */ -} + </div> */} |