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
142 changes: 121 additions & 21 deletions demo/js/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,14 @@ var interactPlugin = createInteractPlugin({
layerId: 'linked-parcels',
// idProperty: 'id'
},{
layerId: 'OS/TopographicArea_1/Agricultural Land'
layerId: 'OS/TopographicArea_1/Agricultural Land',
idProperty: 'TOID'
},{
layerId: 'fill-inactive.cold',
idProperty: 'id'
},{
layerId: 'stroke-inactive.cold',
idProperty: 'id'
}],
interactionMode: 'select', // 'auto', 'select', 'marker' // defaults to 'marker'
multiSelect: true,
Expand All @@ -32,10 +39,10 @@ var interactPlugin = createInteractPlugin({
})

var drawPlugin = createDrawPlugin({
//snapLayers: ['OS/TopographicLine/Building Outline']
snapLayers: ['OS/TopographicArea_1/Agricultural Land', 'OS/TopographicLine/Building Outline']
})

let framePlugin = createFramePlugin({
var framePlugin = createFramePlugin({
aspectRatio: 1.5
})

Expand Down Expand Up @@ -139,7 +146,7 @@ var interactiveMap = new InteractiveMap('map', {
showMarker: false,
// isExpanded: true
}),
useLocationPlugin(),
// useLocationPlugin(),
interactPlugin,
framePlugin,
drawPlugin
Expand All @@ -155,43 +162,130 @@ interactiveMap.on('map:ready', function (e) {
// framePlugin.addFrame('test', {
// aspectRatio: 1
// })
interactPlugin.enable()
interactPlugin.enable({
debug: true
})
})

interactiveMap.on('datasets:ready', () => {
interactiveMap.on('datasets:ready', function () {
// datasetsPlugin.hideFeatures({
// featureIds: [1148, 1134],
// idProperty: 'gid',
// datasetId: 'field-parcels'
// })
})

// Ref to the selected feature
var selectedFeatureId = null

interactiveMap.on('draw:ready', function () {
// drawPlugin.addFeature({
// id: 'test1234',
// type: 'Feature',
// geometry: { type: 'Polygon', coordinates: [[[-2.9406643378873127,54.918060570259456],[-2.9092219779267054,54.91564249172612],[-2.904350626383433,54.90329530000005],[-2.909664828067463,54.89540129642464],[-2.9225074821353587,54.88979816151294],[-2.937121536764323,54.88826989853317],[-2.95682836800691,54.88916139231736],[-2.965463945742613,54.898966521920045],[-2.966349646023133,54.910805898763385],[-2.9406643378873127,54.918060570259456]]] },
// properties: {
// stroke: 'rgba(0,112,60,1)',
// fill: 'rgba(0,112,60,0.2)',
// strokeWidth: 2,
// }
// })
interactiveMap.addButton('drawPolygon', {
label: 'Draw polygon',
group: 'Drawing tools',
iconSvgContent: '<path d="M19.5 7v10M4.5 7v10M7 19.5h10M7 4.5h10"/><path d="M22 18v3a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1v-3a1 1 0 0 1 1-1h3a1 1 0 0 1 1 1zm0-15v3a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1h3a1 1 0 0 1 1 1zM7 18v3a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1v-3a1 1 0 0 1 1-1h3a1 1 0 0 1 1 1zM7 3v3a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1h3a1 1 0 0 1 1 1z"/>',
isPressed: false,
mobile: { slot: 'right-top' },
tablet: { slot: 'right-top' },
desktop: { slot: 'right-top' },
onClick: function (e) {
e.target.setAttribute('aria-pressed', true)
drawPlugin.newPolygon(crypto.randomUUID(), {
stroke: '#e6c700',
fill: 'rgba(255, 221, 0, 0.1)'
})
}
})
interactiveMap.addButton('drawLine', {
label: 'Draw line',
group: 'Drawing tools',
iconSvgContent: '<path d="M5.706 16.294L16.294 5.706"/><path d="M21 2v3c0 .549-.451 1-1 1h-3c-.549 0-1-.451-1-1V2c0-.549.451-1 1-1h3c.549 0 1 .451 1 1zM6 17v3c0 .549-.451 1-1 1H2c-.549 0-1-.451-1-1v-3c0-.549.451-1 1-1h3c.549 0 1 .451 1 1z"/>',
isPressed: false,
mobile: { slot: 'right-top' },
tablet: { slot: 'right-top' },
desktop: { slot: 'right-top' },
onClick: function (e) {
e.target.setAttribute('aria-pressed', true)
drawPlugin.newLine(crypto.randomUUID(), {
stroke: { outdoor: '#99704a', dark: '#ffffff' }
})
}
})
interactiveMap.addButton('editFeature', {
label: 'Edit feature',
group: 'Drawing tools',
iconSvgContent: '<path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"/><path d="m15 5 4 4"/>',
isDisabled: true,
mobile: { slot: 'right-top' },
tablet: { slot: 'right-top' },
desktop: { slot: 'right-top' },
onClick: function (e) {
if (e.target.getAttribute('aria-disabled') === 'true') {
return
}
interactPlugin.disable()
drawPlugin.editFeature(selectedFeatureId)
}
})
interactiveMap.addButton('deleteFeature', {
label: 'Delete feature',
group: 'Drawing tools',
iconSvgContent: '<path d="M10 11v6"/><path d="M14 11v6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/><path d="M3 6h18"/><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>',
isDisabled: true,
mobile: { slot: 'right-top' },
tablet: { slot: 'right-top' },
desktop: { slot: 'right-top' },
onClick: function (e) {
if (e.target.getAttribute('aria-disabled') === 'true') {
return
}
drawPlugin.deleteFeature(selectedFeatureId)
interactiveMap.toggleButtonState('drawPolygon', 'disabled', false)
interactiveMap.toggleButtonState('drawLine', 'disabled', false)
interactiveMap.toggleButtonState('editFeature', 'disabled', true)
interactiveMap.toggleButtonState('deleteFeature', 'disabled', true)
}
})
drawPlugin.addFeature({
id: 'test1234',
type: 'Feature',
geometry: {'type':'Polygon','coordinates':[[[-2.8792962,54.7095463],[-2.8773445,54.7089363],[-2.8755615,54.7080257],[-2.8750521,54.7079797],[-2.8740651,54.7079522],[-2.8734760,54.7086512],[-2.8739855,54.7091846],[-2.8748292,54.7098284],[-2.8752749,54.7103526],[-2.8762460,54.7104170],[-2.8765803,54.7103342],[-2.8783315,54.7105366],[-2.8784429,54.7101319],[-2.8786499,54.7099571],[-2.8791275,54.7099112],[-2.8792962,54.7095463]],[[-2.8779654,54.7097916],[-2.8768886,54.7094843],[-2.8758538,54.7094200],[-2.8754081,54.7096223],[-2.8754559,54.7099442],[-2.8756947,54.7102201],[-2.8761404,54.7102569],[-2.8767236,54.7101963],[-2.8774559,54.7102606],[-2.8778698,54.7101135],[-2.8779654,54.7097916]]]},
// geometry: { type: 'Polygon', coordinates: [[[-2.9406643378873127,54.918060570259456],[-2.9092219779267054,54.91564249172612],[-2.904350626383433,54.90329530000005],[-2.909664828067463,54.89540129642464],[-2.9225074821353587,54.88979816151294],[-2.937121536764323,54.88826989853317],[-2.95682836800691,54.88916139231736],[-2.965463945742613,54.898966521920045],[-2.966349646023133,54.910805898763385],[-2.9406643378873127,54.918060570259456]]] },
stroke: 'rgba(0,112,60,1)',
fill: 'rgba(0,112,60,0.2)',
strokeWidth: 2
})
// drawPlugin.split('test1234', {
// snapLayers: ['OS/TopographicArea_1/Agricultural Land']
// })
// drawPlugin.newPolygon('test', {
// snapLayers: ['OS/TopographicArea_1/Agricultural Land']
// })
// drawPlugin.editFeature('test1234')
// drawPlugin.editFeature('test1234', {
// snapLayers: ['OS/TopographicArea_1/Agricultural Land']
// })
})

interactiveMap.on('draw:start', function (e) {
console.log('draw:start')
interactPlugin.disable()
})

interactiveMap.on('draw:create', function (e) {
// console.log('draw:create', e)
console.log('draw:create')
})

interactiveMap.on('draw:update', function (e) {
// console.log('draw:update', e)
console.log('draw:update')
})

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

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

interactiveMap.on('interact:done', function (e) {
Expand All @@ -200,14 +294,20 @@ interactiveMap.on('interact:done', function (e) {

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

interactiveMap.on('interact:selectionchange', function (e) {
console.log('interact:selectionchange', e)
var singleFeature = e.selectedFeatures.length === 1
selectedFeatureId = singleFeature ? e.selectedFeatures?.[0]?.featureId : null
interactiveMap.toggleButtonState('drawPolygon', 'disabled', !!singleFeature)
interactiveMap.toggleButtonState('drawLine', 'disabled', !!singleFeature)
interactiveMap.toggleButtonState('editFeature', 'disabled', !singleFeature)
interactiveMap.toggleButtonState('deleteFeature', 'disabled', !singleFeature)
})

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

// Update selected feature
Expand Down
19 changes: 13 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
"react": "^19.2.0",
"react-dom": "^19.2.0",
"remove-files-webpack-plugin": "^1.5.0",
"resize-observer": "^1.0.4",
"resize-observer-polyfill": "^1.5.1",
"rimraf": "^6.1.0",
"sass": "^1.89.2",
"sass-loader": "^16.0.5",
Expand Down Expand Up @@ -124,6 +124,7 @@
"@turf/line-intersect": "^7.3.3",
"@turf/point-to-line-distance": "^7.3.3",
"@turf/polygon-to-line": "^7.3.3",
"abortcontroller-polyfill": "^1.7.8",
"core-js": "^3.44.0",
"govuk-frontend": "^5.13.0",
"maplibre-gl": "^5.15.0",
Expand Down
18 changes: 15 additions & 3 deletions plugins/beta/draw-ml/src/api/addFeature.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { flattenStyleProperties } from '../utils/flattenStyleProperties.js'

export const addFeature = ({ mapProvider, services }, feature) => {
const { draw } = mapProvider
const { eventBus } = services
Expand All @@ -6,10 +8,20 @@ export const addFeature = ({ mapProvider, services }, feature) => {
return
}

// Extract style props from top level, flatten variants, merge with custom properties
const { stroke, fill, strokeWidth, properties, ...rest } = feature
const flatFeature = {
...rest,
properties: {
...properties,
...flattenStyleProperties({ stroke, fill, strokeWidth })
}
}

// --- Add feature to draw instance
draw.add(feature, {
draw.add(flatFeature, {
userProperties: true
})

eventBus.emit('draw:add', feature)
}
eventBus.emit('draw:add', flatFeature)
}
21 changes: 16 additions & 5 deletions plugins/beta/draw-ml/src/api/editFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,43 @@ import { getSnapInstance } from '../utils/snapHelpers.js'
* @param {string} featureId - ID of the feature to edit
* @param {object} options - Options including snapLayers
*/
export const editFeature = ({ appState, appConfig, mapState, pluginState, mapProvider }, featureId, options = {}) => {
export const editFeature = ({ appState, appConfig, mapState, pluginConfig, pluginState, mapProvider }, featureId, options = {}) => {
const { dispatch } = pluginState
const { draw, map } = mapProvider

if (!draw) {
return
}

// Determin snapLayers from pluginConfig or runtime config
let snapLayers = null
if (options.snapLayers !== undefined) {
snapLayers = options.snapLayers
} else if (pluginConfig.snapLayers !== undefined) {
snapLayers = pluginConfig.snapLayers
} else {
snapLayers = null
}

// Set per-call snap layers if provided
const snap = getSnapInstance(map)
if (snap?.setSnapLayers) {
snap.setSnapLayers(options.snapLayers || null)
} else if (options.snapLayers) {
snap.setSnapLayers(snapLayers)
} else if (snapLayers) {
// Snap instance not ready yet - store for later
map._pendingSnapLayers = options.snapLayers
map._pendingSnapLayers = snapLayers
} else {
// No action
}

// Update state so UI can react to snap layer availability
dispatch({ type: 'SET_HAS_SNAP_LAYERS', payload: options.snapLayers?.length > 0 })
dispatch({ type: 'SET_HAS_SNAP_LAYERS', payload: snapLayers?.length > 0 })

// Change mode to edit_vertex
draw.changeMode('edit_vertex', {
container: appState.layoutRefs.viewportRef.current,
deleteVertexButtonId: `${appConfig.id}-draw-delete-point`,
undoButtonId: `${appConfig.id}-draw-undo`,
isPanEnabled: appState.interfaceType !== 'keyboard',
interfaceType: appState.interfaceType,
scale: { small: 1, medium: 1.5, large: 2 }[mapState.mapSize],
Expand Down
Loading