mapbox-gl-draw
mapbox-gl-draw copied to clipboard
Feature request: customizable source id
The scenario is: I need to create multiple draw instances and tailor them for different purposes, say one for measuring distance/area, one for creating poi geojson.
Yet since all mapbox-gl-draw instances are using the same source id, it throws the following error when adding multiple draw instance to the map:
There is already a source with this ID.
My current approach is setting a type property for each feature generated by different draw instance during event 'draw.create' to distinguish them..
I think this can be better implemented by passing a source id parameter to create separated source and layer for each draw instance.
Thank you.
Update: Tried to add user defined suffix to source and layer id, now there can be multiple draw instances on same map, yet only features added with the 1st draw instance work as expected. commit As can be seen in the example below: https://jsfiddle.net/skywalkershen/qwor36m7/2/
Problem with layer display:
The polygons are hidden for the most of the time during creation. Click on polygon/point button of a draw instance toggles features created with other draw instances to off.
Problem with feature selection:
Only the features in the 1st draw instance can be modified and selected as expected.
The first click on feature created with 2nd or 3rd draw instance throw the following error:
Uncaught TypeError: Cannot read property 'toGeoJSON' of undefined
After that, click on features throw the following error:
Uncaught TypeError: Cannot read property 'type' of undefined at module.exports.SimpleSelect.clickOnFeature
Get events separated. https://jsfiddle.net/skywalkershen/qwor36m7/6/ Open console to see log on different draw instances' events
Seconding this feature
Each draw instance should be creating it's own source with it's own unique identifier.
Having an isolated component which relies on specific layers being available at a central point breaks the compartmentalisation of this feature.
MapboxDraw.constants.sources.COLD and MapboxDraw.constants.sources.HOT are used for the layers and can be adjusted before creating the instance.
However gl-draw-point-static.hot, gl-draw-polygon-stroke-static.hot, etc. Are not so simple, these layer names come from styles. They could benefit from using a constant in their names.
Taking the template from https://github.com/mapbox/mapbox-gl-draw/blob/main/docs/EXAMPLES.md#lines-and-polygons we can adjust the id of those layers.
i.e. In Vue was able to use the component _uid variable to give these unique names:
First the sources:
MapboxDraw.constants.sources.COLD = `mapbox-gl-draw-cold_${this._uid}`;
MapboxDraw.constants.sources.HOT = `mapbox-gl-draw-hot_${this._uid}`;
Then the layers:
styles: [
// ACTIVE (being drawn)
// line stroke
{
"id": `gl-draw-line_${this._uid}`,
"type": "line",
"filter": ["all", ["==", "$type", "LineString"], ["!=", "mode", "static"]],
"layout": {
"line-cap": "round",
"line-join": "round"
},
"paint": {
"line-color": "#D20C0C",
"line-dasharray": [0.2, 2],
"line-width": 2
}
},
// polygon fill
{
"id": `gl-draw-polygon-fill_${this._uid}`,
"type": "fill",
"filter": ["all", ["==", "$type", "Polygon"], ["!=", "mode", "static"]],
"paint": {
"fill-color": "#D20C0C",
"fill-outline-color": "#D20C0C",
"fill-opacity": 0.1
}
},
// polygon mid points
{
'id': `gl-draw-polygon-midpoint_${this._uid}`,
'type': 'circle',
'filter': ['all',
['==', '$type', 'Point'],
['==', 'meta', 'midpoint']],
'paint': {
'circle-radius': 3,
'circle-color': '#fbb03b'
}
},
// polygon outline stroke
// This doesn't style the first edge of the polygon, which uses the line stroke styling instead
{
"id": `gl-draw-polygon-stroke-active_${this._uid}`,
"type": "line",
"filter": ["all", ["==", "$type", "Polygon"], ["!=", "mode", "static"]],
"layout": {
"line-cap": "round",
"line-join": "round"
},
"paint": {
"line-color": "#D20C0C",
"line-dasharray": [0.2, 2],
"line-width": 2
}
},
// vertex point halos
{
"id": `gl-draw-polygon-and-line-vertex-halo-active_${this._uid}`,
"type": "circle",
"filter": ["all", ["==", "meta", "vertex"], ["==", "$type", "Point"], ["!=", "mode", "static"]],
"paint": {
"circle-radius": 5,
"circle-color": "#FFF"
}
},
// vertex points
{
"id": `gl-draw-polygon-and-line-vertex-active_${this._uid}`,
"type": "circle",
"filter": ["all", ["==", "meta", "vertex"], ["==", "$type", "Point"], ["!=", "mode", "static"]],
"paint": {
"circle-radius": 3,
"circle-color": "#D20C0C",
}
},
// INACTIVE (static, already drawn)
// line stroke
{
"id": `gl-draw-line-static_${this._uid}`,
"type": "line",
"filter": ["all", ["==", "$type", "LineString"], ["==", "mode", "static"]],
"layout": {
"line-cap": "round",
"line-join": "round"
},
"paint": {
"line-color": "#000",
"line-width": 3
}
},
// polygon fill
{
"id": `gl-draw-polygon-fill-static_${this._uid}`,
"type": "fill",
"filter": ["all", ["==", "$type", "Polygon"], ["==", "mode", "static"]],
"paint": {
"fill-color": "#000",
"fill-outline-color": "#000",
"fill-opacity": 0.1
}
},
// polygon outline
{
"id": `gl-draw-polygon-stroke-static_${this._uid}`,
"type": "line",
"filter": ["all", ["==", "$type", "Polygon"], ["==", "mode", "static"]],
"layout": {
"line-cap": "round",
"line-join": "round"
},
"paint": {
"line-color": "#000",
"line-width": 3
}
}
],
The defaults for these styles are contained within https://github.com/mapbox/mapbox-gl-draw/blob/4e51ce41378323809e5efeb5454cc132d5dbf991/src/lib/theme.js
Unless META is also overloaded featuresAt() will grab features from unrelated instances, resulting in events being triggered during mouseover of features not currently being edited.
With a reused constant string featuresAt() will pickup items from other layers. It could pass the filter to map.queryRenderedFeatures(), it could also provide a list of pertinent layers.
https://github.com/mapbox/mapbox-gl-draw/blob/4e51ce41378323809e5efeb5454cc132d5dbf991/src/lib/features_at.js#L35-L36
Adjusting these constants will help target ONLY the correct feature when editing:
MapboxDraw.constants.meta.FEATURE = `feature_${this._uid}`;
MapboxDraw.constants.meta.MIDPOINT = `midpoint_${this._uid}`;
MapboxDraw.constants.meta.VERTEX = `vertex_${this._uid}`;
However this breaks simple_select mode and doesn't allow created polygons to be selected. Vertex's also vanish from lines in creation mode.
Seems fixable but think rather than attempting to work with this I'll refactor to a single instance pattern. Believe this use-case should have been considered from the beginning when designing a component to not rely on specific configuration of it's parent.