From bc23855777633dfd1caf7237b75c1e8fee88dff4 Mon Sep 17 00:00:00 2001 From: zaultavangar Date: Mon, 11 Dec 2023 20:37:52 -0500 Subject: new updates to map feature --- src/client/documents/Documents.ts | 25 +- src/client/views/nodes/MapBox/MapAnchorMenu.scss | 20 ++ src/client/views/nodes/MapBox/MapAnchorMenu.tsx | 76 ++++-- src/client/views/nodes/MapBox/MapBox.scss | 40 ++- src/client/views/nodes/MapBox/MapBox.tsx | 288 +++++++++++++++------ src/client/views/nodes/MapBox/MapboxApiUtility.ts | 2 + src/client/views/nodes/MapBox/MarkerIcons.tsx | 87 +++++++ .../icon_images/mapbox-marker-icon-20px-blue.png | Bin 0 -> 1623 bytes src/fields/Doc.ts | 2 +- 9 files changed, 438 insertions(+), 102 deletions(-) create mode 100644 src/client/views/nodes/MapBox/MarkerIcons.tsx create mode 100644 src/client/views/nodes/MapBox/icon_images/mapbox-marker-icon-20px-blue.png (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 02794c432..3db9f4f06 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -176,12 +176,14 @@ export class DocumentOptions { _dimUnit?: DIMt = new DimInfo("units of collectionMulti{row,col} element's width or height - 'px' or '*' for pixels or relative units"); latitude?: NUMt = new NumInfo('latitude coordinate for map views', false); longitude?: NUMt = new NumInfo('longitude coordinate for map views', false); - routeCoordinates?: LISTt = new ListInfo("stores a route's/direction's coordinates"); // for a route document, this stores the route's coordiantes + routeCoordinates?: STRt = new StrInfo("stores a route's/direction's coordinates (stringified version)"); // for a route document, this stores the route's coordiantes + markerType?: STRt = new StrInfo('Defines the marker type for a pushpin document'); + markerColor?: STRt= new StrInfo('Defines the marker color for a pushpin document'); map?: STRt = new StrInfo('text location of map'); map_type?: STRt = new StrInfo('type of map view', false); map_zoom?: NUMt = new NumInfo('zoom of a map view', false); wikiData?: STRt = new StrInfo('WikiData ID related to map location'); - description?: STRt = new StrInfo('A description of the document') + description?: STRt = new StrInfo('A description of the document'); _timecodeToShow?: NUMt = new NumInfo('the time that a document should be displayed (e.g., when an annotation shows up as a video plays)', false); _timecodeToHide?: NUMt = new NumInfo('the time that a document should be hidden', false); _width?: NUMt = new NumInfo('displayed width of a document'); @@ -783,6 +785,13 @@ export namespace Docs { options: {}, }, ], + [ + DocumentType.MAPROUTE, + { + layout: { view: CollectionView, dataField: defaultDataKey }, + options: {}, + }, + ], ]); const suffix = 'Proto'; @@ -1139,16 +1148,12 @@ export namespace Docs { documents: Array, options: DocumentOptions, id?: string) { + return InstanceFromProto(Prototypes.get(DocumentType.PUSHPIN), new List(documents), { latitude, longitude, infoWindowOpen, ...options }, id); } - export function MapRouteDocument( - infoWindowOpen: boolean, - documents: Array, - options: DocumentOptions, - id?: string - ) { - return InstanceFromProto(Prototypes.get(DocumentType.MAPROUTE), new List(documents), {infoWindowOpen, ...options}, id) + export function MapRouteDocument(infoWindowOpen: boolean, documents: Array, options: DocumentOptions, id?: string) { + return InstanceFromProto(Prototypes.get(DocumentType.MAPROUTE), new List(documents), { infoWindowOpen, ...options }, id); } // shouldn't ever need to create a KVP document-- instead set the LayoutTemplateString to be a KeyValueBox for the DocumentView (see addDocTab in TabDocView) @@ -2015,4 +2020,4 @@ ScriptingGlobals.add(function generateLinkTitle(link: Doc) { const link_anchor_2title = link.link_anchor_2 && link.link_anchor_2 !== link ? Cast(link.link_anchor_2, Doc, null)?.title : ''; const relation = link.link_relationship || 'to'; return `${link_anchor_1title} (${relation}) ${link_anchor_2title}`; -}); +}); \ No newline at end of file diff --git a/src/client/views/nodes/MapBox/MapAnchorMenu.scss b/src/client/views/nodes/MapBox/MapAnchorMenu.scss index e2fcd78fc..c36d98afe 100644 --- a/src/client/views/nodes/MapBox/MapAnchorMenu.scss +++ b/src/client/views/nodes/MapBox/MapAnchorMenu.scss @@ -103,6 +103,26 @@ } + .customized-marker-container{ + display: flex; + flex-direction: column; + gap: 10px; + + .current-marker-container{ + display: flex; + align-items: center; + gap: 5px; + } + + .all-markers-container{ + display: flex; + align-items: center; + gap: 10px; + flex-wrap: wrap; + max-width: 400px; + } + } + diff --git a/src/client/views/nodes/MapBox/MapAnchorMenu.tsx b/src/client/views/nodes/MapBox/MapAnchorMenu.tsx index fca3998c8..2c2879900 100644 --- a/src/client/views/nodes/MapBox/MapAnchorMenu.tsx +++ b/src/client/views/nodes/MapBox/MapAnchorMenu.tsx @@ -32,6 +32,9 @@ import { Autocomplete, Checkbox, FormControlLabel, TextField } from '@mui/materi import { MapboxApiUtility, TransportationType } from './MapboxApiUtility'; import { MapBox } from './MapBox'; import { List } from '../../../../fields/List'; +import { MapboxColor, MarkerIcons } from './MarkerIcons'; +import { CirclePicker } from 'react-color'; +import { Position } from 'geojson'; type MapAnchorMenuType = 'standard' | 'route' | 'calendar' | 'customize'; @@ -58,9 +61,13 @@ export class MapAnchorMenu extends AntimodeMenu { public DisplayRoute: (routeInfoMap: Record | undefined, type: TransportationType) => void = unimplementedFunction; public HideRoute: () => void = unimplementedFunction; - public AddNewRouteToMap: (coordinates: List, origin: string, destination: string) => void = unimplementedFunction; + public AddNewRouteToMap: (coordinates: Position[], origin: string, destination: string) => void = unimplementedFunction; public CreatePin: (feature: any) => void = unimplementedFunction; + public UpdateMarkerColor: (color: string) => void = unimplementedFunction; + public UpdateMarkerIcon: (iconKey: string) => void = unimplementedFunction; + + private allMapPinDocs: Doc[] = []; @@ -151,11 +158,13 @@ export class MapAnchorMenu extends AntimodeMenu { @action CustomizeClick = () => { + this.currentRouteInfoMap = undefined; this.menuType = 'customize'; } @action BackClick = () => { + this.currentRouteInfoMap = undefined; this.menuType = 'standard'; } @@ -238,11 +247,26 @@ export class MapAnchorMenu extends AntimodeMenu { HandleAddRouteClick = () => { if (this.currentRouteInfoMap && this.selectedTransportationType && this.selectedDestinationFeature){ const coordinates = this.currentRouteInfoMap[this.selectedTransportationType].coordinates; - this.AddNewRouteToMap(this.currentRouteInfoMap![this.selectedTransportationType].coordinates, this.title ?? "", this.selectedDestinationFeature.place_name); + console.log(coordinates); + this.AddNewRouteToMap(coordinates, this.title ?? "", this.selectedDestinationFeature.place_name); this.HideRoute(); } } + getMarkerIcon = (): JSX.Element | undefined => { + if (this.pinDoc){ + const markerType = StrCast(this.pinDoc.markerType); + const markerColor = StrCast(this.pinDoc.markerColor); + + if (markerType.startsWith("MAPBOX")){ + return MarkerIcons.getMapboxIcon(markerColor as MapboxColor); + } else { // font awesome icon + return MarkerIcons.getFontAwesomeIcon(markerType, markerColor); + } + } + return undefined; + } + render() { const buttons = ( @@ -325,19 +349,6 @@ export class MapAnchorMenu extends AntimodeMenu { icon={} color={SettingsManager.userColor} /> - } - color={SettingsManager.userColor} - /> - {}} - /> { + } + {this.menuType === 'customize' && +
+
+
Current Marker:
+
+ {this.getMarkerIcon()} +
+
+
+ console.log(color.hex)} + /> +
+
+ {Object.keys(MarkerIcons.FAMarkerIconsMap).map((iconKey) => { + const icon = MarkerIcons.getFontAwesomeIcon(iconKey); + if (icon){ + return ( +
+ {}} + icon={MarkerIcons.getFontAwesomeIcon(iconKey, 'white')} + /> +
+ ) + } + return null; + })} +
+
+
} {buttons} diff --git a/src/client/views/nodes/MapBox/MapBox.scss b/src/client/views/nodes/MapBox/MapBox.scss index 946c6f495..bc2f90fbd 100644 --- a/src/client/views/nodes/MapBox/MapBox.scss +++ b/src/client/views/nodes/MapBox/MapBox.scss @@ -12,8 +12,10 @@ font-size: 17; } .mapBox-searchbar { - // display: flex; - // flex-direction: row; + display: flex; + flex-direction: row; + gap: 5px; + align-items: center; width: calc(100% - 40px); // .editableText-container { @@ -25,6 +27,38 @@ // } } + .mapbox-settings-panel{ + z-index: 900; + padding: 10px 20px; + display: flex; + background-color: rgb(187, 187, 187); + font-size: 1.3em; + flex-direction: column; + align-items: flex-start; + justify-content: center; + gap: 7px; + position: absolute; + border-top-left-radius: 5px; + border-bottom-left-radius: 5px; + + .mapbox-style-select{ + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: center; + gap: 4px; + } + + .mapbox-terrain-selection{ + display: flex; + flex-direction: row; + align-items: center; + justify-content: flex-start; + gap: 4px; + } + + } + .mapbox-geocoding-search-results { z-index: 900; display: flex; @@ -35,6 +69,8 @@ background-color: rgb(187, 187, 187); font-size: 1.4em; padding: 10px; + border-top-right-radius: 5px; + border-bottom-right-radius: 5px; .search-result-container { width: 100%; diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index 2b563faf2..ac926e1fb 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -9,7 +9,7 @@ import * as React from 'react'; import { Doc, DocListCast, Field, LinkedTo, Opt } from '../../../../fields/Doc'; import { DocCss, Highlight } from '../../../../fields/DocSymbols'; import { Id } from '../../../../fields/FieldSymbols'; -import { DocCast, NumCast, StrCast } from '../../../../fields/Types'; +import { Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types'; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../../Utils'; import { Docs, DocUtils } from '../../../documents/Documents'; import { DocumentType } from '../../../documents/DocumentTypes'; @@ -52,11 +52,13 @@ import './MapBox.scss'; import { NumberLiteralType } from 'typescript'; // import { GeocoderControl } from './GeocoderControl'; import mapboxgl, { LngLat, MapLayerMouseEvent } from 'mapbox-gl'; -import { Feature, FeatureCollection } from 'geojson'; +import { Feature, FeatureCollection, GeoJsonProperties, Geometry, LineString, MultiLineString, Position } from 'geojson'; import { MarkerEvent } from 'react-map-gl/dist/esm/types'; import { MapboxApiUtility, TransportationType} from './MapboxApiUtility'; -import { Autocomplete, TextField } from '@mui/material'; +import { Autocomplete, Checkbox, FormControlLabel, TextField } from '@mui/material'; import { List } from '../../../../fields/List'; +import { listSpec } from '../../../../fields/Schema'; +import { IconLookup, faGear } from '@fortawesome/free-solid-svg-icons'; // amongus /** @@ -140,15 +142,17 @@ export class MapBox extends ViewBoxAnnotatableComponent anno.type === DocumentType.MAPROUTE); } - @computed get allRoutesGeoJson() { - const features = this.allRoutes.map(route => { + @computed get allRoutesGeoJson(): FeatureCollection { + const features: Feature[] = this.allRoutes.map(route => { + console.log("Route coords: ", route.coordinates); + const geometry: LineString = { + type: 'LineString', + coordinates: JSON.parse(StrCast(route.coordinates)) + } return { type: 'Feature', properties: {}, - geometry: { - type: 'LineString', - coordinates: route.coordinates - } + geometry: geometry }; }); @@ -771,7 +775,14 @@ export class MapBox extends ViewBoxAnnotatableComponent, origin: string, destination: string) => { + createMapRoute = undoable((coordinates: Position[], origin: string, destination: string) => { + console.log(coordinates); const mapRoute = Docs.Create.MapRouteDocument( false, [], - {title: `${origin} -> ${destination}`, routeCoordinates: coordinates}, + {title: `${origin} -> ${destination}`, routeCoordinates: JSON.stringify(coordinates)}, ); this.addDocument(mapRoute, this.annotationKey); return mapRoute; @@ -800,29 +812,11 @@ export class MapBox extends ViewBoxAnnotatableComponent { - this.mapboxMapViewState = e.viewState; - } - @action addMarkerForFeature = (feature: any) => { @@ -838,6 +832,12 @@ export class MapBox extends ViewBoxAnnotatableComponent { + this.settingsOpen= false; this.featuresFromGeocodeResults = features; }) } @@ -988,6 +989,75 @@ export class MapBox extends ViewBoxAnnotatableComponent { + this.featuresFromGeocodeResults = []; + this.settingsOpen = !this.settingsOpen; + } + + @action + changeMapStyle = (e: React.ChangeEvent) => { + this.mapStyle = `mapbox://styles/mapbox/${e.target.value}` + } + + @action + onMapMove = (e: ViewStateChangeEvent) => { + this.mapboxMapViewState = e.viewState; + } + + @action + toggleShowTerrain = () => { + this.showTerrain = !this.showTerrain; + } + + @action + onBearingChange = (e: React.ChangeEvent) => { + const newVal = parseInt(e.target.value) + if (!isNaN(newVal) && newVal >= 0){ + this.mapboxMapViewState = { + ...this.mapboxMapViewState, + bearing: parseInt(e.target.value) + } + } + } + + @action + onPitchChange = (e: React.ChangeEvent) => { + const newVal = parseInt(e.target.value); + if (!isNaN(newVal) && newVal >= 0){ + this.mapboxMapViewState = { + ...this.mapboxMapViewState, + pitch: parseInt(e.target.value) + } + } + } + + + static _firstRender = true; static _rerenderDelay = 500; @@ -1029,51 +1099,59 @@ export class MapBox extends ViewBoxAnnotatableComponent this.handleSearchChange(e.target.value)} /> - {/* this.handleSearchChange(searchText)} - onChange={(e, selectedOption) => { - this.handleSearchChange(""); // clear input - this.addMarkerForFeature(selectedOption); - }} - options={this.featuresFromGeocodeResults - .filter(feature => feature.place_name) - .map(feature => feature)} - getOptionLabel={(feature) => feature.place_name} - renderInput={(params) => ( - - )} - /> */} - {/* typeof newText === 'string' && this.handleSearchChange(newText)} - // onEnter={e => this.bingSearch()} - onEnter={e => {}} - height={32} - // placeholder={this.bingSearchBarContents || 'Enter a location'} - placeholder='Enter a location' - textAlign="center" - /> */} - {/*