188 lines
4.9 KiB
JavaScript
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);
|