UNPKG

@globalfishingwatch/react-map-gl

Version:

A React wrapper for MapboxGL-js and overlay API.

286 lines (242 loc) 7.62 kB
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty"; import * as React from 'react'; import { PureComponent, createRef } from 'react'; import PropTypes from 'prop-types'; import { normalizeStyle } from '../utils/style-utils'; import WebMercatorViewport from 'viewport-mercator-project'; import ResizeObserver from 'resize-observer-polyfill'; import Mapbox from '../mapbox/mapbox'; import mapboxgl from '../utils/mapboxgl'; import { checkVisibilityConstraints } from '../utils/map-constraints'; import { MAPBOX_LIMITS } from '../utils/map-state'; import MapContext, { MapContextProvider } from './map-context'; const TOKEN_DOC_URL = 'https://visgl.github.io/react-map-gl/docs/get-started/mapbox-tokens'; const NO_TOKEN_WARNING = 'A valid API access token is required to use Mapbox data'; function noop() {} const UNAUTHORIZED_ERROR_CODE = 401; const CONTAINER_STYLE = { position: 'absolute', width: '100%', height: '100%', overflow: 'hidden' }; const propTypes = Object.assign({}, Mapbox.propTypes, { width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), onResize: PropTypes.func, preventStyleDiffing: PropTypes.bool, disableTokenWarning: PropTypes.bool, visible: PropTypes.bool, className: PropTypes.string, style: PropTypes.object, visibilityConstraints: PropTypes.object }); const defaultProps = Object.assign({}, Mapbox.defaultProps, { preventStyleDiffing: false, disableTokenWarning: false, visible: true, onResize: noop, className: '', style: null, visibilityConstraints: MAPBOX_LIMITS }); export default class StaticMap extends PureComponent { constructor(...args) { super(...args); _defineProperty(this, "state", { accessTokenInvalid: false }); _defineProperty(this, "_mapbox", null); _defineProperty(this, "_map", null); _defineProperty(this, "_mapboxMapRef", createRef()); _defineProperty(this, "_mapContainerRef", createRef()); _defineProperty(this, "_queryParams", {}); _defineProperty(this, "_width", 0); _defineProperty(this, "_height", 0); _defineProperty(this, "_resizeObserver", null); _defineProperty(this, "_context", null); _defineProperty(this, "getMap", () => { return this._map; }); _defineProperty(this, "queryRenderedFeatures", (geometry, options = {}) => { return this._map.queryRenderedFeatures(geometry, options); }); _defineProperty(this, "_mapboxMapError", evt => { const statusCode = evt.error && evt.error.status || evt.status; if (statusCode === UNAUTHORIZED_ERROR_CODE && !this.state.accessTokenInvalid) { console.error(NO_TOKEN_WARNING); this.setState({ accessTokenInvalid: true }); } this.props.onError(evt); }); } static supported() { return mapboxgl && mapboxgl.supported(); } componentDidMount() { if (!StaticMap.supported()) { return; } const { mapStyle } = this.props; this._mapbox = new Mapbox(Object.assign({}, this.props, { mapboxgl, width: this._width, height: this._height, container: this._mapboxMapRef.current, onError: this._mapboxMapError, mapStyle: normalizeStyle(mapStyle) })); this._map = this._mapbox.getMap(); const resizeObserver = new ResizeObserver(entries => { if (entries[0].contentRect) { const { width, height } = entries[0].contentRect; this._width = width; this._height = height; this.props.onResize({ width, height }); this.forceUpdate(); } }); const container = this._mapContainerRef.current; if (container) { resizeObserver.observe(container); } this._resizeObserver = resizeObserver; } componentDidUpdate(prevProps) { if (this._mapbox) { this._updateMapStyle(prevProps, this.props); this._updateMapProps(this.props); } if (this._context && this._context.setMap && !this._context.map) { this._context.setMap(this._map); } } componentWillUnmount() { if (this._mapbox) { this._mapbox.finalize(); this._mapbox = null; this._map = null; } if (this._resizeObserver) { this._resizeObserver.disconnect(); } } _updateMapSize(width, height) { if (this._width !== width || this._height !== height) { this._width = width; this._height = height; this._updateMapProps(this.props); } } _updateMapStyle(oldProps, newProps) { const mapStyle = newProps.mapStyle; const oldMapStyle = oldProps.mapStyle; if (mapStyle !== oldMapStyle && mapStyle) { this._map.setStyle(normalizeStyle(mapStyle), { diff: !this.props.preventStyleDiffing }); } } _updateMapProps(props) { if (!this._mapbox) { return; } this._mapbox.setProps(Object.assign({}, props, { width: this._width, height: this._height })); } _renderNoTokenWarning() { if (this.state.accessTokenInvalid && !this.props.disableTokenWarning) { const style = { position: 'absolute', left: 0, top: 0 }; return React.createElement("div", { key: "warning", id: "no-token-warning", style: style }, React.createElement("h3", { key: "header" }, "NO_TOKEN_WARNING"), React.createElement("div", { key: "text" }, "For information on setting up your basemap, read"), React.createElement("a", { key: "link", href: TOKEN_DOC_URL }, "Note on Map Tokens")); } return null; } _renderOverlays() { if (!this._map) { return null; } const { _width: width, _height: height } = this; this._updateMapSize(width, height); return React.createElement(MapContext.Consumer, null, interactiveContext => { this._context = interactiveContext; const context = { ...interactiveContext, viewport: interactiveContext.viewport || new WebMercatorViewport({ ...this.props, ...this.props.viewState, width, height }), map: this._map, container: interactiveContext.container || this._mapContainerRef.current }; return React.createElement(MapContextProvider, { value: context }, React.createElement("div", { key: "map-overlays", className: "overlays", style: CONTAINER_STYLE }, this.props.children)); }); } render() { const { className, width, height, style, visibilityConstraints } = this.props; const mapContainerStyle = Object.assign({ position: 'relative' }, style, { width, height }); const visible = this.props.visible && checkVisibilityConstraints(this.props.viewState || this.props, visibilityConstraints); const mapStyle = Object.assign({}, CONTAINER_STYLE, { visibility: visible ? 'inherit' : 'hidden' }); return React.createElement("div", { key: "map-container", style: mapContainerStyle, ref: this._mapContainerRef }, React.createElement("div", { key: "map-mapbox", ref: this._mapboxMapRef, style: mapStyle, className: className }), this._renderOverlays(), this._renderNoTokenWarning()); } } _defineProperty(StaticMap, "propTypes", propTypes); _defineProperty(StaticMap, "defaultProps", defaultProps); //# sourceMappingURL=static-map.js.map