Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions demo/js/draw-ol.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,14 +177,6 @@ interactiveMap.on('draw:cancelled', function (e) {
interactPlugin.enable()
})

interactiveMap.on('interact:done', function (e) {
console.log('interact:done', e)
})

interactiveMap.on('interact:cancel', function (e) {
console.log('interact:cancel', e)
interactPlugin.enable()
})

interactiveMap.on('interact:selectionchange', function (e) {
const singleFeature = e.selectedFeatures.length === 1
Expand Down
21 changes: 12 additions & 9 deletions demo/js/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ const datasetsPlugin = createDatasetsPlugin({
})

const interactiveMap = new InteractiveMap('map', {
behaviour: 'mapOnly',
behaviour: 'hybrid',
mapProvider: maplibreProvider(),
reverseGeocodeProvider: openNamesProvider({
url: process.env.OS_NEAREST_URL,
Expand All @@ -108,6 +108,11 @@ const interactiveMap = new InteractiveMap('map', {
readMapText: true,
// enableFullscreen: true,
// hasExitButton: true,
backAndContinue: {
backLabel: 'Back',
continueLabel: 'Continue',
continueEnabledWhen: ({ pluginStates }) => pluginStates.interact?.selectedFeatures.length > 0
},
// markers: [{
// id: 'location',
// coords: [-2.9592267, 54.9045977],
Expand Down Expand Up @@ -146,6 +151,7 @@ interactiveMap.on('app:ready', function (e) {
// console.log('app:ready')
})


interactiveMap.on('map:ready', function (e) {
// framePlugin.addFrame('test', {
// aspectRatio: 1
Expand Down Expand Up @@ -269,14 +275,6 @@ interactiveMap.on('draw:cancelled', function (e) {
interactPlugin.enable()
})

interactiveMap.on('interact:done', function (e) {
console.log('interact:done', e)
})

interactiveMap.on('interact:cancel', function (e) {
console.log('interact:cancel', e)
interactPlugin.enable()
})

interactiveMap.on('interact:selectionchange', function (e) {
const drawLayers = ['stroke-inactive.cold', 'fill-inactive.cold']
Expand Down Expand Up @@ -310,4 +308,9 @@ interactiveMap.on('search:match', function (e) {
// Hide selected feature
interactiveMap.on('search:clear', function (e) {
// console.log('Search clear')
})

interactiveMap.on('app:continue', function (payload) {
console.log('app:continue')
console.log(payload)
})
7 changes: 0 additions & 7 deletions demo/js/farming.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,13 +153,6 @@ interactiveMap.on('draw:ready', function () {
// drawPlugin.editFeature('test1234')
})

interactiveMap.on('interact:done', function (e) {
console.log('interact:done', e)
})

interactiveMap.on('interact:cancel', function (e) {
console.log('interact:cancel', e)
})

interactiveMap.on('interact:selectionchange', function (e) {
console.log('interact:selectionchange', e)
Expand Down
8 changes: 0 additions & 8 deletions demo/js/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -351,14 +351,6 @@ interactiveMap.on('datasets:ready', function () {
// Ref to the selected features
let selectedFeatureIds = []

interactiveMap.on('interact:done', function (e) {
console.log('interact:done', e)
})

interactiveMap.on('interact:cancel', function (e) {
console.log('interact:cancel', e)
interactPlugin.enable()
})

interactiveMap.on('interact:selectionchange', function (e) {
const drawLayers = ['stroke-inactive.cold', 'fill-inactive.cold']
Expand Down
148 changes: 111 additions & 37 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,34 @@ Whether to automatically determine the colour scheme based on the user's system

---

### `backAndContinue`
**Type:** `BackAndContinueConfig | null`
**Default:** `null`

Shows Back and/or Continue navigation buttons in the actions bar when the map is fullscreen. Intended for multi-step journey flows where the map is one step a user must complete before proceeding.

Provide `backLabel` to render a Back button; provide `continueLabel` to render a Continue button. Both are optional — include either or both.

The Continue button always starts **disabled**. Enable it either declaratively via the `continueEnabledWhen` function or imperatively via [`setContinueEnabled()`](#setcontinueenabledenabled).

```js
new InteractiveMap('map', {
behaviour: 'mapOnly',
backAndContinue: {
backLabel: 'Back',
continueLabel: 'Continue',
// Enable Continue once the user has selected at least one feature
continueEnabledWhen: ({ pluginStates }) =>
pluginStates.interact?.selectedFeatures.length > 0
}
})
```

> [!NOTE]
> In `mapOnly` behaviour the Back button is hidden when there is no browser history to go back to (direct link / bookmark). In `buttonFirst` or `hybrid` behaviour the Back button navigates back in browser history if the map was opened via the button, or collapses the map if arrived via a direct link or bookmark.

---

### `backgroundColor`
**Type:** `string | Object<string, string>`
**Default:** `var(--background-color)`
Expand Down Expand Up @@ -311,19 +339,6 @@ URL query parameter used to control fullscreen/hybrid/buttonFirst state. Overrid

---

### `urlPosition`
**Type:** `'sync' | 'readOnly' | 'none'`
**Default:** `'sync'`

Controls how map center and zoom interact with the page URL.

| Value | Behaviour |
|---|---|
| `'sync'` | Reads center/zoom from the URL on load and writes back on pan/zoom — enables bookmarking and sharing the current map view |
| `'readOnly'` | Seeds the initial view from the URL but never writes back |
| `'none'` | Ignores the URL entirely — use when you don't want the user's pan/zoom to be persisted or shared |
---

### `markers`
**Type:** `MarkerConfig[]`

Expand All @@ -333,30 +348,6 @@ See [MarkerConfig](./api/marker-config.md) for full details.

---

### `symbolDefaults`
**Type:** `Partial<SymbolDefaults>`

App-wide defaults for symbol and marker appearance.

| Property | Default |
|---|---|
| `symbol` | `'pin'` |
| `backgroundColor` | `'#ca3535'` |
| `foregroundColor` | `'#ffffff'` |

```js
new InteractiveMap('map', {
symbolDefaults: {
symbol: 'circle',
backgroundColor: { outdoor: '#1d70b8', dark: '#4c9ed9' }
}
})
```

See [Symbol Config](./api/symbol-config.md) for the full property list.

---

### `maxExtent`
**Type:** `[number, number, number, number]`

Expand Down Expand Up @@ -481,6 +472,30 @@ new InteractiveMap('map', {

---

### `symbolDefaults`
**Type:** `Partial<SymbolDefaults>`

App-wide defaults for symbol and marker appearance.

| Property | Default |
|---|---|
| `symbol` | `'pin'` |
| `backgroundColor` | `'#ca3535'` |
| `foregroundColor` | `'#ffffff'` |

```js
new InteractiveMap('map', {
symbolDefaults: {
symbol: 'circle',
backgroundColor: { outdoor: '#1d70b8', dark: '#4c9ed9' }
}
})
```

See [Symbol Config](./api/symbol-config.md) for the full property list.

---

### `transformRequest`
**Type:** `function`

Expand All @@ -497,6 +512,20 @@ See the [MapLibre documentation](https://maplibre.org/maplibre-gl-js/docs/API/ty

---

### `urlPosition`
**Type:** `'sync' | 'readOnly' | 'none'`
**Default:** `'sync'`

Controls how map center and zoom interact with the page URL.

| Value | Behaviour |
|---|---|
| `'sync'` | Reads center/zoom from the URL on load and writes back on pan/zoom — enables bookmarking and sharing the current map view |
| `'readOnly'` | Seeds the initial view from the URL but never writes back |
| `'none'` | Ignores the URL entirely — use when you don't want the user's pan/zoom to be persisted or shared |

---

### `zoom`
**Type:** `number`

Expand Down Expand Up @@ -720,6 +749,31 @@ See [ControlDefinition](./api/control-definition.md) for configuration options.

---

### `setContinueEnabled(enabled)`

Enable or disable the Continue button added by [`backAndContinue`](#backandcontinue). Use this for imperative control — for example, enabling Continue after an async operation or in response to an external event. For reactive state-derived conditions, prefer the `continueEnabledWhen` function in `backAndContinue` instead.

> [!NOTE]
> If `continueEnabledWhen` is configured alongside `setContinueEnabled`, the function will override the imperative call on the next state change.

| Parameter | Type | Description |
|-----------|------|-------------|
| `enabled` | `boolean` | `true` to enable the Continue button, `false` to disable it |

```js
// Enable Continue after a draw operation completes
interactiveMap.on('draw:merged', () => {
interactiveMap.setContinueEnabled(true)
})

// Disable it again if the merge is undone
interactiveMap.on('draw:unmerged', () => {
interactiveMap.setContinueEnabled(false)
})
```

---

### `setMode(mode)`

Programmatically set the application mode. See the [`mode`](#mode) option for more detail.
Expand Down Expand Up @@ -860,6 +914,26 @@ interactiveMap.on('app:ready', () => {

---

### `app:continue`

Emitted when the user clicks the Continue button added by [`backAndContinue`](#backandcontinue). Includes a snapshot of all plugin states and the current map state at the moment Continue was clicked.

**Payload:**

| Property | Type | Description |
|---|---|---|
| `pluginStates` | `object` | All plugin states keyed by plugin ID (e.g. `pluginStates.interact.selectedFeatures`) |
| `mapState` | `object` | Current map state including `zoom`, `center`, `bounds` and other map properties |

```js
interactiveMap.on('app:continue', ({ pluginStates, mapState }) => {
const selectedFeatures = pluginStates.interact?.selectedFeatures ?? []
console.log('User continued with', selectedFeatures.length, 'features at zoom', mapState.zoom)
})
```

---

### `map:ready`

Emitted when the underlying map is ready and initial app state (style and size) has settled.
Expand Down
3 changes: 3 additions & 0 deletions plugins/beta/draw-ml/src/manifest.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,21 @@ export const manifest = {
id: 'drawCancel',
label: 'Cancel',
variant: 'tertiary',
exclusiveSlot: true,
hiddenWhen: ({ pluginState }) => !pluginState.mode,
...createButtonSlots(true)
}, {
id: 'drawAddPoint',
label: 'Add point',
variant: 'primary',
exclusiveSlot: true,
hiddenWhen: ({ appState, pluginState }) => !['draw_polygon', 'draw_line'].includes(pluginState.mode) || appState.interfaceType !== 'touch',
...createButtonSlots(true)
}, {
id: 'drawDone',
label: 'Done',
variant: 'primary',
exclusiveSlot: true,
hiddenWhen: ({ pluginState }) => !['draw_polygon', 'draw_line', 'edit_vertex'].includes(pluginState.mode),
enableWhen: ({ pluginState }) => pluginState.numVertecies >= (pluginState.mode === 'draw_polygon' ? 3 : 2),
...createButtonSlots(true)
Expand Down
4 changes: 2 additions & 2 deletions plugins/interact/src/InteractInit.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const InteractInit = ({
pluginState
}) => {
const { dispatch, enabled, selectedFeatures, interactionModes, layers } = pluginState
const { eventBus, closeApp } = services
const { eventBus } = services
const { crossHair, mapStyle, markers } = mapState

const selectMarkerOnly = isSelectMarkerOnly(interactionModes)
Expand Down Expand Up @@ -66,7 +66,7 @@ export const InteractInit = ({

useCrossHairVisibility({ crossHair, enabled, selectMarkerOnly, appState })

useAttachEvents({ pluginState, appState, mapState, buttonConfig, eventBus, handleInteraction, closeApp })
useAttachEvents({ pluginState, appState, mapState, buttonConfig, eventBus, handleInteraction })

return null
}
2 changes: 1 addition & 1 deletion plugins/interact/src/InteractInit.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ beforeEach(() => {
props = {
appState: { interfaceType: 'mouse', layoutRefs: { viewportRef: { current: document.createElement('div') }, appContainerRef: { current: document.createElement('div') } } },
mapState: { crossHair: { fixAtCenter: jest.fn(), hide: jest.fn() }, mapStyle: {} },
services: { eventBus: { emit: jest.fn() }, closeApp: jest.fn() },
services: { eventBus: { emit: jest.fn() } },
buttonConfig: {},
mapProvider: { setHoverCursor: jest.fn() },
pluginState: {
Expand Down
Loading
Loading