Pass along the ability to measure and cache text width

This commit is contained in:
Tim Schaub
2018-11-19 15:34:48 -07:00
parent e058eb3164
commit 8b50c3c6cb
4 changed files with 44 additions and 35 deletions

View File

@@ -10,15 +10,17 @@ import {lerp} from '../../math.js';
* @param {number} end End offset of the `flatCoordinates`.
* @param {number} stride Stride.
* @param {string} text Text to place on the path.
* @param {function(string):number} measure Measure function returning the
* width of the character passed as 1st argument.
* @param {number} startM m along the path where the text starts.
* @param {number} maxAngle Max angle between adjacent chars in radians.
* @param {number} scale The product of the text scale and the device pixel ratio.
* @param {function(string, string, Object<string, number>):number} measureAndCacheTextWidth Measure and cache text width.
* @param {string} font The font.
* @param {Object<string, number>} cache A cache of measured widths.
* @return {Array<Array<*>>} The result array of null if `maxAngle` was
* exceeded. Entries of the array are x, y, anchorX, angle, chunk.
*/
export function drawTextOnPath(
flatCoordinates, offset, end, stride, text, measure, startM, maxAngle) {
flatCoordinates, offset, end, stride, text, startM, maxAngle, scale, measureAndCacheTextWidth, font, cache) {
const result = [];
// Keep text upright
@@ -41,7 +43,7 @@ export function drawTextOnPath(
index = reverse ? numChars - i - 1 : i;
const char = text.charAt(index);
chunk = reverse ? char + chunk : chunk + char;
const charLength = measure(chunk) - chunkLength;
const charLength = scale * measureAndCacheTextWidth(font, chunk, cache) - chunkLength;
chunkLength += charLength;
const charM = startM + charLength / 2;
while (offset < end - stride && segmentM + segmentLength < charM) {

View File

@@ -324,6 +324,22 @@ export function measureTextWidth(font, text) {
}
/**
* Measure text width using a cache.
* @param {string} font The font.
* @param {string} text The text to measure.
* @param {Object<string, number>} cache A lookup of cached widths by text.
* @returns {number} The text width.
*/
export function measureAndCacheTextWidth(font, text, cache) {
if (text in cache) {
return cache[text];
}
const width = cache[text] = measureTextWidth(font, text);
return width;
}
/**
* @param {string} font Font to use for measuring.
* @param {Array<string>} lines Lines to measure.

View File

@@ -19,10 +19,8 @@ import {
apply as applyTransform,
setFromArray as transformSetFromArray
} from '../../transform.js';
import {createCanvasContext2D} from '../../dom.js';
import {labelCache, defaultTextAlign, measureTextHeight, measureTextWidth, measureTextWidths} from '../canvas.js';
import {labelCache, defaultTextAlign, measureTextHeight, measureAndCacheTextWidth, measureTextWidths} from '../canvas.js';
/**
@@ -736,29 +734,22 @@ class CanvasExecutor {
const textState = this.textStates[textKey];
const font = textState.font;
const textScale = textState.scale;
const textScale = textState.scale * measurePixelRatio;
let widths = this.widths_[font];
if (!widths) {
this.widths_[font] = widths = {};
let cachedWidths;
if (font in this.widths_) {
cachedWidths = this.widths_[font];
} else {
cachedWidths = this.widths_[font] = {};
}
//FIXME Do not create this function on every call
const measure = function(text) {
let width = widths[text];
if (!width) {
width = widths[text] = measureTextWidth(font, text);
}
return width * textScale * measurePixelRatio;
};
const pathLength = lineStringLength(pixelCoordinates, begin, end, 2);
const textLength = measure(text);
const textLength = textScale * measureAndCacheTextWidth(font, text, cachedWidths);
if (overflow || textLength <= pathLength) {
const textAlign = this.textStates[textKey].textAlign;
const startM = (pathLength - textLength) * TEXT_ALIGN[textAlign];
const parts = drawTextOnPath(
pixelCoordinates, begin, end, 2, text, measure, startM, maxAngle);
pixelCoordinates, begin, end, 2, text, startM, maxAngle, textScale, measureAndCacheTextWidth, font, cachedWidths);
if (parts) {
let c, cc, chars, label, part;
if (strokeKey) {