website/src/Components/Map.js
2020-03-01 20:40:51 +01:00

188 lines
4.9 KiB
JavaScript

import React from 'react';
import ReactMapGL, { Marker } from 'react-map-gl';
import { Button } from "react-bootstrap";
import XmlReader from 'xml-reader';
import { withToastManager } from 'react-toast-notifications';
import PropTypes from 'prop-types';
import { haveSelectedGas, extractGasStationFromXml } from '../helpers';
import 'mapbox-gl/dist/mapbox-gl.css';
const mapboxToken = 'pk.eyJ1IjoiZGFya291IiwiYSI6ImNrNzkwdmlsdTBtMmwzZnM0ZmI4Z3h4czIifQ.GU2CdcMiKiApHNhI0ylGtQ';
class Map extends React.Component {
constructor(props) {
super(props);
this.state = {
viewport: {
width: '100vw',
height: '100vh',
latitude: 44.837789,
longitude: -0.57918,
zoom: 11,
},
userLocation: {
// latitude: 44.837789,
// longitude: -0.57918,
},
gasStations: [],
};
this.mapRef = React.createRef();
this.loadGasStations();
}
componentDidMount() {
this.setUserLocation();
}
/**
* Méthode permettant de mettre à jour la position de la map
* @param {Object} viewport
*/
onViewportChange = (viewport) => {
this.setState({ viewport });
}
/**
* Méthode permettant de sauvegarder la position de l'utilisateur
*/
setUserLocation() {
navigator.geolocation.getCurrentPosition((position) => {
const setUserLocation = {
latitude: position.coords.latitude,
longitude: position.coords.longitude,
};
const newViewport = {
height: '100vh',
width: '100vw',
latitude: position.coords.latitude,
longitude: position.coords.longitude,
zoom: 10,
};
this.setState({
viewport: newViewport,
userLocation: setUserLocation,
});
});
}
/**
* Méthode permettant de filter sur la liste des stations affichables sur la carte
* @param {Object} gasStation
* @return {Boolean}
*/
displayThisGasStation = (gasStation) => {
const mapGL = this.mapRef.getMap();
const bounds = mapGL.getBounds();
return (bounds._ne.lat > gasStation.latitude && bounds._sw.lat < gasStation.latitude)
&& (bounds._ne.lng > gasStation.longitude && bounds._sw.lng < gasStation.longitude);
}
/**
* Méthode permettant de charger le fichier xml contenant la liste des stations
*/
loadGasStations() {
const {
toastManager,
} = this.props;
fetch('/gasStations.xml')
.then((response) => response.text())
.then((response) => {
const reader = XmlReader.create();
reader.on('done', (data) => {
const pdv = data.children;
const gasStations = [];
for (let i = 0; i < pdv.length; i += 1) {
const currentPdv = pdv[i];
gasStations.push(extractGasStationFromXml(currentPdv));
}
this.setState((prevState) => ({
...prevState,
gasStations,
}));
});
reader.parse(response);
}).catch(() => {
toastManager.add('Erreur lors du chargement de la liste des stations', { appearance: 'error', autoDismiss: true });
});
}
/**
* Méthode gérant le rendu de la vue
*/
render() {
const {
viewport,
userLocation,
gasStations,
} = this.state;
const {
showGasStation,
selectedGasType,
} = this.props;
return (
<>
<ReactMapGL
{...viewport}
mapStyle="mapbox://styles/mapbox/outdoors-v11"
onViewportChange={this.onViewportChange}
mapboxApiAccessToken={mapboxToken}
ref={(map) => { if (map) this.mapRef = map; }}
>
{
Object.keys(userLocation).length !== 0 ? (
<Marker
latitude={userLocation.latitude}
longitude={userLocation.longitude}
>
<img className="locationIcon" src="/car.png" alt="My position" />
</Marker>
) : (null)
}
{gasStations.filter(this.displayThisGasStation).filter((station) => haveSelectedGas(station, selectedGasType)).map((gasStation) => (
<Marker
key={gasStation.id}
latitude={gasStation.latitude}
longitude={gasStation.longitude}
>
<Button
variant="link"
onClick={() => showGasStation(gasStation)}
onFocus={() => { }}
onBlur={() => { }}
>
<img
className="locationIcon"
src="/gas-station.png"
alt={`${gasStation.id}`}
/>
</Button>
</Marker>
))}
</ReactMapGL>
</>
);
}
}
Map.propTypes = {
selectedGasType: PropTypes.string.isRequired,
showGasStation: PropTypes.func.isRequired,
toastManager: PropTypes.shape({
add: PropTypes.func,
}).isRequired,
};
export default withToastManager(Map);