From a847f83b3c4c626cc6ae14a9129b03bf1e16b023 Mon Sep 17 00:00:00 2001 From: Arindam Bose Date: Thu, 13 Feb 2020 12:19:01 -0800 Subject: [PATCH] Map API functions such as easeTo and flyTo now support padding: PaddingOptions which lets developers shift the center of perspective for a map when building floating sidebars. Asymmetric viewport (#8638) Co-authored-by: Vladimir Agafonkin --- src/geo/edge_insets.js | 102 ++++++++++++++ src/geo/transform.js | 76 +++++++++-- src/render/draw_debug.js | 50 +++++++ src/render/painter.js | 7 +- src/ui/camera.js | 99 ++++++++++---- src/ui/map.js | 20 ++- .../padding/ease-to-btm-distort/expected.png | Bin 0 -> 12345 bytes .../padding/ease-to-btm-distort/style.json | 112 +++++++++++++++ .../padding/ease-to-left-distort/expected.png | Bin 0 -> 11859 bytes .../padding/ease-to-left-distort/style.json | 112 +++++++++++++++ .../padding/ease-to-no-distort/expected.png | Bin 0 -> 11978 bytes .../padding/ease-to-no-distort/style.json | 127 ++++++++++++++++++ .../ease-to-right-distort/expected.png | Bin 0 -> 11593 bytes .../padding/ease-to-right-distort/style.json | 112 +++++++++++++++ .../padding/ease-to-top-distort/expected.png | Bin 0 -> 10598 bytes .../padding/ease-to-top-distort/style.json | 112 +++++++++++++++ .../debug/padding/set-padding/expected.png | Bin 0 -> 11900 bytes .../debug/padding/set-padding/style.json | 82 +++++++++++ test/suite_implementation.js | 1 + test/unit/geo/edge_insets.test.js | 99 ++++++++++++++ test/unit/ui/camera.test.js | 39 ++++++ 21 files changed, 1114 insertions(+), 36 deletions(-) create mode 100644 src/geo/edge_insets.js create mode 100644 test/integration/render-tests/debug/padding/ease-to-btm-distort/expected.png create mode 100644 test/integration/render-tests/debug/padding/ease-to-btm-distort/style.json create mode 100644 test/integration/render-tests/debug/padding/ease-to-left-distort/expected.png create mode 100644 test/integration/render-tests/debug/padding/ease-to-left-distort/style.json create mode 100644 test/integration/render-tests/debug/padding/ease-to-no-distort/expected.png create mode 100644 test/integration/render-tests/debug/padding/ease-to-no-distort/style.json create mode 100644 test/integration/render-tests/debug/padding/ease-to-right-distort/expected.png create mode 100644 test/integration/render-tests/debug/padding/ease-to-right-distort/style.json create mode 100644 test/integration/render-tests/debug/padding/ease-to-top-distort/expected.png create mode 100644 test/integration/render-tests/debug/padding/ease-to-top-distort/style.json create mode 100644 test/integration/render-tests/debug/padding/set-padding/expected.png create mode 100644 test/integration/render-tests/debug/padding/set-padding/style.json create mode 100644 test/unit/geo/edge_insets.test.js diff --git a/src/geo/edge_insets.js b/src/geo/edge_insets.js new file mode 100644 index 00000000000..5835d7c161d --- /dev/null +++ b/src/geo/edge_insets.js @@ -0,0 +1,102 @@ +// @flow +import {number} from "../style-spec/util/interpolate"; +import Point from "@mapbox/point-geometry"; +import {clamp} from "../util/util"; + +/** + * An `EdgeInset` object represents screen space padding applied to the edges of the viewport. + * This shifts the apprent center or the vanishing point of the map. This is useful for adding floating UI elements + * on top of the map and having the vanishing point shift as UI elements resize. + * + * @param {number} [top=0] + * @param {number} [bottom=0] + * @param {number} [left=0] + * @param {number} [right=0] + */ +class EdgeInsets { + top: number; + bottom: number; + left: number; + right: number; + + constructor(top: number = 0, bottom: number = 0, left: number = 0, right: number = 0) { + if (isNaN(top) || top < 0 || + isNaN(bottom) || bottom < 0 || + isNaN(left) || left < 0 || + isNaN(right) || right < 0 + ) { + throw new Error('Invalid value for edge-insets, top, bottom, left and right must all be numbers'); + } + + this.top = top; + this.bottom = bottom; + this.left = left; + this.right = right; + } + + /** + * Interpolates the inset in-place. + * This maintains the current inset value for any inset not present in `target`. + * + * @param {PaddingOptions} target + * @param {number} t + * @returns {EdgeInsets} + * @memberof EdgeInsets + */ + interpolate(start: PaddingOptions | EdgeInsets, target: PaddingOptions, t: number): EdgeInsets { + if (target.top != null && start.top != null) this.top = number(start.top, target.top, t); + if (target.bottom != null && start.bottom != null) this.bottom = number(start.bottom, target.bottom, t); + if (target.left != null && start.left != null) this.left = number(start.left, target.left, t); + if (target.right != null && start.right != null) this.right = number(start.right, target.right, t); + + return this; + } + + /** + * Utility method that computes the new apprent center or vanishing point after applying insets. + * This is in pixels and with the top left being (0.0) and +y being downwards. + * + * @param {number} width + * @param {number} height + * @returns {Point} + * @memberof EdgeInsets + */ + getCenter(width: number, height: number): Point { + // Clamp insets so they never overflow width/height and always calculate a valid center + const x = clamp((this.left + width - this.right) / 2, 0, width); + const y = clamp((this.top + height - this.bottom) / 2, 0, height); + + return new Point(x, y); + } + + equals(other: PaddingOptions): boolean { + return this.top === other.top && + this.bottom === other.bottom && + this.left === other.left && + this.right === other.right; + } + + clone(): EdgeInsets { + return new EdgeInsets(this.top, this.bottom, this.left, this.right); + } + + /** + * Returns the current sdtate as json, useful when you want to have a + * read-only representation of the inset. + * + * @returns {PaddingOptions} + * @memberof EdgeInsets + */ + toJSON(): PaddingOptions { + return { + top: this.top, + bottom: this.bottom, + left: this.left, + right: this.right + }; + } +} + +export type PaddingOptions = {top: ?number, bottom: ?number, right: ?number, left: ?number}; + +export default EdgeInsets; diff --git a/src/geo/transform.js b/src/geo/transform.js index af33f5922d9..7e5b232dc94 100644 --- a/src/geo/transform.js +++ b/src/geo/transform.js @@ -9,8 +9,10 @@ import {number as interpolate} from '../style-spec/util/interpolate'; import EXTENT from '../data/extent'; import {vec4, mat4, mat2, vec2} from 'gl-matrix'; import {Aabb, Frustum} from '../util/primitives.js'; +import EdgeInsets from './edge_insets'; import {UnwrappedTileID, OverscaledTileID, CanonicalTileID} from '../source/tile_id'; +import type {PaddingOptions} from './edge_insets'; /** * A single transform, generally used for a single tile to be @@ -49,6 +51,7 @@ class Transform { _minPitch: number; _maxPitch: number; _center: LngLat; + _edgeInsets: EdgeInsets; _constraining: boolean; _posMatrixCache: {[string]: Float32Array}; _alignedPosMatrixCache: {[string]: Float32Array}; @@ -74,6 +77,7 @@ class Transform { this._fov = 0.6435011087932844; this._pitch = 0; this._unmodified = true; + this._edgeInsets = new EdgeInsets(); this._posMatrixCache = {}; this._alignedPosMatrixCache = {}; } @@ -90,6 +94,7 @@ class Transform { clone._fov = this._fov; clone._pitch = this._pitch; clone._unmodified = this._unmodified; + clone._edgeInsets = this._edgeInsets.clone(); clone._calcMatrices(); return clone; } @@ -137,8 +142,8 @@ class Transform { return this.tileSize * this.scale; } - get centerPoint(): Point { - return this.size._div(2); + get centerOffset(): Point { + return this.centerPoint._sub(this.size._div(2)); } get size(): Point { @@ -204,6 +209,52 @@ class Transform { this._calcMatrices(); } + get padding(): PaddingOptions { return this._edgeInsets.toJSON(); } + set padding(padding: PaddingOptions) { + if (this._edgeInsets.equals(padding)) return; + this._unmodified = false; + //Update edge-insets inplace + this._edgeInsets.interpolate(this._edgeInsets, padding, 1); + this._calcMatrices(); + } + + /** + * The center of the screen in pixels with the top-left corner being (0,0) + * and +y axis pointing downwards. This accounts for padding. + * + * @readonly + * @type {Point} + * @memberof Transform + */ + get centerPoint(): Point { + return this._edgeInsets.getCenter(this.width, this.height); + } + + /** + * Returns if the padding params match + * + * @param {PaddingOptions} padding + * @returns {boolean} + * @memberof Transform + */ + isPaddingEqual(padding: PaddingOptions): boolean { + return this._edgeInsets.equals(padding); + } + + /** + * Helper method to upadte edge-insets inplace + * + * @param {PaddingOptions} target + * @param {number} t + * @memberof Transform + */ + interpolatePadding(start: PaddingOptions, target: PaddingOptions, t: number) { + this._unmodified = false; + this._edgeInsets.interpolate(start, target, t); + this._constrain(); + this._calcMatrices(); + } + /** * Return a zoom level that will cover all tiles the transform * @param {Object} options @@ -281,9 +332,10 @@ class Transform { const centerPoint = [numTiles * centerCoord.x, numTiles * centerCoord.y, 0]; const cameraFrustum = Frustum.fromInvProjectionMatrix(this.invProjMatrix, this.worldSize, z); - // No change of LOD behavior for pitch lower than 60: return only tile ids from the requested zoom level + // No change of LOD behavior for pitch lower than 60 and when there is no top padding: return only tile ids from the requested zoom level let minZoom = options.minzoom || 0; - if (this.pitch <= 60.0) + // Use 0.1 as an epsilon to avoid for explicit == 0.0 floating point checks + if (this.pitch <= 60.0 && this._edgeInsets.top < 0.1) minZoom = z; // There should always be a certain number of maximum zoom level tiles surrounding the center location @@ -616,15 +668,17 @@ class Transform { _calcMatrices() { if (!this.height) return; - this.cameraToCenterDistance = 0.5 / Math.tan(this._fov / 2) * this.height; + const halfFov = this._fov / 2; + const offset = this.centerOffset; + this.cameraToCenterDistance = 0.5 / Math.tan(halfFov) * this.height; - // Find the distance from the center point [width/2, height/2] to the - // center top point [width/2, 0] in Z units, using the law of sines. + // Find the distance from the center point [width/2 + offset.x, height/2 + offset.y] to the + // center top point [width/2 + offset.x, 0] in Z units, using the law of sines. // 1 Z unit is equivalent to 1 horizontal px at the center of the map // (the distance between[width/2, height/2] and [width/2 + 1, height/2]) - const halfFov = this._fov / 2; const groundAngle = Math.PI / 2 + this._pitch; - const topHalfSurfaceDistance = Math.sin(halfFov) * this.cameraToCenterDistance / Math.sin(clamp(Math.PI - groundAngle - halfFov, 0.01, Math.PI - 0.01)); + const fovAboveCenter = this._fov * (0.5 + offset.y / this.height); + const topHalfSurfaceDistance = Math.sin(fovAboveCenter) * this.cameraToCenterDistance / Math.sin(clamp(Math.PI - groundAngle - fovAboveCenter, 0.01, Math.PI - 0.01)); const point = this.point; const x = point.x, y = point.y; @@ -646,6 +700,10 @@ class Transform { let m = new Float64Array(16); mat4.perspective(m, this._fov, this.width / this.height, nearZ, farZ); + //Apply center of perspective offset + m[8] = -offset.x * 2 / this.width; + m[9] = offset.y * 2 / this.height; + mat4.scale(m, m, [1, -1, 1]); mat4.translate(m, m, [0, 0, -this.cameraToCenterDistance]); mat4.rotateX(m, m, this._pitch); diff --git a/src/render/draw_debug.js b/src/render/draw_debug.js index 56cb6cfc473..8071b8444e9 100644 --- a/src/render/draw_debug.js +++ b/src/render/draw_debug.js @@ -11,6 +11,7 @@ import StencilMode from '../gl/stencil_mode'; import CullFaceMode from '../gl/cull_face_mode'; import {debugUniformValues} from './program/debug_program'; import Color from '../style-spec/util/color'; +import browser from '../util/browser'; import type Painter from './painter'; import type SourceCache from '../source/source_cache'; @@ -18,6 +19,55 @@ import type {OverscaledTileID} from '../source/tile_id'; export default drawDebug; +const topColor = new Color(1, 0, 0, 1); +const btmColor = new Color(0, 1, 0, 1); +const leftColor = new Color(0, 0, 1, 1); +const rightColor = new Color(1, 0, 1, 1); +const centerColor = new Color(0, 1, 1, 1); + +export function drawDebugPadding(painter: Painter) { + const padding = painter.transform.padding; + const lineWidth = 3; + // Top + drawHorizontalLine(painter, painter.transform.height - (padding.top || 0), lineWidth, topColor); + // Bottom + drawHorizontalLine(painter, padding.bottom || 0, lineWidth, btmColor); + // Left + drawVerticalLine(painter, padding.left || 0, lineWidth, leftColor); + // Right + drawVerticalLine(painter, painter.transform.width - (padding.right || 0), lineWidth, rightColor); + // Center + const center = painter.transform.centerPoint; + drawCrosshair(painter, center.x, painter.transform.height - center.y, centerColor); +} + +function drawCrosshair(painter: Painter, x: number, y: number, color: Color) { + const size = 20; + const lineWidth = 2; + //Vertical line + drawDebugSSRect(painter, x - lineWidth / 2, y - size / 2, lineWidth, size, color); + //Horizontal line + drawDebugSSRect(painter, x - size / 2, y - lineWidth / 2, size, lineWidth, color); +} + +function drawHorizontalLine(painter: Painter, y: number, lineWidth: number, color: Color) { + drawDebugSSRect(painter, 0, y + lineWidth / 2, painter.transform.width, lineWidth, color); +} + +function drawVerticalLine(painter: Painter, x: number, lineWidth: number, color: Color) { + drawDebugSSRect(painter, x - lineWidth / 2, 0, lineWidth, painter.transform.height, color); +} + +function drawDebugSSRect(painter: Painter, x: number, y: number, width: number, height: number, color: Color) { + const context = painter.context; + const gl = context.gl; + + gl.enable(gl.SCISSOR_TEST); + gl.scissor(x * browser.devicePixelRatio, y * browser.devicePixelRatio, width * browser.devicePixelRatio, height * browser.devicePixelRatio); + context.clear({color}); + gl.disable(gl.SCISSOR_TEST); +} + function drawDebug(painter: Painter, sourceCache: SourceCache, coords: Array) { for (let i = 0; i < coords.length; i++) { drawDebugTile(painter, sourceCache, coords[i]); diff --git a/src/render/painter.js b/src/render/painter.js index 5499e109d57..01f51643923 100644 --- a/src/render/painter.js +++ b/src/render/painter.js @@ -33,7 +33,7 @@ import fillExtrusion from './draw_fill_extrusion'; import hillshade from './draw_hillshade'; import raster from './draw_raster'; import background from './draw_background'; -import debug from './draw_debug'; +import debug, {drawDebugPadding} from './draw_debug'; import custom from './draw_custom'; const draw = { @@ -69,6 +69,7 @@ export type RenderPass = 'offscreen' | 'opaque' | 'translucent'; type PainterOptions = { showOverdrawInspector: boolean, showTileBoundaries: boolean, + showPadding: boolean, rotating: boolean, zooming: boolean, moving: boolean, @@ -473,6 +474,10 @@ class Painter { } } + if (this.options.showPadding) { + drawDebugPadding(this); + } + // Set defaults for most GL values so that anyone using the state after the render // encounters more expected values. this.context.setDefault(); diff --git a/src/ui/camera.js b/src/ui/camera.js index 7b88df5eca5..c5abb8b86bb 100644 --- a/src/ui/camera.js +++ b/src/ui/camera.js @@ -3,7 +3,6 @@ import { bindAll, extend, - deepEqual, warnOnce, clamp, wrap, @@ -22,6 +21,7 @@ import type {LngLatLike} from '../geo/lng_lat'; import type {LngLatBoundsLike} from '../geo/lng_lat_bounds'; import type {TaskID} from '../util/task_queue'; import type {PointLike} from '@mapbox/point-geometry'; +import type {PaddingOptions} from '../geo/edge_insets'; /** * Options common to {@link Map#jumpTo}, {@link Map#easeTo}, and {@link Map#flyTo}, controlling the desired location, @@ -35,13 +35,15 @@ import type {PointLike} from '@mapbox/point-geometry'; * is "up"; for example, a bearing of 90° orients the map so that east is up. * @property {number} pitch The desired pitch, in degrees. * @property {LngLatLike} around If `zoom` is specified, `around` determines the point around which the zoom is centered. + * @property {PaddingOptions} padding Dimensions in pixels applied on eachs side of the viewport for shifting the vanishing point. */ export type CameraOptions = { center?: LngLatLike, zoom?: number, bearing?: number, pitch?: number, - around?: LngLatLike + around?: LngLatLike, + padding?: PaddingOptions }; /** @@ -83,6 +85,7 @@ class Camera extends Evented { _zooming: boolean; _rotating: boolean; _pitching: boolean; + _padding: boolean; _bearingSnap: number; _easeEndTimeoutID: TimeoutID; @@ -284,6 +287,34 @@ class Camera extends Evented { return this; } + /** + * Returns the current padding applied around the map viewport. + * + * @memberof Map# + * @returns The current padding around the map viewport. + */ + getPadding(): PaddingOptions { return this.transform.padding; } + + /** + * Sets the padding in pixels around the viewport. + * + * Equivalent to `jumpTo({padding: padding})`. + * + * @memberof Map# + * @param padding The desired padding. Format: { left: number, right: number, top: number, bottom: number } + * @param eventData Additional properties to be added to event objects of events triggered by this method. + * @fires movestart + * @fires moveend + * @returns {Map} `this` + * @example + * // Sets a left padding of 300px, and a top padding of 50px + * map.setPadding({ left: 300, top: 50 }); + */ + setPadding(padding: PaddingOptions, eventData?: Object) { + this.jumpTo({padding}, eventData); + return this; + } + /** * Rotates the map to the specified bearing, with an animated transition. The bearing is the compass direction * that is \"up\"; for example, a bearing of 90° orients the map so that east is up. @@ -424,13 +455,14 @@ class Camera extends Evented { * }); */ _cameraForBoxAndBearing(p0: LngLatLike, p1: LngLatLike, bearing: number, options?: CameraOptions): void | CameraOptions & AnimationOptions { + const defaultPadding = { + top: 0, + bottom: 0, + right: 0, + left: 0 + }; options = extend({ - padding: { - top: 0, - bottom: 0, - right: 0, - left: 0 - }, + padding: defaultPadding, offset: [0, 0], maxZoom: this.transform.maxZoom }, options); @@ -444,18 +476,10 @@ class Camera extends Evented { left: p }; } - if (!deepEqual(Object.keys(options.padding).sort((a, b) => { - if (a < b) return -1; - if (a > b) return 1; - return 0; - }), ["bottom", "left", "right", "top"])) { - warnOnce( - "options.padding must be a positive number, or an Object with keys 'bottom', 'left', 'right', 'top'" - ); - return; - } + options.padding = extend(defaultPadding, options.padding); const tr = this.transform; + const edgePadding = tr.padding; // We want to calculate the upper right and lower left of the box defined by p0 and p1 // in a coordinate system rotate to match the destination bearing. @@ -469,8 +493,8 @@ class Camera extends Evented { // Calculate zoom: consider the original bbox and padding. const size = upperRight.sub(lowerLeft); - const scaleX = (tr.width - options.padding.left - options.padding.right) / size.x; - const scaleY = (tr.height - options.padding.top - options.padding.bottom) / size.y; + const scaleX = (tr.width - (edgePadding.left + edgePadding.right + options.padding.left + options.padding.right)) / size.x; + const scaleY = (tr.height - (edgePadding.top + edgePadding.bottom + options.padding.top + options.padding.bottom)) / size.y; if (scaleY < 0 || scaleX < 0) { warnOnce( @@ -628,6 +652,10 @@ class Camera extends Evented { tr.pitch = +options.pitch; } + if (options.padding != null && !tr.isPaddingEqual(options.padding)) { + tr.padding = options.padding; + } + this.fire(new Event('movestart', eventData)) .fire(new Event('move', eventData)); @@ -653,7 +681,7 @@ class Camera extends Evented { } /** - * Changes any combination of center, zoom, bearing, and pitch, with an animated transition + * Changes any combination of center, zoom, bearing, pitch, and padding with an animated transition * between old and new values. The map will retain its current values for any * details not specified in `options`. * @@ -693,12 +721,15 @@ class Camera extends Evented { startZoom = this.getZoom(), startBearing = this.getBearing(), startPitch = this.getPitch(), + startPadding = this.getPadding(), zoom = 'zoom' in options ? +options.zoom : startZoom, bearing = 'bearing' in options ? this._normalizeBearing(options.bearing, startBearing) : startBearing, - pitch = 'pitch' in options ? +options.pitch : startPitch; + pitch = 'pitch' in options ? +options.pitch : startPitch, + padding = 'padding' in options ? options.padding : tr.padding; - const pointAtOffset = tr.centerPoint.add(Point.convert(options.offset)); + const offsetAsPoint = Point.convert(options.offset); + let pointAtOffset = tr.centerPoint.add(offsetAsPoint); const locationAtOffset = tr.pointLocation(pointAtOffset); const center = LngLat.convert(options.center || locationAtOffset); this._normalizeCenter(center); @@ -717,6 +748,7 @@ class Camera extends Evented { this._zooming = (zoom !== startZoom); this._rotating = (startBearing !== bearing); this._pitching = (pitch !== startPitch); + this._padding = !tr.isPaddingEqual(padding); this._prepareEase(eventData, options.noMoveStart); @@ -732,6 +764,12 @@ class Camera extends Evented { if (this._pitching) { tr.pitch = interpolate(startPitch, pitch, k); } + if (this._padding) { + tr.interpolatePadding(startPadding, padding, k); + // When padding is being applied, Transform#centerPoint is changing continously, + // thus we need to recalculate offsetPoint every fra,e + pointAtOffset = tr.centerPoint.add(offsetAsPoint); + } if (around) { tr.setLocationAtPoint(around, aroundPoint); @@ -796,6 +834,7 @@ class Camera extends Evented { this._zooming = false; this._rotating = false; this._pitching = false; + this._padding = false; if (wasZooming) { this.fire(new Event('zoomend', eventData)); @@ -895,14 +934,17 @@ class Camera extends Evented { const tr = this.transform, startZoom = this.getZoom(), startBearing = this.getBearing(), - startPitch = this.getPitch(); + startPitch = this.getPitch(), + startPadding = this.getPadding(); const zoom = 'zoom' in options ? clamp(+options.zoom, tr.minZoom, tr.maxZoom) : startZoom; const bearing = 'bearing' in options ? this._normalizeBearing(options.bearing, startBearing) : startBearing; const pitch = 'pitch' in options ? +options.pitch : startPitch; + const padding = 'padding' in options ? options.padding : tr.padding; const scale = tr.zoomScale(zoom - startZoom); - const pointAtOffset = tr.centerPoint.add(Point.convert(options.offset)); + const offsetAsPoint = Point.convert(options.offset); + let pointAtOffset = tr.centerPoint.add(offsetAsPoint); const locationAtOffset = tr.pointLocation(pointAtOffset); const center = LngLat.convert(options.center || locationAtOffset); this._normalizeCenter(center); @@ -990,6 +1032,7 @@ class Camera extends Evented { this._zooming = true; this._rotating = (startBearing !== bearing); this._pitching = (pitch !== startPitch); + this._padding = !tr.isPaddingEqual(padding); this._prepareEase(eventData, false); @@ -1005,6 +1048,12 @@ class Camera extends Evented { if (this._pitching) { tr.pitch = interpolate(startPitch, pitch, k); } + if (this._padding) { + tr.interpolatePadding(startPadding, padding, k); + // When padding is being applied, Transform#centerPoint is changing continously, + // thus we need to recalculate offsetPoint every frame + pointAtOffset = tr.centerPoint.add(offsetAsPoint); + } const newCenter = k === 1 ? center : tr.unproject(from.add(delta.mult(u(s))).mult(scale)); tr.setLocationAtPoint(tr.renderWorldCopies ? newCenter.wrap() : newCenter, pointAtOffset); diff --git a/src/ui/map.js b/src/ui/map.js index c00e326197f..63f2cdfe4d9 100755 --- a/src/ui/map.js +++ b/src/ui/map.js @@ -271,6 +271,7 @@ class Map extends Camera { _interactive: ?boolean; _showTileBoundaries: ?boolean; _showCollisionBoxes: ?boolean; + _showPadding: ?boolean; _showOverdrawInspector: boolean; _repaint: ?boolean; _vertices: ?boolean; @@ -2198,8 +2199,9 @@ class Map extends Camera { rotating: this.isRotating(), zooming: this.isZooming(), moving: this.isMoving(), + fadeDuration: this._fadeDuration, + showPadding: this.showPadding, gpuTiming: !!this.listens('gpu-timing-layer'), - fadeDuration: this._fadeDuration }); this.fire(new Event('render')); @@ -2349,6 +2351,22 @@ class Map extends Camera { this._update(); } + /** + * Gets and sets a Boolean indicating whether the map will visualize + * the padding offsets. + * + * @name showPadding + * @type {boolean} + * @instance + * @memberof Map + */ + get showPadding(): boolean { return !!this._showPadding; } + set showPadding(value: boolean) { + if (this._showPadding === value) return; + this._showPadding = value; + this._update(); + } + /** * Gets and sets a Boolean indicating whether the map will render boxes * around all symbols in the data source, revealing which symbols diff --git a/test/integration/render-tests/debug/padding/ease-to-btm-distort/expected.png b/test/integration/render-tests/debug/padding/ease-to-btm-distort/expected.png new file mode 100644 index 0000000000000000000000000000000000000000..f7ddba62f9672e79701ada9d09f72013c98aea40 GIT binary patch literal 12345 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℞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 literal 0 HcmV?d00001 diff --git a/test/integration/render-tests/debug/padding/ease-to-left-distort/style.json b/test/integration/render-tests/debug/padding/ease-to-left-distort/style.json new file mode 100644 index 00000000000..9f9d70ad524 --- /dev/null +++ b/test/integration/render-tests/debug/padding/ease-to-left-distort/style.json @@ -0,0 +1,112 @@ +{ + "version": 8, + "metadata": { + "test": { + "showPadding": true, + "height": 256, + "operations": [ + [ + "easeTo", + { + "padding": { + "top": 20, + "left": 250, + "bottom": 10, + "right": 15 + } + } + ], + [ + "wait", + 500 + ] + ] + } + }, + "center": [ 0, 0 ], + "zoom": 8, + "pitch": 60, + "sources": { + "northward-road": { + "type": "geojson", + "data": { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [ 0, -25], + [ 0, 25] + ] + } + },{ + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [ -0.2, -25], + [ -0.2, 25] + ] + } + },{ + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [ 0.2, -25], + [ 0.2, 25] + ] + } + },{ + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [ -25, 0.2], + [ 25, 0.2] + ] + } + },{ + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [ -25, -0.2], + [ 25, -0.2] + ] + } + },{ + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [ -25, 0], + [ 25, 0] + ] + } + } + ] + } + } + }, + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "line", + "type": "line", + "source": "northward-road", + "layout": {}, + "paint": { + "line-width": 10 + } + } + ] +} diff --git a/test/integration/render-tests/debug/padding/ease-to-no-distort/expected.png b/test/integration/render-tests/debug/padding/ease-to-no-distort/expected.png new file mode 100644 index 0000000000000000000000000000000000000000..e709e1c98ede9eea1526eac058cf6a8546f4e428 GIT binary patch literal 11978 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 VbW8AIe53x8jpb@q?r)pI{~tMFD4zfT literal 0 HcmV?d00001 diff --git a/test/integration/render-tests/debug/padding/ease-to-no-distort/style.json b/test/integration/render-tests/debug/padding/ease-to-no-distort/style.json new file mode 100644 index 00000000000..46ec2f25030 --- /dev/null +++ b/test/integration/render-tests/debug/padding/ease-to-no-distort/style.json @@ -0,0 +1,127 @@ +{ + "version": 8, + "metadata": { + "test": { + "showPadding": true, + "height": 256, + "operations": [ + [ + "easeTo", + { + "padding": { + "top": 20, + "left": 50, + "bottom": 10, + "right": 250 + } + } + ], + [ + "wait", + 500 + ], + [ + "easeTo", + { + "padding": { + "top": 10, + "left": 10, + "bottom": 10, + "right": 10 + } + } + ], + [ + "wait", + 500 + ] + ] + } + }, + "center": [ 0, 0 ], + "zoom": 8, + "pitch": 60, + "sources": { + "northward-road": { + "type": "geojson", + "data": { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [ 0, -25], + [ 0, 25] + ] + } + },{ + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [ -0.2, -25], + [ -0.2, 25] + ] + } + },{ + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [ 0.2, -25], + [ 0.2, 25] + ] + } + },{ + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [ -25, 0.2], + [ 25, 0.2] + ] + } + },{ + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [ -25, -0.2], + [ 25, -0.2] + ] + } + },{ + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [ -25, 0], + [ 25, 0] + ] + } + } + ] + } + } + }, + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "line", + "type": "line", + "source": "northward-road", + "layout": {}, + "paint": { + "line-width": 10 + } + } + ] +} diff --git a/test/integration/render-tests/debug/padding/ease-to-right-distort/expected.png b/test/integration/render-tests/debug/padding/ease-to-right-distort/expected.png new file mode 100644 index 0000000000000000000000000000000000000000..ddf26422755bf4a12fd685ce567e2e55891cd820 GIT binary patch literal 11593 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 Ao&W#< literal 0 HcmV?d00001 diff --git a/test/integration/render-tests/debug/padding/ease-to-top-distort/style.json b/test/integration/render-tests/debug/padding/ease-to-top-distort/style.json new file mode 100644 index 00000000000..183d7da9c15 --- /dev/null +++ b/test/integration/render-tests/debug/padding/ease-to-top-distort/style.json @@ -0,0 +1,112 @@ +{ + "version": 8, + "metadata": { + "test": { + "showPadding": true, + "height": 256, + "operations": [ + [ + "easeTo", + { + "padding": { + "top": 100, + "left": 50, + "bottom": 10, + "right": 250 + } + } + ], + [ + "wait", + 500 + ] + ] + } + }, + "center": [ 0, 0 ], + "zoom": 8, + "pitch": 60, + "sources": { + "northward-road": { + "type": "geojson", + "data": { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [ 0, -25], + [ 0, 25] + ] + } + },{ + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [ -0.2, -25], + [ -0.2, 25] + ] + } + },{ + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [ 0.2, -25], + [ 0.2, 25] + ] + } + },{ + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [ -25, 0.2], + [ 25, 0.2] + ] + } + },{ + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [ -25, -0.2], + [ 25, -0.2] + ] + } + },{ + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [ -25, 0], + [ 25, 0] + ] + } + } + ] + } + } + }, + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "line", + "type": "line", + "source": "northward-road", + "layout": {}, + "paint": { + "line-width": 10 + } + } + ] +} diff --git a/test/integration/render-tests/debug/padding/set-padding/expected.png b/test/integration/render-tests/debug/padding/set-padding/expected.png new file mode 100644 index 0000000000000000000000000000000000000000..c1d5e83e1ebd97bb8f29f6b0d7cf31183316d7f6 GIT binary patch literal 11900 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 literal 0 HcmV?d00001 diff --git a/test/integration/render-tests/debug/padding/set-padding/style.json b/test/integration/render-tests/debug/padding/set-padding/style.json new file mode 100644 index 00000000000..c54c836ed35 --- /dev/null +++ b/test/integration/render-tests/debug/padding/set-padding/style.json @@ -0,0 +1,82 @@ +{ + "version": 8, + "metadata": { + "test": { + "showPadding": true, + "height": 256, + "operations": [ + [ + "setPadding", + { + "top": 20, + "left": 125, + "bottom": 10, + "right": 15 + } + ], + [ + "wait" + ] + ] + } + }, + "center": [ 0, 0 ], + "zoom": 8, + "pitch": 60, + "sources": { + "northward-road": { + "type": "geojson", + "data": { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [ 0, -25], + [ 0, 25] + ] + } + },{ + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [ -0.2, -25], + [ -0.2, 25] + ] + } + },{ + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [ 0.2, -25], + [ 0.2, 25] + ] + } + } + ] + } + } + }, + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "line", + "type": "line", + "source": "northward-road", + "layout": {}, + "paint": { + "line-width": 10 + } + } + ] +} diff --git a/test/suite_implementation.js b/test/suite_implementation.js index 5aef1a905d3..0b33c0803dc 100644 --- a/test/suite_implementation.js +++ b/test/suite_implementation.js @@ -66,6 +66,7 @@ module.exports = function(style, options, _callback) { // eslint-disable-line im if (options.debug) map.showTileBoundaries = true; if (options.showOverdrawInspector) map.showOverdrawInspector = true; + if (options.showPadding) map.showPadding = true; const gl = map.painter.context.gl; diff --git a/test/unit/geo/edge_insets.test.js b/test/unit/geo/edge_insets.test.js new file mode 100644 index 00000000000..ccfc1982cf4 --- /dev/null +++ b/test/unit/geo/edge_insets.test.js @@ -0,0 +1,99 @@ +import {test} from '../../util/test'; +import EdgeInsets from '../../../src/geo/edge_insets'; + +test('EdgeInsets', (t) => { + t.test('#constructor', (t) => { + t.ok(new EdgeInsets() instanceof EdgeInsets, 'creates an object with default values'); + t.throws(() => { + new EdgeInsets(NaN, 10); + }, `Invalid input EdgeInsets(NaN, 10) gets detected and error is thrown`); + t.throws(() => { + new EdgeInsets(-10, 10, 20, 10); + }, `Invalid input EdgeInsets(-10, 10, 20, 10) gets detected and error is thrown`); + + t.test('valid initialization', (t) => { + const top = 10; + const bottom = 15; + const left = 26; + const right = 19; + + const inset = new EdgeInsets(top, bottom, left, right); + t.equal(inset.top, top); + t.equal(inset.bottom, bottom); + t.equal(inset.left, left); + t.equal(inset.right, right); + t.end(); + }); + t.end(); + }); + + t.test('#getCenter', (t) => { + t.test('valid input', (t) => { + const inset = new EdgeInsets(10, 15, 50, 10); + const center = inset.getCenter(600, 400); + t.equal(center.x, 320); + t.equal(center.y, 197.5); + t.end(); + }); + + t.test('center clamping', (t) => { + const inset = new EdgeInsets(300, 200, 500, 200); + const center = inset.getCenter(600, 400); + // Midpoint of the overlap when padding overlaps + t.equal(center.x, 450); + t.equal(center.y, 250); + t.end(); + }); + t.end(); + }); + + t.test('#interpolate', (t) => { + t.test('it works', (t) => { + const inset1 = new EdgeInsets(10, 15, 50, 10); + const inset2 = new EdgeInsets(20, 30, 100, 10); + const inset3 = inset1.interpolate(inset1, inset2, 0.5); + // inset1 is mutated in-place + t.equal(inset3, inset1); + + t.equal(inset3.top, 15); + t.equal(inset3.bottom, 22.5); + t.equal(inset3.left, 75); + t.equal(inset3.right, 10); + t.end(); + }); + + t.test('it retains insets that dont have new parameters passed in', (t) => { + const inset = new EdgeInsets(10, 15, 50, 10); + const target = { + top: 20 + }; + inset.interpolate(inset, target, 0.5); + t.equal(inset.top, 15); + t.equal(inset.bottom, 15); + t.equal(inset.left, 50); + t.equal(inset.right, 10); + t.end(); + }); + + t.end(); + }); + + t.test('#equals', (t) => { + const inset1 = new EdgeInsets(10, 15, 50, 10); + const inset2 = new EdgeInsets(10, 15, 50, 10); + const inset3 = new EdgeInsets(10, 15, 50, 11); + t.ok(inset1.equals(inset2)); + t.notOk(inset2.equals(inset3)); + t.end(); + }); + + t.test('#clone', (t) => { + const inset1 = new EdgeInsets(10, 15, 50, 10); + const inset2 = inset1.clone(); + t.notOk(inset2 === inset1); + t.ok(inset1.equals(inset2)); + t.end(); + }); + + t.end(); +}); diff --git a/test/unit/ui/camera.test.js b/test/unit/ui/camera.test.js index c801dd87f16..fe656b558ff 100644 --- a/test/unit/ui/camera.test.js +++ b/test/unit/ui/camera.test.js @@ -316,6 +316,45 @@ test('camera', (t) => { t.end(); }); + t.test('#setPadding', (t) => { + t.test('sets padding', (t) => { + const camera = createCamera(); + const padding = {left: 300, top: 100, right: 50, bottom: 10}; + camera.setPadding(padding); + t.deepEqual(camera.getPadding(), padding); + t.end(); + }); + + t.test('existing padding is retained if no new values are passed in', (t) => { + const camera = createCamera(); + const padding = {left: 300, top: 100, right: 50, bottom: 10}; + camera.setPadding(padding); + camera.setPadding({}); + + const currentPadding = camera.getPadding(); + t.deepEqual(currentPadding, padding); + t.end(); + }); + + t.test('doesnt change padding thats already present if new value isnt passed in', (t) => { + const camera = createCamera(); + const padding = {left: 300, top: 100, right: 50, bottom: 10}; + camera.setPadding(padding); + const padding1 = {right: 100}; + camera.setPadding(padding1); + + const currentPadding = camera.getPadding(); + t.equal(currentPadding.left, padding.left); + t.equal(currentPadding.top, padding.top); + // padding1 here + t.equal(currentPadding.right, padding1.right); + t.equal(currentPadding.bottom, padding.bottom); + t.end(); + }); + + t.end(); + }); + t.test('#panBy', (t) => { t.test('pans by specified amount', (t) => { const camera = createCamera();