UNPKG

@globalfishingwatch/react-map-gl

Version:

A React wrapper for MapboxGL-js and overlay API.

385 lines (302 loc) 9.14 kB
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty"; import PropTypes from 'prop-types'; import { document } from '../utils/globals'; function noop() {} function defaultOnError(event) { if (event) { console.error(event.error); } } const propTypes = { container: PropTypes.object, gl: PropTypes.object, mapboxApiAccessToken: PropTypes.string, mapboxApiUrl: PropTypes.string, attributionControl: PropTypes.bool, preserveDrawingBuffer: PropTypes.bool, reuseMaps: PropTypes.bool, transformRequest: PropTypes.func, mapOptions: PropTypes.object, mapStyle: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), visible: PropTypes.bool, asyncRender: PropTypes.bool, onLoad: PropTypes.func, onError: PropTypes.func, width: PropTypes.number, height: PropTypes.number, viewState: PropTypes.object, longitude: PropTypes.number, latitude: PropTypes.number, zoom: PropTypes.number, bearing: PropTypes.number, pitch: PropTypes.number, altitude: PropTypes.number }; const defaultProps = { container: document.body, mapboxApiAccessToken: getAccessToken(), mapboxApiUrl: 'https://api.mapbox.com', preserveDrawingBuffer: false, attributionControl: true, reuseMaps: false, mapOptions: {}, mapStyle: 'mapbox://styles/mapbox/light-v8', visible: true, asyncRender: false, onLoad: noop, onError: defaultOnError, width: 0, height: 0, longitude: 0, latitude: 0, zoom: 0, bearing: 0, pitch: 0, altitude: 1.5 }; export function getAccessToken() { let accessToken = null; if (typeof window !== 'undefined' && window.location) { const match = window.location.search.match(/access_token=([^&\/]*)/); accessToken = match && match[1]; } if (!accessToken && typeof process !== 'undefined') { accessToken = accessToken || process.env.MapboxAccessToken || process.env.REACT_APP_MAPBOX_ACCESS_TOKEN; } return accessToken || 'no-token'; } function checkPropTypes(props, component = 'component') { if (props.debug) { PropTypes.checkPropTypes(propTypes, props, 'prop', component); } } export default class Mapbox { constructor(props) { _defineProperty(this, "mapboxgl", void 0); _defineProperty(this, "props", defaultProps); _defineProperty(this, "_map", null); _defineProperty(this, "width", 0); _defineProperty(this, "height", 0); _defineProperty(this, "_fireLoadEvent", () => { this.props.onLoad({ type: 'load', target: this._map }); }); if (!props.mapboxgl) { throw new Error('Mapbox not available'); } this.mapboxgl = props.mapboxgl; if (!Mapbox.initialized) { Mapbox.initialized = true; this._checkStyleSheet(this.mapboxgl.version); } this._initialize(props); } finalize() { this._destroy(); return this; } setProps(props) { this._update(this.props, props); return this; } resize() { this._map.resize(); return this; } redraw() { const map = this._map; if (map.style) { if (map._frame) { map._frame.cancel(); map._frame = null; } map._render(); } } getMap() { return this._map; } _reuse(props) { this._map = Mapbox.savedMap; const oldContainer = this._map.getContainer(); const newContainer = props.container; newContainer.classList.add('mapboxgl-map'); while (oldContainer.childNodes.length > 0) { newContainer.appendChild(oldContainer.childNodes[0]); } this._map._container = newContainer; Mapbox.savedMap = null; if (props.mapStyle) { this._map.setStyle(props.mapStyle, { diff: false }); } if (this._map.isStyleLoaded()) { this._fireLoadEvent(); } else { this._map.once('styledata', this._fireLoadEvent); } } _create(props) { if (props.reuseMaps && Mapbox.savedMap) { this._reuse(props); } else { if (props.gl) { const getContext = HTMLCanvasElement.prototype.getContext; HTMLCanvasElement.prototype.getContext = () => { HTMLCanvasElement.prototype.getContext = getContext; return props.gl; }; } const mapOptions = { container: props.container, center: [0, 0], zoom: 8, pitch: 0, bearing: 0, maxZoom: 24, style: props.mapStyle, interactive: false, trackResize: false, attributionControl: props.attributionControl, preserveDrawingBuffer: props.preserveDrawingBuffer }; if (props.transformRequest) { mapOptions.transformRequest = props.transformRequest; } this._map = new this.mapboxgl.Map(Object.assign({}, mapOptions, props.mapOptions)); this._map.once('load', props.onLoad); this._map.on('error', props.onError); } return this; } _destroy() { if (!this._map) { return; } if (!Mapbox.savedMap) { Mapbox.savedMap = this._map; this._map.off('load', this.props.onLoad); this._map.off('error', this.props.onError); this._map.off('styledata', this._fireLoadEvent); } else { this._map.remove(); } this._map = null; } _initialize(props) { props = Object.assign({}, defaultProps, props); checkPropTypes(props, 'Mapbox'); this.mapboxgl.accessToken = props.mapboxApiAccessToken || defaultProps.mapboxApiAccessToken; this.mapboxgl.baseApiUrl = props.mapboxApiUrl; this._create(props); const { container } = props; Object.defineProperty(container, 'offsetWidth', { get: () => this.width }); Object.defineProperty(container, 'clientWidth', { get: () => this.width }); Object.defineProperty(container, 'offsetHeight', { get: () => this.height }); Object.defineProperty(container, 'clientHeight', { get: () => this.height }); const canvas = this._map.getCanvas(); if (canvas) { canvas.style.outline = 'none'; } this._updateMapViewport({}, props); this._updateMapSize({}, props); this.props = props; } _update(oldProps, newProps) { if (!this._map) { return; } newProps = Object.assign({}, this.props, newProps); checkPropTypes(newProps, 'Mapbox'); const viewportChanged = this._updateMapViewport(oldProps, newProps); const sizeChanged = this._updateMapSize(oldProps, newProps); if (!newProps.asyncRender && (viewportChanged || sizeChanged)) { this.redraw(); } this.props = newProps; } _updateMapSize(oldProps, newProps) { const sizeChanged = oldProps.width !== newProps.width || oldProps.height !== newProps.height; if (sizeChanged) { this.width = newProps.width; this.height = newProps.height; this.resize(); } return sizeChanged; } _updateMapViewport(oldProps, newProps) { const oldViewState = this._getViewState(oldProps); const newViewState = this._getViewState(newProps); const viewportChanged = newViewState.latitude !== oldViewState.latitude || newViewState.longitude !== oldViewState.longitude || newViewState.zoom !== oldViewState.zoom || newViewState.pitch !== oldViewState.pitch || newViewState.bearing !== oldViewState.bearing || newViewState.altitude !== oldViewState.altitude; if (viewportChanged) { this._map.jumpTo(this._viewStateToMapboxProps(newViewState)); if (newViewState.altitude !== oldViewState.altitude) { this._map.transform.altitude = newViewState.altitude; } } return viewportChanged; } _getViewState(props) { const { longitude, latitude, zoom, pitch = 0, bearing = 0, altitude = 1.5 } = props.viewState || props; return { longitude, latitude, zoom, pitch, bearing, altitude }; } _checkStyleSheet(mapboxVersion = '0.47.0') { if (typeof document === 'undefined') { return; } try { const testElement = document.createElement('div'); testElement.className = 'mapboxgl-map'; testElement.style.display = 'none'; document.body.appendChild(testElement); const isCssLoaded = window.getComputedStyle(testElement).position !== 'static'; if (!isCssLoaded) { const link = document.createElement('link'); link.setAttribute('rel', 'stylesheet'); link.setAttribute('type', 'text/css'); link.setAttribute('href', "https://api.tiles.mapbox.com/mapbox-gl-js/v".concat(mapboxVersion, "/mapbox-gl.css")); document.head.appendChild(link); } } catch (error) {} } _viewStateToMapboxProps(viewState) { return { center: [viewState.longitude, viewState.latitude], zoom: viewState.zoom, bearing: viewState.bearing, pitch: viewState.pitch }; } } _defineProperty(Mapbox, "initialized", false); _defineProperty(Mapbox, "propTypes", propTypes); _defineProperty(Mapbox, "defaultProps", defaultProps); _defineProperty(Mapbox, "savedMap", null); //# sourceMappingURL=mapbox.js.map