Keep track of used labels

This commit is contained in:
ahocevar
2019-01-22 21:00:21 +01:00
parent ea45068335
commit 592b6cf362
11 changed files with 150 additions and 37 deletions
+3 -14
View File
@@ -4,8 +4,8 @@
import {getFontFamilies} from '../css.js';
import {createCanvasContext2D} from '../dom.js';
import {clear} from '../obj.js';
import LRUCache from '../structs/LRUCache.js';
import {create as createTransform} from '../transform.js';
import LabelCache from './canvas/LabelCache.js';
/**
@@ -163,21 +163,10 @@ export const defaultLineWidth = 1;
/**
* The label cache for text rendering. To change the default cache size of 2048
* entries, use {@link module:ol/structs/LRUCache#setSize}.
* @type {LRUCache<HTMLCanvasElement>}
* @type {LabelCache}
* @api
*/
export const labelCache = new LRUCache();
/**
* Prune the label cache.
*/
export function pruneLabelCache() {
while (labelCache.canExpireCache()) {
const canvas = labelCache.pop();
canvas.width = canvas.height = 0;
}
}
export const labelCache = new LabelCache();
/**
+12 -2
View File
@@ -20,6 +20,7 @@ import {
} from '../../transform.js';
import {createCanvasContext2D} from '../../dom.js';
import {labelCache, defaultTextAlign, measureTextHeight, measureAndCacheTextWidth, measureTextWidths} from '../canvas.js';
import Disposable from '../../Disposable.js';
/**
@@ -52,7 +53,7 @@ const p3 = [];
const p4 = [];
class Executor {
class Executor extends Disposable {
/**
* @param {import("../../extent.js").Extent} maxExtent Maximum extent.
* @param {number} resolution Resolution.
@@ -62,6 +63,7 @@ class Executor {
* @param {SerializableInstructions} instructions The serializable instructions
*/
constructor(maxExtent, resolution, pixelRatio, overlaps, declutterTree, instructions) {
super();
/**
* @type {?}
*/
@@ -163,6 +165,14 @@ class Executor {
this.widths_ = {};
}
/**
* @inheritDoc
*/
disposeInternal() {
labelCache.release(this);
super.disposeInternal();
}
/**
* @param {string} text Text.
@@ -230,7 +240,7 @@ class Executor {
}
}
}
return labelCache.get(key);
return labelCache.get(key, this);
}
/**
+17 -4
View File
@@ -10,6 +10,7 @@ import {isEmpty} from '../../obj.js';
import BuilderType from './BuilderType.js';
import {create as createTransform, compose as composeTransform} from '../../transform.js';
import Executor from './Executor.js';
import Disposable from '../../Disposable.js';
/**
* @const
@@ -25,7 +26,7 @@ const ORDER = [
];
class ExecutorGroup {
class ExecutorGroup extends Disposable {
/**
* @param {import("../../extent.js").Extent} maxExtent Max extent.
* @param {number} resolution Resolution.
@@ -36,9 +37,8 @@ class ExecutorGroup {
* The serializable instructions.
* @param {number=} opt_renderBuffer Optional rendering buffer.
*/
constructor(maxExtent, resolution, pixelRatio, overlaps, declutterTree,
allInstructions, opt_renderBuffer) {
constructor(maxExtent, resolution, pixelRatio, overlaps, declutterTree, allInstructions, opt_renderBuffer) {
super();
/**
* Declutter tree.
* @private
@@ -130,6 +130,19 @@ class ExecutorGroup {
}
}
/**
* @inheritDoc
*/
disposeInternal() {
for (const z in this.executorsByZIndex_) {
const executors = this.executorsByZIndex_[z];
for (const key in executors) {
executors[key].disposeInternal();
}
}
super.disposeInternal();
}
/**
* @param {Array<BuilderType>} executors Executors.
* @return {boolean} Has executors of the provided types.
+69
View File
@@ -0,0 +1,69 @@
import {getUid} from '../../util.js';
import LRUCache from '../../structs/LRUCache.js';
/**
* @module ol/render/canvas/LabelCache
*/
/**
* @classdesc
* Cache of pre-rendered labels.
* @fires import("../events/Event.js").Event
*/
class LabelCache extends LRUCache {
/**
* @inheritDoc
*/
constructor(opt_highWaterMark) {
super(opt_highWaterMark);
this.consumers = {};
}
clear() {
super.clear();
this.consumers = {};
}
/**
* @override
* @param {string} key Label key.
* @param {import("./Executor.js").default} consumer Label consumer.
* @return {HTMLCanvasElement} Label.
*/
get(key, consumer) {
const canvas = super.get(key);
const consumerId = getUid(consumer);
if (!(consumerId in this.consumers)) {
this.consumers[consumerId] = {};
}
this.consumers[consumerId][key] = true;
return canvas;
}
prune() {
outer:
while (this.canExpireCache()) {
const key = this.peekLastKey();
for (const consumerId in this.consumers) {
if (key in this.consumers[consumerId]) {
break outer;
}
}
const canvas = this.pop();
canvas.width = canvas.height = 0;
for (const consumerId in this.consumers) {
delete this.consumers[consumerId][key];
}
}
}
/**
* @param {import("./Executor.js").default} consumer Label consumer.
*/
release(consumer) {
delete this.consumers[getUid(consumer)];
}
}
export default LabelCache;
+2 -2
View File
@@ -6,7 +6,7 @@ import {asColorLike} from '../../colorlike.js';
import {intersects} from '../../extent.js';
import {matchingChunk} from '../../geom/flat/straightchunk.js';
import GeometryType from '../../geom/GeometryType.js';
import {pruneLabelCache, defaultTextAlign, defaultPadding, defaultLineCap, defaultLineDashOffset, defaultLineDash, defaultLineJoin, defaultFillStyle, checkFont, defaultFont, defaultLineWidth, defaultMiterLimit, defaultStrokeStyle, defaultTextBaseline} from '../canvas.js';
import {labelCache, defaultTextAlign, defaultPadding, defaultLineCap, defaultLineDashOffset, defaultLineDash, defaultLineJoin, defaultFillStyle, checkFont, defaultFont, defaultLineWidth, defaultMiterLimit, defaultStrokeStyle, defaultTextBaseline} from '../canvas.js';
import CanvasInstruction from './Instruction.js';
import CanvasBuilder from './Builder.js';
import TextPlacement from '../../style/TextPlacement.js';
@@ -131,7 +131,7 @@ class CanvasTextBuilder extends CanvasBuilder {
*/
this.strokeKey_ = '';
pruneLabelCache();
labelCache.prune();
}
/**