Mapbox, draw polygons of different colors - javascript

Using Mapbox GL, I want to be able to create polygons and give them individual colors, but after along search and read through the api doc, just can'tfigure out out this is supposed to be done.
nb: I want to use draw not addlayer as I want the polygon to still be editable afterwards.
nb: this.color is a hex value selected by the user
maybe I'm a newbie n00bing out, maybe the approach isn't quite right.
// when a poly is created add a color property to it and save it into the stagedFeatures array
this.map.on('draw.create', e => {
e.features.forEach(feature => {
feature['properties'] = { color: this.color }
this.stagedFeatures.push(feature)
})
})
// set the color of the next polygon
document.getElementById('colourSelector').addEventListener('change', e => {
if (e.target['value']) {
this.color = e.target['value']
this.setStyle()
}
})
// generate the styles
getStyles() {
return [
{
'id': 'gl-draw-polygon-fill-inactive',
'type': 'fill',
'filter': [
'all',
['==', 'active', 'false'],
['==', '$type', 'Polygon'],
['!=', 'mode', 'static']
],
'paint': {
// my problem is likely here, have tried many expressions etc but mapbox
// expressions aren't super easy to figure out
'fill-color': this.color,
'fill-outline-color': this.color,
'fill-opacity': 0.5
}
},
...
// redraw the map and readd the polygons
setStyle() {
this.map.removeControl(this.draw)
if (typeof this.map.getSource('staged-features') !== 'undefined') {
this.map.removeSource('staged-features')
}
this.map.addSource("staged-features", {
type: "geojson",
data: {
type: "FeatureCollection",
features: this.stagedFeatures
},
})
this.draw = new MapboxDraw({
userProperties: true,
displayControlsDefault: false,
controls: {
polygon: true,
trash: true
},
styles: this.getStyles()
})
this.map.addControl(this.draw)
// loop through any features that the map needs to redraw
this.stagedFeatures.forEach(i => {
console.warn('restore polygons', i)
this.draw.add(i)
})
}
whats happening is the polys redraw but using only the selected color, I'm wanted to get an expression workeing the pulls back the color from the feature.properties.color value
['get', 'color'] with a fallback to this.color doesn't appear to work here.
whats happening is the polys redraw but using only the selected color, I'm wanted to get an expression workeing the pulls back the color from the feature.properties.color value
['get', 'color'] with a fallback to this.color doesn't appear to work here.
https://docs.mapbox.com/mapbox-gl-js/style-spec/expressions/
tried the null operators suggested here:
https://github.com/mapbox/mapbox-gl-js/issues/5761

Related

Chart.js showing different graphs with select

basically, I have made a Graph that looks like this Image.
I want to make the Graph update whenever I choose an option ( a location in this example). Any idea how could I go on about this?
It sounds like you need to update the chart data whenever the user selects a value from the dropdown. So, add an event listener to the location selector dropdown element, then replace the chart data with the data for the selected location, then call chart update. That part is very simple. It's explained in the chart.js docs under Updating Charts. https://www.chartjs.org/docs/latest/developers/updates.html
For example, if you had location data in an object and a transformData function to convert it to x/y coordinates, you might do something like this for a line chart:
const defaultLocation = 'munchen';
const chart = new Chart(chartCanvas,
{
type: 'line',
data: transformData(locationData[defaultLocation]),
options: {
animation: false,
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
beginAtZero: true,
},
x: {
type: 'timeseries',
},
},
},
});
const locationSelector = document.getElementById("location-selector");
locationSelector.addEventListener('change', ({ target }) => {
chart.data = transformData(locationData[target.value]);
chart.update();
});

Mapbox GL setData to update layer

