Cleanly separate text building and execution
This commit is contained in:
@@ -10,7 +10,7 @@ import {drawTextOnPath} from '../../geom/flat/textpath.js';
|
|||||||
import {transform2D} from '../../geom/flat/transform.js';
|
import {transform2D} from '../../geom/flat/transform.js';
|
||||||
import {CANVAS_LINE_DASH} from '../../has.js';
|
import {CANVAS_LINE_DASH} from '../../has.js';
|
||||||
import {isEmpty} from '../../obj.js';
|
import {isEmpty} from '../../obj.js';
|
||||||
import {drawImage, resetTransform, defaultPadding} from '../canvas.js';
|
import {drawImage, resetTransform, defaultPadding, defaultTextBaseline} from '../canvas.js';
|
||||||
import CanvasInstruction from './Instruction.js';
|
import CanvasInstruction from './Instruction.js';
|
||||||
import {TEXT_ALIGN} from '../replay.js';
|
import {TEXT_ALIGN} from '../replay.js';
|
||||||
import {
|
import {
|
||||||
@@ -525,6 +525,35 @@ class CanvasInstructionsExecutor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {string} text The text to draw.
|
||||||
|
* @param {string} textKey The key of the text state.
|
||||||
|
* @param {string} strokeKey The key for the stroke state.
|
||||||
|
* @param {string} fillKey The key for the fill state.
|
||||||
|
* @return {{label: HTMLCanvasElement, anchorX: number, anchorY: number}} The text image and its anchor.
|
||||||
|
*/
|
||||||
|
drawTextImageWithPointPlacement_(text, textKey, strokeKey, fillKey) {
|
||||||
|
const textState = this.textStates[textKey];
|
||||||
|
|
||||||
|
const label = this.getImage(text, textKey, fillKey, strokeKey);
|
||||||
|
|
||||||
|
const strokeState = this.strokeStates[strokeKey]; // FIXME: check if it is correct, was this.textStrokeState_;
|
||||||
|
const pixelRatio = this.pixelRatio;
|
||||||
|
const align = TEXT_ALIGN[textState.textAlign || defaultTextAlign];
|
||||||
|
const baseline = TEXT_ALIGN[textState.textBaseline || defaultTextBaseline]; // FIXME: why I need a default now?
|
||||||
|
const strokeWidth = strokeState && strokeState.lineWidth ? strokeState.lineWidth : 0;
|
||||||
|
|
||||||
|
const anchorX = align * label.width / pixelRatio + 2 * (0.5 - align) * strokeWidth;
|
||||||
|
const anchorY = baseline * label.height / pixelRatio + 2 * (0.5 - baseline) * strokeWidth;
|
||||||
|
|
||||||
|
return {
|
||||||
|
label: label,
|
||||||
|
anchorX: anchorX,
|
||||||
|
anchorY: anchorY
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @param {CanvasRenderingContext2D} context Context.
|
* @param {CanvasRenderingContext2D} context Context.
|
||||||
@@ -566,7 +595,8 @@ class CanvasInstructionsExecutor {
|
|||||||
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, anchorY, prevX, prevY, roundX, roundY, declutterGroup, image;
|
let anchorX, anchorY, prevX, prevY, roundX, roundY, declutterGroup, image, text, textKey;
|
||||||
|
let strokeKey, fillKey;
|
||||||
let pendingFill = 0;
|
let pendingFill = 0;
|
||||||
let pendingStroke = 0;
|
let pendingStroke = 0;
|
||||||
let lastFillInstruction = null;
|
let lastFillInstruction = null;
|
||||||
@@ -658,20 +688,44 @@ class CanvasInstructionsExecutor {
|
|||||||
case CanvasInstruction.DRAW_IMAGE:
|
case CanvasInstruction.DRAW_IMAGE:
|
||||||
d = /** @type {number} */ (instruction[1]);
|
d = /** @type {number} */ (instruction[1]);
|
||||||
dd = /** @type {number} */ (instruction[2]);
|
dd = /** @type {number} */ (instruction[2]);
|
||||||
image = /** @type {HTMLCanvasElement|HTMLVideoElement|HTMLImageElement} */
|
image = /** @type {HTMLCanvasElement|HTMLVideoElement|HTMLImageElement} */ (instruction[3]);
|
||||||
(instruction[3]);
|
|
||||||
// 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]);
|
||||||
declutterGroup = featureCallback ? null : /** @type {import("../canvas.js").DeclutterGroup} */ (instruction[6]);
|
declutterGroup = featureCallback ? null : /** @type {import("../canvas.js").DeclutterGroup} */ (instruction[6]);
|
||||||
const height = /** @type {number} */ (instruction[7]);
|
let height = /** @type {number} */ (instruction[7]);
|
||||||
const opacity = /** @type {number} */ (instruction[8]);
|
const opacity = /** @type {number} */ (instruction[8]);
|
||||||
const originX = /** @type {number} */ (instruction[9]);
|
const originX = /** @type {number} */ (instruction[9]);
|
||||||
const originY = /** @type {number} */ (instruction[10]);
|
const originY = /** @type {number} */ (instruction[10]);
|
||||||
const rotateWithView = /** @type {boolean} */ (instruction[11]);
|
const rotateWithView = /** @type {boolean} */ (instruction[11]);
|
||||||
let rotation = /** @type {number} */ (instruction[12]);
|
let rotation = /** @type {number} */ (instruction[12]);
|
||||||
const scale = /** @type {number} */ (instruction[13]);
|
const scale = /** @type {number} */ (instruction[13]);
|
||||||
const width = /** @type {number} */ (instruction[14]);
|
let width = /** @type {number} */ (instruction[14]);
|
||||||
|
|
||||||
|
|
||||||
|
if (!image) {
|
||||||
|
if (instruction.length < 19 || !instruction[18]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
text = /** @type {string} */ (instruction[18]);
|
||||||
|
textKey = /** @type {string} */ (instruction[19]);
|
||||||
|
strokeKey = /** @type {string} */ (instruction[20]);
|
||||||
|
fillKey = /** @type {string} */ (instruction[21]);
|
||||||
|
const labelWithAnchor = this.drawTextImageWithPointPlacement_(text, textKey, strokeKey, fillKey);
|
||||||
|
const textOffsetX = /** @type {number} */ (instruction[22]);
|
||||||
|
const textOffsetY = /** @type {number} */ (instruction[23]);
|
||||||
|
image = instruction[3] = labelWithAnchor.label;
|
||||||
|
anchorX = instruction[4] = (labelWithAnchor.anchorX - textOffsetX) * this.pixelRatio;
|
||||||
|
anchorY = instruction[5] = (labelWithAnchor.anchorY - textOffsetY) * this.pixelRatio;
|
||||||
|
height = instruction[8] = image.height;
|
||||||
|
width = instruction[14] = image.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
let geometryWidths;
|
||||||
|
if (instruction.length > 24) {
|
||||||
|
geometryWidths = /** @type {number} */ (instruction[24]);
|
||||||
|
}
|
||||||
|
|
||||||
let padding, backgroundFill, backgroundStroke;
|
let padding, backgroundFill, backgroundStroke;
|
||||||
if (instruction.length > 16) {
|
if (instruction.length > 16) {
|
||||||
@@ -686,7 +740,13 @@ class CanvasInstructionsExecutor {
|
|||||||
if (rotateWithView) {
|
if (rotateWithView) {
|
||||||
rotation += viewRotation;
|
rotation += viewRotation;
|
||||||
}
|
}
|
||||||
|
let widthIndex = 0;
|
||||||
for (; d < dd; d += 2) {
|
for (; d < dd; d += 2) {
|
||||||
|
if (geometryWidths) {
|
||||||
|
if (geometryWidths[widthIndex++] < width) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
this.replayImage_(context,
|
this.replayImage_(context,
|
||||||
pixelCoordinates[d], pixelCoordinates[d + 1], image, anchorX, anchorY,
|
pixelCoordinates[d], pixelCoordinates[d + 1], image, anchorX, anchorY,
|
||||||
declutterGroup, height, opacity, originX, originY, rotation, scale,
|
declutterGroup, height, opacity, originX, originY, rotation, scale,
|
||||||
@@ -703,14 +763,14 @@ class CanvasInstructionsExecutor {
|
|||||||
const baseline = /** @type {number} */ (instruction[3]);
|
const baseline = /** @type {number} */ (instruction[3]);
|
||||||
declutterGroup = featureCallback ? null : /** @type {import("../canvas.js").DeclutterGroup} */ (instruction[4]);
|
declutterGroup = featureCallback ? null : /** @type {import("../canvas.js").DeclutterGroup} */ (instruction[4]);
|
||||||
const overflow = /** @type {number} */ (instruction[5]);
|
const overflow = /** @type {number} */ (instruction[5]);
|
||||||
const fillKey = /** @type {string} */ (instruction[6]);
|
fillKey = /** @type {string} */ (instruction[6]);
|
||||||
const maxAngle = /** @type {number} */ (instruction[7]);
|
const maxAngle = /** @type {number} */ (instruction[7]);
|
||||||
const measurePixelRatio = /** @type {number} */ (instruction[8]);
|
const measurePixelRatio = /** @type {number} */ (instruction[8]);
|
||||||
const offsetY = /** @type {number} */ (instruction[9]);
|
const offsetY = /** @type {number} */ (instruction[9]);
|
||||||
const strokeKey = /** @type {string} */ (instruction[10]);
|
strokeKey = /** @type {string} */ (instruction[10]);
|
||||||
const strokeWidth = /** @type {number} */ (instruction[11]);
|
const strokeWidth = /** @type {number} */ (instruction[11]);
|
||||||
const text = /** @type {string} */ (instruction[12]);
|
text = /** @type {string} */ (instruction[12]);
|
||||||
const textKey = /** @type {string} */ (instruction[13]);
|
textKey = /** @type {string} */ (instruction[13]);
|
||||||
const pixelRatioScale = /** @type {number} */ (instruction[14]);
|
const pixelRatioScale = /** @type {number} */ (instruction[14]);
|
||||||
|
|
||||||
const textState = this.textStates[textKey];
|
const textState = this.textStates[textKey];
|
||||||
|
|||||||
@@ -3,12 +3,10 @@
|
|||||||
*/
|
*/
|
||||||
import {getUid} from '../../util.js';
|
import {getUid} from '../../util.js';
|
||||||
import {asColorLike} from '../../colorlike.js';
|
import {asColorLike} from '../../colorlike.js';
|
||||||
import {createCanvasContext2D} from '../../dom.js';
|
|
||||||
import {intersects} from '../../extent.js';
|
import {intersects} from '../../extent.js';
|
||||||
import {matchingChunk} from '../../geom/flat/straightchunk.js';
|
import {matchingChunk} from '../../geom/flat/straightchunk.js';
|
||||||
import GeometryType from '../../geom/GeometryType.js';
|
import GeometryType from '../../geom/GeometryType.js';
|
||||||
import {CANVAS_LINE_DASH} from '../../has.js';
|
import {labelCache, defaultTextAlign, defaultPadding, defaultLineCap, defaultLineDashOffset, defaultLineDash, defaultLineJoin, defaultFillStyle, checkFont, defaultFont, defaultLineWidth, defaultMiterLimit, defaultStrokeStyle, defaultTextBaseline} from '../canvas.js';
|
||||||
import {labelCache, measureTextWidths, defaultTextAlign, measureTextHeight, defaultPadding, defaultLineCap, defaultLineDashOffset, defaultLineDash, defaultLineJoin, defaultFillStyle, checkFont, defaultFont, defaultLineWidth, defaultMiterLimit, defaultStrokeStyle, defaultTextBaseline} from '../canvas.js';
|
|
||||||
import CanvasInstruction from './Instruction.js';
|
import CanvasInstruction from './Instruction.js';
|
||||||
import CanvasInstructionsBuilder from './InstructionsBuilder.js';
|
import CanvasInstructionsBuilder from './InstructionsBuilder.js';
|
||||||
import {TEXT_ALIGN} from '../replay.js';
|
import {TEXT_ALIGN} from '../replay.js';
|
||||||
@@ -195,8 +193,8 @@ class CanvasTextBuilder extends CanvasInstructionsBuilder {
|
|||||||
this.endGeometry(geometry, feature);
|
this.endGeometry(geometry, feature);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
const label = this.getImage(this.text_, this.textKey_, this.fillKey_, this.strokeKey_);
|
|
||||||
const width = label.width / this.pixelRatio;
|
const geometryWidths = [];
|
||||||
switch (geometryType) {
|
switch (geometryType) {
|
||||||
case GeometryType.POINT:
|
case GeometryType.POINT:
|
||||||
case GeometryType.MULTI_POINT:
|
case GeometryType.MULTI_POINT:
|
||||||
@@ -215,8 +213,8 @@ class CanvasTextBuilder extends CanvasInstructionsBuilder {
|
|||||||
break;
|
break;
|
||||||
case GeometryType.POLYGON:
|
case GeometryType.POLYGON:
|
||||||
flatCoordinates = /** @type {import("../../geom/Polygon.js").default} */ (geometry).getFlatInteriorPoint();
|
flatCoordinates = /** @type {import("../../geom/Polygon.js").default} */ (geometry).getFlatInteriorPoint();
|
||||||
if (!textState.overflow && flatCoordinates[2] / this.resolution < width) {
|
if (!textState.overflow) {
|
||||||
return;
|
geometryWidths.push(flatCoordinates[2] / this.resolution);
|
||||||
}
|
}
|
||||||
stride = 3;
|
stride = 3;
|
||||||
break;
|
break;
|
||||||
@@ -224,9 +222,10 @@ class CanvasTextBuilder extends CanvasInstructionsBuilder {
|
|||||||
const interiorPoints = /** @type {import("../../geom/MultiPolygon.js").default} */ (geometry).getFlatInteriorPoints();
|
const interiorPoints = /** @type {import("../../geom/MultiPolygon.js").default} */ (geometry).getFlatInteriorPoints();
|
||||||
flatCoordinates = [];
|
flatCoordinates = [];
|
||||||
for (i = 0, ii = interiorPoints.length; i < ii; i += 3) {
|
for (i = 0, ii = interiorPoints.length; i < ii; i += 3) {
|
||||||
if (textState.overflow || interiorPoints[i + 2] / this.resolution >= width) {
|
if (!textState.overflow) {
|
||||||
flatCoordinates.push(interiorPoints[i], interiorPoints[i + 1]);
|
geometryWidths.push(interiorPoints[i + 2] / this.resolution);
|
||||||
}
|
}
|
||||||
|
flatCoordinates.push(interiorPoints[i], interiorPoints[i + 1]);
|
||||||
}
|
}
|
||||||
end = flatCoordinates.length;
|
end = flatCoordinates.length;
|
||||||
if (end == 0) {
|
if (end == 0) {
|
||||||
@@ -236,6 +235,9 @@ class CanvasTextBuilder extends CanvasInstructionsBuilder {
|
|||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
end = this.appendFlatCoordinates(flatCoordinates, 0, end, stride, false, false);
|
end = this.appendFlatCoordinates(flatCoordinates, 0, end, stride, false, false);
|
||||||
|
|
||||||
|
this.saveTextStates_();
|
||||||
|
|
||||||
if (textState.backgroundFill || textState.backgroundStroke) {
|
if (textState.backgroundFill || textState.backgroundStroke) {
|
||||||
this.setFillStrokeStyle(textState.backgroundFill, textState.backgroundStroke);
|
this.setFillStrokeStyle(textState.backgroundFill, textState.backgroundStroke);
|
||||||
if (textState.backgroundFill) {
|
if (textState.backgroundFill) {
|
||||||
@@ -247,122 +249,42 @@ class CanvasTextBuilder extends CanvasInstructionsBuilder {
|
|||||||
this.hitDetectionInstructions.push(this.createStroke(this.state));
|
this.hitDetectionInstructions.push(this.createStroke(this.state));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.beginGeometry(geometry, feature);
|
this.beginGeometry(geometry, feature);
|
||||||
this.drawTextImage_(label, begin, end);
|
|
||||||
|
// The image is unknown at this stage so we pass null; it will be computed at render time.
|
||||||
|
// For clarity, we pass Infinity for numerical values that will be computed at render time.
|
||||||
|
const pixelRatio = this.pixelRatio;
|
||||||
|
this.instructions.push([CanvasInstruction.DRAW_IMAGE, begin, end,
|
||||||
|
null, Infinity, Infinity, this.declutterGroup_, Infinity, 1, 0, 0,
|
||||||
|
this.textRotateWithView_, this.textRotation_, 1, Infinity,
|
||||||
|
textState.padding == defaultPadding ?
|
||||||
|
defaultPadding : textState.padding.map(function(p) {
|
||||||
|
return p * pixelRatio;
|
||||||
|
}),
|
||||||
|
!!textState.backgroundFill, !!textState.backgroundStroke,
|
||||||
|
this.text_, this.textKey_, this.strokeKey_, this.fillKey_,
|
||||||
|
this.textOffsetX_, this.textOffsetY_,
|
||||||
|
geometryWidths.length > 0 ? geometryWidths : null
|
||||||
|
]);
|
||||||
|
this.hitDetectionInstructions.push([CanvasInstruction.DRAW_IMAGE, begin, end,
|
||||||
|
null, Infinity, Infinity, this.declutterGroup_, Infinity, 1, 0, 0,
|
||||||
|
this.textRotateWithView_, this.textRotation_, 1 / this.pixelRatio, Infinity,
|
||||||
|
textState.padding,
|
||||||
|
!!textState.backgroundFill, !!textState.backgroundStroke,
|
||||||
|
this.text_, this.textKey_, this.strokeKey_, this.fillKey_,
|
||||||
|
this.textOffsetX_, this.textOffsetY_,
|
||||||
|
geometryWidths.length > 0 ? geometryWidths : null
|
||||||
|
]);
|
||||||
|
|
||||||
this.endGeometry(geometry, feature);
|
this.endGeometry(geometry, feature);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} text Text.
|
|
||||||
* @param {string} textKey Text style key.
|
|
||||||
* @param {string} fillKey Fill style key.
|
|
||||||
* @param {string} strokeKey Stroke style key.
|
|
||||||
* @return {HTMLCanvasElement} Image.
|
|
||||||
*/
|
|
||||||
getImage(text, textKey, fillKey, strokeKey) {
|
|
||||||
let label;
|
|
||||||
const key = strokeKey + textKey + text + fillKey + this.pixelRatio;
|
|
||||||
|
|
||||||
if (!labelCache.containsKey(key)) {
|
|
||||||
const strokeState = strokeKey ? this.strokeStates[strokeKey] || this.textStrokeState_ : null;
|
|
||||||
const fillState = fillKey ? this.fillStates[fillKey] || this.textFillState_ : null;
|
|
||||||
const textState = this.textStates[textKey] || this.textState_;
|
|
||||||
const pixelRatio = this.pixelRatio;
|
|
||||||
const scale = textState.scale * pixelRatio;
|
|
||||||
const align = TEXT_ALIGN[textState.textAlign || defaultTextAlign];
|
|
||||||
const strokeWidth = strokeKey && strokeState.lineWidth ? strokeState.lineWidth : 0;
|
|
||||||
|
|
||||||
const lines = text.split('\n');
|
|
||||||
const numLines = lines.length;
|
|
||||||
const widths = [];
|
|
||||||
const width = measureTextWidths(textState.font, lines, widths);
|
|
||||||
const lineHeight = measureTextHeight(textState.font);
|
|
||||||
const height = lineHeight * numLines;
|
|
||||||
const renderWidth = (width + strokeWidth);
|
|
||||||
const context = createCanvasContext2D(
|
|
||||||
Math.ceil(renderWidth * scale),
|
|
||||||
Math.ceil((height + strokeWidth) * scale));
|
|
||||||
label = context.canvas;
|
|
||||||
labelCache.set(key, label);
|
|
||||||
if (scale != 1) {
|
|
||||||
context.scale(scale, scale);
|
|
||||||
}
|
|
||||||
context.font = textState.font;
|
|
||||||
if (strokeKey) {
|
|
||||||
context.strokeStyle = strokeState.strokeStyle;
|
|
||||||
context.lineWidth = strokeWidth;
|
|
||||||
context.lineCap = /** @type {CanvasLineCap} */ (strokeState.lineCap);
|
|
||||||
context.lineJoin = /** @type {CanvasLineJoin} */ (strokeState.lineJoin);
|
|
||||||
context.miterLimit = strokeState.miterLimit;
|
|
||||||
if (CANVAS_LINE_DASH && strokeState.lineDash.length) {
|
|
||||||
context.setLineDash(strokeState.lineDash);
|
|
||||||
context.lineDashOffset = strokeState.lineDashOffset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (fillKey) {
|
|
||||||
context.fillStyle = fillState.fillStyle;
|
|
||||||
}
|
|
||||||
context.textBaseline = 'middle';
|
|
||||||
context.textAlign = 'center';
|
|
||||||
const leftRight = (0.5 - align);
|
|
||||||
const x = align * label.width / scale + leftRight * strokeWidth;
|
|
||||||
let i;
|
|
||||||
if (strokeKey) {
|
|
||||||
for (i = 0; i < numLines; ++i) {
|
|
||||||
context.strokeText(lines[i], x + leftRight * widths[i], 0.5 * (strokeWidth + lineHeight) + i * lineHeight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (fillKey) {
|
|
||||||
for (i = 0; i < numLines; ++i) {
|
|
||||||
context.fillText(lines[i], x + leftRight * widths[i], 0.5 * (strokeWidth + lineHeight) + i * lineHeight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return labelCache.get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @param {HTMLCanvasElement} label Label.
|
|
||||||
* @param {number} begin Begin.
|
|
||||||
* @param {number} end End.
|
|
||||||
*/
|
*/
|
||||||
drawTextImage_(label, begin, end) {
|
saveTextStates_() {
|
||||||
const textState = this.textState_;
|
|
||||||
const strokeState = this.textStrokeState_;
|
|
||||||
const pixelRatio = this.pixelRatio;
|
|
||||||
const align = TEXT_ALIGN[textState.textAlign || defaultTextAlign];
|
|
||||||
const baseline = TEXT_ALIGN[textState.textBaseline];
|
|
||||||
const strokeWidth = strokeState && strokeState.lineWidth ? strokeState.lineWidth : 0;
|
|
||||||
|
|
||||||
const anchorX = align * label.width / pixelRatio + 2 * (0.5 - align) * strokeWidth;
|
|
||||||
const anchorY = baseline * label.height / pixelRatio + 2 * (0.5 - baseline) * strokeWidth;
|
|
||||||
this.instructions.push([CanvasInstruction.DRAW_IMAGE, begin, end,
|
|
||||||
label, (anchorX - this.textOffsetX_) * pixelRatio, (anchorY - this.textOffsetY_) * pixelRatio,
|
|
||||||
this.declutterGroup_, label.height, 1, 0, 0, this.textRotateWithView_, this.textRotation_,
|
|
||||||
1, label.width,
|
|
||||||
textState.padding == defaultPadding ?
|
|
||||||
defaultPadding : textState.padding.map(function(p) {
|
|
||||||
return p * pixelRatio;
|
|
||||||
}),
|
|
||||||
!!textState.backgroundFill, !!textState.backgroundStroke
|
|
||||||
]);
|
|
||||||
this.hitDetectionInstructions.push([CanvasInstruction.DRAW_IMAGE, begin, end,
|
|
||||||
label, (anchorX - this.textOffsetX_) * pixelRatio, (anchorY - this.textOffsetY_) * pixelRatio,
|
|
||||||
this.declutterGroup_, label.height, 1, 0, 0, this.textRotateWithView_, this.textRotation_,
|
|
||||||
1 / pixelRatio, label.width, textState.padding,
|
|
||||||
!!textState.backgroundFill, !!textState.backgroundStroke
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
* @param {number} begin Begin.
|
|
||||||
* @param {number} end End.
|
|
||||||
* @param {import("../canvas.js").DeclutterGroup} declutterGroup Declutter group.
|
|
||||||
*/
|
|
||||||
drawChars_(begin, end, declutterGroup) {
|
|
||||||
const strokeState = this.textStrokeState_;
|
const strokeState = this.textStrokeState_;
|
||||||
const textState = this.textState_;
|
const textState = this.textState_;
|
||||||
const fillState = this.textFillState_;
|
const fillState = this.textFillState_;
|
||||||
@@ -382,10 +304,11 @@ class CanvasTextBuilder extends CanvasInstructionsBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const textKey = this.textKey_;
|
const textKey = this.textKey_;
|
||||||
if (!(this.textKey_ in this.textStates)) {
|
if (!(textKey in this.textStates)) {
|
||||||
this.textStates[this.textKey_] = /** @type {import("../canvas.js").TextState} */ ({
|
this.textStates[textKey] = /** @type {import("../canvas.js").TextState} */ ({
|
||||||
font: textState.font,
|
font: textState.font,
|
||||||
textAlign: textState.textAlign || defaultTextAlign,
|
textAlign: textState.textAlign || defaultTextAlign,
|
||||||
|
textBaseline: textState.textBaseline || defaultTextBaseline,
|
||||||
scale: textState.scale
|
scale: textState.scale
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -397,6 +320,23 @@ class CanvasTextBuilder extends CanvasInstructionsBuilder {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {number} begin Begin.
|
||||||
|
* @param {number} end End.
|
||||||
|
* @param {import("../canvas.js").DeclutterGroup} declutterGroup Declutter group.
|
||||||
|
*/
|
||||||
|
drawChars_(begin, end, declutterGroup) {
|
||||||
|
const strokeState = this.textStrokeState_;
|
||||||
|
const textState = this.textState_;
|
||||||
|
|
||||||
|
const strokeKey = this.strokeKey_;
|
||||||
|
const textKey = this.textKey_;
|
||||||
|
const fillKey = this.fillKey_;
|
||||||
|
this.saveTextStates_();
|
||||||
|
|
||||||
|
|
||||||
const pixelRatio = this.pixelRatio;
|
const pixelRatio = this.pixelRatio;
|
||||||
const baseline = TEXT_ALIGN[textState.textBaseline];
|
const baseline = TEXT_ALIGN[textState.textBaseline];
|
||||||
|
|||||||
Reference in New Issue
Block a user