From df83cc8ae5e4ca5db2c1ca79b0017263f83ef496 Mon Sep 17 00:00:00 2001
From: Aubrey-Li <63608597+Aubrey-Li@users.noreply.github.com>
Date: Wed, 28 Jul 2021 13:46:48 -0700
Subject: marker updates

---
 src/client/views/nodes/MapBox/MapBox.tsx | 293 +++++++++++++------------------
 1 file changed, 119 insertions(+), 174 deletions(-)

(limited to 'src/client/views/nodes/MapBox/MapBox.tsx')

diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index cc7bf6d84..d52b91908 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -1,25 +1,35 @@
-import { Autocomplete, GoogleMap, GoogleMapProps, InfoBox, Marker } from '@react-google-maps/api';
+import { Autocomplete, GoogleMap, GoogleMapProps, InfoBox, InfoWindow, Marker } from '@react-google-maps/api';
 import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from 'mobx';
 import { observer } from "mobx-react";
 import * as React from "react";
 import { Doc, WidthSym } from '../../../../fields/Doc';
 import { documentSchema } from '../../../../fields/documentSchemas';
 import { makeInterface } from '../../../../fields/Schema';
-import { NumCast } from '../../../../fields/Types';
+import { Cast, NumCast, StrCast } from '../../../../fields/Types';
 import { setupMoveUpEvents, emptyFunction } from '../../../../Utils';
 import { DragManager } from '../../../util/DragManager';
 import { undoBatch } from '../../../util/UndoManager';
+import { CollectionViewType } from '../../collections/CollectionView';
+import { TabDocView } from '../../collections/TabDocView';
 import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocComponent';
 import { SidebarAnnos } from '../../SidebarAnnos';
+import { StyleProp } from '../../StyleProvider';
 import { FieldView, FieldViewProps } from '../FieldView';
+import { PresMovement } from '../PresBox';
 import "./MapBox.scss"
+import { MapMarker } from './MapMarker';
 
 type MapDocument = makeInterface<[typeof documentSchema]>;
 const MapDocument = makeInterface(documentSchema);
 
+export type Coordinates = {
+    lat: number,
+    lng: number,
+}
+
 export type LocationData = {
-    id?: number;
-    pos?: { lat: number, lng: number };
+    id: string;
+    pos: Coordinates;
 };
 
 const mapContainerStyle = {
@@ -31,56 +41,64 @@ const defaultCenter = {
     lng: -115.234,
 };
 
+const mapOptions = {
+    fullscreenControl: false,
+}
+
+const drawingManager = new 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,
+        ],
+    },
+});
+
+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 _sidebarRef = React.createRef<SidebarAnnos>();
     public static LayoutString(fieldKey: string) { return FieldView.LayoutString(MapBox, fieldKey); }
 
-    @observable private _map = null as unknown as google.maps.Map;
-    @observable private selectedPlace: LocationData = null as any;
-    @observable private markerMap = {};
+    @observable private _map: google.maps.Map = null as unknown as google.maps.Map;
+    @observable private selectedPlace: MapMarker | undefined;
+    @observable private markerMap: { [id: string]: google.maps.Marker } = {};
     @observable private center = defaultCenter;
     @observable private zoom = 2.5;
-    @observable private clickedLatLng = null;
     @observable private infoWindowOpen = false;
     @observable private bounds = new window.google.maps.LatLngBounds();
     @observable private inputRef = React.createRef<HTMLInputElement>();
-    @observable private buttonRef = React.createRef<HTMLDivElement>();
     @observable private searchMarkers: google.maps.Marker[] = [];
+    @observable private searchBox = new window.google.maps.places.Autocomplete(this.inputRef.current!, options);
+    @observable private childDocs: MapMarker[] = [];
 
-    private 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;
-
-    @observable private searchBox = new window.google.maps.places.Autocomplete(this.inputRef.current!, this.options);
+    static _canAnnotate = true;
+    static _hadSelection: boolean = false;
+    private _sidebarRef = React.createRef<SidebarAnnos>();
+    private _ref: React.RefObject<HTMLDivElement> = React.createRef();
 