In my angular app I am using directions api and trying to add a route path from one direction to another. On the first time when making the ajax request route path is creating properly but from the second time i can not see the route path.
I am getting this error from second time onwards of the ajax request - Layer with id "route" already exists on this map
Is there any way to update the source and layer in mapbox?
drawRoute() {
const url = `https://api.mapbox.com/directions/v5/mapbox/driving/${this.startData?.lng},${this.startData?.lat};${this.endData?.lng},${this.endData?.lat}?alternatives=true&geometries=geojson&steps=true&access_token=${environment.mapbox.accessToken}`;
this._http.get(url).subscribe({
next: (result) => {
const geojson: any = {
type: 'Feature',
properties: {},
geometry: {
type: 'LineString',
coordinates: result.routes[0]
}
};
if (this.map?.getSource('route')) {
const source: mapboxgl.GeoJSONSource = this.map?.getSource('route') as
mapboxgl.GeoJSONSource;
source.setData(geojson);
} else {
this.map?.addSource('route', {
type: 'geojson',
data: {
type: 'Feature',
properties: {},
geometry: {
type: 'LineString',
coordinates: result.routes[0].geometry.coordinates
}
}
});
}
this.map?.addLayer({
id: 'route',
type: 'line',
source: 'route',
layout: {
'line-join': 'round',
'line-cap': 'round'
},
paint: {
'line-color': '#1F5ED8',
'line-width': 2
}
});
},
error: (err) => {}
})
}
I think that the setData() method that is available for GeoJSON sources in Mapbox GL JS is what you are looking for. The method allows you to update the underlying source data and triggers a map re-render. The data-driven styling should then kick in and style your updates layers as desired.
https://docs.mapbox.com/mapbox-gl-js/api/sources/#geojsonsource#setdata
Here is a pseudo-code example
map.getSource("source-id").setData(updatedGeoJSONData);
Hope this helps! I have been writing a series of guides for Mapbox that you might be interested in too. Here are some links:
The Mapbox Developer's Handbook
A Complete Guide to Sources and Layers in React and Mapbox GL JS

How to add hover effect to new layer created with custom geojson

I've built a map and added a layer that highlights a specific neighborhood, I'd like to add a hover effect to the layer. just like in this example https://docs.mapbox.com/mapbox-gl-js/example/hover-styles
I got as far as creating my own layer with the geojson but the example I am trying to follow uses an external data source whereas I am using my own. I tried to reference my data but I don't think I am doing it correctly. Pleases see this link with a working version showing the layer highlighting the neighborhood.
This is the link to what I have so far https://jsfiddle.net/jrax4pvm/1/
Here's my JS
mapboxgl.accessToken =
'pk.eyJ1IjoibGVvc29ubmVrdXM5NSIsImEiOiJjazAxdHcyZWExMHBjM2lwN2psMDhheXQwIn0.KpEYrurG0lE55PLKMuYtKw';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/leosonnekus95/ck11gbbaz0neb1cmrunqmijkf',
zoom: 15,
center: [174.7570008, -36.8658221]
});
map.on('load', function () {
'id': 'Uptown',
'type': 'fill',
'source': {
'type': 'geojson',
'data': {
'type': 'Feature',
'geometry': {
'type': 'Polygon',
'coordinates':
[
[ /* Co-ordinates here..*/ ]]
}
}
},
'layout': {},
'paint': {
'fill-color': '#088',
'fill-opacity': 0.8
}
});
});
I'd really like to make this layer hoverable/clickable and suspect I have to create a combined version of these two examples
https://docs.mapbox.com/mapbox-gl-js/example/geojson-polygon/
https://docs.mapbox.com/mapbox-gl-js/example/hover-styles/
and would like some guidance.
You'll want to add map.on('mouseenter') and map.on('mouseleave') functions which target your layer to your code like this:
map.on('mouseenter', 'Uptown', function(e) {
map.setPaintProperty('Uptown', 'fill-color', '#FF0000');
});
map.on('mouseleave', 'Uptown', function() {
map.setPaintProperty('Uptown', 'fill-color', '#1F06F0'));
});
I've updated your code in another JSFiddle (https://jsfiddle.net/pjleonard37/jfd0bsha/) with these changes.
Disclaimer: I work at Mapbox

