UNPKG

google-map-react

Version:

Isomorphic component that allows rendering react components on a google map

1,711 lines (1,387 loc) 66 kB
import React, { Component } from 'react'; import PropTypes from 'prop-types'; import ReactDOM from 'react-dom'; import EventEmitter from 'eventemitter3'; import Point from '@mapbox/point-geometry'; function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } var style = { width: '100%', height: '100%', left: 0, top: 0, margin: 0, padding: 0, position: 'absolute' }; var GoogleMapMap = /*#__PURE__*/function (_Component) { _inheritsLoose(GoogleMapMap, _Component); function GoogleMapMap() { return _Component.apply(this, arguments) || this; } var _proto = GoogleMapMap.prototype; _proto.shouldComponentUpdate = function shouldComponentUpdate() { return false; }; _proto.render = function render() { var registerChild = this.props.registerChild; return /*#__PURE__*/React.createElement("div", { ref: registerChild, style: style }); }; return GoogleMapMap; }(Component); var MarkerDispatcher = /*#__PURE__*/function (_EventEmitter) { _inheritsLoose(MarkerDispatcher, _EventEmitter); function MarkerDispatcher(gmapInstance) { var _this; _this = _EventEmitter.call(this) || this; _this.gmapInstance = gmapInstance; return _this; } var _proto = MarkerDispatcher.prototype; _proto.getChildren = function getChildren() { return this.gmapInstance.props.children; }; _proto.getMousePosition = function getMousePosition() { return this.gmapInstance.mouse_; }; _proto.getUpdateCounter = function getUpdateCounter() { return this.gmapInstance.updateCounter_; }; _proto.dispose = function dispose() { this.gmapInstance = null; this.removeAllListeners(); }; return MarkerDispatcher; }(EventEmitter); var omit = function omit(obj, keys) { var rest = _extends({}, obj); for (var i = 0; i < keys.length; i++) { var key = keys[i]; if (key in rest) { delete rest[key]; } } return rest; }; var hasOwnProperty = Object.prototype.hasOwnProperty; function is(x, y) { if (x === y) { return x !== 0 || y !== 0 || 1 / x === 1 / y; } return x !== x && y !== y; } function shallowEqual(objA, objB) { if (is(objA, objB)) { return true; } if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) { return false; } var keysA = Object.keys(objA); var keysB = Object.keys(objB); if (keysA.length !== keysB.length) { return false; } for (var i = 0; i < keysA.length; i++) { if (!hasOwnProperty.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) { return false; } } return true; } var mainStyle = { width: '100%', height: '100%', left: 0, top: 0, margin: 0, padding: 0, position: 'absolute' }; var style$1 = { width: 0, height: 0, left: 0, top: 0, backgroundColor: 'transparent', position: 'absolute' }; var GoogleMapMarkers = /*#__PURE__*/function (_Component) { _inheritsLoose(GoogleMapMarkers, _Component); function GoogleMapMarkers(props) { var _this; _this = _Component.call(this, props) || this; _this._getState = function () { return { children: _this.props.dispatcher.getChildren(), updateCounter: _this.props.dispatcher.getUpdateCounter() }; }; _this._onChangeHandler = function () { if (!_this.dimensionsCache_) { return; } var prevChildCount = (_this.state.children || []).length; var state = _this._getState(); _this.setState(state, function () { return (state.children || []).length !== prevChildCount && _this._onMouseChangeHandler(); }); }; _this._onChildClick = function () { if (_this.props.onChildClick) { if (_this.hoverChildProps_) { var hoverKey = _this.hoverKey_; var childProps = _this.hoverChildProps_; _this.props.onChildClick(hoverKey, childProps); } } }; _this._onChildMouseDown = function () { if (_this.props.onChildMouseDown) { if (_this.hoverChildProps_) { var hoverKey = _this.hoverKey_; var childProps = _this.hoverChildProps_; _this.props.onChildMouseDown(hoverKey, childProps); } } }; _this._onChildMouseEnter = function (hoverKey, childProps) { if (!_this.dimensionsCache_) { return; } if (_this.props.onChildMouseEnter) { _this.props.onChildMouseEnter(hoverKey, childProps); } _this.hoverChildProps_ = childProps; _this.hoverKey_ = hoverKey; _this.setState({ hoverKey: hoverKey }); }; _this._onChildMouseLeave = function () { if (!_this.dimensionsCache_) { return; } var hoverKey = _this.hoverKey_; var childProps = _this.hoverChildProps_; if (hoverKey !== undefined && hoverKey !== null) { if (_this.props.onChildMouseLeave) { _this.props.onChildMouseLeave(hoverKey, childProps); } _this.hoverKey_ = null; _this.hoverChildProps_ = null; _this.setState({ hoverKey: null }); } }; _this._onMouseAllow = function (value) { if (!value) { _this._onChildMouseLeave(); } _this.allowMouse_ = value; }; _this._onMouseChangeHandler = function () { if (_this.allowMouse_) { _this._onMouseChangeHandlerRaf(); } }; _this._onMouseChangeHandlerRaf = function () { if (!_this.dimensionsCache_) { return; } var mp = _this.props.dispatcher.getMousePosition(); if (mp) { var distances = []; var hoverDistance = _this.props.getHoverDistance(); React.Children.forEach(_this.state.children, function (child, childIndex) { if (!child) return; if (child.props.latLng === undefined && child.props.lat === undefined && child.props.lng === undefined) { return; } var childKey = child.key !== undefined && child.key !== null ? child.key : childIndex; var dist = _this.props.distanceToMouse(_this.dimensionsCache_[childKey], mp, child.props); if (dist < hoverDistance) { distances.push({ key: childKey, dist: dist, props: child.props }); } }); if (distances.length) { distances.sort(function (a, b) { return a.dist - b.dist; }); var hoverKey = distances[0].key; var childProps = distances[0].props; if (_this.hoverKey_ !== hoverKey) { _this._onChildMouseLeave(); _this._onChildMouseEnter(hoverKey, childProps); } } else { _this._onChildMouseLeave(); } } else { _this._onChildMouseLeave(); } }; _this._getDimensions = function (key) { var childKey = key; return _this.dimensionsCache_[childKey]; }; _this.dimensionsCache_ = {}; _this.hoverKey_ = null; _this.hoverChildProps_ = null; _this.allowMouse_ = true; _this.state = _extends({}, _this._getState(), { hoverKey: null }); return _this; } var _proto = GoogleMapMarkers.prototype; _proto.componentDidMount = function componentDidMount() { this.props.dispatcher.on('kON_CHANGE', this._onChangeHandler); this.props.dispatcher.on('kON_MOUSE_POSITION_CHANGE', this._onMouseChangeHandler); this.props.dispatcher.on('kON_CLICK', this._onChildClick); this.props.dispatcher.on('kON_MDOWN', this._onChildMouseDown); }; _proto.shouldComponentUpdate = function shouldComponentUpdate(nextProps, nextState) { if (this.props.experimental === true) { return !shallowEqual(this.props, nextProps) || !shallowEqual(omit(this.state, ['hoverKey']), omit(nextState, ['hoverKey'])); } return !shallowEqual(this.props, nextProps) || !shallowEqual(this.state, nextState); }; _proto.componentWillUnmount = function componentWillUnmount() { this.props.dispatcher.removeListener('kON_CHANGE', this._onChangeHandler); this.props.dispatcher.removeListener('kON_MOUSE_POSITION_CHANGE', this._onMouseChangeHandler); this.props.dispatcher.removeListener('kON_CLICK', this._onChildClick); this.props.dispatcher.removeListener('kON_MDOWN', this._onChildMouseDown); this.dimensionsCache_ = null; }; _proto.render = function render() { var _this2 = this; var mainElementStyle = this.props.style || mainStyle; this.dimensionsCache_ = {}; var markers = React.Children.map(this.state.children, function (child, childIndex) { if (!child) return undefined; if (child.props.latLng === undefined && child.props.lat === undefined && child.props.lng === undefined) { return React.cloneElement(child, { $geoService: _this2.props.geoService, $onMouseAllow: _this2._onMouseAllow, $prerender: _this2.props.prerender }); } var latLng = child.props.latLng !== undefined ? child.props.latLng : { lat: child.props.lat, lng: child.props.lng }; var pt = _this2.props.insideMapPanes ? _this2.props.geoService.fromLatLngToDivPixel(latLng) : _this2.props.geoService.fromLatLngToCenterPixel(latLng); var stylePtPos = { left: pt.x, top: pt.y }; if (child.props.seLatLng !== undefined || child.props.seLat !== undefined && child.props.seLng !== undefined) { var seLatLng = child.props.seLatLng !== undefined ? child.props.seLatLng : { lat: child.props.seLat, lng: child.props.seLng }; var sePt = _this2.props.insideMapPanes ? _this2.props.geoService.fromLatLngToDivPixel(seLatLng) : _this2.props.geoService.fromLatLngToCenterPixel(seLatLng); stylePtPos.width = sePt.x - pt.x; stylePtPos.height = sePt.y - pt.y; } var containerPt = _this2.props.geoService.fromLatLngToContainerPixel(latLng); var childKey = child.key !== undefined && child.key !== null ? child.key : childIndex; _this2.dimensionsCache_[childKey] = _extends({ x: containerPt.x, y: containerPt.y }, latLng); return /*#__PURE__*/React.createElement("div", { key: childKey, style: _extends({}, style$1, stylePtPos), className: child.props.$markerHolderClassName }, React.cloneElement(child, { $hover: childKey === _this2.state.hoverKey, $getDimensions: _this2._getDimensions, $dimensionKey: childKey, $geoService: _this2.props.geoService, $onMouseAllow: _this2._onMouseAllow, $prerender: _this2.props.prerender })); }); return /*#__PURE__*/React.createElement("div", { style: mainElementStyle }, markers); }; return GoogleMapMarkers; }(Component); GoogleMapMarkers.propTypes = { geoService: PropTypes.any, style: PropTypes.any, distanceToMouse: PropTypes.func, dispatcher: PropTypes.any, onChildClick: PropTypes.func, onChildMouseDown: PropTypes.func, onChildMouseLeave: PropTypes.func, onChildMouseEnter: PropTypes.func, getHoverDistance: PropTypes.func, insideMapPanes: PropTypes.bool, prerender: PropTypes.bool }; GoogleMapMarkers.defaultProps = { insideMapPanes: false, prerender: false }; var style$2 = { width: '50%', height: '50%', left: '50%', top: '50%', margin: 0, padding: 0, position: 'absolute' }; function GoogleMapMarkersPrerender (props) { return /*#__PURE__*/React.createElement("div", { style: style$2 }, /*#__PURE__*/React.createElement(GoogleMapMarkers, _extends({}, props, { prerender: true }))); } var generateHeatmap = function generateHeatmap(instance, _ref) { var positions = _ref.positions; return new instance.visualization.HeatmapLayer({ data: positions.reduce(function (acc, _ref2) { var lat = _ref2.lat, lng = _ref2.lng, _ref2$weight = _ref2.weight, weight = _ref2$weight === void 0 ? 1 : _ref2$weight; acc.push({ location: new instance.LatLng(lat, lng), weight: weight }); return acc; }, []) }); }; var optionsHeatmap = function optionsHeatmap(instance, _ref3) { var _ref3$options = _ref3.options, options = _ref3$options === void 0 ? {} : _ref3$options; return Object.keys(options).map(function (option) { return instance.set(option, options[option]); }); }; var BASE_URL = 'https://maps'; var DEFAULT_URL = BASE_URL + ".googleapis.com"; var API_PATH = '/maps/api/js?callback=_$_google_map_initialize_$_'; var $script_ = null; var loadPromise_; var resolveCustomPromise_; var _customPromise = new Promise(function (resolve) { resolveCustomPromise_ = resolve; }); var googleMapLoader = (function (bootstrapURLKeys, heatmapLibrary) { if (!$script_) { $script_ = require('scriptjs'); } if (!bootstrapURLKeys) { return _customPromise; } if (loadPromise_) { return loadPromise_; } loadPromise_ = new Promise(function (resolve, reject) { if (typeof window === 'undefined') { reject(new Error('google map cannot be loaded outside browser env')); return; } if (window.google && window.google.maps) { resolve(window.google.maps); return; } if (typeof window._$_google_map_initialize_$_ !== 'undefined') { reject(new Error('google map initialization error')); } window._$_google_map_initialize_$_ = function () { delete window._$_google_map_initialize_$_; resolve(window.google.maps); }; if (process.env.NODE_ENV !== 'production') { if (Object.keys(bootstrapURLKeys).indexOf('callback') > -1) { var message = "\"callback\" key in bootstrapURLKeys is not allowed,\n use onGoogleApiLoaded property instead"; console.error(message); throw new Error(message); } } if (heatMapLibrary) { bootstrapURLKeys.libraries ? bootstrapURLKeys.libraries.append('visualization') : bootstrapURLKeys['libraries'] = ['visualization']; console.warn("heatMapLibrary will be deprecated in the future. Please use bootstrapURLKeys.libraries property instead (libraries=['visualization'])."); } var googleMapsLibs = ['places', 'drawing', 'geometry', 'visualization']; if (bootstrapURLKeys.libraries) { bootstrapURLKeys.libraries = bootstrapURLKeys.libraries.filter(function (lib, i) { return bootstrapURLKeys.libraries.indexOf(lib) === i && googleMapsLibs.includes(lib); }); } var params = Object.keys(bootstrapURLKeys).reduce(function (r, key) { return r + "&" + key + "=" + bootstrapURLKeys[key]; }, ''); $script_("" + DEFAULT_URL + API_PATH + params + libraries, function () { return typeof window.google === 'undefined' && reject(new Error('google map initialization error (not loaded)')); }); }); resolveCustomPromise_(loadPromise_); return loadPromise_; }); function wrap(n, min, max) { var d = max - min; return n === max ? n : ((n - min) % d + d) % d + min; } var LatLng = /*#__PURE__*/function () { function LatLng(lat, lng) { if (isNaN(lat) || isNaN(lng)) { throw new Error("Invalid LatLng object: (" + lat + ", " + lng + ")"); } this.lat = +lat; this.lng = +lng; } var _proto = LatLng.prototype; _proto.wrap = function wrap$1() { return new LatLng(this.lat, wrap(this.lng, -180, 180)); }; return LatLng; }(); LatLng.convert = function (a) { if (a instanceof LatLng) { return a; } if (Array.isArray(a)) { return new LatLng(a[0], a[1]); } if ('lng' in a && 'lat' in a) { return new LatLng(a.lat, a.lng); } return a; }; var Transform = /*#__PURE__*/function () { function Transform(tileSize, minZoom, maxZoom) { this.tileSize = tileSize || 512; this._minZoom = minZoom || 0; this._maxZoom = maxZoom || 52; this.latRange = [-85.05113, 85.05113]; this.width = 0; this.height = 0; this.zoom = 0; this.center = new LatLng(0, 0); this.angle = 0; } var _proto = Transform.prototype; _proto.zoomScale = function zoomScale(zoom) { return Math.pow(2, zoom); }; _proto.scaleZoom = function scaleZoom(scale) { return Math.log(scale) / Math.LN2; }; _proto.project = function project(latlng, worldSize) { return new Point(this.lngX(latlng.lng, worldSize), this.latY(latlng.lat, worldSize)); }; _proto.unproject = function unproject(point, worldSize) { return new LatLng(this.yLat(point.y, worldSize), this.xLng(point.x, worldSize)); }; _proto.lngX = function lngX(lon, worldSize) { return (180 + lon) * (worldSize || this.worldSize) / 360; }; _proto.latY = function latY(lat, worldSize) { var y = 180 / Math.PI * Math.log(Math.tan(Math.PI / 4 + lat * Math.PI / 360)); return (180 - y) * (worldSize || this.worldSize) / 360; }; _proto.xLng = function xLng(x, worldSize) { return x * 360 / (worldSize || this.worldSize) - 180; }; _proto.yLat = function yLat(y, worldSize) { var y2 = 180 - y * 360 / (worldSize || this.worldSize); return 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90; }; _proto.locationPoint = function locationPoint(latlng) { var p = this.project(latlng); return this.centerPoint._sub(this.point._sub(p)._rotate(this.angle)); }; _proto.pointLocation = function pointLocation(p) { var p2 = this.centerPoint._sub(p)._rotate(-this.angle); return this.unproject(this.point.sub(p2)); }; _createClass(Transform, [{ key: "minZoom", get: function get() { return this._minZoom; }, set: function set(zoom) { this._minZoom = zoom; this.zoom = Math.max(this.zoom, zoom); } }, { key: "maxZoom", get: function get() { return this._maxZoom; }, set: function set(zoom) { this._maxZoom = zoom; this.zoom = Math.min(this.zoom, zoom); } }, { key: "worldSize", get: function get() { return this.tileSize * this.scale; } }, { key: "centerPoint", get: function get() { return new Point(0, 0); } }, { key: "size", get: function get() { return new Point(this.width, this.height); } }, { key: "bearing", get: function get() { return -this.angle / Math.PI * 180; }, set: function set(bearing) { this.angle = -wrap(bearing, -180, 180) * Math.PI / 180; } }, { key: "zoom", get: function get() { return this._zoom; }, set: function set(zoom) { var zoomV = Math.min(Math.max(zoom, this.minZoom), this.maxZoom); this._zoom = zoomV; this.scale = this.zoomScale(zoomV); this.tileZoom = Math.floor(zoomV); this.zoomFraction = zoomV - this.tileZoom; } }, { key: "x", get: function get() { return this.lngX(this.center.lng); } }, { key: "y", get: function get() { return this.latY(this.center.lat); } }, { key: "point", get: function get() { return new Point(this.x, this.y); } }]); return Transform; }(); var Geo = /*#__PURE__*/function () { function Geo(tileSize) { this.hasSize_ = false; this.hasView_ = false; this.transform_ = new Transform(tileSize || 512); } var _proto = Geo.prototype; _proto.setView = function setView(center, zoom, bearing) { this.transform_.center = LatLng.convert(center); this.transform_.zoom = +zoom; this.transform_.bearing = +bearing; this.hasView_ = true; }; _proto.setViewSize = function setViewSize(width, height) { this.transform_.width = width; this.transform_.height = height; this.hasSize_ = true; }; _proto.setMapCanvasProjection = function setMapCanvasProjection(maps, mapCanvasProjection) { this.maps_ = maps; this.mapCanvasProjection_ = mapCanvasProjection; }; _proto.canProject = function canProject() { return this.hasSize_ && this.hasView_; }; _proto.hasSize = function hasSize() { return this.hasSize_; }; _proto.fromLatLngToCenterPixel = function fromLatLngToCenterPixel(ptLatLng) { return this.transform_.locationPoint(LatLng.convert(ptLatLng)); }; _proto.fromLatLngToDivPixel = function fromLatLngToDivPixel(ptLatLng) { if (this.mapCanvasProjection_) { var latLng = new this.maps_.LatLng(ptLatLng.lat, ptLatLng.lng); return this.mapCanvasProjection_.fromLatLngToDivPixel(latLng); } return this.fromLatLngToCenterPixel(ptLatLng); }; _proto.fromLatLngToContainerPixel = function fromLatLngToContainerPixel(ptLatLng) { if (this.mapCanvasProjection_) { var latLng = new this.maps_.LatLng(ptLatLng.lat, ptLatLng.lng); return this.mapCanvasProjection_.fromLatLngToContainerPixel(latLng); } var pt = this.fromLatLngToCenterPixel(ptLatLng); pt.x -= this.transform_.worldSize * Math.round(pt.x / this.transform_.worldSize); pt.x += this.transform_.width / 2; pt.y += this.transform_.height / 2; return pt; }; _proto.fromContainerPixelToLatLng = function fromContainerPixelToLatLng(ptXY) { if (this.mapCanvasProjection_) { var latLng = this.mapCanvasProjection_.fromContainerPixelToLatLng(ptXY); return { lat: latLng.lat(), lng: latLng.lng() }; } var ptxy = _extends({}, ptXY); ptxy.x -= this.transform_.width / 2; ptxy.y -= this.transform_.height / 2; var ptRes = this.transform_.pointLocation(Point.convert(ptxy)); ptRes.lng -= 360 * Math.round(ptRes.lng / 360); return ptRes; }; _proto.getWidth = function getWidth() { return this.transform_.width; }; _proto.getHeight = function getHeight() { return this.transform_.height; }; _proto.getZoom = function getZoom() { return this.transform_.zoom; }; _proto.getCenter = function getCenter() { var ptRes = this.transform_.pointLocation({ x: 0, y: 0 }); return ptRes; }; _proto.getBounds = function getBounds(margins, roundFactor) { var bndT = margins && margins[0] || 0; var bndR = margins && margins[1] || 0; var bndB = margins && margins[2] || 0; var bndL = margins && margins[3] || 0; if (this.getWidth() - bndR - bndL > 0 && this.getHeight() - bndT - bndB > 0) { var topLeftCorner = this.transform_.pointLocation(Point.convert({ x: bndL - this.getWidth() / 2, y: bndT - this.getHeight() / 2 })); var bottomRightCorner = this.transform_.pointLocation(Point.convert({ x: this.getWidth() / 2 - bndR, y: this.getHeight() / 2 - bndB })); var res = [topLeftCorner.lat, topLeftCorner.lng, bottomRightCorner.lat, bottomRightCorner.lng, bottomRightCorner.lat, topLeftCorner.lng, topLeftCorner.lat, bottomRightCorner.lng]; if (roundFactor) { res = res.map(function (r) { return Math.round(r * roundFactor) / roundFactor; }); } return res; } return [0, 0, 0, 0]; }; return Geo; }(); function raf(callback) { if (window.requestAnimationFrame) { return window.requestAnimationFrame(callback); } var nativeRaf = window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame; return nativeRaf ? nativeRaf(callback) : window.setTimeout(callback, 1e3 / 60); } var log2 = Math.log2 ? Math.log2 : function (x) { return Math.log(x) / Math.LN2; }; function pick(obj, fn) { return Object.keys(obj).reduce(function (result, key) { if (fn(obj[key])) { result[key] = obj[key]; } return result; }, {}); } var isEmpty = function isEmpty(val) { if (val !== null && typeof val === 'object') { if (Object.keys(val).length === 0) { return true; } } else if (val === null || val === undefined || val === '') { return true; } return false; }; function isObjectLike(value) { return !!value && typeof value === 'object'; } var objectToString = Object.prototype.toString; function isNumber(value) { var numberTag = '[object Number]'; return typeof value === 'number' || isObjectLike(value) && objectToString.call(value) === numberTag; } var detectBrowserResult_ = null; function detectBrowser() { if (detectBrowserResult_) { return detectBrowserResult_; } if (typeof navigator !== 'undefined') { var isExplorer = navigator.userAgent.indexOf('MSIE') > -1; var isFirefox = navigator.userAgent.indexOf('Firefox') > -1; var isOpera = navigator.userAgent.toLowerCase().indexOf('op') > -1; var isChrome = navigator.userAgent.indexOf('Chrome') > -1; var isSafari = navigator.userAgent.indexOf('Safari') > -1; if (isChrome && isSafari) { isSafari = false; } if (isChrome && isOpera) { isChrome = false; } detectBrowserResult_ = { isExplorer: isExplorer, isFirefox: isFirefox, isOpera: isOpera, isChrome: isChrome, isSafari: isSafari }; return detectBrowserResult_; } detectBrowserResult_ = { isChrome: true, isExplorer: false, isFirefox: false, isOpera: false, isSafari: false }; return detectBrowserResult_; } var fnToString = function fnToString(fn) { return Function.prototype.toString.call(fn); }; function isPlainObject(obj) { if (!obj || typeof obj !== 'object') { return false; } var proto = typeof obj.constructor === 'function' ? Object.getPrototypeOf(obj) : Object.prototype; if (proto === null) { return true; } var constructor = proto.constructor; return typeof constructor === 'function' && constructor instanceof constructor && fnToString(constructor) === fnToString(Object); } function isArraysEqualEps(arrayA, arrayB, eps) { if (arrayA && arrayB) { for (var i = 0; i !== arrayA.length; ++i) { if (Math.abs(arrayA[i] - arrayB[i]) > eps) { return false; } } return true; } return false; } function hasPassiveSupport() { var passiveSupported = false; try { var options = Object.defineProperty({}, 'passive', { get: function get() { passiveSupported = true; } }); window.addEventListener('test', options, options); window.removeEventListener('test', options, options); } catch (err) { passiveSupported = false; } return passiveSupported; } function addPassiveEventListener(element, eventName, func, capture) { element.addEventListener(eventName, func, hasPassiveSupport() ? { capture: capture, passive: true } : capture); } var canUseDOM = !!(typeof window !== 'undefined' && window.document && window.document.createElement); var _window; if (canUseDOM) { _window = window; } else if (typeof self !== 'undefined') { _window = self; } else { _window = undefined; } var attachEvent = typeof document !== 'undefined' && document.attachEvent; var stylesCreated = false; if (canUseDOM && !attachEvent) { var requestFrame = function () { var raf = _window.requestAnimationFrame || _window.mozRequestAnimationFrame || _window.webkitRequestAnimationFrame || function (fn) { return _window.setTimeout(fn, 20); }; return function (fn) { return raf(fn); }; }(); var cancelFrame = function () { var cancel = _window.cancelAnimationFrame || _window.mozCancelAnimationFrame || _window.webkitCancelAnimationFrame || _window.clearTimeout; return function (id) { return cancel(id); }; }(); var resetTriggers = function resetTriggers(element) { var triggers = element.__resizeTriggers__, expand = triggers.firstElementChild, contract = triggers.lastElementChild, expandChild = expand.firstElementChild; contract.scrollLeft = contract.scrollWidth; contract.scrollTop = contract.scrollHeight; expandChild.style.width = expand.offsetWidth + 1 + 'px'; expandChild.style.height = expand.offsetHeight + 1 + 'px'; expand.scrollLeft = expand.scrollWidth; expand.scrollTop = expand.scrollHeight; }; var checkTriggers = function checkTriggers(element) { return element.offsetWidth != element.__resizeLast__.width || element.offsetHeight != element.__resizeLast__.height; }; var scrollListener = function scrollListener(e) { var element = this; resetTriggers(this); if (this.__resizeRAF__) cancelFrame(this.__resizeRAF__); this.__resizeRAF__ = requestFrame(function () { if (checkTriggers(element)) { element.__resizeLast__.width = element.offsetWidth; element.__resizeLast__.height = element.offsetHeight; element.__resizeListeners__.forEach(function (fn) { fn.call(element, e); }); } }); }; var animation = false, keyframeprefix = '', animationstartevent = 'animationstart', domPrefixes = 'Webkit Moz O ms'.split(' '), startEvents = 'webkitAnimationStart animationstart oAnimationStart MSAnimationStart'.split(' '), pfx = ''; if (canUseDOM) { var elm = document.createElement('fakeelement'); if (elm.style.animationName !== undefined) { animation = true; } if (animation === false) { for (var i = 0; i < domPrefixes.length; i++) { if (elm.style[domPrefixes[i] + 'AnimationName'] !== undefined) { pfx = domPrefixes[i]; keyframeprefix = '-' + pfx.toLowerCase() + '-'; animationstartevent = startEvents[i]; animation = true; break; } } } } var animationName = 'resizeanim'; var animationKeyframes = '@' + keyframeprefix + 'keyframes ' + animationName + ' { from { opacity: 0; } to { opacity: 0; } } '; var animationStyle = keyframeprefix + 'animation: 1ms ' + animationName + '; '; } var createStyles = function createStyles() { if (!stylesCreated) { var css = (animationKeyframes ? animationKeyframes : '') + '.resize-triggers { ' + (animationStyle ? animationStyle : '') + 'visibility: hidden; opacity: 0; } ' + '.resize-triggers, .resize-triggers > div, .contract-trigger:before { content: " "; display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; } .resize-triggers > div { background: #eee; overflow: auto; } .contract-trigger:before { width: 200%; height: 200%; }', head = document.head || document.getElementsByTagName('head')[0], style = document.createElement('style'); style.type = 'text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); stylesCreated = true; } }; var addResizeListener = function addResizeListener(element, fn) { if (element.parentNode === undefined) { var tempParentDiv = document.createElement('div'); element.parentNode = tempParentDiv; } element = element.parentNode; if (attachEvent) element.attachEvent('onresize', fn);else { if (!element.__resizeTriggers__) { if (getComputedStyle(element).position == 'static') element.style.position = 'relative'; createStyles(); element.__resizeLast__ = {}; element.__resizeListeners__ = []; (element.__resizeTriggers__ = document.createElement('div')).className = 'resize-triggers'; element.__resizeTriggers__.innerHTML = '<div class="expand-trigger"><div></div></div>' + '<div class="contract-trigger"></div>'; element.appendChild(element.__resizeTriggers__); resetTriggers(element); addPassiveEventListener(element, 'scroll', scrollListener, true); animationstartevent && element.__resizeTriggers__.addEventListener(animationstartevent, function (e) { if (e.animationName == animationName) resetTriggers(element); }); } element.__resizeListeners__.push(fn); } }; var removeResizeListener = function removeResizeListener(element, fn) { element = element.parentNode; if (attachEvent) element.detachEvent('onresize', fn);else { element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1); if (!element.__resizeListeners__.length) { element.removeEventListener('scroll', scrollListener); element.__resizeTriggers__ = !element.removeChild(element.__resizeTriggers__); } } }; var kEPS = 0.00001; var K_GOOGLE_TILE_SIZE = 256; var K_IDLE_TIMEOUT = 100; var K_IDLE_CLICK_TIMEOUT = 300; var DEFAULT_MIN_ZOOM = 3; var DRAW_CALLED_DURING_ANIMATION_VERSION = 32; var IS_REACT_16 = ReactDOM.createPortal !== undefined; var createPortal = IS_REACT_16 ? ReactDOM.createPortal : ReactDOM.unstable_renderSubtreeIntoContainer; function defaultOptions_() { return { overviewMapControl: false, streetViewControl: false, rotateControl: true, mapTypeControl: false, styles: [{ featureType: 'poi', elementType: 'labels', stylers: [{ visibility: 'off' }] }], minZoom: DEFAULT_MIN_ZOOM }; } var latLng2Obj = function latLng2Obj(latLng) { return isPlainObject(latLng) ? latLng : { lat: latLng[0], lng: latLng[1] }; }; var _checkMinZoom = function _checkMinZoom(zoom, minZoom) { if (process.env.NODE_ENV !== 'production') { if (zoom < minZoom) { console.warn('GoogleMap: ' + 'minZoom option is less than recommended ' + 'minZoom option for your map sizes.\n' + 'overrided to value ' + minZoom); } } if (minZoom < zoom) { return zoom; } return minZoom; }; var isFullScreen = function isFullScreen() { return document.fullscreen || document.webkitIsFullScreen || document.mozFullScreen || document.msFullscreenElement; }; var GoogleMap = /*#__PURE__*/function (_Component) { _inheritsLoose(GoogleMap, _Component); function GoogleMap(props) { var _this; _this = _Component.call(this, props) || this; _this._getMinZoom = function () { if (_this.geoService_.getWidth() > 0 || _this.geoService_.getHeight() > 0) { var tilesPerWidth = Math.ceil(_this.geoService_.getWidth() / K_GOOGLE_TILE_SIZE) + 2; var tilesPerHeight = Math.ceil(_this.geoService_.getHeight() / K_GOOGLE_TILE_SIZE) + 2; var maxTilesPerDim = Math.max(tilesPerWidth, tilesPerHeight); return Math.ceil(log2(maxTilesPerDim)); } return DEFAULT_MIN_ZOOM; }; _this._computeMinZoom = function (minZoom) { if (!isEmpty(minZoom)) { return minZoom; } return _this._getMinZoom(); }; _this._mapDomResizeCallback = function () { _this.resetSizeOnIdle_ = true; if (_this.maps_) { var originalCenter = _this.props.center || _this.props.defaultCenter; var currentCenter = _this.map_.getCenter(); _this.maps_.event.trigger(_this.map_, 'resize'); _this.map_.setCenter(_this.props.resetBoundsOnResize ? originalCenter : currentCenter); } }; _this._setLayers = function (layerTypes) { layerTypes.forEach(function (layerType) { _this.layers_[layerType] = new _this.maps_[layerType](); _this.layers_[layerType].setMap(_this.map_); }); }; _this._renderPortal = function () { return /*#__PURE__*/React.createElement(GoogleMapMarkers, { experimental: _this.props.experimental, onChildClick: _this._onChildClick, onChildMouseDown: _this._onChildMouseDown, onChildMouseEnter: _this._onChildMouseEnter, onChildMouseLeave: _this._onChildMouseLeave, geoService: _this.geoService_, insideMapPanes: true, distanceToMouse: _this.props.distanceToMouse, getHoverDistance: _this._getHoverDistance, dispatcher: _this.markersDispatcher_ }); }; _this._initMap = function () { if (_this.initialized_) { return; } _this.initialized_ = true; var propsCenter = latLng2Obj(_this.props.center || _this.props.defaultCenter); _this.geoService_.setView(propsCenter, _this.props.zoom || _this.props.defaultZoom, 0); _this._onBoundsChanged(); var bootstrapURLKeys = _extends({}, _this.props.apiKey && { key: _this.props.apiKey }, _this.props.bootstrapURLKeys); _this.props.googleMapLoader(bootstrapURLKeys, _this.props.heatmapLibrary).then(function (maps) { if (!_this.mounted_) { return; } var centerLatLng = _this.geoService_.getCenter(); var propsOptions = { zoom: _this.props.zoom || _this.props.defaultZoom, center: new maps.LatLng(centerLatLng.lat, centerLatLng.lng) }; if (_this.props.heatmap.positions) { Object.assign(_assertThisInitialized(_this), { heatmap: generateHeatmap(maps, _this.props.heatmap) }); optionsHeatmap(_this.heatmap, _this.props.heatmap); } var mapPlainObjects = pick(maps, isPlainObject); var options = typeof _this.props.options === 'function' ? _this.props.options(mapPlainObjects) : _this.props.options; var defaultOptions = defaultOptions_(); var draggableOptions = !isEmpty(_this.props.draggable) && { draggable: _this.props.draggable }; var minZoom = _this._computeMinZoom(options.minZoom); _this.minZoom_ = minZoom; var preMapOptions = _extends({}, defaultOptions, { minZoom: minZoom }, options, propsOptions); _this.defaultDraggableOption_ = !isEmpty(preMapOptions.draggable) ? preMapOptions.draggable : _this.defaultDraggableOption_; var mapOptions = _extends({}, preMapOptions, draggableOptions); mapOptions.minZoom = _checkMinZoom(mapOptions.minZoom, minZoom); var map = new maps.Map(ReactDOM.findDOMNode(_this.googleMapDom_), mapOptions); _this.map_ = map; _this.maps_ = maps; _this._setLayers(_this.props.layerTypes); var versionMatch = maps.version.match(/^3\.(\d+)\./); var mapsVersion = versionMatch && Number(versionMatch[1]); var this_ = _assertThisInitialized(_this); var overlay = Object.assign(new maps.OverlayView(), { onAdd: function onAdd() { var K_MAX_WIDTH = typeof screen !== 'undefined' ? screen.width + "px" : '2000px'; var K_MAX_HEIGHT = typeof screen !== 'undefined' ? screen.height + "px" : '2000px'; var div = document.createElement('div'); div.style.backgroundColor = 'transparent'; div.style.position = 'absolute'; div.style.left = '0px'; div.style.top = '0px'; div.style.width = K_MAX_WIDTH; div.style.height = K_MAX_HEIGHT; if (this_.props.overlayViewDivStyle) { var overlayViewDivStyle = this_.props.overlayViewDivStyle; if (typeof overlayViewDivStyle === 'object') { Object.keys(overlayViewDivStyle).forEach(function (property) { div.style[property] = overlayViewDivStyle[property]; }); } } var panes = this.getPanes(); panes.overlayMouseTarget.appendChild(div); this_.geoService_.setMapCanvasProjection(maps, overlay.getProjection()); if (!IS_REACT_16) { createPortal(this_, this_._renderPortal(), div, function () { return this_.setState({ overlay: div }); }); } else { this_.setState({ overlay: div }); } }, onRemove: function onRemove() { var renderedOverlay = this_.state.overlay; if (renderedOverlay && !IS_REACT_16) { ReactDOM.unmountComponentAtNode(renderedOverlay); } this_.setState({ overlay: null }); }, draw: function draw() { this_.updateCounter_++; this_._onBoundsChanged(map, maps, !this_.props.debounced); if (!this_.googleApiLoadedCalled_) { this_._onGoogleApiLoaded({ map: map, maps: maps, ref: this_.googleMapDom_ }); this_.googleApiLoadedCalled_ = true; } if (this_.mouse_) { var latLng = this_.geoService_.fromContainerPixelToLatLng(this_.mouse_); this_.mouse_.lat = latLng.lat; this_.mouse_.lng = latLng.lng; } this_._onChildMouseMove(); if (this_.markersDispatcher_) { this_.markersDispatcher_.emit('kON_CHANGE'); if (this_.fireMouseEventOnIdle_) { this_.markersDispatcher_.emit('kON_MOUSE_POSITION_CHANGE'); } } } }); _this.overlay_ = overlay; overlay.setMap(map); if (_this.props.heatmap.positions) { _this.heatmap.setMap(map); } if (_this.props.onTilesLoaded) { maps.event.addListener(map, 'tilesloaded', function () { this_._onTilesLoaded(); }); } maps.event.addListener(map, 'zoom_changed', function () { if (this_.geoService_.getZoom() !== map.getZoom()) { if (!this_.zoomAnimationInProgress_) { this_.zoomAnimationInProgress_ = true; this_._onZoomAnimationStart(map.zoom); } if (mapsVersion < DRAW_CALLED_DURING_ANIMATION_VERSION) { var TIMEOUT_ZOOM = 300; if (new Date().getTime() - _this.zoomControlClickTime_ < TIMEOUT_ZOOM) { raf(function () { return raf(function () { this_.updateCounter_++; this_._onBoundsChanged(map, maps); }); }); } else { this_.updateCounter_++; this_._onBoundsChanged(map, maps); } } } }); maps.event.addListener(map, 'idle', function () { if (_this.resetSizeOnIdle_) { _this._setViewSize(); var currMinZoom = _this._computeMinZoom(options.minZoom); if (currMinZoom !== _this.minZoom_) { _this.minZoom_ = currMinZoom; map.setOptions({ minZoom: currMinZoom }); } _this.resetSizeOnIdle_ = false; } if (this_.zoomAnimationInProgress_) { this_.zoomAnimationInProgress_ = false; this_._onZoomAnimationEnd(map.zoom); } this_.updateCounter_++; this_._onBoundsChanged(map, maps); this_.dragTime_ = 0; if (this_.markersDispatcher_) { this_.markersDispatcher_.emit('kON_CHANGE'); } }); maps.event.addListener(map, 'mouseover', function () { this_.mouseInMap_ = true; }); maps.event.addListener(map, 'click', function () { this_.mouseInMap_ = true; }); maps.event.addListener(map, 'mouseout', function () { this_.mouseInMap_ = false; this_.mouse_ = null; this_.markersDispatcher_.emit('kON_MOUSE_POSITION_CHANGE'); }); maps.event.addListener(map, 'drag', function () { this_.dragTime_ = new Date().getTime(); this_._onDrag(map); }); maps.event.addListener(map, 'dragend', function () { var idleListener = maps.event.addListener(map, 'idle', function () { maps.event.removeListener(idleListener); this_._onDragEnd(map); }); }); maps.event.addListener(map, 'maptypeid_changed', function () { this_._onMapTypeIdChange(map.getMapTypeId()); }); })["catch"](function (e) { _this._onGoogleApiLoaded({ map: null, maps: null, ref: _this.googleMapDom_ }); console.error(e); throw e; }); }; _this._onGoogleApiLoaded = function () { if (_this.props.onGoogleApiLoaded) { var _this$props; if (process.env.NODE_ENV !== 'production' && _this.props.yesIWantToUseGoogleMapApiInternals !== true) { console.warn('GoogleMap: ' + 'Usage of internal api objects is dangerous ' + 'and can cause a lot of issues.\n' + 'To hide this warning add yesIWantToUseGoogleMapApiInternals={true} ' + 'to <GoogleMap instance'); } (_this$props = _this.props).onGoogleApiLoaded.apply(_this$props, arguments); } }; _this._getHoverDistance = function () { return _this.props.hoverDistance; }; _this._onDrag = function () { var _this$props2; return _this.props.onDrag && (_this$props2 = _this.props).onDrag.apply(_this$props2, arguments); }; _this._onDragEnd = function () { var _this$props3; return _this.props.onDragEnd && (_this$props3 = _this.props).onDragEnd.apply(_this$props3, arguments); }; _this._onMapTypeIdChange = function () { var _this$props4; return _this.props.onMapTypeIdChange && (_this$props4 = _this.props).onMapTypeIdChange.apply(_this$props4, arguments); }; _this._onZoomAnimationStart = function () { var _this$props5; return _this.props.onZoomAnimationStart && (_this$props5 = _this.props).onZoomAnimationStart.apply(_this$props5, arguments); }; _this._onZoomAnimationEnd = function () { var _this$props6; return _this.props.onZoomAnimationEnd && (_this$props6 = _this.props).onZoomAnimationEnd.apply(_this$props6, arguments); }; _this._onTilesLoaded = function () { return _this.props.onTilesLoaded && _this.props.onTilesLoaded(); }; _this._onChildClick = function () { if (_this.props.onChildClick) { var _this$props7; return (_this$props7 = _this.props).onChildClick.apply(_this$props7, arguments); } return undefined; }; _this._onChildMouseDown = function (hoverKey, childProps) { _this.childMouseDownArgs_ = [hoverKey, childProps]; if (_this.props.onChildMouseDown) { _this.props.onChildMouseDown(hoverKey, childProps, _extends({}, _this.mouse_)); } }; _this._onChildMouseUp = function () { if (_this.childMouseDownArgs_) { if (_this.props.onChildMouseUp) { var _this$props8; (_this$props8 = _this.props).onChildMouseUp.apply(_this$props8, _this.childMouseDownArgs_.concat([_extends({}, _this.mouse_)])); } _this.childMouseDownArgs_ = null; _this.childMouseUpTime_ = new Date().getTime(); } }; _this._onChildMouseMove = function () { if (_this.childMouseDownArgs_) { if (_this.props.onChildMouseMove) { var _this$props9; (_this$props9 = _this.props).onChildMouseMove.apply(_this$props9, _this.childMouseDownArgs_.concat([_extends({}, _this.mouse_)])); } } }; _this._onChildMouseEnter = function () { if (_this.props.onChildMouseEnter) { var _this$props10; return (_this$props10 = _this.props).onChildMouseEnter.apply(_this$props10, arguments); } return undefined; }; _this._onChildMouseLeave = function () { if (_this.props.onChildMouseLeave) { var _this$props11; return (_this$props11 = _this.props).onChildMouseLeave.apply(_this$props11, arguments); } return undefined; }; _this._setViewSize = function () { if (!_this.mounted_) return; if (isFullScreen()) { _this.geoService_.setViewSize(window.innerWidth, window.innerHeight); } else { var mapDom = ReactDOM.findDOMNode(_this.googleMapDom_); _this.geoService_.setViewSize(mapDom.clientWidth, mapDom.clientHeight); } _this._onBoundsChanged(); }; _this._onWindowResize = function () { _this.resetSizeOnIdle_ = true; }; _this._onMapMouseMove = function (e) { if (!_this.mouseInMap_) return; var currTime = new Date().getTime(); var K_RECALC_CLIENT_RECT_MS = 50; if (currTime - _this.mouseMoveTime_ > K_RECALC_CLIENT_RECT_MS) { _this.boundingRect_ = e.currentTarget.getBoundingClientRect(); } _this.mouseMoveTime_ = currTime; var mousePosX = e.clientX - _this.boundingRect_.left; var mousePosY = e.clientY - _this.boundingRect_.top; if (!_this.mouse_) { _this.mouse_ = { x: 0, y: 0, lat: 0, lng: 0 }; } _this.mouse_.x = mousePosX; _this.mouse_.y = m