Smarter opacity handling

This commit is contained in:
ahocevar
2019-05-22 15:39:21 +02:00
parent ae47d3df58
commit ace5c65ee5
7 changed files with 39 additions and 19 deletions
+8 -1
View File
@@ -39,7 +39,7 @@ import {create as createTransform, apply as applyTransform} from './transform.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 * @property {Array<DeclutterItems>} declutterItems
* @property {import("./coordinate.js").Coordinate} focus * @property {import("./coordinate.js").Coordinate} focus
* @property {number} index * @property {number} index
* @property {Array<import("./layer/Layer.js").State>} layerStatesArray * @property {Array<import("./layer/Layer.js").State>} layerStatesArray
@@ -54,6 +54,13 @@ import {create as createTransform, apply as applyTransform} from './transform.js
*/ */
/**
* @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
*/ */
+3 -2
View File
@@ -122,9 +122,10 @@ export function renderDeclutterItems(frameState, declutterTree) {
} }
const items = frameState.declutterItems; const items = frameState.declutterItems;
for (let z = items.length - 1; z >= 0; --z) { for (let z = items.length - 1; z >= 0; --z) {
const zIndexItems = items[z]; const item = items[z];
const zIndexItems = item.items;
for (let i = 0, ii = zIndexItems.length; i < ii; i += 3) { for (let i = 0, ii = zIndexItems.length; i < ii; i += 3) {
declutterTree = zIndexItems[i].renderDeclutter(zIndexItems[i + 1], zIndexItems[i + 2], declutterTree); declutterTree = zIndexItems[i].renderDeclutter(zIndexItems[i + 1], zIndexItems[i + 2], item.opacity, declutterTree);
} }
} }
items.length = 0; items.length = 0;
+15 -8
View File
@@ -416,10 +416,11 @@ class Executor extends Disposable {
/** /**
* @param {import("../canvas.js").DeclutterGroup} declutterGroup Declutter group. * @param {import("../canvas.js").DeclutterGroup} declutterGroup Declutter group.
* @param {import("../../Feature.js").FeatureLike} feature Feature. * @param {import("../../Feature.js").FeatureLike} feature Feature.
* @param {number} opacity Layer opacity.
* @param {?} declutterTree Declutter tree. * @param {?} declutterTree Declutter tree.
* @return {?} Declutter tree. * @return {?} Declutter tree.
*/ */
renderDeclutter(declutterGroup, feature, declutterTree) { renderDeclutter(declutterGroup, feature, opacity, declutterTree) {
if (declutterGroup && declutterGroup.length > 5) { if (declutterGroup && declutterGroup.length > 5) {
const groupCount = declutterGroup[4]; const groupCount = declutterGroup[4];
if (groupCount == 1 || groupCount == declutterGroup.length - 5) { if (groupCount == 1 || groupCount == declutterGroup.length - 5) {
@@ -438,13 +439,19 @@ class Executor extends Disposable {
declutterTree.insert(box); declutterTree.insert(box);
for (let j = 5, jj = declutterGroup.length; j < jj; ++j) { for (let j = 5, jj = declutterGroup.length; j < jj; ++j) {
const declutterData = /** @type {Array} */ (declutterGroup[j]); const declutterData = /** @type {Array} */ (declutterGroup[j]);
if (declutterData) { const context = declutterData[0];
if (declutterData.length > 11) { const currentAlpha = context.globalAlpha;
this.replayTextBackground_(declutterData[0], if (currentAlpha !== opacity) {
declutterData[13], declutterData[14], declutterData[15], declutterData[16], context.globalAlpha = opacity;
declutterData[11], declutterData[12]); }
} if (declutterData.length > 11) {
drawImage.apply(undefined, declutterData); this.replayTextBackground_(declutterData[0],
declutterData[13], declutterData[14], declutterData[15], declutterData[16],
declutterData[11], declutterData[12]);
}
drawImage.apply(undefined, declutterData);
if (currentAlpha !== opacity) {
context.globalAlpha = currentAlpha;
} }
} }
} }
+7 -3
View File
@@ -430,10 +430,11 @@ export function getCircleArray(radius) {
* @param {!Object<string, Array<*>>} declutterReplays Declutter replays. * @param {!Object<string, Array<*>>} declutterReplays Declutter replays.
* @param {CanvasRenderingContext2D} context Context. * @param {CanvasRenderingContext2D} context Context.
* @param {number} rotation Rotation. * @param {number} rotation Rotation.
* @param {number} opacity Opacity.
* @param {boolean} snapToPixel Snap point symbols and text to integer pixels. * @param {boolean} snapToPixel Snap point symbols and text to integer pixels.
* @param {Array<Array<*>>} declutterItems Declutter items. * @param {Array<import("../../PluggableMap.js").DeclutterItems>} declutterItems Declutter items.
*/ */
export function replayDeclutter(declutterReplays, context, rotation, snapToPixel, declutterItems) { export function replayDeclutter(declutterReplays, context, rotation, opacity, snapToPixel, declutterItems) {
const zs = Object.keys(declutterReplays).map(Number).sort(numberSafeCompareFunction); const zs = Object.keys(declutterReplays).map(Number).sort(numberSafeCompareFunction);
const skippedFeatureUids = {}; const skippedFeatureUids = {};
for (let z = 0, zz = zs.length; z < zz; ++z) { for (let z = 0, zz = zs.length; z < zz; ++z) {
@@ -443,7 +444,10 @@ export function replayDeclutter(declutterReplays, context, rotation, snapToPixel
const executor = executorData[i++]; const executor = executorData[i++];
if (executor !== currentExecutor) { if (executor !== currentExecutor) {
currentExecutor = executor; currentExecutor = executor;
declutterItems.push(executor.declutterItems); declutterItems.push({
items: executor.declutterItems,
opacity: opacity
});
} }
const transform = executorData[i++]; const transform = executorData[i++];
executor.execute(context, transform, rotation, skippedFeatureUids, snapToPixel); executor.execute(context, transform, rotation, skippedFeatureUids, snapToPixel);
+1 -1
View File
@@ -79,7 +79,7 @@ class CanvasLayerRenderer extends LayerRenderer {
useContainer(target, transform, opacity) { useContainer(target, transform, opacity) {
const layerClassName = this.getLayer().getClassName(); const layerClassName = this.getLayer().getClassName();
let container, context; let container, context;
if (target) { if (target && target.style.opacity === '') {
const canvas = target.firstElementChild; const canvas = target.firstElementChild;
if (canvas instanceof HTMLCanvasElement) { if (canvas instanceof HTMLCanvasElement) {
context = canvas.getContext('2d'); context = canvas.getContext('2d');
+4 -3
View File
@@ -164,7 +164,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
if (declutterReplays) { if (declutterReplays) {
const viewHints = frameState.viewHints; const viewHints = frameState.viewHints;
const hifi = !(viewHints[ViewHint.ANIMATING] || viewHints[ViewHint.INTERACTING]); const hifi = !(viewHints[ViewHint.ANIMATING] || viewHints[ViewHint.INTERACTING]);
replayDeclutter(declutterReplays, context, rotation, hifi, frameState.declutterItems); replayDeclutter(declutterReplays, context, rotation, 1, hifi, frameState.declutterItems);
} }
if (clipped) { if (clipped) {
@@ -174,8 +174,9 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
this.postRender(context, frameState); this.postRender(context, frameState);
const opacity = layerState.opacity; const opacity = layerState.opacity;
if (opacity !== parseFloat(canvas.style.opacity)) { const container = this.container;
canvas.style.opacity = opacity; if (opacity !== parseFloat(container.style.opacity)) {
container.style.opacity = opacity === 1 ? '' : opacity;
} }
return this.container; return this.container;
+1 -1
View File
@@ -478,7 +478,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
} }
} }
if (declutterReplays) { if (declutterReplays) {
replayDeclutter(declutterReplays, context, rotation, hifi, frameState.declutterItems); replayDeclutter(declutterReplays, context, rotation, layerState.opacity, hifi, frameState.declutterItems);
} }
return this.container; return this.container;