Mapbox markers flashing when using `icon-allow-overlap`

I have a map that's using mapboxgl-js to hide or show map markers based on some criteria.
Hiding the markers is working as expected, but when I want the markers to show again they flash for some milliseconds then disappear again while the map hides labels (street names etc.) on the underlying layer before they show up again.
See this video: https://streamable.com/debcp
See this codepen: https://codepen.io/jakobfuchs/details/VRRgJO
I came to the conclusion that this is caused by setting 'icon-allow-overlap': true on the marker symbol layer.
Any suggestions how I can keep that setting and avoid the flashing?
The strange thing is that this does not happen 100% of the time but ~95% of the time.
Code samples:
Marker layer:
map.addLayer({
id: 'property-layer',
type: 'symbol',
source: 'properties',
filter: ['!has', 'point_count'],
layout: {
'symbol-placement': 'point',
'icon-image': 'marker',
'icon-size': 1,
'icon-anchor': 'bottom',
'icon-allow-overlap': true,
}
});
Filter code:
const filterToggle = document.getElementById('filterToggle');
filterToggle.addEventListener('change', function(e) {
if (openPopup) {
openPopup.remove();
openPopup = '';
}
let properties;
if (this.checked) {
properties = {
type: "FeatureCollection",
features: features.features.filter((property) => property.properties.availability === 'Available')
}
} else {
properties = features;
}
map.getSource('properties').setData(properties);
});
I have faced with the same issue and my solution is use the icon-ignore-placement instead of icon-allow-overlap, and it's still not have any issues
You can find the document here: https://docs.mapbox.com/mapbox-gl-js/style-spec/#layout-symbol-icon-ignore-placement
Hope this will help, thanks!

Highcharts annotations not rendering

I'm trying to dynamically add annotations to my high charts in React. I'm using the addAnnotation function to add a new annotation whenever a hover event is triggered on my app, but the annotation does not render. I dropped a debugger into my code, and when I call chart.annotations I can see there is currently an array of annotations, but they are not rendering. I even have make a call to the addPlotLine in this function and the plotline is rendered on the chart. My config file looks like this
chart: {
annotations: [{
labelOptions: {
backgroundColor: 'rgba(0, 0, 0, 0.5)',
verticalAlign: 'top',
align: 'right',
}
}],
annotationsOptions: {
},
.... some lots more config options
}
and my on hover function to add the annotation is as follows
if( isNumber(value) )
//this renders a plotline
chart.xAxis[0].addPlotLine(baseChartHandle.generateInteractivePlotLine(value));
// this doesn't render my annotation however
chart.addAnnotation({
linkedTo: value,
title: {
text: "It works!"
}
});
}
I found that when I added annotations using Highcharts that the "linkedTo" function never worked despite my trials.
Despite adding a guid to my point, it never was able to apply it. I would suggest in your case adding it by x and y value, then finding the point that way instead. Here is how I have added annotations in the past successfully:
series.data.forEach(function (point) {
var annotationObject =
{
id: point.id,
labelOptions: {
y: 15,
verticalAlign: 'bottom',
distance: 25
},
labels: []
};
}
var text = <get text you want to push>;
annotationObject.labels.push(
{
point: {
xAxis: 0,
yAxis: 0,
x: point.x,
y: point.y
},
text: text
}
);
_chart.addAnnotation(annotationObject);
});
I also found a bug in HighCharts when using remove annotations, as a heads up. Each point will need an id like above, but it should be called by this line:
_chart.removeAnnotation(id);
It will remove the annotation, however you will get lots of complaints from highcharts if you try to do anything after, and it will break. I found the answer here, in annotations.js :
The red box is code I added. If you do removeAnnotation(ann.id), and it rerenders, it will fail because the labels object is null. Adding this check lets you do that without the labelCollectors failing.
Happy charting.

Categories

Resources