From 1fd62f7602b5c1bffeac40da100edfd10c05fdc1 Mon Sep 17 00:00:00 2001 From: hu de yi Date: Fri, 29 Nov 2024 17:13:28 +0800 Subject: [PATCH] some tweak for text render performance (#2454) * some tweak for text render performance * consider text style is dynamic * updates --- src/core/Canvas.ts | 14 +++++++---- src/core/util/strings.ts | 6 +++-- src/renderer/geometry/Painter.ts | 15 ++++++++---- .../symbolizers/TextMarkerSymbolizer.ts | 23 ++++++++++++------- 4 files changed, 39 insertions(+), 19 deletions(-) diff --git a/src/core/Canvas.ts b/src/core/Canvas.ts index a8e1bf9da4..8140392ce8 100644 --- a/src/core/Canvas.ts +++ b/src/core/Canvas.ts @@ -18,6 +18,7 @@ import Extent from '../geo/Extent'; import Size from '../geo/Size'; import CollisionIndex from './CollisionIndex'; import LRUCache from './util/LRUCache'; +import { TextSymbol } from '../symbol'; const charTextureLRUCache = new LRUCache(50000); function getCharTexture(tempCtx: Ctx, style, char: string) { @@ -535,19 +536,19 @@ const Canvas = { return canvas; }, - prepareCanvasFont(ctx: Ctx, style) { + prepareCanvasFont(ctx: Ctx, style: TextSymbol, font?: string) { if (ctx.textBaseline !== TEXT_BASELINE) { ctx.textBaseline = TEXT_BASELINE; } - const font = getFont(style); + font = font || getFont(style); if (ctx.font !== font) { ctx.font = font; } - let fill = style['textFill']; + let fill = style['textFill'] as string; if (!fill) { fill = DEFAULT_TEXT_COLOR; } - const fillStyle = Canvas.getRgba(fill, style['textOpacity']); + const fillStyle = Canvas.getRgba(fill, style['textOpacity'] as number); if (ctx.fillStyle !== fillStyle) { ctx.fillStyle = fillStyle; } @@ -774,10 +775,13 @@ const Canvas = { // support #RRGGBB/#RGB now. // if color was like [red, orange...]/rgb(a)/hsl(a), op will not combined to result - getRgba(color: any, op: number) { + getRgba(color: string, op: number) { if (isNil(op)) { op = 1; } + if (color[0] === '#' && op === 1) { + return color; + } if (color[0] !== '#') { if (Array.isArray(color)) { color = Canvas.normalizeColorToRGBA(color, op); diff --git a/src/core/util/strings.ts b/src/core/util/strings.ts index 0723b6e12b..b6a935f48f 100644 --- a/src/core/util/strings.ts +++ b/src/core/util/strings.ts @@ -177,7 +177,10 @@ export function replaceVariable(str: string, props: Object) { if (!isString(str)) { return str; } - + const [left, right] = TEMPLATE_CHARS; + if (str.indexOf(left) === -1 && str.indexOf(right) === -1) { + return str; + } function getValue(key) { if (!props) { return EMPTY_STRING; @@ -190,7 +193,6 @@ export function replaceVariable(str: string, props: Object) { } return value; } - const [left, right] = TEMPLATE_CHARS; const keys = templateKeys(str); for (let i = 0, len = keys.length; i < len; i++) { const key = keys[i]; diff --git a/src/renderer/geometry/Painter.ts b/src/renderer/geometry/Painter.ts index 61fa3cd2ee..f9ceb239be 100644 --- a/src/renderer/geometry/Painter.ts +++ b/src/renderer/geometry/Painter.ts @@ -47,6 +47,8 @@ const TEMP_BBOX = { maxy: -Infinity }; +const TEMP_CANVAS_CTX = []; + /** * @classdesc * Painter class for all geometry types except the collection types. @@ -652,24 +654,29 @@ class Painter extends Class { return; } } - const map = this.getMap(); if (this._aboveCamera()) { return; } //Multiplexing offset - this.containerOffset = offset || mapStateCache.offset || map._pointToContainerPoint(renderer.middleWest)._add(0, -map.height / 2); + this.containerOffset = offset || mapStateCache.offset; + if (!this.containerOffset) { + const map = this.getMap(); + this.containerOffset = map._pointToContainerPoint(renderer.middleWest)._add(0, -map.height / 2); + } this._beforePaint(); const ctx = context || renderer.context; if (!ctx.isHitTesting) { this._resetSymbolizersBBOX(); } - const contexts = [ctx, renderer.resources]; + // const contexts = [ctx, renderer.resources]; + TEMP_CANVAS_CTX[0] = ctx; + TEMP_CANVAS_CTX[1] = renderer.resources; for (let i = this.symbolizers.length - 1; i >= 0; i--) { // reduce function call if (ctx.shadowBlur || this.symbolizers[i].symbol['shadowBlur']) { this._prepareShadow(ctx, this.symbolizers[i].symbol); } - this.symbolizers[i].symbolize(...contexts); + this.symbolizers[i].symbolize(...TEMP_CANVAS_CTX); } this._afterPaint(); this._painted = true; diff --git a/src/renderer/geometry/symbolizers/TextMarkerSymbolizer.ts b/src/renderer/geometry/symbolizers/TextMarkerSymbolizer.ts index 89837d9e6c..aa76e2701c 100644 --- a/src/renderer/geometry/symbolizers/TextMarkerSymbolizer.ts +++ b/src/renderer/geometry/symbolizers/TextMarkerSymbolizer.ts @@ -6,7 +6,7 @@ import { hasFunctionDefinition } from '../../../core/mapbox'; import { isTextSymbol, getTextMarkerFixedExtent, getMarkerRotationExtent, } from '../../../core/util/marker'; import Canvas from '../../../core/Canvas'; import PointSymbolizer from './PointSymbolizer'; -import { replaceVariable, describeText } from '../../../core/util/strings'; +import { replaceVariable, describeText, getFont } from '../../../core/util/strings'; import { Geometry } from '../../../geometry'; import Painter from '../Painter'; import { ResourceCache } from '../..'; @@ -61,6 +61,9 @@ export default class TextMarkerSymbolizer extends PointSymbolizer { _fixedExtent: PointExtent; //@internal _index: number; + //cache font for performance + //@internal + _textFont: string; static test(symbol: any): boolean { return isTextSymbol(symbol); @@ -87,14 +90,14 @@ export default class TextMarkerSymbolizer extends PointSymbolizer { if (!this.isVisible()) { return; } - if (!this.painter.isHitTesting() && (this.style['textSize'] === 0 || - !this.style['textOpacity'] && (!this.style['textHaloRadius'] || !this.style['textHaloOpacity']) || - this.style['textWrapWidth'] === 0)) { + + const style = this.style; + if (!this.painter.isHitTesting() && (style['textSize'] === 0 || + !style['textOpacity'] && (!style['textHaloRadius'] || !style['textHaloOpacity']) || + style['textWrapWidth'] === 0)) { return; } - - const style = this.style, - strokeAndFill = this.strokeAndFill; + const strokeAndFill = this.strokeAndFill; const textContent = replaceVariable(this.style['textName'], this.geometry.getProperties()); if (this._dynamic) { delete this._textDesc; @@ -102,7 +105,11 @@ export default class TextMarkerSymbolizer extends PointSymbolizer { const textDesc = this._textDesc = this._textDesc || describeText(textContent, this.style); this._prepareContext(ctx); this.prepareCanvas(ctx, strokeAndFill, resources); - Canvas.prepareCanvasFont(ctx, style); + //cache font for performance + if (!this._textFont) { + this._textFont = getFont(style); + } + Canvas.prepareCanvasFont(ctx, style, !this._dynamic ? this._textFont : null); const textHaloRadius = style.textHaloRadius || 0; this.rotations = []; if (this.isAlongLine()) {