diff --git a/packages/victory-core/src/victory-util/textsize.ts b/packages/victory-core/src/victory-util/textsize.ts
index d7d2e80a3..01a40db03 100644
--- a/packages/victory-core/src/victory-util/textsize.ts
+++ b/packages/victory-core/src/victory-util/textsize.ts
@@ -1,6 +1,6 @@
// http://www.pearsonified.com/2012/01/characters-per-line.php
/* eslint-disable no-magic-numbers */
-import { assign, defaults } from "lodash";
+import { assign, defaults, memoize } from "lodash";
// Based on measuring specific character widths
// as in the following example https://bl.ocks.org/tophtucker/62f93a4658387bb61e4510c37e2e97cf
@@ -243,6 +243,77 @@ const _approximateTextHeightInternal = (text: string | string[], style) => {
}, 0);
};
+const _approximateDimensionsInternal = (
+ text: string | string[],
+ style?: TextSizeStyleInterface,
+) => {
+ const angle = Array.isArray(style)
+ ? style[0] && style[0].angle
+ : style && style.angle;
+ const height = _approximateTextHeightInternal(text, style);
+ const width = _approximateTextWidthInternal(text, style);
+ const widthWithRotate = angle
+ ? _getSizeWithRotate(width, height, angle)
+ : width;
+ const heightWithRotate = angle
+ ? _getSizeWithRotate(height, width, angle)
+ : height;
+ return {
+ width: widthWithRotate,
+ height: heightWithRotate * coefficients.heightOverlapCoef,
+ };
+};
+
+const _getMeasurementContainer = memoize(() => {
+ const element = document.createElementNS("http://www.w3.org/2000/svg", "svg");
+ element.setAttribute("xlink", "http://www.w3.org/1999/xlink");
+
+ const containerElement = document.createElementNS(
+ "http://www.w3.org/2000/svg",
+ "text",
+ );
+ element.appendChild(containerElement);
+
+ element.style.position = "fixed";
+ element.style.top = "-9999px";
+ element.style.left = "-9999px";
+
+ document.body.appendChild(element);
+
+ return containerElement;
+});
+
+const _measureDimensionsInternal = (
+ text: string | string[],
+ style?: TextSizeStyleInterface,
+) => {
+ const containerElement = _getMeasurementContainer();
+
+ const lines = _splitToLines(text);
+ for (const [i, line] of lines.entries()) {
+ const textElement = document.createElementNS(
+ "http://www.w3.org/2000/svg",
+ "tspan",
+ );
+ const params = _prepareParams(style, i);
+ textElement.style.fontFamily = params.fontFamily;
+ textElement.style.transform = `rotate(${params.angle})`;
+ textElement.style.fontSize = `${params.fontSize}px`;
+ textElement.style.lineHeight = params.lineHeight;
+ textElement.style.fontFamily = params.fontFamily;
+ textElement.style.letterSpacing = params.letterSpacing;
+ textElement.textContent = line;
+
+ containerElement.appendChild(textElement);
+ }
+
+ const { width, height } = containerElement.getBoundingClientRect();
+
+ containerElement.innerHTML = "";
+
+ return { width, height };
+};
+
export interface TextSizeStyleInterface {
angle?: number;
characterConstant?: string;
@@ -255,21 +326,18 @@ export interface TextSizeStyleInterface {
// Stubbable implementation.
export const _approximateTextSizeInternal = {
impl: (text: string | string[], style?: TextSizeStyleInterface) => {
- const angle = Array.isArray(style)
- ? style[0] && style[0].angle
- : style && style.angle;
- const height = _approximateTextHeightInternal(text, style);
- const width = _approximateTextWidthInternal(text, style);
- const widthWithRotate = angle
- ? _getSizeWithRotate(width, height, angle)
- : width;
- const heightWithRotate = angle
- ? _getSizeWithRotate(height, width, angle)
- : height;
- return {
- width: widthWithRotate,
- height: heightWithRotate * coefficients.heightOverlapCoef,
- };
+ // Attempt to first measure the element in DOM. If there is no DOM, fallback
+ // to the less accurate approximation algorithm.
+ const isClient =
+ typeof window !== "undefined" &&
+ typeof window.document !== "undefined" &&
+ typeof window.document.createElement !== "undefined";
+
+ if (!isClient) {
+ return _approximateDimensionsInternal(text, style);
+ }
+
+ return _measureDimensionsInternal(text, style);
},
};
diff --git a/stories/victory-label.stories.js b/stories/victory-label.stories.js
index 322c92b9f..66b094861 100644
--- a/stories/victory-label.stories.js
+++ b/stories/victory-label.stories.js
@@ -415,6 +415,30 @@ export const LineHeight = () => {
/>
}
/>
+
+ }
+ />
+
+ }
+ />
);
};