-    @observable private myPlaces = [
-        { id: 1, pos: { lat: 39.09366509575983, lng: -94.58751660204751 } },
-        { id: 2, pos: { lat: 41.82399, lng: -71.41283 } },
-        { id: 3, pos: { lat: 47.606214, lng: -122.33207 } },
-    ];
 
     @action
     private setSearchBox = (searchBox: any) => {
         this.searchBox = searchBox;
     }
 
-    @action
-    private setButton = (button: any) => {
-        this.buttonRef = button;
-        this._map.controls[google.maps.ControlPosition.TOP_RIGHT].push(this.buttonRef.current!)
-    }
-
-    // iterate myPlaces to size, center, and zoom map to contain all markers
+    // iterate childDocs to size, center, and zoom map to contain all markers
     private fitBounds = (map: google.maps.Map) => {
         console.log('map bound is:' + this.bounds);
-        this.myPlaces.map(place => {
-            this.bounds.extend(place.pos);
-            return place.id;
+        this.childDocs.map(place => {
+            this.bounds.extend(place._latlngLocation);
+            return place._markerId;
         });
         map.fitBounds(this.bounds)
     }
@@ -89,40 +107,46 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     @action
     private loadHandler = (map: google.maps.Map) => {
         this._map = map;
+        drawingManager.setMap(map);
         this.fitBounds(map);
+    }
 
-        // //add a custom control for button add marker 
-        // //TODO: why this doesn't work
-        // const google = window.google;
-        // console.log("google window: " + google)
-        // const controlButtonDiv = document.createElement('div');
-        // ReactDOM.render(<button onClick={() => console.log('click me to add marker!')}>Add Marker</button>, controlButtonDiv);
-        // map.controls[google.maps.ControlPosition.TOP_RIGHT].push(controlButtonDiv);
+    @action
+    private markerLoadHandler = (marker: google.maps.Marker, place: MapMarker) => {
+        place._markerId ? this.markerMap[place._markerId] = marker : null;
     }
 
     @action
-    private markerClickHandler = (e: MouseEvent, place: LocationData) => {
+    private markerClickHandler = (e: MouseEvent, place: any) => {
         // set which place was clicked
-        this.selectedPlace = place
+        this.selectedPlace = place;
 
-        console.log(this.selectedPlace.id);
-        console.log(this.selectedPlace.pos);
+        console.log(this.selectedPlace);
 
         // used so clicking a second marker works
         if (this.infoWindowOpen) {
             this.infoWindowOpen = false;
             console.log("closeinfowindow")
         }
-        else {
-            this.infoWindowOpen = true;
-            console.log("open infowindow")
-        }
+        this.infoWindowOpen = true;
+        console.log("open infowindow")
     }
 
+    /**
+     * Called when dragging documents into map sidebar
+     * @param doc 
+     * @param sidebarKey 
+     * @returns 
+     */
     sidebarAddDocument = (doc: Doc | Doc[], sidebarKey?: string) => {
         if (!this.layoutDoc._showSidebar) this.toggleSidebar();
         return this.addDocument(doc, sidebarKey);
     }
+
+    /**
+     * What does this do exactly? How to operate on sidebar?
+     * @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]);
@@ -137,6 +161,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             return false;
         }, emptyFunction, this.toggleSidebar);
     }
+
     toggleSidebar = action(() => {
         const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]);
         const ratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? 250 : 0) + nativeWidth) / nativeWidth;
@@ -145,23 +170,10 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         this.layoutDoc._width = this.layoutDoc[WidthSym]() * nativeWidth * ratio / curNativeWidth;
         this.layoutDoc._showSidebar = nativeWidth !== this.layoutDoc._nativeWidth;
     });
-    sidebarWidth = () => !this.layoutDoc._showSidebar ? 0 : (NumCast(this.layoutDoc.nativeWidth) - Doc.NativeWidth(this.dataDoc)) * this.props.PanelWidth() / NumCast(this.layoutDoc.nativeWidth);
 
-    @action
-    @undoBatch
-    private handleDragMarker = (marker: any, place: LocationData) => {
-        // if (marker != null) {
-        //     place = {
-        //         id: place.id,
-        //         position: {
-        //             lat: marker.latLng.lat().toFixed(3),
-        //             lng: marker.latLng.lng().toFixed(3)
-        //         }
-        //     }
-
-        //     console.log(place);
-        //     console.log(this.myPlaces);
-        // }
+    sidebarWidth = () => {
+        !this.layoutDoc._showSidebar ? 0 :
+            (NumCast(this.layoutDoc.nativeWidth) - Doc.NativeWidth(this.dataDoc)) * this.props.PanelWidth() / NumCast(this.layoutDoc.nativeWidth);
     }
 
     @action
@@ -185,17 +197,16 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             this._map.setZoom(17);
         }
 
-        /** 
-         * customize icon => customized icon for the nature of the location selected (hard to tell from other pre-existing markers, probably won't implement
-         */
-        // 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),
-        // };
+        // 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);
         });
@@ -203,64 +214,21 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         this.searchMarkers.push(
             new window.google.maps.Marker({
                 map: this._map,
+                icon,
                 title: place.name,
                 position: place.geometry.location,
             })
         )
     }
 
