From c57246f8f2ee165dcb6f49624c1e40107a366e3a Mon Sep 17 00:00:00 2001 From: cybice Date: Sun, 4 Oct 2015 02:56:02 +0300 Subject: [PATCH] Add minZoom calculation. --- CHANGELOG.md | 3 +++ src/google_map.js | 49 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e439fb..626fb05 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +###Sun Oct 5 2015 +Add minZoom calculation, to prevent situations when one map point can have multiple screen coordinates. + ###Sun Oct 4 2015 Add ability to access to internal google api diff --git a/src/google_map.js b/src/google_map.js index b7fb1c9..8c50901 100644 --- a/src/google_map.js +++ b/src/google_map.js @@ -28,6 +28,8 @@ const ReactDOM = isReact14(React) const kEPS = 0.00001; const K_GOOGLE_TILE_SIZE = 256; +// real minZoom calculated here _getMinZoom +const DEFAULT_MIN_ZOOM = 3; function defaultOptions_(/* maps */) { return { @@ -37,7 +39,7 @@ function defaultOptions_(/* maps */) { mapTypeControl: false, // disable poi styles: [{ featureType: 'poi', elementType: 'labels', stylers: [{ visibility: 'off' }]}], - minZoom: 3, // i need to dynamically calculate possible zoom value + minZoom: DEFAULT_MIN_ZOOM, // dynamically recalculted if possible during init }; } @@ -124,6 +126,8 @@ export default class GoogleMap extends Component { this.geoService_ = new Geo(K_GOOGLE_TILE_SIZE); this.centerIsObject_ = isPlainObject(this.props.center); + this.minZoom_ = DEFAULT_MIN_ZOOM; + if (process.env.NODE_ENV !== 'production') { if (this.props.center === undefined && this.props.defaultCenter === undefined) { console.warn( 'center or defaultCenter' + // eslint-disable-line no-console @@ -229,6 +233,20 @@ export default class GoogleMap extends Component { delete this.markersDispatcher_; } + // calc minZoom if map size available + // it's better to not set minZoom less than this calculation gives + // otherwise there is no homeomorphism between screen coordinates and map + // (one map coordinate can have different screen coordinates) + _getMinZoom = () => { + if (this.geoService_.getWidth() > 0 || this.geoService_.getHeight() > 0) { + const tilesPerWidth = Math.ceil(this.geoService_.getWidth() / K_GOOGLE_TILE_SIZE) + 2; + const tilesPerHeight = Math.ceil(this.geoService_.getHeight() / K_GOOGLE_TILE_SIZE) + 2; + const maxTilesPerDim = Math.max(tilesPerWidth, tilesPerHeight); + return Math.ceil(Math.log2(maxTilesPerDim)); + } + return DEFAULT_MIN_ZOOM; + } + _initMap = () => { const propsCenter = latLng2Obj(this.props.center || this.props.defaultCenter); this.geoService_.setView(propsCenter, this.props.zoom || this.props.defaultZoom, 0); @@ -265,7 +283,27 @@ export default class GoogleMap extends Component { : this.props.options; const defaultOptions = defaultOptions_(mapPlainObjects); - const mapOptions = {...defaultOptions, ...options, ...propsOptions}; + const minZoom = this._getMinZoom(); + this.minZoom_ = minZoom; + + const mapOptions = { + ...defaultOptions, + minZoom, + ...options, + ...propsOptions, + }; + + if (process.env.NODE_ENV !== 'production') { + if (mapOptions.minZoom < minZoom) { + console.warn( 'minZoom option is less than recommended ' + // eslint-disable-line + 'minZoom option for your map sizes.\n' + + 'overrided to value ' + minZoom); + } + } + + if (mapOptions.minZoom < minZoom) { + mapOptions.minZoom = minZoom; + } const map = new maps.Map(ReactDOM.findDOMNode(this.refs.google_map_dom), mapOptions); this.map_ = map; @@ -354,6 +392,13 @@ export default class GoogleMap extends Component { maps.event.addListener(map, 'idle', () => { if (this.resetSizeOnIdle_) { this._setViewSize(); + const currMinZoom = this._getMinZoom(); + + if (currMinZoom !== this.minZoom_) { + this.minZoom_ = currMinZoom; + map.setOptions({minZoom: currMinZoom}); + } + this.resetSizeOnIdle_ = false; }