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;