diff options
-rw-r--r-- | src/client/documents/Documents.ts | 25 | ||||
-rw-r--r-- | src/client/views/nodes/MapBox/MapAnchorMenu.scss | 20 | ||||
-rw-r--r-- | src/client/views/nodes/MapBox/MapAnchorMenu.tsx | 76 | ||||
-rw-r--r-- | src/client/views/nodes/MapBox/MapBox.scss | 40 | ||||
-rw-r--r-- | src/client/views/nodes/MapBox/MapBox.tsx | 288 | ||||
-rw-r--r-- | src/client/views/nodes/MapBox/MapboxApiUtility.ts | 2 | ||||
-rw-r--r-- | src/client/views/nodes/MapBox/MarkerIcons.tsx | 87 | ||||
-rw-r--r-- | src/client/views/nodes/MapBox/icon_images/mapbox-marker-icon-20px-blue.png | bin | 0 -> 1623 bytes | |||
-rw-r--r-- | src/fields/Doc.ts | 2 |
9 files changed, 438 insertions, 102 deletions
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<Doc>, 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<Doc>, - options: DocumentOptions, - id?: string - ) { - return InstanceFromProto(Prototypes.get(DocumentType.MAPROUTE), new List(documents), {infoWindowOpen, ...options}, id) + export function MapRouteDocument(infoWindowOpen: boolean, documents: Array<Doc>, 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<AntimodeMenuProps> { public DisplayRoute: (routeInfoMap: Record<TransportationType, any> | undefined, type: TransportationType) => void = unimplementedFunction; public HideRoute: () => void = unimplementedFunction; - public AddNewRouteToMap: (coordinates: List<any>, 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<AntimodeMenuProps> { @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<AntimodeMenuProps> { 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 = ( @@ -326,19 +350,6 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> { color={SettingsManager.userColor} /> <IconButton - tooltip="Upload image" // - onPointerDown={this.TriggerFileInputClick} - icon={<FontAwesomeIcon icon={faUpload as IconLookup} />} - color={SettingsManager.userColor} - /> - <input - type="file" - accept="image/*" // Optionally, specify accepted file types - ref={this._fileInputRef} - style={{ display: "none" }} - onChange={() => {}} - /> - <IconButton tooltip="Revert to original" // onPointerDown={this.BackClick} icon={<FontAwesomeIcon icon={faArrowsRotate as IconLookup} />} @@ -469,6 +480,41 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> { } + {this.menuType === 'customize' && + <div className='customized-marker-container'> + <div className='current-marker-container'> + <div>Current Marker: </div> + <div> + {this.getMarkerIcon()} + </div> + </div> + <div className='color-picker-container' style={{marginBottom: '10px'}}> + <CirclePicker + circleSize={15} + circleSpacing={7} + width='100%' + onChange={(color) => console.log(color.hex)} + /> + </div> + <div className='all-markers-container'> + {Object.keys(MarkerIcons.FAMarkerIconsMap).map((iconKey) => { + const icon = MarkerIcons.getFontAwesomeIcon(iconKey); + if (icon){ + return ( + <div key={iconKey} className='marker-icon'> + <IconButton + onPointerDown={() => {}} + icon={MarkerIcons.getFontAwesomeIcon(iconKey, 'white')} + /> + </div> + ) + } + return null; + })} + </div> + <div style={{width: '100%', height:'3px', color: 'white'}}></div> + </div> + } {buttons} </div> , true); 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<ViewBoxAnnotatableProps @computed get allRoutes() { return this.allAnnotations.filter(anno => anno.type === DocumentType.MAPROUTE); } - @computed get allRoutesGeoJson() { - const features = this.allRoutes.map(route => { + @computed get allRoutesGeoJson(): FeatureCollection { + const features: Feature<Geometry, GeoJsonProperties>[] = 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<ViewBoxAnnotatableProps NumCast(longitude), false, [], - {title: location ?? `lat=${latitude},lng=${longitude}`, map: location, description: "", wikiData: wikiData}, + { + title: location ?? `lat=${latitude},lng=${longitude}`, + map: location, + description: "", + wikiData: wikiData, + markerType: 'MAPBOX_MARKER', + markerColor: '#3FB1CE' + }, // { title: map ?? `lat=${latitude},lng=${longitude}`, map: map }, // ,'pushpinIDamongus'+ this.incrementer++ ); @@ -783,11 +794,12 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps }, 'createpin'); @action - createMapRoute = undoable((coordinates: List<any>, 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<ViewBoxAnnotatableProps - @observable - mapboxMapViewState: ViewState = { - zoom: 9, - longitude: -71.41, - latitude: 41.82, - pitch: 0, - bearing: 0, - padding: { - top: 0, - bottom: 0, - left: 0, - right: 0 - } - } + @observable featuresFromGeocodeResults: any[] = []; - @action - onMapMove = (e: ViewStateChangeEvent) => { - this.mapboxMapViewState = e.viewState; - } - @action addMarkerForFeature = (feature: any) => { @@ -838,6 +832,12 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps location, wikiData ) + + if (this._mapRef.current){ + this._mapRef.current.flyTo({ + center: feature.center + }); + } this.featuresFromGeocodeResults = []; } else { @@ -855,6 +855,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps const features = await MapboxApiUtility.forwardGeocodeForFeatures(searchText); if (features){ runInAction(() => { + this.settingsOpen= false; this.featuresFromGeocodeResults = features; }) } @@ -988,6 +989,75 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps + @observable + mapboxMapViewState: ViewState = { + zoom: 9, + longitude: -71.45, + latitude: 41.82, + pitch: 0, + bearing: 0, + padding: { + top: 0, + bottom: 0, + left: 0, + right: 0 + } + } + + @observable + settingsOpen: boolean = false; + + @observable + mapStyle: string = 'mapbox://styles/mapbox/streets-v12' + + @observable + showTerrain: boolean = false; + + @action + toggleSettings = () => { + this.featuresFromGeocodeResults = []; + this.settingsOpen = !this.settingsOpen; + } + + @action + changeMapStyle = (e: React.ChangeEvent<HTMLSelectElement>) => { + 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<HTMLInputElement>) => { + 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<HTMLInputElement>) => { + 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<ViewBoxAnnotatableProps placeholder='Enter a location' onChange={(e) => this.handleSearchChange(e.target.value)} /> - {/* <Autocomplete - fullWidth - id="map-location-searcher" - freeSolo - onInputChange={(e, searchText) => 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) => ( - <TextField - {...params} - placeholder='Enter a location' - /> - )} - /> */} - {/* <EditableText - // editing - setVal={(newText: string | number) => 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" - /> */} - {/* <IconButton - icon={ - <svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="magnifying-glass" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" color="#DFDFDF"> - <path - fill="currentColor" - d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352a144 144 0 1 0 0-288 144 144 0 1 0 0 288z"></path> - </svg> - } - onClick={this.bingSearch} + <IconButton + icon={<FontAwesomeIcon icon={faGear as IconLookup} size='1x'/>} type={Type.TERT} + onClick={(e) => this.toggleSettings()} + /> - <div style={{ width: 30, height: 30 }} ref={this._dragRef} onPointerDown={this.dragToggle}> - <Button tooltip="drag to place a pushpin" icon={<FontAwesomeIcon size={'lg'} icon={'bullseye'} />} /> - </div> */} </div> + {this.settingsOpen && + <div className='mapbox-settings-panel' style={{right: `${0+ this.sidebarWidth()}px`}}> + <div className='mapbox-style-select'> + <div> + Map Style: + </div> + <div> + <select onChange={this.changeMapStyle}> + <option value='streets-v12'>Streets</option> + <option value='outdoors-v12'>Outdoors</option> + <option value='light-v11'>Light</option> + <option value='dark-v11'>Dark</option> + <option value='satellite-v9'>Satellite</option> + <option value='satellite-streets-v12'>Satellite Streets</option> + <option value='navigation-day-v1'>Navigation Day</option> + <option value='navigation-night-v1'>Navigation Night</option> + </select> + </div> + </div> + <div className='mapbox-bearing-selection'> + <div>Bearing: </div> + <input + value={this.mapboxMapViewState.bearing} + min={0} + type='number' + onChange={this.onBearingChange}/> + </div> + <div className='mapbox-pitch-selection'> + <div>Pitch: </div> + <input + value={this.mapboxMapViewState.pitch} + min={0} + type='number' + onChange={this.onPitchChange}/> + </div> + <div className='mapbox-terrain-selection'> + <div>Show terrain: </div> + <input + type='checkbox' + checked={this.showTerrain} + onChange={this.toggleShowTerrain} + /> + </div> + </div> + } + <div className='mapbox-geocoding-search-results'> {this.featuresFromGeocodeResults.length > 0 && ( <React.Fragment> @@ -1107,15 +1185,24 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps }} mapboxAccessToken={MAPBOX_ACCESS_TOKEN} id="mapbox-map" - mapStyle="mapbox://styles/mapbox/streets-v9" + mapStyle={this.mapStyle} style={{height: '100%', width: '100%'}} {...this.mapboxMapViewState} onMove={this.onMapMove} onDblClick={this.handleMapClick} + terrain={this.showTerrain ? { source: 'mapbox-dem', exaggeration: 2.0 } : undefined} > + <Source + id="mapbox-dem" + type="raster-dem" + url="mapbox://mapbox.mapbox-terrain-dem-v1" + tileSize={512} + maxzoom={14} + /> <Source id='temporary-route' type='geojson' data={this.temporaryRouteSource}/> + <Source id='map-routes' type='geojson' data={this.allRoutesGeoJson}/> <Layer id='temporary-route-layer' type='line' @@ -1123,6 +1210,14 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps layout={{"line-join": "round", "line-cap": "round"}} paint={{"line-color": "#36454F", "line-width": 4, "line-dasharray": [1,1]}} /> + <Layer + id='map-routes-layer' + type='line' + source='map-routes' + layout={{"line-join": "round", "line-cap": "round"}} + paint={{"line-color": "#FF0000", "line-width": 4}} + /> + <> {this.allPushpins // .filter(anno => !anno.layout_unrendered) @@ -1219,3 +1314,48 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps ); } } + +{/* <Autocomplete + fullWidth + id="map-location-searcher" + freeSolo + onInputChange={(e, searchText) => 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) => ( + <TextField + {...params} + placeholder='Enter a location' + /> + )} + /> */} + {/* <EditableText + // editing + setVal={(newText: string | number) => 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" + /> */} + {/* <IconButton + icon={ + <svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="magnifying-glass" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" color="#DFDFDF"> + <path + fill="currentColor" + d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352a144 144 0 1 0 0-288 144 144 0 1 0 0 288z"></path> + </svg> + } + onClick={this.bingSearch} + type={Type.TERT} + /> + <div style={{ width: 30, height: 30 }} ref={this._dragRef} onPointerDown={this.dragToggle}> + <Button tooltip="drag to place a pushpin" icon={<FontAwesomeIcon size={'lg'} icon={'bullseye'} />} /> + </div> */}
\ No newline at end of file diff --git a/src/client/views/nodes/MapBox/MapboxApiUtility.ts b/src/client/views/nodes/MapBox/MapboxApiUtility.ts index 80962f435..011b6f72a 100644 --- a/src/client/views/nodes/MapBox/MapboxApiUtility.ts +++ b/src/client/views/nodes/MapBox/MapboxApiUtility.ts @@ -68,6 +68,8 @@ export class MapboxApiUtility { const geometry = routeData.geometry; const coordinates = geometry.coordinates; + console.log(coordinates); + routeInfoMap[transportationTypeKey] = { duration: this.secondsToMinutesHours(routeData.duration), distance: this.metersToMiles(routeData.distance), diff --git a/src/client/views/nodes/MapBox/MarkerIcons.tsx b/src/client/views/nodes/MapBox/MarkerIcons.tsx new file mode 100644 index 000000000..cf50109ac --- /dev/null +++ b/src/client/views/nodes/MapBox/MarkerIcons.tsx @@ -0,0 +1,87 @@ +import { IconProp } from '@fortawesome/fontawesome-svg-core'; +import { faShopify } from '@fortawesome/free-brands-svg-icons'; +import { IconLookup, faBasketball, faBicycle, faBowlFood, faBus, faCameraRetro, faCar, faCartShopping, faFilm, faFootball, faFutbol, faHockeyPuck, faHospital, faHotel, faHouse, faLandmark, faMasksTheater, faMugSaucer, faPersonHiking, faPlane, faSchool, faShirt, faShop, faSquareParking, faStar, faTrainSubway, faTree, faUtensils, faVolleyball } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import React = require('react'); + +export type MapboxColor = 'yellow' | 'red' | 'orange' | 'purple' | 'pink' | 'blue' | 'green'; +type ColorProperties = { + fill: string, + stroke: string +} +type ColorsMap = { + [key in MapboxColor]: ColorProperties; +} + +export class MarkerIcons { + + static getMapboxIcon = (color: string) => { + return ( + <svg xmlns="http://www.w3.org/2000/svg" id="marker" data-name="marker" width="20" height="48" viewBox="0 0 20 35"> + <g id="mapbox-marker-icon"> + <g id="icon"> + <ellipse id="shadow" cx="10" cy="27" rx="9" ry="5" fill="#c4c4c4" opacity="0.3" /> + <g id="mask" opacity="0.3"> + <g id="group"> + <path id="shadow-2" data-name="shadow" fill="#bfbfbf" d="M10,32c5,0,9-2.2,9-5s-4-5-9-5-9,2.2-9,5S5,32,10,32Z" fillRule="evenodd"/> + </g> + </g> + <path id="color" fill={color} strokeWidth="0.5" d="M19.25,10.4a13.0663,13.0663,0,0,1-1.4607,5.2235,41.5281,41.5281,0,0,1-3.2459,5.5483c-1.1829,1.7369-2.3662,3.2784-3.2541,4.3859-.4438.5536-.8135.9984-1.0721,1.3046-.0844.1-.157.1852-.2164.2545-.06-.07-.1325-.1564-.2173-.2578-.2587-.3088-.6284-.7571-1.0723-1.3147-.8879-1.1154-2.0714-2.6664-3.2543-4.41a42.2677,42.2677,0,0,1-3.2463-5.5535A12.978,12.978,0,0,1,.75,10.4,9.4659,9.4659,0,0,1,10,.75,9.4659,9.4659,0,0,1,19.25,10.4Z"/> + <path id="circle" fill="#fff" stroke='white' strokeWidth="0.5" d="M13.55,10A3.55,3.55,0,1,1,10,6.45,3.5484,3.5484,0,0,1,13.55,10Z"/> + </g> + </g> + <rect width="20" height="48" fill="none"/> + </svg> + ) + } + + static getFontAwesomeIcon(key: string, color?: string): JSX.Element | undefined { + const icon: IconProp = MarkerIcons.FAMarkerIconsMap[key]; + + if (icon) { + const iconProps: any = { icon }; + + if (color) { + iconProps.color = color; + } + + return (<FontAwesomeIcon {...iconProps} size='1x' />); + } + + return undefined; + } + + static FAMarkerIconsMap: {[key: string]: IconProp} = { + 'RESTAURANT_ICON': faUtensils, + 'HOTEL_ICON': faHotel, + 'HOUSE_ICON': faHouse, + 'AIRPLANE_ICON': faPlane, + 'CAR_ICON': faCar, + 'BUS_ICON': faBus, + 'TRAIN_ICON': faTrainSubway, + 'BICYCLE_ICON': faBicycle, + 'PARKING_ICON': faSquareParking, + 'PHOTO_ICON': faCameraRetro, + 'CAFE_ICON': faMugSaucer, + 'STAR_ICON': faStar, + 'SHOPPING_CART_ICON': faCartShopping, + 'SHOPIFY_ICON': faShopify, + 'SHOP_ICON': faShop, + 'SHIRT_ICON': faShirt, + 'FOOD_ICON': faBowlFood, + 'LANDMARK_ICON': faLandmark, + 'HOSPITAL_ICON': faHospital, + 'NATURE_ICON': faTree, + 'HIKING_ICON': faPersonHiking, + 'SOCCER_ICON': faFutbol, + 'VOLLEYBALL_ICON': faVolleyball, + 'BASKETBALL_ICON': faBasketball, + 'HOCKEY_ICON': faHockeyPuck, + 'FOOTBALL_ICON': faFootball, + 'SCHOOL_ICON': faSchool, + 'THEATER_ICON': faMasksTheater, + 'FILM_ICON': faFilm + } + + +}
\ No newline at end of file diff --git a/src/client/views/nodes/MapBox/icon_images/mapbox-marker-icon-20px-blue.png b/src/client/views/nodes/MapBox/icon_images/mapbox-marker-icon-20px-blue.png Binary files differnew file mode 100644 index 000000000..8b686e2aa --- /dev/null +++ b/src/client/views/nodes/MapBox/icon_images/mapbox-marker-icon-20px-blue.png diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 084cb872a..1678d9012 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -1598,4 +1598,4 @@ ScriptingGlobals.add(function setDocFilter(container: Doc, key: string, value: a }); ScriptingGlobals.add(function setDocRangeFilter(container: Doc, key: string, range: number[]) { Doc.setDocRangeFilter(container, key, range); -}); +});
\ No newline at end of file |