Skip to content

Commit

Permalink
fix marker draggability after map size change
Browse files Browse the repository at this point in the history
Oddly, the map would pan with the marker drag after switching to
fullscreen mode, effectively rendering the marker almost immovable.
  • Loading branch information
warm-coolguy committed Mar 14, 2024
1 parent abc45ae commit 426176b
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 83 deletions.
4 changes: 4 additions & 0 deletions packages/plugins/Pins/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# CHANGELOG

## 1.3.1

- Fix: The map dragged along with the pin in some situations, rendering the pin effectively immovable. This has been fixed.

## 1.3.0

- Feature: Pins can now be re-initialized with the `setupInitial` action. This is an advanced feature currently only available when coding clients.
Expand Down
18 changes: 18 additions & 0 deletions packages/plugins/Pins/src/store/getters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { PolarGetterTree } from '@polar/lib-custom-types'
import { generateSimpleGetters } from '@repositoryname/vuex-generators'
import { PinsGetters, PinsState } from '../types'
import { getInitialState } from './state'

const getters: PolarGetterTree<PinsState, PinsGetters> = {
...generateSimpleGetters(getInitialState()),
toZoomLevel(_, __, ___, rootGetters) {
return (rootGetters.configuration.pins || {}).toZoomLevel || 0
},
atZoomLevel(_, __, ___, rootGetters) {
return (
(rootGetters.configuration.pins || {}).appearOnClick?.atZoomLevel || 0
)
},
}

export default getters
126 changes: 43 additions & 83 deletions packages/plugins/Pins/src/store/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import {
generateSimpleGetters,
generateSimpleMutations,
} from '@repositoryname/vuex-generators'
import { generateSimpleMutations } from '@repositoryname/vuex-generators'
import { passesBoundaryCheck } from '@polar/lib-passes-boundary-check'
import VectorLayer from 'ol/layer/Vector'
import Point from 'ol/geom/Point'
Expand All @@ -13,56 +10,52 @@ import { toLonLat, transform } from 'ol/proj'
import { pointerMove } from 'ol/events/condition'
import { Geometry } from 'ol/geom'
import { Coordinate } from 'ol/coordinate'
import { PinsState } from '../types'
import { PinsState, PinsGetters } from '../types'
import getPointCoordinate from '../util/getPointCoordinate'
import { getPinStyle } from '../util/getPinStyle'

const getInitialState = (): PinsState => ({
isActive: false,
transformedCoordinate: [],
latLon: [],
coordinatesAfterDrag: [],
getsDragged: false,
toZoomLevel: 0,
atZoomLevel: 0,
})
import { getInitialState } from './state'
import getters from './getters'

