|
|
@ -14,7 +14,13 @@ import { Drawable, Options } from "roughjs/bin/core";
|
|
|
|
import { RoughSVG } from "roughjs/bin/svg";
|
|
|
|
import { RoughSVG } from "roughjs/bin/svg";
|
|
|
|
import { RoughGenerator } from "roughjs/bin/generator";
|
|
|
|
import { RoughGenerator } from "roughjs/bin/generator";
|
|
|
|
import { SceneState } from "../scene/types";
|
|
|
|
import { SceneState } from "../scene/types";
|
|
|
|
import { SVG_NS, distance, getFontString, getFontFamilyString } from "../utils";
|
|
|
|
import {
|
|
|
|
|
|
|
|
SVG_NS,
|
|
|
|
|
|
|
|
distance,
|
|
|
|
|
|
|
|
getFontString,
|
|
|
|
|
|
|
|
getFontFamilyString,
|
|
|
|
|
|
|
|
isRTL,
|
|
|
|
|
|
|
|
} from "../utils";
|
|
|
|
import { isPathALoop } from "../math";
|
|
|
|
import { isPathALoop } from "../math";
|
|
|
|
import rough from "roughjs/bin/rough";
|
|
|
|
import rough from "roughjs/bin/rough";
|
|
|
|
|
|
|
|
|
|
|
@ -100,12 +106,21 @@ const drawElementOnCanvas = (
|
|
|
|
}
|
|
|
|
}
|
|
|
|
default: {
|
|
|
|
default: {
|
|
|
|
if (isTextElement(element)) {
|
|
|
|
if (isTextElement(element)) {
|
|
|
|
|
|
|
|
const rtl = isRTL(element.text);
|
|
|
|
|
|
|
|
const shouldTemporarilyAttach = rtl && !context.canvas.isConnected;
|
|
|
|
|
|
|
|
if (shouldTemporarilyAttach) {
|
|
|
|
|
|
|
|
// to correctly render RTL text mixed with LTR, we have to append it
|
|
|
|
|
|
|
|
// to the DOM
|
|
|
|
|
|
|
|
document.body.appendChild(context.canvas);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
context.canvas.setAttribute("dir", rtl ? "rtl" : "ltr");
|
|
|
|
const font = context.font;
|
|
|
|
const font = context.font;
|
|
|
|
context.font = getFontString(element);
|
|
|
|
context.font = getFontString(element);
|
|
|
|
const fillStyle = context.fillStyle;
|
|
|
|
const fillStyle = context.fillStyle;
|
|
|
|
context.fillStyle = element.strokeColor;
|
|
|
|
context.fillStyle = element.strokeColor;
|
|
|
|
const textAlign = context.textAlign;
|
|
|
|
const textAlign = context.textAlign;
|
|
|
|
context.textAlign = element.textAlign as CanvasTextAlign;
|
|
|
|
context.textAlign = element.textAlign as CanvasTextAlign;
|
|
|
|
|
|
|
|
|
|
|
|
// Canvas does not support multiline text by default
|
|
|
|
// Canvas does not support multiline text by default
|
|
|
|
const lines = element.text.replace(/\r\n?/g, "\n").split("\n");
|
|
|
|
const lines = element.text.replace(/\r\n?/g, "\n").split("\n");
|
|
|
|
const lineHeight = element.height / lines.length;
|
|
|
|
const lineHeight = element.height / lines.length;
|
|
|
@ -119,13 +134,16 @@ const drawElementOnCanvas = (
|
|
|
|
for (let i = 0; i < lines.length; i++) {
|
|
|
|
for (let i = 0; i < lines.length; i++) {
|
|
|
|
context.fillText(
|
|
|
|
context.fillText(
|
|
|
|
lines[i],
|
|
|
|
lines[i],
|
|
|
|
0 + horizontalOffset,
|
|
|
|
horizontalOffset,
|
|
|
|
(i + 1) * lineHeight - verticalOffset,
|
|
|
|
(i + 1) * lineHeight - verticalOffset,
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
context.fillStyle = fillStyle;
|
|
|
|
context.fillStyle = fillStyle;
|
|
|
|
context.font = font;
|
|
|
|
context.font = font;
|
|
|
|
context.textAlign = textAlign;
|
|
|
|
context.textAlign = textAlign;
|
|
|
|
|
|
|
|
if (shouldTemporarilyAttach) {
|
|
|
|
|
|
|
|
context.canvas.remove();
|
|
|
|
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
throw new Error(`Unimplemented type ${element.type}`);
|
|
|
|
throw new Error(`Unimplemented type ${element.type}`);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -342,6 +360,8 @@ const drawElementFromCanvas = (
|
|
|
|
context.rotate(-element.angle);
|
|
|
|
context.rotate(-element.angle);
|
|
|
|
context.translate(-cx, -cy);
|
|
|
|
context.translate(-cx, -cy);
|
|
|
|
context.scale(window.devicePixelRatio, window.devicePixelRatio);
|
|
|
|
context.scale(window.devicePixelRatio, window.devicePixelRatio);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Clear the nested element we appended to the DOM
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
export const renderElement = (
|
|
|
|
export const renderElement = (
|
|
|
@ -375,9 +395,12 @@ export const renderElement = (
|
|
|
|
case "draw":
|
|
|
|
case "draw":
|
|
|
|
case "arrow":
|
|
|
|
case "arrow":
|
|
|
|
case "text": {
|
|
|
|
case "text": {
|
|
|
|
const elementWithCanvas = generateElement(element, generator, sceneState);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (renderOptimizations) {
|
|
|
|
if (renderOptimizations) {
|
|
|
|
|
|
|
|
const elementWithCanvas = generateElement(
|
|
|
|
|
|
|
|
element,
|
|
|
|
|
|
|
|
generator,
|
|
|
|
|
|
|
|
sceneState,
|
|
|
|
|
|
|
|
);
|
|
|
|
drawElementFromCanvas(elementWithCanvas, rc, context, sceneState);
|
|
|
|
drawElementFromCanvas(elementWithCanvas, rc, context, sceneState);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
|
|
|
|
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
|
|
|
@ -492,10 +515,11 @@ export const renderElementToSvg = (
|
|
|
|
: element.textAlign === "right"
|
|
|
|
: element.textAlign === "right"
|
|
|
|
? element.width
|
|
|
|
? element.width
|
|
|
|
: 0;
|
|
|
|
: 0;
|
|
|
|
|
|
|
|
const direction = isRTL(element.text) ? "rtl" : "ltr";
|
|
|
|
const textAnchor =
|
|
|
|
const textAnchor =
|
|
|
|
element.textAlign === "center"
|
|
|
|
element.textAlign === "center"
|
|
|
|
? "middle"
|
|
|
|
? "middle"
|
|
|
|
: element.textAlign === "right"
|
|
|
|
: element.textAlign === "right" || direction === "rtl"
|
|
|
|
? "end"
|
|
|
|
? "end"
|
|
|
|
: "start";
|
|
|
|
: "start";
|
|
|
|
for (let i = 0; i < lines.length; i++) {
|
|
|
|
for (let i = 0; i < lines.length; i++) {
|
|
|
@ -508,6 +532,7 @@ export const renderElementToSvg = (
|
|
|
|
text.setAttribute("fill", element.strokeColor);
|
|
|
|
text.setAttribute("fill", element.strokeColor);
|
|
|
|
text.setAttribute("text-anchor", textAnchor);
|
|
|
|
text.setAttribute("text-anchor", textAnchor);
|
|
|
|
text.setAttribute("style", "white-space: pre;");
|
|
|
|
text.setAttribute("style", "white-space: pre;");
|
|
|
|
|
|
|
|
text.setAttribute("direction", direction);
|
|
|
|
node.appendChild(text);
|
|
|
|
node.appendChild(text);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
svgRoot.appendChild(node);
|
|
|
|
svgRoot.appendChild(node);
|
|
|
|