From 9d48c95e5a556f5be4abde83d9443e384a33197c Mon Sep 17 00:00:00 2001
From: Eric <ericmabr@gmail.com>
Date: Mon, 10 Jul 2023 14:26:37 -0400
Subject: Location metadata synced and reactions working

---
 src/client/views/nodes/MapBox/MapBox.tsx | 264 +++++++++++++++++--------------
 1 file changed, 148 insertions(+), 116 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 7d3dcb811..f1f6b0756 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -4,17 +4,19 @@ import BingMapsReact from 'bingmaps-react';
 import { EditableText } from 'browndash-components';
 import e from 'connect-flash';
 import { truncateSync } from 'fs';
-import { action, computed, IReactionDisposer, observable, ObservableMap, runInAction } from 'mobx';
+import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, 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 { ScriptField } from '../../../../fields/ScriptField';
 import { NumCast, StrCast } from '../../../../fields/Types';
-import { emptyFunction, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../../Utils';
+import { emptyFunction, returnAll, returnEmptyDoclist, returnEmptyString, returnFalse, returnIgnore, returnOne, setupMoveUpEvents, Utils } from '../../../../Utils';
 import { Docs } from '../../../documents/Documents';
 import { DragManager } from '../../../util/DragManager';
 import { SnappingManager } from '../../../util/SnappingManager';
+import { Transform } from '../../../util/Transform';
 import { UndoManager } from '../../../util/UndoManager';
 import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm';
 import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocComponent';
@@ -23,8 +25,9 @@ import { MarqueeAnnotator } from '../../MarqueeAnnotator';
 import { AnchorMenu } from '../../pdf/AnchorMenu';
 import { Annotation } from '../../pdf/Annotation';
 import { SidebarAnnos } from '../../SidebarAnnos';
+import { DocumentView } from '../DocumentView';
 import { FieldView, FieldViewProps } from '../FieldView';
-import { PinProps } from '../trails';
+import { PinProps, PresBox } from '../trails';
 import './MapBox.scss';
 import { MapBoxInfoWindow } from './MapBoxInfoWindow';
 // amongus
@@ -126,11 +129,23 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     static _hadSelection: boolean = false;
     private _sidebarRef = React.createRef<SidebarAnnos>();
     private _ref: React.RefObject<HTMLDivElement> = React.createRef();
-
+    private _disposer: {[key:string]:IReactionDisposer} = {}
     componentDidMount() {
         this.props.setContentView?.(this);
+        this._disposer.location = reaction(() => ({lat:this.rootDoc.latitude, lng:this.rootDoc.longitude}), 
+        (locationObject) => {
+
+            //TODO: SAVE ZOOM? VIEW STYLE?
+            this._bingMap.current.setView({
+                center: new this.MicrosoftMaps.Location(locationObject.lat, locationObject.lng),
+            });
+
+        }, {fireImmediately: true});
     }
 
+    componentWillUnmount(): void {
+        Object.keys(this._disposer).forEach(key => this._disposer[key]?.())
+    }
     // iterate allMarkers to size, center, and zoom map to contain all markers
     private fitBounds = (map: google.maps.Map) => {
         const curBounds = map.getBounds() ?? new window.google.maps.LatLngBounds();
@@ -240,7 +255,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             map: map,
         });
         map.panTo(position);
-        const mapMarker = Docs.Create.MapMarkerDocument(NumCast(position.lat()), NumCast(position.lng()), false, [], {});
+        const mapMarker = Docs.Create.PushpinDocument(NumCast(position.lat()), NumCast(position.lng()), false, [], {});
         this.addDocument(mapMarker, this.annotationKey);
     };
 
@@ -368,7 +383,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 if (existingMarker) {
                     Doc.AddDocToList(existingMarker, 'data', doc);
                 } else {
-                    const marker = Docs.Create.MapMarkerDocument(NumCast(doc.lat), NumCast(doc.lng), false, [doc], {});
+                    const marker = Docs.Create.PushpinDocument(NumCast(doc.lat), NumCast(doc.lng), false, [doc], {});
                     this.addDocument(marker, this.annotationKey);
                 }
             }
@@ -512,7 +527,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         );
     }
 
-    getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => AnchorMenu.Instance?.GetAnchor(this._savedAnnotations, addAsAnnotation) ?? this.rootDoc;
+    // Old get anchor function
+    // getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => AnchorMenu.Instance?.GetAnchor(this._savedAnnotations, addAsAnnotation) ?? this.rootDoc;
 
     /**
      * render contents in allMapMarkers (e.g. images with exifData) into google maps as map marker
@@ -592,57 +608,78 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         entityType: 'PopulatedPlace',
     };
 
-    @action
-    updateView = () => {
-        this._bingMap.current.setView({
-            center: new this.MicrosoftMaps.Location(this.dataDoc.latitude, this.dataDoc.longitude),
-            // zoom: location
-        });
-    };
+    
 
+    /*
+     * Creates Pushpin doc and adds it to the list of annotations
+     */
     @action
     createPushpin = (latitude: number, longitude: number) => {
         // Stores the pushpin as a MapMarkerDocument
-        const mapMarker = Docs.Create.MapMarkerDocument(NumCast(latitude), NumCast(longitude), false, [], {});
+        const mapMarker = Docs.Create.PushpinDocument(NumCast(latitude), NumCast(longitude), false, [], {});
         this.addDocument(mapMarker, this.annotationKey);
-        mapMarker.infoWindowOpen = true;
-    };
 
