Files
coopgo/node_modules/ol/render/canvas/TextBuilder.js
sgauthier 6e64e138e2
All checks were successful
Publish To Prod / deploy_and_publish (push) Successful in 35s
planning
2024-10-14 09:15:30 +02:00

572 lines
22 KiB
JavaScript

var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
/**
* @module ol/render/canvas/TextBuilder
*/
import CanvasBuilder from './Builder.js';
import CanvasInstruction from './Instruction.js';
import TextPlacement from '../../style/TextPlacement.js';
import { asColorLike } from '../../colorlike.js';
import { defaultFillStyle, defaultFont, defaultLineCap, defaultLineDash, defaultLineDashOffset, defaultLineJoin, defaultLineWidth, defaultMiterLimit, defaultPadding, defaultStrokeStyle, defaultTextAlign, defaultTextBaseline, registerFont, } from '../canvas.js';
import { getUid } from '../../util.js';
import { intersects } from '../../extent.js';
import { matchingChunk } from '../../geom/flat/straightchunk.js';
/**
* @const
* @enum {number}
*/
export var TEXT_ALIGN = {
'left': 0,
'end': 0,
'center': 0.5,
'right': 1,
'start': 1,
'top': 0,
'middle': 0.5,
'hanging': 0.2,
'alphabetic': 0.8,
'ideographic': 0.8,
'bottom': 1,
};
var CanvasTextBuilder = /** @class */ (function (_super) {
__extends(CanvasTextBuilder, _super);
/**
* @param {number} tolerance Tolerance.
* @param {import("../../extent.js").Extent} maxExtent Maximum extent.
* @param {number} resolution Resolution.
* @param {number} pixelRatio Pixel ratio.
*/
function CanvasTextBuilder(tolerance, maxExtent, resolution, pixelRatio) {
var _this = _super.call(this, tolerance, maxExtent, resolution, pixelRatio) || this;
/**
* @private
* @type {Array<HTMLCanvasElement>}
*/
_this.labels_ = null;
/**
* @private
* @type {string|Array<string>}
*/
_this.text_ = '';
/**
* @private
* @type {number}
*/
_this.textOffsetX_ = 0;
/**
* @private
* @type {number}
*/
_this.textOffsetY_ = 0;
/**
* @private
* @type {boolean|undefined}
*/
_this.textRotateWithView_ = undefined;
/**
* @private
* @type {number}
*/
_this.textRotation_ = 0;
/**
* @private
* @type {?import("../canvas.js").FillState}
*/
_this.textFillState_ = null;
/**
* @type {!Object<string, import("../canvas.js").FillState>}
*/
_this.fillStates = {};
/**
* @private
* @type {?import("../canvas.js").StrokeState}
*/
_this.textStrokeState_ = null;
/**
* @type {!Object<string, import("../canvas.js").StrokeState>}
*/
_this.strokeStates = {};
/**
* @private
* @type {import("../canvas.js").TextState}
*/
_this.textState_ = /** @type {import("../canvas.js").TextState} */ ({});
/**
* @type {!Object<string, import("../canvas.js").TextState>}
*/
_this.textStates = {};
/**
* @private
* @type {string}
*/
_this.textKey_ = '';
/**
* @private
* @type {string}
*/
_this.fillKey_ = '';
/**
* @private
* @type {string}
*/
_this.strokeKey_ = '';
/**
* Data shared with an image builder for combined decluttering.
* @private
* @type {import("../canvas.js").DeclutterImageWithText}
*/
_this.declutterImageWithText_ = undefined;
return _this;
}
/**
* @return {import("../canvas.js").SerializableInstructions} the serializable instructions.
*/
CanvasTextBuilder.prototype.finish = function () {
var instructions = _super.prototype.finish.call(this);
instructions.textStates = this.textStates;
instructions.fillStates = this.fillStates;
instructions.strokeStates = this.strokeStates;
return instructions;
};
/**
* @param {import("../../geom/SimpleGeometry.js").default|import("../Feature.js").default} geometry Geometry.
* @param {import("../../Feature.js").FeatureLike} feature Feature.
*/
CanvasTextBuilder.prototype.drawText = function (geometry, feature) {
var fillState = this.textFillState_;
var strokeState = this.textStrokeState_;
var textState = this.textState_;
if (this.text_ === '' || !textState || (!fillState && !strokeState)) {
return;
}
var coordinates = this.coordinates;
var begin = coordinates.length;
var geometryType = geometry.getType();
var flatCoordinates = null;
var stride = geometry.getStride();
if (textState.placement === TextPlacement.LINE &&
(geometryType == 'LineString' ||
geometryType == 'MultiLineString' ||
geometryType == 'Polygon' ||
geometryType == 'MultiPolygon')) {
if (!intersects(this.getBufferedMaxExtent(), geometry.getExtent())) {
return;
}
var ends = void 0;
flatCoordinates = geometry.getFlatCoordinates();
if (geometryType == 'LineString') {
ends = [flatCoordinates.length];
}
else if (geometryType == 'MultiLineString') {
ends = /** @type {import("../../geom/MultiLineString.js").default} */ (geometry).getEnds();
}
else if (geometryType == 'Polygon') {
ends = /** @type {import("../../geom/Polygon.js").default} */ (geometry)
.getEnds()
.slice(0, 1);
}
else if (geometryType == 'MultiPolygon') {
var endss =
/** @type {import("../../geom/MultiPolygon.js").default} */ (geometry).getEndss();
ends = [];
for (var i = 0, ii = endss.length; i < ii; ++i) {
ends.push(endss[i][0]);
}
}
this.beginGeometry(geometry, feature);
var textAlign = textState.textAlign;
// No `justify` support for line placement.
var flatOffset = 0;
var flatEnd = void 0;
for (var o = 0, oo = ends.length; o < oo; ++o) {
if (textAlign == undefined) {
var range = matchingChunk(textState.maxAngle, flatCoordinates, flatOffset, ends[o], stride);
flatOffset = range[0];
flatEnd = range[1];
}
else {
flatEnd = ends[o];
}
for (var i = flatOffset; i < flatEnd; i += stride) {
coordinates.push(flatCoordinates[i], flatCoordinates[i + 1]);
}
var end = coordinates.length;
flatOffset = ends[o];
this.drawChars_(begin, end);
begin = end;
}
this.endGeometry(feature);
}
else {
var geometryWidths = textState.overflow ? null : [];
switch (geometryType) {
case 'Point':
case 'MultiPoint':
flatCoordinates =
/** @type {import("../../geom/MultiPoint.js").default} */ (geometry).getFlatCoordinates();
break;
case 'LineString':
flatCoordinates =
/** @type {import("../../geom/LineString.js").default} */ (geometry).getFlatMidpoint();
break;
case 'Circle':
flatCoordinates =
/** @type {import("../../geom/Circle.js").default} */ (geometry).getCenter();
break;
case 'MultiLineString':
flatCoordinates =
/** @type {import("../../geom/MultiLineString.js").default} */ (geometry).getFlatMidpoints();
stride = 2;
break;
case 'Polygon':
flatCoordinates =
/** @type {import("../../geom/Polygon.js").default} */ (geometry).getFlatInteriorPoint();
if (!textState.overflow) {
geometryWidths.push(flatCoordinates[2] / this.resolution);
}
stride = 3;
break;
case 'MultiPolygon':
var interiorPoints =
/** @type {import("../../geom/MultiPolygon.js").default} */ (geometry).getFlatInteriorPoints();
flatCoordinates = [];
for (var i = 0, ii = interiorPoints.length; i < ii; i += 3) {
if (!textState.overflow) {
geometryWidths.push(interiorPoints[i + 2] / this.resolution);
}
flatCoordinates.push(interiorPoints[i], interiorPoints[i + 1]);
}
if (flatCoordinates.length === 0) {
return;
}
stride = 2;
break;
default:
}
var end = this.appendFlatPointCoordinates(flatCoordinates, stride);
if (end === begin) {
return;
}
if (geometryWidths &&
(end - begin) / 2 !== flatCoordinates.length / stride) {
var beg_1 = begin / 2;
geometryWidths = geometryWidths.filter(function (w, i) {
var keep = coordinates[(beg_1 + i) * 2] === flatCoordinates[i * stride] &&
coordinates[(beg_1 + i) * 2 + 1] === flatCoordinates[i * stride + 1];
if (!keep) {
--beg_1;
}
return keep;
});
}
this.saveTextStates_();
if (textState.backgroundFill || textState.backgroundStroke) {
this.setFillStrokeStyle(textState.backgroundFill, textState.backgroundStroke);
if (textState.backgroundFill) {
this.updateFillStyle(this.state, this.createFill);
this.hitDetectionInstructions.push(this.createFill(this.state));
}
if (textState.backgroundStroke) {
this.updateStrokeStyle(this.state, this.applyStroke);
this.hitDetectionInstructions.push(this.createStroke(this.state));
}
}
this.beginGeometry(geometry, feature);
// adjust padding for negative scale
var padding = textState.padding;
if (padding != defaultPadding &&
(textState.scale[0] < 0 || textState.scale[1] < 0)) {
var p0 = textState.padding[0];
var p1 = textState.padding[1];
var p2 = textState.padding[2];
var p3 = textState.padding[3];
if (textState.scale[0] < 0) {
p1 = -p1;
p3 = -p3;
}
if (textState.scale[1] < 0) {
p0 = -p0;
p2 = -p2;
}
padding = [p0, p1, p2, p3];
}
// The image is unknown at this stage so we pass null; it will be computed at render time.
// For clarity, we pass NaN for offsetX, offsetY, width and height, which will be computed at
// render time.
var pixelRatio_1 = this.pixelRatio;
this.instructions.push([
CanvasInstruction.DRAW_IMAGE,
begin,
end,
null,
NaN,
NaN,
NaN,
1,
0,
0,
this.textRotateWithView_,
this.textRotation_,
[1, 1],
NaN,
undefined,
this.declutterImageWithText_,
padding == defaultPadding
? defaultPadding
: padding.map(function (p) {
return p * pixelRatio_1;
}),
!!textState.backgroundFill,
!!textState.backgroundStroke,
this.text_,
this.textKey_,
this.strokeKey_,
this.fillKey_,
this.textOffsetX_,
this.textOffsetY_,
geometryWidths,
]);
var scale = 1 / pixelRatio_1;
this.hitDetectionInstructions.push([
CanvasInstruction.DRAW_IMAGE,
begin,
end,
null,
NaN,
NaN,
NaN,
1,
0,
0,
this.textRotateWithView_,
this.textRotation_,
[scale, scale],
NaN,
undefined,
this.declutterImageWithText_,
padding,
!!textState.backgroundFill,
!!textState.backgroundStroke,
this.text_,
this.textKey_,
this.strokeKey_,
this.fillKey_,
this.textOffsetX_,
this.textOffsetY_,
geometryWidths,
]);
this.endGeometry(feature);
}
};
/**
* @private
*/
CanvasTextBuilder.prototype.saveTextStates_ = function () {
var strokeState = this.textStrokeState_;
var textState = this.textState_;
var fillState = this.textFillState_;
var strokeKey = this.strokeKey_;
if (strokeState) {
if (!(strokeKey in this.strokeStates)) {
this.strokeStates[strokeKey] = {
strokeStyle: strokeState.strokeStyle,
lineCap: strokeState.lineCap,
lineDashOffset: strokeState.lineDashOffset,
lineWidth: strokeState.lineWidth,
lineJoin: strokeState.lineJoin,
miterLimit: strokeState.miterLimit,
lineDash: strokeState.lineDash,
};
}
}
var textKey = this.textKey_;
if (!(textKey in this.textStates)) {
this.textStates[textKey] = {
font: textState.font,
textAlign: textState.textAlign || defaultTextAlign,
justify: textState.justify,
textBaseline: textState.textBaseline || defaultTextBaseline,
scale: textState.scale,
};
}
var fillKey = this.fillKey_;
if (fillState) {
if (!(fillKey in this.fillStates)) {
this.fillStates[fillKey] = {
fillStyle: fillState.fillStyle,
};
}
}
};
/**
* @private
* @param {number} begin Begin.
* @param {number} end End.
*/
CanvasTextBuilder.prototype.drawChars_ = function (begin, end) {
var strokeState = this.textStrokeState_;
var textState = this.textState_;
var strokeKey = this.strokeKey_;
var textKey = this.textKey_;
var fillKey = this.fillKey_;
this.saveTextStates_();
var pixelRatio = this.pixelRatio;
var baseline = TEXT_ALIGN[textState.textBaseline];
var offsetY = this.textOffsetY_ * pixelRatio;
var text = this.text_;
var strokeWidth = strokeState
? (strokeState.lineWidth * Math.abs(textState.scale[0])) / 2
: 0;
this.instructions.push([
CanvasInstruction.DRAW_CHARS,
begin,
end,
baseline,
textState.overflow,
fillKey,
textState.maxAngle,
pixelRatio,
offsetY,
strokeKey,
strokeWidth * pixelRatio,
text,
textKey,
1,
]);
this.hitDetectionInstructions.push([
CanvasInstruction.DRAW_CHARS,
begin,
end,
baseline,
textState.overflow,
fillKey,
textState.maxAngle,
1,
offsetY,
strokeKey,
strokeWidth,
text,
textKey,
1 / pixelRatio,
]);
};
/**
* @param {import("../../style/Text.js").default} textStyle Text style.
* @param {Object} [opt_sharedData] Shared data.
*/
CanvasTextBuilder.prototype.setTextStyle = function (textStyle, opt_sharedData) {
var textState, fillState, strokeState;
if (!textStyle) {
this.text_ = '';
}
else {
var textFillStyle = textStyle.getFill();
if (!textFillStyle) {
fillState = null;
this.textFillState_ = fillState;
}
else {
fillState = this.textFillState_;
if (!fillState) {
fillState = /** @type {import("../canvas.js").FillState} */ ({});
this.textFillState_ = fillState;
}
fillState.fillStyle = asColorLike(textFillStyle.getColor() || defaultFillStyle);
}
var textStrokeStyle = textStyle.getStroke();
if (!textStrokeStyle) {
strokeState = null;
this.textStrokeState_ = strokeState;
}
else {
strokeState = this.textStrokeState_;
if (!strokeState) {
strokeState = /** @type {import("../canvas.js").StrokeState} */ ({});
this.textStrokeState_ = strokeState;
}
var lineDash = textStrokeStyle.getLineDash();
var lineDashOffset = textStrokeStyle.getLineDashOffset();
var lineWidth = textStrokeStyle.getWidth();
var miterLimit = textStrokeStyle.getMiterLimit();
strokeState.lineCap = textStrokeStyle.getLineCap() || defaultLineCap;
strokeState.lineDash = lineDash ? lineDash.slice() : defaultLineDash;
strokeState.lineDashOffset =
lineDashOffset === undefined ? defaultLineDashOffset : lineDashOffset;
strokeState.lineJoin = textStrokeStyle.getLineJoin() || defaultLineJoin;
strokeState.lineWidth =
lineWidth === undefined ? defaultLineWidth : lineWidth;
strokeState.miterLimit =
miterLimit === undefined ? defaultMiterLimit : miterLimit;
strokeState.strokeStyle = asColorLike(textStrokeStyle.getColor() || defaultStrokeStyle);
}
textState = this.textState_;
var font = textStyle.getFont() || defaultFont;
registerFont(font);
var textScale = textStyle.getScaleArray();
textState.overflow = textStyle.getOverflow();
textState.font = font;
textState.maxAngle = textStyle.getMaxAngle();
textState.placement = textStyle.getPlacement();
textState.textAlign = textStyle.getTextAlign();
textState.justify = textStyle.getJustify();
textState.textBaseline =
textStyle.getTextBaseline() || defaultTextBaseline;
textState.backgroundFill = textStyle.getBackgroundFill();
textState.backgroundStroke = textStyle.getBackgroundStroke();
textState.padding = textStyle.getPadding() || defaultPadding;
textState.scale = textScale === undefined ? [1, 1] : textScale;
var textOffsetX = textStyle.getOffsetX();
var textOffsetY = textStyle.getOffsetY();
var textRotateWithView = textStyle.getRotateWithView();
var textRotation = textStyle.getRotation();
this.text_ = textStyle.getText() || '';
this.textOffsetX_ = textOffsetX === undefined ? 0 : textOffsetX;
this.textOffsetY_ = textOffsetY === undefined ? 0 : textOffsetY;
this.textRotateWithView_ =
textRotateWithView === undefined ? false : textRotateWithView;
this.textRotation_ = textRotation === undefined ? 0 : textRotation;
this.strokeKey_ = strokeState
? (typeof strokeState.strokeStyle == 'string'
? strokeState.strokeStyle
: getUid(strokeState.strokeStyle)) +
strokeState.lineCap +
strokeState.lineDashOffset +
'|' +
strokeState.lineWidth +
strokeState.lineJoin +
strokeState.miterLimit +
'[' +
strokeState.lineDash.join() +
']'
: '';
this.textKey_ =
textState.font +
textState.scale +
(textState.textAlign || '?') +
(textState.justify || '?') +
(textState.textBaseline || '?');
this.fillKey_ = fillState
? typeof fillState.fillStyle == 'string'
? fillState.fillStyle
: '|' + getUid(fillState.fillStyle)
: '';
}
this.declutterImageWithText_ = opt_sharedData;
};
return CanvasTextBuilder;
}(CanvasBuilder));
export default CanvasTextBuilder;
//# sourceMappingURL=TextBuilder.js.map