diff --git a/changelog/upgrade-notes.md b/changelog/upgrade-notes.md index fff1a1231d..65d5662a11 100644 --- a/changelog/upgrade-notes.md +++ b/changelog/upgrade-notes.md @@ -42,7 +42,7 @@ The `getUid` function from the `ol/util` module now returns a string instead of When a map contains a layer from a `ol/source/OSM` source, the `ol/control/Attribution` control will be shown with the `collapsible: false` behavior. -To get the previous behavior, configure the `ol/control/Attribution` control with `collapsible: true`. +To get the previous behavior, configure the `ol/control/Attribution` control with `collapsible: true`. ### v5.2.0 diff --git a/src/ol/VectorImageTile.js b/src/ol/VectorImageTile.js index eaa36142c9..ac5fbd68bf 100644 --- a/src/ol/VectorImageTile.js +++ b/src/ol/VectorImageTile.js @@ -72,6 +72,12 @@ class VectorImageTile extends Tile { */ this.sourceTiles_ = sourceTiles; + /** + * @private + * @type {boolean} + */ + this.sourceTilesLoaded = false; + /** * Keys of source tiles used by this tile. Use with {@link #getTile}. * @type {Array} @@ -312,7 +318,8 @@ class VectorImageTile extends Tile { if (loaded == this.tileKeys.length) { this.loadListenerKeys_.forEach(unlistenByKey); this.loadListenerKeys_.length = 0; - this.setState(TileState.LOADED); + this.sourceTilesLoaded = true; + this.changed(); } else { this.setState(empty == this.tileKeys.length ? TileState.EMPTY : TileState.ERROR); } diff --git a/src/ol/render.js b/src/ol/render.js index 9364f79264..8494cb61c7 100644 --- a/src/ol/render.js +++ b/src/ol/render.js @@ -2,7 +2,7 @@ * @module ol/render */ import {DEVICE_PIXEL_RATIO} from './has.js'; -import {create as createTransform, scale as scaleTransform} from './transform.js'; +import {apply as applyTransform, create as createTransform, scale as scaleTransform} from './transform.js'; import CanvasImmediateRenderer from './render/canvas/Immediate.js'; @@ -77,3 +77,27 @@ export function toContext(context, opt_options) { const transform = scaleTransform(createTransform(), pixelRatio, pixelRatio); return new CanvasImmediateRenderer(context, pixelRatio, extent, transform, 0); } + +/** + * Gets a vector context for drawing to + * @param {import("./render/Event.js").default} event Render event. + */ +export function getVectorContext(event) { + const frameState = event.frameState; + return new CanvasImmediateRenderer( + event.context, frameState.pixelRatio, frameState.extent, + event.pixelTransform, frameState.viewState.rotation); +} + +/** + * Gets the pixel of the event's canvas context from the map viewport's css pixel + * @param {import("./render/Event.js").default} event Render event. + * @param {import("./pixel.js").Pixel} pixel Css pixel relative to the top-left + * corner of the map viewport. + * @api + */ +export function getPixelFromPixel(event, pixel) { + const result = pixel.slice(0); + applyTransform(event.pixelTransform, pixel); + return result; +} diff --git a/src/ol/render/Event.js b/src/ol/render/Event.js index 6d23e04f53..28caf9fdc2 100644 --- a/src/ol/render/Event.js +++ b/src/ol/render/Event.js @@ -8,21 +8,22 @@ class RenderEvent extends Event { /** * @param {import("./EventType.js").default} type Type. - * @param {import("./VectorContext.js").default=} opt_vectorContext Vector context. + * @param {import("../transform.js").Transform=} opt_pixelTransform Transform. * @param {import("../PluggableMap.js").FrameState=} opt_frameState Frame state. * @param {?CanvasRenderingContext2D=} opt_context Context. * @param {?import("../webgl/Helper.js").default=} opt_glContext WebGL Context. */ - constructor(type, opt_vectorContext, opt_frameState, opt_context, opt_glContext) { + constructor(type, opt_pixelTransform, opt_frameState, opt_context, opt_glContext) { super(type); /** - * For canvas, this is an instance of {@link module:ol/render/canvas/Immediate}. - * @type {import("./VectorContext.js").default|undefined} + * Transform from css pixels (relative to the top-left corner of the map viewport) + * to render pixel on this event's `context`. + * @type {import("../transform.js").Transform|undefined} * @api */ - this.vectorContext = opt_vectorContext; + this.pixelTransform = opt_pixelTransform; /** * An object representing the current render frame state. diff --git a/src/ol/renderer/canvas/Layer.js b/src/ol/renderer/canvas/Layer.js index 6475a8366e..055de92de4 100644 --- a/src/ol/renderer/canvas/Layer.js +++ b/src/ol/renderer/canvas/Layer.js @@ -83,25 +83,21 @@ class CanvasLayerRenderer extends LayerRenderer { * @param {import("../../render/EventType.js").default} type Event type. * @param {CanvasRenderingContext2D} context Context. * @param {import("../../PluggableMap.js").FrameState} frameState Frame state. - * @param {import("../../transform.js").Transform=} opt_transform Transform. + * @param {import("../../transform.js").Transform} pixelTransform Transform. * @private */ - dispatchComposeEvent_(type, context, frameState, opt_transform) { + dispatchComposeEvent_(type, context, frameState, pixelTransform) { const layer = this.getLayer(); if (layer.hasListener(type)) { const halfWidth = (frameState.size[0] * frameState.pixelRatio) / 2; const halfHeight = (frameState.size[1] * frameState.pixelRatio) / 2; const rotation = frameState.viewState.rotation; - rotateAtOffset(context, -rotation, halfWidth, halfHeight); - const transform = opt_transform !== undefined ? - opt_transform : this.getTransform(frameState, 0); const render = new CanvasImmediateRenderer( - context, frameState.pixelRatio, frameState.extent, transform, + context, frameState.pixelRatio, frameState.extent, pixelTransform, frameState.viewState.rotation); - const composeEvent = new RenderEvent(type, render, frameState, + const composeEvent = new RenderEvent(type, pixelTransform, frameState, context, null); layer.dispatchEvent(composeEvent); - rotateAtOffset(context, rotation, halfWidth, halfHeight); } } diff --git a/src/ol/renderer/canvas/VectorTileLayer.js b/src/ol/renderer/canvas/VectorTileLayer.js index f1bb8c7dd5..94cbd6ea28 100644 --- a/src/ol/renderer/canvas/VectorTileLayer.js +++ b/src/ol/renderer/canvas/VectorTileLayer.js @@ -5,7 +5,7 @@ import {getUid} from '../../util.js'; import {createCanvasContext2D} from '../../dom.js'; import TileState from '../../TileState.js'; import ViewHint from '../../ViewHint.js'; -import {listen, unlisten} from '../../events.js'; +import {listen, unlisten, unlistenByKey} from '../../events.js'; import EventType from '../../events/EventType.js'; import rbush from 'rbush'; import {buffer, containsCoordinate, equals, getIntersection, getTopLeft, intersects} from '../../extent.js'; @@ -108,6 +108,12 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer { */ this.renderedLayerRevision_; + /** + * @private + * @type {Array.} + */ + this.tilesToRender_ = []; + /** * @private * @type {import("../../transform.js").Transform} @@ -134,11 +140,13 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer { */ getTile(z, x, y, pixelRatio, projection) { const tile = super.getTile(z, x, y, pixelRatio, projection); - if (tile.getState() === TileState.LOADED) { - this.createExecutorGroup_(/** @type {import("../../VectorImageTile.js").default} */ (tile), pixelRatio, projection); - if (this.context) { - this.renderTileImage_(/** @type {import("../../VectorImageTile.js").default} */ (tile), pixelRatio, projection); - } + if (tile.getState() === TileState.IDLE) { + const key = listen(tile, EventType.CHANGE, function() { + if (tile.getState() === TileState.LOADING && tile.sourceTilesLoaded) { + this.tilesToRender_.push(tile); + unlistenByKey(key); + } + }.bind(this)); } return tile; }