Why can't Polygon appear in react-leaflet from API? - javascript

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:

Related

'TypeError: t is undefined' and no heatmap color appears on the map

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!

"TypeError: map.addLayer is not a function"

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);

Why is the Heatmap Leaflet in Map not showing up?

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

Unable to smoothly animate the icons on map when coordinates changes using mapbox-gl

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

Apollo Queries triggered and causing rerendering in useContext on URL Change

GIF of Rerender occuring
I'm not sure how to proceed. As you can see, the Header's state (as passed down via context) is switching from the user's data --> undefined --> same user's data. This occurs every time there's a url change, and doesn't happen when I do things that don't change the url (like opening the cart for example).
Is this expected behaviour? Is there any way I can get the query in my context to only be called when there is no user data or when the user data changes? I tried using useMemo, but to no avail.
auth.context
import React, { useState} from "react";
import {
CURRENT_USER,
GET_LOGGED_IN_CUSTOMER,
} from "graphql/query/customer.query";
import { gql, useQuery, useLazyQuery } from "#apollo/client";
import { isBrowser } from "components/helpers/isBrowser";
export const AuthContext = React.createContext({});
export const AuthProvider = ({ children }) => {
const [customer, { data, loading, error }] = useLazyQuery(
GET_LOGGED_IN_CUSTOMER,
{
ssr: true,
}
);
const { data: auth } = useQuery(CURRENT_USER, {
onCompleted: (auth) => {
console.log(auth);
customer({
variables: {
where: {
id: auth.currentUser.id,
},
},
});
},
ssr: true,
});
console.log(data);
const isValidToken = () => {
if (isBrowser && data) {
const token = localStorage.getItem("token");
if (error) {
console.log("error", error);
}
if (token && data) {
console.log("token + auth");
return true;
} else return false;
}
};
const [isAuthenticated, makeAuthenticated] = useState(isValidToken());
function authenticate() {
makeAuthenticated(isValidToken());
}
function signout() {
makeAuthenticated(false);
localStorage.removeItem("token");
}
return (
<AuthContext.Provider
value={{
isAuthenticated,
data,
authenticate,
auth,
signout,
}}
>
{children}
</AuthContext.Provider>
);
};
(In Header, userData is equal to data just passed through an intermediary component (to provide to mobile version)).
header.tsx
import React, { useContext } from "react";
import Router, { useRouter } from "next/router";
import { useApolloClient } from "#apollo/client";
import { openModal } from "#redq/reuse-modal";
import SearchBox from "components/SearchBox/SearchBox";
import { SearchContext } from "contexts/search/search.context";
import { AuthContext } from "contexts/auth/auth.context";
import LoginModal from "containers/LoginModal";
import { RightMenu } from "./Menu/RightMenu/RightMenu";
import { LeftMenu } from "./Menu/LeftMenu/LeftMenu";
import HeaderWrapper from "./Header.style";
import LogoImage from "image/hatchli-reduced-logo.svg";
import { isCategoryPage } from "../is-home-page";
type Props = {
className?: string;
token?: string;
pathname?: string;
userData?: any;
};
const Header: React.FC<Props> = ({ className, userData }) => {
const client = useApolloClient();
const { isAuthenticated, signout } = useContext<any>(AuthContext);
const { state, dispatch } = useContext(SearchContext);
console.log(isAuthenticated);
console.log(userData);
const { pathname, query } = useRouter();
const handleLogout = () => {
if (typeof window !== "undefined") {
signout();
client.resetStore();
Router.push("/medicine");
}
};
const handleJoin = () => {
openModal({
config: {
className: "login-modal",
disableDragging: true,
width: "auto",
height: "auto",
animationFrom: { transform: "translateY(100px)" },
animationTo: { transform: "translateY(0)" },
transition: {
mass: 1,
tension: 180,
friction: 26,
},
},
component: LoginModal,
componentProps: {},
closeComponent: "",
closeOnClickOutside: true,
});
};
const onSearch = (text: any) => {
dispatch({
type: "UPDATE",
payload: {
...state,
text,
},
});
};
const { text } = state;
const onClickHandler = () => {
const updatedQuery = query.category
? { text: text, category: query.category }
: { text };
Router.push({
pathname: pathname,
query: updatedQuery,
});
};
const showSearch = isCategoryPage(pathname);
return (
<HeaderWrapper className={className}>
<LeftMenu logo={LogoImage} />
{showSearch && (
<SearchBox
className="headerSearch"
handleSearch={(value: any) => onSearch(value)}
onClick={onClickHandler}
placeholder="Search anything..."
hideType={true}
minimal={true}
showSvg={true}
style={{ width: "100%" }}
value={text || ""}
/>
)}
<RightMenu
isAuth={userData}
onJoin={handleJoin}
onLogout={handleLogout}
avatar={userData && userData.user && userData.user.avatar}
/>
</HeaderWrapper>
);
};
export default Header;

Categories