-    // @computed get markerContent() {
-    //     const allMarkers = this.childLayoutPairs
-    //     const markerId = NumCast(this.layoutDoc._itemIndex);
-    //     const selectedMarker = this.childLayoutPairs?.[markerId];
-    //     const position = {
-    //         lat: NumCast(this.layoutDoc.lat),
-    //         lng: NumCast(this.layoutDoc.lng)
-    //     }
-    //     return <>
-    //         {
-    //             allMarkers?.map(place => (
-    //                 <Marker
-    //                     key={markerId}
-    //                     position={position}
-    //                     onClick={e => this.markerClickHandler(e, place.layout)} //??
-    //                     draggable={true}
-    //                     onDragEnd={marker => this.handleDragMarker(marker, place.layout)}
-    //                 />
-    //             ))
-    //         }
-    //         {this.infoWindowOpen && selectedMarker && (
-    //             <InfoBox
-    //                 //anchor={selectedMarker}
-    //                 // onCloseClick={this.handleInfoWindowClose}
-    //                 position={position}
-    //             // options={{ enableEventPropagation: true }}
-    //             >
-    //                 <div style={{ backgroundColor: 'white', opacity: 0.75, padding: 12 }}>
-    //                     <div style={{ fontSize: 16 }}>
-    //                         {/* the linkmenu as the ones in other nodes */}
-    //                         <div>
-    //                             <a>a link to another node</a>
-    //                             <hr />
-    //                         </div>
-    //                         <div>
-    //                             <a>a link to another node</a>
-    //                             <hr />
-    //                         </div>
-    //                         <div>
-    //                             <a>a link to another node</a>
-    //                             <hr />
-    //                         </div>
-    //                         <div>
-    //                             <button>New +</button>
-    //                         </div>
-    //                     </div>
-    //                 </div>
-    //             </InfoBox>
-    //         )}
-
-    //     </>
-    // }
+    @action
+    private handleInfoWindowClose = () => {
+        if (this.infoWindowOpen) {
+            this.infoWindowOpen = false;
+        }
+        this.infoWindowOpen = false;
+        this.selectedPlace = undefined;
+    }
 
     @action
     private addMarker = (location: google.maps.LatLng | undefined, map: google.maps.Map) => {
@@ -270,38 +238,26 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         });
     }
 