+        // mapMarker.infoWindowOpen = true;
+    };
 
-    selectedPin: Doc | undefined;
-    infobox: any;
+    /*
+     * Pushpin onclick
+     */
     pushpinClicked = (pin:Doc) => {
-        pin["infoWindowOpen"] = 
-        // true
-        !pin.infoWindowOpen;
-        // if (this.selectedPin){
-        //     this.selectedPin.infoWindowOpen = false;
-        //     this.selectedPin = pin
-        // }
-        // else{
-        //     this.selectedPin = pin
-        // }
-        this.addAllPins();
+        pin.infoWindowOpen = !pin.infoWindowOpen;
+
+    //     @action
+    // onPointerDown = (e: React.PointerEvent) => {
+    //     if (e.button === 2 || e.ctrlKey) {
+    //         AnchorMenu.Instance.Status = 'annotation';
+    //         AnchorMenu.Instance.Delete = this.deleteAnnotation.bind(this);
+    //         AnchorMenu.Instance.Pinned = false;
+    //         AnchorMenu.Instance.PinToPres = this.pinToPres;
+    //         AnchorMenu.Instance.MakeTargetToggle = this.makeTargretToggle;
+    //         AnchorMenu.Instance.IsTargetToggler = this.isTargetToggler;
+    //         AnchorMenu.Instance.ShowTargetTrail = () => this.showTargetTrail(this.annoTextRegion);
+    //         AnchorMenu.Instance.jumpTo(e.clientX, e.clientY, true);
+    //         e.stopPropagation();
+    //     } else if (e.button === 0) {
+    //         e.stopPropagation();
+    //         LinkFollower.FollowLink(undefined, this.annoTextRegion, false);
+    //     }
+    // };
+
+        // TODO: UPDATE FOR DASHDOC SELECTION
     };
 
     /**
-     * Returns a list of MapMarkerDocument
+     * Returns a list of Pushpin docs
      */
     @computed get allMapPushpins() {
         return DocListCast(this.dataDoc[this.annotationKey]);
     }
+
     /**
-     * Map OnClick create pushpin
+     * Map OnClick ~> creates a pushpin
      */
     @action
     mapOnClick = (e: { location: { latitude: any; longitude: any } }) => {
         if (this.placePinOn) {
             this.createPushpin(e.location.latitude, e.location.longitude);
-            this.addAllPins();
+            // this.addAllPins();
             this.placePinOn = false;
         }
     };
 
+
+    
+
+    /*
+     * Updates values of layout doc to match the current map
+     */
+    @action
+    updateLayout = () => {
+            this.dataDoc.latitude = this._bingMap.current.getCenter().latitude;
+            this.dataDoc.longitude = this._bingMap.current.getCenter().longitude;
+    };
+
     searched_pin: any;
     /*
      * For Bing Maps
@@ -651,20 +688,20 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
      **/
     @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();
+        // Centers on the searched location
+        this._bingMap.current.setView({
+            center: new this.MicrosoftMaps.Location(this.dataDoc.latitude, this.dataDoc.longitude),
+        });
+        this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'click', this.mapOnClick);
+        this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'viewchangeend', this.updateLayout);
+
 
+        
         // 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) {
@@ -672,82 +709,65 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             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
+     * Adds all pushpins in dataDoc onto the map (render) - OLD & UNUSED
      */
     @action
     addAllPins = () => {
         this._bingMap.current.entities.clear();
         if (this.searched_pin) this._bingMap.current.entities.push(this.searched_pin);
-        
-        this.allMapPushpins.map(pin => this.createPushPin(pin));
-
-        
+        // this.allMapPushpins.map(pin => this.addPushpin(pin));
     };
 
-    @action
-    createPushPin = (pin: any) => {
-        var pushPin:any;
-        if (pin.infoWindowOpen){
-            pushPin = new this.MicrosoftMaps.Pushpin(new this.MicrosoftMaps.Location(pin.lat, pin.lng), {
-                // title: this.bingSearchBarContents,
-                // subTitle: 'subtitle here',
-                // text: '1',
-                // height: '50px'
+    /*
+     * Returns doc w/ relevant info
+     */
+    getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => {
+        const anchor =
+            Docs.Create.MapanchorDocument({
+                title: 'MapAnchor:' + this.rootDoc.title,
+                presLat: NumCast(this.dataDoc.latitude),
+                presLong: NumCast(this.dataDoc.longitude),
+                // presTransition: 1000,
+                unrendered: true,
+                annotationOn: this.rootDoc,
             });
+        if (anchor) {
+            if (!addAsAnnotation) anchor.backgroundColor = 'transparent';
+            /* addAsAnnotation &&*/ this.addDocument(anchor);
+            PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), map: true } }, this.rootDoc);
+            return anchor;
         }
-        else{
-            pushPin = new this.MicrosoftMaps.Pushpin(new this.MicrosoftMaps.Location(pin.lat, pin.lng), {icon: 'http://icons.iconarchive.com/icons/icons-land/vista-map-markers/24/Map-Marker-Marker-Outside-Chartreuse-icon.png'});
-        }
-        
-        this._bingMap.current.entities.push(pushPin);
-
-        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);
-        }
+        return this.rootDoc;
+    };
 
