diff options
Diffstat (limited to 'src/client/views/nodes/MapBox/MapBox.tsx')
-rw-r--r-- | src/client/views/nodes/MapBox/MapBox.tsx | 691 |
1 files changed, 691 insertions, 0 deletions
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx new file mode 100644 index 000000000..7875060e2 --- /dev/null +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -0,0 +1,691 @@ +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Autocomplete, GoogleMap, GoogleMapProps, InfoWindow, LoadScript, Marker } from '@react-google-maps/api'; +import { action, computed, IReactionDisposer, observable, ObservableMap } from 'mobx'; +import { observer } from "mobx-react"; +import * as React from "react"; +import { Doc, DocListCast, Opt, WidthSym } from '../../../../fields/Doc'; +import { documentSchema } from '../../../../fields/documentSchemas'; +import { Id } from '../../../../fields/FieldSymbols'; +import { InkTool } from '../../../../fields/InkField'; +import { makeInterface } from '../../../../fields/Schema'; +import { NumCast, StrCast } from '../../../../fields/Types'; +import { TraceMobx } from '../../../../fields/util'; +import { emptyFunction, OmitKeys, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents, Utils } from '../../../../Utils'; +import { Docs } from '../../../documents/Documents'; +import { CurrentUserUtils } from '../../../util/CurrentUserUtils'; +import { DragManager } from '../../../util/DragManager'; +import { SelectionManager } from '../../../util/SelectionManager'; +import { SnappingManager } from '../../../util/SnappingManager'; +import { undoBatch } from '../../../util/UndoManager'; +import { CollectionFreeFormView, MarqueeOptionsMenu } from '../../collections/collectionFreeForm'; +import { CollectionStackingView } from '../../collections/CollectionStackingView'; +import { CollectionViewType } from '../../collections/CollectionView'; +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 { StyleProp } from '../../StyleProvider'; +import { FieldView, FieldViewProps } from '../FieldView'; +import * as dotenv from 'dotenv'; +import "./MapBox.scss"; + +/** + * 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; + +type MapDocument = makeInterface<[typeof documentSchema]>; +const MapDocument = makeInterface(documentSchema); + +const mapContainerStyle = { + height: '100%', +}; + +const defaultCenter = { + lat: 38.685, + lng: -115.234, +}; + +const mapOptions = { + fullscreenControl: false, +} + +dotenv.config({ path: __dirname + '/.env' }) +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); + +/** + * 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 MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps & Partial<GoogleMapProps>, MapDocument>(MapDocument) { + + 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(MapBox, 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 markerIdToMapMarker: { [id: string]: Doc | MapMarker | undefined } = {}; + @observable private center = navigator.geolocation ? navigator.geolocation.getCurrentPosition : defaultCenter; + @observable private zoom = 2.5; + @observable private _marqueeing: number[] | undefined; + @observable private _isAnnotating = false; + @observable private bounds = new window.google.maps.LatLngBounds(); + @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(); + + constructor(props: any) { + super(props); + } + + @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) => { + console.log('map bound is:' + this.bounds); + this.allMapMarkers.map(place => { + this.bounds.extend({ lat: NumCast(place.lat), lng: NumCast(place.lng) }); + }); + map.fitBounds(this.bounds) + } + + /** + * Custom control for add marker button + * @param controlDiv + * @param map + */ + private CenterControl = (controlDiv: Element) => { + // Set CSS for the control border. + const controlUI = document.createElement("div"); + + controlUI.style.backgroundColor = "#fff"; + controlUI.style.border = "2px solid #fff"; + controlUI.style.borderRadius = "3px"; + controlUI.style.cursor = "pointer"; + controlUI.style.marginTop = "8px"; + controlUI.style.marginBottom = "22px"; + controlUI.style.textAlign = "center"; + controlUI.title = "Click to add marker to the location your pointer is at"; + controlDiv.appendChild(controlUI); + + // Set CSS for the control interior. + const controlText = document.createElement("div"); + + controlText.style.color = "rgb(25,25,25)"; + controlText.style.fontFamily = "Roboto,Arial,sans-serif"; + controlText.style.fontSize = "16px"; + controlText.style.lineHeight = "38px"; + controlText.style.paddingLeft = "5px"; + controlText.style.paddingRight = "5px"; + controlText.innerHTML = "Add Marker"; + controlUI.appendChild(controlText); + + // 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"; + controlText.style.color = "rgb(25,25,25)"; + } else { + this.toggleAddMarker = true; + console.log("add marker button status:" + this.toggleAddMarker); + controlUI.style.backgroundColor = "#4476f7"; + controlText.style.color = "rgb(255,255,255)"; + }; + }); + } + + /** + * 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); + } + + + /** + * 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; + const centerControlDiv = document.createElement("div"); + this.CenterControl(centerControlDiv); + map.controls[google.maps.ControlPosition.TOP_RIGHT].push(centerControlDiv); + //drawingManager.setMap(map); + if (navigator.geolocation) { + navigator.geolocation.getCurrentPosition( + (position: GeolocationPosition) => { + const pos = { + lat: position.coords.latitude, + lng: position.coords.longitude, + }; + this._map.setCenter(pos); + } + ); + } else { + alert("Your geolocation is not supported by browser.") + }; + console.log("all sidebar docs during map loading is:") + console.log(this.allSidebarDocs); + this.fitBounds(map); + + + // listener to addmarker event + this._map.addListener('click', (e) => { + console.log("add marker map status:" + this.toggleAddMarker); + if (this.toggleAddMarker == true) { + this.placeMarker(e.latLng, map) + console.log(this.allMapMarkers) + } + }) + } + + /** + * 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; + + console.log("the following is a markerMap from id to Marker:") + console.log(this.markerMap); + } + + /** + * 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: MouseEvent, place: Doc) => { + // set which place was clicked + this.selectedPlace = place; + + console.log("you have selected this location:"); + console.log(this.selectedPlace); + + place.infoWindowOpen = true; + console.log("open infowindow") + } + + /** + * 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"); + console.log(this.allSidebarDocs); + 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); + doc.onClickBehavior = "enterPortal"; + 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 + console.log("sidebaraddDocument"); + console.log(doc); + + 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; + docs.forEach(doc => { + console.log(this.allMapMarkers); + console.log(this.allSidebarDocs); + }) + 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) => { + const localDelta = this.props.ScreenToLocalTransform().scale(this.props.scaling?.() || 1).transformDirection(delta[0], delta[1]); + const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]); + const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth); + const ratio = (curNativeWidth + localDelta[0] / (this.props.scaling?.() || 1)) / nativeWidth; + if (ratio >= 1) { + this.layoutDoc.nativeWidth = nativeWidth * ratio; + this.layoutDoc._width = this.layoutDoc[WidthSym]() + localDelta[0]; + this.layoutDoc._showSidebar = nativeWidth !== this.layoutDoc._nativeWidth; + } + return false; + }, emptyFunction, this.toggleSidebar); + } + + 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 = () => { + console.log(this.searchBox); + 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) { + console.log(this._map); + this._map.fitBounds(place.geometry.viewport); + } else { + console.log(this._map); + 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, + }) + ) + } + + + @action + private handleInfoWindowClose = (place: Doc) => { + if (place.infoWindowOpen) { + place.infoWindowOpen = false; + } + place.infoWindowOpen = false; + } + + /** + * Handles toggle of sidebar on click the little comment button + */ + @computed get sidebarHandle() { + TraceMobx(); + const annotated = DocListCast(this.dataDoc[this.SidebarKey]).filter(d => d?.author).length; + const color = !annotated ? Colors.WHITE : Colors.BLACK; + const backgroundColor = !annotated ? this.sidebarWidth() ? Colors.MEDIUM_BLUE : Colors.BLACK : this.props.styleProvider?.(this.rootDoc, this.props as any, StyleProp.WidgetColor + (annotated ? ":annotated" : "")); + return (!annotated) ? (null) : + <div className="formattedTextBox-sidebar-handle" onPointerDown={this.sidebarDown} + style={{ + left: `max(0px, calc(100% - ${this.sidebarWidthPercent} - 17px))`, + backgroundColor: backgroundColor, + color: color, + opacity: annotated ? 1 : undefined + }} > + <FontAwesomeIcon icon={"comment-alt"} /> + </div>; + } + + // TODO: Adding highlight box layer to Maps + @action + toggleSidebar = () => { + const prevWidth = this.sidebarWidth(); + this.layoutDoc._showSidebar = ((this.layoutDoc._sidebarWidthPercent = StrCast(this.layoutDoc._sidebarWidthPercent, "0%") === "0%" ? "50%" : "0%")) !== "0%"; + this.layoutDoc._width = this.layoutDoc._showSidebar ? NumCast(this.layoutDoc._width) * 2 : Math.max(20, NumCast(this.layoutDoc._width) - prevWidth); + } + + sidebarDown = (e: React.PointerEvent) => { + setupMoveUpEvents(this, e, this.sidebarMove, emptyFunction, () => setTimeout(this.toggleSidebar), false); + } + 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].includes(CurrentUserUtils.SelectedTool)) { + 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 = () => this.props.isContentActive() && this.props.pointerEvents !== "none" && !MarqueeOptionsMenu.Instance.isShown() ? "all" : SnappingManager.GetIsDragging() ? undefined : "none"; + + @computed get annotationLayer() { + TraceMobx(); + const pe = this.pointerEvents(); + 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 {...this.props} fieldKey={this.annotationKey} pointerEvents={pe} showInfo={this.showInfo} dataDoc={this.dataDoc} anno={anno} key={`${anno[Id]}-annotation`} />)} + </div>; + + } + + + getAnchor = () => { + const anchor = + AnchorMenu.Instance?.GetAnchor(this._savedAnnotations) ?? + this.rootDoc + return anchor; + } + + infoWidth = () => this.props.PanelWidth() / 5; + infoHeight = () => this.props.PanelWidth() / 5; + + // Collection stacking view for documents in the infowindow of a map marker + private renderChildDocs = (selectedDoc: Doc) => { + return <div style={{ width: this.infoWidth(), height: this.infoHeight() }}> + <CollectionStackingView { + ...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "setContentView"]).omit} + Document={selectedDoc} + DataDoc={undefined} + NativeWidth={returnZero} + NativeHeight={returnZero} + PanelHeight={this.infoHeight} + PanelWidth={this.infoWidth} + docFilters={returnEmptyFilter} + setHeight={emptyFunction} + isAnnotationOverlay={false} + select={emptyFunction} + scaling={returnOne} + isContentActive={returnTrue} + chromeHidden={true} + rootSelected={returnFalse} + whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged} + childHideDecorationTitle={returnTrue} + // childDocumentsActive={returnFalse} + removeDocument={this.removeDocument} + moveDocument={this.moveDocument} + addDocument={this.addDocument} + CollectionView={undefined} + ScreenToLocalTransform={this.props.ScreenToLocalTransform} + renderDepth={this.props.renderDepth + 1} + viewType={CollectionViewType.Stacking} + fieldKey={"data"} + pointerEvents={"all"} + /></div>; + } + + /** + * 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 => this.markerClickHandler(e, place)} + /> + )) + } + + /** + * Renders infowindow corresponding to a map marker document + * @param place + * @returns + */ + private renderInfoWindow = (place: Doc) => { + + return place.infoWindowOpen && ( + <InfoWindow + key={place[Id]} + anchor={this.markerMap[place[Id]]} + onCloseClick={() => this.handleInfoWindowClose(place)} + > + <div className="mapbox-infowindow" style={{ backgroundColor: 'white', opacity: 0.75, padding: 12, fontSize: 17 }}> + {this.renderChildDocs(place)} + <hr /> + <div> + <button>New link+</button> + </div> + </div> + </InfoWindow> + ) + } + + // 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.scaling?.() || 1) - this.sidebarWidth(); // (this.Document.scrollHeight || Doc.NativeHeight(this.Document) || 0); + panelHeight = () => this.props.PanelHeight() / (this.props.scaling?.() || 1); // () => this._pageSizes.length && this._pageSizes[0] ? this._pageSizes[0].width : Doc.NativeWidth(this.Document); + scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._scrollTop)); + transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()]; + opaqueFilter = () => [...this.props.docFilters(), Utils.IsOpaqueFilter()]; + + anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick; + + render() { + const renderAnnotations = (docFilters?: () => string[]) => + <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "setContentView"]).omit} + renderDepth={this.props.renderDepth + 1} + isAnnotationOverlay={true} + fieldKey={this.annotationKey} + CollectionView={undefined} + setPreviewCursor={this.setPreviewCursor} + PanelWidth={this.panelWidth} + PanelHeight={this.panelHeight} + ScreenToLocalTransform={this.scrollXf} + scaling={returnOne} + dropAction={"alias"} + docFilters={docFilters || this.props.docFilters} + dontRenderDocuments={docFilters ? false : true} + select={emptyFunction} + ContentScaling={returnOne} + bringToFront={emptyFunction} + whenChildContentsActiveChanged={this.whenChildContentsActiveChanged} + removeDocument={this.removeDocument} + moveDocument={this.moveDocument} + addDocument={this.sidebarAddDocument} + childPointerEvents={true} + pointerEvents={CurrentUserUtils.SelectedTool !== InkTool.None || this._isAnnotating || SnappingManager.GetIsDragging() ? "all" : "none"} />; + return <div className="mapBox" ref={this._ref}> + {console.log(apiKey)} + {/* <LoadScript + googleMapsApiKey={apiKey!} + libraries={['places', 'drawing']} + > */} + <div className="mapBox-wrapper" + onWheel={e => e.stopPropagation()} + onPointerDown={e => (e.button === 0 && !e.ctrlKey) && e.stopPropagation()} + style={{ width: `calc(100% - ${this.sidebarWidthPercent})` }}> + + <div style={{ mixBlendMode: "multiply" }}> + {renderAnnotations(this.transparentFilter)} + </div> + {renderAnnotations(this.opaqueFilter)} + {SnappingManager.GetIsDragging() ? (null) : renderAnnotations()} + {this.annotationLayer} + <GoogleMap + mapContainerStyle={mapContainerStyle} + zoom={this.zoom} + onLoad={map => this.loadHandler(map)} + options={mapOptions} + > + <Autocomplete + onLoad={this.setSearchBox} + onPlaceChanged={this.handlePlaceChanged}> + <input ref={this.inputRef} className="searchbox" type="text" placeholder="Search anywhere:" /> + </Autocomplete> + + {this.renderMarkers()} + {this.allMapMarkers.map(place => ( + this.renderInfoWindow(place) + ))} + {this.handleMapCenter(this._map)} + </GoogleMap> + {!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} + mainCont={this._mainCont.current} />} + </div> + {/* </LoadScript > */} + <div className="mapBox-sidebar" + style={{ 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> + <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> + </div>; + } +}
\ No newline at end of file |