@ngroznykh/papirus 0.3.7 → 0.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/papirus.js +111 -7
- package/dist/papirus.js.map +1 -1
- package/dist/utils/SvgExporter.d.ts +4 -0
- package/dist/utils/SvgExporter.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/papirus.js
CHANGED
|
@@ -8711,7 +8711,7 @@ class SvgExporter {
|
|
|
8711
8711
|
shape = `<rect x="${bounds.x}" y="${bounds.y}" width="${bounds.width}" height="${bounds.height}"`;
|
|
8712
8712
|
}
|
|
8713
8713
|
}
|
|
8714
|
-
const label =
|
|
8714
|
+
const label = this.renderNodeLabel(node, bounds);
|
|
8715
8715
|
const icon = this.renderNodeIcon(node, bounds);
|
|
8716
8716
|
return [
|
|
8717
8717
|
`${shape} fill="${fill}" fill-opacity="${fillOpacity}" stroke="${stroke}" stroke-width="${strokeWidth}" stroke-opacity="${strokeOpacity}"${dash}${dashOffset}/>`,
|
|
@@ -8727,14 +8727,72 @@ class SvgExporter {
|
|
|
8727
8727
|
const style = edge.style;
|
|
8728
8728
|
const stroke = style.strokeColor ?? "#666666";
|
|
8729
8729
|
const strokeWidth = style.strokeWidth ?? 2;
|
|
8730
|
-
const
|
|
8730
|
+
const strokeOpacity = (style.strokeOpacity ?? 1) * (style.opacity ?? 1);
|
|
8731
|
+
const lineCap = style.lineCap ? ` stroke-linecap="${style.lineCap}"` : "";
|
|
8732
|
+
const lineJoin = style.lineJoin ? ` stroke-linejoin="${style.lineJoin}"` : "";
|
|
8731
8733
|
const dashValues = style.flowDash ?? style.lineDash;
|
|
8732
8734
|
const dash = dashValues ? ` stroke-dasharray="${dashValues.join(" ")}"` : "";
|
|
8733
8735
|
const dashOffset = style.lineDashOffset !== void 0 ? ` stroke-dashoffset="${style.lineDashOffset}"` : "";
|
|
8734
8736
|
const d = this.buildPath(edge);
|
|
8735
8737
|
const markerShapes = this.renderEdgeMarkers(edge, stroke);
|
|
8736
|
-
const label =
|
|
8737
|
-
return `<path d="${d}" fill="none" stroke="${stroke}" stroke-width="${strokeWidth}" opacity="${
|
|
8738
|
+
const label = this.renderEdgeLabel(edge, edgeLabelOffset);
|
|
8739
|
+
return `<path d="${d}" fill="none" stroke="${stroke}" stroke-width="${strokeWidth}" stroke-opacity="${strokeOpacity}" color="${stroke}"${lineCap}${lineJoin}${dash}${dashOffset}/>${markerShapes}${label}`;
|
|
8740
|
+
}
|
|
8741
|
+
renderEdgeLabel(edge, edgeLabelOffset) {
|
|
8742
|
+
if (!edge.label) {
|
|
8743
|
+
return "";
|
|
8744
|
+
}
|
|
8745
|
+
const labelPoint = this.getEdgeLabelPoint(edge, edgeLabelOffset);
|
|
8746
|
+
const text = this.renderTextLabel(edge.label.text, labelPoint, edge.label.style);
|
|
8747
|
+
const bg = this.renderEdgeLabelBackground(edge, labelPoint);
|
|
8748
|
+
return `${bg}${text}`;
|
|
8749
|
+
}
|
|
8750
|
+
renderEdgeLabelBackground(edge, point) {
|
|
8751
|
+
if (!edge.label) {
|
|
8752
|
+
return "";
|
|
8753
|
+
}
|
|
8754
|
+
const metrics = this.measureTextLabel(edge.label.text, edge.label.style, edge.label.padding, edge.label.margin);
|
|
8755
|
+
const bgPadding = edge.labelBackground?.padding ?? EDGE_LABEL_BACKGROUND_PADDING;
|
|
8756
|
+
const bgColor = edge.labelBackground?.color ?? "#ffffff";
|
|
8757
|
+
const bgOpacity = edge.labelBackground?.opacity ?? 1;
|
|
8758
|
+
const bgRadius = edge.labelBackground?.borderRadius ?? EDGE_LABEL_BACKGROUND_RADIUS;
|
|
8759
|
+
const x = point.x - metrics.width / 2 - bgPadding;
|
|
8760
|
+
const y = point.y - metrics.height / 2 - bgPadding;
|
|
8761
|
+
const width = metrics.width + bgPadding * 2;
|
|
8762
|
+
const height = metrics.height + bgPadding * 2;
|
|
8763
|
+
const radius = Math.max(0, Math.min(bgRadius, width / 2, height / 2));
|
|
8764
|
+
if (radius <= 0) {
|
|
8765
|
+
return `<rect x="${x}" y="${y}" width="${width}" height="${height}" fill="${bgColor}" fill-opacity="${bgOpacity}"/>`;
|
|
8766
|
+
}
|
|
8767
|
+
return `<rect x="${x}" y="${y}" width="${width}" height="${height}" rx="${radius}" ry="${radius}" fill="${bgColor}" fill-opacity="${bgOpacity}"/>`;
|
|
8768
|
+
}
|
|
8769
|
+
measureTextLabel(text, style = {}, padding = 8, margin = 0) {
|
|
8770
|
+
const fontSize = style.fontSize ?? 14;
|
|
8771
|
+
const fontFamily = style.fontFamily ?? "sans-serif";
|
|
8772
|
+
const fontWeight = style.fontWeight ?? "normal";
|
|
8773
|
+
const lineHeight = fontSize * 1.2;
|
|
8774
|
+
const lines = text.split("\n");
|
|
8775
|
+
let maxWidth = 0;
|
|
8776
|
+
if (typeof document !== "undefined") {
|
|
8777
|
+
const canvas = document.createElement("canvas");
|
|
8778
|
+
const ctx = canvas.getContext("2d");
|
|
8779
|
+
if (ctx) {
|
|
8780
|
+
ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;
|
|
8781
|
+
for (const line of lines) {
|
|
8782
|
+
maxWidth = Math.max(maxWidth, ctx.measureText(line).width);
|
|
8783
|
+
}
|
|
8784
|
+
}
|
|
8785
|
+
}
|
|
8786
|
+
if (maxWidth === 0) {
|
|
8787
|
+
const longestLine = lines.reduce((max, line) => line.length > max.length ? line : max, "");
|
|
8788
|
+
maxWidth = longestLine.length * fontSize * 0.6;
|
|
8789
|
+
}
|
|
8790
|
+
const resolvedPadding = Math.max(0, padding);
|
|
8791
|
+
const resolvedMargin = Math.max(0, margin);
|
|
8792
|
+
return {
|
|
8793
|
+
width: maxWidth + resolvedPadding * 2 + resolvedMargin * 2,
|
|
8794
|
+
height: lines.length * lineHeight + resolvedPadding * 2 + resolvedMargin * 2
|
|
8795
|
+
};
|
|
8738
8796
|
}
|
|
8739
8797
|
resolveMarkerConfig(edge, side) {
|
|
8740
8798
|
const marker = side === "start" ? edge.startMarker : edge.endMarker;
|
|
@@ -8905,9 +8963,55 @@ class SvgExporter {
|
|
|
8905
8963
|
const opacity = style.opacity ?? 1;
|
|
8906
8964
|
const anchor = style.align === "left" ? "start" : style.align === "right" ? "end" : "middle";
|
|
8907
8965
|
const baseline = style.baseline === "top" ? "text-before-edge" : style.baseline === "bottom" ? "text-after-edge" : "middle";
|
|
8908
|
-
|
|
8909
|
-
|
|
8910
|
-
|
|
8966
|
+
const lines = text.split("\n");
|
|
8967
|
+
if (lines.length <= 1) {
|
|
8968
|
+
return `<text x="${point.x}" y="${point.y}" fill="${fill}" fill-opacity="${opacity}" font-size="${fontSize}" font-family="${fontFamily}" font-weight="${fontWeight}" text-anchor="${anchor}" dominant-baseline="${baseline}">${this.escapeText(
|
|
8969
|
+
text
|
|
8970
|
+
)}</text>`;
|
|
8971
|
+
}
|
|
8972
|
+
const lineHeight = fontSize * 1.2;
|
|
8973
|
+
const startY = point.y - (lines.length - 1) * lineHeight / 2;
|
|
8974
|
+
const tspans = lines.map((line, index) => `<tspan x="${point.x}" y="${startY + index * lineHeight}">${this.escapeText(line)}</tspan>`).join("");
|
|
8975
|
+
return `<text x="${point.x}" y="${point.y}" fill="${fill}" fill-opacity="${opacity}" font-size="${fontSize}" font-family="${fontFamily}" font-weight="${fontWeight}" text-anchor="${anchor}" dominant-baseline="${baseline}">${tspans}</text>`;
|
|
8976
|
+
}
|
|
8977
|
+
renderNodeLabel(node, bounds) {
|
|
8978
|
+
const label = node.label;
|
|
8979
|
+
if (!label) {
|
|
8980
|
+
return "";
|
|
8981
|
+
}
|
|
8982
|
+
const style = label.style;
|
|
8983
|
+
const fontSize = style.fontSize ?? 14;
|
|
8984
|
+
const lineHeight = fontSize * 1.2;
|
|
8985
|
+
const lines = label.text.split("\n");
|
|
8986
|
+
const textHeight = Math.max(lineHeight, lines.length * lineHeight);
|
|
8987
|
+
const padding = Math.max(0, label.padding);
|
|
8988
|
+
const margin = Math.max(0, label.margin);
|
|
8989
|
+
const inset = padding + margin;
|
|
8990
|
+
const align = style.align ?? "center";
|
|
8991
|
+
const placement = node.labelPlacement === "auto" ? "center" : node.labelPlacement;
|
|
8992
|
+
const inner = {
|
|
8993
|
+
x: bounds.x + margin,
|
|
8994
|
+
y: bounds.y + margin,
|
|
8995
|
+
width: Math.max(0, bounds.width - margin * 2),
|
|
8996
|
+
height: Math.max(0, bounds.height - margin * 2)
|
|
8997
|
+
};
|
|
8998
|
+
let x = inner.x + inner.width / 2;
|
|
8999
|
+
if (align === "left") {
|
|
9000
|
+
x = inner.x + inset;
|
|
9001
|
+
} else if (align === "right") {
|
|
9002
|
+
x = inner.x + inner.width - inset;
|
|
9003
|
+
}
|
|
9004
|
+
let y = inner.y + inner.height / 2;
|
|
9005
|
+
if (placement === "top") {
|
|
9006
|
+
y = inner.y + inset + textHeight / 2;
|
|
9007
|
+
} else if (placement === "bottom") {
|
|
9008
|
+
y = inner.y + inner.height - inset - textHeight / 2;
|
|
9009
|
+
} else if (placement === "left") {
|
|
9010
|
+
x = inner.x + inset;
|
|
9011
|
+
} else if (placement === "right") {
|
|
9012
|
+
x = inner.x + inner.width - inset;
|
|
9013
|
+
}
|
|
9014
|
+
return this.renderTextLabel(label.text, { x, y }, style);
|
|
8911
9015
|
}
|
|
8912
9016
|
getNodeCornerRadius(node, bounds) {
|
|
8913
9017
|
const rectangleRadius = "cornerRadius" in node && typeof node.cornerRadius === "number" ? node.cornerRadius ?? 0 : node.style.cornerRadius ?? 0;
|