-        //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;
+    /*
+    *   Input: pin doc
+    *   Adds MicrosoftMaps Pushpin to the map (render)
+    */
+    @action
+    addPushpin = (pin: Doc) => {
+        const pushPin = pin.infoWindowOpen ? new this.MicrosoftMaps.Pushpin(new this.MicrosoftMaps.Location(pin.lat, pin.lng), {}): new this.MicrosoftMaps.Pushpin(new this.MicrosoftMaps.Location(pin.lat, pin.lng), {icon: 'http://icons.iconarchive.com/icons/icons-land/vista-map-markers/24/Map-Marker-Marker-Outside-Chartreuse-icon.png'});
 
-        //Add a click event handler to the pushpin.
-        // For bing maps infobox
-        // this.MicrosoftMaps.Events.addHandler(pushPin, 'click', this.pushpinClicked);
+        
+        this._bingMap.current.entities.push(pushPin);
 
         // For our infowindow
         this.MicrosoftMaps.Events.addHandler(pushPin, 'click', (e: any) => this.pushpinClicked(pin));
-        // this.MicrosoftMaps.Events.addHandler(pushPin, 'mouseover', (e:any) => this.onHover(e));
-    };
+    }
+
+    /*
+    *   Input: pin doc
+    *   Adds MicrosoftMaps Pushpin to the map (render)
+    */
+    @action
+    removePushpin = (pin:any)=>{
+        this._bingMap.current.entities.clear();
+        this.allMapPushpins
+        this.allMapPushpins.map(pin => this.addPushpin(pin));
+    }
 
     /**
      * View options for bing maps
@@ -809,25 +829,37 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                     {this.placePinOn ? <input type="button" value="Place Pin Mode On" onClick={this.togglePlacePin} /> : <input type="button" value="Place Pin Mode Off" onClick={this.togglePlacePin} />}
 
                     <BingMapsReact onMapReady={this.bingMapReady} bingMapsKey={bingApiKey} height="100%" mapOptions={this.bingMapOptions} width="100%" viewOptions={this.bingViewOptions}>
+                    </BingMapsReact>
+                    <div>
                         {this.allMapPushpins
-                            .filter(marker => marker.infoWindowOpen)
-                            .map(marker => (
-                                // console.log('this is a marker window')
-                                <MapBoxInfoWindow
-                                    key={marker[Id]}
+                            .map(pushpin => (
+                                <DocumentView
                                     {...this.props}
-                                    setContentView={emptyFunction}
-                                    place={marker}
-                                    markerMap={this.markerMap}
-                                    PanelWidth={this.infoWidth}
-                                    PanelHeight={this.infoHeight}
-                                    moveDocument={this.moveDocument}
-                                    isAnyChildContentActive={this.isAnyChildContentActive}
-                                    whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
-                                />
+                                    
+                                    // HOW DO I PASS IN pushpin???
+                                    // HOW DO I MAKE SURE IT KNOWS TO MAKE MapPushpinBox???
+                                    Document={pushpin}
+                                    DataDoc={undefined}
+                                    PanelWidth={returnOne}
+                                    PanelHeight={returnOne}
+                                    NativeWidth={returnOne} 
+                                    NativeHeight={returnOne}
+                                    onClick={()=>new ScriptField(undefined)}
+                                    onKey={undefined}
+                                    onDoubleClick={undefined}
+                                    onBrowseClick={undefined}
+                                    docFilters={returnEmptyDoclist}
+                                    docRangeFilters={returnEmptyDoclist}
+                                    searchFilterDocs={returnEmptyDoclist}
+                                    isDocumentActive={returnFalse}
+                                    isContentActive={returnFalse}
+                                    addDocTab={returnFalse}
+                                    ScreenToLocalTransform={()=>new Transform(0,0,0)}
+                                    fitContentsToBox={undefined}
+                                    focus={returnOne}
+                        />
                             ))}
-                    </BingMapsReact>
-
+                    </div>
                     {/* <MapBoxInfoWindow
                                     key={Docs.Create.MapMarkerDocument(NumCast(40), NumCast(40), false, [], {})[Id]}
                                     {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight', 'setContentView']).omit}
-- 
cgit v1.2.3-70-g09d2

