aboutsummaryrefslogtreecommitdiff
path: root/src/client/views
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views')
-rw-r--r--src/client/views/collections/MapView/CollectionMapView.scss1
-rw-r--r--src/client/views/collections/MapView/CollectionMapView.tsx9
-rw-r--r--src/client/views/nodes/MapBox/MapBox.tsx293
-rw-r--r--src/client/views/nodes/MapBox/MapMarker.tsx (renamed from src/client/views/nodes/MapMarker/MapMarker.tsx)25
4 files changed, 145 insertions, 183 deletions
diff --git a/src/client/views/collections/MapView/CollectionMapView.scss b/src/client/views/collections/MapView/CollectionMapView.scss
index 6ad0f3a92..0dc226c04 100644
--- a/src/client/views/collections/MapView/CollectionMapView.scss
+++ b/src/client/views/collections/MapView/CollectionMapView.scss
@@ -26,6 +26,7 @@
position: absolute;
left: 50%;
margin-left: -120px;
+ margin-top: 5px;
}
}
}
diff --git a/src/client/views/collections/MapView/CollectionMapView.tsx b/src/client/views/collections/MapView/CollectionMapView.tsx
index d7025f6da..1166de61c 100644
--- a/src/client/views/collections/MapView/CollectionMapView.tsx
+++ b/src/client/views/collections/MapView/CollectionMapView.tsx
@@ -14,7 +14,7 @@ import React = require("react");
import requestPromise = require("request-promise");
import ReactDOM from 'react-dom';
import { DragManager } from '../../../util/DragManager';
-import { MapMarker } from '../../nodes/MapMarker/MapMarker';
+import { MapMarker } from '../../nodes/MapBox/MapMarker';
/**
@@ -60,8 +60,9 @@ const drawingManager = new google.maps.drawing.DrawingManager({
position: google.maps.ControlPosition.TOP_RIGHT,
drawingModes: [
google.maps.drawing.OverlayType.MARKER,
- google.maps.drawing.OverlayType.CIRCLE,
- google.maps.drawing.OverlayType.POLYLINE,
+ // 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,
],
},
});
@@ -83,11 +84,9 @@ export default class CollectionMapView extends CollectionSubView<MapSchema, Part
@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);
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 >;
}
diff --git a/src/client/views/nodes/MapMarker/MapMarker.tsx b/src/client/views/nodes/MapBox/MapMarker.tsx
index d87fd1b11..34057cf48 100644
--- a/src/client/views/nodes/MapMarker/MapMarker.tsx
+++ b/src/client/views/nodes/MapBox/MapMarker.tsx
@@ -7,17 +7,26 @@ import { Doc, DocListCast, Opt } from "../../../../fields/Doc";
import { documentSchema } from "../../../../fields/documentSchemas";
import { Id } from "../../../../fields/FieldSymbols";
import { createSchema, makeInterface } from "../../../../fields/Schema";
+import { Cast, NumCast } from "../../../../fields/Types";
import { CurrentUserUtils } from "../../../util/CurrentUserUtils";
import { DragManager } from "../../../util/DragManager";
+import { CollectionViewType } from "../../collections/CollectionView";
+import { TabDocView } from "../../collections/TabDocView";
import { ViewBoxAnnotatableProps, ViewBoxAnnotatableComponent } from "../../DocComponent";
import { AnchorMenu } from "../../pdf/AnchorMenu";
import { FieldView, FieldViewProps } from "../FieldView";
import { FormattedTextBox } from "../formattedText/FormattedTextBox";
import { RichTextMenu } from "../formattedText/RichTextMenu";
+import { PresMovement } from "../PresBox";
type MarkerDocument = makeInterface<[typeof documentSchema]>;
const MarkerDocument = makeInterface(documentSchema);
+export type Coordinates = {
+ lat: number,
+ lng: number,
+}
+
@observer
export class MapMarker extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps, MarkerDocument>(MarkerDocument) {
makeLinkAnchor(arg1: string, undefined: undefined, arg3: string) {
@@ -26,19 +35,27 @@ export class MapMarker extends ViewBoxAnnotatableComponent<ViewBoxAnnotatablePro
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(MapMarker, fieldKey); }
private _markerRef: React.RefObject<google.maps.Marker> = React.createRef();
private _disposers: { [name: string]: IReactionDisposer } = {};
- private _latlngLocation!: google.maps.LatLng;
- private _markerId!: number;
+ _latlngLocation!: Coordinates;
+ _markerId!: number;
private _editorView: Opt<EditorView> // we'll see if this becomes useful for marker annotation/create link
@observable _title: string = ""; // the title of the marker
@observable _description: string = ""; // the description of the marker contents
@observable isMarkerActive: boolean = false; // whether the marker is selected (we'll see if we need this)
- @observable associatedDocs: Doc[] = []; // a list of documents with the same/similar geographic coordinates
@observable activeLinks: Doc[] = []; //TBD: what linking data structure looks like
+ @computed get childDocs() { return DocListCast(this.dataDoc[this.fieldKey]); } // a list of documents with the same/similar geographic coordinates
+ @computed get tagDocs() { // might come in handy for filtering
+ const tagDocs: Doc[] = [];
+ for (const doc of this.childDocs) {
+ const tagDoc = Cast(doc.presentationTargetDoc, Doc, null);
+ tagDocs.push(tagDoc);
+ }
+ return tagDocs;
+ }
+
/**
* Methods
*/
-
componentDidMount() { }
componentWillMount() { }