No empty declutter instructions, but with individual box

This commit is contained in:
Andreas Hocevar
2020-06-08 22:43:38 +02:00
parent ff980077ee
commit 686c665c71
2 changed files with 119 additions and 104 deletions

View File

@@ -7,7 +7,6 @@ import ImageBuilder from './ImageBuilder.js';
import LineStringBuilder from './LineStringBuilder.js'; import LineStringBuilder from './LineStringBuilder.js';
import PolygonBuilder from './PolygonBuilder.js'; import PolygonBuilder from './PolygonBuilder.js';
import TextBuilder from './TextBuilder.js'; import TextBuilder from './TextBuilder.js';
import {createEmpty} from '../../extent.js';
/** /**
* @type {Object<import("./BuilderType").default, typeof Builder>} * @type {Object<import("./BuilderType").default, typeof Builder>}
@@ -78,15 +77,15 @@ class BuilderGroup {
* @return {import("../canvas").DeclutterGroups} The resulting instruction groups. * @return {import("../canvas").DeclutterGroups} The resulting instruction groups.
*/ */
addDeclutter(group) { addDeclutter(group) {
/** @type {Array<*>} */
let declutter = null; let declutter = null;
if (this.declutter_) { if (this.declutter_) {
if (group) { if (group) {
declutter = this.declutterGroups_; declutter = this.declutterGroups_;
/** @type {number} */ (declutter[0][4])++; /** @type {number} */ (declutter[0][0])++;
} else { } else {
declutter = [createEmpty()]; declutter = [[1]];
this.declutterGroups_ = declutter; this.declutterGroups_ = declutter;
declutter[0].push(1);
} }
} }
return declutter; return declutter;

View File

@@ -14,8 +14,8 @@ import {
import { import {
createEmpty, createEmpty,
createOrUpdate, createOrUpdate,
createOrUpdateEmpty, getHeight,
extend, getWidth,
intersects, intersects,
} from '../../extent.js'; } from '../../extent.js';
import { import {
@@ -323,6 +323,7 @@ class Executor {
* @param {Array<number>} padding Padding. * @param {Array<number>} padding Padding.
* @param {Array<*>} fillInstruction Fill instruction. * @param {Array<*>} fillInstruction Fill instruction.
* @param {Array<*>} strokeInstruction Stroke instruction. * @param {Array<*>} strokeInstruction Stroke instruction.
* @return {boolean} The image or label was rendered.
*/ */
replayImageOrLabel_( replayImageOrLabel_(
context, context,
@@ -431,10 +432,9 @@ class Executor {
} }
if (declutterGroup) { if (declutterGroup) {
if (!intersects && declutterGroup[4] == 1) { if (!intersects && declutterGroup[0] == 1) {
return; return false;
} }
extend(declutterGroup, tmpExtent);
const declutterArgs = intersects const declutterArgs = intersects
? [ ? [
context, context,
@@ -448,6 +448,7 @@ class Executor {
x, x,
y, y,
scale, scale,
tmpExtent.slice(),
] ]
: null; : null;
if (declutterArgs) { if (declutterArgs) {
@@ -490,6 +491,7 @@ class Executor {
scale scale
); );
} }
return true;
} }
/** /**
@@ -535,51 +537,57 @@ class Executor {
* @return {?} Declutter tree. * @return {?} Declutter tree.
*/ */
renderDeclutter(declutterGroup, feature, opacity, declutterTree) { renderDeclutter(declutterGroup, feature, opacity, declutterTree) {
if (declutterGroup && declutterGroup.length > 5) { /** @type {Array<import("../../structs/RBush.js").Entry>} */
const groupCount = declutterGroup[4]; const boxes = [];
if (groupCount == 1 || groupCount == declutterGroup.length - 5) { for (let i = 1, ii = declutterGroup.length; i < ii; ++i) {
/** @type {import("../../structs/RBush.js").Entry} */ const declutterData = declutterGroup[i];
const box = { const box = declutterData[11];
minX: /** @type {number} */ (declutterGroup[0]), boxes.push({
minY: /** @type {number} */ (declutterGroup[1]), minX: box[0],
maxX: /** @type {number} */ (declutterGroup[2]), minY: box[1],
maxY: /** @type {number} */ (declutterGroup[3]), maxX: box[2],
value: feature, maxY: box[3],
}; value: feature,
if (!declutterTree) { });
declutterTree = new RBush(9); }
} if (!declutterTree) {
if (!declutterTree.collides(box)) { declutterTree = new RBush(9);
declutterTree.insert(box); }
for (let j = 5, jj = declutterGroup.length; j < jj; ++j) { let collides = false;
const declutterData = /** @type {Array} */ (declutterGroup[j]); for (let i = 0, ii = boxes.length; i < ii; ++i) {
const context = declutterData[0]; if (declutterTree.collides(boxes[i])) {
const currentAlpha = context.globalAlpha; collides = true;
if (currentAlpha !== opacity) { break;
context.globalAlpha = opacity;
}
if (declutterData.length > 11) {
this.replayTextBackground_(
declutterData[0],
declutterData[13],
declutterData[14],
declutterData[15],
declutterData[16],
declutterData[11],
declutterData[12],
true
);
}
drawImageOrLabel.apply(undefined, declutterData);
if (currentAlpha !== opacity) {
context.globalAlpha = currentAlpha;
}
}
}
declutterGroup.length = 5;
createOrUpdateEmpty(declutterGroup);
} }
} }
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; return declutterTree;
} }
@@ -847,13 +855,11 @@ class Executor {
if (declutterGroups) { if (declutterGroups) {
const index = Math.floor(declutterGroupIndex); const index = Math.floor(declutterGroupIndex);
if (declutterGroups.length < index + 1) { if (declutterGroups.length < index + 1) {
declutterGroup = createEmpty(); declutterGroup = [declutterGroups[0][0], declutterGroups[0][1]];
declutterGroup.push(declutterGroups[0][4]);
declutterGroups.push(declutterGroup);
} }
declutterGroup = declutterGroups[index]; declutterGroup = declutterGroups[index];
} }
this.replayImageOrLabel_( const rendered = this.replayImageOrLabel_(
context, context,
contextScale, contextScale,
pixelCoordinates[d], pixelCoordinates[d],
@@ -878,12 +884,17 @@ class Executor {
? /** @type {Array<*>} */ (lastStrokeInstruction) ? /** @type {Array<*>} */ (lastStrokeInstruction)
: null : null
); );
if (declutterGroup) { if (
if (declutterGroupIndex === Math.floor(declutterGroupIndex)) { rendered &&
this.declutterItems.push(this, declutterGroup, feature); declutterGroup &&
} declutterGroups[declutterGroups.length] !== declutterGroup
declutterGroupIndex += 1 / declutterGroup[4]; ) {
declutterGroups.push(declutterGroup);
} }
if (declutterGroup.length - 1 === declutterGroup[0]) {
this.declutterItems.push(this, declutterGroup, feature);
}
declutterGroupIndex += 1 / declutterGroup[0];
} }
++i; ++i;
break; break;
@@ -935,6 +946,7 @@ class Executor {
cachedWidths cachedWidths
); );
if (parts) { if (parts) {
let rendered = false;
let c, cc, chars, label, part; let c, cc, chars, label, part;
if (strokeKey) { if (strokeKey) {
for (c = 0, cc = parts.length; c < cc; ++c) { for (c = 0, cc = parts.length; c < cc; ++c) {
@@ -946,27 +958,28 @@ class Executor {
baseline * label.height + baseline * label.height +
(0.5 - baseline) * 2 * strokeWidth - (0.5 - baseline) * 2 * strokeWidth -
offsetY; offsetY;
this.replayImageOrLabel_( rendered =
context, this.replayImageOrLabel_(
contextScale, context,
/** @type {number} */ (part[0]), contextScale,
/** @type {number} */ (part[1]), /** @type {number} */ (part[0]),
label, /** @type {number} */ (part[1]),
anchorX, label,
anchorY, anchorX,
declutterGroup, anchorY,
label.height, declutterGroup,
1, label.height,
0, 1,
0, 0,
/** @type {number} */ (part[3]), 0,
pixelRatioScale, /** @type {number} */ (part[3]),
false, pixelRatioScale,
label.width, false,
defaultPadding, label.width,
null, defaultPadding,
null null,
); null
) || rendered;
} }
} }
if (fillKey) { if (fillKey) {
@@ -976,32 +989,35 @@ class Executor {
label = this.createLabel(chars, textKey, fillKey, ''); label = this.createLabel(chars, textKey, fillKey, '');
anchorX = /** @type {number} */ (part[2]); anchorX = /** @type {number} */ (part[2]);
anchorY = baseline * label.height - offsetY; anchorY = baseline * label.height - offsetY;
this.replayImageOrLabel_( rendered =
context, this.replayImageOrLabel_(
contextScale, context,
/** @type {number} */ (part[0]), contextScale,
/** @type {number} */ (part[1]), /** @type {number} */ (part[0]),
label, /** @type {number} */ (part[1]),
anchorX, label,
anchorY, anchorX,
declutterGroup, anchorY,
label.height, declutterGroup,
1, label.height,
0, 1,
0, 0,
/** @type {number} */ (part[3]), 0,
pixelRatioScale, /** @type {number} */ (part[3]),
false, pixelRatioScale,
label.width, false,
defaultPadding, label.width,
null, defaultPadding,
null null,
); null
) || rendered;
} }
} }
if (rendered) {
this.declutterItems.push(this, declutterGroup, feature);
}
} }
} }
this.declutterItems.push(this, declutterGroup, feature);
++i; ++i;
break; break;
case CanvasInstruction.END_GEOMETRY: case CanvasInstruction.END_GEOMETRY: