Smarter reuse detection
This commit is contained in:
@@ -362,10 +362,12 @@ class Executor extends Disposable {
|
||||
const declutterArgs = intersects ?
|
||||
[context, transform ? transform.slice(0) : null, opacity, image, originX, originY, w, h, x, y, scale] :
|
||||
null;
|
||||
if (declutterArgs && fillStroke) {
|
||||
declutterArgs.push(fillInstruction, strokeInstruction, p1, p2, p3, p4);
|
||||
if (declutterArgs) {
|
||||
if (fillStroke) {
|
||||
declutterArgs.push(fillInstruction, strokeInstruction, p1, p2, p3, p4);
|
||||
}
|
||||
declutterGroup.push(declutterArgs);
|
||||
}
|
||||
declutterGroup.push(declutterArgs);
|
||||
} else if (intersects) {
|
||||
if (fillStroke) {
|
||||
this.replayTextBackground_(context, p1, p2, p3, p4,
|
||||
|
||||
@@ -9,7 +9,6 @@ import MapRenderer from './Map.js';
|
||||
import SourceState from '../source/State.js';
|
||||
import {replaceChildren} from '../dom.js';
|
||||
import {labelCache} from '../render/canvas.js';
|
||||
import {altShiftKeysOnly} from '../events/condition.js';
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,7 +6,7 @@ import ViewHint from '../../ViewHint.js';
|
||||
import {containsExtent, intersects} from '../../extent.js';
|
||||
import {getIntersection, isEmpty} from '../../extent.js';
|
||||
import CanvasLayerRenderer from './Layer.js';
|
||||
import {compose as composeTransform, makeInverse, toString as transformToString, apply as applyTransform} from '../../transform.js';
|
||||
import {compose as composeTransform, makeInverse, toString as transformToString} from '../../transform.js';
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
|
||||
@@ -8,7 +8,6 @@ import RenderEventType from '../../render/EventType.js';
|
||||
import {rotateAtOffset} from '../../render/canvas.js';
|
||||
import LayerRenderer from '../Layer.js';
|
||||
import {create as createTransform, apply as applyTransform, compose as composeTransform, toString as transformToString} from '../../transform.js';
|
||||
import ContextEventType from '../../webgl/ContextEventType.js';
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
@@ -64,16 +63,20 @@ class CanvasLayerRenderer extends LayerRenderer {
|
||||
*/
|
||||
this.context = null;
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.containerReused = false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a rendering container from an existing target, if compatible.
|
||||
* @param {HTMLElement} target Potential render target.
|
||||
* @param {import("../../transform").Transform} transform Transform.
|
||||
* @return {boolean} The target is reused for this layer.
|
||||
*/
|
||||
useContainer(target, transform) {
|
||||
let reused = false;
|
||||
const layerClassName = this.getLayer().getClassName();
|
||||
let container, context;
|
||||
if (target) {
|
||||
const canvas = target.firstElementChild;
|
||||
@@ -82,33 +85,33 @@ class CanvasLayerRenderer extends LayerRenderer {
|
||||
}
|
||||
}
|
||||
if (context && context.canvas.style.transform === transformToString(transform)) {
|
||||
container = target;
|
||||
reused = true;
|
||||
} else {
|
||||
context = null;
|
||||
container = this.container;
|
||||
if (!container) {
|
||||
container = document.createElement('div');
|
||||
const style = container.style;
|
||||
style.position = 'absolute';
|
||||
style.width = '100%';
|
||||
style.height = '100%';
|
||||
}
|
||||
// Container of the previous layer renderer can be used.
|
||||
target.classList.add(layerClassName);
|
||||
this.container = target;
|
||||
this.context = context;
|
||||
this.containerReused = true;
|
||||
} else if (this.containerReused) {
|
||||
// Previously reused container cannot be used any more.
|
||||
this.container = null;
|
||||
this.context = null;
|
||||
this.containerReused = false;
|
||||
}
|
||||
if (container !== this.container) {
|
||||
container.classList.add(this.getLayer().getClassName());
|
||||
if (!this.container) {
|
||||
container = document.createElement('div');
|
||||
container.className = layerClassName;
|
||||
let style = container.style;
|
||||
style.position = 'absolute';
|
||||
style.width = '100%';
|
||||
style.height = '100%';
|
||||
context = createCanvasContext2D();
|
||||
const canvas = context.canvas;
|
||||
container.appendChild(canvas);
|
||||
style = canvas.style;
|
||||
style.position = 'absolute';
|
||||
style.transformOrigin = 'top left';
|
||||
this.container = container;
|
||||
if (!context) {
|
||||
context = createCanvasContext2D();
|
||||
const canvas = context.canvas;
|
||||
container.appendChild(canvas);
|
||||
const style = canvas.style;
|
||||
style.position = 'absolute';
|
||||
style.transformOrigin = 'top left';
|
||||
}
|
||||
this.context = context;
|
||||
}
|
||||
return reused;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,7 +7,6 @@ import TileState from '../../TileState.js';
|
||||
import {createEmpty, equals, getIntersection, getTopLeft} from '../../extent.js';
|
||||
import CanvasLayerRenderer from './Layer.js';
|
||||
import {apply as applyTransform, compose as composeTransform, makeInverse, toString as transformToString} from '../../transform.js';
|
||||
import {numberSafeCompareFunction} from '../../array.js';
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
@@ -234,7 +233,7 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
||||
-width / 2, -height / 2
|
||||
);
|
||||
|
||||
const reused = this.useContainer(target, this.pixelTransform_);
|
||||
this.useContainer(target, this.pixelTransform_);
|
||||
const context = this.context;
|
||||
const canvas = context.canvas;
|
||||
|
||||
@@ -251,7 +250,7 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
||||
if (canvas.width != width || canvas.height != height) {
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
} else if (!reused) {
|
||||
} else if (!this.containerReused) {
|
||||
context.clearRect(0, 0, width, height);
|
||||
}
|
||||
|
||||
|
||||
@@ -70,17 +70,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
renderFrame(frameState, layerState) {
|
||||
const context = this.context;
|
||||
const canvas = context.canvas;
|
||||
|
||||
const replayGroup = this.replayGroup_;
|
||||
if (!replayGroup || replayGroup.isEmpty()) {
|
||||
if (canvas.width > 0) {
|
||||
canvas.width = 0;
|
||||
}
|
||||
return canvas;
|
||||
}
|
||||
renderFrame(frameState, layerState, target) {
|
||||
|
||||
const pixelRatio = frameState.pixelRatio;
|
||||
|
||||
@@ -88,6 +78,18 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
|
||||
makeScale(this.pixelTransform_, 1 / pixelRatio, 1 / pixelRatio);
|
||||
makeInverse(this.inversePixelTransform_, this.pixelTransform_);
|
||||
|
||||
this.useContainer(target, this.pixelTransform_);
|
||||
const context = this.context;
|
||||
const canvas = context.canvas;
|
||||
|
||||
const replayGroup = this.replayGroup_;
|
||||
if (!replayGroup || replayGroup.isEmpty()) {
|
||||
if (!this.containerReused && canvas.width > 0) {
|
||||
canvas.width = 0;
|
||||
}
|
||||
return this.container;
|
||||
}
|
||||
|
||||
// resize and clear
|
||||
const width = Math.round(frameState.size[0] * pixelRatio);
|
||||
const height = Math.round(frameState.size[1] * pixelRatio);
|
||||
@@ -98,7 +100,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
|
||||
if (canvas.style.transform !== canvasTransform) {
|
||||
canvas.style.transform = canvasTransform;
|
||||
}
|
||||
} else {
|
||||
} else if (!this.containerReused) {
|
||||
context.clearRect(0, 0, width, height);
|
||||
}
|
||||
|
||||
@@ -166,7 +168,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
|
||||
canvas.style.opacity = opacity;
|
||||
}
|
||||
|
||||
return canvas;
|
||||
return this.container;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -123,27 +123,31 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
* @inheritDoc
|
||||
*/
|
||||
useContainer(target, transform) {
|
||||
let context;
|
||||
let overlayContext;
|
||||
if (target && target.childElementCount === 2) {
|
||||
context = target.lastElementChild.getContext('2d');
|
||||
if (!context) {
|
||||
overlayContext = target.lastElementChild.getContext('2d');
|
||||
if (!overlayContext) {
|
||||
target = null;
|
||||
}
|
||||
} else {
|
||||
context = this.overlayContext_;
|
||||
if (!this.overlayContext_) {
|
||||
context = createCanvasContext2D();
|
||||
const style = context.canvas.style;
|
||||
style.position = 'absolute';
|
||||
style.transformOrigin = 'top left';
|
||||
}
|
||||
}
|
||||
const reused = super.useContainer(target, transform);
|
||||
const containerReused = this.containerReused;
|
||||
super.useContainer(target, transform);
|
||||
if (containerReused && !this.containerReused && !overlayContext) {
|
||||
this.overlayContext_ = null;
|
||||
}
|
||||
if (this.containerReused && overlayContext) {
|
||||
this.overlayContext_ = overlayContext;
|
||||
}
|
||||
if (!this.overlayContext_) {
|
||||
const overlayContext = createCanvasContext2D();
|
||||
const style = overlayContext.canvas.style;
|
||||
style.position = 'absolute';
|
||||
style.transformOrigin = 'top left';
|
||||
this.overlayContext_ = overlayContext;
|
||||
}
|
||||
if (this.container.childElementCount === 1) {
|
||||
this.container.appendChild(context.canvas);
|
||||
this.container.appendChild(this.overlayContext_.canvas);
|
||||
}
|
||||
this.overlayContext_ = context;
|
||||
return reused;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -401,7 +405,6 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
|
||||
if (!isEmpty(this.renderTileImageQueue_) && !this.extentChanged) {
|
||||
this.renderTileImages_(hifi, frameState);
|
||||
return this.container;
|
||||
}
|
||||
|
||||
const context = this.overlayContext_;
|
||||
@@ -427,7 +430,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
if (canvas.style.transform !== canvasTransform) {
|
||||
canvas.style.transform = canvasTransform;
|
||||
}
|
||||
} else {
|
||||
} else if (!this.containerReused) {
|
||||
context.clearRect(0, 0, width, height);
|
||||
}
|
||||
|
||||
@@ -496,10 +499,6 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
canvas.style.opacity = opacity;
|
||||
}
|
||||
|
||||
// Now that we have rendered the tiles we have already, let's prepare new tile images
|
||||
// for the next frame
|
||||
this.renderTileImages_(hifi, frameState);
|
||||
|
||||
return this.container;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user