I am trying to move the selected marker with deviceId by fetching data from api endpoint. At first render i am fetching the cordinates data for last 1 minute and pushing the cordinates in an empty array declared as Path and after every 30 seconds I am running a setinterval function which fetches the data of last 30 seconds in every 30 seconds and pushes the cordinates in the Path array. this is the code which can give some idea:
import {
withGoogleMap,
withScriptjs,
GoogleMap,
Polyline,
Marker
} from "react-google-maps";
const mapStyles = require("./mapStyles.json");
const Map = ({deviceId}) => {
const [progress, setProgress]= useState()
const path= []
const getInitialPositions = async () => {
let from = new Date()
let milliseconds = Date.parse(from)
milliseconds = milliseconds - (1* 60 * 1000)
from = new Date(milliseconds).toISOString()
console.log(from)
const to = new Date().toISOString()
console.log(to)
const response = await fetch(`/api/positions/?deviceId=${37}&from=${from}&to=${to}`, {
headers: {
'Accept': 'application/json'
}
})
const items = await response.json()
console.log(items)
items.map( item => {
path.push({lat: item.latitude, lng: item.longitude})
return path
})
console.log(path)
};
const getPositions30Seconds = async () => {
let from = new Date()
let milliseconds = Date.parse(from)
milliseconds = milliseconds - (0.5* 60 * 1000)
from = new Date(milliseconds).toISOString()
console.log(from)
const to = new Date().toISOString()
console.log(to)
const response = await fetch(`/api/positions/?deviceId=14&from=${from}&to=${to}`, {
headers: {
'Accept': 'application/json'
}
})
const items = await response.json()
console.log(items)
items.map( item => {
path.push({lat: item.latitude, lng: item.longitude})
return path
})
console.log(path)
};
useEffect (() => {
const interval = window.setInterval(getPositions30Seconds,30000)
return () => {
window.clearInterval(interval)
}
},[]);
useEffect(()=>{
getInitialPositions()
},[])
const icon = {
url: '/images/icon/car.png',
scaledSize: new window.google.maps.Size(30, 30),
anchor: { x: 10, y: 10 }
};
return (
<GoogleMap
defaultZoom={4}
defaultCenter={path[path.length-1]}
defaultOptions={{ styles: mapStyles, fullscreenControl: false, mapTypeControl: false, streetViewControl: false}}
>
{progress && (
<>
<Polyline
path={progress}
options={{ strokeColor: "light" }}
/>
<Marker
icon={icon}
position={progress[progress.length - 1]}
/>
</>
)}
</GoogleMap>
);
};
const MapComponent = withScriptjs(withGoogleMap(Map))
export default () => (
<MapComponent
googleMapURL={`https://maps.googleapis.com/maps/api/js?key=${process.env.REACT_APP_GOOGLEMAP_KEY}&v=3.exp&libraries=geometry,drawing,places`}
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `100%`, width: '100%' }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
)
I want to use this path array just like below mentioned class component which have a static Path array data.
import React from "react";
import {
withGoogleMap,
withScriptjs,
GoogleMap,
Polyline,
Marker
} from "react-google-maps";
const mapStyles = require("./mapStyles.json");
class Map extends React.Component {
state = {
progress: [],
selectedMarker: false
};
path = [
{ lat: 28.539533333333335, lng: 77.05334444444445},
{lat: 28.539581666666667, lng: 77.05323333333334},
{lat: 28.539614999999998, lng: 77.05313333333334},
{lat: 28.539766666666665, lng: 77.05258166666667},
{lat: 28.539884444444443, lng: 77.05252666666667},
{lat: 28.539884444444443, lng: 77.05252666666667},
{lat: 28.542425, lng: 77.05253666666667},
{lat: 28.544408333333333, lng: 77.05254333333333},
{lat: 28.544445, lng: 77.052655},
{lat: 28.544383333333332, lng: 77.05419333333333},
{lat: 28.544383333333332, lng: 77.05419333333333},
{lat: 28.544383333333332, lng: 77.05419333333333},
{lat: 28.544383333333332, lng: 77.05419333333333},
{lat: 28.544383333333332, lng: 77.05419333333333},
{lat: 28.544439999999998, lng: 77.05512},
{lat: 28.544561666666667, lng: 77.055295},
{lat: 28.546363333333336, lng: 77.05680833333334},
{lat: 28.54712166666667, lng: 77.05741277777777},
{lat: 28.547226666666667, lng: 77.05737},
{lat: 28.54752166666667, lng: 77.05704},
{lat: 28.54752166666667, lng: 77.05704},
{lat: 28.54752166666667, lng: 77.05704},
{lat: 28.54752166666667, lng: 77.05704},
{lat: 28.54752166666667, lng: 77.05704},
{lat: 28.547706666666667, lng: 77.05692833333333},
{lat: 28.548081666666665, lng: 77.05644666666666},
{lat: 28.548235000000002, lng: 77.05629},
{lat: 28.548235000000002, lng: 77.05629},
{lat: 28.548571666666668, lng: 77.05574333333333},
{lat: 28.548655, lng: 77.05571166666667},
{lat: 28.548745, lng: 77.05563666666667},
{lat:28.55049, lng: 77.05438},
{lat: 28.550714999999997, lng: 77.05413666666666},
{lat: 28.55175, lng: 77.05356833333333},
{lat: 28.553496666666668, lng: 77.05223166666667},
{lat: 28.553915, lng: 77.05173833333333 }
];
velocity = 50;
initialDate = new Date();
getDistance = () => {
// seconds between when the component loaded and now
const differentInTime = (new Date() - this.initialDate) / 8000; // pass to seconds
return differentInTime * this.velocity;
};
componentDidMount = () => {
this.interval = window.setInterval(this.moveObject, 100);
};
handleClick = (marker, event) => {
// console.log({ marker })
this.setState({ selectedMarker: marker })
}
componentWillUnmount = () => {
window.clearInterval(this.interval);
};
moveObject = () => {
const distance = this.getDistance();
if (!distance) {
return;
}
let progress = this.path.filter(
coordinates => coordinates.distance < distance
);
const nextLine = this.path.find(
coordinates => coordinates.distance > distance
);
if (!nextLine) {
this.setState({ progress });
return; // it's the end!
}
const lastLine = progress[progress.length - 1];
const lastLineLatLng = new window.google.maps.LatLng(
lastLine.lat,
lastLine.lng
);
const nextLineLatLng = new window.google.maps.LatLng(
nextLine.lat,
nextLine.lng
);
// distance of this line
const totalDistance = nextLine.distance - lastLine.distance;
const percentage = (distance - lastLine.distance) / totalDistance;
const position = window.google.maps.geometry.spherical.interpolate(
lastLineLatLng,
nextLineLatLng,
percentage
);
progress = progress.concat(position);
this.setState({ progress });
};
componentWillMount = () => {
this.path = this.path.map((coordinates, i, array) => {
if (i === 0) {
return { ...coordinates, distance: 0 }; // it begins here!
}
const { lat: lat1, lng: lng1 } = coordinates;
const latLong1 = new window.google.maps.LatLng(lat1, lng1);
const { lat: lat2, lng: lng2 } = array[0];
const latLong2 = new window.google.maps.LatLng(lat2, lng2);
// in meters:
const distance = window.google.maps.geometry.spherical.computeDistanceBetween(
latLong1,
latLong2
);
return { ...coordinates, distance };
});
console.log(this.path);
};
componentDidUpdate = () => {
const distance = this.getDistance();
if (!distance) {
return;
}
let progress = this.path.filter(
coordinates => coordinates.distance < distance
);
const nextLine = this.path.find(
coordinates => coordinates.distance > distance
);
let point1, point2;
if (nextLine) {
point1 = progress[progress.length - 1];
point2 = nextLine;
} else {
// it's the end, so use the latest 2
point1 = progress[progress.length - 2];
point2 = progress[progress.length - 1];
}
const point1LatLng = new window.google.maps.LatLng(point1.lat, point1.lng);
const point2LatLng = new window.google.maps.LatLng(point2.lat, point2.lng);
const angle = window.google.maps.geometry.spherical.computeHeading(
point1LatLng,
point2LatLng
);
const actualAngle = angle - 35;
const markerUrl =
'/images/icon/car.png'
const item = document.querySelector(`[src="${markerUrl}"]`);
if (item) {
// when it hasn't loaded, it's null
item.style.transform = `rotate(${actualAngle}deg)`;
}
};
render = () => {
const icon = {
url: '/images/icon/car.png',
scaledSize: new window.google.maps.Size(35, 35),
anchor: { x: 10, y: 10 }
};
return (
<GoogleMap
defaultZoom={18}
defaultCenter={{lat: 28.539766666666665, lng: 77.05258166666667}}
defaultOptions={{
styles: mapStyles,
fullscreenControl: false,
mapTypeControl: false,
streetViewControl: false,
}}
>
{this.state.progress && (
<>
<Polyline
path={this.state.progress}
options={{ strokeColor: "gray" }}
/>
<Marker
icon={icon}
position={this.state.progress[this.state.progress.length - 1]}
/>
</>
)}
</GoogleMap>
);
};
}
const MapComponent = withScriptjs(withGoogleMap(Map));
export default () => (
<MapComponent
googleMapURL={`https://maps.googleapis.com/maps/api/js?key=${process.env.REACT_APP_GOOGLEMAP_KEY}&v=3.exp&libraries=geometry,drawing,places`}
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `100%`, width: '100%' }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
)
It works fine(with static data) and the marker moves smoothly but .I want to implement this dynamically for every devices on click. I am posting this because I am stuck as I am new to react . I am finding hooks a bit easy so tried with functional component but failing to do it. stuck since 5 days and now i am helpless. Somebody help me to implement this like a charm.