-    // @action
-    // private renderMarkerToMap = (marker: Doc) => {
-    //     const id = StrCast(marker.id);
-    //     const lat = NumCast(marker.lat);
-    //     const lng = NumCast(marker.lng);
-
-    //     return <Marker
-    //         key={id}
-    //         position={{ lat: lat, lng: lng }}
-    //         onClick={e => this.markerClickHandler(e, marker)}
-    //     />
-    // }
-
     render() {
         const { Document, fieldKey, isContentActive: active } = this.props;
 
-        return <div className="MapBox">
-            HELLO WORLD!
-            {/*<div className={"MapBox-contents"}
+        return <div className="MapBox" ref={this._ref}>
+            {/* HELLO WORLD! */}
+            <div className={"MapBox-contents"}
                 style={{ pointerEvents: active() ? undefined : "none", overflow: 'hidden' }}
                 onWheel={e => e.stopPropagation()}
                 onPointerDown={e => (e.button === 0 && !e.ctrlKey) && e.stopPropagation()} >
-                // {/* <LoadScript
+                {/* // {/* <LoadScript
                 //     googleMapsApiKey={process.env.GOOGLE_MAPS!}
                 //     libraries={['places', 'drawing']}
-                // > 
+                // >  */}
                 <div className="map-wrapper">
                     <GoogleMap
                         mapContainerStyle={mapContainerStyle}
                         zoom={this.zoom}
                         center={this.center}
                         onLoad={map => this.loadHandler(map)}
+                        options={mapOptions}
                     >
                         <Autocomplete
                             onLoad={this.setSearchBox}
@@ -309,53 +265,42 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                             <input ref={this.inputRef} className="searchbox" type="text" placeholder="Search anywhere:" />
                         </Autocomplete>
 
-                        <div onLoad={this.setButton}>
-                            <div ref={this.buttonRef} className="add-button-UI" >
-                                <div className="add-button-Text">Add Marker</div>
-                            </div>
-                        </div>
-
-                        {this.myPlaces.map(place => (
+                        {this.childDocs.map(place => (
                             <Marker
-                                key={place.id}
-                                position={place.pos}
-                                // onLoad={marker => this.markerLoadHandler(marker, place)}
+                                key={place._markerId}
+                                position={place._latlngLocation}
+                                onLoad={marker => this.markerLoadHandler(marker, place)}
                                 onClick={e => this.markerClickHandler(e, place)}
-                                draggable={true}
-                                onDragEnd={marker => this.handleDragMarker(marker, place)}
                             />
                         ))}
                         {this.infoWindowOpen && this.selectedPlace && (
-                            <InfoBox
-                                // anchor={this.markerMap[this.selectedPlace.id]}
-                                // onCloseClick={this.handleInfoWindowClose}
-                                position={this.selectedPlace.pos}
-                            // options={{ enableEventPropagation: true }}
+                            <InfoWindow
+                                anchor={this.markerMap[this.selectedPlace._markerId!]}
+                                onCloseClick={this.handleInfoWindowClose}
                             >
                                 <div style={{ backgroundColor: 'white', opacity: 0.75, padding: 12 }}>
                                     <div style={{ fontSize: 16 }}>
                                         <div>
-                                            <a>a link to another node</a>
+                                            <img src="http://placekitten.com/200/300" />
                                             <hr />
-                                        </div>
-                                        <div>
-                                            <a>a link to another node</a>
+                                            <form>
+                                                <label>Title: </label><br />
+                                                <input type="text" id="fname" name="fname"></input><br />
+                                                <label>Desription: </label><br />
+                                                <textarea style={{ height: 150 }} id="lname" name="lname" placeholder="Notes, a short description of this location, a brief comment, etc."></textarea>
+                                            </form>
                                             <hr />
-                                        </div>
-                                        <div>
-                                            <a>a link to another node</a>
-                                            <hr />
-                                        </div>
-                                        <div>
-                                            <button>New +</button>
+                                            <div>
+                                                <button>New link+</button>
+                                            </div>
                                         </div>
                                     </div>
                                 </div>
-                            </InfoBox>
+                            </InfoWindow>
                         )}
                     </GoogleMap>
                 </div>
-                {/* </LoadScript >
+                {/* {/* </LoadScript > */}
                 <SidebarAnnos ref={this._sidebarRef}
                     {...this.props}
                     fieldKey={this.annotationKey}
@@ -367,7 +312,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                     removeDocument={this.removeDocument}
                     isContentActive={this.isContentActive}
                 />
-        </div >*/}
+            </div >
         </div >;
     }
 
-- 
cgit v1.2.3-70-g09d2

