UNPKG

@goongmaps/goong-map-react

Version:

A fork of react-map-gl. React components for Goong JS

302 lines 7.32 kB
import WebMercatorViewport, { normalizeViewportProps } from 'viewport-mercator-project'; import { clamp } from './math-utils'; import assert from './assert'; export const MAPBOX_LIMITS = { minZoom: 0, maxZoom: 24, minPitch: 0, maxPitch: 85 }; const DEFAULT_STATE = { pitch: 0, bearing: 0, altitude: 1.5 }; const PITCH_MOUSE_THRESHOLD = 5; const PITCH_ACCEL = 1.2; export default class MapState { constructor(_ref) { let { width, height, latitude, longitude, zoom, bearing = DEFAULT_STATE.bearing, pitch = DEFAULT_STATE.pitch, altitude = DEFAULT_STATE.altitude, maxZoom = MAPBOX_LIMITS.maxZoom, minZoom = MAPBOX_LIMITS.minZoom, maxPitch = MAPBOX_LIMITS.maxPitch, minPitch = MAPBOX_LIMITS.minPitch, transitionDuration, transitionEasing, transitionInterpolator, transitionInterruption, startPanLngLat, startZoomLngLat, startRotatePos, startBearing, startPitch, startZoom } = _ref; assert(Number.isFinite(width), '`width` must be supplied'); assert(Number.isFinite(height), '`height` must be supplied'); assert(Number.isFinite(longitude), '`longitude` must be supplied'); assert(Number.isFinite(latitude), '`latitude` must be supplied'); assert(Number.isFinite(zoom), '`zoom` must be supplied'); this._viewportProps = this._applyConstraints({ width, height, latitude, longitude, zoom, bearing, pitch, altitude, maxZoom, minZoom, maxPitch, minPitch, transitionDuration, transitionEasing, transitionInterpolator, transitionInterruption }); this._state = { startPanLngLat, startZoomLngLat, startRotatePos, startBearing, startPitch, startZoom }; } getViewportProps() { return this._viewportProps; } getState() { return this._state; } panStart(_ref2) { let { pos } = _ref2; return this._getUpdatedMapState({ startPanLngLat: this._unproject(pos) }); } pan(_ref3) { let { pos, startPos } = _ref3; const startPanLngLat = this._state.startPanLngLat || this._unproject(startPos); if (!startPanLngLat) { return this; } const [longitude, latitude] = this._calculateNewLngLat({ startPanLngLat, pos }); return this._getUpdatedMapState({ longitude, latitude }); } panEnd() { return this._getUpdatedMapState({ startPanLngLat: null }); } rotateStart(_ref4) { let { pos } = _ref4; return this._getUpdatedMapState({ startRotatePos: pos, startBearing: this._viewportProps.bearing, startPitch: this._viewportProps.pitch }); } rotate(_ref5) { let { pos, deltaAngleX = 0, deltaAngleY = 0 } = _ref5; const { startRotatePos, startBearing, startPitch } = this._state; if (!Number.isFinite(startBearing) || !Number.isFinite(startPitch)) { return this; } let newRotation; if (pos) { newRotation = this._calculateNewPitchAndBearing({ ...this._getRotationParams(pos, startRotatePos), startBearing, startPitch }); } else { newRotation = { bearing: startBearing + deltaAngleX, pitch: startPitch + deltaAngleY }; } return this._getUpdatedMapState(newRotation); } rotateEnd() { return this._getUpdatedMapState({ startBearing: null, startPitch: null }); } zoomStart(_ref6) { let { pos } = _ref6; return this._getUpdatedMapState({ startZoomLngLat: this._unproject(pos), startZoom: this._viewportProps.zoom }); } zoom(_ref7) { let { pos, startPos, scale } = _ref7; assert(scale > 0, '`scale` must be a positive number'); let { startZoom, startZoomLngLat } = this._state; if (!Number.isFinite(startZoom)) { startZoom = this._viewportProps.zoom; startZoomLngLat = this._unproject(startPos) || this._unproject(pos); } assert(startZoomLngLat, '`startZoomLngLat` prop is required ' + 'for zoom behavior to calculate where to position the map.'); const zoom = this._calculateNewZoom({ scale, startZoom: startZoom || 0 }); const zoomedViewport = new WebMercatorViewport(Object.assign({}, this._viewportProps, { zoom })); const [longitude, latitude] = zoomedViewport.getMapCenterByLngLatPosition({ lngLat: startZoomLngLat, pos }); return this._getUpdatedMapState({ zoom, longitude, latitude }); } zoomEnd() { return this._getUpdatedMapState({ startZoomLngLat: null, startZoom: null }); } _getUpdatedMapState(newProps) { return new MapState(Object.assign({}, this._viewportProps, this._state, newProps)); } _applyConstraints(props) { const { maxZoom, minZoom, zoom } = props; props.zoom = clamp(zoom, minZoom, maxZoom); const { maxPitch, minPitch, pitch } = props; props.pitch = clamp(pitch, minPitch, maxPitch); Object.assign(props, normalizeViewportProps(props)); return props; } _unproject(pos) { const viewport = new WebMercatorViewport(this._viewportProps); return pos && viewport.unproject(pos); } _calculateNewLngLat(_ref8) { let { startPanLngLat, pos } = _ref8; const viewport = new WebMercatorViewport(this._viewportProps); return viewport.getMapCenterByLngLatPosition({ lngLat: startPanLngLat, pos }); } _calculateNewZoom(_ref9) { let { scale, startZoom } = _ref9; const { maxZoom, minZoom } = this._viewportProps; const zoom = startZoom + Math.log2(scale); return clamp(zoom, minZoom, maxZoom); } _calculateNewPitchAndBearing(_ref10) { let { deltaScaleX, deltaScaleY, startBearing, startPitch } = _ref10; deltaScaleY = clamp(deltaScaleY, -1, 1); const { minPitch, maxPitch } = this._viewportProps; const bearing = startBearing + 180 * deltaScaleX; let pitch = startPitch; if (deltaScaleY > 0) { pitch = startPitch + deltaScaleY * (maxPitch - startPitch); } else if (deltaScaleY < 0) { pitch = startPitch - deltaScaleY * (minPitch - startPitch); } return { pitch, bearing }; } _getRotationParams(pos, startPos) { const deltaX = pos[0] - startPos[0]; const deltaY = pos[1] - startPos[1]; const centerY = pos[1]; const startY = startPos[1]; const { width, height } = this._viewportProps; const deltaScaleX = deltaX / width; let deltaScaleY = 0; if (deltaY > 0) { if (Math.abs(height - startY) > PITCH_MOUSE_THRESHOLD) { deltaScaleY = deltaY / (startY - height) * PITCH_ACCEL; } } else if (deltaY < 0) { if (startY > PITCH_MOUSE_THRESHOLD) { deltaScaleY = 1 - centerY / startY; } } deltaScaleY = Math.min(1, Math.max(-1, deltaScaleY)); return { deltaScaleX, deltaScaleY }; } } //# sourceMappingURL=map-state.js.map