Remove decluttering for a fresh start

This commit is contained in:
Andreas Hocevar
2020-09-18 23:31:20 +02:00
parent 740e11f1fa
commit 7a5e0db59f
18 changed files with 108 additions and 551 deletions

View File

@@ -6,7 +6,6 @@ import stringify from 'json-stringify-safe';
import styleFunction from 'ol-mapbox-style/dist/stylefunction.js'; import styleFunction from 'ol-mapbox-style/dist/stylefunction.js';
import {Projection} from '../src/ol/proj.js'; import {Projection} from '../src/ol/proj.js';
import {inView} from '../src/ol/layer/Layer.js'; import {inView} from '../src/ol/layer/Layer.js';
import {renderDeclutterItems} from '../src/ol/render.js';
import {getTilePriority as tilePriorityFunction} from '../src/ol/TileQueue.js'; import {getTilePriority as tilePriorityFunction} from '../src/ol/TileQueue.js';
/** @type {any} */ /** @type {any} */
@@ -145,7 +144,6 @@ worker.addEventListener('message', (event) => {
renderer.renderFrame(frameState, canvas); renderer.renderFrame(frameState, canvas);
} }
}); });
renderDeclutterItems(frameState, null);
if (tileQueue.getTilesLoading() < maxTotalLoading) { if (tileQueue.getTilesLoading() < maxTotalLoading) {
tileQueue.reprioritize(); tileQueue.reprioritize();
tileQueue.loadMoreTiles(maxTotalLoading, maxNewLoads); tileQueue.loadMoreTiles(maxTotalLoading, maxNewLoads);

View File

@@ -51,7 +51,6 @@ import {removeNode} from './dom.js';
* @property {boolean} animate * @property {boolean} animate
* @property {import("./transform.js").Transform} coordinateToPixelTransform * @property {import("./transform.js").Transform} coordinateToPixelTransform
* @property {null|import("./extent.js").Extent} extent * @property {null|import("./extent.js").Extent} extent
* @property {Array<DeclutterItems>} declutterItems
* @property {number} index * @property {number} index
* @property {Array<import("./layer/Layer.js").State>} layerStatesArray * @property {Array<import("./layer/Layer.js").State>} layerStatesArray
* @property {number} layerIndex * @property {number} layerIndex
@@ -64,12 +63,6 @@ import {removeNode} from './dom.js';
* @property {!Object<string, Object<string, boolean>>} wantedTiles * @property {!Object<string, Object<string, boolean>>} wantedTiles
*/ */
/**
* @typedef {Object} DeclutterItems
* @property {Array<*>} items Declutter items of an executor.
* @property {number} opacity Layer opacity.
*/
/** /**
* @typedef {function(PluggableMap, ?FrameState): any} PostRenderFunction * @typedef {function(PluggableMap, ?FrameState): any} PostRenderFunction
*/ */
@@ -1379,9 +1372,6 @@ class PluggableMap extends BaseObject {
frameState = { frameState = {
animate: false, animate: false,
coordinateToPixelTransform: this.coordinateToPixelTransform_, coordinateToPixelTransform: this.coordinateToPixelTransform_,
declutterItems: previousFrameState
? previousFrameState.declutterItems
: [],
extent: getForViewAndSize( extent: getForViewAndSize(
viewState.center, viewState.center,
viewState.resolution, viewState.resolution,

View File

@@ -129,29 +129,3 @@ export function getRenderPixel(event, pixel) {
applyTransform(event.inversePixelTransform.slice(), result); applyTransform(event.inversePixelTransform.slice(), result);
return result; return result;
} }
/**
* @param {import("./PluggableMap.js").FrameState} frameState Frame state.
* @param {?} declutterTree Declutter tree.
* @returns {?} Declutter tree.
*/
export function renderDeclutterItems(frameState, declutterTree) {
if (declutterTree) {
declutterTree.clear();
}
const items = frameState.declutterItems;
for (let z = items.length - 1; z >= 0; --z) {
const item = items[z];
const zIndexItems = item.items;
for (let i = 0, ii = zIndexItems.length; i < ii; i += 3) {
declutterTree = zIndexItems[i].renderDeclutter(
zIndexItems[i + 1],
zIndexItems[i + 2],
item.opacity,
declutterTree
);
}
}
items.length = 0;
return declutterTree;
}

View File

@@ -100,15 +100,13 @@ class VectorContext {
/** /**
* @param {import("../style/Image.js").default} imageStyle Image style. * @param {import("../style/Image.js").default} imageStyle Image style.
* @param {import("./canvas.js").DeclutterGroup=} opt_declutterGroup Declutter.
*/ */
setImageStyle(imageStyle, opt_declutterGroup) {} setImageStyle(imageStyle) {}
/** /**
* @param {import("../style/Text.js").default} textStyle Text style. * @param {import("../style/Text.js").default} textStyle Text style.
* @param {import("./canvas.js").DeclutterGroups=} opt_declutterGroups Declutter.
*/ */
setTextStyle(textStyle, opt_declutterGroups) {} setTextStyle(textStyle) {}
} }
export default VectorContext; export default VectorContext;

View File

@@ -67,23 +67,6 @@ import {toString} from '../transform.js';
* @property {Array<number>} [padding] * @property {Array<number>} [padding]
*/ */
/**
* Container for decluttered replay instructions that need to be rendered or
* omitted together, i.e. when styles render both an image and text, or for the
* characters that form text along lines. The basic elements of this array are
* `[minX, minY, maxX, maxY, count]`, where the first four entries are the
* rendered extent of the group in pixel space. `count` is the number of styles
* in the group, i.e. 2 when an image and a text are grouped, or 1 otherwise.
* In addition to these four elements, declutter instruction arrays (i.e. the
* arguments to {@link module:ol/render/canvas~drawImage} are appended to the array.
* @typedef {Array<*>} DeclutterGroup
*/
/**
* Declutter groups for support of multi geometries.
* @typedef {Array<DeclutterGroup>} DeclutterGroups
*/
/** /**
* @const * @const
* @type {string} * @type {string}

View File

@@ -26,21 +26,8 @@ class BuilderGroup {
* @param {import("../../extent.js").Extent} maxExtent Max extent. * @param {import("../../extent.js").Extent} maxExtent Max extent.
* @param {number} resolution Resolution. * @param {number} resolution Resolution.
* @param {number} pixelRatio Pixel ratio. * @param {number} pixelRatio Pixel ratio.
* @param {boolean} declutter Decluttering enabled.
*/ */
constructor(tolerance, maxExtent, resolution, pixelRatio, declutter) { constructor(tolerance, maxExtent, resolution, pixelRatio) {
/**
* @type {boolean}
* @private
*/
this.declutter_ = declutter;
/**
* @type {import("../canvas.js").DeclutterGroups}
* @private
*/
this.declutterGroups_ = null;
/** /**
* @private * @private
* @type {number} * @type {number}
@@ -72,25 +59,6 @@ class BuilderGroup {
this.buildersByZIndex_ = {}; this.buildersByZIndex_ = {};
} }
/**
* @param {boolean} group Group with previous builder.
* @return {import("../canvas").DeclutterGroups} The resulting instruction groups.
*/
addDeclutter(group) {
/** @type {Array<*>} */
let declutter = null;
if (this.declutter_) {
if (group) {
declutter = this.declutterGroups_;
/** @type {number} */ (declutter[0][0])++;
} else {
declutter = [[1]];
this.declutterGroups_ = declutter;
}
}
return declutter;
}
/** /**
* @return {!Object<string, !Object<import("./BuilderType").default, import("./Builder.js").SerializableInstructions>>} The serializable instructions * @return {!Object<string, !Object<import("./BuilderType").default, import("./Builder.js").SerializableInstructions>>} The serializable instructions
*/ */

View File

@@ -2,7 +2,6 @@
* @module ol/render/canvas/Executor * @module ol/render/canvas/Executor
*/ */
import CanvasInstruction from './Instruction.js'; import CanvasInstruction from './Instruction.js';
import RBush from 'rbush';
import {TEXT_ALIGN} from './TextBuilder.js'; import {TEXT_ALIGN} from './TextBuilder.js';
import {WORKER_OFFSCREEN_CANVAS} from '../../has.js'; import {WORKER_OFFSCREEN_CANVAS} from '../../has.js';
import { import {
@@ -11,13 +10,7 @@ import {
create as createTransform, create as createTransform,
setFromArray as transformSetFromArray, setFromArray as transformSetFromArray,
} from '../../transform.js'; } from '../../transform.js';
import { import {createEmpty, createOrUpdate, intersects} from '../../extent.js';
createEmpty,
createOrUpdate,
getHeight,
getWidth,
intersects,
} from '../../extent.js';
import { import {
defaultPadding, defaultPadding,
defaultTextBaseline, defaultTextBaseline,
@@ -97,11 +90,6 @@ class Executor {
*/ */
this.alignFill_; this.alignFill_;
/**
* @type {Array<*>}
*/
this.declutterItems = [];
/** /**
* @protected * @protected
* @type {Array<*>} * @type {Array<*>}
@@ -274,7 +262,6 @@ class Executor {
* @param {import("../../coordinate.js").Coordinate} p4 4th point of the background box. * @param {import("../../coordinate.js").Coordinate} p4 4th point of the background box.
* @param {Array<*>} fillInstruction Fill instruction. * @param {Array<*>} fillInstruction Fill instruction.
* @param {Array<*>} strokeInstruction Stroke instruction. * @param {Array<*>} strokeInstruction Stroke instruction.
* @param {boolean} declutter Declutter.
*/ */
replayTextBackground_( replayTextBackground_(
context, context,
@@ -283,8 +270,7 @@ class Executor {
p3, p3,
p4, p4,
fillInstruction, fillInstruction,
strokeInstruction, strokeInstruction
declutter
) { ) {
context.beginPath(); context.beginPath();
context.moveTo.apply(context, p1); context.moveTo.apply(context, p1);
@@ -294,9 +280,6 @@ class Executor {
context.lineTo.apply(context, p1); context.lineTo.apply(context, p1);
if (fillInstruction) { if (fillInstruction) {
this.alignFill_ = /** @type {boolean} */ (fillInstruction[2]); this.alignFill_ = /** @type {boolean} */ (fillInstruction[2]);
if (declutter) {
context.fillStyle = /** @type {import("../../colorlike.js").ColorLike} */ (fillInstruction[1]);
}
this.fill_(context); this.fill_(context);
} }
if (strokeInstruction) { if (strokeInstruction) {
@@ -317,7 +300,6 @@ class Executor {
* @param {import("../canvas.js").Label|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} imageOrLabel Image. * @param {import("../canvas.js").Label|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} imageOrLabel Image.
* @param {number} anchorX Anchor X. * @param {number} anchorX Anchor X.
* @param {number} anchorY Anchor Y. * @param {number} anchorY Anchor Y.
* @param {import("../canvas.js").DeclutterGroup} declutterGroup Declutter group.
* @param {number} height Height. * @param {number} height Height.
* @param {number} opacity Opacity. * @param {number} opacity Opacity.
* @param {number} originX Origin X. * @param {number} originX Origin X.
@@ -339,7 +321,6 @@ class Executor {
imageOrLabel, imageOrLabel,
anchorX, anchorX,
anchorY, anchorY,
declutterGroup,
height, height,
opacity, opacity,
originX, originX,
@@ -417,15 +398,8 @@ class Executor {
tmpExtent tmpExtent
); );
} }
let renderBufferX = 0; const renderBufferX = 0; // increase this.renderBuffer_ for decluttering
let renderBufferY = 0; const renderBufferY = 0; // increase this.renderBuffer_ for decluttering
if (declutterGroup) {
const renderBuffer = this.renderBuffer_;
renderBuffer[0] = Math.max(renderBuffer[0], getWidth(tmpExtent));
renderBufferX = renderBuffer[0];
renderBuffer[1] = Math.max(renderBuffer[1], getHeight(tmpExtent));
renderBufferY = renderBuffer[1];
}
const canvas = context.canvas; const canvas = context.canvas;
const strokePadding = strokeInstruction const strokePadding = strokeInstruction
? (strokeInstruction[2] * scale[0]) / 2 ? (strokeInstruction[2] * scale[0]) / 2
@@ -443,40 +417,7 @@ class Executor {
y = Math.round(y); y = Math.round(y);
} }
if (declutterGroup) { if (intersects) {
if (!intersects && declutterGroup[0] == 1) {
return false;
}
const declutterArgs = intersects
? [
context,
transform ? transform.slice(0) : null,
opacity,
imageOrLabel,
originX,
originY,
w,
h,
x,
y,
scale,
tmpExtent.slice(),
]
: null;
if (declutterArgs) {
if (fillStroke) {
declutterArgs.push(
fillInstruction,
strokeInstruction,
p1.slice(0),
p2.slice(0),
p3.slice(0),
p4.slice(0)
);
}
declutterGroup.push(declutterArgs);
}
} else if (intersects) {
if (fillStroke) { if (fillStroke) {
this.replayTextBackground_( this.replayTextBackground_(
context, context,
@@ -485,8 +426,7 @@ class Executor {
p3, p3,
p4, p4,
/** @type {Array<*>} */ (fillInstruction), /** @type {Array<*>} */ (fillInstruction),
/** @type {Array<*>} */ (strokeInstruction), /** @type {Array<*>} */ (strokeInstruction)
false
); );
} }
drawImageOrLabel( drawImageOrLabel(
@@ -541,68 +481,6 @@ class Executor {
} }
} }
/**
* @param {import("../canvas.js").DeclutterGroup} declutterGroup Declutter group.
* @param {import("../../Feature.js").FeatureLike} feature Feature.
* @param {number} opacity Layer opacity.
* @param {?} declutterTree Declutter tree.
* @return {?} Declutter tree.
*/
renderDeclutter(declutterGroup, feature, opacity, declutterTree) {
/** @type {Array<import("../../structs/RBush.js").Entry>} */
const boxes = [];
for (let i = 1, ii = declutterGroup.length; i < ii; ++i) {
const declutterData = declutterGroup[i];
const box = declutterData[11];
boxes.push({
minX: box[0],
minY: box[1],
maxX: box[2],
maxY: box[3],
value: feature,
});
}
if (!declutterTree) {
declutterTree = new RBush(9);
}
let collides = false;
for (let i = 0, ii = boxes.length; i < ii; ++i) {
if (declutterTree.collides(boxes[i])) {
collides = true;
break;
}
}
if (!collides) {
declutterTree.load(boxes);
for (let j = 1, jj = declutterGroup.length; j < jj; ++j) {
const declutterData = /** @type {Array} */ (declutterGroup[j]);
const context = declutterData[0];
const currentAlpha = context.globalAlpha;
if (currentAlpha !== opacity) {
context.globalAlpha = opacity;
}
if (declutterData.length > 12) {
this.replayTextBackground_(
declutterData[0],
declutterData[14],
declutterData[15],
declutterData[16],
declutterData[17],
declutterData[12],
declutterData[13],
true
);
}
drawImageOrLabel.apply(undefined, declutterData);
if (currentAlpha !== opacity) {
context.globalAlpha = currentAlpha;
}
}
}
declutterGroup.length = 1;
return declutterTree;
}
/** /**
* @private * @private
* @param {string} text The text to draw. * @param {string} text The text to draw.
@@ -659,7 +537,6 @@ class Executor {
featureCallback, featureCallback,
opt_hitExtent opt_hitExtent
) { ) {
this.declutterItems.length = 0;
/** @type {Array<number>} */ /** @type {Array<number>} */
let pixelCoordinates; let pixelCoordinates;
if (this.pixelCoordinates_ && equals(transform, this.renderedTransform_)) { if (this.pixelCoordinates_ && equals(transform, this.renderedTransform_)) {
@@ -682,17 +559,7 @@ class Executor {
const ii = instructions.length; // end of instructions const ii = instructions.length; // end of instructions
let d = 0; // data index let d = 0; // data index
let dd; // end of per-instruction data let dd; // end of per-instruction data
let anchorX, let anchorX, anchorY, prevX, prevY, roundX, roundY, image, text, textKey;
anchorY,
prevX,
prevY,
roundX,
roundY,
declutterGroup,
declutterGroups,
image,
text,
textKey;
let strokeKey, fillKey; let strokeKey, fillKey;
let pendingFill = 0; let pendingFill = 0;
let pendingStroke = 0; let pendingStroke = 0;
@@ -796,22 +663,21 @@ class Executor {
// Remaining arguments in DRAW_IMAGE are in alphabetical order // Remaining arguments in DRAW_IMAGE are in alphabetical order
anchorX = /** @type {number} */ (instruction[4]); anchorX = /** @type {number} */ (instruction[4]);
anchorY = /** @type {number} */ (instruction[5]); anchorY = /** @type {number} */ (instruction[5]);
declutterGroups = featureCallback ? null : instruction[6]; let height = /** @type {number} */ (instruction[6]);
let height = /** @type {number} */ (instruction[7]); const opacity = /** @type {number} */ (instruction[7]);
const opacity = /** @type {number} */ (instruction[8]); const originX = /** @type {number} */ (instruction[8]);
const originX = /** @type {number} */ (instruction[9]); const originY = /** @type {number} */ (instruction[9]);
const originY = /** @type {number} */ (instruction[10]); const rotateWithView = /** @type {boolean} */ (instruction[10]);
const rotateWithView = /** @type {boolean} */ (instruction[11]); let rotation = /** @type {number} */ (instruction[11]);
let rotation = /** @type {number} */ (instruction[12]); const scale = /** @type {import("../../size.js").Size} */ (instruction[12]);
const scale = /** @type {import("../../size.js").Size} */ (instruction[13]); let width = /** @type {number} */ (instruction[13]);
let width = /** @type {number} */ (instruction[14]);
if (!image && instruction.length >= 19) { if (!image && instruction.length >= 18) {
// create label images // create label images
text = /** @type {string} */ (instruction[18]); text = /** @type {string} */ (instruction[17]);
textKey = /** @type {string} */ (instruction[19]); textKey = /** @type {string} */ (instruction[18]);
strokeKey = /** @type {string} */ (instruction[20]); strokeKey = /** @type {string} */ (instruction[19]);
fillKey = /** @type {string} */ (instruction[21]); fillKey = /** @type {string} */ (instruction[20]);
const labelWithAnchor = this.drawLabelWithPointPlacement_( const labelWithAnchor = this.drawLabelWithPointPlacement_(
text, text,
textKey, textKey,
@@ -820,28 +686,28 @@ class Executor {
); );
image = labelWithAnchor.label; image = labelWithAnchor.label;
instruction[3] = image; instruction[3] = image;
const textOffsetX = /** @type {number} */ (instruction[22]); const textOffsetX = /** @type {number} */ (instruction[21]);
anchorX = (labelWithAnchor.anchorX - textOffsetX) * this.pixelRatio; anchorX = (labelWithAnchor.anchorX - textOffsetX) * this.pixelRatio;
instruction[4] = anchorX; instruction[4] = anchorX;
const textOffsetY = /** @type {number} */ (instruction[23]); const textOffsetY = /** @type {number} */ (instruction[22]);
anchorY = (labelWithAnchor.anchorY - textOffsetY) * this.pixelRatio; anchorY = (labelWithAnchor.anchorY - textOffsetY) * this.pixelRatio;
instruction[5] = anchorY; instruction[5] = anchorY;
height = image.height; height = image.height;
instruction[7] = height; instruction[6] = height;
width = image.width; width = image.width;
instruction[14] = width; instruction[13] = width;
} }
let geometryWidths; let geometryWidths;
if (instruction.length > 24) { if (instruction.length > 23) {
geometryWidths = /** @type {number} */ (instruction[24]); geometryWidths = /** @type {number} */ (instruction[23]);
} }
let padding, backgroundFill, backgroundStroke; let padding, backgroundFill, backgroundStroke;
if (instruction.length > 16) { if (instruction.length > 15) {
padding = /** @type {Array<number>} */ (instruction[15]); padding = /** @type {Array<number>} */ (instruction[14]);
backgroundFill = /** @type {boolean} */ (instruction[16]); backgroundFill = /** @type {boolean} */ (instruction[15]);
backgroundStroke = /** @type {boolean} */ (instruction[17]); backgroundStroke = /** @type {boolean} */ (instruction[16]);
} else { } else {
padding = defaultPadding; padding = defaultPadding;
backgroundFill = false; backgroundFill = false;
@@ -856,7 +722,6 @@ class Executor {
rotation -= viewRotation; rotation -= viewRotation;
} }
let widthIndex = 0; let widthIndex = 0;
let declutterGroupIndex = 0;
for (; d < dd; d += 2) { for (; d < dd; d += 2) {
if ( if (
geometryWidths && geometryWidths &&
@@ -864,14 +729,7 @@ class Executor {
) { ) {
continue; continue;
} }
if (declutterGroups) { this.replayImageOrLabel_(
const index = Math.floor(declutterGroupIndex);
declutterGroup =
declutterGroups.length < index + 1
? [declutterGroups[0][0]]
: declutterGroups[index];
}
const rendered = this.replayImageOrLabel_(
context, context,
contextScale, contextScale,
pixelCoordinates[d], pixelCoordinates[d],
@@ -879,7 +737,6 @@ class Executor {
image, image,
anchorX, anchorX,
anchorY, anchorY,
declutterGroup,
height, height,
opacity, opacity,
originX, originX,
@@ -896,19 +753,6 @@ class Executor {
? /** @type {Array<*>} */ (lastStrokeInstruction) ? /** @type {Array<*>} */ (lastStrokeInstruction)
: null : null
); );
if (
rendered &&
declutterGroup &&
declutterGroups[declutterGroups.length - 1] !== declutterGroup
) {
declutterGroups.push(declutterGroup);
}
if (declutterGroup) {
if (declutterGroup.length - 1 === declutterGroup[0]) {
this.declutterItems.push(this, declutterGroup, feature);
}
declutterGroupIndex += 1 / declutterGroup[0];
}
} }
++i; ++i;
break; break;
@@ -916,19 +760,18 @@ class Executor {
const begin = /** @type {number} */ (instruction[1]); const begin = /** @type {number} */ (instruction[1]);
const end = /** @type {number} */ (instruction[2]); const end = /** @type {number} */ (instruction[2]);
const baseline = /** @type {number} */ (instruction[3]); const baseline = /** @type {number} */ (instruction[3]);
declutterGroup = featureCallback ? null : instruction[4]; const overflow = /** @type {number} */ (instruction[4]);
const overflow = /** @type {number} */ (instruction[5]); fillKey = /** @type {string} */ (instruction[5]);
fillKey = /** @type {string} */ (instruction[6]); const maxAngle = /** @type {number} */ (instruction[6]);
const maxAngle = /** @type {number} */ (instruction[7]); const measurePixelRatio = /** @type {number} */ (instruction[7]);
const measurePixelRatio = /** @type {number} */ (instruction[8]); const offsetY = /** @type {number} */ (instruction[8]);
const offsetY = /** @type {number} */ (instruction[9]); strokeKey = /** @type {string} */ (instruction[9]);
strokeKey = /** @type {string} */ (instruction[10]); const strokeWidth = /** @type {number} */ (instruction[10]);
const strokeWidth = /** @type {number} */ (instruction[11]); text = /** @type {string} */ (instruction[11]);
text = /** @type {string} */ (instruction[12]); textKey = /** @type {string} */ (instruction[12]);
textKey = /** @type {string} */ (instruction[13]);
const pixelRatioScale = [ const pixelRatioScale = [
/** @type {number} */ (instruction[14]), /** @type {number} */ (instruction[13]),
/** @type {number} */ (instruction[14]), /** @type {number} */ (instruction[13]),
]; ];
const textState = this.textStates[textKey]; const textState = this.textStates[textKey];
@@ -990,7 +833,6 @@ class Executor {
label, label,
anchorX, anchorX,
anchorY, anchorY,
declutterGroup,
label.height, label.height,
1, 1,
0, 0,
@@ -1021,7 +863,6 @@ class Executor {
label, label,
anchorX, anchorX,
anchorY, anchorY,
declutterGroup,
label.height, label.height,
1, 1,
0, 0,
@@ -1036,9 +877,6 @@ class Executor {
) || rendered; ) || rendered;
} }
} }
if (rendered) {
this.declutterItems.push(this, declutterGroup, feature);
}
} }
} }
++i; ++i;

View File

@@ -162,7 +162,6 @@ class ExecutorGroup {
* @param {number} rotation Rotation. * @param {number} rotation Rotation.
* @param {number} hitTolerance Hit tolerance in pixels. * @param {number} hitTolerance Hit tolerance in pixels.
* @param {function(import("../../Feature.js").FeatureLike): T} callback Feature callback. * @param {function(import("../../Feature.js").FeatureLike): T} callback Feature callback.
* @param {Array<import("../../Feature.js").FeatureLike>} declutteredFeatures Decluttered features.
* @return {T|undefined} Callback result. * @return {T|undefined} Callback result.
* @template T * @template T
*/ */
@@ -171,8 +170,7 @@ class ExecutorGroup {
resolution, resolution,
rotation, rotation,
hitTolerance, hitTolerance,
callback, callback
declutteredFeatures
) { ) {
hitTolerance = Math.round(hitTolerance); hitTolerance = Math.round(hitTolerance);
const contextSize = hitTolerance * 2 + 1; const contextSize = hitTolerance * 2 + 1;
@@ -234,17 +232,7 @@ class ExecutorGroup {
for (let j = 0; j < contextSize; j++) { for (let j = 0; j < contextSize; j++) {
if (mask[i][j]) { if (mask[i][j]) {
if (imageData[(j * contextSize + i) * 4 + 3] > 0) { if (imageData[(j * contextSize + i) * 4 + 3] > 0) {
let result; const result = callback(feature);
if (
!(
declutteredFeatures &&
(builderType == BuilderType.IMAGE ||
builderType == BuilderType.TEXT)
) ||
declutteredFeatures.indexOf(feature) !== -1
) {
result = callback(feature);
}
if (result) { if (result) {
return result; return result;
} else { } else {
@@ -318,7 +306,6 @@ class ExecutorGroup {
* @param {boolean} snapToPixel Snap point symbols and test to integer pixel. * @param {boolean} snapToPixel Snap point symbols and test to integer pixel.
* @param {Array<import("./BuilderType.js").default>=} opt_builderTypes Ordered replay types to replay. * @param {Array<import("./BuilderType.js").default>=} opt_builderTypes Ordered replay types to replay.
* Default is {@link module:ol/render/replay~ORDER} * Default is {@link module:ol/render/replay~ORDER}
* @param {Object<string, import("../canvas.js").DeclutterGroup>=} opt_declutterReplays Declutter replays.
*/ */
execute( execute(
context, context,
@@ -326,8 +313,7 @@ class ExecutorGroup {
transform, transform,
viewRotation, viewRotation,
snapToPixel, snapToPixel,
opt_builderTypes, opt_builderTypes
opt_declutterReplays
) { ) {
/** @type {Array<number>} */ /** @type {Array<number>} */
const zs = Object.keys(this.executorsByZIndex_).map(Number); const zs = Object.keys(this.executorsByZIndex_).map(Number);
@@ -349,26 +335,13 @@ class ExecutorGroup {
const builderType = builderTypes[j]; const builderType = builderTypes[j];
replay = replays[builderType]; replay = replays[builderType];
if (replay !== undefined) { if (replay !== undefined) {
if ( replay.execute(
opt_declutterReplays && context,
(builderType == BuilderType.IMAGE || contextScale,
builderType == BuilderType.TEXT) transform,
) { viewRotation,
const declutter = opt_declutterReplays[zIndexKey]; snapToPixel
if (!declutter) { );
opt_declutterReplays[zIndexKey] = [replay, transform.slice(0)];
} else {
declutter.push(replay, transform.slice(0));
}
} else {
replay.execute(
context,
contextScale,
transform,
viewRotation,
snapToPixel
);
}
} }
} }
} }
@@ -454,41 +427,4 @@ export function getCircleArray(radius) {
return arr; return arr;
} }
/**
* @param {!Object<string, Array<*>>} declutterReplays Declutter replays.
* @param {CanvasRenderingContext2D} context Context.
* @param {number} rotation Rotation.
* @param {number} opacity Opacity.
* @param {boolean} snapToPixel Snap point symbols and text to integer pixels.
* @param {Array<import("../../PluggableMap.js").DeclutterItems>} declutterItems Declutter items.
*/
export function replayDeclutter(
declutterReplays,
context,
rotation,
opacity,
snapToPixel,
declutterItems
) {
const zs = Object.keys(declutterReplays)
.map(Number)
.sort(numberSafeCompareFunction);
for (let z = 0, zz = zs.length; z < zz; ++z) {
const executorData = declutterReplays[zs[z].toString()];
let currentExecutor;
for (let i = 0, ii = executorData.length; i < ii; ) {
const executor = executorData[i++];
const transform = executorData[i++];
executor.execute(context, 1, transform, rotation, snapToPixel);
if (executor !== currentExecutor && executor.declutterItems.length > 0) {
currentExecutor = executor;
declutterItems.push({
items: executor.declutterItems,
opacity: opacity,
});
}
}
}
}
export default ExecutorGroup; export default ExecutorGroup;

View File

@@ -14,12 +14,6 @@ class CanvasImageBuilder extends CanvasBuilder {
constructor(tolerance, maxExtent, resolution, pixelRatio) { constructor(tolerance, maxExtent, resolution, pixelRatio) {
super(tolerance, maxExtent, resolution, pixelRatio); super(tolerance, maxExtent, resolution, pixelRatio);
/**
* @private
* @type {import("../canvas.js").DeclutterGroups}
*/
this.declutterGroups_ = null;
/** /**
* @private * @private
* @type {HTMLCanvasElement|HTMLVideoElement|HTMLImageElement} * @type {HTMLCanvasElement|HTMLVideoElement|HTMLImageElement}
@@ -120,7 +114,6 @@ class CanvasImageBuilder extends CanvasBuilder {
// Remaining arguments to DRAW_IMAGE are in alphabetical order // Remaining arguments to DRAW_IMAGE are in alphabetical order
this.anchorX_ * this.imagePixelRatio_, this.anchorX_ * this.imagePixelRatio_,
this.anchorY_ * this.imagePixelRatio_, this.anchorY_ * this.imagePixelRatio_,
this.declutterGroups_,
Math.ceil(this.height_ * this.imagePixelRatio_), Math.ceil(this.height_ * this.imagePixelRatio_),
this.opacity_, this.opacity_,
this.originX_, this.originX_,
@@ -141,7 +134,6 @@ class CanvasImageBuilder extends CanvasBuilder {
// Remaining arguments to DRAW_IMAGE are in alphabetical order // Remaining arguments to DRAW_IMAGE are in alphabetical order
this.anchorX_, this.anchorX_,
this.anchorY_, this.anchorY_,
this.declutterGroups_,
this.height_, this.height_,
this.opacity_, this.opacity_,
this.originX_, this.originX_,
@@ -175,7 +167,6 @@ class CanvasImageBuilder extends CanvasBuilder {
// Remaining arguments to DRAW_IMAGE are in alphabetical order // Remaining arguments to DRAW_IMAGE are in alphabetical order
this.anchorX_ * this.imagePixelRatio_, this.anchorX_ * this.imagePixelRatio_,
this.anchorY_ * this.imagePixelRatio_, this.anchorY_ * this.imagePixelRatio_,
this.declutterGroups_,
Math.ceil(this.height_ * this.imagePixelRatio_), Math.ceil(this.height_ * this.imagePixelRatio_),
this.opacity_, this.opacity_,
this.originX_, this.originX_,
@@ -196,7 +187,6 @@ class CanvasImageBuilder extends CanvasBuilder {
// Remaining arguments to DRAW_IMAGE are in alphabetical order // Remaining arguments to DRAW_IMAGE are in alphabetical order
this.anchorX_, this.anchorX_,
this.anchorY_, this.anchorY_,
this.declutterGroups_,
this.height_, this.height_,
this.opacity_, this.opacity_,
this.originX_, this.originX_,
@@ -233,9 +223,8 @@ class CanvasImageBuilder extends CanvasBuilder {
/** /**
* @param {import("../../style/Image.js").default} imageStyle Image style. * @param {import("../../style/Image.js").default} imageStyle Image style.
* @param {import("../canvas.js").DeclutterGroup} declutterGroups Declutter.
*/ */
setImageStyle(imageStyle, declutterGroups) { setImageStyle(imageStyle) {
const anchor = imageStyle.getAnchor(); const anchor = imageStyle.getAnchor();
const size = imageStyle.getSize(); const size = imageStyle.getSize();
const hitDetectionImage = imageStyle.getHitDetectionImage(); const hitDetectionImage = imageStyle.getHitDetectionImage();
@@ -244,7 +233,6 @@ class CanvasImageBuilder extends CanvasBuilder {
this.imagePixelRatio_ = imageStyle.getPixelRatio(this.pixelRatio); this.imagePixelRatio_ = imageStyle.getPixelRatio(this.pixelRatio);
this.anchorX_ = anchor[0]; this.anchorX_ = anchor[0];
this.anchorY_ = anchor[1]; this.anchorY_ = anchor[1];
this.declutterGroups_ = declutterGroups;
this.hitDetectionImage_ = hitDetectionImage; this.hitDetectionImage_ = hitDetectionImage;
this.image_ = image; this.image_ = image;
this.height_ = size[1]; this.height_ = size[1];

View File

@@ -52,12 +52,6 @@ class CanvasTextBuilder extends CanvasBuilder {
constructor(tolerance, maxExtent, resolution, pixelRatio) { constructor(tolerance, maxExtent, resolution, pixelRatio) {
super(tolerance, maxExtent, resolution, pixelRatio); super(tolerance, maxExtent, resolution, pixelRatio);
/**
* @private
* @type {import("../canvas.js").DeclutterGroups}
*/
this.declutterGroups_;
/** /**
* @private * @private
* @type {Array<HTMLCanvasElement>} * @type {Array<HTMLCanvasElement>}
@@ -226,12 +220,7 @@ class CanvasTextBuilder extends CanvasBuilder {
} }
const end = coordinates.length; const end = coordinates.length;
flatOffset = ends[o]; flatOffset = ends[o];
const declutterGroup = this.declutterGroups_ this.drawChars_(begin, end);
? o === 0
? this.declutterGroups_[0]
: [].concat(this.declutterGroups_[0])
: null;
this.drawChars_(begin, end, declutterGroup);
begin = end; begin = end;
} }
this.endGeometry(feature); this.endGeometry(feature);
@@ -331,7 +320,6 @@ class CanvasTextBuilder extends CanvasBuilder {
null, null,
NaN, NaN,
NaN, NaN,
this.declutterGroups_,
NaN, NaN,
1, 1,
0, 0,
@@ -363,7 +351,6 @@ class CanvasTextBuilder extends CanvasBuilder {
null, null,
NaN, NaN,
NaN, NaN,
this.declutterGroups_,
NaN, NaN,
1, 1,
0, 0,
@@ -433,9 +420,8 @@ class CanvasTextBuilder extends CanvasBuilder {
* @private * @private
* @param {number} begin Begin. * @param {number} begin Begin.
* @param {number} end End. * @param {number} end End.
* @param {import("../canvas.js").DeclutterGroup} declutterGroup Declutter group.
*/ */
drawChars_(begin, end, declutterGroup) { drawChars_(begin, end) {
const strokeState = this.textStrokeState_; const strokeState = this.textStrokeState_;
const textState = this.textState_; const textState = this.textState_;
@@ -458,7 +444,6 @@ class CanvasTextBuilder extends CanvasBuilder {
begin, begin,
end, end,
baseline, baseline,
declutterGroup,
textState.overflow, textState.overflow,
fillKey, fillKey,
textState.maxAngle, textState.maxAngle,
@@ -475,7 +460,6 @@ class CanvasTextBuilder extends CanvasBuilder {
begin, begin,
end, end,
baseline, baseline,
declutterGroup,
textState.overflow, textState.overflow,
fillKey, fillKey,
textState.maxAngle, textState.maxAngle,
@@ -491,15 +475,12 @@ class CanvasTextBuilder extends CanvasBuilder {
/** /**
* @param {import("../../style/Text.js").default} textStyle Text style. * @param {import("../../style/Text.js").default} textStyle Text style.
* @param {import("../canvas.js").DeclutterGroups} declutterGroups Declutter.
*/ */
setTextStyle(textStyle, declutterGroups) { setTextStyle(textStyle) {
let textState, fillState, strokeState; let textState, fillState, strokeState;
if (!textStyle) { if (!textStyle) {
this.text_ = ''; this.text_ = '';
} else { } else {
this.declutterGroups_ = declutterGroups;
const textFillStyle = textStyle.getFill(); const textFillStyle = textStyle.getFill();
if (!textFillStyle) { if (!textFillStyle) {
fillState = null; fillState = null;

View File

@@ -101,17 +101,10 @@ class LayerRenderer extends Observable {
* @param {import("../PluggableMap.js").FrameState} frameState Frame state. * @param {import("../PluggableMap.js").FrameState} frameState Frame state.
* @param {number} hitTolerance Hit tolerance in pixels. * @param {number} hitTolerance Hit tolerance in pixels.
* @param {function(import("../Feature.js").FeatureLike, import("../layer/Layer.js").default): T} callback Feature callback. * @param {function(import("../Feature.js").FeatureLike, import("../layer/Layer.js").default): T} callback Feature callback.
* @param {Array<import("../Feature.js").FeatureLike>} declutteredFeatures Decluttered features.
* @return {T|void} Callback result. * @return {T|void} Callback result.
* @template T * @template T
*/ */
forEachFeatureAtCoordinate( forEachFeatureAtCoordinate(coordinate, frameState, hitTolerance, callback) {}
coordinate,
frameState,
hitTolerance,
callback,
declutteredFeatures
) {}
/** /**
* @abstract * @abstract

View File

@@ -8,7 +8,6 @@ import {compose as composeTransform, makeInverse} from '../transform.js';
import {getWidth} from '../extent.js'; import {getWidth} from '../extent.js';
import {shared as iconImageCache} from '../style/IconImageCache.js'; import {shared as iconImageCache} from '../style/IconImageCache.js';
import {inView} from '../layer/Layer.js'; import {inView} from '../layer/Layer.js';
import {renderDeclutterItems} from '../render.js';
import {wrapX} from '../coordinate.js'; import {wrapX} from '../coordinate.js';
/** /**
@@ -26,11 +25,6 @@ class MapRenderer extends Disposable {
* @type {import("../PluggableMap.js").default} * @type {import("../PluggableMap.js").default}
*/ */
this.map_ = map; this.map_ = map;
/**
* @private
*/
this.declutterTree_ = null;
} }
/** /**
@@ -116,12 +110,6 @@ class MapRenderer extends Disposable {
const layerStates = frameState.layerStatesArray; const layerStates = frameState.layerStatesArray;
const numLayers = layerStates.length; const numLayers = layerStates.length;
let declutteredFeatures;
if (this.declutterTree_) {
declutteredFeatures = this.declutterTree_.all().map(function (entry) {
return entry.value;
});
}
const tmpCoord = []; const tmpCoord = [];
for (let i = 0; i < offsets.length; i++) { for (let i = 0; i < offsets.length; i++) {
@@ -149,8 +137,7 @@ class MapRenderer extends Disposable {
tmpCoord, tmpCoord,
frameState, frameState,
hitTolerance, hitTolerance,
callback, callback
declutteredFeatures
); );
} }
if (result) { if (result) {
@@ -226,9 +213,7 @@ class MapRenderer extends Disposable {
* Render. * Render.
* @param {?import("../PluggableMap.js").FrameState} frameState Frame state. * @param {?import("../PluggableMap.js").FrameState} frameState Frame state.
*/ */
renderFrame(frameState) { renderFrame(frameState) {}
this.declutterTree_ = renderDeclutterItems(frameState, this.declutterTree_);
}
/** /**
* @param {import("../PluggableMap.js").FrameState} frameState Frame state. * @param {import("../PluggableMap.js").FrameState} frameState Frame state.

View File

@@ -10,7 +10,6 @@ import ViewHint from '../../ViewHint.js';
import {apply, compose, create} from '../../transform.js'; import {apply, compose, create} from '../../transform.js';
import {assign} from '../../obj.js'; import {assign} from '../../obj.js';
import {getHeight, getWidth, isEmpty, scaleFromCenter} from '../../extent.js'; import {getHeight, getWidth, isEmpty, scaleFromCenter} from '../../extent.js';
import {renderDeclutterItems} from '../../render.js';
/** /**
* @classdesc * @classdesc
@@ -115,7 +114,6 @@ class CanvasVectorImageLayerRenderer extends CanvasImageLayerRenderer {
{}, {},
frameState, frameState,
{ {
declutterItems: [],
extent: renderedExtent, extent: renderedExtent,
size: [width, height], size: [width, height],
viewState: /** @type {import("../../View.js").State} */ (assign( viewState: /** @type {import("../../View.js").State} */ (assign(
@@ -139,7 +137,6 @@ class CanvasVectorImageLayerRenderer extends CanvasImageLayerRenderer {
) { ) {
vectorRenderer.clipping = false; vectorRenderer.clipping = false;
vectorRenderer.renderFrame(imageFrameState, null); vectorRenderer.renderFrame(imageFrameState, null);
renderDeclutterItems(imageFrameState, null);
callback(); callback();
} }
} }
@@ -191,32 +188,23 @@ class CanvasVectorImageLayerRenderer extends CanvasImageLayerRenderer {
* @param {import("../../PluggableMap.js").FrameState} frameState Frame state. * @param {import("../../PluggableMap.js").FrameState} frameState Frame state.
* @param {number} hitTolerance Hit tolerance in pixels. * @param {number} hitTolerance Hit tolerance in pixels.
* @param {function(import("../../Feature.js").FeatureLike, import("../../layer/Layer.js").default): T} callback Feature callback. * @param {function(import("../../Feature.js").FeatureLike, import("../../layer/Layer.js").default): T} callback Feature callback.
* @param {Array<import("../../Feature.js").FeatureLike>} declutteredFeatures Decluttered features.
* @return {T|void} Callback result. * @return {T|void} Callback result.
* @template T * @template T
*/ */
forEachFeatureAtCoordinate( forEachFeatureAtCoordinate(coordinate, frameState, hitTolerance, callback) {
coordinate,
frameState,
hitTolerance,
callback,
declutteredFeatures
) {
if (this.vectorRenderer_) { if (this.vectorRenderer_) {
return this.vectorRenderer_.forEachFeatureAtCoordinate( return this.vectorRenderer_.forEachFeatureAtCoordinate(
coordinate, coordinate,
frameState, frameState,
hitTolerance, hitTolerance,
callback, callback
declutteredFeatures
); );
} else { } else {
return super.forEachFeatureAtCoordinate( return super.forEachFeatureAtCoordinate(
coordinate, coordinate,
frameState, frameState,
hitTolerance, hitTolerance,
callback, callback
declutteredFeatures
); );
} }
} }

View File

@@ -3,9 +3,7 @@
*/ */
import CanvasBuilderGroup from '../../render/canvas/BuilderGroup.js'; import CanvasBuilderGroup from '../../render/canvas/BuilderGroup.js';
import CanvasLayerRenderer from './Layer.js'; import CanvasLayerRenderer from './Layer.js';
import ExecutorGroup, { import ExecutorGroup from '../../render/canvas/ExecutorGroup.js';
replayDeclutter,
} from '../../render/canvas/ExecutorGroup.js';
import ViewHint from '../../ViewHint.js'; import ViewHint from '../../ViewHint.js';
import { import {
apply, apply,
@@ -219,8 +217,6 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
viewHints[ViewHint.ANIMATING] || viewHints[ViewHint.INTERACTING] viewHints[ViewHint.ANIMATING] || viewHints[ViewHint.INTERACTING]
); );
const declutterReplays = this.getLayer().getDeclutter() ? {} : null;
const multiWorld = vectorSource.getWrapX() && projection.canWrapX(); const multiWorld = vectorSource.getWrapX() && projection.canWrapX();
const worldWidth = multiWorld ? getWidth(projectionExtent) : null; const worldWidth = multiWorld ? getWidth(projectionExtent) : null;
const endWorld = multiWorld const endWorld = multiWorld
@@ -245,26 +241,10 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
transform, transform,
rotation, rotation,
snapToPixel, snapToPixel,
undefined, undefined
declutterReplays
); );
} while (++world < endWorld); } while (++world < endWorld);
if (declutterReplays) {
const viewHints = frameState.viewHints;
const hifi = !(
viewHints[ViewHint.ANIMATING] || viewHints[ViewHint.INTERACTING]
);
replayDeclutter(
declutterReplays,
context,
rotation,
1,
hifi,
frameState.declutterItems
);
}
if (clipped) { if (clipped) {
context.restore(); context.restore();
} }
@@ -388,17 +368,10 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
* @param {import("../../PluggableMap.js").FrameState} frameState Frame state. * @param {import("../../PluggableMap.js").FrameState} frameState Frame state.
* @param {number} hitTolerance Hit tolerance in pixels. * @param {number} hitTolerance Hit tolerance in pixels.
* @param {function(import("../../Feature.js").FeatureLike, import("../../layer/Layer.js").default): T} callback Feature callback. * @param {function(import("../../Feature.js").FeatureLike, import("../../layer/Layer.js").default): T} callback Feature callback.
* @param {Array<import("../../Feature.js").FeatureLike>} declutteredFeatures Decluttered features.
* @return {T|void} Callback result. * @return {T|void} Callback result.
* @template T * @template T
*/ */
forEachFeatureAtCoordinate( forEachFeatureAtCoordinate(coordinate, frameState, hitTolerance, callback) {
coordinate,
frameState,
hitTolerance,
callback,
declutteredFeatures
) {
if (!this.replayGroup_) { if (!this.replayGroup_) {
return undefined; return undefined;
} else { } else {
@@ -423,8 +396,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
features[key] = true; features[key] = true;
return callback(feature, layer); return callback(feature, layer);
} }
}, }
layer.getDeclutter() ? declutteredFeatures : null
); );
return result; return result;
@@ -556,8 +528,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
getRenderTolerance(resolution, pixelRatio), getRenderTolerance(resolution, pixelRatio),
extent, extent,
resolution, resolution,
pixelRatio, pixelRatio
vectorLayer.getDeclutter()
); );
const userProjection = getUserProjection(); const userProjection = getUserProjection();

View File

@@ -2,9 +2,7 @@
* @module ol/renderer/canvas/VectorTileLayer * @module ol/renderer/canvas/VectorTileLayer
*/ */
import CanvasBuilderGroup from '../../render/canvas/BuilderGroup.js'; import CanvasBuilderGroup from '../../render/canvas/BuilderGroup.js';
import CanvasExecutorGroup, { import CanvasExecutorGroup from '../../render/canvas/ExecutorGroup.js';
replayDeclutter,
} from '../../render/canvas/ExecutorGroup.js';
import CanvasTileLayerRenderer from './TileLayer.js'; import CanvasTileLayerRenderer from './TileLayer.js';
import EventType from '../../events/EventType.js'; import EventType from '../../events/EventType.js';
import ReplayType from '../../render/canvas/BuilderType.js'; import ReplayType from '../../render/canvas/BuilderType.js';
@@ -292,8 +290,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
0, 0,
sharedExtent, sharedExtent,
resolution, resolution,
pixelRatio, pixelRatio
layer.getDeclutter()
); );
const squaredTolerance = getSquaredRenderTolerance( const squaredTolerance = getSquaredRenderTolerance(
resolution, resolution,
@@ -365,17 +362,10 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
* @param {import("../../PluggableMap.js").FrameState} frameState Frame state. * @param {import("../../PluggableMap.js").FrameState} frameState Frame state.
* @param {number} hitTolerance Hit tolerance in pixels. * @param {number} hitTolerance Hit tolerance in pixels.
* @param {function(import("../../Feature.js").FeatureLike, import("../../layer/Layer.js").default): T} callback Feature callback. * @param {function(import("../../Feature.js").FeatureLike, import("../../layer/Layer.js").default): T} callback Feature callback.
* @param {Array<import("../../Feature.js").FeatureLike>} declutteredFeatures Decluttered features.
* @return {T|void} Callback result. * @return {T|void} Callback result.
* @template T * @template T
*/ */
forEachFeatureAtCoordinate( forEachFeatureAtCoordinate(coordinate, frameState, hitTolerance, callback) {
coordinate,
frameState,
hitTolerance,
callback,
declutteredFeatures
) {
const resolution = frameState.viewState.resolution; const resolution = frameState.viewState.resolution;
const rotation = frameState.viewState.rotation; const rotation = frameState.viewState.rotation;
hitTolerance = hitTolerance == undefined ? 0 : hitTolerance; hitTolerance = hitTolerance == undefined ? 0 : hitTolerance;
@@ -420,11 +410,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
* @return {?} Callback result. * @return {?} Callback result.
*/ */
function (feature) { function (feature) {
if ( if (tileContainsCoordinate) {
tileContainsCoordinate ||
(declutteredFeatures &&
declutteredFeatures.indexOf(feature) !== -1)
) {
let key = feature.getId(); let key = feature.getId();
if (key === undefined) { if (key === undefined) {
key = getUid(feature); key = getUid(feature);
@@ -434,8 +420,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
return callback(feature, layer); return callback(feature, layer);
} }
} }
}, }
layer.getDeclutter() ? declutteredFeatures : null
); );
} }
} }
@@ -587,7 +572,6 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
} }
const context = this.context; const context = this.context;
const declutterReplays = layer.getDeclutter() ? {} : null;
const replayTypes = VECTOR_REPLAYS[renderMode]; const replayTypes = VECTOR_REPLAYS[renderMode];
const pixelRatio = frameState.pixelRatio; const pixelRatio = frameState.pixelRatio;
const viewState = frameState.viewState; const viewState = frameState.viewState;
@@ -640,27 +624,29 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
} }
const currentZ = tile.tileCoord[0]; const currentZ = tile.tileCoord[0];
let currentClip; let currentClip;
if (!declutterReplays && !clipped) { if (!clipped) {
currentClip = executorGroup.getClipCoords(transform); currentClip = executorGroup.getClipCoords(transform);
context.save(); if (currentClip) {
context.save();
// Create a clip mask for regions in this low resolution tile that are // Create a clip mask for regions in this low resolution tile that are
// already filled by a higher resolution tile // already filled by a higher resolution tile
for (let j = 0, jj = clips.length; j < jj; ++j) { for (let j = 0, jj = clips.length; j < jj; ++j) {
const clip = clips[j]; const clip = clips[j];
if (currentZ < clipZs[j]) { if (currentZ < clipZs[j]) {
context.beginPath(); context.beginPath();
// counter-clockwise (outer ring) for current tile // counter-clockwise (outer ring) for current tile
context.moveTo(currentClip[0], currentClip[1]); context.moveTo(currentClip[0], currentClip[1]);
context.lineTo(currentClip[2], currentClip[3]); context.lineTo(currentClip[2], currentClip[3]);
context.lineTo(currentClip[4], currentClip[5]); context.lineTo(currentClip[4], currentClip[5]);
context.lineTo(currentClip[6], currentClip[7]); context.lineTo(currentClip[6], currentClip[7]);
// clockwise (inner ring) for higher resolution tile // clockwise (inner ring) for higher resolution tile
context.moveTo(clip[6], clip[7]); context.moveTo(clip[6], clip[7]);
context.lineTo(clip[4], clip[5]); context.lineTo(clip[4], clip[5]);
context.lineTo(clip[2], clip[3]); context.lineTo(clip[2], clip[3]);
context.lineTo(clip[0], clip[1]); context.lineTo(clip[0], clip[1]);
context.clip(); context.clip();
}
} }
} }
} }
@@ -670,10 +656,9 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
transform, transform,
rotation, rotation,
hifi, hifi,
replayTypes, replayTypes
declutterReplays
); );
if (!declutterReplays && !clipped) { if (!clipped && currentClip) {
context.restore(); context.restore();
clips.push(currentClip); clips.push(currentClip);
clipZs.push(currentZ); clipZs.push(currentZ);
@@ -681,17 +666,6 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
} }
} }
} }
if (declutterReplays) {
const layerState = frameState.layerStatesArray[frameState.layerIndex];
replayDeclutter(
declutterReplays,
context,
rotation,
layerState.opacity,
hifi,
frameState.declutterItems
);
}
return this.container; return this.container;
} }

View File

@@ -80,7 +80,7 @@ function renderCircleGeometry(builderGroup, geometry, style, feature) {
style.getZIndex(), style.getZIndex(),
BuilderType.TEXT BuilderType.TEXT
); );
textReplay.setTextStyle(textStyle, builderGroup.addDeclutter(false)); textReplay.setTextStyle(textStyle);
textReplay.drawText(geometry, feature); textReplay.drawText(geometry, feature);
} }
} }
@@ -224,7 +224,7 @@ function renderLineStringGeometry(builderGroup, geometry, style, feature) {
style.getZIndex(), style.getZIndex(),
BuilderType.TEXT BuilderType.TEXT
); );
textReplay.setTextStyle(textStyle, builderGroup.addDeclutter(false)); textReplay.setTextStyle(textStyle);
textReplay.drawText(geometry, feature); textReplay.drawText(geometry, feature);
} }
} }
@@ -251,7 +251,7 @@ function renderMultiLineStringGeometry(builderGroup, geometry, style, feature) {
style.getZIndex(), style.getZIndex(),
BuilderType.TEXT BuilderType.TEXT
); );
textReplay.setTextStyle(textStyle, builderGroup.addDeclutter(false)); textReplay.setTextStyle(textStyle);
textReplay.drawText(geometry, feature); textReplay.drawText(geometry, feature);
} }
} }
@@ -279,7 +279,7 @@ function renderMultiPolygonGeometry(builderGroup, geometry, style, feature) {
style.getZIndex(), style.getZIndex(),
BuilderType.TEXT BuilderType.TEXT
); );
textReplay.setTextStyle(textStyle, builderGroup.addDeclutter(false)); textReplay.setTextStyle(textStyle);
textReplay.drawText(geometry, feature); textReplay.drawText(geometry, feature);
} }
} }
@@ -300,7 +300,7 @@ function renderPointGeometry(builderGroup, geometry, style, feature) {
style.getZIndex(), style.getZIndex(),
BuilderType.IMAGE BuilderType.IMAGE
); );
imageReplay.setImageStyle(imageStyle, builderGroup.addDeclutter(false)); imageReplay.setImageStyle(imageStyle);
imageReplay.drawPoint(geometry, feature); imageReplay.drawPoint(geometry, feature);
} }
const textStyle = style.getText(); const textStyle = style.getText();
@@ -309,7 +309,7 @@ function renderPointGeometry(builderGroup, geometry, style, feature) {
style.getZIndex(), style.getZIndex(),
BuilderType.TEXT BuilderType.TEXT
); );
textReplay.setTextStyle(textStyle, builderGroup.addDeclutter(!!imageStyle)); textReplay.setTextStyle(textStyle);
textReplay.drawText(geometry, feature); textReplay.drawText(geometry, feature);
} }
} }
@@ -330,7 +330,7 @@ function renderMultiPointGeometry(builderGroup, geometry, style, feature) {
style.getZIndex(), style.getZIndex(),
BuilderType.IMAGE BuilderType.IMAGE
); );
imageReplay.setImageStyle(imageStyle, builderGroup.addDeclutter(false)); imageReplay.setImageStyle(imageStyle);
imageReplay.drawMultiPoint(geometry, feature); imageReplay.drawMultiPoint(geometry, feature);
} }
const textStyle = style.getText(); const textStyle = style.getText();
@@ -339,7 +339,7 @@ function renderMultiPointGeometry(builderGroup, geometry, style, feature) {
style.getZIndex(), style.getZIndex(),
BuilderType.TEXT BuilderType.TEXT
); );
textReplay.setTextStyle(textStyle, builderGroup.addDeclutter(!!imageStyle)); textReplay.setTextStyle(textStyle);
textReplay.drawText(geometry, feature); textReplay.drawText(geometry, feature);
} }
} }
@@ -367,7 +367,7 @@ function renderPolygonGeometry(builderGroup, geometry, style, feature) {
style.getZIndex(), style.getZIndex(),
BuilderType.TEXT BuilderType.TEXT
); );
textReplay.setTextStyle(textStyle, builderGroup.addDeclutter(false)); textReplay.setTextStyle(textStyle);
textReplay.drawText(geometry, feature); textReplay.drawText(geometry, feature);
} }
} }

