242 lines
9.0 KiB
JavaScript
242 lines
9.0 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.TextPath = void 0;
|
|
const Util_1 = require("../Util");
|
|
const Factory_1 = require("../Factory");
|
|
const Shape_1 = require("../Shape");
|
|
const Path_1 = require("./Path");
|
|
const Text_1 = require("./Text");
|
|
const Validators_1 = require("../Validators");
|
|
const Global_1 = require("../Global");
|
|
const EMPTY_STRING = '', NORMAL = 'normal';
|
|
function _fillFunc(context) {
|
|
context.fillText(this.partialText, 0, 0);
|
|
}
|
|
function _strokeFunc(context) {
|
|
context.strokeText(this.partialText, 0, 0);
|
|
}
|
|
class TextPath extends Shape_1.Shape {
|
|
constructor(config) {
|
|
super(config);
|
|
this.dummyCanvas = Util_1.Util.createCanvasElement();
|
|
this.dataArray = [];
|
|
this._readDataAttribute();
|
|
this.on('dataChange.konva', function () {
|
|
this._readDataAttribute();
|
|
this._setTextData();
|
|
});
|
|
this.on('textChange.konva alignChange.konva letterSpacingChange.konva kerningFuncChange.konva fontSizeChange.konva fontFamilyChange.konva', this._setTextData);
|
|
this._setTextData();
|
|
}
|
|
_getTextPathLength() {
|
|
return Path_1.Path.getPathLength(this.dataArray);
|
|
}
|
|
_getPointAtLength(length) {
|
|
if (!this.attrs.data) {
|
|
return null;
|
|
}
|
|
const totalLength = this.pathLength;
|
|
if (length - 1 > totalLength) {
|
|
return null;
|
|
}
|
|
return Path_1.Path.getPointAtLengthOfDataArray(length, this.dataArray);
|
|
}
|
|
_readDataAttribute() {
|
|
this.dataArray = Path_1.Path.parsePathData(this.attrs.data);
|
|
this.pathLength = this._getTextPathLength();
|
|
}
|
|
_sceneFunc(context) {
|
|
context.setAttr('font', this._getContextFont());
|
|
context.setAttr('textBaseline', this.textBaseline());
|
|
context.setAttr('textAlign', 'left');
|
|
context.save();
|
|
const textDecoration = this.textDecoration();
|
|
const fill = this.fill();
|
|
const fontSize = this.fontSize();
|
|
const glyphInfo = this.glyphInfo;
|
|
if (textDecoration === 'underline') {
|
|
context.beginPath();
|
|
}
|
|
for (let i = 0; i < glyphInfo.length; i++) {
|
|
context.save();
|
|
const p0 = glyphInfo[i].p0;
|
|
context.translate(p0.x, p0.y);
|
|
context.rotate(glyphInfo[i].rotation);
|
|
this.partialText = glyphInfo[i].text;
|
|
context.fillStrokeShape(this);
|
|
if (textDecoration === 'underline') {
|
|
if (i === 0) {
|
|
context.moveTo(0, fontSize / 2 + 1);
|
|
}
|
|
context.lineTo(fontSize, fontSize / 2 + 1);
|
|
}
|
|
context.restore();
|
|
}
|
|
if (textDecoration === 'underline') {
|
|
context.strokeStyle = fill;
|
|
context.lineWidth = fontSize / 20;
|
|
context.stroke();
|
|
}
|
|
context.restore();
|
|
}
|
|
_hitFunc(context) {
|
|
context.beginPath();
|
|
const glyphInfo = this.glyphInfo;
|
|
if (glyphInfo.length >= 1) {
|
|
const p0 = glyphInfo[0].p0;
|
|
context.moveTo(p0.x, p0.y);
|
|
}
|
|
for (let i = 0; i < glyphInfo.length; i++) {
|
|
const p1 = glyphInfo[i].p1;
|
|
context.lineTo(p1.x, p1.y);
|
|
}
|
|
context.setAttr('lineWidth', this.fontSize());
|
|
context.setAttr('strokeStyle', this.colorKey);
|
|
context.stroke();
|
|
}
|
|
getTextWidth() {
|
|
return this.textWidth;
|
|
}
|
|
getTextHeight() {
|
|
Util_1.Util.warn('text.getTextHeight() method is deprecated. Use text.height() - for full height and text.fontSize() - for one line height.');
|
|
return this.textHeight;
|
|
}
|
|
setText(text) {
|
|
return Text_1.Text.prototype.setText.call(this, text);
|
|
}
|
|
_getContextFont() {
|
|
return Text_1.Text.prototype._getContextFont.call(this);
|
|
}
|
|
_getTextSize(text) {
|
|
const dummyCanvas = this.dummyCanvas;
|
|
const _context = dummyCanvas.getContext('2d');
|
|
_context.save();
|
|
_context.font = this._getContextFont();
|
|
const metrics = _context.measureText(text);
|
|
_context.restore();
|
|
return {
|
|
width: metrics.width,
|
|
height: parseInt(`${this.fontSize()}`, 10),
|
|
};
|
|
}
|
|
_setTextData() {
|
|
const { width, height } = this._getTextSize(this.attrs.text);
|
|
this.textWidth = width;
|
|
this.textHeight = height;
|
|
this.glyphInfo = [];
|
|
if (!this.attrs.data) {
|
|
return null;
|
|
}
|
|
const letterSpacing = this.letterSpacing();
|
|
const align = this.align();
|
|
const kerningFunc = this.kerningFunc();
|
|
const textWidth = Math.max(this.textWidth + ((this.attrs.text || '').length - 1) * letterSpacing, 0);
|
|
let offset = 0;
|
|
if (align === 'center') {
|
|
offset = Math.max(0, this.pathLength / 2 - textWidth / 2);
|
|
}
|
|
if (align === 'right') {
|
|
offset = Math.max(0, this.pathLength - textWidth);
|
|
}
|
|
const charArr = (0, Text_1.stringToArray)(this.text());
|
|
let offsetToGlyph = offset;
|
|
for (let i = 0; i < charArr.length; i++) {
|
|
const charStartPoint = this._getPointAtLength(offsetToGlyph);
|
|
if (!charStartPoint)
|
|
return;
|
|
let glyphWidth = this._getTextSize(charArr[i]).width + letterSpacing;
|
|
if (charArr[i] === ' ' && align === 'justify') {
|
|
const numberOfSpaces = this.text().split(' ').length - 1;
|
|
glyphWidth += (this.pathLength - textWidth) / numberOfSpaces;
|
|
}
|
|
const charEndPoint = this._getPointAtLength(offsetToGlyph + glyphWidth);
|
|
if (!charEndPoint)
|
|
return;
|
|
const width = Path_1.Path.getLineLength(charStartPoint.x, charStartPoint.y, charEndPoint.x, charEndPoint.y);
|
|
let kern = 0;
|
|
if (kerningFunc) {
|
|
try {
|
|
kern = kerningFunc(charArr[i - 1], charArr[i]) * this.fontSize();
|
|
}
|
|
catch (e) {
|
|
kern = 0;
|
|
}
|
|
}
|
|
charStartPoint.x += kern;
|
|
charEndPoint.x += kern;
|
|
this.textWidth += kern;
|
|
const midpoint = Path_1.Path.getPointOnLine(kern + width / 2.0, charStartPoint.x, charStartPoint.y, charEndPoint.x, charEndPoint.y);
|
|
const rotation = Math.atan2(charEndPoint.y - charStartPoint.y, charEndPoint.x - charStartPoint.x);
|
|
this.glyphInfo.push({
|
|
transposeX: midpoint.x,
|
|
transposeY: midpoint.y,
|
|
text: charArr[i],
|
|
rotation: rotation,
|
|
p0: charStartPoint,
|
|
p1: charEndPoint,
|
|
});
|
|
offsetToGlyph += glyphWidth;
|
|
}
|
|
}
|
|
getSelfRect() {
|
|
if (!this.glyphInfo.length) {
|
|
return {
|
|
x: 0,
|
|
y: 0,
|
|
width: 0,
|
|
height: 0,
|
|
};
|
|
}
|
|
const points = [];
|
|
this.glyphInfo.forEach(function (info) {
|
|
points.push(info.p0.x);
|
|
points.push(info.p0.y);
|
|
points.push(info.p1.x);
|
|
points.push(info.p1.y);
|
|
});
|
|
let minX = points[0] || 0;
|
|
let maxX = points[0] || 0;
|
|
let minY = points[1] || 0;
|
|
let maxY = points[1] || 0;
|
|
let x, y;
|
|
for (let i = 0; i < points.length / 2; i++) {
|
|
x = points[i * 2];
|
|
y = points[i * 2 + 1];
|
|
minX = Math.min(minX, x);
|
|
maxX = Math.max(maxX, x);
|
|
minY = Math.min(minY, y);
|
|
maxY = Math.max(maxY, y);
|
|
}
|
|
const fontSize = this.fontSize();
|
|
return {
|
|
x: minX - fontSize / 2,
|
|
y: minY - fontSize / 2,
|
|
width: maxX - minX + fontSize,
|
|
height: maxY - minY + fontSize,
|
|
};
|
|
}
|
|
destroy() {
|
|
Util_1.Util.releaseCanvas(this.dummyCanvas);
|
|
return super.destroy();
|
|
}
|
|
}
|
|
exports.TextPath = TextPath;
|
|
TextPath.prototype._fillFunc = _fillFunc;
|
|
TextPath.prototype._strokeFunc = _strokeFunc;
|
|
TextPath.prototype._fillFuncHit = _fillFunc;
|
|
TextPath.prototype._strokeFuncHit = _strokeFunc;
|
|
TextPath.prototype.className = 'TextPath';
|
|
TextPath.prototype._attrsAffectingSize = ['text', 'fontSize', 'data'];
|
|
(0, Global_1._registerNode)(TextPath);
|
|
Factory_1.Factory.addGetterSetter(TextPath, 'data');
|
|
Factory_1.Factory.addGetterSetter(TextPath, 'fontFamily', 'Arial');
|
|
Factory_1.Factory.addGetterSetter(TextPath, 'fontSize', 12, (0, Validators_1.getNumberValidator)());
|
|
Factory_1.Factory.addGetterSetter(TextPath, 'fontStyle', NORMAL);
|
|
Factory_1.Factory.addGetterSetter(TextPath, 'align', 'left');
|
|
Factory_1.Factory.addGetterSetter(TextPath, 'letterSpacing', 0, (0, Validators_1.getNumberValidator)());
|
|
Factory_1.Factory.addGetterSetter(TextPath, 'textBaseline', 'middle');
|
|
Factory_1.Factory.addGetterSetter(TextPath, 'fontVariant', NORMAL);
|
|
Factory_1.Factory.addGetterSetter(TextPath, 'text', EMPTY_STRING);
|
|
Factory_1.Factory.addGetterSetter(TextPath, 'textDecoration', '');
|
|
Factory_1.Factory.addGetterSetter(TextPath, 'kerningFunc', undefined);
|