diff --git a/src/App.module.css b/src/App.module.css index 3e390460..6fdc6671 100644 --- a/src/App.module.css +++ b/src/App.module.css @@ -188,3 +188,20 @@ .sidebarOpenButton:hover svg { fill: black; } + +.drawIcon { + position: absolute; + right: 62px; + top: 10px; + background-color: white; + + padding: 4px; + width: 34px; + height: 34px; +} + +.drawIcon svg { + color: gray; + width: 100%; + height: 100%; +} diff --git a/src/App.tsx b/src/App.tsx index 92e9ef7d..a2dbeb92 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -43,6 +43,9 @@ import PlainButton from '@/PlainButton' import useAreasLayer from '@/layers/UseAreasLayer' import useExternalMVTLayer from '@/layers/UseExternalMVTLayer' import LocationButton from '@/map/LocationButton' +import DrawIcon from './map/gesture.svg' +import Dispatcher from '@/stores/Dispatcher' +import { DrawHandfreeQueryPoints, ToggleRoutingGraph } from '@/actions/Actions' export const POPUP_CONTAINER_ID = 'popup-container' export const SIDEBAR_CONTENT_ID = 'sidebar-content' @@ -105,7 +108,13 @@ export default function App() { useAreasLayer(map, settings.drawAreasEnabled, query.customModelStr, query.customModelEnabled) useRoutingGraphLayer(map, mapOptions.routingGraphEnabled) useUrbanDensityLayer(map, mapOptions.urbanDensityEnabled) - usePathsLayer(map, route.routingResult.paths, route.selectedPath, query.queryPoints) + usePathsLayer( + map, + route.routingResult.paths, + route.selectedPath, + query.queryPoints, + settings.drawHandfreeQueryPointsEnabled + ) useQueryPointsLayer(map, query.queryPoints) usePathDetailsLayer(map, pathDetails) const isSmallScreen = useMediaQuery({ query: '(max-width: 44rem)' }) @@ -123,6 +132,7 @@ export default function App() { error={error} encodedValues={info.encoded_values} drawAreas={settings.drawAreasEnabled} + drawHandfreeQueryPoints={settings.drawHandfreeQueryPointsEnabled} /> ) : ( )} @@ -148,9 +159,19 @@ interface LayoutProps { error: ErrorStoreState encodedValues: object[] drawAreas: boolean + drawHandfreeQueryPoints: boolean } -function LargeScreenLayout({ query, route, map, error, mapOptions, encodedValues, drawAreas }: LayoutProps) { +function LargeScreenLayout({ + query, + route, + map, + error, + mapOptions, + encodedValues, + drawAreas, + drawHandfreeQueryPoints, +}: LayoutProps) { const [showSidebar, setShowSidebar] = useState(true) const [showCustomModelBox, setShowCustomModelBox] = useState(false) return ( @@ -200,6 +221,13 @@ function LargeScreenLayout({ query, route, map, error, mapOptions, encodedValues
+
Dispatcher.dispatch(new DrawHandfreeQueryPoints(!drawHandfreeQueryPoints))} + > + +
@@ -213,7 +241,16 @@ function LargeScreenLayout({ query, route, map, error, mapOptions, encodedValues ) } -function SmallScreenLayout({ query, route, map, error, mapOptions, encodedValues, drawAreas }: LayoutProps) { +function SmallScreenLayout({ + query, + route, + map, + error, + mapOptions, + encodedValues, + drawAreas, + drawHandfreeQueryPoints, +}: LayoutProps) { return ( <>
@@ -231,6 +268,13 @@ function SmallScreenLayout({ query, route, map, error, mapOptions, encodedValues
+
Dispatcher.dispatch(new DrawHandfreeQueryPoints(!drawHandfreeQueryPoints))} + > + +
diff --git a/src/actions/Actions.ts b/src/actions/Actions.ts index 4278d395..1089d6a1 100644 --- a/src/actions/Actions.ts +++ b/src/actions/Actions.ts @@ -240,7 +240,15 @@ export class InstructionClicked implements Action { export class ToggleDistanceUnits implements Action {} -export class DrawAreas implements Action { +export class DrawCustomModelAreas implements Action { + readonly enabled: boolean + + constructor(enabled: boolean) { + this.enabled = enabled + } +} + +export class DrawHandfreeQueryPoints implements Action { readonly enabled: boolean constructor(enabled: boolean) { diff --git a/src/api/Api.ts b/src/api/Api.ts index afd19f6c..588d41cb 100644 --- a/src/api/Api.ts +++ b/src/api/Api.ts @@ -229,7 +229,7 @@ export class ApiImpl implements Api { const routeNumber = this.routeCounter++ this.mapMatch(args) - // this.route(args) + // this.route(args) .then(result => { if (routeNumber > this.lastRouteNumber) { this.lastRouteNumber = routeNumber diff --git a/src/layers/UsePathsLayer.tsx b/src/layers/UsePathsLayer.tsx index 007cfe37..d99206e6 100644 --- a/src/layers/UsePathsLayer.tsx +++ b/src/layers/UsePathsLayer.tsx @@ -7,7 +7,7 @@ import VectorSource from 'ol/source/Vector' import { GeoJSON } from 'ol/format' import { Stroke, Style } from 'ol/style' import { fromLonLat } from 'ol/proj' -import { Draw, Select } from 'ol/interaction' +import { Draw, Modify, Select, Snap } from 'ol/interaction' import { click, primaryAction } from 'ol/events/condition' import Dispatcher from '@/stores/Dispatcher' import { SetQueryPoints, SetSelectedPath } from '@/actions/Actions' @@ -22,10 +22,18 @@ const selectedPathLayerKey = 'selectedPathLayer' const accessNetworkLayerKey = 'accessNetworkLayer' const handDrawQueryPointsLayerKey = 'handDrawQueryPointsLayer' -export default function usePathsLayer(map: Map, paths: Path[], selectedPath: Path, queryPoints: QueryPoint[]) { +export default function usePathsLayer( + map: Map, + paths: Path[], + selectedPath: Path, + queryPoints: QueryPoint[], + drawFreehandQueryPoints: boolean +) { useEffect(() => { - removeHandDrawQueryPointsLayers(map) - addHandDrawQueryPointLayer(map) + removeDrawHandfreeQueryPointsLayers(map) + + if (drawFreehandQueryPoints) addDrawFreehandQueryPointsLayer(map) + else removeDrawHandfreeQueryPointsLayers(map) removeCurrentPathLayers(map) addUnselectedPathsLayer( @@ -36,9 +44,9 @@ export default function usePathsLayer(map: Map, paths: Path[], selectedPath: Pat addAccessNetworkLayer(map, selectedPath, queryPoints) return () => { removeCurrentPathLayers(map) - removeHandDrawQueryPointsLayers(map) + removeDrawHandfreeQueryPointsLayers(map) } - }, [map, paths, selectedPath]) + }, [map, paths, selectedPath, drawFreehandQueryPoints]) } function removeCurrentPathLayers(map: Map) { @@ -48,14 +56,20 @@ function removeCurrentPathLayers(map: Map) { .forEach(l => map.removeLayer(l)) } -function removeHandDrawQueryPointsLayers(map: Map) { +function removeDrawHandfreeQueryPointsLayers(map: Map) { + map.getInteractions() + .getArray() + .forEach(i => { + if ('gh:draw_handfree' == i.get('source') && i instanceof Draw) i.setActive(false) + }) + map.getLayers() .getArray() .filter(l => l.get(handDrawQueryPointsLayerKey)) .forEach(l => map.removeLayer(l)) } -function addHandDrawQueryPointLayer(map: Map) { +function addDrawFreehandQueryPointsLayer(map: Map) { const source = new VectorSource() // TODO NOW cache style @@ -87,7 +101,7 @@ function addHandDrawQueryPointLayer(map: Map) { return [style] }, }) - + vectorLayer.set(handDrawQueryPointsLayerKey, true) map.addLayer(vectorLayer) const draw = new Draw({ @@ -98,8 +112,7 @@ function addHandDrawQueryPointLayer(map: Map) { // we handle this later // maxPoints: 200, - /* TODO how to move the map? */ - // freehand: false, + freehand: true, source: source, type: 'LineString', }) @@ -149,7 +162,7 @@ function addHandDrawQueryPointLayer(map: Map) { } return false }) - + draw.set('source', 'gh:draw_handfree') map.addInteraction(draw) } diff --git a/src/map/gesture.svg b/src/map/gesture.svg new file mode 100644 index 00000000..c87aca70 --- /dev/null +++ b/src/map/gesture.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/sidebar/CustomModelBox.tsx b/src/sidebar/CustomModelBox.tsx index 92e9c6b6..7c4f1b90 100644 --- a/src/sidebar/CustomModelBox.tsx +++ b/src/sidebar/CustomModelBox.tsx @@ -6,7 +6,13 @@ import styles from '@/sidebar/CustomModelBox.module.css' import { useCallback, useEffect, useRef, useState } from 'react' import { create } from 'custom-model-editor/src/index' import Dispatcher from '@/stores/Dispatcher' -import { ClearRoute, DismissLastError, DrawAreas, SetCustomModel, SetCustomModelEnabled } from '@/actions/Actions' +import { + ClearRoute, + DismissLastError, + DrawCustomModelAreas, + SetCustomModel, + SetCustomModelEnabled, +} from '@/actions/Actions' import { tr } from '@/translation/Translation' import PlainButton from '@/PlainButton' import { customModel2prettyString, customModelExamples } from '@/sidebar/CustomModelExamples' @@ -101,7 +107,7 @@ export default function CustomModelBox({ className={styles.drawAreas} title={tr('draw_areas_enabled')} style={{ color: drawAreas ? '' : 'lightgray' }} - onClick={() => Dispatcher.dispatch(new DrawAreas(!drawAreas))} + onClick={() => Dispatcher.dispatch(new DrawCustomModelAreas(!drawAreas))} > {drawAreas ? : } diff --git a/src/stores/SettingsStore.ts b/src/stores/SettingsStore.ts index 1e57e15c..4714af28 100644 --- a/src/stores/SettingsStore.ts +++ b/src/stores/SettingsStore.ts @@ -1,11 +1,16 @@ import Store from '@/stores/Store' import { Action } from '@/stores/Dispatcher' -import { DrawAreas, SetCustomModelEnabled, ToggleDistanceUnits } from '@/actions/Actions' +import { + DrawCustomModelAreas, + DrawHandfreeQueryPoints, + SetCustomModelEnabled, + ToggleDistanceUnits, +} from '@/actions/Actions' export interface Settings { showDistanceInMiles: boolean drawAreasEnabled: boolean - handDrawQueryPointsEnabled: boolean + drawHandfreeQueryPointsEnabled: boolean } export default class SettingsStore extends Store { @@ -13,7 +18,7 @@ export default class SettingsStore extends Store { super({ showDistanceInMiles: false, drawAreasEnabled: false, - handDrawQueryPointsEnabled: true, + drawHandfreeQueryPointsEnabled: false, }) } @@ -29,7 +34,12 @@ export default class SettingsStore extends Store { ...state, drawAreasEnabled: false, } - } else if (action instanceof DrawAreas) { + } else if (action instanceof DrawHandfreeQueryPoints) { + return { + ...state, + drawHandfreeQueryPointsEnabled: action.enabled, + } + } else if (action instanceof DrawCustomModelAreas) { return { ...state, drawAreasEnabled: action.enabled,