// OK for module creation
// eslint-disable-next-line max-lines-per-function
export const makeStoreModule = () => {
let pinsLayer: VectorLayer<Vector<Geometry>>

const move = new Select({
layers: (l) => l === pinsLayer,
style: null,
condition: pointerMove,
})

const storeModule: PolarModule<PinsState, PinsState> = {
const storeModule: PolarModule<PinsState, PinsGetters> = {
namespaced: true,
state: getInitialState(),
actions: {
/**
* Responsible for setting up the module by adding a watcher. This watcher
* calls removeMarker and showMarker if the store for addressSearch changes
* its value for the chosenAddress.
*/
setupModule({ getters, rootGetters, dispatch, commit }): void {
const { appearOnClick, coordinateSource, movable, toZoomLevel } =
rootGetters.configuration.pins || {}
const interactions = rootGetters.map.getInteractions()
if (toZoomLevel) {
commit('setToZoomLevel', toZoomLevel)
}
if (appearOnClick?.atZoomLevel) {
commit('setAtZoomLevel', appearOnClick.atZoomLevel)
}
const showPin = appearOnClick === undefined ? true : appearOnClick.show
setupModule({ rootGetters, dispatch }): void {
dispatch('setupClickInteraction')
dispatch('setupCoordinateSource')
rootGetters.map.addInteraction(move)
move.on('select', ({ selected }) => {
const { movable } = rootGetters.configuration.pins || {}
if (!movable || movable === 'none') {
document.body.style.cursor = selected.length ? 'not-allowed' : ''
}
})
dispatch('setupInitial')
// without update, map will pan during drag
this.watch(
() => rootGetters.hasSmallWidth || rootGetters.hasSmallHeight,
() => dispatch('updateMarkerDraggability')
)
},
setupClickInteraction({ rootGetters, getters, commit, dispatch }): void {
const { appearOnClick, movable } = rootGetters.configuration.pins || {}
if (typeof movable === 'boolean') {
console.warn(
"@polar/plugin-pins: Using a boolean for the configuration parameter 'movable' has been deprecated and will be removed in the next major release."
)
}
const interactions = rootGetters.map.getInteractions()
const showPin = appearOnClick === undefined ? true : appearOnClick.show
rootGetters.map.on('singleclick', async ({ coordinate }) => {
const isDrawing = interactions.getArray().some(
(interaction) =>
Expand All @@ -72,7 +65,6 @@ export const makeStoreModule = () => {
// @ts-expect-error | internal hack to detect it from Draw plugin
interaction._isDeleteSelect
)

if (
((typeof movable === 'boolean' && movable) ||
movable === 'drag' ||
Expand All @@ -85,15 +77,17 @@ export const makeStoreModule = () => {
(await dispatch('isCoordinateInBoundaryLayer', coordinate))
) {
const payload = { coordinates: coordinate, clicked: true }

dispatch('removeMarker')
dispatch('showMarker', payload)
commit('setCoordinatesAfterDrag', coordinate)
dispatch('updateCoordinates', coordinate)
}
})

},
setupCoordinateSource({ rootGetters, dispatch }): void {
const { coordinateSource } = rootGetters.configuration.pins || {}
if (coordinateSource) {
// redo marker if source (e.g. from addressSearch) changes
this.watch(
() => rootGetters[coordinateSource],
(feature) => {
Expand All @@ -113,16 +107,6 @@ export const makeStoreModule = () => {
{ deep: true }
)
}

rootGetters.map.addInteraction(move)
move.on('select', ({ selected }) => {
const { movable } = rootGetters.configuration.pins || {}
if (!movable || movable === 'none') {
document.body.style.cursor = selected.length ? 'not-allowed' : ''
}
})

dispatch('setupInitial')
},
setupInitial({ rootGetters, getters, dispatch, commit }): void {
const { initial } = rootGetters.configuration.pins as PinsConfiguration
Expand All @@ -132,7 +116,6 @@ export const makeStoreModule = () => {
typeof epsg === 'string'
? transform(coordinates, epsg, rootGetters.configuration.epsg)
: coordinates

dispatch('removeMarker')
dispatch('showMarker', {
coordinates: transformedCoordinates,
Expand Down Expand Up @@ -190,23 +173,20 @@ export const makeStoreModule = () => {
map.addLayer(pinsLayer)
pinsLayer.setZIndex(100)
commit('setIsActive', true)
const movable = configuration.pins?.movable
if (typeof movable === 'boolean' && movable) {
dispatch('makeMarkerDraggable')
} else if (movable === 'drag') {
dispatch('makeMarkerDraggable')
}
dispatch('updateMarkerDraggability')
}
},
/**
* Makes the mapMarker draggable
*/
makeMarkerDraggable({
rootGetters: { map },
// Decides whether to make the mapMarker draggable and, if so, does so.
updateMarkerDraggability({
rootGetters: { map, configuration },
getters,
commit,
dispatch,
}): void {
const movable = configuration.pins?.movable
if (movable !== 'drag' && movable !== true) {
return
}
const { atZoomLevel } = getters
const previousTranslate = map
.getInteractions()
Expand All @@ -221,7 +201,6 @@ export const makeStoreModule = () => {
map.removeInteraction(previousTranslate)
}
map.addInteraction(translate)

translate.on('translatestart', () => {
commit('setGetsDragged', true)
})
Expand All @@ -231,7 +210,6 @@ export const makeStoreModule = () => {
const geometry = feat.getGeometry()
// @ts-expect-error | abstract method missing on type, exists in all implementations
let coordinates = geometry?.getCoordinates()

if (!(await dispatch('isCoordinateInBoundaryLayer', coordinates))) {
coordinates = getters.transformedCoordinate
dispatch('removeMarker')
Expand All @@ -245,15 +223,10 @@ export const makeStoreModule = () => {
})
})
},
/**
* Removes the mapMarker from the map by removing its vectorLayer
*/
// Removes the mapMarker from the map by removing its vectorLayer
removeMarker({ rootGetters: { map }, commit }): void {
map.getLayers().forEach(function (layer) {
if (
layer !== undefined &&
layer.get('polarInternalId') === 'mapMarkerVectorLayer'
) {
if (layer?.get?.('polarInternalId') === 'mapMarkerVectorLayer') {
map.removeLayer(layer)
}
})
Expand All @@ -266,7 +239,6 @@ export const makeStoreModule = () => {
updateCoordinates({ commit, rootGetters }, coordinates: Coordinate) {
const lonLat = toLonLat(coordinates, rootGetters.configuration.epsg)
const latLon = [lonLat[1], lonLat[0]]

commit('setTransformedCoordinate', coordinates)
commit('setLatLon', latLon)
},
Expand All @@ -281,13 +253,11 @@ export const makeStoreModule = () => {
): Promise<boolean> {
const { boundaryLayerId, toastAction, boundaryOnError } =
rootGetters.configuration?.pins || {}

const boundaryCheckResult = await passesBoundaryCheck(
rootGetters.map,
boundaryLayerId,
coordinates
)

if (
!boundaryLayerId ||
// if a setup error occurred, client will act as if no boundaryLayerId specified
Expand All @@ -297,15 +267,10 @@ export const makeStoreModule = () => {
) {
return true
}

const errorOccurred = typeof boundaryCheckResult === 'symbol'

if (toastAction) {
const toast = errorOccurred
? {
type: 'error',
text: 'plugins.pins.toast.boundaryError',
}
? { type: 'error', text: 'plugins.pins.toast.boundaryError' }
: {
type: 'info',
text: 'plugins.pins.toast.notInBoundary',
Expand All @@ -320,16 +285,11 @@ export const makeStoreModule = () => {
: ['Pin position outside of boundary layer:', coordinates]
)
}

return false
},
},
mutations: {
...generateSimpleMutations(getInitialState()),
},
getters: {
...generateSimpleGetters(getInitialState()),
},
mutations: { ...generateSimpleMutations(getInitialState()) },
getters,
}
return storeModule
}
9 changes: 9 additions & 0 deletions packages/plugins/Pins/src/store/state.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { PinsState } from '../types'

export const getInitialState = (): PinsState => ({
isActive: false,
transformedCoordinate: [],
latLon: [],
coordinatesAfterDrag: [],
getsDragged: false,
})
3 changes: 3 additions & 0 deletions packages/plugins/Pins/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ export interface PinsState {
latLon: number[]
coordinatesAfterDrag: number[]
getsDragged: boolean
}

export interface PinsGetters extends PinsState {
toZoomLevel: number
atZoomLevel: number
}

0 comments on commit 426176b

Please sign in to comment.