SITUATION IMAGE:
SITUATION:
Not showing heatMap in my Map not showing properly.
What have I done wrong ?
Why doesn't the Heatmap Leaflet appear on the Map?
And part heatmapLayer.setData(FeatureCollection); if removed heatmapLayer so setData(FeatureCollection); it pops up but instead appears a marker on the map like this:
CODE:
import React, { useEffect, useState, useRef } from "react";
import { GeoJSON } from "react-leaflet";
import { useRecoilValue, useSetRecoilState } from "recoil";
import HeatmapOverlay from "leaflet-heatmap";
import { arcgisToken } from "../recoil";
import { mapBounds, loadingMap } from "../state";
import { getLocationCity } from "../data/arcgis";
import "leaflet.heat";
export default function HSales() {
const [data, setData] = useState();
const setIsLoading = useSetRecoilState(loadingMap);
const bounds = useRecoilValue(mapBounds);
const tokenArcgis = useRecoilValue(arcgisToken);
const geoJsonLayer = useRef(null);
useEffect(() => {
const fetchDataSpeedtestKel = () => {
const body = {
returnGeometry: true,
rollbackOnFailure: true,
geometry: JSON.stringify({
xmin: bounds.west,
ymin: bounds.south,
xmax: bounds.east,
ymax: bounds.north,
spatialReference: { wkid: 4326 },
}),
geometryType: "esriGeometryEnvelope",
token: tokenArcgis,
};
setIsLoading(true);
getLocationCity(body)
.then((response) => {
const array = [];
response.features.forEach((element) => {
array.push({
type: "Feature",
properties: element["attributes"],
geometry: {
type: "Point",
coordinates: [
element["geometry"]["x"],
element["geometry"]["y"],
],
},
});
});
const FeatureCollection = {
type: "FeatureCollection",
features: array,
};
if (geoJsonLayer.current) {
geoJsonLayer.current.clearLayers().addData(FeatureCollection);
}
var cfg = {
radius: 0.1,
maxOpacity: 1,
scaleRadius: true,
useLocalExtrema: true,
latField: "x",
lngField: "y",
};
var heatmapLayer = new HeatmapOverlay(cfg);
setData(FeatureCollection);
// setData(FeatureCollection);
})
.catch((err) => console.log(err))
.finally(() => setIsLoading(false));
};
fetchDataSpeedtestKel();
}, [bounds, setIsLoading, tokenArcgis]);
if (data) {
return (
<>
<GeoJSON
ref={geoJsonLayer}
data={data}
/>
</>
);
}
}
your response from getLocationCity in the example:
export const getLocationCity = async (params) => {
try {
const body = DataCustom(params);
const result = await instanceArcgis.post(
"/rest/HomeLocation/4/query",
body,
);
return await result?.data;
}
Earlier I read and sample coding via the link:
https://www.patrick-wied.at/static/heatmapjs/example-heatmap-leaflet.html
https://codesandbox.io/s/suspicious-chandrasekhar-sybk67?file=/src/index.js
Related
I was copying code from this solution: Is there a way to use leaflet.heat in react? and I'm getting an error.
TypeError: t is undefined
enter image description here
in the currentPosition function
export const currentPosition = atom({
key: "currentPosition",
default: [-2.600, -11.01],
});
in the getLocationCity function
export const getLocationCity = async (params) => {
try {
const body = DataCustom(params);
const result = await instanceArcgis.post(
"/rest/HomeLocation/11/query",
body,
);
return await result?.data;
}catch (error) {
console.log(error);
}
But I tried different options and it still doesn't work. And it outputs the results from the API but does not come out the Heatmap color on the map which instead comes out only the words "Marker".
enter image description here
Full JS code:
import React, { useEffect, useState, useRef } from "react";
import { GeoJSON } from "react-leaflet";
import { useRecoilValue, useSetRecoilState } from "recoil";
import HeatmapOverlay from "leaflet-heatmap";
import { arcgisToken } from "../recoil";
import { mapBounds, loadingMap } from "../state";
import { getLocationCity } from "../data/arcgis";
import "leaflet.heat";
export default function HSales() {
const [data, setData] = useState();
const setIsLoading = useSetRecoilState(loadingMap);
const bounds = useRecoilValue(mapBounds);
const tokenArcgis = useRecoilValue(arcgisToken);
const geoJsonLayer = useRef(null);
useEffect(() => {
const fetchDataSpeedtestKel = () => {
const body = {
returnGeometry: true,
rollbackOnFailure: true,
geometry: JSON.stringify({
xmin: bounds.west,
ymin: bounds.south,
xmax: bounds.east,
ymax: bounds.north,
spatialReference: { wkid: 4326 },
}),
geometryType: "esriGeometryEnvelope",
token: tokenArcgis,
};
setIsLoading(true);
getLocationCity(body)
.then((response) => {
let array = [];
let points = [];
response.features.forEach((element) => {
points.push([
element["geometry"]["x"],
element["geometry"]["y"]
])
array.push({
type: "Feature",
properties: element["attributes"],
geometry: {
type: "Point",
coordinates: [
element["geometry"]["x"],
element["geometry"]["y"],
],
},
});
});
const FeatureCollection = {
type: "FeatureCollection",
features: array,
};
if (geoJsonLayer.current) {
geoJsonLayer.current.clearLayers().addData(FeatureCollection);
}
// setPosition(FeatureCollection);
setData(FeatureCollection);
L.heatLayer(points).addTo(data);
})
.catch((err) => console.log(err))
.finally(() => setIsLoading(false))
};
fetchDataSpeedtestKel();
}, [bounds, setIsLoading, tokenArcgis, position]);
if (data) {
return (
<>
<GeoJSON
ref={geoJsonLayer}
data={data}
/>
</>
);
}
}
Thank you so much!
I was copying code from this solution: Is there a way to use leaflet.heat in react? and I'm getting an error
TypeError: map.addLayer is not a function
in the currentPosition function
export const currentPosition = atom({
key: "currentPosition",
default: [-2.600, -11.01],
});
in the getLocationCity function
export const getLocationCity = async (params) => {
try {
const body = DataCustom(params);
const result = await instanceArcgis.post(
"/rest/HomeLocation/11/query",
body,
);
return await result?.data;
}catch (error) {
console.log(error);
}
I'm sure it's a var or placement order issue, but I tried various options and it still doesn't work. And it outputs results from the API but no Heatmap color comes out just 'Marker'
Full JS code:
import React, { useEffect, useState, useRef } from "react";
import { GeoJSON } from "react-leaflet";
import { useRecoilValue, useSetRecoilState } from "recoil";
import HeatmapOverlay from "leaflet-heatmap";
import { arcgisToken } from "../recoil";
import { mapBounds, loadingMap } from "../state";
import { getLocationCity } from "../data/arcgis";
import "leaflet.heat";
export default function HSales() {
const [data, setData] = useState();
const setIsLoading = useSetRecoilState(loadingMap);
const bounds = useRecoilValue(mapBounds);
const tokenArcgis = useRecoilValue(arcgisToken);
const geoJsonLayer = useRef(null);
useEffect(() => {
const fetchDataSpeedtestKel = () => {
const body = {
returnGeometry: true,
rollbackOnFailure: true,
geometry: JSON.stringify({
xmin: bounds.west,
ymin: bounds.south,
xmax: bounds.east,
ymax: bounds.north,
spatialReference: { wkid: 4326 },
}),
geometryType: "esriGeometryEnvelope",
token: tokenArcgis,
};
setIsLoading(true);
getLocationCity(body)
.then((response) => {
const array = [];
response.features.forEach((element) => {
array.push({
type: "Feature",
properties: element["attributes"],
geometry: {
type: "Point",
coordinates: [
element["geometry"]["x"],
element["geometry"]["y"],
],
},
});
});
const FeatureCollection = {
type: "FeatureCollection",
features: array,
};
if (geoJsonLayer.current) {
geoJsonLayer.current.clearLayers().addData(FeatureCollection);
}
const points = response.features
? response.features.map((element) => {
return [
element["geometry"]["x"],
element["geometry"]["y"]
];
})
: [];
setData(FeatureCollection);
L.heatLayer(points).addTo(position);
setPosition(data);
})
.catch((err) => console.log(err))
.finally(() => setIsLoading(false));
};
fetchDataSpeedtestKel();
}, [bounds, setIsLoading, tokenArcgis]);
if (data) {
return (
<>
<GeoJSON
ref={geoJsonLayer}
data={data}
/>
</>
);
}
}
Thank you so much! Jim
setData(FeatureCollection);
L.heatLayer(points).addTo(position);
setPosition(data);
"setData" this update function doesn’t update the value right away.
Rather, it enqueues the update operation. Then, after re-rendering the component, the argument of useState will be ignored and this function will return the most recent value inside data.
May be you can try something like setPosition(FeatureCollection);
I need to access Polygon coordinates from API. I'm using Leaflet and React-Leaflet but it's not showing up on maps. This is my Polygon component:
import React, { useEffect, useState, useRef } from "react";
import { GeoJSON } from "react-leaflet";
import { getHome } from "../arcgis";
import { useRecoilValue, useSetRecoilState } from "recoil";
import { arcgisToken } from "../../../recoil";
import { mapBounds, loadingMap } from "../state";
export default function Home(props) {
const [data, setData] = useState();
const setIsLoading = useSetRecoilState(loadingMap);
const bounds = useRecoilValue(mapBounds);
const tokenArcgis = useRecoilValue(arcgisToken);
const geoJsonLayer = useRef(null);
useEffect(() => {
const fetchDataSpeedtestKel = () => {
const body = {
f: "json",
where: `1=1`,
outFields: "*",
returnGeometry: true,
rollbackOnFailure: true,
geometry: JSON.stringify({
xmin: bounds.west,
ymin: bounds.south,
xmax: bounds.east,
ymax: bounds.north,
spatialReference: { wkid: 4326 },
}),
geometryType: "esriGeometryEnvelope",
inSR: 4326,
outSR: 4326,
resultRecordCount: 2000,
token: tokenArcgis,
};
setIsLoading(true);
getApartmentAPC(body)
.then((response) => {
const array = [];
response.features.forEach((element) => {
array.push({
type: "Feature",
properties: element["attributes"],
geometry: {
type: "Polygon",
coordinates: [
element["geometry"]["x"],
element["geometry"]["y"],
],
},
});
});
const FeatureCollection = {
type: "FeatureCollection",
features: array,
};
if (geoJsonLayer.current) {
geoJsonLayer.current.clearLayers().addData(FeatureCollection);
}
setData(FeatureCollection);
})
.catch((err) => console.log(err))
.finally(() => setIsLoading(false));
};
fetchDataSpeedtestKel();
}, [bounds, setIsLoading, tokenArcgis]);
if (data) {
return (
<>
<GeoJSON
ref={geoJsonLayer}
data={props.data}
/>
</>
);
} else {
return <div></div>;
}
}
The import { get Home } from "../arcgis"; section to fetch data or Polygons from the API.
And I took from the API and the link from the postman app:
import { instanceArcgis } from "./instance";
import { FormDataCustom } from "../utils/baseFunctions";
export const getHome = async (params) => {
try {
const body = FormDataCustom(params);
const result = await instanceArcgis.post(
"/rest/services/tracking/Home/1/query",
body,
);
return await result?.data;
}
};
The following image shows Polygon data not appearing in the Home feature on maps from the API:
In the below slice code I am Getting the data from a server using createAsyncThunk. Now I am trying to delete data locally for which I have written a reducer called removeData.
import { createAsyncThunk, createSlice } from "#reduxjs/toolkit";
import axios from "axios";
export const dataTableSlice = createSlice({
name: "dataTable",
initialState: {
isGridData: [],
isLoading: false,
},
reducers: {
removeData: (state, action) => {
const dataSource = [...state.isGridData];
const filteredData = dataSource.filter(
(item) => item.id !== action.payload.id
);
state.isGridData.push(filteredData);
},
},
extraReducers: (builder) => {
builder
.addCase(loadData.pending, (state, action) => {
state.isLoading = true;
})
.addCase(loadData.fulfilled, (state, action) => {
state.isGridData = [...action.payload.data];
state.isLoading = false;
});
},
});
export const loadData = createAsyncThunk("loadData", async () => {
return await axios.get("https://jsonplaceholder.typicode.com/comments");
});
export const { removeData } = dataTableSlice.actions;
export default dataTableSlice.reducer;
Component
import { Table,Popconfirm,Button } from 'antd';
import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import {loadData,removeData} from '../../features/DataTableState/DataTableSlice';
import "antd/dist/antd.css";
import './DataTable.scss';
const DataTable = () => {
const gridData = useSelector((state) => state.dataTable.isGridData);
const isLoading = useSelector((state) => state.dataTable.isLoading);
const dispatch = useDispatch();
useEffect(() => {
dispatch(loadData());
},[dispatch]);
const inventoryData = gridData.map((item) => ({
...item,
inventory:Math.floor(Math.random() * 6) + 20,
}));
const modifiedData = inventoryData.map(({body,...item}) =>({
...item,
key:item.id,
message:body,
}));
// const handleDelete = (record) =>{
// const dataSource = [...modifiedData];
// const filteredData = dataSource.filter((item) => item.id !== record.id);
// }
const columns = [
{
title:'Id',
dataIndex:'id',
align:'center',
},
{
title:'product',
dataIndex:'name',
align:'center',
editTable:true
},
{
title:'description',
dataIndex:'message',
align:'center',
editTable:true
},
{
title:'inventory',
dataIndex:'inventory',
align:'center',
editTable:false
},
{
title:'Action',
dataIndex:'action',
align:'center',
render: (_,record) =>
modifiedData.length >= 1 ? (
<Popconfirm title="Are you sure?" onConfirm={dispatch(removeData(record))}>
<Button danger type='primary'>Delete</Button>
</Popconfirm>
):null,
},
];
// const data = [
// {
// Id:1,
// product:'gas1',
// description:'18kg',
// inventory:52,
// },
// {
// Id:2,
// product:'gas1',
// description:'18kg',
// inventory:52,
// },
// {
// Id:3,
// product:'gas1',
// description:'18kg',
// inventory:52,
// },
// {
// Id:4,
// product:'gas1',
// description:'18kg',
// inventory:52,
// }
// ]
return (
<div className='data-table'>
<section className='space'></section>
<Table
className='table'
columns={columns}
dataSource={modifiedData}
bordered
loading={isLoading}
style={{flex:2}}/>
</div>
);
}
export default DataTable
Below given are errors in console:
1.serializableStateInvariantMiddleware.ts:195 A non-serializable value was detected in an action, in the path: payload.config.adapter. Value:
Take a look at the logic that dispatched this action: {type: 'loadData/fulfilled', payload: {…}, meta: {…}}
2.Warning: Cannot update a component (DataTable) while rendering a different component (Cell). To locate the bad setState() call inside Cell, follow the stack trace as described in https://reactjs.org/link/setstate-in-render
this is my react map component:
import 'mapbox-gl/dist/mapbox-gl.css';
import './switcher/switcher.css';
import mapboxgl from 'mapbox-gl';
import React, { useRef, useLayoutEffect, useEffect, useState } from 'react';
import { deviceCategories } from '../common/deviceCategories';
import { loadIcon, loadImage } from './mapUtil';
import { styleCarto} from './mapStyles';
import { useAttributePreference } from '../common/preferences';
const element = document.createElement('div');
element.style.width = '100%';
element.style.height = '100%';
export const map = new mapboxgl.Map({
container: element,
style: styleCarto(),
center: [80.379370, 23.846870],
zoom: 4.8
});
let ready = false;
const readyListeners = new Set();
const addReadyListener = listener => {
readyListeners.add(listener);
listener(ready);
};
const removeReadyListener = listener => {
readyListeners.delete(listener);
};
const updateReadyValue = value => {
ready = value;
readyListeners.forEach(listener => listener(value));
};
const initMap = async () => {
const background = await loadImage('images/background.svg');
await Promise.all(deviceCategories.map(async category => {
if (!map.hasImage(category)) {
const imageData = await loadIcon(category, background, `images/icon/car.png`);
map.addImage(category, imageData, { pixelRatio: window.devicePixelRatio });
}
}));
updateReadyValue(true);
};
map.on('load', initMap);
map.addControl(new mapboxgl.NavigationControl({
showCompass: false,
}));
const Map = ({ children }) => {
const containerEl = useRef(null);
const [mapReady, setMapReady] = useState(false);
const mapboxAccessToken = useAttributePreference('mapboxAccessToken');
useEffect(() => {
mapboxgl.accessToken = mapboxAccessToken;
}, [mapboxAccessToken]);
useEffect(() => {
const listener = ready => setMapReady(ready);
addReadyListener(listener);
return () => {
removeReadyListener(listener);
};
}, []);
useLayoutEffect(() => {
const currentEl = containerEl.current;
currentEl.appendChild(element);
if (map) {
map.resize();
}
return () => {
currentEl.removeChild(element);
};
}, [containerEl]);
return (
<div style={{ width: '100%', height: '100%' }} ref={containerEl}>
{mapReady && children}
</div>
);
};
export default Map;
I am fetching coordinates from api endpoint using socket controller, there is redux store that handle the changes in the data, however the position of the icons changes but its not smooth ,i have been trying to make it done since 5 days but i dont find any way how to do it, i am not finding mapbox documentation helpful
Below is the position map component , here the positions are being refreshed and updated to new cordinates, but i want to animate the changes on screen like movement of car on uber/ola app.
import React, { useCallback, useEffect } from 'react';
import ReactDOM from 'react-dom';
import mapboxgl from 'mapbox-gl';
import { Provider, useSelector } from 'react-redux';
import { map } from './Map';
import store from '../store';
import { useHistory } from 'react-router-dom';
import StatusView from './StatusView';
const PositionsMap = ({ positions }) => {
const id = 'positions';
const history = useHistory();
const devices = useSelector(state => state.devices.items);
const createFeature = (devices, position) => {
const device = devices[position.deviceId] || null;
return {
deviceId: position.deviceId,
name: device ? device.name : '',
category: device && (device.category || 'default'),
}
};
const onMouseEnter = () => map.getCanvas().style.cursor = 'pointer';
const onMouseLeave = () => map.getCanvas().style.cursor = '';
const onClickCallback = useCallback(event => {
const feature = event.features[0];
let coordinates = feature.geometry.coordinates.slice();
while (Math.abs(event.lngLat.lng - coordinates[0]) > 180) {
coordinates[0] += event.lngLat.lng > coordinates[0] ? 360 : -360;
}
const placeholder = document.createElement('div');
ReactDOM.render(
<Provider store={store}>
<StatusView deviceId={feature.properties.deviceId} onShowDetails={positionId => history.push(`/position/${positionId}`)} />
</Provider>,
placeholder
);
new mapboxgl.Popup({
offset: 20,
anchor: 'bottom-left',
closeButton: false,
className: 'popup'
})
.setDOMContent(placeholder)
.setLngLat(coordinates)
.addTo(map);
}, [history]);
useEffect(() => {
map.addSource(id, {
'type': 'geojson',
'data': {
type: 'FeatureCollection',
features: [],
}
});
map.addLayer({
'id': id,
'type': 'symbol',
'source': id,
'layout': {
'icon-image': '{category}',
'icon-allow-overlap': true,
'text-field': '{name}',
'text-allow-overlap': true,
'text-anchor': 'bottom',
'text-offset': [0, -2],
'text-font': ['Roboto Regular'],
'text-size': 12,
}
});
map.on('mouseenter', id, onMouseEnter);
map.on('mouseleave', id, onMouseLeave);
map.on('click', id, onClickCallback);
return () => {
Array.from(map.getContainer().getElementsByClassName('mapboxgl-popup')).forEach(el => el.remove());
map.off('mouseenter', id, onMouseEnter);
map.off('mouseleave', id, onMouseLeave);
map.off('click', id, onClickCallback);
map.removeLayer(id);
map.removeSource(id);
};
}, [onClickCallback]);
useEffect(() => {
map.getSource(id).setData({
type: 'FeatureCollection',
features: positions.map(position => ({
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [position.longitude, position.latitude]
},
properties: createFeature(devices, position),
}))
});
}, [devices, positions]);
return null;
}
export default PositionsMap;
can any body help on thin to figure what i have been missing