@defra/interactive-map 0.0.37-alpha → 0.0.39-alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/templates/draw-tools.njk +4 -3
- package/dist/css/index.css +1 -1
- package/dist/esm/im-core.js +1 -1
- package/dist/esm/im-shell.js +1 -1
- package/dist/umd/im-core.js +1 -1
- package/dist/umd/index.js +1 -1
- package/docs/api.md +32 -0
- package/docs/examples/draw-tools.mdx +0 -4
- package/docs/plugins/draw.md +482 -0
- package/docs/plugins.md +2 -6
- package/govuk-prototype-kit.config.json +3 -2
- package/package.json +2 -4
- package/plugins/beta/draw-es/dist/esm/im-draw-es-plugin.js +1 -1
- package/plugins/beta/draw-ml/dist/esm/im-draw-ml-plugin.js +1 -1
- package/plugins/beta/draw-ml/dist/umd/im-draw-ml-plugin.js +1 -1
- package/plugins/beta/draw-ol/dist/esm/im-draw-ol-plugin.js +1 -1
- package/plugins/beta/map-styles/dist/css/index.css +1 -97
- package/plugins/datasets/dist/esm/im-datasets-plugin.js +1 -1
- package/plugins/datasets/dist/umd/im-datasets-plugin.js +1 -1
- package/plugins/datasets/src/registry/dataset.js +3 -1
- package/plugins/datasets/src/registry/datasetRegistry.js +30 -24
- package/plugins/datasets/src/registry/datasetRegistry.test.js +25 -18
- package/plugins/draw/dist/esm/im-draw-ml-adapter.js +1 -0
- package/plugins/draw/dist/esm/im-draw-ol-adapter.js +1 -0
- package/plugins/draw/dist/esm/im-draw-plugin.js +1 -0
- package/plugins/draw/dist/esm/index.js +1 -0
- package/plugins/draw/dist/umd/im-draw-ml-adapter.js +1 -0
- package/plugins/draw/dist/umd/im-draw-ol-adapter.js +2 -0
- package/plugins/draw/dist/umd/im-draw-ol-adapter.js.LICENSE.txt +1 -0
- package/plugins/draw/dist/umd/im-draw-plugin.js +2 -0
- package/plugins/draw/dist/umd/im-draw-plugin.js.LICENSE.txt +1 -0
- package/plugins/draw/dist/umd/index.js +2 -0
- package/plugins/draw/dist/umd/index.js.LICENSE.txt +1 -0
- package/plugins/draw/src/DrawInit.jsx +89 -0
- package/plugins/draw/src/DrawInit.test.jsx +184 -0
- package/plugins/draw/src/adapterEvents.js +127 -0
- package/plugins/draw/src/adapterEvents.test.js +20 -0
- package/plugins/draw/src/adapters/adapterContract.test.js +48 -0
- package/plugins/draw/src/adapters/loadDrawAdapter.js +14 -0
- package/plugins/draw/src/adapters/loadDrawAdapter.test.js +53 -0
- package/plugins/draw/src/adapters/maplibre/MaplibreDrawAdapter.js +367 -0
- package/plugins/draw/src/adapters/maplibre/MaplibreDrawAdapter.test.js +799 -0
- package/plugins/draw/src/adapters/maplibre/defaults.js +1 -0
- package/plugins/draw/src/adapters/maplibre/drawEvents.js +35 -0
- package/plugins/draw/src/adapters/maplibre/mapboxDraw.js +126 -0
- package/plugins/draw/src/adapters/maplibre/mapboxDraw.test.js +268 -0
- package/plugins/draw/src/adapters/maplibre/mapboxSnap.js +39 -0
- package/plugins/draw/src/adapters/maplibre/mapboxSnap.test.js +91 -0
- package/plugins/draw/src/adapters/maplibre/modes/createDrawMode.js +58 -0
- package/plugins/draw/src/adapters/maplibre/modes/createDrawMode.test.js +53 -0
- package/plugins/draw/src/adapters/maplibre/modes/disabledMode.js +23 -0
- package/plugins/draw/src/adapters/maplibre/modes/disabledMode.test.js +21 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawLineMode.js +15 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawLineMode.test.js +37 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/__helpers__/harness.js +115 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/clickHandlers.js +193 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/clickHandlers.test.js +241 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/keyboardHandlers.js +78 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/keyboardHandlers.test.js +75 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/lifecycle.js +78 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/lifecycle.test.js +48 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/pointerHandlers.js +103 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/pointerHandlers.test.js +127 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/renderHelpers.js +59 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/renderHelpers.test.js +34 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/undoHandlers.js +193 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawMode/undoHandlers.test.js +195 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawPolygonMode.js +16 -0
- package/plugins/draw/src/adapters/maplibre/modes/drawPolygonMode.test.js +27 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/__helpers__/harness.js +107 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/geometryHelpers.js +139 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/geometryHelpers.test.js +46 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/helpers.js +2 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/helpers.test.js +17 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/keyboardHandlers.js +151 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/keyboardHandlers.test.js +123 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/pointerHandlers.js +161 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/pointerHandlers.test.js +98 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/touchHandlers.js +133 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/touchHandlers.test.js +105 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/undoHandlers.js +166 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/undoHandlers.test.js +133 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/vertexOperations.js +210 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/vertexOperations.test.js +167 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/vertexQueries.js +121 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode/vertexQueries.test.js +73 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode.js +249 -0
- package/plugins/draw/src/adapters/maplibre/modes/editVertexMode.test.js +153 -0
- package/plugins/draw/src/adapters/maplibre/snap/constants.js +2 -0
- package/plugins/draw/src/adapters/maplibre/snap/mapHandlers.js +39 -0
- package/plugins/draw/src/adapters/maplibre/snap/mapHandlers.test.js +106 -0
- package/plugins/draw/src/adapters/maplibre/snap/prototypePatches.js +148 -0
- package/plugins/draw/src/adapters/maplibre/snap/prototypePatches.test.js +238 -0
- package/plugins/draw/src/adapters/maplibre/snap/snapInstance.js +115 -0
- package/plugins/draw/src/adapters/maplibre/snap/snapInstance.test.js +151 -0
- package/plugins/draw/src/adapters/maplibre/snap/sourceData.js +34 -0
- package/plugins/draw/src/adapters/maplibre/snap/sourceData.test.js +62 -0
- package/plugins/draw/src/adapters/maplibre/styles.js +207 -0
- package/plugins/draw/src/adapters/maplibre/styles.test.js +155 -0
- package/plugins/draw/src/adapters/maplibre/utils/snapHelpers.js +202 -0
- package/plugins/draw/src/adapters/maplibre/utils/snapHelpers.test.js +253 -0
- package/plugins/draw/src/adapters/maplibre/utils/touchClickWorkaround.js +57 -0
- package/plugins/draw/src/adapters/maplibre/utils/touchClickWorkaround.test.js +106 -0
- package/plugins/draw/src/adapters/openlayers/OLDrawAdapter.js +117 -0
- package/plugins/draw/src/adapters/openlayers/OLDrawAdapter.test.js +159 -0
- package/plugins/draw/src/adapters/openlayers/__helpers__/harness.js +90 -0
- package/plugins/draw/src/adapters/openlayers/core/OLDrawManager.js +178 -0
- package/plugins/draw/src/adapters/openlayers/core/OLDrawManager.test.js +153 -0
- package/plugins/draw/src/adapters/openlayers/core/featureStore.js +69 -0
- package/plugins/draw/src/adapters/openlayers/core/featureStore.test.js +58 -0
- package/plugins/draw/src/adapters/openlayers/core/internalEvents.js +8 -0
- package/plugins/draw/src/adapters/openlayers/core/styles.js +155 -0
- package/plugins/draw/src/adapters/openlayers/core/styles.test.js +143 -0
- package/plugins/draw/src/adapters/openlayers/defaults.js +1 -0
- package/plugins/draw/src/adapters/openlayers/draw/DrawMode.js +272 -0
- package/plugins/draw/src/adapters/openlayers/draw/DrawMode.test.js +431 -0
- package/plugins/draw/src/adapters/openlayers/draw/drawInput.js +139 -0
- package/plugins/draw/src/adapters/openlayers/draw/drawInput.test.js +140 -0
- package/plugins/draw/src/adapters/openlayers/draw/vertexPlacement.js +144 -0
- package/plugins/draw/src/adapters/openlayers/draw/vertexPlacement.test.js +196 -0
- package/plugins/draw/src/adapters/openlayers/edit/EditMode.js +385 -0
- package/plugins/draw/src/adapters/openlayers/edit/EditMode.test.js +303 -0
- package/plugins/draw/src/adapters/openlayers/edit/activeVertexLayer.js +55 -0
- package/plugins/draw/src/adapters/openlayers/edit/activeVertexLayer.test.js +53 -0
- package/plugins/draw/src/adapters/openlayers/edit/keyboardHandler.js +157 -0
- package/plugins/draw/src/adapters/openlayers/edit/keyboardHandler.test.js +195 -0
- package/plugins/draw/src/adapters/openlayers/edit/midpointLayer.js +57 -0
- package/plugins/draw/src/adapters/openlayers/edit/midpointLayer.test.js +42 -0
- package/plugins/draw/src/adapters/openlayers/edit/modifyInteraction.js +83 -0
- package/plugins/draw/src/adapters/openlayers/edit/modifyInteraction.test.js +80 -0
- package/plugins/draw/src/adapters/openlayers/edit/nudge.js +118 -0
- package/plugins/draw/src/adapters/openlayers/edit/nudge.test.js +165 -0
- package/plugins/draw/src/adapters/openlayers/edit/pointerHandlers.js +79 -0
- package/plugins/draw/src/adapters/openlayers/edit/pointerHandlers.test.js +78 -0
- package/plugins/draw/src/adapters/openlayers/edit/selectionState.js +116 -0
- package/plugins/draw/src/adapters/openlayers/edit/selectionState.test.js +109 -0
- package/plugins/draw/src/adapters/openlayers/edit/touchHandler.js +184 -0
- package/plugins/draw/src/adapters/openlayers/edit/touchHandler.test.js +133 -0
- package/plugins/draw/src/adapters/openlayers/edit/undoOps.js +94 -0
- package/plugins/draw/src/adapters/openlayers/edit/undoOps.test.js +64 -0
- package/plugins/draw/src/adapters/openlayers/edit/vertexHitTest.js +74 -0
- package/plugins/draw/src/adapters/openlayers/edit/vertexHitTest.test.js +28 -0
- package/plugins/draw/src/adapters/openlayers/edit/vertexLayer.js +49 -0
- package/plugins/draw/src/adapters/openlayers/edit/vertexLayer.test.js +42 -0
- package/plugins/draw/src/adapters/openlayers/edit/vertexOps.js +100 -0
- package/plugins/draw/src/adapters/openlayers/edit/vertexOps.test.js +80 -0
- package/plugins/draw/src/adapters/openlayers/olDraw.js +40 -0
- package/plugins/draw/src/adapters/openlayers/olDraw.test.js +70 -0
- package/plugins/draw/src/adapters/openlayers/snap/snapEngine.js +220 -0
- package/plugins/draw/src/adapters/openlayers/snap/snapEngine.test.js +232 -0
- package/plugins/draw/src/adapters/openlayers/snap/snapGeometry.js +198 -0
- package/plugins/draw/src/adapters/openlayers/snap/snapGeometry.test.js +136 -0
- package/plugins/draw/src/adapters/openlayers/snap/snapIndicator.js +81 -0
- package/plugins/draw/src/adapters/openlayers/snap/snapIndicator.test.js +72 -0
- package/plugins/draw/src/adapters/openlayers/snap/snapInteraction.js +57 -0
- package/plugins/draw/src/adapters/openlayers/snap/snapInteraction.test.js +68 -0
- package/plugins/draw/src/adapters/openlayers/snap/snapManager.js +99 -0
- package/plugins/draw/src/adapters/openlayers/snap/snapManager.test.js +101 -0
- package/plugins/draw/src/adapters/openlayers/utils/geometryHelpers.js +103 -0
- package/plugins/draw/src/adapters/openlayers/utils/geometryHelpers.test.js +76 -0
- package/plugins/draw/src/adapters/openlayers/utils/olCoords.js +35 -0
- package/plugins/draw/src/adapters/openlayers/utils/olCoords.test.js +22 -0
- package/plugins/draw/src/adapters/openlayers/utils/sketchHelpers.js +22 -0
- package/plugins/draw/src/adapters/openlayers/utils/sketchHelpers.test.js +18 -0
- package/plugins/draw/src/adapters/openlayers/utils/touchTarget.js +8 -0
- package/plugins/draw/src/api/addFeature.js +22 -0
- package/plugins/draw/src/api/addFeature.test.js +41 -0
- package/plugins/draw/src/api/deleteFeature.js +11 -0
- package/plugins/draw/src/api/deleteFeature.test.js +24 -0
- package/plugins/draw/src/api/editFeature.js +54 -0
- package/plugins/draw/src/api/editFeature.test.js +134 -0
- package/plugins/draw/src/api/merge.js +30 -0
- package/plugins/draw/src/api/merge.test.js +57 -0
- package/plugins/draw/src/api/newLine.js +41 -0
- package/plugins/draw/src/api/newLine.test.js +93 -0
- package/plugins/draw/src/api/newPolygon.js +41 -0
- package/plugins/draw/src/api/newPolygon.test.js +93 -0
- package/plugins/draw/src/api/split.js +117 -0
- package/plugins/draw/src/api/split.test.js +204 -0
- package/plugins/draw/src/defaults.js +52 -0
- package/plugins/draw/src/defaults.test.js +18 -0
- package/plugins/draw/src/draw.scss +43 -0
- package/plugins/draw/src/events.js +237 -0
- package/plugins/draw/src/events.test.js +369 -0
- package/plugins/draw/src/index.js +10 -0
- package/plugins/draw/src/index.test.js +24 -0
- package/plugins/draw/src/manifest.js +170 -0
- package/plugins/draw/src/manifest.test.js +147 -0
- package/plugins/draw/src/reducer.js +69 -0
- package/plugins/draw/src/reducer.test.js +85 -0
- package/plugins/draw/src/utils/debounce.js +16 -0
- package/plugins/draw/src/utils/debounce.test.js +40 -0
- package/plugins/draw/src/utils/eventBus.js +36 -0
- package/plugins/draw/src/utils/eventBus.test.js +47 -0
- package/plugins/draw/src/utils/flattenStyleProperties.js +25 -0
- package/plugins/draw/src/utils/flattenStyleProperties.test.js +33 -0
- package/plugins/draw/src/utils/getValueForStyle.js +33 -0
- package/plugins/draw/src/utils/getValueForStyle.test.js +32 -0
- package/plugins/draw/src/utils/resolveColors.js +39 -0
- package/plugins/draw/src/utils/resolveColors.test.js +34 -0
- package/plugins/draw/src/utils/spatial.js +243 -0
- package/plugins/draw/src/utils/spatial.test.js +243 -0
- package/plugins/draw/src/utils/touchTarget.js +95 -0
- package/plugins/draw/src/utils/touchTarget.test.js +107 -0
- package/plugins/draw/src/utils/undoStack.js +31 -0
- package/plugins/draw/src/utils/undoStack.test.js +49 -0
- package/plugins/draw/src/validation/liveDrawChecks.js +120 -0
- package/plugins/draw/src/validation/liveDrawChecks.test.js +159 -0
- package/plugins/draw/src/validation/liveStroke.js +85 -0
- package/plugins/draw/src/validation/liveStroke.test.js +150 -0
- package/plugins/draw/src/validation/rules.areaError.test.js +12 -0
- package/plugins/draw/src/validation/rules.js +186 -0
- package/plugins/draw/src/validation/rules.test.js +120 -0
- package/plugins/draw/src/validation/validateGeometry.js +119 -0
- package/plugins/draw/src/validation/validateGeometry.test.js +200 -0
- package/plugins/interact/dist/esm/im-interact-plugin.js +1 -1
- package/plugins/interact/dist/umd/im-interact-plugin.js +1 -1
- package/plugins/interact/src/hooks/useInteractionHandlers.js +1 -1
- package/plugins/interact/src/hooks/useInteractionHandlers.test.js +1 -1
- package/plugins/interact/src/utils/buildStylesMap.js +1 -0
- package/plugins/search/dist/css/index.css +1 -317
- package/rollup.esm.mjs +35 -28
- package/sonar-project.properties +2 -2
- package/src/App/components/Attributions/Attributions.module.scss +1 -0
- package/src/App/components/Hints/Hints.module.scss +5 -4
- package/src/App/components/KeyboardHelp/KeyboardHelp.jsx +1 -1
- package/src/App/components/KeyboardHelp/KeyboardHelp.test.jsx +11 -0
- package/src/App/components/MoveControl/MoveControl.jsx +73 -9
- package/src/App/components/MoveControl/MoveControl.module.scss +12 -2
- package/src/App/components/MoveControl/MoveControl.test.jsx +136 -0
- package/src/App/hooks/useHintsAPI.js +67 -0
- package/src/App/hooks/useHintsAPI.test.js +145 -0
- package/src/App/renderer/PluginInits.jsx +4 -0
- package/src/App/renderer/PluginInits.test.jsx +7 -1
- package/src/InteractiveMap/InteractiveMap.js +20 -0
- package/src/InteractiveMap/InteractiveMap.test.js +7 -0
- package/src/config/events.js +4 -0
- package/src/scss/settings/_dimensions.scss +3 -0
- package/src/services/announcer.js +38 -3
- package/src/services/announcer.test.js +133 -1
- package/src/services/hints.js +3 -0
- package/src/services/hints.test.js +19 -0
- package/src/types.js +12 -0
- package/src/utils/detectInterfaceType.js +5 -1
- package/src/utils/isMac.js +15 -0
- package/src/utils/isMac.test.js +37 -0
- package/webpack.umd.mjs +1 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { createDrawInput } from './drawInput.js'
|
|
2
|
+
import { createVertexPlacement } from './vertexPlacement.js'
|
|
3
|
+
import { createFakeMap, createContainer } from '../__helpers__/harness.js'
|
|
4
|
+
|
|
5
|
+
jest.mock('./vertexPlacement.js', () => ({
|
|
6
|
+
createVertexPlacement: jest.fn(() => ({
|
|
7
|
+
placeVertex: jest.fn(),
|
|
8
|
+
updateRubberbanding: jest.fn(),
|
|
9
|
+
clearLastCoord: jest.fn()
|
|
10
|
+
}))
|
|
11
|
+
}))
|
|
12
|
+
|
|
13
|
+
const setup = (interfaceType = 'mouse') => {
|
|
14
|
+
const map = createFakeMap()
|
|
15
|
+
const container = createContainer()
|
|
16
|
+
const button = document.createElement('button')
|
|
17
|
+
button.id = 'add-pt'
|
|
18
|
+
document.body.appendChild(button)
|
|
19
|
+
const onUndo = jest.fn()
|
|
20
|
+
const input = createDrawInput({
|
|
21
|
+
drawInteraction: { getMap: () => map },
|
|
22
|
+
options: { container, addVertexButtonId: 'add-pt', interfaceType, mapProvider: {}, snap: null, onUndo }
|
|
23
|
+
})
|
|
24
|
+
const placement = createVertexPlacement.mock.results.at(-1).value
|
|
25
|
+
liveInputs.push(input)
|
|
26
|
+
return { map, view: map.getView(), container, button, input, placement, onUndo }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const liveInputs = []
|
|
30
|
+
afterEach(() => {
|
|
31
|
+
liveInputs.splice(0).forEach((i) => i.destroy())
|
|
32
|
+
document.body.innerHTML = ''
|
|
33
|
+
jest.clearAllMocks()
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
const key = (props) => window.dispatchEvent(new KeyboardEvent('keydown', { cancelable: true, ...props }))
|
|
37
|
+
|
|
38
|
+
test('Enter places a vertex and switches to keyboard — only while focus is inside the viewport', () => {
|
|
39
|
+
const { container, input, placement } = setup()
|
|
40
|
+
key({ key: 'Enter' })
|
|
41
|
+
expect(placement.placeVertex).not.toHaveBeenCalled()
|
|
42
|
+
|
|
43
|
+
container.focus()
|
|
44
|
+
key({ key: 'Enter' })
|
|
45
|
+
expect(placement.placeVertex).toHaveBeenCalled()
|
|
46
|
+
expect(input.getInterfaceType()).toBe('keyboard')
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
test('arrow keys switch to the keyboard interface without placing', () => {
|
|
50
|
+
const { container, input, placement } = setup()
|
|
51
|
+
container.focus()
|
|
52
|
+
key({ key: 'ArrowUp' })
|
|
53
|
+
expect(input.getInterfaceType()).toBe('keyboard')
|
|
54
|
+
expect(placement.placeVertex).not.toHaveBeenCalled()
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
test('ctrl/cmd+z triggers undo', () => {
|
|
58
|
+
const { container, onUndo } = setup()
|
|
59
|
+
container.focus()
|
|
60
|
+
key({ key: 'z', ctrlKey: true })
|
|
61
|
+
expect(onUndo).toHaveBeenCalled()
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
test('the add-vertex button places a vertex; other clicks do not', () => {
|
|
65
|
+
const { button, placement } = setup()
|
|
66
|
+
button.click()
|
|
67
|
+
expect(placement.placeVertex).toHaveBeenCalledTimes(1)
|
|
68
|
+
document.body.click()
|
|
69
|
+
expect(placement.placeVertex).toHaveBeenCalledTimes(1)
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
test('pointer and touch input switch the interface type', () => {
|
|
73
|
+
const { container, input, placement } = setup('keyboard')
|
|
74
|
+
container.dispatchEvent(Object.assign(new Event('pointerdown'), { pointerType: 'mouse' }))
|
|
75
|
+
expect(input.getInterfaceType()).toBe('mouse')
|
|
76
|
+
expect(placement.clearLastCoord).toHaveBeenCalled()
|
|
77
|
+
|
|
78
|
+
container.dispatchEvent(new Event('touchstart'))
|
|
79
|
+
expect(input.getInterfaceType()).toBe('touch')
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
test('a touch pointerdown is left for the touchstart handler to classify', () => {
|
|
83
|
+
const { container, input, placement } = setup('keyboard')
|
|
84
|
+
container.dispatchEvent(Object.assign(new Event('pointerdown'), { pointerType: 'touch' }))
|
|
85
|
+
expect(input.getInterfaceType()).toBe('keyboard') // onPointerdown ignored the touch pointer
|
|
86
|
+
expect(placement.clearLastCoord).not.toHaveBeenCalled()
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
test('the interface type defaults to mouse when none is supplied', () => {
|
|
90
|
+
const map = createFakeMap()
|
|
91
|
+
const container = createContainer()
|
|
92
|
+
const input = createDrawInput({
|
|
93
|
+
drawInteraction: { getMap: () => map },
|
|
94
|
+
options: { container, addVertexButtonId: 'add-pt', mapProvider: {}, snap: null, onUndo: jest.fn() }
|
|
95
|
+
})
|
|
96
|
+
liveInputs.push(input)
|
|
97
|
+
expect(input.getInterfaceType()).toBe('mouse')
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
test('pointer moves and map pans update the rubber band except for the mouse interface', () => {
|
|
101
|
+
const { container, view, placement } = setup('touch')
|
|
102
|
+
container.dispatchEvent(new Event('pointermove'))
|
|
103
|
+
view.emit('change:center')
|
|
104
|
+
expect(placement.updateRubberbanding).toHaveBeenCalledTimes(2)
|
|
105
|
+
|
|
106
|
+
const mouse = setup('mouse')
|
|
107
|
+
mouse.container.dispatchEvent(new Event('pointermove'))
|
|
108
|
+
mouse.view.emit('change:center')
|
|
109
|
+
expect(mouse.placement.updateRubberbanding).not.toHaveBeenCalled()
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
test('setInterfaceType updates the interface and refreshes the rubber band immediately for non-mouse types, e.g. switching to touch and panning via MoveControl mid-session', () => {
|
|
113
|
+
const { input, placement } = setup('mouse')
|
|
114
|
+
input.setInterfaceType('touch')
|
|
115
|
+
expect(input.getInterfaceType()).toBe('touch')
|
|
116
|
+
expect(placement.updateRubberbanding).toHaveBeenCalledTimes(1)
|
|
117
|
+
|
|
118
|
+
input.setInterfaceType('mouse')
|
|
119
|
+
expect(input.getInterfaceType()).toBe('mouse')
|
|
120
|
+
expect(placement.updateRubberbanding).toHaveBeenCalledTimes(1) // not called again for mouse
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
test('keyboard pan animations keep the rubber band anchored via postrender', () => {
|
|
124
|
+
const { map, view, placement } = setup('keyboard')
|
|
125
|
+
view.getAnimating.mockReturnValue(true)
|
|
126
|
+
map.emit('postrender')
|
|
127
|
+
expect(placement.updateRubberbanding).toHaveBeenCalledTimes(1)
|
|
128
|
+
view.getAnimating.mockReturnValue(false)
|
|
129
|
+
map.emit('postrender')
|
|
130
|
+
expect(placement.updateRubberbanding).toHaveBeenCalledTimes(1)
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
test('destroy removes all listeners', () => {
|
|
134
|
+
const { container, button, input, placement } = setup()
|
|
135
|
+
input.destroy()
|
|
136
|
+
container.focus()
|
|
137
|
+
key({ key: 'Enter' })
|
|
138
|
+
button.click()
|
|
139
|
+
expect(placement.placeVertex).not.toHaveBeenCalled()
|
|
140
|
+
})
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { coordToPixel, pixelDist } from '../utils/olCoords.js'
|
|
2
|
+
import { getLastPlacedSketchCoord } from '../utils/sketchHelpers.js'
|
|
3
|
+
|
|
4
|
+
const SNAP_TOLERANCE = 12 // pixels
|
|
5
|
+
// Minimum ring length to allow snap-to-close (placed vertices + rubber-band)
|
|
6
|
+
const MIN_SKETCH_COORDS = { Polygon: 4, LineString: 3 }
|
|
7
|
+
const DUPLICATE_TOLERANCE_PX = 2
|
|
8
|
+
|
|
9
|
+
export const isCloseToFirstVertex = (map, coord, sketchCoords, geometryType) => {
|
|
10
|
+
if (geometryType !== 'Polygon' || sketchCoords.length < MIN_SKETCH_COORDS.Polygon) {
|
|
11
|
+
return false
|
|
12
|
+
}
|
|
13
|
+
const currentPixel = coordToPixel(map, coord)
|
|
14
|
+
const firstPixel = coordToPixel(map, sketchCoords[0])
|
|
15
|
+
if (!currentPixel || !firstPixel) {
|
|
16
|
+
return false
|
|
17
|
+
}
|
|
18
|
+
return pixelDist(currentPixel, firstPixel) < SNAP_TOLERANCE
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const applyRubberbanding = (geom, centerCoord) => {
|
|
22
|
+
if (geom.getType() === 'LineString') {
|
|
23
|
+
const updated = [...geom.getCoordinates()]
|
|
24
|
+
updated[updated.length - 1] = centerCoord
|
|
25
|
+
geom.setCoordinates(updated)
|
|
26
|
+
} else if (geom.getType() === 'Polygon') {
|
|
27
|
+
const updated = geom.getCoordinates().map((ring, i) => {
|
|
28
|
+
if (i !== 0) {
|
|
29
|
+
return ring
|
|
30
|
+
}
|
|
31
|
+
const r = [...ring]
|
|
32
|
+
r[r.length - 1] = centerCoord
|
|
33
|
+
return r
|
|
34
|
+
})
|
|
35
|
+
geom.setCoordinates(updated)
|
|
36
|
+
} else {
|
|
37
|
+
// No action
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Close/finish handling for a placed coordinate. Pure with respect to the
|
|
43
|
+
* lastPlacedCoord bookkeeping: returns the updated value alongside whether the
|
|
44
|
+
* coordinate was consumed as a close/finish attempt (caller must not append).
|
|
45
|
+
*
|
|
46
|
+
* @returns {{ handled: boolean, lastPlacedCoord: number[] | null }}
|
|
47
|
+
*/
|
|
48
|
+
const tryClose = ({ drawInteraction, canFinish, geom, sketchCoords, coord, lastPlacedCoord }) => {
|
|
49
|
+
if (lastPlacedCoord && lastPlacedCoord[0] === coord[0] && lastPlacedCoord[1] === coord[1]) {
|
|
50
|
+
// Same position as last placed: don't duplicate. Close only if enough real vertices exist.
|
|
51
|
+
if (canFinish?.()) { drawInteraction.finishDrawing() }
|
|
52
|
+
return { handled: true, lastPlacedCoord: null }
|
|
53
|
+
}
|
|
54
|
+
const map = drawInteraction.getMap()
|
|
55
|
+
if (isCloseToFirstVertex(map, coord, sketchCoords, geom.getType())) {
|
|
56
|
+
drawInteraction.finishDrawing()
|
|
57
|
+
return { handled: true, lastPlacedCoord }
|
|
58
|
+
}
|
|
59
|
+
// When the add-vertex button overlays the map (touch UI), OL's native pointer handler
|
|
60
|
+
// and this button click handler both fire for the same tap. Detect that OL already
|
|
61
|
+
// committed a vertex at coord's position and skip the duplicate appendCoordinates,
|
|
62
|
+
// but register coord as lastPlacedCoord so a second tap at the same position can close.
|
|
63
|
+
const lastCommitted = getLastPlacedSketchCoord(geom)
|
|
64
|
+
if (lastCommitted) {
|
|
65
|
+
const p1 = map.getPixelFromCoordinate(lastCommitted)
|
|
66
|
+
const p2 = map.getPixelFromCoordinate(coord)
|
|
67
|
+
if (p1 && p2) {
|
|
68
|
+
const dx = p1[0] - p2[0]; const dy = p1[1] - p2[1]
|
|
69
|
+
if (dx * dx + dy * dy < DUPLICATE_TOLERANCE_PX * DUPLICATE_TOLERANCE_PX) {
|
|
70
|
+
return { handled: true, lastPlacedCoord: coord }
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return { handled: false, lastPlacedCoord }
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Crosshair-driven vertex placement for touch/keyboard drawing.
|
|
79
|
+
*
|
|
80
|
+
* Owns the sketch-feature and last-placed-coordinate bookkeeping via the Draw
|
|
81
|
+
* interaction's lifecycle events, and implements placing a vertex at the map
|
|
82
|
+
* center: rubber-band updates, duplicate suppression when OL already committed
|
|
83
|
+
* the same tap, close-on-repeat and close-near-first-vertex behaviour.
|
|
84
|
+
*
|
|
85
|
+
* @returns {{ placeVertex, updateRubberbanding, clearLastCoord }}
|
|
86
|
+
*/
|
|
87
|
+
export const createVertexPlacement = ({ drawInteraction, mapProvider, snap, canFinish, canPlace, getInterfaceType }) => {
|
|
88
|
+
let sketchFeature = null
|
|
89
|
+
let lastPlacedCoord = null
|
|
90
|
+
|
|
91
|
+
const resetSketch = (feature = null) => {
|
|
92
|
+
sketchFeature = feature
|
|
93
|
+
lastPlacedCoord = null
|
|
94
|
+
}
|
|
95
|
+
drawInteraction.on('drawstart', (e) => resetSketch(e.feature))
|
|
96
|
+
drawInteraction.on('drawend', () => resetSketch())
|
|
97
|
+
drawInteraction.on('drawabort', () => resetSketch())
|
|
98
|
+
|
|
99
|
+
const snappedCenter = () => {
|
|
100
|
+
const raw = mapProvider.getCenter()
|
|
101
|
+
return (getInterfaceType() !== 'mouse' && snap) ? snap.apply(raw) : raw
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const updateRubberbanding = () => {
|
|
105
|
+
if (!sketchFeature) {
|
|
106
|
+
// No sketch yet — update snap indicator at crosshair position so targets are
|
|
107
|
+
// visible before the first vertex is placed (touch/keyboard only; mouse uses
|
|
108
|
+
// the OL snap interaction's pointermove handler instead).
|
|
109
|
+
if (getInterfaceType() !== 'mouse' && snap) {
|
|
110
|
+
snap.apply(mapProvider.getCenter())
|
|
111
|
+
}
|
|
112
|
+
return
|
|
113
|
+
}
|
|
114
|
+
const geom = sketchFeature.getGeometry()
|
|
115
|
+
if (!geom.getCoordinates().length) {
|
|
116
|
+
return
|
|
117
|
+
}
|
|
118
|
+
applyRubberbanding(geom, snappedCenter())
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const placeVertex = () => {
|
|
122
|
+
const coord = snappedCenter()
|
|
123
|
+
snap?.hideIndicator()
|
|
124
|
+
if (sketchFeature) {
|
|
125
|
+
const geom = sketchFeature.getGeometry()
|
|
126
|
+
const rawCoords = geom.getCoordinates()
|
|
127
|
+
const sketchCoords = geom.getType() === 'Polygon' ? (rawCoords[0] || []) : rawCoords
|
|
128
|
+
const result = tryClose({ drawInteraction, canFinish, geom, sketchCoords, coord, lastPlacedCoord })
|
|
129
|
+
lastPlacedCoord = result.lastPlacedCoord
|
|
130
|
+
if (result.handled) { return }
|
|
131
|
+
}
|
|
132
|
+
// appendCoordinates bypasses the Draw interaction's condition, so the placement
|
|
133
|
+
// gate must run here explicitly — touch/keyboard parity with the mouse path.
|
|
134
|
+
if (canPlace && !canPlace(coord)) { return }
|
|
135
|
+
drawInteraction.appendCoordinates([coord])
|
|
136
|
+
lastPlacedCoord = coord
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
placeVertex,
|
|
141
|
+
updateRubberbanding,
|
|
142
|
+
clearLastCoord () { lastPlacedCoord = null }
|
|
143
|
+
}
|
|
144
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import Point from 'ol/geom/Point.js'
|
|
2
|
+
import Polygon from 'ol/geom/Polygon.js'
|
|
3
|
+
import Feature from 'ol/Feature.js'
|
|
4
|
+
import { createVertexPlacement, applyRubberbanding, isCloseToFirstVertex } from './vertexPlacement.js'
|
|
5
|
+
import { createFakeMap, createEmitter, polygonFeature, lineFeature } from '../__helpers__/harness.js'
|
|
6
|
+
|
|
7
|
+
const CENTER = [5, 5]
|
|
8
|
+
|
|
9
|
+
const setup = ({ interfaceType = 'touch', snap = null, canFinish = () => true, canPlace } = {}) => {
|
|
10
|
+
const map = createFakeMap()
|
|
11
|
+
const bus = createEmitter()
|
|
12
|
+
const drawInteraction = {
|
|
13
|
+
on: bus.on,
|
|
14
|
+
emit: bus.emit,
|
|
15
|
+
getMap: () => map,
|
|
16
|
+
appendCoordinates: jest.fn(),
|
|
17
|
+
finishDrawing: jest.fn()
|
|
18
|
+
}
|
|
19
|
+
const placement = createVertexPlacement({
|
|
20
|
+
drawInteraction,
|
|
21
|
+
mapProvider: { getCenter: () => CENTER },
|
|
22
|
+
snap,
|
|
23
|
+
canFinish,
|
|
24
|
+
canPlace,
|
|
25
|
+
getInterfaceType: () => interfaceType
|
|
26
|
+
})
|
|
27
|
+
const startSketch = (feature) => { bus.emit('drawstart', { feature }); return feature }
|
|
28
|
+
return { drawInteraction, placement, startSketch, bus }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
describe('placing vertices', () => {
|
|
32
|
+
test('appends the crosshair position, snapped when a snap manager is active', () => {
|
|
33
|
+
const { placement, drawInteraction } = setup()
|
|
34
|
+
placement.placeVertex()
|
|
35
|
+
expect(drawInteraction.appendCoordinates).toHaveBeenCalledWith([CENTER])
|
|
36
|
+
|
|
37
|
+
const snap = { apply: jest.fn(() => [9, 9]), hideIndicator: jest.fn() }
|
|
38
|
+
const snapped = setup({ snap })
|
|
39
|
+
snapped.placement.placeVertex()
|
|
40
|
+
expect(snapped.drawInteraction.appendCoordinates).toHaveBeenCalledWith([[9, 9]])
|
|
41
|
+
expect(snap.hideIndicator).toHaveBeenCalled()
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
test('a canPlace veto rejects the placement — the vertex is never appended', () => {
|
|
45
|
+
const canPlace = jest.fn(() => false)
|
|
46
|
+
const { placement, drawInteraction } = setup({ canPlace })
|
|
47
|
+
placement.placeVertex()
|
|
48
|
+
expect(canPlace).toHaveBeenCalledWith(CENTER)
|
|
49
|
+
expect(drawInteraction.appendCoordinates).not.toHaveBeenCalled()
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
test('a canPlace veto does not block a finish tap (close runs before the gate)', () => {
|
|
53
|
+
let allow = true
|
|
54
|
+
const { placement, drawInteraction, startSketch } = setup({ canPlace: () => allow })
|
|
55
|
+
startSketch(lineFeature([[0, 0], [50, 50]]))
|
|
56
|
+
placement.placeVertex() // placed at the crosshair
|
|
57
|
+
allow = false
|
|
58
|
+
placement.placeVertex() // same spot again → a finish attempt, not a placement
|
|
59
|
+
expect(drawInteraction.finishDrawing).toHaveBeenCalledTimes(1)
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
test('the mouse interface ignores snapping (the OL snap interaction covers it)', () => {
|
|
63
|
+
const snap = { apply: jest.fn(() => [9, 9]), hideIndicator: jest.fn() }
|
|
64
|
+
const { placement, drawInteraction } = setup({ interfaceType: 'mouse', snap })
|
|
65
|
+
placement.placeVertex()
|
|
66
|
+
expect(drawInteraction.appendCoordinates).toHaveBeenCalledWith([CENTER])
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
test('a second tap at the same spot finishes the shape instead of duplicating — when finishable', () => {
|
|
70
|
+
const { placement, drawInteraction, startSketch } = setup()
|
|
71
|
+
startSketch(lineFeature([[0, 0], [50, 50]]))
|
|
72
|
+
placement.placeVertex()
|
|
73
|
+
placement.placeVertex()
|
|
74
|
+
expect(drawInteraction.appendCoordinates).toHaveBeenCalledTimes(1)
|
|
75
|
+
expect(drawInteraction.finishDrawing).toHaveBeenCalledTimes(1)
|
|
76
|
+
|
|
77
|
+
const unfinishable = setup({ canFinish: () => false })
|
|
78
|
+
unfinishable.startSketch(lineFeature([[0, 0], [50, 50]]))
|
|
79
|
+
unfinishable.placement.placeVertex()
|
|
80
|
+
unfinishable.placement.placeVertex()
|
|
81
|
+
unfinishable.placement.placeVertex() // duplicate reset the bookkeeping — placed again
|
|
82
|
+
expect(unfinishable.drawInteraction.finishDrawing).not.toHaveBeenCalled()
|
|
83
|
+
expect(unfinishable.drawInteraction.appendCoordinates).toHaveBeenCalledTimes(2)
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
test('placing near the first polygon vertex closes the ring', () => {
|
|
87
|
+
const { placement, drawInteraction, startSketch } = setup()
|
|
88
|
+
startSketch(polygonFeature([[0, 0], [30, 0], [30, 30], [8, 8], [0, 0]])) // center [5,5] within 12px of [0,0]
|
|
89
|
+
placement.placeVertex()
|
|
90
|
+
expect(drawInteraction.finishDrawing).toHaveBeenCalled()
|
|
91
|
+
expect(drawInteraction.appendCoordinates).not.toHaveBeenCalled()
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
test('a vertex OL already committed at the same position is not appended twice', () => {
|
|
95
|
+
const { placement, drawInteraction, startSketch } = setup()
|
|
96
|
+
startSketch(lineFeature([[0, 0], [5, 6], [50, 50]])) // last committed [5,6] within 2px of center
|
|
97
|
+
placement.placeVertex()
|
|
98
|
+
expect(drawInteraction.appendCoordinates).not.toHaveBeenCalled()
|
|
99
|
+
placement.placeVertex() // now registered as last placed — same spot again closes
|
|
100
|
+
expect(drawInteraction.finishDrawing).toHaveBeenCalled()
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
test('the first vertex of a fresh sketch appends — nothing is committed yet', () => {
|
|
104
|
+
const { placement, drawInteraction, startSketch } = setup()
|
|
105
|
+
startSketch(lineFeature([[0, 0]])) // only the rubber-band coord, no committed vertex
|
|
106
|
+
placement.placeVertex()
|
|
107
|
+
expect(drawInteraction.appendCoordinates).toHaveBeenCalledWith([CENTER])
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
test('an unprojectable committed vertex skips the duplicate-tolerance check', () => {
|
|
111
|
+
const { placement, drawInteraction, startSketch } = setup()
|
|
112
|
+
startSketch(lineFeature([[0, 0], [5, 6], [50, 50]]))
|
|
113
|
+
drawInteraction.getMap().getPixelFromCoordinate = () => null // mid view transition
|
|
114
|
+
placement.placeVertex()
|
|
115
|
+
expect(drawInteraction.appendCoordinates).toHaveBeenCalledWith([CENTER])
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
test('placing into an empty polygon sketch (no ring yet) appends without error', () => {
|
|
119
|
+
const { placement, drawInteraction, startSketch } = setup()
|
|
120
|
+
startSketch(new Feature(new Polygon([]))) // ring not created yet
|
|
121
|
+
placement.placeVertex()
|
|
122
|
+
expect(drawInteraction.appendCoordinates).toHaveBeenCalledWith([CENTER])
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
test('clearLastCoord and sketch end/abort reset the duplicate bookkeeping', () => {
|
|
126
|
+
const { placement, drawInteraction, startSketch, bus } = setup()
|
|
127
|
+
startSketch(lineFeature([[0, 0], [50, 50]]))
|
|
128
|
+
placement.placeVertex()
|
|
129
|
+
placement.clearLastCoord()
|
|
130
|
+
placement.placeVertex()
|
|
131
|
+
expect(drawInteraction.appendCoordinates).toHaveBeenCalledTimes(2)
|
|
132
|
+
|
|
133
|
+
bus.emit('drawend')
|
|
134
|
+
placement.placeVertex() // no sketch — plain append
|
|
135
|
+
expect(drawInteraction.appendCoordinates).toHaveBeenCalledTimes(3)
|
|
136
|
+
bus.emit('drawabort')
|
|
137
|
+
})
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
describe('rubber-banding', () => {
|
|
141
|
+
test('moves the trailing coordinate of a line or polygon ring to the crosshair', () => {
|
|
142
|
+
const { placement, startSketch } = setup()
|
|
143
|
+
const line = startSketch(lineFeature([[0, 0], [50, 50]]))
|
|
144
|
+
placement.updateRubberbanding()
|
|
145
|
+
expect(line.getGeometry().getCoordinates()).toEqual([[0, 0], CENTER])
|
|
146
|
+
|
|
147
|
+
const poly = setup()
|
|
148
|
+
const hole = [[10, 10], [12, 10], [12, 12], [10, 10]]
|
|
149
|
+
const feature = poly.startSketch(new Feature(new Polygon([[[0, 0], [30, 0], [50, 50], [0, 0]], hole])))
|
|
150
|
+
poly.placement.updateRubberbanding()
|
|
151
|
+
expect(feature.getGeometry().getCoordinates()[0].at(-1)).toEqual(CENTER)
|
|
152
|
+
expect(feature.getGeometry().getCoordinates()[1]).toEqual(hole) // inner rings untouched
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
test('without a sketch it only refreshes the snap indicator at the crosshair (non-mouse)', () => {
|
|
156
|
+
const snap = { apply: jest.fn((c) => c), hideIndicator: jest.fn() }
|
|
157
|
+
const { placement } = setup({ snap })
|
|
158
|
+
placement.updateRubberbanding()
|
|
159
|
+
expect(snap.apply).toHaveBeenCalledWith(CENTER)
|
|
160
|
+
|
|
161
|
+
const mouse = setup({ interfaceType: 'mouse', snap })
|
|
162
|
+
snap.apply.mockClear()
|
|
163
|
+
mouse.placement.updateRubberbanding()
|
|
164
|
+
expect(snap.apply).not.toHaveBeenCalled()
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
test('an empty sketch geometry is left alone', () => {
|
|
168
|
+
const { placement, startSketch } = setup()
|
|
169
|
+
const line = startSketch(lineFeature([]))
|
|
170
|
+
placement.updateRubberbanding() // must not throw
|
|
171
|
+
expect(line.getGeometry().getCoordinates()).toEqual([])
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
test('applyRubberbanding ignores unsupported geometry types', () => {
|
|
175
|
+
const point = new Point([1, 1])
|
|
176
|
+
applyRubberbanding(point, CENTER)
|
|
177
|
+
expect(point.getCoordinates()).toEqual([1, 1])
|
|
178
|
+
})
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
describe('isCloseToFirstVertex', () => {
|
|
182
|
+
const map = createFakeMap()
|
|
183
|
+
|
|
184
|
+
test('only closes polygons with enough vertices, within the snap tolerance', () => {
|
|
185
|
+
const ring = [[0, 0], [30, 0], [30, 30], [8, 8], [0, 0]]
|
|
186
|
+
expect(isCloseToFirstVertex(map, [5, 5], ring, 'Polygon')).toBe(true)
|
|
187
|
+
expect(isCloseToFirstVertex(map, [20, 20], ring, 'Polygon')).toBe(false)
|
|
188
|
+
expect(isCloseToFirstVertex(map, [5, 5], ring, 'LineString')).toBe(false)
|
|
189
|
+
expect(isCloseToFirstVertex(map, [5, 5], [[0, 0], [30, 0]], 'Polygon')).toBe(false)
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
test('is false when a coordinate cannot be projected to a pixel', () => {
|
|
193
|
+
const nullMap = { getPixelFromCoordinate: () => null }
|
|
194
|
+
expect(isCloseToFirstVertex(nullMap, [5, 5], [[0, 0], [1, 1], [2, 2], [3, 3]], 'Polygon')).toBe(false)
|
|
195
|
+
})
|
|
196
|
+
})
|