aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/views/nodes/MapBox/MapBox.tsx355
-rw-r--r--src/client/views/nodes/MapBox/MapBox2.tsx791
-rw-r--r--src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx4
3 files changed, 1073 insertions, 77 deletions
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index 36be7d257..c44f5765a 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -1,6 +1,7 @@
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 { EditableText } from 'browndash-components';
import { action, computed, IReactionDisposer, observable, ObservableMap, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
@@ -24,7 +25,7 @@ import { FieldView, FieldViewProps } from '../FieldView';
import { PinProps } from '../trails';
import './MapBox.scss';
import { MapBoxInfoWindow } from './MapBoxInfoWindow';
-
+// amongus
/**
* MapBox architecture:
* Main component: MapBox.tsx
@@ -218,6 +219,27 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
controlDiv.appendChild(controlUI);
return controlDiv;
};
+ /**
+ * Load and render all map markers
+ * @param marker
+ * @param place
+ */
+ @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;
+ };
/**
* Place the marker on google maps & store the empty marker as a MapMarker Document in allMarkers list
@@ -298,25 +320,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,
+ })
+ );
};
/**
@@ -397,52 +443,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() {
@@ -591,13 +591,204 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
});
};
+ /**
+ *
+ *
+ * ERIC'S BING MAP CODE BELOW
+ *
+ *
+ *
+ **/
+
+ bingSearchBarContents: any = 'Boston, MA'; // For Bing Maps: The contents of the Bing search bar (string)
+
+ geoDataRequestOptions = {
+ entityType: 'PopulatedPlace',
+ };
+
+ @action
+ updateView = () => {
+ this._bingMap.current.setView({
+ center: new this.MicrosoftMaps.Location(this.dataDoc.latitude, this.dataDoc.longitude),
+ // zoom: location
+ });
+ };
+
+ @action
+ createPushpin = (latitude: number, longitude: number) => {
+ // Stores the pushpin as a MapMarkerDocument
+ const mapMarker = Docs.Create.MapMarkerDocument(NumCast(latitude), NumCast(longitude), false, [], {});
+ this.addDocument(mapMarker, this.annotationKey);
+ mapMarker.infoWindowOpen = true;
+ };
+
+ infobox: any;
+ pushpinClicked = (e: { target: { metadata: { title: any; description: any }; getLocation: () => any } }) => {
+ //Make sure the infobox has metadata to display.
+ if (e.target.metadata) {
+ //Set the infobox options with the metadata of the pushpin. // HOW DO I GET THE CORRECT INFOBOX FOR THIS PIN? CAN I use this e?
+ this.infobox.setOptions({
+ location: e.target.getLocation(),
+ title: e.target.metadata.title,
+ description: e.target.metadata.description,
+ visible: true,
+ });
+ }
+ };
+
+ //PushpinClicked using MapBoxInfoWindow
+ private pushpinClicked2 = (e: { target: { metadata: { title: any; description: any }; getLocation: () => any } }, pin: Doc) => {
+ // // set which place was clicked
+ // this.selectedPlace = place;
+ pin.infoWindowOpen = true;
+ // console.log("later:" + pin.infoWindowOpen)
+ };
+
+ /**
+ * Returns a list of MapMarkerDocument
+ */
+ @computed get allMapPushpins() {
+ return DocListCast(this.dataDoc[this.annotationKey]);
+ }
+ /**
+ * Map OnClick create pushpin
+ */
+ @action
+ mapOnClick = (e: { location: { latitude: any; longitude: any } }) => {
+ if (this.placePinOn) {
+ this.createPushpin(e.location.latitude, e.location.longitude);
+ this.addAllPins();
+ this.placePinOn = false;
+ console.log('PUSHPIN CREATED');
+ }
+ };
+
+ 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 () => {
+ this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'click', this.mapOnClick);
+ this.addAllPins();
+
+ const location = await this.bingGeocode(this._bingMap, this.bingSearchBarContents);
+
+ this.dataDoc.latitude = location.latitude;
+ this.dataDoc.longitude = location.longitude;
+ this.updateView();
+
+ // Creates a temporary pin but does not add it to the dataDoc
+ var temp = new this.MicrosoftMaps.Pushpin(new this.MicrosoftMaps.Location(location.latitude, location.longitude), {
+ // title: this.bingSearchBarContents,
+ // subTitle: 'subtitle here',
+ // text: '1',
+ color: 'blue',
+ });
+ if (temp != this.searched_pin || this.searched_pin == null) {
+ this._bingMap.current.entities.push(this.searched_pin);
+ this.searched_pin = temp;
+ }
+
+ // console.log(this.allMapPushpins
+ // .filter(marker => marker.infoWindowOpen)
+ // .length)
+ // console.log(this.allMapPushpins
+ // .map(marker => console.log(marker.infoWindowOpen)))
+ };
+
+ /**
+ * Adds all pushpins in dataDoc onto the map
+ */
+ @action
+ addAllPins = () => {
+ this._bingMap.current.entities.clear();
+ //TODO: clear all infoboxes
+ if (this.searched_pin) this._bingMap.current.entities.push(this.searched_pin);
+ this.allMapPushpins.map(pin => this.createInfobox(pin));
+ this.allMapPushpins.map(pin => this._bingMap.current.entities.push(pin));
+ };
+
+ @action
+ createInfobox = (pin: any) => {
+ var pushPin = new this.MicrosoftMaps.Pushpin(new this.MicrosoftMaps.Location(pin.lat, pin.lng), {
+ // title: this.bingSearchBarContents,
+ // subTitle: 'subtitle here',
+ // text: '1'
+ });
+ this._bingMap.current.entities.push(pushPin);
+
+ var id = Utils.GenerateGuid();
+ document.getElementById(id);
+ var infoboxTemplate = '<div class="customInfobox"><div class="title">{title}</div>{description}</div>';
+ // var infowindowtemp = '<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}/>'
+
+ // console.log(<div id={id} style={{width:100, height:100, background:"blue"}}/>)
+ // var htmlString = ReactDOMServer.renderToString(<div id={id} style={{width:100, height:100, background:"blue"}}/>);
+
+ //Create an infobox at the pin
+ this.infobox = new this.MicrosoftMaps.Infobox(new this.MicrosoftMaps.Location(pin.lat, pin.lng), {
+ htmlContent: infoboxTemplate, // style="width:100; height:100; background:blue"
+ visible: false,
+ });
+ try {
+ // console.log(document.getElementById(id))
+ // console.log(this.infobox)
+ // const root = ReactDOM.createRoot(document.getElementById(id)!);
+ // root.render(<div style={{width:100, height:100, background:"blue"}}/>);
+ } catch (e) {
+ console.log(e);
+ }
+
+ //Assign the infobox to a map instance.
+ this.infobox.setMap(this._bingMap.current);
+ //Store some metadata with the pushpin.
+ pushPin.metadata = {
+ title: pushPin.title,
+ description: 'Pin description',
+ };
+ // pushPin.infoWindowOpen = true;
+
+ //Add a click event handler to the pushpin.
+ // For bing maps infobox
+ // this.MicrosoftMaps.Events.addHandler(pushPin, 'click', this.pushpinClicked);
+
+ // For our infowindow
+ this.MicrosoftMaps.Events.addHandler(pushPin, 'click', (e: any) => this.pushpinClicked(e));
+ // this.MicrosoftMaps.Events.addHandler(pushPin, 'mouseover', (e:any) => this.onHover(e));
+ };
+
+ /**
+ * 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,
+ };
+
+ /**
+ * Toggles mode for placing a pin down on map
+ */
+ @observable
+ placePinOn: boolean | undefined;
+ @action
+ togglePlacePin = () => {
+ if (this.placePinOn) this.placePinOn = false;
+ else this.placePinOn = true;
};
+
bingMapReady = (map: any) => (this._bingMap = map.map);
render() {
const renderAnnotations = (docFilters?: () => string[]) => null;
@@ -622,17 +813,18 @@ 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>
+ {!MapBox.UseBing ? null : <EditableText editing onEdit={(newText: string) => (this.bingSearchBarContents = newText)} placeholder="..." size="medium" text="Boston, MA" onKeyPress={(e: { key: any }) => console.log(e.key)} />}
+
+ {!MapBox.UseBing ? null : <input type="button" value="Search" onClick={this.bingSearch} />}
+
+ {!MapBox.UseBing ? null : this.placePinOn ? <input type="button" value="Place Pin Mode On" onClick={this.togglePlacePin} /> : <input type="button" value="Place Pin Mode Off" onClick={this.togglePlacePin} />}
- {this.renderMarkers()}
- {this.allMapMarkers
+ {!MapBox.UseBing ? null : (
+ <BingMapsReact onMapReady={this.bingMapReady} bingMapsKey={bingApiKey} height="100%" mapOptions={this.bingMapOptions} width="100%" viewOptions={this.bingViewOptions}>
+ {this.allMapPushpins
.filter(marker => marker.infoWindowOpen)
.map(marker => (
+ // console.log('this is a marker window')
<MapBoxInfoWindow
key={marker[Id]}
{...this.props}
@@ -646,9 +838,20 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
/>
))}
- {/* {this.handleMapCenter(this._map)} */}
- </GoogleMap>
- </div>
+ </BingMapsReact>
+ )}
+ {/* <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}
diff --git a/src/client/views/nodes/MapBox/MapBox2.tsx b/src/client/views/nodes/MapBox/MapBox2.tsx
new file mode 100644
index 000000000..4c28d4df1
--- /dev/null
+++ b/src/client/views/nodes/MapBox/MapBox2.tsx
@@ -0,0 +1,791 @@
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { Autocomplete, GoogleMap, GoogleMapProps, Marker } from '@react-google-maps/api';
+import BingMapsReact from 'bingmaps-react';
+import { EditableText } from 'browndash-components';
+import { action, computed, IReactionDisposer, observable, ObservableMap, runInAction } from 'mobx';
+import { observer } from 'mobx-react';
+import * as React from 'react';
+import { Doc, DocListCast, Opt, WidthSym } from '../../../../fields/Doc';
+import { Id } from '../../../../fields/FieldSymbols';
+import { InkTool } from '../../../../fields/InkField';
+import { NumCast, StrCast } from '../../../../fields/Types';
+import { emptyFunction, OmitKeys, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../../Utils';
+import { Docs } from '../../../documents/Documents';
+import { DragManager } from '../../../util/DragManager';
+import { SnappingManager } from '../../../util/SnappingManager';
+import { 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 { FieldView, FieldViewProps } from '../FieldView';
+import { PinProps } from '../trails';
+import './MapBox.scss';
+import { MapBoxInfoWindow } from './MapBoxInfoWindow';
+
+/**
+ * MapBox architecture:
+ * Main component: MapBox.tsx
+ * Supporting Components: SidebarAnnos, CollectionStackingView
+ *
+ * MapBox is a node that extends the ViewBoxAnnotatableComponent. Similar to PDFBox and WebBox, it supports interaction between sidebar content and document content.
+ * The main body of MapBox uses Google Maps API to allow location retrieval, adding map markers, pan and zoom, and open street view.
+ * Dash Document architecture is integrated with Maps API: When drag and dropping documents with ExifData (gps Latitude and Longitude information) available,
+ * sidebarAddDocument function checks if the document contains lat & lng information, if it does, then the document is added to both the sidebar and the infowindow (a pop up corresponding to a map marker--pin on map).
+ * The lat and lng field of the document is filled when importing (spec see ConvertDMSToDD method and processFileUpload method in Documents.ts).
+ * A map marker is considered a document that contains a collection with stacking view of documents, it has a lat, lng location, which is passed to Maps API's custom marker (red pin) to be rendered on the google maps
+ */
+
+// const _global = (window /* browser */ || global /* node */) as any;
+
+const mapContainerStyle = {
+ height: '100%',
+};
+
+const defaultCenter = {
+ lat: 42.360081,
+ lng: -71.058884,
+};
+
+const mapOptions = {
+ fullscreenControl: false,
+};
+
+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`;
+console.log(script.src);
+document.head.appendChild(script);
+
+/**
+ * Consider integrating later: allows for drawing, circling, making shapes on map
+ */
+// const drawingManager = new window.google.maps.drawing.DrawingManager({
+// drawingControl: true,
+// drawingControlOptions: {
+// position: google.maps.ControlPosition.TOP_RIGHT,
+// drawingModes: [
+// google.maps.drawing.OverlayType.MARKER,
+// // currently we are not supporting the following drawing mode on map, a thought for future development
+// google.maps.drawing.OverlayType.CIRCLE,
+// google.maps.drawing.OverlayType.POLYLINE,
+// ],
+// },
+// });
+
+// 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 MapBox2 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();
+ @observable private _overlayAnnoInfo: Opt<Doc>;
+ showInfo = action((anno: Opt<Doc>) => (this._overlayAnnoInfo = anno));
+ public static LayoutString(fieldKey: string) {
+ return FieldView.LayoutString(MapBox2, fieldKey);
+ }
+ public get SidebarKey() {
+ return this.fieldKey + '-sidebar';
+ }
+ private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean) => void);
+ @computed get inlineTextAnnotations() {
+ return this.allMapMarkers.filter(a => a.textInlineAnnotations);
+ }
+
+ @observable private _map: google.maps.Map = null as unknown as google.maps.Map;
+ @observable private selectedPlace: Doc | undefined;
+ @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 _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>();
+ @computed get allSidebarDocs() {
+ return DocListCast(this.dataDoc[this.SidebarKey]);
+ }
+ @computed get allMapMarkers() {
+ return DocListCast(this.dataDoc[this.annotationKey]);
+ }
+ @observable private toggleAddMarker = false;
+ private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
+
+ @observable _showSidebar = false;
+ @computed get SidebarShown() {
+ return this._showSidebar || this.layoutDoc._showSidebar ? true : false;
+ }
+
+ static _canAnnotate = true;
+ static _hadSelection: boolean = false;
+ private _sidebarRef = React.createRef<SidebarAnnos>();
+ private _ref: React.RefObject<HTMLDivElement> = React.createRef();
+
+ componentDidMount() {
+ this.props.setContentView?.(this);
+ }
+
+ @action
+ private setSearchBox = (searchBox: any) => {
+ this.searchBox = searchBox;
+ };
+
+ // 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();
+ const isFitting = this.allMapMarkers.reduce((fits, place) => fits && curBounds?.contains({ lat: NumCast(place.lat), lng: NumCast(place.lng) }), true as boolean);
+ !isFitting && map.fitBounds(this.allMapMarkers.reduce((bounds, place) => bounds.extend({ lat: NumCast(place.lat), lng: NumCast(place.lng) }), new window.google.maps.LatLngBounds()));
+ };
+
+ /**
+ * Custom control for add marker button
+ * @param controlDiv
+ * @param map
+ */
+ 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;
+ };
+
+ /**
+ * Place the marker on google maps & store the empty marker as a MapMarker Document in allMarkers list
+ * @param position - the LatLng position where the marker is placed
+ * @param map
+ */
+ @action
+ private placeMarker = (position: google.maps.LatLng, map: google.maps.Map) => {
+ const marker = new google.maps.Marker({
+ position: position,
+ map: map,
+ });
+ map.panTo(position);
+ const mapMarker = Docs.Create.MapMarkerDocument(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.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 = () => {
+ if (this._loadPending && this._map.getBounds()) {
+ this._loadPending = false;
+ this.layoutDoc.fitContentsToBox && this.fitBounds(this._map);
+ }
+ this.dataDoc.mapLat = this._map.getCenter()?.lat();
+ this.dataDoc.mapLng = this._map.getCenter()?.lng();
+ };
+
+ @action
+ zoomChanged = () => {
+ if (this._loadPending && this._map.getBounds()) {
+ this._loadPending = false;
+ this.layoutDoc.fitContentsToBox && this.fitBounds(this._map);
+ }
+ this.dataDoc.mapZoom = this._map.getZoom();
+ };
+
+ /**
+ * Load and render all map markers
+ * @param marker
+ * @param place
+ */
+ @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;
+ };
+
+ /**
+ * Called when dragging documents into map sidebar or directly into infowindow; to create a map marker, ref to MapMarkerDocument in Documents.ts
+ * @param doc
+ * @param sidebarKey
+ * @returns
+ */
+ sidebarAddDocument = (doc: Doc | Doc[], sidebarKey?: string) => {
+ console.log('print all sidebar Docs');
+ if (!this.layoutDoc._showSidebar) this.toggleSidebar();
+ const docs = doc instanceof Doc ? [doc] : doc;
+ docs.forEach(doc => {
+ if (doc.lat !== undefined && doc.lng !== undefined) {
+ const existingMarker = this.allMapMarkers.find(marker => marker.lat === doc.lat && marker.lng === doc.lng);
+ if (existingMarker) {
+ Doc.AddDocToList(existingMarker, 'data', doc);
+ } else {
+ const marker = Docs.Create.MapMarkerDocument(NumCast(doc.lat), NumCast(doc.lng), false, [doc], {});
+ this.addDocument(marker, this.annotationKey);
+ }
+ }
+ }); //add to annotation list
+
+ return this.addDocument(doc, sidebarKey); // add to sidebar list
+ };
+
+ /**
+ * Removing documents from the sidebar
+ * @param doc
+ * @param sidebarKey
+ * @returns
+ */
+ sidebarRemoveDocument = (doc: Doc | Doc[], sidebarKey?: string) => {
+ if (this.layoutDoc._showSidebar) this.toggleSidebar();
+ const docs = doc instanceof Doc ? [doc] : doc;
+ return this.removeDocument(doc, sidebarKey);
+ };
+
+ /**
+ * Toggle sidebar onclick the tiny comment button on the top right corner
+ * @param e
+ */
+ sidebarBtnDown = (e: React.PointerEvent) => {
+ setupMoveUpEvents(
+ this,
+ e,
+ (e, down, delta) =>
+ runInAction(() => {
+ const localDelta = this.props
+ .ScreenToLocalTransform()
+ .scale(this.props.NativeDimScaling?.() || 1)
+ .transformDirection(delta[0], delta[1]);
+ const fullWidth = this.layoutDoc[WidthSym]();
+ const mapWidth = fullWidth - this.sidebarWidth();
+ if (this.sidebarWidth() + localDelta[0] > 0) {
+ this._showSidebar = true;
+ this.layoutDoc._width = fullWidth + localDelta[0];
+ this.layoutDoc._sidebarWidthPercent = ((100 * (this.sidebarWidth() + localDelta[0])) / (fullWidth + localDelta[0])).toString() + '%';
+ } else {
+ this._showSidebar = false;
+ this.layoutDoc._width = mapWidth;
+ this.layoutDoc._sidebarWidthPercent = '0%';
+ }
+ return false;
+ }),
+ emptyFunction,
+ () => UndoManager.RunInBatch(this.toggleSidebar, 'toggle sidebar map')
+ );
+ };
+
+ sidebarWidth = () => (Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100) * this.props.PanelWidth();
+ @computed get sidebarWidthPercent() {
+ return StrCast(this.layoutDoc._sidebarWidthPercent, '0%');
+ }
+ @computed get sidebarColor() {
+ return StrCast(this.layoutDoc.sidebarColor, StrCast(this.layoutDoc[this.props.fieldKey + '-backgroundColor'], '#e4e4e4'));
+ }
+
+ /**
+ * 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() {
+ return (
+ <div
+ className="mapBox-overlayButton-sidebar"
+ key="sidebar"
+ title="Toggle Sidebar"
+ style={{
+ display: !this.props.isContentActive() ? 'none' : undefined,
+ top: StrCast(this.rootDoc._showTitle) === 'title' ? 20 : 5,
+ backgroundColor: this.SidebarShown ? Colors.MEDIUM_BLUE : Colors.BLACK,
+ }}
+ onPointerDown={this.sidebarBtnDown}>
+ <FontAwesomeIcon style={{ color: Colors.WHITE }} icon={'comment-alt'} size="sm" />
+ </div>
+ );
+ }
+
+ // TODO: Adding highlight box layer to Maps
+ @action
+ toggleSidebar = () => {
+ //1.2 * w * ? = .2 * w .2/1.2
+ const prevWidth = this.sidebarWidth();
+ this.layoutDoc._showSidebar = (this.layoutDoc._sidebarWidthPercent = StrCast(this.layoutDoc._sidebarWidthPercent, '0%') === '0%' ? `${(100 * 0.2) / 1.2}%` : '0%') !== '0%';
+ this.layoutDoc._width = this.layoutDoc._showSidebar ? NumCast(this.layoutDoc._width) * 1.2 : Math.max(20, NumCast(this.layoutDoc._width) - prevWidth);
+ };
+
+ sidebarDown = (e: React.PointerEvent) => {
+ setupMoveUpEvents(this, e, this.sidebarMove, emptyFunction, () => setTimeout(this.toggleSidebar), true);
+ };
+ sidebarMove = (e: PointerEvent, down: number[], delta: number[]) => {
+ const bounds = this._ref.current!.getBoundingClientRect();
+ this.layoutDoc._sidebarWidthPercent = '' + 100 * Math.max(0, 1 - (e.clientX - bounds.left) / bounds.width) + '%';
+ this.layoutDoc._showSidebar = this.layoutDoc._sidebarWidthPercent !== '0%';
+ e.preventDefault();
+ return false;
+ };
+
+ setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean) => void) => (this._setPreviewCursor = func);
+
+ @action
+ onMarqueeDown = (e: React.PointerEvent) => {
+ if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
+ setupMoveUpEvents(
+ this,
+ e,
+ action(e => {
+ MarqueeAnnotator.clearAnnotations(this._savedAnnotations);
+ this._marqueeing = [e.clientX, e.clientY];
+ return true;
+ }),
+ returnFalse,
+ () => MarqueeAnnotator.clearAnnotations(this._savedAnnotations),
+ false
+ );
+ }
+ };
+ @action finishMarquee = (x?: number, y?: number) => {
+ this._marqueeing = undefined;
+ this._isAnnotating = false;
+ x !== undefined && y !== undefined && this._setPreviewCursor?.(x, y, false, false);
+ };
+
+ addDocumentWrapper = (doc: Doc | Doc[], annotationKey?: string) => {
+ return this.addDocument(doc, annotationKey);
+ };
+
+ pointerEvents = () => {
+ return this.props.isContentActive() && this.props.pointerEvents?.() !== 'none' && !MarqueeOptionsMenu.Instance.isShown() ? 'all' : SnappingManager.GetIsDragging() ? undefined : 'none';
+ };
+ @computed get annotationLayer() {
+ return (
+ <div className="mapBox-annotationLayer" style={{ height: Doc.NativeHeight(this.Document) || undefined }} ref={this._annotationLayer}>
+ {this.inlineTextAnnotations
+ .sort((a, b) => NumCast(a.y) - NumCast(b.y))
+ .map(anno => (
+ <Annotation key={`${anno[Id]}-annotation`} {...this.props} fieldKey={this.annotationKey} pointerEvents={this.pointerEvents} showInfo={this.showInfo} dataDoc={this.dataDoc} anno={anno} />
+ ))}
+ </div>
+ );
+ }
+
+ 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
+ * @returns
+ */
+ private renderMarkers = () => {
+ return this.allMapMarkers.map(place => (
+ <Marker key={place[Id]} position={{ lat: NumCast(place.lat), lng: NumCast(place.lng) }} onLoad={marker => this.markerLoadHandler(marker, place)} onClick={(e: google.maps.MapMouseEvent) => this.markerClickHandler(e, place)} />
+ ));
+ };
+
+ // 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._scrollTop));
+ transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()];
+ opaqueFilter = () => [...this.props.docFilters(), Utils.IsOpaqueFilter()];
+ infoWidth = () => this.props.PanelWidth() / 5;
+ infoHeight = () => this.props.PanelHeight() / 5;
+ anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick;
+ savedAnnotations = () => this._savedAnnotations;
+
+ _bingSearchManager: any;
+ _bingMap: any;
+ get MicrosoftMaps() {
+ return (window as any).Microsoft.Maps;
+ }
+ // uses Bing Search to retrieve lat/lng for a location. eg.,
+ // const results = this.geocodeQuery(map.map, 'Philadelphia, PA');
+ // to move the map to that location:
+ // const location = await this.geocodeQuery(this._bingMap, 'Philadelphia, PA');
+ // this._bingMap.current.setView({
+ // mapTypeId: this.MicrosoftMaps.MapTypeId.aerial,
+ // center: new this.MicrosoftMaps.Location(loc.latitude, loc.longitude),
+ // });
+ //
+ bingGeocode = (map: any, query: string) => {
+ return new Promise<{ latitude: number; longitude: number }>((res, reject) => {
+ //If search manager is not defined, load the search module.
+ if (!this._bingSearchManager) {
+ //Create an instance of the search manager and call the geocodeQuery function again.
+ this.MicrosoftMaps.loadModule('Microsoft.Maps.Search', () => {
+ this._bingSearchManager = new this.MicrosoftMaps.Search.SearchManager(map.current);
+ res(this.bingGeocode(map, query));
+ });
+ } else {
+ this._bingSearchManager.geocode({
+ where: query,
+ callback: action((r: any) => {
+ res(r.results[0].location);
+ }),
+ errorCallback: (e: any) => reject(),
+ });
+ }
+ });
+ };
+
+
+
+
+ bingSearchBarContents: any = "Boston, MA"; // For Bing Maps: The contents of the Bing search bar (string)
+
+ /*
+ * 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() =>{
+
+ // clear all pins
+ this._bingMap.current.entities.clear();
+
+ const location = await this.bingGeocode(this._bingMap, this.bingSearchBarContents);
+
+ // this.rootDoc.latitude =location.latitude;
+ // this.rootDoc.longitude =location.longitude; // TODO: How to update the rootDoc with the correct info?
+ //DocComponents file is where rootDoc is
+
+ // call a helper method that updates the this._bingMap.current.setView,
+ // replaces this method call below
+ this._bingMap.current.setView({
+ center: new this.MicrosoftMaps.Location(location.latitude, location.longitude),
+ // zoom: ,
+ });
+
+ //Create custom Pushpin
+ var pin = new this.MicrosoftMaps.Pushpin(new this.MicrosoftMaps.Location(location.latitude, location.longitude), {
+ title: this.bingSearchBarContents,
+ subTitle: 'subtitle here',
+ text: '1'
+ });
+
+ //Add the pushpin to the map
+ this._bingMap.current.entities.push(pin);
+ // const mapMarker = Docs.Create.MapMarkerDocument(this._bingMap.location.latitude, this._bingMap.location.latitude, false, [], {});
+ // this.addDocument(mapMarker, this.annotationKey); // tells mapbox to add this marker to set of annotations on doc
+ }
+
+
+ // /**
+ // * For Bing Maps
+ // * Place the marker on bing maps & store the empty marker as a MapMarker Document in allMarkers list
+ // * @param position - the LatLng position where the marker is placed
+ // * @param map
+ // */
+ // @action
+ // private placeMarker = (position: google.maps.LatLng, map: google.maps.Map) => {
+ // const marker = new google.maps.Marker({
+ // position: position,
+ // map: map,
+ // });
+ // map.panTo(position);
+ // const mapMarker = Docs.Create.MapMarkerDocument(NumCast(position.lat()), NumCast(position.lng()), false, [], {});
+ // this.addDocument(mapMarker, this.annotationKey);
+ // };
+
+
+
+
+
+ bingViewOptions = {
+ center: { latitude: defaultCenter.lat, longitude: defaultCenter.lng },// TODO: latitude: this.rootDoc.latitude, longitude: this.rootDoc.longitude
+ mapTypeId: 'grayscale',
+ };
+ bingMapOptions = {
+ navigationBarMode: 'square',
+ };
+ bingMapReady = (map: any) => (this._bingMap = map.map);
+ render() {
+ const renderAnnotations = (docFilters?: () => string[]) => null;
+ return (
+ <div className="mapBox" ref={this._ref}>
+ <div
+ className="mapBox-wrapper"
+ onWheel={e => e.stopPropagation()}
+ onPointerDown={async e => {
+ e.button === 0 && !e.ctrlKey && e.stopPropagation();
+ // just a simple test of bing maps geocode api
+ // const loc = await this.bingGeocode(this._bingMap, 'Philadelphia, PA');
+ // this._bingMap.current.setView({
+ // mapTypeId: this.MicrosoftMaps.MapTypeId.aerial,
+ // center: new this.MicrosoftMaps.Location(loc.latitude, loc.longitude),
+ // zoom: 15,
+ // });
+ }}
+ style={{ width: `calc(100% - ${this.sidebarWidthPercent})` }}>
+
+
+ <div style={{ mixBlendMode: 'multiply' }}>{renderAnnotations(this.transparentFilter)}</div>
+ {renderAnnotations(this.opaqueFilter)}
+ {SnappingManager.GetIsDragging() ? null : renderAnnotations()}
+ {this.annotationLayer}
+
+
+
+ {!MapBox2.UseBing ? null :
+ <EditableText editing
+ onEdit={(newText: string) => this.bingSearchBarContents = newText}
+ placeholder="..."
+ size="medium"
+ text="Boston, MA"
+ onKeyPress={e => console.log(e.key)}
+ />}
+
+ {!MapBox2.UseBing ? null :
+ <input type="button" value="Search"
+ onClick={this.bingSearch}/>}
+
+
+ {!MapBox2.UseBing ? null : <BingMapsReact onMapReady={this.bingMapReady} bingMapsKey={bingApiKey} height="100%" mapOptions={this.bingMapOptions} width="100%" viewOptions={this.bingViewOptions} />}
+ {this.allMapMarkers
+ .filter(marker => marker.infoWindowOpen)
+ .map(marker => (
+ <MapBoxInfoWindow
+ key={marker[Id]}
+ {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight', 'setContentView']).omit}
+ place={marker}
+ markerMap={this.markerMap}
+ PanelWidth={this.infoWidth}
+ PanelHeight={this.infoHeight}
+ moveDocument={this.moveDocument}
+ isAnyChildContentActive={this.isAnyChildContentActive}
+ whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
+ />
+ ))}
+
+
+ <div style={{ display: MapBox2.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]}
+ {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight', 'setContentView']).omit}
+ 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>
+
+ {!this._marqueeing || !this._mainCont.current || !this._annotationLayer.current ? null : (
+ <MarqueeAnnotator
+ rootDoc={this.rootDoc}
+ anchorMenuClick={this.anchorMenuClick}
+ scrollTop={0}
+ down={this._marqueeing}
+ scaling={returnOne}
+ addDocument={this.addDocumentWrapper}
+ docView={this.props.docViewPath().lastElement()}
+ finishMarquee={this.finishMarquee}
+ savedAnnotations={this.savedAnnotations}
+ annotationLayer={this._annotationLayer.current}
+ selectionText={returnEmptyString}
+ mainCont={this._mainCont.current}
+ />
+ )}
+ </div>
+ {/* </LoadScript > */}
+ <div className="mapBox-sidebar" style={{ position: 'absolute', right: 0, height: '100%', width: `${this.sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
+ <SidebarAnnos
+ ref={this._sidebarRef}
+ {...this.props}
+ fieldKey={this.fieldKey}
+ rootDoc={this.rootDoc}
+ layoutDoc={this.layoutDoc}
+ dataDoc={this.dataDoc}
+ showSidebar={this.SidebarShown}
+ nativeWidth={NumCast(this.layoutDoc._nativeWidth)}
+ whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
+ PanelWidth={this.sidebarWidth}
+ sidebarAddDocument={this.sidebarAddDocument}
+ moveDocument={this.moveDocument}
+ removeDocument={this.sidebarRemoveDocument}
+ />
+ </div>
+ {this.sidebarHandle}
+ </div>
+ );
+ }
+}
diff --git a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
index 7b437c7de..0c1a62ddb 100644
--- a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
+++ b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
@@ -47,7 +47,9 @@ export class MapBoxInfoWindow extends React.Component<MapBoxInfoWindowProps & Vi
removeDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((p, d) => p && Doc.RemoveDocFromList(this.props.place, 'data', d), true as boolean);
render() {
return (
- <InfoWindow anchor={this.props.markerMap[this.props.place[Id]]} onCloseClick={this.handleInfoWindowClose}>
+ <InfoWindow
+ // anchor={this.props.markerMap[this.props.place[Id]]}
+ onCloseClick={this.handleInfoWindowClose}>
<div className="mapbox-infowindow">
<div style={{ width: this.props.PanelWidth(), height: this.props.PanelHeight() }}>
<CollectionStackingView