@krainovsd/graph 0.14.0-beta.8 → 0.14.0-beta.9
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/lib/cjs/index.cjs +209 -0
- package/lib/cjs/index.cjs.map +1 -1
- package/lib/esm/module/GraphCanvas/GraphCanvas.js +4 -0
- package/lib/esm/module/GraphCanvas/GraphCanvas.js.map +1 -1
- package/lib/esm/module/GraphCanvas/lib/utils/svg-context.js +159 -0
- package/lib/esm/module/GraphCanvas/lib/utils/svg-context.js.map +1 -0
- package/lib/esm/module/GraphCanvas/slices/export-svg.js +63 -0
- package/lib/esm/module/GraphCanvas/slices/export-svg.js.map +1 -0
- package/lib/index.d.ts +1 -0
- package/package.json +1 -1
package/lib/cjs/index.cjs
CHANGED
|
@@ -2952,6 +2952,212 @@ function initCollideForce(forceUpdate) {
|
|
|
2952
2952
|
}
|
|
2953
2953
|
}
|
|
2954
2954
|
|
|
2955
|
+
function escapeXml(s) {
|
|
2956
|
+
return s
|
|
2957
|
+
.replace(/&/g, "&")
|
|
2958
|
+
.replace(/</g, "<")
|
|
2959
|
+
.replace(/>/g, ">")
|
|
2960
|
+
.replace(/"/g, """);
|
|
2961
|
+
}
|
|
2962
|
+
class SvgContextAdapter {
|
|
2963
|
+
parts;
|
|
2964
|
+
globalAlpha = 1;
|
|
2965
|
+
fillStyle = "black";
|
|
2966
|
+
strokeStyle = "black";
|
|
2967
|
+
lineWidth = 1;
|
|
2968
|
+
textAlign = "start";
|
|
2969
|
+
_font = "normal normal 400 12px sans-serif";
|
|
2970
|
+
fontFamily = "sans-serif";
|
|
2971
|
+
fontSize = 12;
|
|
2972
|
+
fontWeight = 400;
|
|
2973
|
+
fontStyle = "normal";
|
|
2974
|
+
stateStack = [];
|
|
2975
|
+
currentPath = [];
|
|
2976
|
+
hasPath = false;
|
|
2977
|
+
transformX = 0;
|
|
2978
|
+
transformY = 0;
|
|
2979
|
+
transformK = 1;
|
|
2980
|
+
constructor(parts) {
|
|
2981
|
+
this.parts = parts;
|
|
2982
|
+
}
|
|
2983
|
+
set font(value) {
|
|
2984
|
+
this._font = value;
|
|
2985
|
+
const p = value.trim().split(/\s+/);
|
|
2986
|
+
if (p.length >= 5) {
|
|
2987
|
+
this.fontStyle = p[0];
|
|
2988
|
+
this.fontWeight = parseInt(p[2], 10) || 400;
|
|
2989
|
+
this.fontSize = parseFloat(p[3]) || 12;
|
|
2990
|
+
this.fontFamily = p.slice(4).join(" ");
|
|
2991
|
+
}
|
|
2992
|
+
}
|
|
2993
|
+
get font() {
|
|
2994
|
+
return this._font;
|
|
2995
|
+
}
|
|
2996
|
+
save() {
|
|
2997
|
+
this.stateStack.push({
|
|
2998
|
+
globalAlpha: this.globalAlpha,
|
|
2999
|
+
fillStyle: this.fillStyle,
|
|
3000
|
+
strokeStyle: this.strokeStyle,
|
|
3001
|
+
lineWidth: this.lineWidth,
|
|
3002
|
+
font: this._font,
|
|
3003
|
+
fontFamily: this.fontFamily,
|
|
3004
|
+
fontSize: this.fontSize,
|
|
3005
|
+
fontWeight: this.fontWeight,
|
|
3006
|
+
fontStyle: this.fontStyle,
|
|
3007
|
+
textAlign: this.textAlign,
|
|
3008
|
+
});
|
|
3009
|
+
}
|
|
3010
|
+
restore() {
|
|
3011
|
+
const state = this.stateStack.pop();
|
|
3012
|
+
if (state) {
|
|
3013
|
+
this.globalAlpha = state.globalAlpha;
|
|
3014
|
+
this.fillStyle = state.fillStyle;
|
|
3015
|
+
this.strokeStyle = state.strokeStyle;
|
|
3016
|
+
this.lineWidth = state.lineWidth;
|
|
3017
|
+
this._font = state.font;
|
|
3018
|
+
this.fontFamily = state.fontFamily;
|
|
3019
|
+
this.fontSize = state.fontSize;
|
|
3020
|
+
this.fontWeight = state.fontWeight;
|
|
3021
|
+
this.fontStyle = state.fontStyle;
|
|
3022
|
+
this.textAlign = state.textAlign;
|
|
3023
|
+
}
|
|
3024
|
+
}
|
|
3025
|
+
beginPath() {
|
|
3026
|
+
this.currentPath = [];
|
|
3027
|
+
this.hasPath = false;
|
|
3028
|
+
}
|
|
3029
|
+
closePath() {
|
|
3030
|
+
this.currentPath.push("Z");
|
|
3031
|
+
}
|
|
3032
|
+
moveTo(x, y) {
|
|
3033
|
+
this.hasPath = true;
|
|
3034
|
+
this.currentPath.push(`M${x},${y}`);
|
|
3035
|
+
}
|
|
3036
|
+
lineTo(x, y) {
|
|
3037
|
+
this.hasPath = true;
|
|
3038
|
+
this.currentPath.push(`L${x},${y}`);
|
|
3039
|
+
}
|
|
3040
|
+
arc(cx, cy, radius, startAngle, endAngle) {
|
|
3041
|
+
this.hasPath = true;
|
|
3042
|
+
if (endAngle - startAngle >= 2 * Math.PI - 0.01) {
|
|
3043
|
+
const x1 = cx - radius;
|
|
3044
|
+
const x2 = cx + radius;
|
|
3045
|
+
this.currentPath.push(`M${x1},${cy} A${radius},${radius} 0 1,1 ${x2},${cy} A${radius},${radius} 0 1,1 ${x1},${cy}`);
|
|
3046
|
+
}
|
|
3047
|
+
else {
|
|
3048
|
+
const sx = cx + radius * Math.cos(startAngle);
|
|
3049
|
+
const sy = cy + radius * Math.sin(startAngle);
|
|
3050
|
+
const ex = cx + radius * Math.cos(endAngle);
|
|
3051
|
+
const ey = cy + radius * Math.sin(endAngle);
|
|
3052
|
+
this.currentPath.push(`M${sx},${sy} A${radius},${radius} 0 0,1 ${ex},${ey}`);
|
|
3053
|
+
}
|
|
3054
|
+
}
|
|
3055
|
+
quadraticCurveTo(cpx, cpy, x, y) {
|
|
3056
|
+
this.hasPath = true;
|
|
3057
|
+
this.currentPath.push(`Q${cpx},${cpy} ${x},${y}`);
|
|
3058
|
+
}
|
|
3059
|
+
roundRect(x, y, w, h, radii) {
|
|
3060
|
+
this.hasPath = true;
|
|
3061
|
+
const r = typeof radii === "number" ? radii : (radii[0] ?? 0);
|
|
3062
|
+
if (r < 0.001) {
|
|
3063
|
+
this.currentPath.push(`M${x},${y} L${x + w},${y} L${x + w},${y + h} L${x},${y + h} Z`);
|
|
3064
|
+
}
|
|
3065
|
+
else {
|
|
3066
|
+
this.currentPath.push(`M${x + r},${y} L${x + w - r},${y} A${r},${r} 0 0,1 ${x + w},${y + r} L${x + w},${y + h - r} A${r},${r} 0 0,1 ${x + w - r},${y + h} L${x + r},${y + h} A${r},${r} 0 0,1 ${x},${y + h - r} L${x},${y + r} A${r},${r} 0 0,1 ${x + r},${y} Z`);
|
|
3067
|
+
}
|
|
3068
|
+
}
|
|
3069
|
+
rect(x, y, w, h) {
|
|
3070
|
+
this.hasPath = true;
|
|
3071
|
+
this.currentPath.push(`M${x},${y} L${x + w},${y} L${x + w},${y + h} L${x},${y + h} Z`);
|
|
3072
|
+
}
|
|
3073
|
+
fill() {
|
|
3074
|
+
if (!this.hasPath)
|
|
3075
|
+
return;
|
|
3076
|
+
const d = this.currentPath.join(" ");
|
|
3077
|
+
this.parts.push(`<path d="${d}" fill="${this.fillStyle}" stroke="none" opacity="${this.globalAlpha}" stroke-linejoin="round"/>`);
|
|
3078
|
+
}
|
|
3079
|
+
stroke() {
|
|
3080
|
+
if (!this.hasPath)
|
|
3081
|
+
return;
|
|
3082
|
+
const d = this.currentPath.join(" ");
|
|
3083
|
+
this.parts.push(`<path d="${d}" fill="none" stroke="${this.strokeStyle}" stroke-width="${this.lineWidth}" opacity="${this.globalAlpha}" stroke-linecap="round" stroke-linejoin="round"/>`);
|
|
3084
|
+
}
|
|
3085
|
+
fillText(text, x, y) {
|
|
3086
|
+
const anchor = this.textAlign === "center" ? "middle" : this.textAlign === "right" ? "end" : "start";
|
|
3087
|
+
this.parts.push(`<text x="${x}" y="${y}" font-family="${this.fontFamily}" font-size="${this.fontSize}" font-weight="${this.fontWeight}" font-style="${this.fontStyle}" fill="${this.fillStyle}" text-anchor="${anchor}" opacity="${this.globalAlpha}">${escapeXml(text)}</text>`);
|
|
3088
|
+
}
|
|
3089
|
+
fillRect(x, y, w, h) {
|
|
3090
|
+
this.parts.push(`<rect x="${x}" y="${y}" width="${w}" height="${h}" fill="${this.fillStyle}" opacity="${this.globalAlpha}"/>`);
|
|
3091
|
+
}
|
|
3092
|
+
strokeRect(x, y, w, h) {
|
|
3093
|
+
this.parts.push(`<rect x="${x}" y="${y}" width="${w}" height="${h}" fill="none" stroke="${this.strokeStyle}" stroke-width="${this.lineWidth}" opacity="${this.globalAlpha}"/>`);
|
|
3094
|
+
}
|
|
3095
|
+
clearRect() { }
|
|
3096
|
+
translate(x, y) {
|
|
3097
|
+
this.transformX = x;
|
|
3098
|
+
this.transformY = y;
|
|
3099
|
+
}
|
|
3100
|
+
scale(k) {
|
|
3101
|
+
this.transformK = k;
|
|
3102
|
+
}
|
|
3103
|
+
closeTransform() {
|
|
3104
|
+
this.parts.unshift(`<g transform="translate(${this.transformX},${this.transformY}) scale(${this.transformK})">`);
|
|
3105
|
+
this.parts.push("</g>");
|
|
3106
|
+
}
|
|
3107
|
+
setLineDash() { }
|
|
3108
|
+
clip() { }
|
|
3109
|
+
drawImage() { }
|
|
3110
|
+
}
|
|
3111
|
+
|
|
3112
|
+
function exportToSvgSlice(filename = "graph.svg", fit = false) {
|
|
3113
|
+
this.tick();
|
|
3114
|
+
let svgWidth = this.width;
|
|
3115
|
+
let svgHeight = this.height;
|
|
3116
|
+
const svgParts = [];
|
|
3117
|
+
const adapter = new SvgContextAdapter(svgParts);
|
|
3118
|
+
const clone = Object.assign(Object.create(Object.getPrototypeOf(this)), this);
|
|
3119
|
+
clone.context = adapter;
|
|
3120
|
+
clone.isSelecting = false;
|
|
3121
|
+
clone.listeners = {};
|
|
3122
|
+
clone.nodes = jsHelpers.cloneDeep(this.nodes);
|
|
3123
|
+
clone.links = jsHelpers.cloneDeep(this.links);
|
|
3124
|
+
clone.particles = jsHelpers.cloneDeep(this.particles);
|
|
3125
|
+
if (fit) {
|
|
3126
|
+
const bounds = computeGraphBounds(clone.nodes);
|
|
3127
|
+
if (bounds) {
|
|
3128
|
+
const pad = 50;
|
|
3129
|
+
const graphWidth = bounds.maxX - bounds.minX;
|
|
3130
|
+
const graphHeight = bounds.maxY - bounds.minY;
|
|
3131
|
+
if (graphWidth > 0 && graphHeight > 0) {
|
|
3132
|
+
svgWidth = graphWidth + pad * 2;
|
|
3133
|
+
svgHeight = graphHeight + pad * 2;
|
|
3134
|
+
const graphCenterX = bounds.minX + graphWidth / 2;
|
|
3135
|
+
const graphCenterY = bounds.minY + graphHeight / 2;
|
|
3136
|
+
clone.areaTransform = d3Zoom.zoomIdentity
|
|
3137
|
+
.translate(svgWidth / 2, svgHeight / 2)
|
|
3138
|
+
.translate(-graphCenterX, -graphCenterY);
|
|
3139
|
+
clone.width = svgWidth;
|
|
3140
|
+
clone.height = svgHeight;
|
|
3141
|
+
}
|
|
3142
|
+
}
|
|
3143
|
+
}
|
|
3144
|
+
const draw = initDraw.call(clone);
|
|
3145
|
+
draw();
|
|
3146
|
+
adapter.closeTransform();
|
|
3147
|
+
const svg = [
|
|
3148
|
+
`<svg xmlns="http://www.w3.org/2000/svg" width="${svgWidth}" height="${svgHeight}">`,
|
|
3149
|
+
...svgParts,
|
|
3150
|
+
"</svg>",
|
|
3151
|
+
].join("\n");
|
|
3152
|
+
const blob = new Blob([svg], { type: "image/svg+xml;charset=utf-8" });
|
|
3153
|
+
const url = URL.createObjectURL(blob);
|
|
3154
|
+
const a = document.createElement("a");
|
|
3155
|
+
a.href = url;
|
|
3156
|
+
a.download = filename;
|
|
3157
|
+
a.click();
|
|
3158
|
+
URL.revokeObjectURL(url);
|
|
3159
|
+
}
|
|
3160
|
+
|
|
2955
3161
|
class GraphCanvas {
|
|
2956
3162
|
/** initial data */
|
|
2957
3163
|
nodes;
|
|
@@ -3081,6 +3287,9 @@ class GraphCanvas {
|
|
|
3081
3287
|
}
|
|
3082
3288
|
this.animateZoom(area, target, this.areaTransform, duration);
|
|
3083
3289
|
};
|
|
3290
|
+
exportToSvg = (filename = "graph.svg", fit = false) => {
|
|
3291
|
+
exportToSvgSlice.call(this, filename, fit);
|
|
3292
|
+
};
|
|
3084
3293
|
changeData = (options, alpha = 0.5, clearCache = true, precompute = false) => {
|
|
3085
3294
|
if (options.links != undefined)
|
|
3086
3295
|
this.links = options.links;
|