@maxgraph/core
Version:
maxGraph is a fully client side JavaScript diagramming library that uses SVG and HTML for rendering.
701 lines (697 loc) • 29.6 kB
JavaScript
;
/*
Copyright 2021-present The maxGraph project Contributors
Copyright (c) 2006-2015, JGraph Ltd
Copyright (c) 2006-2015, Gaudenz Alder
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const Client_js_1 = __importDefault(require("../../../Client.js"));
const Constants_js_1 = require("../../../util/Constants.js");
const mathUtils_js_1 = require("../../../util/mathUtils.js");
const styleUtils_js_1 = require("../../../util/styleUtils.js");
const Point_js_1 = __importDefault(require("../../geometry/Point.js"));
const Shape_js_1 = __importDefault(require("../Shape.js"));
const Rectangle_js_1 = __importDefault(require("../../geometry/Rectangle.js"));
const StringUtils_js_1 = require("../../../util/StringUtils.js");
const domUtils_js_1 = require("../../../util/domUtils.js");
const SvgCanvas2D_js_1 = __importDefault(require("../../canvas/SvgCanvas2D.js"));
const utils_js_1 = require("../../../internal/utils.js");
/**
* Extends {@link Shape} to implement a text shape.
*
* This shape is **NOT** registered in {@link CellRenderer} when using {@link Graph} or calling {@link registerDefaultShapes}.
*
* To change vertical text from "bottom to top" to "top to bottom", the following code can be used:
* ```javascript
* TextShape.prototype.verticalTextRotation = 90;
* ```
*
* @category Vertex Shapes
*/
class TextShape extends Shape_js_1.default {
constructor(value, bounds, align = 'center', valign = 'middle', color = 'black', family = Constants_js_1.DEFAULT_FONTFAMILY, size = Constants_js_1.DEFAULT_FONTSIZE, fontStyle = Constants_js_1.DEFAULT_FONTSTYLE, spacing = 2, spacingTop = 0, spacingRight = 0, spacingBottom = 0, spacingLeft = 0, horizontal = true, background = Constants_js_1.NONE, border = Constants_js_1.NONE, wrap = false, clipped = false, overflow = 'visible', labelPadding = 0, textDirection = Constants_js_1.DEFAULT_TEXT_DIRECTION) {
super();
this.margin = null;
this.unrotatedBoundingBox = null;
this.flipH = false;
this.flipV = false;
/**
* Specifies the spacing to be added to the top spacing. Default is 0. Use the
* value 5 here to get the same label positions as in mxGraph 1.x.
*/
this.baseSpacingTop = 0;
/**
* Specifies the spacing to be added to the bottom spacing. Default is 0. Use the
* value 1 here to get the same label positions as in mxGraph 1.x.
*/
this.baseSpacingBottom = 0;
/**
* Specifies the spacing to be added to the left spacing. Default is 0.
*/
this.baseSpacingLeft = 0;
/**
* Specifies the spacing to be added to the right spacing. Default is 0.
*/
this.baseSpacingRight = 0;
/**
* Specifies if linefeeds in HTML labels should be replaced with BR tags.
* Default is true.
*/
this.replaceLinefeeds = true;
/**
* Rotation for vertical text. Default is -90 (bottom to top).
*/
this.verticalTextRotation = -90;
/**
* Specifies if the string size should be measured in <updateBoundingBox> if
* the label is clipped and the label position is center and middle. If this is
* true, then the bounding box will be set to <bounds>. Default is true.
* <ignoreStringSize> has precedence over this switch.
*/
this.ignoreClippedStringSize = true;
/**
* Specifies if the actual string size should be measured. If disabled the
* boundingBox will not ignore the actual size of the string, otherwise
* <bounds> will be used instead. Default is false.
*/
this.ignoreStringSize = false;
/**
* Contains the last rendered text value. Used for caching.
*/
this.lastValue = null;
/**
* Specifies if caching for HTML labels should be enabled. Default is true.
*/
this.cacheEnabled = true;
this.value = value;
this.bounds = bounds;
this.color = color ?? 'black';
this.align = align ?? 'center';
this.valign = valign ?? 'middle';
this.family = family ?? Constants_js_1.DEFAULT_FONTFAMILY;
this.size = size ?? Constants_js_1.DEFAULT_FONTSIZE;
this.fontStyle = fontStyle ?? Constants_js_1.DEFAULT_FONTSTYLE;
this.spacing = spacing ?? 2;
this.spacingTop = this.spacing + (spacingTop ?? 0);
this.spacingRight = this.spacing + (spacingRight ?? 0);
this.spacingBottom = this.spacing + (spacingBottom ?? 0);
this.spacingLeft = this.spacing + (spacingLeft ?? 0);
this.horizontal = horizontal ?? true;
this.background = background;
this.border = border;
this.wrap = wrap ?? false;
this.clipped = clipped ?? false;
this.overflow = overflow ?? 'visible';
this.labelPadding = labelPadding ?? 0;
this.textDirection = textDirection;
this.rotation = 0;
this.updateMargin();
}
/**
* Disables offset in IE9 for crisper image output.
*/
getSvgScreenOffset() {
return 0;
}
/**
* Returns true if the bounds are not null and all of its variables are numeric.
*/
checkBounds() {
return (!isNaN(this.scale) &&
isFinite(this.scale) &&
this.scale > 0 &&
this.bounds &&
!isNaN(this.bounds.x) &&
!isNaN(this.bounds.y) &&
!isNaN(this.bounds.width) &&
!isNaN(this.bounds.height));
}
/**
* Generic rendering code.
*/
paint(c, update = false) {
// Scale is passed-through to canvas
const s = this.scale;
const x = this.bounds.x / s;
const y = this.bounds.y / s;
const w = this.bounds.width / s;
const h = this.bounds.height / s;
this.updateTransform(c, x, y, w, h);
this.configureCanvas(c, x, y, w, h);
if (update) {
c.updateText(x, y, w, h, this.align, this.valign, this.wrap, this.overflow, this.clipped, this.getTextRotation(), this.node);
}
else {
// Checks if text contains HTML markup
const realHtml = (0, domUtils_js_1.isNode)(this.value) || this.dialect === 'strictHtml';
// Always renders labels as HTML in VML
const fmt = realHtml ? 'html' : '';
let val = this.value;
if (!realHtml && fmt === 'html') {
// @ts-ignore
val = (0, StringUtils_js_1.htmlEntities)(val, false);
}
if (fmt === 'html' && !(0, domUtils_js_1.isNode)(this.value)) {
val = (0, StringUtils_js_1.replaceTrailingNewlines)(val, '<div><br></div>');
}
// Handles trailing newlines to make sure they are visible in rendering output
val =
!(0, domUtils_js_1.isNode)(this.value) && this.replaceLinefeeds && fmt === 'html'
? val.replace(/\n/g, '<br/>')
: val;
let dir = this.textDirection;
if (dir === 'auto' && !realHtml) {
dir = this.getAutoDirection();
}
if (dir !== 'ltr' && dir !== 'rtl') {
dir = '';
}
c.text(x, y, w, h, val, this.align, this.valign, this.wrap, fmt, this.overflow, this.clipped, this.getTextRotation(), dir);
}
}
/**
* Renders the text using the given DOM nodes.
*/
redraw() {
if (this.visible &&
this.checkBounds() &&
this.cacheEnabled &&
this.lastValue === this.value &&
((0, domUtils_js_1.isNode)(this.value) || this.dialect === 'strictHtml')) {
if (this.node.nodeName === 'DIV') {
this.redrawHtmlShape();
this.updateBoundingBox();
}
else {
const canvas = this.createCanvas();
if (canvas) {
// Specifies if events should be handled
canvas.pointerEvents = this.pointerEvents;
this.paint(canvas, true);
this.destroyCanvas(canvas);
this.updateBoundingBox();
}
}
}
else {
super.redraw();
if ((0, domUtils_js_1.isNode)(this.value) || this.dialect === 'strictHtml') {
this.lastValue = this.value;
}
else {
this.lastValue = null;
}
}
}
/**
* Resets all styles.
*/
resetStyles() {
super.resetStyles();
this.color = 'black';
this.align = 'center';
this.valign = 'middle';
this.family = Constants_js_1.DEFAULT_FONTFAMILY;
this.size = Constants_js_1.DEFAULT_FONTSIZE;
this.fontStyle = Constants_js_1.DEFAULT_FONTSTYLE;
this.spacing = 2;
this.spacingTop = 2;
this.spacingRight = 2;
this.spacingBottom = 2;
this.spacingLeft = 2;
this.horizontal = true;
this.background = Constants_js_1.NONE;
this.border = Constants_js_1.NONE;
this.textDirection = Constants_js_1.DEFAULT_TEXT_DIRECTION;
this.margin = null;
}
/**
* Extends mxShape to update the text styles.
*
* @param state <CellState> of the corresponding cell.
*/
apply(state) {
const old = this.spacing;
super.apply(state);
if (this.style) {
this.fontStyle = this.style.fontStyle ?? this.fontStyle;
this.family = this.style.fontFamily ?? this.family;
this.size = this.style.fontSize ?? this.size;
this.color = this.style.fontColor ?? this.color;
this.align = this.style.align ?? this.align;
this.valign = this.style.verticalAlign ?? this.valign;
this.spacing = this.style.spacing ?? this.spacing;
this.spacingTop = (this.style.spacingTop ?? this.spacingTop - old) + this.spacing;
this.spacingRight =
(this.style.spacingRight ?? this.spacingRight - old) + this.spacing;
this.spacingBottom =
(this.style.spacingBottom ?? this.spacingBottom - old) + this.spacing;
this.spacingLeft =
(this.style.spacingLeft ?? this.spacingLeft - old) + this.spacing;
this.horizontal = this.style.horizontal ?? this.horizontal;
this.background = this.style.labelBackgroundColor ?? this.background;
this.border = this.style.labelBorderColor ?? this.border;
this.textDirection = this.style.textDirection ?? Constants_js_1.DEFAULT_TEXT_DIRECTION;
this.opacity = this.style.textOpacity ?? 100;
this.updateMargin();
}
this.flipV = false;
this.flipH = false;
}
/**
* Used to determine the automatic text direction.
*
* Returns 'ltr' or 'rtl' depending on the contents of {@link value}.
*
* This is not invoked for HTML, wrapped content or if {@link value} is a DOM node.
*/
getAutoDirection() {
// Looks for strong (directional) characters
const tmp = /[A-Za-z\u05d0-\u065f\u066a-\u06ef\u06fa-\u07ff\ufb1d-\ufdff\ufe70-\ufefc]/.exec(String(this.value));
// Returns the direction defined by the character
return tmp && tmp.length > 0 && tmp[0] > 'z' ? 'rtl' : 'ltr';
}
/**
* Returns the node that contains the rendered input.
*/
getContentNode() {
let result = this.node;
if (result) {
// Rendered with no foreignObject
if (!result.ownerSVGElement) {
// @ts-ignore
result = this.node.firstChild.firstChild;
}
else {
// Innermost DIV that contains the actual content
// @ts-ignore
result = result.firstChild.firstChild.firstChild.firstChild.firstChild;
}
}
return result;
}
/**
* Updates the <boundingBox> for this shape using the given node and position.
*/
updateBoundingBox() {
let { node } = this;
this.boundingBox = this.bounds.clone();
const rot = this.getTextRotation();
const h = this.style?.labelPosition ?? 'center';
const v = this.style?.verticalLabelPosition ?? 'middle';
if (!this.ignoreStringSize &&
node &&
this.overflow !== 'fill' &&
(!this.clipped || !this.ignoreClippedStringSize || h !== 'center' || v !== 'middle')) {
let ow = null;
let oh = null;
if (node.firstChild &&
node.firstChild.firstChild &&
node.firstChild.firstChild.nodeName === 'foreignObject') {
// Uses second inner DIV for font metrics
// @ts-ignore
node = node.firstChild.firstChild.firstChild.firstChild;
// @ts-ignore
oh = node.offsetHeight * this.scale;
if (this.overflow === 'width') {
ow = this.boundingBox.width;
}
else {
// @ts-ignore
ow = node.offsetWidth * this.scale;
}
}
else {
try {
const b = node.getBBox();
// Workaround for bounding box of empty string
if (typeof this.value === 'string' && (0, StringUtils_js_1.trim)(this.value)?.length === 0) {
this.boundingBox = null;
}
else if (b.width === 0 && b.height === 0) {
this.boundingBox = null;
}
else {
this.boundingBox = new Rectangle_js_1.default(b.x, b.y, b.width, b.height);
}
return;
}
catch (e) {
// Ignores NS_ERROR_FAILURE in FF if container display is none.
}
}
if (ow && oh) {
this.boundingBox = new Rectangle_js_1.default(this.bounds.x, this.bounds.y, ow, oh);
}
}
if (this.boundingBox) {
const margin = this.margin;
if (rot !== 0) {
// Accounts for pre-rotated x and y
const bbox = ((0, mathUtils_js_1.getBoundingBox)(new Rectangle_js_1.default(margin.x * this.boundingBox.width, margin.y * this.boundingBox.height, this.boundingBox.width, this.boundingBox.height), rot, new Point_js_1.default(0, 0)));
this.unrotatedBoundingBox = Rectangle_js_1.default.fromRectangle(this.boundingBox);
this.unrotatedBoundingBox.x += margin.x * this.unrotatedBoundingBox.width;
this.unrotatedBoundingBox.y += margin.y * this.unrotatedBoundingBox.height;
this.boundingBox.x += bbox.x;
this.boundingBox.y += bbox.y;
this.boundingBox.width = bbox.width;
this.boundingBox.height = bbox.height;
}
else {
this.boundingBox.x += margin.x * this.boundingBox.width;
this.boundingBox.y += margin.y * this.boundingBox.height;
this.unrotatedBoundingBox = null;
}
}
}
/**
* Returns 0 to avoid using rotation in the canvas via updateTransform.
*/
getShapeRotation() {
return 0;
}
/**
* Returns the rotation for the text label of the corresponding shape.
*/
getTextRotation() {
return this.state && this.state.shape ? this.state.shape.getTextRotation() : 0;
}
/**
* Inverts the bounds if {@link Shape#isBoundsInverted} returns true or if the
* horizontal style is false.
*/
isPaintBoundsInverted() {
return !this.horizontal && !!this.state && this.state.cell.isVertex();
}
/**
* Sets the state of the canvas for drawing the shape.
*/
configureCanvas(c, x, y, w, h) {
super.configureCanvas(c, x, y, w, h);
c.setFontColor(this.color);
c.setFontBackgroundColor(this.background);
c.setFontBorderColor(this.border);
c.setFontFamily(this.family);
c.setFontSize(this.size);
c.setFontStyle(this.fontStyle);
}
/**
* Private helper function to create SVG elements
*/
getHtmlValue() {
let val = this.value;
if (this.dialect !== 'strictHtml') {
val = (0, StringUtils_js_1.htmlEntities)(val, false);
}
// Handles trailing newlines to make sure they are visible in rendering output
val = (0, StringUtils_js_1.replaceTrailingNewlines)(val, '<div><br></div>');
val = this.replaceLinefeeds ? val.replace(/\n/g, '<br/>') : val;
return val;
}
/**
* Private helper function to create SVG elements
*/
getTextCss() {
const lh = Constants_js_1.ABSOLUTE_LINE_HEIGHT ? `${this.size * Constants_js_1.LINE_HEIGHT}px` : Constants_js_1.LINE_HEIGHT;
let css = `display: inline-block; font-size: ${this.size}px; ` +
`font-family: ${this.family}; color: ${this.color}; line-height: ${lh}; pointer-events: ${this.pointerEvents ? 'all' : 'none'}; `;
(0, utils_js_1.matchBinaryMask)(this.fontStyle, Constants_js_1.FONT_STYLE_MASK.BOLD) &&
(css += 'font-weight: bold; ');
(0, utils_js_1.matchBinaryMask)(this.fontStyle, Constants_js_1.FONT_STYLE_MASK.ITALIC) &&
(css += 'font-style: italic; ');
const txtDecor = [];
(0, utils_js_1.matchBinaryMask)(this.fontStyle, Constants_js_1.FONT_STYLE_MASK.UNDERLINE) &&
txtDecor.push('underline');
(0, utils_js_1.matchBinaryMask)(this.fontStyle, Constants_js_1.FONT_STYLE_MASK.STRIKETHROUGH) &&
txtDecor.push('line-through');
txtDecor.length > 0 && (css += `text-decoration: ${txtDecor.join(' ')}; `);
return css;
}
/**
* Updates the HTML node(s) to reflect the latest bounds and scale.
*/
redrawHtmlShape() {
const w = Math.max(0, Math.round(this.bounds.width / this.scale));
const h = Math.max(0, Math.round(this.bounds.height / this.scale));
const flex = `position: absolute; left: ${Math.round(this.bounds.x)}px; ` +
`top: ${Math.round(this.bounds.y)}px; pointer-events: none; `;
const block = this.getTextCss();
const margin = this.margin;
const node = this.node;
SvgCanvas2D_js_1.default.createCss(w + 2, h, this.align, this.valign, this.wrap, this.overflow, this.clipped, this.background !== Constants_js_1.NONE ? (0, StringUtils_js_1.htmlEntities)(this.background, true) : null, this.border !== Constants_js_1.NONE ? (0, StringUtils_js_1.htmlEntities)(this.border, true) : null, flex, block, this.scale, (dx, dy, flex, item, block, ofl) => {
const r = this.getTextRotation();
let tr = (this.scale !== 1 ? `scale(${this.scale}) ` : '') +
(r !== 0 ? `rotate(${r}deg) ` : '') +
(margin.x !== 0 || margin.y !== 0
? `translate(${margin.x * 100}%,${margin.y * 100}%)`
: '');
if (tr !== '') {
tr = `transform-origin: 0 0; transform: ${tr}; `;
}
if (ofl === '') {
flex += item;
item = `display:inline-block; min-width: 100%; ${tr}`;
}
else {
item += tr;
if (Client_js_1.default.IS_SF) {
item += '-webkit-clip-path: content-box;';
}
}
if (this.opacity < 100) {
block += `opacity: ${this.opacity / 100}; `;
}
node.setAttribute('style', flex);
const html = (0, domUtils_js_1.isNode)(this.value)
? // @ts-ignore
this.value.outerHTML
: this.getHtmlValue();
if (!node.firstChild) {
node.innerHTML = `<div><div>${html}</div></div>`;
}
// @ts-ignore
node.firstChild.firstChild.setAttribute('style', block);
// @ts-ignore
node.firstChild.setAttribute('style', item);
});
}
/**
* Sets the inner HTML of the given element to the <value>.
*/
updateInnerHtml(elt) {
if ((0, domUtils_js_1.isNode)(this.value)) {
// @ts-ignore
elt.innerHTML = this.value.outerHTML;
}
else {
let val = this.value;
if (this.dialect !== 'strictHtml') {
// LATER: Can be cached in updateValue
val = (0, StringUtils_js_1.htmlEntities)(val, false);
}
// Handles trailing newlines to make sure they are visible in rendering output
val = (0, StringUtils_js_1.replaceTrailingNewlines)(val, '<div> </div>');
val = this.replaceLinefeeds ? val.replace(/\n/g, '<br/>') : val;
val = `<div style="display:inline-block;_display:inline;">${val}</div>`;
elt.innerHTML = val;
}
}
/**
* Updates the HTML node(s) to reflect the latest bounds and scale.
*/
updateValue() {
const node = this.node;
if ((0, domUtils_js_1.isNode)(this.value)) {
node.innerHTML = '';
node.appendChild(this.value);
}
else {
let val = this.value;
if (this.dialect !== 'strictHtml') {
val = (0, StringUtils_js_1.htmlEntities)(val, false);
}
// Handles trailing newlines to make sure they are visible in rendering output
val = (0, StringUtils_js_1.replaceTrailingNewlines)(val, '<div><br></div>');
val = this.replaceLinefeeds ? val.replace(/\n/g, '<br/>') : val;
const bg = this.background !== Constants_js_1.NONE ? this.background : null;
const bd = this.border !== Constants_js_1.NONE ? this.border : null;
if (this.overflow === 'fill' || this.overflow === 'width') {
if (bg) {
node.style.backgroundColor = bg;
}
if (bd) {
node.style.border = `1px solid ${bd}`;
}
}
else {
let css = '';
if (bg) {
css += `background-color:${(0, StringUtils_js_1.htmlEntities)(bg, true)};`;
}
if (bd) {
css += `border:1px solid ${(0, StringUtils_js_1.htmlEntities)(bd, true)};`;
}
// Wrapper DIV for background, zoom needed for inline in quirks
// and to measure wrapped font sizes in all browsers
// FIXME: Background size in quirks mode for wrapped text
const lh = Constants_js_1.ABSOLUTE_LINE_HEIGHT ? `${this.size * Constants_js_1.LINE_HEIGHT}px` : Constants_js_1.LINE_HEIGHT;
val =
`<div style="zoom:1;${css}display:inline-block;_display:inline;text-decoration:inherit;` +
`padding-bottom:1px;padding-right:1px;line-height:${lh}">${val}</div>`;
}
node.innerHTML = val;
// Sets text direction
const divs = node.getElementsByTagName('div');
if (divs.length > 0) {
let dir = this.textDirection;
if (dir === 'auto' && this.dialect !== 'strictHtml') {
dir = this.getAutoDirection();
}
if (dir === 'ltr' || dir === 'rtl') {
divs[divs.length - 1].setAttribute('dir', dir);
}
else {
divs[divs.length - 1].removeAttribute('dir');
}
}
}
}
/**
* Updates the HTML node(s) to reflect the latest bounds and scale.
*/
updateFont(node) {
const { style } = node;
// @ts-ignore
style.lineHeight = Constants_js_1.ABSOLUTE_LINE_HEIGHT
? `${this.size * Constants_js_1.LINE_HEIGHT}px`
: Constants_js_1.LINE_HEIGHT;
style.fontSize = `${this.size}px`;
style.fontFamily = this.family;
style.verticalAlign = 'top';
style.color = this.color;
(0, utils_js_1.matchBinaryMask)(this.fontStyle, Constants_js_1.FONT_STYLE_MASK.BOLD)
? (style.fontWeight = 'bold')
: (style.fontWeight = '');
(0, utils_js_1.matchBinaryMask)(this.fontStyle, Constants_js_1.FONT_STYLE_MASK.ITALIC)
? (style.fontStyle = 'italic')
: (style.fontStyle = '');
const txtDecor = [];
(0, utils_js_1.matchBinaryMask)(this.fontStyle, Constants_js_1.FONT_STYLE_MASK.UNDERLINE) &&
txtDecor.push('underline');
(0, utils_js_1.matchBinaryMask)(this.fontStyle, Constants_js_1.FONT_STYLE_MASK.STRIKETHROUGH) &&
txtDecor.push('line-through');
txtDecor.length > 0 && (style.textDecoration = txtDecor.join(' '));
if (this.align === 'center') {
style.textAlign = 'center';
}
else if (this.align === 'right') {
style.textAlign = 'right';
}
else {
style.textAlign = 'left';
}
}
/**
* Updates the HTML node(s) to reflect the latest bounds and scale.
*/
updateSize(node, enableWrap = false) {
const w = Math.max(0, Math.round(this.bounds.width / this.scale));
const h = Math.max(0, Math.round(this.bounds.height / this.scale));
const { style } = node;
// NOTE: Do not use maxWidth here because wrapping will
// go wrong if the cell is outside of the viewable area
if (this.clipped) {
style.overflow = 'hidden';
style.maxHeight = `${h}px`;
style.maxWidth = `${w}px`;
}
else if (this.overflow === 'fill') {
style.width = `${w + 1}px`;
style.height = `${h + 1}px`;
style.overflow = 'hidden';
}
else if (this.overflow === 'width') {
style.width = `${w + 1}px`;
style.maxHeight = `${h + 1}px`;
style.overflow = 'hidden';
}
if (this.wrap && w > 0) {
style.wordWrap = Constants_js_1.WORD_WRAP;
style.whiteSpace = 'normal';
style.width = `${w}px`;
if (enableWrap && this.overflow !== 'fill' && this.overflow !== 'width') {
let sizeDiv = node;
if (sizeDiv.firstChild != null && sizeDiv.firstChild.nodeName === 'DIV') {
// @ts-ignore
sizeDiv = sizeDiv.firstChild;
if (node.style.wordWrap === 'break-word') {
sizeDiv.style.width = '100%';
}
}
let tmp = sizeDiv.offsetWidth;
// Workaround for text measuring in hidden containers
if (tmp === 0) {
const prev = node.parentNode;
node.style.visibility = 'hidden';
document.body.appendChild(node);
tmp = sizeDiv.offsetWidth;
node.style.visibility = '';
prev.appendChild(node);
}
tmp += 3;
if (this.clipped) {
tmp = Math.min(tmp, w);
}
style.width = `${tmp}px`;
}
}
else {
style.whiteSpace = 'nowrap';
}
}
/**
* Returns the spacing as an {@link Point}.
*/
updateMargin() {
this.margin = (0, styleUtils_js_1.getAlignmentAsPoint)(this.align, this.valign);
}
/**
* Returns the spacing as an {@link Point}.
*/
getSpacing() {
let dx = 0;
let dy = 0;
if (this.align === 'center') {
dx = (this.spacingLeft - this.spacingRight) / 2;
}
else if (this.align === 'right') {
dx = -this.spacingRight - this.baseSpacingRight;
}
else {
dx = this.spacingLeft + this.baseSpacingLeft;
}
if (this.valign === 'middle') {
dy = (this.spacingTop - this.spacingBottom) / 2;
}
else if (this.valign === 'bottom') {
dy = -this.spacingBottom - this.baseSpacingBottom;
}
else {
dy = this.spacingTop + this.baseSpacingTop;
}
return new Point_js_1.default(dx, dy);
}
}
exports.default = TextShape;