Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix canvas sizing with cases that use the css property transform #11310

Merged
merged 23 commits into from
Dec 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 21 additions & 5 deletions debug/canvas-size.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,38 @@
<meta name='viewport' content='width=device-width, initial-scale=1.0, user-scalable=no'>
<link rel='stylesheet' href='../dist/mapbox-gl.css' />
<style>
body { margin: 0; padding: 0; }
html, body, #map { height: 100%; background-color: gray;}
html, body {
margin: 0;
padding: 0;
background-color: gray;
}
#map-container {
width: 500.52px;
height: 500.52px;
transform: scale(0.7);
transform-origin: top left;
background-color: black;
}
#map {
height: 100%;
width: 100%;
}
</style>
</head>

<body>
<div id='map' style='width: 250.52px; height: 250.52px;'>
<div id="map-container">
<div id="map"></div>
</div>

<script src='../dist/mapbox-gl-dev.js'></script>
<script src='../debug/access_token_generated.js'></script>
<script>

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
});
Expand Down
2 changes: 1 addition & 1 deletion src/ui/control/geolocate_control.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/ui/control/scale_control.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
43 changes: 29 additions & 14 deletions src/ui/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,8 @@ class Map extends Camera {
_averageElevationLastSampledAt: number;
_averageElevation: EasedVariable;
_runtimeProjection: ProjectionSpecification | void | null;
_containerWidth: number;
_containerHeight: number
avpeery marked this conversation as resolved.
Show resolved Hide resolved

/** @section {Interaction handlers} */

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 = {};
Expand Down
2 changes: 1 addition & 1 deletion test/unit/terrain/terrain.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
avpeery marked this conversation as resolved.
Show resolved Hide resolved
const isCenterRendered = pixels[centerOffset] === 255;
if (!beganRenderingContent) {
beganRenderingContent = isCenterRendered;
Expand Down
20 changes: 4 additions & 16 deletions test/unit/ui/hash.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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});
}

Expand Down Expand Up @@ -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});

Expand Down
34 changes: 18 additions & 16 deletions test/unit/ui/map.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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})});
SnailBones marked this conversation as resolved.
Show resolved Hide resolved

map.resize();

Expand Down Expand Up @@ -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');

Expand Down Expand Up @@ -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();

Expand Down
12 changes: 3 additions & 9 deletions test/unit/ui/marker.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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});
}

Expand Down Expand Up @@ -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

Expand Down
10 changes: 2 additions & 8 deletions test/unit/ui/popup.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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});
}

Expand Down
11 changes: 2 additions & 9 deletions test/util/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down