Adding multiple style layers in Mapbox / React js - reactjs

I'm using mapbox gl in React to draw polygons on a map. Would like to fill these polygons, and also adjust the border width of the polygons. My understanding is that it is not possible to adjust the border width as a fill property, so a separate line style must be created.
The problem that I am having, is that when I attempt to add an additional style to set the line width, it does not work. Apparently what is happening is that the first style layer is the one that is rendered, and the second one is not, per the code below: "STYLE LAYERS #'S 1 AND 2." I can get the line style to render if I place it in the first position, but then I get no fill layer, and vice-versa.
Any thoughts on this?
useEffect(() => {
if (map.current) return;
map.current = new mapboxgl.Map({
container: mapContainer.current,
style: "mapbox://styles/mapbox/streets-v11",
center: [lng, lat],
zoom: zoom,
});
});
useEffect(() => {
if (!map.current) return;
map.current.on("move", () => {
console.log(map.current.getCenter().lng.toFixed(4));
setLng(map.current.getCenter().lng.toFixed(4));
setLat(map.current.getCenter().lat.toFixed(4));
setZoom(map.current.getZoom().toFixed(2));
});
});
useEffect(() => {
if (!map.current) return;
map.current.on("load", () => {
dataArray.map((item) => {
map.current.addSource(item.name, {
type: "geojson",
data: {
type: "Feature",
geometry: {
type: "Polygon",
coordinates: item.data,
},
properties: {
name: item.name,
},
},
});
//STYLE LAYER #1
map.current.addLayer({
id: item.name,
type: "fill",
source: item.name,
layout: {},
paint: {
"fill-color": "#aaa",
"fill-opacity": 0.25,
"fill-outline-color": "#000",
},
});
//STYLE LAYER #2
map.current.addLayer({
id: item.name,
type: "line",
source: item.name,
layout: {},
paint: {
"line-color": "#000",
"line-width": 2,
},
});
});
});

Each layer needs to have a unique id (see: https://docs.mapbox.com/mapbox-gl-js/style-spec/layers/). So, you could append "-border" to the line layer id.

Related

Adding series to highchart and remove loading without creating new chart

I'm using Highchart with React.
For the moment I created a starting options:
/**
* Initial chart options, with "loading" enabled
*/
const chartOptions = {
accessibility: {
enabled: false
},
chart: {
type: "column",
events: {
load() {
const chart = this;
chart.showLoading(`${LOADING}...`);
}
}
}
};
In that component I call an API that returns some data to use. So, at that moment, I want to remove the "loading" and adding the data.
I solved for the moment with:
const [options, setOptions] = useState(chartOptions);
useEffect(() => {
if (detail) {
setOptions({
...chartOptions,
chart: {
type: "column"
},
xAxis: {
categories: detail.map(
(item) =>
`${item.data_em.substring(4, 6)}/${item.data_em.substring(0, 4)}`
)
},
series: [
{
name: "Alfa",
color: "#69BC66",
data: detail.map((item) => item.ricevuti)
},
{
name: "Beta",
color: "#DC3545",
data: detail.map((item) => item.mancanti)
},
]
});
}
}, [detail]);
<ChartComponent options={options} />
So, setting a new options in local State when data are ready. But I imagine that in this manner I get a different chart.
It works, but is there a better method?
With using the highcharts-react-official wrapper, the chart is recreated on state update only if immutable option is enabled. Otherwise, only chart.update method is called to apply changes.
Therefore, it is better to apply only the new options. In your case it will be:
useEffect(() => {
if (detail) {
setOptions({
chart: {
type: "column"
},
xAxis: {
categories: detail.map(
(item) =>
`${item.data_em.substring(4, 6)}/${item.data_em.substring(0, 4)}`
)
},
series: [{
name: "Alfa",
color: "#69BC66",
data: detail.map((item) => item.ricevuti)
},
{
name: "Beta",
color: "#DC3545",
data: detail.map((item) => item.mancanti)
},
]
});
}
}, [detail]);
Live demo: https://codesandbox.io/s/highcharts-react-demo-3lvomg?file=/demo.jsx
Docs: https://www.npmjs.com/package/highcharts-react-official#optimal-way-to-update

antd chart in React: shrinks when global state changes

I have a simple antd bar chart within my React app. First it gets displayed fine, but when the user interacts with the website (and changes the global state) sometimes all of a sudden the chart shrinks.
I tried memoizing the chart and wrapped the component with memo() so that no state change in a parent component affects the chart but that did not help either.
As you can see the canvas has the correct dimensions but the chart drawn on that canvas is not filling it up anymore. The chart should be as big as the lightblue box:
import { memo } from 'react';
import { Column } from '#ant-design/plots';
import theme from '#themes/antd.charts.json';
const Chart = memo(({ data, type }) => {
const chartConfig = {
data,
loading: data.length === 0,
theme,
xField: 'type',
yField: 'value',
seriesField: 'type',
yAxis: {
label: {
formatter: (v) => numeral(v).format('0,0'),
},
},
xAxis: false,
height: 300,
appendPadding: 16,
legend: {
position: 'bottom',
flipPage: false,
itemWidth: 580 / 5, //todo: make dynamic depending on width/count
},
interactions: [
{
type: 'element-active',
},
],
label: {
position: 'top',
offsetY: 8,
formatter: ({ value }) =>
`${numeral(value).format('0,0')} ${type === 'hectare' ? `ha` : ``}`,
},
};
return <Column {...chartConfig} />;
});

FeatureLayer - won't render

I have a rather simple code that creates a FeatureLayer where I try to add some client side graphic.
facilitiesLayer = new FeatureLayer({
title: 'Facilities layers',
objectIdField: 'id',
source: [
new Graphic({
geometry: new Point({ longitude: -96.1034353, latitude: 41.5333259 }),
attributes: {
id: 1,
},
}),
],
renderer: new SimpleRenderer({
symbol: new SimpleMarkerSymbol({
size: 32,
color: '#4652C2',
outline: {
color: 'rgba(137,144,215,0.7)',
width: 2,
},
}),
}),
});
mapView.current!.map.add(facilitiesLayer);
after I add the layer to the map I immediately see this in console. If I comment out add layer addition, the map is properly displayed, meaning all of the ESRI stuff is created correct.
How do I find where this conversion fails?
using #arcgis/core 4.18.0

React js and chart js pie chart type

Hello everyone i need to get a dynamic chart js pie type ,
this is the request to get the data :
async componentDidMount(){
axios.get("http://localhost:8080/requete/tab1")
.then(response => response.data)
.then((data) =>{
this.setState({dataL : data})
})
}
this the code with static data :
const options = {
animationEnabled: true,
exportEnabled: true,
theme: "light1",
title:{
text: "Trip Expenses"
},
data: [{
type: "pie",
indexLabel: "{label}: {y}%",
startAngle: -90,
dataPoints: [
{ y: 5, label: "Lost" },
{ y: 24, label: "Won" },
]
}]
}
please what i should to do to get the dynamic value at my chart
Try using react-apexcharts. this lets you create dynamic charts as your wish
You should make new component with chart.js pie and define props, too.
After receiving data from backend, you would import this component and send this data as props.
<Pie {...this.state.data} />
props: {
data: Array,
....
}
computed() {
pie() {
return this.data || [];
}
}

Leaflet circleMarker event not working when used along with leaflet.heat

I am using ui-leaflet for our angular project. We also have leaflet.heat to create heat maps.
The issue is whenever the data is updated the event on circle markers stops working.
Other minor issue I am facing is the heat map doesn't update unless I use timeout.
Not sure what am I doing wrong, any help is appreciated.
I have created a sample jsfiddle. http://jsfiddle.net/srs/13s1fy02/2/
heatMapData = [
[60.265625, -121.640625], [60.671875, -96.328125]
]
heatMapData_1 = [
[37.265625, -121.640625], [38.671875, -96.328125]
]
circleData = {
'features': [
{
'geometry': {
'type': 'Point',
'coordinates': [-120.9998241, 39.7471494]
},
'type': 'Feature',
'properties': {
'popupContent': 'This is popup 1'
}
}
]
};
circleData_1 = {
'features': [
{
'geometry': {
'type': 'Point',
'coordinates': [-100.9998241, 39.7471494]
},
'type': 'Feature',
'properties': {
'popupContent': 'This is popup2'
}
}
]
};
onEachFeature = function(feature, layer) {
return layer.bindPopup(feature.properties.popupContent);
};
$scope.updateData = function() {
if($scope.layers.overlays.hasOwnProperty('heat')){
delete $scope.layers.overlays['heat'];
}
$scope.geojson = {};
//setTimeout(function(){ buildMap(heatMapData_1, circleData_1) }, 300);
buildMap(heatMapData_1, circleData_1);
}
buildMap = function(heatMapData, circleData){
$scope.geojson = {
data: circleData,
onEachFeature: onEachFeature,
pointToLayer: function(feature, latlng) {
return L.circleMarker(latlng, style);
}
};
$scope.layers.overlays = {
heat: {
name: 'Heat Map',
type: 'heat',
data: heatMapData,
layerOptions: {
radius: 10,
scaleRadius: true,
maxZoom: 7,
minOpacity: .5,
max: 1,
gradient: {
.4: 'green',
.6: 'yellow',
1: 'red'
}
},
visible: true
}
};
}
buildMap(heatMapData, circleData)
As for the reason why you cannot click on your Circle Marker when your heat map is on, it is probably just a matter of SVG elements stacking: the heat map is drawn after the Circle Marker and covers the whole map, hence you can no longer mouse interact with the marker.
You can trigger the issue by simply hiding and showing again your heat map overlay (not even need to update).

Resources