反应谷歌地图车辆实时跟踪

时间:2021-04-28 17:58:28

标签: reactjs react-hooks fetch react-google-maps

我试图通过从 api 端点获取数据来移动带有 deviceId 的选定标记。在第一次渲染时,我正在获取最后 1 分钟的坐标数据并将坐标推送到一个声明为 Path 的空数组中,每 30 秒后我运行一个 setinterval 函数,该函数每 30 秒获取最后 30 秒的数据并推送路径数组中的坐标。这是可以提供一些想法的代码:

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%` }} />}
  />
)

我想像下面提到的具有静态路径数组数据的类组件一样使用这个路径数组。

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%` }} />}
    />
  )

它工作正常(使用静态数据)并且标记平滑移动,但是。我想为每个点击的设备动态实现这一点。我发布这个是因为我被卡住了,因为我是新来的反应。我发现钩子有点容易,所以尝试使用功能组件但没有做到。卡住了 5 天,现在我很无助。有人帮我实现这个魅力。

0 个答案:

没有答案