diff --git a/debug/canvas-size.html b/debug/canvas-size.html index d7517c076fd..c277ce20ff4 100644 --- a/debug/canvas-size.html +++ b/debug/canvas-size.html @@ -6,13 +6,29 @@ -
+
+
+
@@ -20,8 +36,8 @@ var map = window.map = new mapboxgl.Map({ container: 'map', - zoom: 12.5, - center: [-77.01866, 38.888], + zoom: 8, + center: [-77.048, 38.845], style: 'mapbox://styles/mapbox/streets-v10', hash: true }); diff --git a/src/ui/control/geolocate_control.js b/src/ui/control/geolocate_control.js index 6d5164f67e8..7375902d7a5 100644 --- a/src/ui/control/geolocate_control.js +++ b/src/ui/control/geolocate_control.js @@ -332,7 +332,7 @@ class GeolocateControl extends Evented { _updateCircleRadius() { assert(this._circleElement); - const y = this._map._container.getBoundingClientRect().height / 2; + const y = this._map._containerHeight / 2; const a = this._map.unproject([0, y]); const b = this._map.unproject([100, y]); const metersPerPixel = a.distanceTo(b) / 100; diff --git a/src/ui/control/scale_control.js b/src/ui/control/scale_control.js index a9991f4cdf8..a85a54ff1cc 100644 --- a/src/ui/control/scale_control.js +++ b/src/ui/control/scale_control.js @@ -92,7 +92,7 @@ function updateScale(map, container, options) { // found between the two coordinates. const maxWidth = options && options.maxWidth || 100; - const y = map._container.getBoundingClientRect().height / 2; + const y = map._containerHeight / 2; const left = map.unproject([0, y]); const right = map.unproject([maxWidth, y]); const maxMeters = left.distanceTo(right); diff --git a/src/ui/map.js b/src/ui/map.js index 7617eaae589..e8869104c5b 100755 --- a/src/ui/map.js +++ b/src/ui/map.js @@ -362,6 +362,8 @@ class Map extends Camera { _averageElevationLastSampledAt: number; _averageElevation: EasedVariable; _runtimeProjection: ProjectionSpecification | void | null; + _containerWidth: number; + _containerHeight: number /** @section {Interaction handlers} */ @@ -460,6 +462,8 @@ class Map extends Camera { this._locale = extend({}, defaultLocale, options.locale); this._clickTolerance = options.clickTolerance; this._cooperativeGestures = options.cooperativeGestures; + this._containerWidth = 0; + this._containerHeight = 0; this._averageElevationLastSampledAt = -Infinity; this._averageElevation = new EasedVariable(0); @@ -715,15 +719,15 @@ class Map extends Camera { * if (mapDiv.style.visibility === true) map.resize(); */ resize(eventData?: Object) { - const [width, height] = this._containerDimensions(); + this._updateContainerDimensions(); // do nothing if container remained the same size - if (width === this.transform.width && height === this.transform.height) return this; + if (this._containerWidth === this.transform.width && this._containerHeight === this.transform.height) return this; - this._resizeCanvas(width, height); + this._resizeCanvas(this._containerWidth, this._containerHeight); - this.transform.resize(width, height); - this.painter.resize(Math.ceil(width), Math.ceil(height)); + this.transform.resize(this._containerWidth, this._containerHeight); + this.painter.resize(Math.ceil(this._containerWidth), Math.ceil(this._containerHeight)); const fireMoving = !this._moving; if (fireMoving) { @@ -2618,16 +2622,27 @@ class Map extends Camera { return this.style.getFeatureState(feature); } - _containerDimensions() { - let width = 0; - let height = 0; + _updateContainerDimensions() { + if (!this._container) return; - if (this._container) { - width = this._container.getBoundingClientRect().width || 400; - height = this._container.getBoundingClientRect().height || 300; + const width = this._container.getBoundingClientRect().width || 400; + const height = this._container.getBoundingClientRect().height || 300; + + let transformValues; + let el = this._container; + while (el && !transformValues) { + const transformMatrix = window.getComputedStyle(el).transform; + if (transformMatrix && transformMatrix !== 'none') transformValues = transformMatrix.match(/matrix.*\((.+)\)/)[1].split(', '); + el = el.parentElement; } - return [width, height]; + if (transformValues) { + this._containerWidth = transformValues[0] && transformValues[0] !== '0' ? Math.abs(width / transformValues[0]) : width; + this._containerHeight = transformValues[3] && transformValues[3] !== '0' ? Math.abs(height / transformValues[3]) : height; + } else { + this._containerWidth = width; + this._containerHeight = height; + } } _detectMissingCSS(): void { @@ -2660,8 +2675,8 @@ class Map extends Camera { this._canvas.setAttribute('aria-label', 'Map'); this._canvas.setAttribute('role', 'region'); - const dimensions = this._containerDimensions(); - this._resizeCanvas(dimensions[0], dimensions[1]); + this._updateContainerDimensions(); + this._resizeCanvas(this._containerWidth, this._containerHeight); const controlContainer = this._controlContainer = DOM.create('div', 'mapboxgl-control-container', container); const positions = this._controlPositions = {}; diff --git a/test/unit/terrain/terrain.test.js b/test/unit/terrain/terrain.test.js index 40dacb0b274..8bb53a7f5d2 100644 --- a/test/unit/terrain/terrain.test.js +++ b/test/unit/terrain/terrain.test.js @@ -415,7 +415,7 @@ test('Elevation', (t) => { const gl = map.painter.context.gl; const pixels = new Uint8Array(gl.drawingBufferWidth * gl.drawingBufferHeight * 4); gl.readPixels(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight, gl.RGBA, gl.UNSIGNED_BYTE, pixels); - const centerOffset = map.getContainer().getBoundingClientRect().width / 2 * (map.getContainer().getBoundingClientRect().height + 1) * 4; + const centerOffset = map._containerWidth / 2 * (map._containerHeight + 1) * 4; const isCenterRendered = pixels[centerOffset] === 255; if (!beganRenderingContent) { beganRenderingContent = isCenterRendered; diff --git a/test/unit/ui/hash.test.js b/test/unit/ui/hash.test.js index bd790063b54..008dc2d60eb 100644 --- a/test/unit/ui/hash.test.js +++ b/test/unit/ui/hash.test.js @@ -12,14 +12,8 @@ test('hash', (t) => { function createMap(t) { const container = window.document.createElement('div'); - Object.defineProperty(container, 'getBoundingClientRect', {value: - () => { - return { - height: 512, - width: 512 - }; - } - }); + Object.defineProperty(container, 'getBoundingClientRect', + {value: () => ({height: 512, width: 512})}); return globalCreateMap(t, {container}); } @@ -313,14 +307,8 @@ test('hash', (t) => { t.test('map#remove', (t) => { const container = window.document.createElement('div'); - Object.defineProperty(container, 'getBoundingClientRect', {value: - () => { - return { - height: 512, - width: 512 - }; - } - }); + Object.defineProperty(container, 'getBoundingClientRect', + {value: () => ({height: 512, width: 512})}); const map = createMap(t, {hash: true}); diff --git a/test/unit/ui/map.test.js b/test/unit/ui/map.test.js index 14740dac1d8..6947df33b8f 100755 --- a/test/unit/ui/map.test.js +++ b/test/unit/ui/map.test.js @@ -749,14 +749,8 @@ test('Map', (t) => { const map = createMap(t), container = map.getContainer(); - Object.defineProperty(container, 'getBoundingClientRect', {value: - () => { - return { - height: 250, - width: 250 - }; - } - }); + Object.defineProperty(container, 'getBoundingClientRect', + {value: () => ({height: 250, width: 250})}); map.resize(); @@ -2703,6 +2697,20 @@ test('Map', (t) => { t.end(); }); + t.test('should calculate correct canvas size when transform css property is applied', (t) => { + const map = createMap(t); + Object.defineProperty(window, 'getComputedStyle', + {value: () => ({transform: 'matrix(0.5, 0, 0, 0.5, 0, 0)'})}); + + map.resize(); + + t.equal(map._containerWidth, 400); + t.equal(map._containerHeight, 400); + + map.remove(); + t.end(); + }); + t.test('should not warn when CSS is present', (t) => { const stub = t.stub(console, 'warn'); @@ -2732,14 +2740,8 @@ test('Map', (t) => { map.flyTo({center: [200, 0], duration: 100}); - Object.defineProperty(container, 'getBoundingClientRect', {value: - () => { - return { - height: 250, - width: 250 - }; - } - }); + Object.defineProperty(container, 'getBoundingClientRect', + {value: () => ({height: 250, width: 250})}); map.resize(); diff --git a/test/unit/ui/marker.test.js b/test/unit/ui/marker.test.js index 688e2a73260..778504fdb57 100644 --- a/test/unit/ui/marker.test.js +++ b/test/unit/ui/marker.test.js @@ -9,14 +9,8 @@ import simulate from '../../util/simulate_interaction.js'; function createMap(t, options = {}) { const container = window.document.createElement('div'); - Object.defineProperty(container, 'getBoundingClientRect', {value: - () => { - return { - height: 512, - width: 512 - }; - } - }); + Object.defineProperty(container, 'getBoundingClientRect', + {value: () => ({height: 512, width: 512})}); return globalCreateMap(t, {container, ...options}); } @@ -298,7 +292,7 @@ test('Popup anchors around default Marker', (t) => { // open the popup marker.togglePopup(); - const mapHeight = map.getContainer().getBoundingClientRect().height; + const mapHeight = map._containerHeight; const markerTop = -marker.getPopup().options.offset.bottom[1]; // vertical distance from tip of marker to the top in pixels const markerRight = -marker.getPopup().options.offset.right[0]; // horizontal distance from the tip of the marker to the right in pixels diff --git a/test/unit/ui/popup.test.js b/test/unit/ui/popup.test.js index 09572d23913..f0c9b7ceec5 100644 --- a/test/unit/ui/popup.test.js +++ b/test/unit/ui/popup.test.js @@ -12,14 +12,8 @@ const containerHeight = 512; function createMap(t, options) { options = options || {}; const container = window.document.createElement('div'); - Object.defineProperty(container, 'getBoundingClientRect', {value: - () => { - return { - height: options.height || containerHeight, - width: options.width || containerWidth - }; - } - }); + Object.defineProperty(container, 'getBoundingClientRect', + {value: () => ({height: options.height || containerHeight, width: options.width || containerWidth})}); return globalCreateMap(t, {container}); } diff --git a/test/util/index.js b/test/util/index.js index 4fcf2996f81..d052b8008df 100644 --- a/test/util/index.js +++ b/test/util/index.js @@ -17,15 +17,8 @@ export function createMap(t, options, callback) { } }; - Object.defineProperty(container, 'getBoundingClientRect', {value: - () => { - return { - height: 200, - width: 200 - }; - }, - configurable: true - }); + Object.defineProperty(container, 'getBoundingClientRect', + {value: () => ({height: 200, width: 200}), configurable: true}); if (!options || !options.skipCSSStub) t.stub(Map.prototype, '_detectMissingCSS'); if (options && options.deleteStyle) delete defaultOptions.style;