aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/MapBox/MapBox.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes/MapBox/MapBox.tsx')
-rw-r--r--src/client/views/nodes/MapBox/MapBox.tsx875
1 files changed, 630 insertions, 245 deletions
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index cf017d746..93020354d 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -1,31 +1,36 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { Autocomplete, GoogleMap, GoogleMapProps, Marker } from '@react-google-maps/api';
+import { GoogleMapProps, Marker } from '@react-google-maps/api';
import BingMapsReact from 'bingmaps-react';
-import { action, computed, IReactionDisposer, observable, ObservableMap, runInAction } from 'mobx';
+import { Button, EditableText, IconButton, Type } from 'browndash-components';
+import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
+import { TbHeartMinus } from 'react-icons/tb';
import { Doc, DocListCast, Opt } from '../../../../fields/Doc';
-import { Width } from '../../../../fields/DocSymbols';
+import { Highlight, Width } from '../../../../fields/DocSymbols';
import { Id } from '../../../../fields/FieldSymbols';
import { InkTool } from '../../../../fields/InkField';
+import { ScriptField } from '../../../../fields/ScriptField';
import { NumCast, StrCast } from '../../../../fields/Types';
-import { emptyFunction, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../../Utils';
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../../Utils';
import { Docs } from '../../../documents/Documents';
+import { DocumentManager } from '../../../util/DocumentManager';
import { DragManager } from '../../../util/DragManager';
import { SnappingManager } from '../../../util/SnappingManager';
-import { UndoManager } from '../../../util/UndoManager';
+import { Transform } from '../../../util/Transform';
+import { undoable, UndoManager } from '../../../util/UndoManager';
import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm';
import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocComponent';
import { Colors } from '../../global/globalEnums';
import { MarqueeAnnotator } from '../../MarqueeAnnotator';
-import { AnchorMenu } from '../../pdf/AnchorMenu';
import { Annotation } from '../../pdf/Annotation';
import { SidebarAnnos } from '../../SidebarAnnos';
+import { DocumentView, OpenWhere } from '../DocumentView';
import { FieldView, FieldViewProps } from '../FieldView';
-import { PinProps } from '../trails';
+import { PinProps, PresBox } from '../trails';
+import { MapAnchorMenu } from './MapAnchorMenu';
import './MapBox.scss';
-import { MapBoxInfoWindow } from './MapBoxInfoWindow';
-
+// amongus
/**
* MapBox architecture:
* Main component: MapBox.tsx
@@ -55,13 +60,12 @@ const mapOptions = {
};
const bingApiKey = process.env.BING_MAPS; // if you're running local, get a Bing Maps api key here: https://www.bingmapsportal.com/ and then add it to the .env file in the Dash-Web root directory as: _CLIENT_BING_MAPS=<your apikey>
-const apiKey = process.env.GOOGLE_MAPS;
-const script = document.createElement('script');
-script.defer = true;
-script.async = true;
-script.src = `https://maps.googleapis.com/maps/api/js?key=${apiKey}&libraries=places,drawing`;
-document.head.appendChild(script);
+// const script = document.createElement('script');
+// script.defer = true;
+// script.async = true;
+// script.src = `https://maps.googleapis.com/maps/api/js?key=${bingApiKey}&libraries=places,drawing`;
+// document.head.appendChild(script);
/**
* Consider integrating later: allows for drawing, circling, making shapes on map
@@ -79,16 +83,8 @@ document.head.appendChild(script);
// },
// });
-// options for searchbox in Google Maps Places Autocomplete API
-const options = {
- fields: ['formatted_address', 'geometry', 'name'], // note: level of details is charged by item per retrieval, not recommended to return all fields
- strictBounds: false,
- types: ['establishment'], // type pf places, subject of change according to user need
-} as google.maps.places.AutocompleteOptions;
-
@observer
export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps & Partial<GoogleMapProps>>() {
- static UseBing = true;
private _dropDisposer?: DragManager.DragDropDisposer;
private _disposers: { [name: string]: IReactionDisposer } = {};
private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
@@ -110,10 +106,9 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
@observable private markerMap: { [id: string]: google.maps.Marker } = {};
@observable private center = navigator.geolocation ? navigator.geolocation.getCurrentPosition : defaultCenter;
@observable private _marqueeing: number[] | undefined;
- @observable private _isAnnotating = false;
@observable private inputRef = React.createRef<HTMLInputElement>();
@observable private searchMarkers: google.maps.Marker[] = [];
- @observable private searchBox = new window.google.maps.places.Autocomplete(this.inputRef.current!, options);
+ @observable private searchBox = undefined as any; // new window.google.maps.places.Autocomplete(this.inputRef.current!, options);
@observable private _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>();
@computed get allSidebarDocs() {
return DocListCast(this.dataDoc[this.SidebarKey]);
@@ -124,25 +119,23 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
@observable private toggleAddMarker = false;
private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
- @observable _showSidebar = false;
@computed get SidebarShown() {
- return this._showSidebar || this.layoutDoc._layout_showSidebar ? true : false;
+ return this.layoutDoc._layout_showSidebar ? true : false;
}
static _canAnnotate = true;
static _hadSelection: boolean = false;
private _sidebarRef = React.createRef<SidebarAnnos>();
private _ref: React.RefObject<HTMLDivElement> = React.createRef();
-
+ private _disposer: { [key: string]: IReactionDisposer } = {};
componentDidMount() {
this.props.setContentView?.(this);
}
- @action
- private setSearchBox = (searchBox: any) => {
- this.searchBox = searchBox;
- };
-
+ componentWillUnmount(): void {
+ this.deselectPin();
+ Object.keys(this._disposer).forEach(key => this._disposer[key]?.());
+ }
// iterate allMarkers to size, center, and zoom map to contain all markers
private fitBounds = (map: google.maps.Map) => {
const curBounds = map.getBounds() ?? new window.google.maps.LatLngBounds();
@@ -151,72 +144,25 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
};
/**
- * Custom control for add marker button
- * @param controlDiv
- * @param map
+ * Load and render all map markers
+ * @param marker
+ * @param place
*/
- private CenterControl = () => {
- const controlDiv = document.createElement('div');
- controlDiv.className = 'mapBox-addMarker';
- // Set CSS for the control border.
- const controlUI = document.createElement('div');
- controlUI.style.backgroundColor = '#fff';
- controlUI.style.borderRadius = '3px';
- controlUI.style.cursor = 'pointer';
- controlUI.style.marginTop = '10px';
- controlUI.style.borderRadius = '4px';
- controlUI.style.marginBottom = '22px';
- controlUI.style.textAlign = 'center';
- controlUI.style.position = 'absolute';
- controlUI.style.width = '32px';
- controlUI.style.height = '32px';
- controlUI.title = 'Click to toggle marker mode. In marker mode, click on map to place a marker.';
-
- const plIcon = document.createElement('img');
- plIcon.src = 'https://cdn4.iconfinder.com/data/icons/wirecons-free-vector-icons/32/add-256.png';
- plIcon.style.color = 'rgb(25,25,25)';
- plIcon.style.fontFamily = 'Roboto,Arial,sans-serif';
- plIcon.style.fontSize = '16px';
- plIcon.style.lineHeight = '32px';
- plIcon.style.left = '18';
- plIcon.style.top = '15';
- plIcon.style.position = 'absolute';
- plIcon.width = 14;
- plIcon.height = 14;
- plIcon.innerHTML = 'Add';
- controlUI.appendChild(plIcon);
-
- // Set CSS for the control interior.
- const markerIcon = document.createElement('img');
- markerIcon.src = 'https://cdn0.iconfinder.com/data/icons/small-n-flat/24/678111-map-marker-1024.png';
- markerIcon.style.color = 'rgb(25,25,25)';
- markerIcon.style.fontFamily = 'Roboto,Arial,sans-serif';
- markerIcon.style.fontSize = '16px';
- markerIcon.style.lineHeight = '32px';
- markerIcon.style.left = '-2';
- markerIcon.style.top = '1';
- markerIcon.width = 30;
- markerIcon.height = 30;
- markerIcon.style.position = 'absolute';
- markerIcon.innerHTML = 'Add';
- controlUI.appendChild(markerIcon);
-
- // Setup the click event listeners
- controlUI.addEventListener('click', () => {
- if (this.toggleAddMarker === true) {
- this.toggleAddMarker = false;
- console.log('add marker button status:' + this.toggleAddMarker);
- controlUI.style.backgroundColor = '#fff';
- markerIcon.style.color = 'rgb(25,25,25)';
- } else {
- this.toggleAddMarker = true;
- console.log('add marker button status:' + this.toggleAddMarker);
- controlUI.style.backgroundColor = '#4476f7';
- markerIcon.style.color = 'rgb(255,255,255)';
- }
- });
- controlDiv.appendChild(controlUI);
- return controlDiv;
+ @action
+ private markerLoadHandler = (marker: google.maps.Marker, place: Doc) => {
+ place[Id] ? (this.markerMap[place[Id]] = marker) : null;
+ };
+
+ /**
+ * on clicking the map marker, set the selected place to the marker document & set infowindowopen to be true
+ * @param e
+ * @param place
+ */
+ @action
+ private markerClickHandler = (e: google.maps.MapMouseEvent, place: Doc) => {
+ // set which place was clicked
+ this.selectedPlace = place;
+ // place.infoWindowOpen = true;
};
/**
@@ -231,52 +177,11 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
map: map,
});
map.panTo(position);
- const mapMarker = Docs.Create.MapMarkerDocument(NumCast(position.lat()), NumCast(position.lng()), false, [], {});
+ const mapMarker = Docs.Create.PushpinDocument(NumCast(position.lat()), NumCast(position.lng()), false, [], {});
this.addDocument(mapMarker, this.annotationKey);
};
_loadPending = true;
- /**
- * store a reference to google map instance
- * setup the drawing manager on the top right corner of map
- * fit map bounds to contain all markers
- * @param map
- */
- @action
- private loadHandler = (map: google.maps.Map) => {
- this._map = map;
- this._loadPending = true;
- const centerControlDiv = this.CenterControl();
- map.controls[google.maps.ControlPosition.TOP_RIGHT].push(centerControlDiv);
- //drawingManager.setMap(map);
- // if (navigator.geolocation) {
- // navigator.geolocation.getCurrentPosition(
- // (position: Position) => {
- // const pos = {
- // lat: position.coords.latitude,
- // lng: position.coords.longitude,
- // };
- // this._map.setCenter(pos);
- // }
- // );
- // } else {
- // alert("Your geolocation is not supported by browser.")
- // };
- map.setZoom(NumCast(this.dataDoc.mapZoom, 2.5));
- map.setCenter(new google.maps.LatLng(NumCast(this.dataDoc.mapLat), NumCast(this.dataDoc.mapLng)));
- setTimeout(() => {
- if (this._loadPending && this._map.getBounds()) {
- this._loadPending = false;
- this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map);
- }
- }, 250);
- // listener to addmarker event
- this._map.addListener('click', (e: MouseEvent) => {
- if (this.toggleAddMarker === true) {
- this.placeMarker((e as any).latLng, map);
- }
- });
- };
@action
centered = () => {
@@ -298,25 +203,49 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
};
/**
- * Load and render all map markers
- * @param marker
- * @param place
+ * function that reads the place inputed from searchbox, then zoom in on the location that's been autocompleted;
+ * add a customized temporary marker on the map
*/
@action
- private markerLoadHandler = (marker: google.maps.Marker, place: Doc) => {
- place[Id] ? (this.markerMap[place[Id]] = marker) : null;
- };
+ private handlePlaceChanged = () => {
+ const place = this.searchBox.getPlace();
- /**
- * on clicking the map marker, set the selected place to the marker document & set infowindowopen to be true
- * @param e
- * @param place
- */
- @action
- private markerClickHandler = (e: google.maps.MapMouseEvent, place: Doc) => {
- // set which place was clicked
- this.selectedPlace = place;
- place.infoWindowOpen = true;
+ if (!place.geometry || !place.geometry.location) {
+ // user entered the name of a place that wasn't suggested & pressed the enter key, or place details request failed
+ window.alert("No details available for input: '" + place.name + "'");
+ return;
+ }
+
+ // zoom in on the location of the search result
+ if (place.geometry.viewport) {
+ this._map.fitBounds(place.geometry.viewport);
+ } else {
+ this._map.setCenter(place.geometry.location);
+ this._map.setZoom(17);
+ }
+
+ // customize icon => customized icon for the nature of the location selected
+ const icon = {
+ url: place.icon as string,
+ size: new google.maps.Size(71, 71),
+ origin: new google.maps.Point(0, 0),
+ anchor: new google.maps.Point(17, 34),
+ scaledSize: new google.maps.Size(25, 25),
+ };
+
+ // put temporary cutomized marker on searched location
+ this.searchMarkers.forEach(marker => {
+ marker.setMap(null);
+ });
+ this.searchMarkers = [];
+ this.searchMarkers.push(
+ new window.google.maps.Marker({
+ map: this._map,
+ icon,
+ title: place.name,
+ position: place.geometry.location,
+ })
+ );
};
/**
@@ -335,7 +264,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
if (existingMarker) {
Doc.AddDocToList(existingMarker, 'data', doc);
} else {
- const marker = Docs.Create.MapMarkerDocument(NumCast(doc.lat), NumCast(doc.lng), false, [doc], {});
+ const marker = Docs.Create.PushpinDocument(NumCast(doc.lat), NumCast(doc.lng), false, [doc], {});
this.addDocument(marker, this.annotationKey);
}
}
@@ -351,7 +280,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
* @returns
*/
sidebarRemoveDocument = (doc: Doc | Doc[], sidebarKey?: string) => {
- if (this.layoutDoc._layout_showSidebar) this.toggleSidebar();
+ // if (this.layoutDoc._layout_showSidebar) this.toggleSidebar();
const docs = doc instanceof Doc ? [doc] : doc;
return this.removeDocument(doc, sidebarKey);
};
@@ -373,11 +302,11 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
const fullWidth = this.layoutDoc[Width]();
const mapWidth = fullWidth - this.sidebarWidth();
if (this.sidebarWidth() + localDelta[0] > 0) {
- this._showSidebar = true;
+ this.layoutDoc._layout_showSidebar = true;
this.layoutDoc._width = fullWidth + localDelta[0];
this.layoutDoc._layout_sidebarWidthPercent = ((100 * (this.sidebarWidth() + localDelta[0])) / (fullWidth + localDelta[0])).toString() + '%';
} else {
- this._showSidebar = false;
+ this.layoutDoc._layout_showSidebar = false;
this.layoutDoc._width = mapWidth;
this.layoutDoc._layout_sidebarWidthPercent = '0%';
}
@@ -397,52 +326,6 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
}
/**
- * function that reads the place inputed from searchbox, then zoom in on the location that's been autocompleted;
- * add a customized temporary marker on the map
- */
- @action
- private handlePlaceChanged = () => {
- const place = this.searchBox.getPlace();
-
- if (!place.geometry || !place.geometry.location) {
- // user entered the name of a place that wasn't suggested & pressed the enter key, or place details request failed
- window.alert("No details available for input: '" + place.name + "'");
- return;
- }
-
- // zoom in on the location of the search result
- if (place.geometry.viewport) {
- this._map.fitBounds(place.geometry.viewport);
- } else {
- this._map.setCenter(place.geometry.location);
- this._map.setZoom(17);
- }
-
- // customize icon => customized icon for the nature of the location selected
- const icon = {
- url: place.icon as string,
- size: new google.maps.Size(71, 71),
- origin: new google.maps.Point(0, 0),
- anchor: new google.maps.Point(17, 34),
- scaledSize: new google.maps.Size(25, 25),
- };
-
- // put temporary cutomized marker on searched location
- this.searchMarkers.forEach(marker => {
- marker.setMap(null);
- });
- this.searchMarkers = [];
- this.searchMarkers.push(
- new window.google.maps.Marker({
- map: this._map,
- icon,
- title: place.name,
- position: place.geometry.location,
- })
- );
- };
-
- /**
* Handles toggle of sidebar on click the little comment button
*/
@computed get sidebarHandle() {
@@ -471,6 +354,18 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
this.layoutDoc._width = this.layoutDoc._layout_showSidebar ? NumCast(this.layoutDoc._width) * 1.2 : Math.max(20, NumCast(this.layoutDoc._width) - prevWidth);
};
+ createNoteAnnotation = () => {
+ !this.layoutDoc.layout_showSidebar && this.toggleSidebar();
+
+ setTimeout(undoable(() => {
+ const note = this._sidebarRef.current?.anchorMenuClick(this.getAnchor(false));
+ if (note && this.selectedPin) {
+ note.latitude = this.selectedPin.latitude;
+ note.longitude = this.selectedPin.latitude;
+ }
+ },"create note annotation"))
+
+ }
sidebarDown = (e: React.PointerEvent) => {
setupMoveUpEvents(this, e, this.sidebarMove, emptyFunction, () => setTimeout(this.toggleSidebar), true);
};
@@ -503,7 +398,6 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
};
@action finishMarquee = (x?: number, y?: number) => {
this._marqueeing = undefined;
- this._isAnnotating = false;
x !== undefined && y !== undefined && this._setPreviewCursor?.(x, y, false, false);
};
@@ -525,7 +419,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
);
}
- getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => AnchorMenu.Instance?.GetAnchor(this._savedAnnotations, addAsAnnotation) ?? this.rootDoc;
+ // Old get anchor function
+ // getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => AnchorMenu.Instance?.GetAnchor(this._savedAnnotations, addAsAnnotation) ?? this.rootDoc;
/**
* render contents in allMapMarkers (e.g. images with exifData) into google maps as map marker
@@ -537,14 +432,6 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
));
};
- // 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());
- // }
- };
-
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));
@@ -590,14 +477,460 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
});
};
+ /**
+ *
+ *
+ * ERIC'S BING MAP CODE BELOW
+ *
+ *
+ *
+ **/
+ @observable
+ bingSearchBarContents: any = 'enter city/zip/...'; // For Bing Maps: The contents of the Bing search bar (string)
+
+ geoDataRequestOptions = {
+ entityType: 'PopulatedPlace',
+ };
+
+ // incrementer: number = 0;
+ /*
+ * Creates Pushpin doc and adds it to the list of annotations
+ */
+ @action
+ createPushpin = undoable((latitude: number, longitude: number) => {
+ // Stores the pushpin as a MapMarkerDocument
+ const mapMarker = Docs.Create.PushpinDocument(
+ NumCast(latitude),
+ NumCast(longitude),
+ false,
+ [],
+ {}
+ // ,'pushpinIDamongus'+ this.incrementer++
+ );
+ this.addDocument(mapMarker, this.annotationKey);
+
+ // mapMarker.infoWindowOpen = true;
+ },"createpin");
+
+ /*
+ * Pushpin dblclick
+ */
+ // @action
+ // pushpinDblClicked = (pin: any, pinDoc?: Doc) => {
+ // if (pinDoc) this.removePushpin(pinDoc);
+ // else this._bingMap.current.entities.remove(pin);
+ // };
+
+ // The pin that is selected
+ @observable
+ selectedPin: Doc | undefined;
+
+ @action
+ deselectPin = () => {
+ if (this.selectedPin) {
+ // Removes filter
+ Doc.setDocFilter(this.rootDoc, "latitude", this.selectedPin.latitude, "remove");
+ Doc.setDocFilter(this.rootDoc, "longitude", this.selectedPin.longitude, "remove");
+
+ const temp = this.selectedPin;
+ this._bingMap.current.entities.remove(this.map_docToPinMap.get(temp));
+ const newpin = new this.MicrosoftMaps.Pushpin(new this.MicrosoftMaps.Location(temp.latitude, temp.longitude));
+ this.MicrosoftMaps.Events.addHandler(newpin, 'click', (e: any) => this.pushpinClicked(temp as Doc));
+ this._bingMap.current.entities.push(newpin);
+ this.map_docToPinMap.set(temp, newpin);
+ this.selectedPin = undefined;
+
+
+ }
+
+ };
+
+ 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)));
+ };
+ /*
+ * Pushpin onclick
+ */
+ @action
+ pushpinClicked = (pinDoc: Doc) => {
+ this.deselectPin();
+ this.selectedPin = pinDoc;
+
+ Doc.setDocFilter(this.rootDoc, "latitude", this.selectedPin.latitude, "match");
+ Doc.setDocFilter(this.rootDoc, "longitude", this.selectedPin.latitude, "match");
+
+ this._bingMap.current.entities.remove(this.map_docToPinMap.get(this.selectedPin));
+ const newpin = new this.MicrosoftMaps.Pushpin(new this.MicrosoftMaps.Location(this.selectedPin.latitude, this.selectedPin.longitude), {
+ color: 'green',
+ });
+ this.MicrosoftMaps.Events.addHandler(newpin, 'click', (e: any) => this.pushpinClicked(this.selectedPin as Doc));
+ this._bingMap.current.entities.push(newpin);
+ this.map_docToPinMap.set(this.selectedPin, newpin);
+
+ MapAnchorMenu.Instance.Delete = this.deleteSelectedPin;
+ MapAnchorMenu.Instance.Center = this.centerOnSelectedPin;
+ MapAnchorMenu.Instance.LinkNote = this.createNoteAnnotation;
+
+ const point = this._bingMap.current.tryLocationToPixel(new this.MicrosoftMaps.Location(this.selectedPin.latitude, this.selectedPin.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);
+ MapAnchorMenu.Instance.jumpTo(cpt[0], cpt[1], true);
+
+ document.addEventListener('pointerdown', this.tryHideMapAnchorMenu, true);
+ this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'click', this.mapOnClick);
+
+ // Filter sidebar:
+
+ };
+
+ /**
+ * Returns a list of Pushpin docs
+ */
+ @computed get allMapPushpins() {
+ return DocListCast(this.dataDoc[this.annotationKey]);
+ }
+
+ /**
+ * Map OnClick
+ */
+ @action
+ mapOnClick = (e: { location: { latitude: any; longitude: any } }) => {
+ if (this.selectedPin) {
+ this.deselectPin();
+ this.MicrosoftMaps.Events.removeEventListener(this._bingMap.current, 'click', this.mapOnClick);
+ }
+ };
+
+ /*
+ * Updates values of layout doc to match the current map
+ */
+ @action
+ updateLayout = () => {
+ this.dataDoc.latitude = this._bingMap.current.getCenter().latitude;
+ this.dataDoc.longitude = this._bingMap.current.getCenter().longitude;
+ this.dataDoc.mapZoom = this._bingMap.current.getZoom();
+ // if(this.dataDoc.mapType == 'x'){
+ // this.dataDoc.locationToLookAt
+ // }
+ // this.dataDoc.mapType = new this.MicrosoftMaps.MapTypeId();
+ };
+ /*
+ * Updates maptype
+ */
+ @action
+ updateMapType = () => {
+ this.dataDoc.mapType = this._bingMap.current.getMapTypeId();
+ };
+
+ searched_pin: any;
+ /*
+ * For Bing Maps
+ * Called by search button's onClick
+ * Finds the geocode of the searched contents and sets location to that location
+ **/
+ @action
+ bingSearch = async () => {
+ const location = await this.bingGeocode(this._bingMap, this.bingSearchBarContents);
+ this.dataDoc.latitude = location.latitude;
+ this.dataDoc.longitude = location.longitude;
+ this.dataDoc.mapZoom = this._bingMap.current.getZoom();
+ // Creates a temporary pin but does not add it to the dataDoc
+ this.createPushpin(this.dataDoc.latitude, this.dataDoc.longitude);
+ };
+
+ /**
+ * Adds all pushpins in dataDoc onto the map (render) - OLD & UNUSED
+ */
+ // @action
+ // addAllPins = () => {
+ // this._bingMap.current.entities.clear();
+ // if (this.searched_pin) this._bingMap.current.entities.push(this.searched_pin);
+ // // this.allMapPushpins.map(pin => this.addPushpin(pin));
+ // };
+
+ /*
+ * Returns doc w/ relevant info
+ */
+ getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => {
+ /// this should use SELECTED pushpin for lat/long if there is a selection, otherwise CENTER
+ const anchor = Docs.Create.MapanchorDocument({
+ title: 'MapAnchor:' + this.rootDoc.title,
+ config_latitude: NumCast(this.selectedPin?.latitude ?? this.dataDoc.latitude),
+ config_longitude: NumCast(this.selectedPin?.longitude ?? this.dataDoc.longitude),
+ config_mapZoom: NumCast(this.dataDoc.mapZoom),
+ config_mapType: StrCast(this.dataDoc.mapType),
+ // preslocationToLookAt:this.dataDoc.locationToLookAt,
+ // presType:
+ layout_unrendered: true,
+ 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.rootDoc);
+ return anchor;
+ }
+ return this.rootDoc;
+ };
+
+ map_docToPinMap = new Map<Doc, any>();
+ /*
+ * Input: pin doc
+ * Adds MicrosoftMaps Pushpin to the map (render)
+ */
+ @action
+ addPushpin = (pin: Doc) => {
+ const pushPin = pin.infoWindowOpen
+ ? new this.MicrosoftMaps.Pushpin(new this.MicrosoftMaps.Location(pin.latitude, pin.longitude), {})
+ : new this.MicrosoftMaps.Pushpin(
+ new this.MicrosoftMaps.Location(pin.latitude, pin.longitude)
+ // {icon: 'http://icons.iconarchive.com/icons/icons-land/vista-map-markers/24/Map-Marker-Marker-Outside-Chartreuse-icon.png'}
+ );
+
+ this._bingMap.current.entities.push(pushPin);
+
+ this.MicrosoftMaps.Events.addHandler(pushPin, 'click', (e: any) => this.pushpinClicked(pin));
+ // this.MicrosoftMaps.Events.addHandler(pushPin, 'dblclick', (e: any) => this.pushpinDblClicked(pushPin, pin));
+ this.map_docToPinMap.set(pin, pushPin);
+ };
+
+ @observable
+ pinIsSelected_TEMPORARY: boolean = false; // toggles if remove pin button appears
+
+ /*
+ * Input: pin doc
+ * Removes pin from annotations
+ */
+ @action
+ removePushpin = (pinDoc: Doc) => {
+ // this.allMapPushpins
+ // this.allMapPushpins.map(pin => this.addPushpin(pin));
+ // this._bingMap.current.entities.clear();
+
+ this.removeDocument(pinDoc, this.annotationKey);
+
+ // this.dataDoc[this.annotationKey]
+ };
+ /*
+ * Removes pushpin from map render
+ */
+ deletePushpin = (pinDoc: Doc) => {
+ this._bingMap.current.entities.remove(this.map_docToPinMap.get(pinDoc));
+ this.map_docToPinMap.delete(pinDoc);
+ this.selectedPin = undefined;
+
+ };
+
+ @action
+ deleteSelectedPin = undoable(() => {
+ if (this.selectedPin) {
+ // Removes filter
+ Doc.setDocFilter(this.rootDoc, "latitude", this.selectedPin.latitude, "remove");
+ Doc.setDocFilter(this.rootDoc, "longitude", this.selectedPin.longitude, "remove");
+
+ this.removePushpin(this.selectedPin);
+ }
+ MapAnchorMenu.Instance.fadeOut(true);
+ document.removeEventListener('pointerdown', this.tryHideMapAnchorMenu, true);
+ }, 'delete pin');
+
+ tryHideMapAnchorMenu = (e: PointerEvent) => {
+ let target = document.elementFromPoint(e.x, e.y);
+
+ while (target != null) {
+ if (target === MapAnchorMenu.top.current) {
+ return;
+ }
+ target = target.parentElement;
+ }
+ e.stopPropagation();
+ e.preventDefault();
+ MapAnchorMenu.Instance.fadeOut(true);
+ document.removeEventListener('pointerdown', this.tryHideMapAnchorMenu, true);
+ };
+
+ // tryhidemenu = e => if( e.parent... == mapanchormenu.top.currrent) do nothing; else hide menu
+
+ @action
+ centerOnSelectedPin = () => {
+ if (this.selectedPin) {
+ this.dataDoc.latitude = this.selectedPin.latitude;
+ this.dataDoc.longitude = this.selectedPin.longitude;
+ }
+ MapAnchorMenu.Instance.fadeOut(true);
+ document.removeEventListener('pointerdown', this.tryHideMapAnchorMenu);
+ };
+
+ /**
+ * View options for bing maps
+ */
bingViewOptions = {
- center: { latitude: defaultCenter.lat, longitude: defaultCenter.lng },
+ // center: { latitude: this.dataDoc.latitude ?? defaultCenter.lat, longitude: this.dataDoc.longitude ?? defaultCenter.lng },
+ zoom: this.dataDoc.latitude ?? 10,
mapTypeId: 'grayscale',
};
+
+ /**
+ * Map options
+ */
bingMapOptions = {
navigationBarMode: 'square',
+ backgroundColor: '#f1f3f4',
+ enableInertia: true,
+ supportedMapTypes: ['grayscale', 'canvasLight'],
+ disableMapTypeSelectorMouseOver: true,
+ // showScalebar:true
+ // disableRoadView:true,
+ // disableBirdseye:true
+ streetsideOptions: {
+ showProblemReporting: false,
+ showCurrentAddress: false,
+ },
+ };
+
+ /**
+ * Toggles mode for placing a pin down on map
+ */
+ @observable
+ placePinOn = false;
+ @action
+ togglePlacePin = () => {
+ if (this.placePinOn) this.placePinOn = false;
+ else this.placePinOn = true;
+ };
+
+ @action
+ searchbarOnEdit = (newText: string) => {
+ this.bingSearchBarContents = newText;
+ };
+
+ /*
+ * Called when BingMap is first rendered
+ * Initializes starting values
+ */
+ @observable _mapReady = false;
+ @action
+ bingMapReady = (map: any) => {
+ this._mapReady = true;
+ this._bingMap = map.map;
+ if (!this._bingMap.current) {
+ alert('NO Map!?');
+ }
+ this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'viewchangeend', undoable(this.updateLayout, 'Map Layout Change'));
+ this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'maptypechanged', undoable(this.updateMapType, 'Map ViewType Change'));
+ this.updateLayout();
+ this._disposer.highlight = reaction( () => this.allMapPushpins.map(doc => doc[Highlight]),
+ () => this.allMapPushpins.forEach(doc => {
+
+ // if(doc[Highlight]){
+ // this.deselectPin();
+ // this.selectedPin = doc;
+
+ // Doc.setDocFilter(this.rootDoc, "latitude", this.selectedPin.latitude, "match");
+ // Doc.setDocFilter(this.rootDoc, "longitude", this.selectedPin.latitude, "match");
+
+ // this._bingMap.current.entities.remove(this.map_docToPinMap.get(this.selectedPin));
+ // const newpin = new this.MicrosoftMaps.Pushpin(new this.MicrosoftMaps.Location(this.selectedPin.latitude, this.selectedPin.longitude), {
+ // color: 'green',
+ // });
+ // this.MicrosoftMaps.Events.addHandler(newpin, 'click', (e: any) => this.pushpinClicked(this.selectedPin as Doc));
+ // this._bingMap.current.entities.push(newpin);
+ // this.map_docToPinMap.set(this.selectedPin, newpin);
+
+ // MapAnchorMenu.Instance.Delete = this.deleteSelectedPin;
+ // MapAnchorMenu.Instance.Center = this.centerOnSelectedPin;
+ // MapAnchorMenu.Instance.LinkNote = this.createNoteAnnotation;
+ // }
+ // if (doc[Highlight]) {
+ // this._bingMap.current.entities.remove(this.map_docToPinMap.get(doc));
+ // const newpin = new this.MicrosoftMaps.Pushpin(new this.MicrosoftMaps.Location(doc.latitude, doc.longitude), {
+ // color: 'orange',
+ // });
+ // this.MicrosoftMaps.Events.addHandler(newpin, 'click', (e: any) => this.pushpinClicked(doc));
+ // this._bingMap.current.entities.push(newpin);
+ // this.map_docToPinMap.set(doc, newpin);
+
+ // }
+ // if (this.map_docToPinMap.get(doc).getColor() == 'orange' && !doc[Highlight]) {
+ // this._bingMap.current.entities.remove(this.map_docToPinMap.get(doc));
+ // const newpin = new this.MicrosoftMaps.Pushpin(new this.MicrosoftMaps.Location(doc.latitude, doc.longitude), {});
+ // this.MicrosoftMaps.Events.addHandler(newpin, 'click', (e: any) => this.pushpinClicked(doc));
+ // this._bingMap.current.entities.push(newpin);
+ // this.map_docToPinMap.set(doc, newpin);
+
+ // }
+ // else if (this.map_docToPinMap.get(doc).getColor() != 'orange' && doc[Highlight]) {
+ // this._bingMap.current.entities.remove(this.map_docToPinMap.get(doc));
+ // const newpin = new this.MicrosoftMaps.Pushpin(new this.MicrosoftMaps.Location(doc.latitude, doc.longitude), {
+ // color: 'orange',
+ // });
+ // this.MicrosoftMaps.Events.addHandler(newpin, 'click', (e: any) => this.pushpinClicked(doc));
+ // this._bingMap.current.entities.push(newpin);
+ // this.map_docToPinMap.set(doc, newpin);
+ // }
+
+
+ })
+ , {fireImmediately: true})
+ // this.updateMapType();
+ this._disposer.location = reaction(
+ () => ({ lat: this.rootDoc.latitude, lng: this.rootDoc.longitude, zoom: this.rootDoc.mapZoom, mapType: this.rootDoc.mapType }),
+ locationObject => {
+ // if (this._bingMap.current)
+ try {
+ locationObject?.zoom &&
+ this._bingMap.current?.setView({
+ mapTypeId: locationObject.mapType,
+ zoom: locationObject.zoom,
+ center: new this.MicrosoftMaps.Location(locationObject.lat, locationObject.lng),
+ });
+ } catch (e) {
+ console.log(e);
+ }
+ },
+ { fireImmediately: true }
+ );
+ };
+
+ // Keeps track of when dragging a pin onto map
+ draggingPin = false;
+ dragToggle = (e: React.PointerEvent) => {
+ // console.log('DRAGGING TOGGLE');
+ document.addEventListener('drop', this.dropPin, true);
+ document.addEventListener('pointermove', this.pinMove, true);
+ e.stopPropagation();
+ };
+ pinMove = (e: PointerEvent) => {
+ // console.log('MOVING');
+ e.stopPropagation();
+ };
+ dropPin = (e: DragEvent) => {
+ e.stopPropagation();
+ e.preventDefault();
+ document.removeEventListener('drop', this.dropPin, true);
+ document.removeEventListener('pointermove', this.pinMove, true);
+ let target = document.elementFromPoint(e.x, e.y);
+
+ while (target != null) {
+ 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] - 32 /* height of search bar */ - this.props.PanelHeight() / 2;
+ const location = this._bingMap.current.tryPixelToLocation(new this.MicrosoftMaps.Point(x, y));
+ this.createPushpin(location.latitude, location.longitude);
+ break;
+ }
+ target = target.parentElement;
+ }
+ };
+
+ searchbarKeyDown = (e: any) => {
+ if (e.key === 'Enter') {
+ this.bingSearch();
+ }
};
- bingMapReady = (map: any) => (this._bingMap = map.map);
render() {
const renderAnnotations = (childFilters?: () => string[]) => null;
return (
@@ -621,33 +954,85 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
{SnappingManager.GetIsDragging() ? null : renderAnnotations()}
{this.annotationLayer}
- {!MapBox.UseBing ? null : <BingMapsReact onMapReady={this.bingMapReady} bingMapsKey={bingApiKey} height="100%" mapOptions={this.bingMapOptions} width="100%" viewOptions={this.bingViewOptions} />}
- <div style={{ display: MapBox.UseBing ? 'none' : undefined }}>
- <GoogleMap mapContainerStyle={mapContainerStyle} onZoomChanged={this.zoomChanged} onCenterChanged={this.centered} onLoad={this.loadHandler} options={mapOptions}>
- <Autocomplete onLoad={this.setSearchBox} onPlaceChanged={this.handlePlaceChanged}>
- <input className="mapBox-input" ref={this.inputRef} type="text" onKeyDown={e => e.stopPropagation()} placeholder="Enter location" />
- </Autocomplete>
-
- {this.renderMarkers()}
- {this.allMapMarkers
- .filter(marker => marker.infoWindowOpen)
- .map(marker => (
- <MapBoxInfoWindow
- key={marker[Id]}
- {...this.props}
- setContentView={emptyFunction}
- place={marker}
- markerMap={this.markerMap}
- PanelWidth={this.infoWidth}
- PanelHeight={this.infoHeight}
- moveDocument={this.moveDocument}
- isAnyChildContentActive={this.isAnyChildContentActive}
- whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
- />
- ))}
- {/* {this.handleMapCenter(this._map)} */}
- </GoogleMap>
+ <div className="mapBox-searchbar">
+ <EditableText
+ // editing
+ setVal={(newText: string | number) => typeof newText === 'string' && this.searchbarOnEdit(newText)}
+ onEnter={e => this.bingSearch()}
+ placeholder={this.bingSearchBarContents}
+ textAlign="center"
+ />
+ <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
+ fill="currentColor"
+ d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352a144 144 0 1 0 0-288 144 144 0 1 0 0 288z"></path>
+ </svg>
+ }
+ onClick={this.bingSearch}
+ onDoubleClick={function noRefCheck() {}}
+ onPointerDown={function noRefCheck() {}}
+ onPointerDownCapture={function noRefCheck() {}}
+ onPointerMove={function noRefCheck() {}}
+ onPointerMoveCapture={function noRefCheck() {}}
+ onPointerUp={function noRefCheck() {}}
+ type={Type.TERT}
+ />
+ <div draggable={true} style={{ width: 30, height: 30 }} onPointerDown={this.dragToggle}>
+ <Button tooltip="drag to place a pushpin" icon={<FontAwesomeIcon size={'lg'} icon={'bullseye'} />} />
+ </div>
+ </div>
+
+ <BingMapsReact
+ onMapReady={this.bingMapReady}
+ bingMapsKey={bingApiKey}
+ height="100%"
+ mapOptions={this.bingMapOptions}
+ width="100%"
+ viewOptions={this.bingViewOptions}
+ onPointerUp
+ {...() => (this.draggingPin = false)}></BingMapsReact>
+ <div>
+ {!this._mapReady
+ ? null
+ : this.allMapPushpins.map(pushpin => (
+ <DocumentView
+ {...this.props}
+ Document={pushpin}
+ DataDoc={undefined}
+ PanelWidth={returnOne}
+ PanelHeight={returnOne}
+ NativeWidth={returnOne}
+ NativeHeight={returnOne}
+ onClick={() => new ScriptField(undefined)}
+ onKey={undefined}
+ onDoubleClick={undefined}
+ onBrowseClick={undefined}
+ childFilters={returnEmptyFilter}
+ childFiltersByRanges={returnEmptyFilter}
+ searchFilterDocs={returnEmptyDoclist}
+ isDocumentActive={returnFalse}
+ isContentActive={returnFalse}
+ addDocTab={returnFalse}
+ ScreenToLocalTransform={() => new Transform(0, 0, 0)}
+ fitContentsToBox={undefined}
+ focus={returnOne}
+ />
+ ))}
</div>
+ {/* <MapBoxInfoWindow
+ key={Docs.Create.MapMarkerDocument(NumCast(40), NumCast(40), false, [], {})[Id]}
+ {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight', 'setContentView']).omit}
+ place={Docs.Create.MapMarkerDocument(NumCast(40), NumCast(40), false, [], {})}
+ markerMap={this.markerMap}
+ PanelWidth={this.infoWidth}
+ PanelHeight={this.infoHeight}
+ moveDocument={this.moveDocument}
+ isAnyChildContentActive={this.isAnyChildContentActive}
+ whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
+ /> */}
+
{!this._marqueeing || !this._mainCont.current || !this._annotationLayer.current ? null : (
<MarqueeAnnotator
rootDoc={this.rootDoc}
@@ -666,7 +1051,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
)}
</div>
{/* </LoadScript > */}
- <div className="mapBox-sidebar" style={{ position: 'absolute', right: 0, height: '100%', width: `${this.layout_sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
+ <div className="mapBox-sidebar" style={{ width: `${this.layout_sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
<SidebarAnnos
ref={this._sidebarRef}
{...this.props}