UNPKG

lml-main

Version:

This is now a mono repository published into many standalone packages.

332 lines 12.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const React = require("react"); const cosmoui_1 = require("cosmoui"); const react_redux_1 = require("react-redux"); const constants_1 = require("../../mapping/constants"); const Actions = require("../../mapping/actions"); const Selectors = require("../../mapping/selectors"); const lodash_1 = require("lodash"); const Data = require("../../mapping/data"); // TODO - this result thingy needs to go const Result = require("./result"); const ts_utils_1 = require("@lml/ts-utils"); const comparePoints = (a, b) => a && b && a.coordinates && a.coordinates && a.coordinates.latitude === b.coordinates.latitude && a.coordinates.longitude === b.coordinates.longitude; class MapComponent extends React.Component { constructor() { super(...arguments); this.mapCreated = false; this.trafficLayer = null; this.trafficLayerShowing = false; this.markers = {}; this.polygons = {}; this.latLngJSONToPoint = (latLng) => ({ type: 'Point', coordinates: { latitude: latLng.lat, longitude: latLng.lng, }, }); this.pointToLatLng = (point) => new google.maps.LatLng(point.coordinates.latitude, point.coordinates.longitude); this.setMapElRef = (mapEl) => this.mapEl = mapEl; } componentDidMount() { this.createMapIfAPIAvailable(); } componentDidUpdate() { this.createMapIfAPIAvailable(); if (this.mapCreated) { // console.log('MAP DID UPDATE', this.props.markers) this.panToCenter(); this.showOrHideTrafficLayer(); this.updateMarkers(); this.updatePolygons(); this.updateDirections(); } } createMapIfAPIAvailable() { if (this.props.google.mapsApiLoaded) { this.createMap(); } } createMap() { if (!this.mapCreated) { const { lat, lng, zoom } = Data.defaultBounds; const center = new google.maps.LatLng(lat, lng); this.map = new google.maps.Map(this.mapEl, { center, zoom }); this.setUserLocation(); this.map.setOptions({ mapTypeControl: false, streetViewControl: false, styles: Data.mapStyle, }); this.mapCreated = true; this.addListenersToMap(); this.directionsService = new google.maps.DirectionsService(); this.directionsDisplay = new google.maps.DirectionsRenderer(); } } setUserLocation() { if (navigator.geolocation) { navigator.geolocation.getCurrentPosition(position => { const { latitude, longitude } = position.coords; const userLocation = { type: 'Point', coordinates: { latitude, longitude }, }; this.props.panMap(userLocation); }); } } addListenersToMap() { const boundsChanged = lodash_1.debounce(() => this.boundsChanged(), 1000); this.map.addListener('bounds_changed', boundsChanged); } boundsChanged() { const bounds = this.map.getBounds(); const center = this.map.getCenter().toJSON(); const ne = bounds.getNorthEast().toJSON(); const sw = bounds.getSouthWest().toJSON(); const nePt = this.latLngJSONToPoint(ne); const swPt = this.latLngJSONToPoint(sw); const centerPt = this.latLngJSONToPoint(center); // console.log('BOUNDS CHANGED', this.center, centerPt) if (!comparePoints(this.center, centerPt)) { this.props.updateBounds(nePt, swPt, centerPt); } } panToCenter() { const { center } = this.props; if (this.center !== center) { this.map.panTo(this.pointToLatLng(center)); this.center = center; } } showOrHideTrafficLayer() { if (this.props.trafficShowing) { this.showTrafficLayer(); return; } this.hideTrafficLayer(); } showTrafficLayer() { if (!this.trafficLayer) { this.trafficLayer = new google.maps.TrafficLayer(); } this.trafficLayer.setMap(this.map); this.trafficLayerShowing = true; } hideTrafficLayer() { if (this.trafficLayer && this.trafficLayerShowing) { this.trafficLayer.setMap(null); this.trafficLayerShowing = true; // really??? this seems improbable! } } updateMarkers() { constants_1.MAP_FILTER_NAMES.forEach((type) => { this.updateMarkersForType(type, this.props.markers[type]); }); } updateMarkersForType(type, markerModels) { if (!(this.markers[type] && Array.isArray(this.markers[type]))) { this.markers[type] = []; } const mm = this.markersForTypeToMap(type); markerModels.forEach((model) => { if (model.position && model.position.coordinates) { const marker = mm.get(model.id); if (marker) { this.updateMarker(marker, model); mm.delete(model.id); } else { this.addMarker(type, model); } } else { console.warn('model does not have proper coordinates', model); } }); this.removeMarkersInMapFromMap(type, mm); } updateMarker(marker, model) { // console.log('UPDATE MARKER', marker, model) marker.setPosition(this.pointToLatLng(model.position)); } addMarker(type, model) { const zIndex = ts_utils_1.getRandomIntOfLength(Data.icons()[type].zIndexLength || 4); const config = { position: this.pointToLatLng(model.position), title: model.title, icon: Object.assign({}, Data.icons()[type], { zIndex }), zIndex, map: this.map, }; // only add labels to couriers if (['courier', 'activeCourier'].indexOf(type) !== -1) { config.label = { text: model.label || '', // fontWeight: 'bold', fontSize: '10px', fontFamily: 'Open Sans', color: 'white', }; } // console.log('ADD MARKER', type, model, config) const marker = new google.maps.Marker(config); marker.id = model.id; marker.addListener('click', () => { this.props.markerClicked(marker.id); }); this.markers[type].push(marker); } markersForTypeToMap(type) { const mm = new Map(); this.markers[type].forEach((marker) => { mm.set(marker.id, marker); }); return mm; } removeMarkersInMapFromMap(type, mm) { this.markers[type] = this.markers[type].filter((marker) => { if (mm.has(marker.id)) { // console.log('REMOVE MARKER', type, mm) mm.get(marker.id).setMap(null); return false; } return true; }); } updatePolygons() { const { polygons } = this.props; Object.keys(polygons).forEach((type) => { this.updatePolygonsForType(type, polygons[type]); }); } updatePolygonsForType(type, polygons) { if (!(this.polygons[type] && Array.isArray(this.polygons[type]))) { this.polygons[type] = []; } const pm = this.polygonsForTypeToMap(type); polygons.forEach((p) => { if (pm.has(p.id)) { // Already on the map so delete it from the Map pm.delete(p.id); } else { this.addPolygon(type, p); } }); this.removePolygonsInMapFromMap(type, pm); } polygonsForTypeToMap(type) { const pm = new Map(); this.polygons[type].forEach((p) => { pm.set(p.id, p); }); return pm; } addPolygon(type, model) { const options = Object.assign(Data.makeShapeForType(type), { paths: this.coordinatesToPath(model.perimeter) }); const polygon = new google.maps.Polygon(options); polygon.id = model.id; polygon.setMap(this.map); this.polygons[type].push(polygon); } coordinatesToPath(perimeter) { return perimeter.coordinates[0][0].map((point) => ({ lat: point[1], lng: point[0] })); } removePolygonsInMapFromMap(type, pm) { this.polygons[type] = this.polygons[type].filter((p) => { if (pm.has(p.id)) { p.setMap(null); return false; } return true; }); } updateDirections() { const { directions } = this.props; if (this.directions !== directions) { // set the new directions on this component this.directions = directions; // it there are directions if (directions) { // then set them on the map this.showDirections(directions); } else { // otherwise remove the existing directions this.directionsDisplay.setMap(null); } } } showDirections(directions) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const result = yield this.requestDirections(this.constructDirectionsRequest(directions)); if (result.success === true) { this.directionsDisplay.setMap(this.map); this.directionsDisplay.setDirections(result.value); } else { console.error('Error displaying directions'); console.error(result.error); console.error(result.error.stack); } }); } requestDirections(request) { return new Promise((resolve) => { this.directionsService.route(request, (result, status) => { if (status !== 'OK') { return resolve(Result.mkFailure(status)); } return resolve(Result.mkSuccess(result)); }); }); } constructDirectionsRequest(directions) { const dWaypoints = directions.waypoints.slice(); const origin = this.pointToLatLng(dWaypoints[0]); const destination = this.pointToLatLng(dWaypoints.slice(-1)[0]); const waypoints = dWaypoints.slice(1, -1).map((w) => ({ location: this.pointToLatLng(w), stopover: true })); return { origin, destination, waypoints, travelMode: 'DRIVING', transitOptions: { departureTime: new Date(), }, }; } render() { return (React.createElement(cosmoui_1.Column, { domRef: this.setMapElRef, onClick: this.props.onClick, className: this.props.className }, this.props.google.mapsAuthError ? 'The google maps key is invalid please contact support' : 'Map loading...')); } } const mapStateToProps = (state, ownProps) => ({ google: state.google, trafficShowing: Selectors.getTrafficShowing(state), center: Selectors.getMapCenter(state), directions: Selectors.getMapDirections(state), polygons: Selectors.getMapPolygons(state), // todo - originally you could filter the markers // according to which ones you wish to show or hide // however this needs to be reimplemented using reselect markers: Selectors.getMapMarkers(state), }); const dispatchToProps = { panMap: Actions.panMap, showTraffic: Actions.showTraffic, hideTraffic: Actions.hideTraffic, updateBounds: Actions.updateBounds, toggleMapFilter: Actions.toggleMapFilter, markerClicked: Actions.markerClicked, }; exports.Maps = react_redux_1.connect(mapStateToProps, dispatchToProps)(MapComponent); //# sourceMappingURL=map.js.map