View File

@@ -598,17 +598,10 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
* @param {import("../../PluggableMap.js").FrameState} frameState Frame state. * @param {import("../../PluggableMap.js").FrameState} frameState Frame state.
* @param {number} hitTolerance Hit tolerance in pixels. * @param {number} hitTolerance Hit tolerance in pixels.
* @param {function(import("../../Feature.js").FeatureLike, import("../../layer/Layer.js").default): T} callback Feature callback. * @param {function(import("../../Feature.js").FeatureLike, import("../../layer/Layer.js").default): T} callback Feature callback.
* @param {Array<import("../../Feature.js").FeatureLike>} declutteredFeatures Decluttered features.
* @return {T|void} Callback result. * @return {T|void} Callback result.
* @template T * @template T
*/ */
forEachFeatureAtCoordinate( forEachFeatureAtCoordinate(coordinate, frameState, hitTolerance, callback) {
coordinate,
frameState,
hitTolerance,
callback,
declutteredFeatures
) {
assert(this.hitDetectionEnabled_, 66); assert(this.hitDetectionEnabled_, 66);
if (!this.hitRenderInstructions_) { if (!this.hitRenderInstructions_) {
return; return;

View File

@@ -565,7 +565,6 @@ class RasterSource extends ImageSource {
}), }),
viewHints: [], viewHints: [],
wantedTiles: {}, wantedTiles: {},
declutterItems: [],
}; };
this.setAttributions(function (frameState) { this.setAttributions(function (frameState) {