@yuneta/gobj-ui 7.23.154 → 7.23.155
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/README.md +12 -2
- package/dist/gobj-ui.cjs.js +150 -6
- package/dist/gobj-ui.es.js +151 -7
- package/package.json +1 -1
- package/src/c_g6_nodes_tree.js +61 -5
- package/src/treedb_elbow.js +113 -0
- package/src/treedb_elbow.test.js +45 -1
package/README.md
CHANGED
|
@@ -1419,7 +1419,8 @@ layouts by three thin adapters in `c_g6_nodes_tree.js`:
|
|
|
1419
1419
|
gained nothing on a whole level opened with the stepper, where every parent
|
|
1420
1420
|
still needed the row of its children beside it. Against `tree`: regions
|
|
1421
1421
|
only 10% of the width, one region open with a 24-device hall 21%, a whole
|
|
1422
|
-
level open 41%. The tree grows taller instead;
|
|
1422
|
+
level open 41%. The tree grows taller instead; with elbow edges or curves
|
|
1423
|
+
alike, since `7.23.155` a curve keeps off the cards too.
|
|
1423
1424
|
- **`radial`** (`treedb-radial`) — the root in the middle, a ring per depth,
|
|
1424
1425
|
every subtree an angular **sector** proportional to its leaves, and the
|
|
1425
1426
|
radius of each ring the largest of three: one `ranksep` out from the ring
|
|
@@ -1481,7 +1482,16 @@ port run. Only the stub at the port is shared. Into a lower row of a stack of
|
|
|
1481
1482
|
the compact tree an edge runs a **comb** (`7.23.154`): along the channel to a
|
|
1482
1483
|
lane of its own in the stack's corridor, down it, and into the gap above its
|
|
1483
1484
|
card; lanes go outermost first by row, so none crosses another, and a comb is
|
|
1484
|
-
drawn as laid out, never routed.
|
|
1485
|
+
drawn as laid out, never routed.
|
|
1486
|
+
|
|
1487
|
+
**Curved edges keep off the cards as well** (`7.23.155`). On a layout with
|
|
1488
|
+
rows a curve is `treedb-curve-v` / `-h`, a subclass of G6's cubic: the cubic
|
|
1489
|
+
as before, unless that very curve — the path G6 would draw, sampled, not the
|
|
1490
|
+
rectangle round it — would cross a card other than its own two, or the edge
|
|
1491
|
+
does not run forward and so would cross its own. Then it takes the way its
|
|
1492
|
+
elbow would (comb, detour, route, the same lanes and staggered turns) with
|
|
1493
|
+
corners rounded to 24px. On a layout with no rows the edges stay G6's plain
|
|
1494
|
+
cubic. G6's `shortest-path` router is not used: it is
|
|
1485
1495
|
not exported, it
|
|
1486
1496
|
falls back in silence to a route that crosses cards, and it rewrites its
|
|
1487
1497
|
module defaults with every config it is given.
|
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -30168,6 +30168,112 @@ function elbow_route(s, t, box_s, box_t, lane, vertical, boxes, stagger) {
|
|
|
30168
30168
|
if (!route && near.length < others.length) route = orth_search(a, z, others.map((b) => box_expand(b, m)));
|
|
30169
30169
|
return route || simple;
|
|
30170
30170
|
}
|
|
30171
|
+
function path_points(path) {
|
|
30172
|
+
let pts = [];
|
|
30173
|
+
let cur = null;
|
|
30174
|
+
for (let c of path) if (c[0] === "M" || c[0] === "L") {
|
|
30175
|
+
cur = [c[1], c[2]];
|
|
30176
|
+
pts.push(cur);
|
|
30177
|
+
} else if (c[0] === "C" && cur) {
|
|
30178
|
+
let [x0, y0] = cur;
|
|
30179
|
+
for (let k = 1; k <= 16; k++) {
|
|
30180
|
+
let u = k / 16;
|
|
30181
|
+
let v = 1 - u;
|
|
30182
|
+
pts.push([v * v * v * x0 + 3 * v * v * u * c[1] + 3 * v * u * u * c[3] + u * u * u * c[5], v * v * v * y0 + 3 * v * v * u * c[2] + 3 * v * u * u * c[4] + u * u * u * c[6]]);
|
|
30183
|
+
}
|
|
30184
|
+
cur = [c[5], c[6]];
|
|
30185
|
+
} else if (c[0] === "Q" && cur) {
|
|
30186
|
+
let [x0, y0] = cur;
|
|
30187
|
+
for (let k = 1; k <= 16; k++) {
|
|
30188
|
+
let u = k / 16;
|
|
30189
|
+
let v = 1 - u;
|
|
30190
|
+
pts.push([v * v * x0 + 2 * v * u * c[1] + u * u * c[3], v * v * y0 + 2 * v * u * c[2] + u * u * c[4]]);
|
|
30191
|
+
}
|
|
30192
|
+
cur = [c[3], c[4]];
|
|
30193
|
+
}
|
|
30194
|
+
return pts;
|
|
30195
|
+
}
|
|
30196
|
+
/************************************************************
|
|
30197
|
+
* Does the G6 path `path` of a curved edge cross a card other than
|
|
30198
|
+
* its own two? Measured on the curve itself -- the path G6 would
|
|
30199
|
+
* draw, sampled -- and not on the rectangle round it, which took
|
|
30200
|
+
* every card the curve merely passed near: the ports of a row
|
|
30201
|
+
* stick well into the space above it. Its own two cards are left
|
|
30202
|
+
* out: the curve starts and ends on their ports.
|
|
30203
|
+
************************************************************/
|
|
30204
|
+
function curve_hits(path, boxes, box_s, box_t) {
|
|
30205
|
+
let pts = path_points(path);
|
|
30206
|
+
if (pts.length < 2) return false;
|
|
30207
|
+
let bb = {
|
|
30208
|
+
x1: Infinity,
|
|
30209
|
+
y1: Infinity,
|
|
30210
|
+
x2: -Infinity,
|
|
30211
|
+
y2: -Infinity
|
|
30212
|
+
};
|
|
30213
|
+
for (let p of pts) {
|
|
30214
|
+
bb.x1 = Math.min(bb.x1, p[0]);
|
|
30215
|
+
bb.y1 = Math.min(bb.y1, p[1]);
|
|
30216
|
+
bb.x2 = Math.max(bb.x2, p[0]);
|
|
30217
|
+
bb.y2 = Math.max(bb.y2, p[1]);
|
|
30218
|
+
}
|
|
30219
|
+
for (let b of boxes || []) {
|
|
30220
|
+
if (same_box(b, box_s) || same_box(b, box_t) || !box_overlaps(b, box_expand(bb, 1))) continue;
|
|
30221
|
+
let inner = box_expand(b, -1);
|
|
30222
|
+
for (let k = 0; k + 1 < pts.length; k++) if (segment_hits(pts[k], pts[k + 1], inner)) return true;
|
|
30223
|
+
}
|
|
30224
|
+
return false;
|
|
30225
|
+
}
|
|
30226
|
+
/************************************************************
|
|
30227
|
+
* A G6 path (['M'|'L'|'Q', ...]) along `points` with every corner
|
|
30228
|
+
* rounded -- by `radius`, or by half the shorter of its two
|
|
30229
|
+
* segments, so a short run is never overshot. The rounding is the
|
|
30230
|
+
* quadratic G6's own polyline uses.
|
|
30231
|
+
************************************************************/
|
|
30232
|
+
function rounded_path(points, radius) {
|
|
30233
|
+
let path = [[
|
|
30234
|
+
"M",
|
|
30235
|
+
points[0][0],
|
|
30236
|
+
points[0][1]
|
|
30237
|
+
]];
|
|
30238
|
+
for (let i = 1; i + 1 < points.length; i++) {
|
|
30239
|
+
let a = points[i - 1];
|
|
30240
|
+
let m = points[i];
|
|
30241
|
+
let b = points[i + 1];
|
|
30242
|
+
let len_in = Math.hypot(m[0] - a[0], m[1] - a[1]);
|
|
30243
|
+
let len_out = Math.hypot(b[0] - m[0], b[1] - m[1]);
|
|
30244
|
+
let r = Math.min(radius, len_in / 2, len_out / 2);
|
|
30245
|
+
let collinear = Math.abs((m[0] - a[0]) * (b[1] - m[1]) - (m[1] - a[1]) * (b[0] - m[0])) < 1e-9;
|
|
30246
|
+
if (r <= 0 || collinear) {
|
|
30247
|
+
path.push([
|
|
30248
|
+
"L",
|
|
30249
|
+
m[0],
|
|
30250
|
+
m[1]
|
|
30251
|
+
]);
|
|
30252
|
+
continue;
|
|
30253
|
+
}
|
|
30254
|
+
let p1 = [m[0] - (m[0] - a[0]) / len_in * r, m[1] - (m[1] - a[1]) / len_in * r];
|
|
30255
|
+
let p2 = [m[0] + (b[0] - m[0]) / len_out * r, m[1] + (b[1] - m[1]) / len_out * r];
|
|
30256
|
+
path.push([
|
|
30257
|
+
"L",
|
|
30258
|
+
p1[0],
|
|
30259
|
+
p1[1]
|
|
30260
|
+
]);
|
|
30261
|
+
path.push([
|
|
30262
|
+
"Q",
|
|
30263
|
+
m[0],
|
|
30264
|
+
m[1],
|
|
30265
|
+
p2[0],
|
|
30266
|
+
p2[1]
|
|
30267
|
+
]);
|
|
30268
|
+
}
|
|
30269
|
+
let last = points[points.length - 1];
|
|
30270
|
+
path.push([
|
|
30271
|
+
"L",
|
|
30272
|
+
last[0],
|
|
30273
|
+
last[1]
|
|
30274
|
+
]);
|
|
30275
|
+
return path;
|
|
30276
|
+
}
|
|
30171
30277
|
//#endregion
|
|
30172
30278
|
//#region node_modules/@babel/runtime/helpers/esm/typeof.js
|
|
30173
30279
|
function _typeof(o) {
|
|
@@ -55055,7 +55161,7 @@ Easing Functions from anime.js, they are tried and true, so, its better to use t
|
|
|
55055
55161
|
var Quad = function Quad(t) {
|
|
55056
55162
|
return Math.pow(t, 2);
|
|
55057
55163
|
};
|
|
55058
|
-
var Cubic = function Cubic(t) {
|
|
55164
|
+
var Cubic$1 = function Cubic(t) {
|
|
55059
55165
|
return Math.pow(t, 3);
|
|
55060
55166
|
};
|
|
55061
55167
|
var Quart = function Quart(t) {
|
|
@@ -55192,10 +55298,10 @@ var EasingFunctions = {
|
|
|
55192
55298
|
"out-quad": EaseOut(Quad),
|
|
55193
55299
|
"in-out-quad": EaseInOut(Quad),
|
|
55194
55300
|
"out-in-quad": EaseOutIn(Quad),
|
|
55195
|
-
"in-cubic": Cubic,
|
|
55196
|
-
"out-cubic": EaseOut(Cubic),
|
|
55197
|
-
"in-out-cubic": EaseInOut(Cubic),
|
|
55198
|
-
"out-in-cubic": EaseOutIn(Cubic),
|
|
55301
|
+
"in-cubic": Cubic$1,
|
|
55302
|
+
"out-cubic": EaseOut(Cubic$1),
|
|
55303
|
+
"in-out-cubic": EaseInOut(Cubic$1),
|
|
55304
|
+
"out-in-cubic": EaseOutIn(Cubic$1),
|
|
55199
55305
|
"in-quart": Quart,
|
|
55200
55306
|
"out-quart": EaseOut(Quart),
|
|
55201
55307
|
"in-out-quart": EaseInOut(Quart),
|
|
@@ -57368,6 +57474,8 @@ function register_layouts(gobj) {
|
|
|
57368
57474
|
(0, _antv_g6.register)(_antv_g6.ExtensionCategory.LAYOUT, "treedb-compact", TreedbCompactLayout);
|
|
57369
57475
|
(0, _antv_g6.register)(_antv_g6.ExtensionCategory.EDGE, "treedb-elbow-v", TreedbElbowV);
|
|
57370
57476
|
(0, _antv_g6.register)(_antv_g6.ExtensionCategory.EDGE, "treedb-elbow-h", TreedbElbowH);
|
|
57477
|
+
(0, _antv_g6.register)(_antv_g6.ExtensionCategory.EDGE, "treedb-curve-v", TreedbCurveV);
|
|
57478
|
+
(0, _antv_g6.register)(_antv_g6.ExtensionCategory.EDGE, "treedb-curve-h", TreedbCurveH);
|
|
57371
57479
|
(0, _antv_g6.register)(_antv_g6.ExtensionCategory.LAYOUT, "treedb-radial", TreedbRadialLayout);
|
|
57372
57480
|
(0, _antv_g6.register)(_antv_g6.ExtensionCategory.NODE, "light", LightNode);
|
|
57373
57481
|
(0, _antv_g6.register)(_antv_g6.ExtensionCategory.NODE, "treedb-card", TreedbCard);
|
|
@@ -58062,7 +58170,9 @@ function layout_direction(gobj) {
|
|
|
58062
58170
|
function edge_type_for(gobj) {
|
|
58063
58171
|
let lr = layout_direction(gobj) === "LR";
|
|
58064
58172
|
let rowless = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "rowless_layouts") || [];
|
|
58065
|
-
|
|
58173
|
+
let rows = !(0, _yuneta_gobj_js.str_in_list)(rowless, gobj.priv.layout);
|
|
58174
|
+
if (rows && (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "edge_shape") === "elbow") return lr ? "treedb-elbow-h" : "treedb-elbow-v";
|
|
58175
|
+
if (rows) return lr ? "treedb-curve-h" : "treedb-curve-v";
|
|
58066
58176
|
return lr ? "cubic-horizontal" : "cubic";
|
|
58067
58177
|
}
|
|
58068
58178
|
/************************************************************
|
|
@@ -59666,6 +59776,40 @@ var TreedbElbowH = class extends _antv_g6.Polyline {
|
|
|
59666
59776
|
return super.getKeyPath(Object.assign({}, attributes, { radius: attributes.radius || ELBOW_RADIUS }));
|
|
59667
59777
|
}
|
|
59668
59778
|
};
|
|
59779
|
+
/************************************************************
|
|
59780
|
+
* A CURVED edge that keeps off the cards. G6's cubic, as before,
|
|
59781
|
+
* unless that very curve -- sampled, not guessed from the
|
|
59782
|
+
* rectangle round it -- would cross a card other than its own two,
|
|
59783
|
+
* or when it does not run forward and so would cross its own:
|
|
59784
|
+
* the card above a lower row of a stack, a row between a parent
|
|
59785
|
+
* and a far child. Then it goes the way an elbow would (the comb,
|
|
59786
|
+
* the detour, the route: the same lanes and staggered turns) with
|
|
59787
|
+
* round corners, so it still reads as a curve. `-v` for rows
|
|
59788
|
+
* stacked top to bottom, `-h` for columns.
|
|
59789
|
+
************************************************************/
|
|
59790
|
+
function curve_key_path(edge, attributes, vertical, plain) {
|
|
59791
|
+
let [s, t] = edge.getEndpoints(attributes, false);
|
|
59792
|
+
let along = vertical ? 1 : 0;
|
|
59793
|
+
let box_s = elbow_box(edge.sourceNode);
|
|
59794
|
+
let box_t = elbow_box(edge.targetNode);
|
|
59795
|
+
let boxes = elbow_obstacles(edge);
|
|
59796
|
+
if (t[along] - s[along] > 20 && !curve_hits(plain, boxes, box_s, box_t)) return plain;
|
|
59797
|
+
return rounded_path([
|
|
59798
|
+
s,
|
|
59799
|
+
...elbow_route(s, t, box_s, box_t, elbow_lane_of(edge), vertical, boxes, elbow_stagger_of(edge, vertical)),
|
|
59800
|
+
t
|
|
59801
|
+
], 24);
|
|
59802
|
+
}
|
|
59803
|
+
var TreedbCurveV = class extends _antv_g6.Cubic {
|
|
59804
|
+
getKeyPath(attributes) {
|
|
59805
|
+
return curve_key_path(this, attributes, true, super.getKeyPath(attributes));
|
|
59806
|
+
}
|
|
59807
|
+
};
|
|
59808
|
+
var TreedbCurveH = class extends _antv_g6.CubicHorizontal {
|
|
59809
|
+
getKeyPath(attributes) {
|
|
59810
|
+
return curve_key_path(this, attributes, false, super.getKeyPath(attributes));
|
|
59811
|
+
}
|
|
59812
|
+
};
|
|
59669
59813
|
var TreedbCompactLayout = class extends _antv_g6.BaseLayout {
|
|
59670
59814
|
async execute(data, options) {
|
|
59671
59815
|
let input = treedb_layout_input(data);
|
package/dist/gobj-ui.es.js
CHANGED
|
@@ -6,7 +6,7 @@ import { createJSONEditor } from "vanilla-jsoneditor";
|
|
|
6
6
|
import { TabulatorFull } from "tabulator-tables";
|
|
7
7
|
import * as maplibregl from "maplibre-gl";
|
|
8
8
|
import uPlot from "uplot";
|
|
9
|
-
import { BaseLayout, BrushSelect, CanvasEvent, Circle, CommonEvent, DragCanvas, EdgeEvent, ExtensionCategory, Graph, HTML, HistoryEvent, NodeEvent, Polyline, Toolbar, ZoomCanvas, register } from "@antv/g6";
|
|
9
|
+
import { BaseLayout, BrushSelect, CanvasEvent, Circle, CommonEvent, Cubic, CubicHorizontal, DragCanvas, EdgeEvent, ExtensionCategory, Graph, HTML, HistoryEvent, NodeEvent, Polyline, Toolbar, ZoomCanvas, register } from "@antv/g6";
|
|
10
10
|
//#region \0rolldown/runtime.js
|
|
11
11
|
var __create = Object.create;
|
|
12
12
|
var __defProp = Object.defineProperty;
|
|
@@ -30163,6 +30163,112 @@ function elbow_route(s, t, box_s, box_t, lane, vertical, boxes, stagger) {
|
|
|
30163
30163
|
if (!route && near.length < others.length) route = orth_search(a, z, others.map((b) => box_expand(b, m)));
|
|
30164
30164
|
return route || simple;
|
|
30165
30165
|
}
|
|
30166
|
+
function path_points(path) {
|
|
30167
|
+
let pts = [];
|
|
30168
|
+
let cur = null;
|
|
30169
|
+
for (let c of path) if (c[0] === "M" || c[0] === "L") {
|
|
30170
|
+
cur = [c[1], c[2]];
|
|
30171
|
+
pts.push(cur);
|
|
30172
|
+
} else if (c[0] === "C" && cur) {
|
|
30173
|
+
let [x0, y0] = cur;
|
|
30174
|
+
for (let k = 1; k <= 16; k++) {
|
|
30175
|
+
let u = k / 16;
|
|
30176
|
+
let v = 1 - u;
|
|
30177
|
+
pts.push([v * v * v * x0 + 3 * v * v * u * c[1] + 3 * v * u * u * c[3] + u * u * u * c[5], v * v * v * y0 + 3 * v * v * u * c[2] + 3 * v * u * u * c[4] + u * u * u * c[6]]);
|
|
30178
|
+
}
|
|
30179
|
+
cur = [c[5], c[6]];
|
|
30180
|
+
} else if (c[0] === "Q" && cur) {
|
|
30181
|
+
let [x0, y0] = cur;
|
|
30182
|
+
for (let k = 1; k <= 16; k++) {
|
|
30183
|
+
let u = k / 16;
|
|
30184
|
+
let v = 1 - u;
|
|
30185
|
+
pts.push([v * v * x0 + 2 * v * u * c[1] + u * u * c[3], v * v * y0 + 2 * v * u * c[2] + u * u * c[4]]);
|
|
30186
|
+
}
|
|
30187
|
+
cur = [c[3], c[4]];
|
|
30188
|
+
}
|
|
30189
|
+
return pts;
|
|
30190
|
+
}
|
|
30191
|
+
/************************************************************
|
|
30192
|
+
* Does the G6 path `path` of a curved edge cross a card other than
|
|
30193
|
+
* its own two? Measured on the curve itself -- the path G6 would
|
|
30194
|
+
* draw, sampled -- and not on the rectangle round it, which took
|
|
30195
|
+
* every card the curve merely passed near: the ports of a row
|
|
30196
|
+
* stick well into the space above it. Its own two cards are left
|
|
30197
|
+
* out: the curve starts and ends on their ports.
|
|
30198
|
+
************************************************************/
|
|
30199
|
+
function curve_hits(path, boxes, box_s, box_t) {
|
|
30200
|
+
let pts = path_points(path);
|
|
30201
|
+
if (pts.length < 2) return false;
|
|
30202
|
+
let bb = {
|
|
30203
|
+
x1: Infinity,
|
|
30204
|
+
y1: Infinity,
|
|
30205
|
+
x2: -Infinity,
|
|
30206
|
+
y2: -Infinity
|
|
30207
|
+
};
|
|
30208
|
+
for (let p of pts) {
|
|
30209
|
+
bb.x1 = Math.min(bb.x1, p[0]);
|
|
30210
|
+
bb.y1 = Math.min(bb.y1, p[1]);
|
|
30211
|
+
bb.x2 = Math.max(bb.x2, p[0]);
|
|
30212
|
+
bb.y2 = Math.max(bb.y2, p[1]);
|
|
30213
|
+
}
|
|
30214
|
+
for (let b of boxes || []) {
|
|
30215
|
+
if (same_box(b, box_s) || same_box(b, box_t) || !box_overlaps(b, box_expand(bb, 1))) continue;
|
|
30216
|
+
let inner = box_expand(b, -1);
|
|
30217
|
+
for (let k = 0; k + 1 < pts.length; k++) if (segment_hits(pts[k], pts[k + 1], inner)) return true;
|
|
30218
|
+
}
|
|
30219
|
+
return false;
|
|
30220
|
+
}
|
|
30221
|
+
/************************************************************
|
|
30222
|
+
* A G6 path (['M'|'L'|'Q', ...]) along `points` with every corner
|
|
30223
|
+
* rounded -- by `radius`, or by half the shorter of its two
|
|
30224
|
+
* segments, so a short run is never overshot. The rounding is the
|
|
30225
|
+
* quadratic G6's own polyline uses.
|
|
30226
|
+
************************************************************/
|
|
30227
|
+
function rounded_path(points, radius) {
|
|
30228
|
+
let path = [[
|
|
30229
|
+
"M",
|
|
30230
|
+
points[0][0],
|
|
30231
|
+
points[0][1]
|
|
30232
|
+
]];
|
|
30233
|
+
for (let i = 1; i + 1 < points.length; i++) {
|
|
30234
|
+
let a = points[i - 1];
|
|
30235
|
+
let m = points[i];
|
|
30236
|
+
let b = points[i + 1];
|
|
30237
|
+
let len_in = Math.hypot(m[0] - a[0], m[1] - a[1]);
|
|
30238
|
+
let len_out = Math.hypot(b[0] - m[0], b[1] - m[1]);
|
|
30239
|
+
let r = Math.min(radius, len_in / 2, len_out / 2);
|
|
30240
|
+
let collinear = Math.abs((m[0] - a[0]) * (b[1] - m[1]) - (m[1] - a[1]) * (b[0] - m[0])) < 1e-9;
|
|
30241
|
+
if (r <= 0 || collinear) {
|
|
30242
|
+
path.push([
|
|
30243
|
+
"L",
|
|
30244
|
+
m[0],
|
|
30245
|
+
m[1]
|
|
30246
|
+
]);
|
|
30247
|
+
continue;
|
|
30248
|
+
}
|
|
30249
|
+
let p1 = [m[0] - (m[0] - a[0]) / len_in * r, m[1] - (m[1] - a[1]) / len_in * r];
|
|
30250
|
+
let p2 = [m[0] + (b[0] - m[0]) / len_out * r, m[1] + (b[1] - m[1]) / len_out * r];
|
|
30251
|
+
path.push([
|
|
30252
|
+
"L",
|
|
30253
|
+
p1[0],
|
|
30254
|
+
p1[1]
|
|
30255
|
+
]);
|
|
30256
|
+
path.push([
|
|
30257
|
+
"Q",
|
|
30258
|
+
m[0],
|
|
30259
|
+
m[1],
|
|
30260
|
+
p2[0],
|
|
30261
|
+
p2[1]
|
|
30262
|
+
]);
|
|
30263
|
+
}
|
|
30264
|
+
let last = points[points.length - 1];
|
|
30265
|
+
path.push([
|
|
30266
|
+
"L",
|
|
30267
|
+
last[0],
|
|
30268
|
+
last[1]
|
|
30269
|
+
]);
|
|
30270
|
+
return path;
|
|
30271
|
+
}
|
|
30166
30272
|
//#endregion
|
|
30167
30273
|
//#region node_modules/@babel/runtime/helpers/esm/typeof.js
|
|
30168
30274
|
function _typeof(o) {
|
|
@@ -55050,7 +55156,7 @@ Easing Functions from anime.js, they are tried and true, so, its better to use t
|
|
|
55050
55156
|
var Quad = function Quad(t) {
|
|
55051
55157
|
return Math.pow(t, 2);
|
|
55052
55158
|
};
|
|
55053
|
-
var Cubic = function Cubic(t) {
|
|
55159
|
+
var Cubic$1 = function Cubic(t) {
|
|
55054
55160
|
return Math.pow(t, 3);
|
|
55055
55161
|
};
|
|
55056
55162
|
var Quart = function Quart(t) {
|
|
@@ -55187,10 +55293,10 @@ var EasingFunctions = {
|
|
|
55187
55293
|
"out-quad": EaseOut(Quad),
|
|
55188
55294
|
"in-out-quad": EaseInOut(Quad),
|
|
55189
55295
|
"out-in-quad": EaseOutIn(Quad),
|
|
55190
|
-
"in-cubic": Cubic,
|
|
55191
|
-
"out-cubic": EaseOut(Cubic),
|
|
55192
|
-
"in-out-cubic": EaseInOut(Cubic),
|
|
55193
|
-
"out-in-cubic": EaseOutIn(Cubic),
|
|
55296
|
+
"in-cubic": Cubic$1,
|
|
55297
|
+
"out-cubic": EaseOut(Cubic$1),
|
|
55298
|
+
"in-out-cubic": EaseInOut(Cubic$1),
|
|
55299
|
+
"out-in-cubic": EaseOutIn(Cubic$1),
|
|
55194
55300
|
"in-quart": Quart,
|
|
55195
55301
|
"out-quart": EaseOut(Quart),
|
|
55196
55302
|
"in-out-quart": EaseInOut(Quart),
|
|
@@ -57363,6 +57469,8 @@ function register_layouts(gobj) {
|
|
|
57363
57469
|
register(ExtensionCategory.LAYOUT, "treedb-compact", TreedbCompactLayout);
|
|
57364
57470
|
register(ExtensionCategory.EDGE, "treedb-elbow-v", TreedbElbowV);
|
|
57365
57471
|
register(ExtensionCategory.EDGE, "treedb-elbow-h", TreedbElbowH);
|
|
57472
|
+
register(ExtensionCategory.EDGE, "treedb-curve-v", TreedbCurveV);
|
|
57473
|
+
register(ExtensionCategory.EDGE, "treedb-curve-h", TreedbCurveH);
|
|
57366
57474
|
register(ExtensionCategory.LAYOUT, "treedb-radial", TreedbRadialLayout);
|
|
57367
57475
|
register(ExtensionCategory.NODE, "light", LightNode);
|
|
57368
57476
|
register(ExtensionCategory.NODE, "treedb-card", TreedbCard);
|
|
@@ -58057,7 +58165,9 @@ function layout_direction(gobj) {
|
|
|
58057
58165
|
function edge_type_for(gobj) {
|
|
58058
58166
|
let lr = layout_direction(gobj) === "LR";
|
|
58059
58167
|
let rowless = gobj_read_attr(gobj, "rowless_layouts") || [];
|
|
58060
|
-
|
|
58168
|
+
let rows = !str_in_list(rowless, gobj.priv.layout);
|
|
58169
|
+
if (rows && gobj_read_str_attr(gobj, "edge_shape") === "elbow") return lr ? "treedb-elbow-h" : "treedb-elbow-v";
|
|
58170
|
+
if (rows) return lr ? "treedb-curve-h" : "treedb-curve-v";
|
|
58061
58171
|
return lr ? "cubic-horizontal" : "cubic";
|
|
58062
58172
|
}
|
|
58063
58173
|
/************************************************************
|
|
@@ -59661,6 +59771,40 @@ var TreedbElbowH = class extends Polyline {
|
|
|
59661
59771
|
return super.getKeyPath(Object.assign({}, attributes, { radius: attributes.radius || ELBOW_RADIUS }));
|
|
59662
59772
|
}
|
|
59663
59773
|
};
|
|
59774
|
+
/************************************************************
|
|
59775
|
+
* A CURVED edge that keeps off the cards. G6's cubic, as before,
|
|
59776
|
+
* unless that very curve -- sampled, not guessed from the
|
|
59777
|
+
* rectangle round it -- would cross a card other than its own two,
|
|
59778
|
+
* or when it does not run forward and so would cross its own:
|
|
59779
|
+
* the card above a lower row of a stack, a row between a parent
|
|
59780
|
+
* and a far child. Then it goes the way an elbow would (the comb,
|
|
59781
|
+
* the detour, the route: the same lanes and staggered turns) with
|
|
59782
|
+
* round corners, so it still reads as a curve. `-v` for rows
|
|
59783
|
+
* stacked top to bottom, `-h` for columns.
|
|
59784
|
+
************************************************************/
|
|
59785
|
+
function curve_key_path(edge, attributes, vertical, plain) {
|
|
59786
|
+
let [s, t] = edge.getEndpoints(attributes, false);
|
|
59787
|
+
let along = vertical ? 1 : 0;
|
|
59788
|
+
let box_s = elbow_box(edge.sourceNode);
|
|
59789
|
+
let box_t = elbow_box(edge.targetNode);
|
|
59790
|
+
let boxes = elbow_obstacles(edge);
|
|
59791
|
+
if (t[along] - s[along] > 20 && !curve_hits(plain, boxes, box_s, box_t)) return plain;
|
|
59792
|
+
return rounded_path([
|
|
59793
|
+
s,
|
|
59794
|
+
...elbow_route(s, t, box_s, box_t, elbow_lane_of(edge), vertical, boxes, elbow_stagger_of(edge, vertical)),
|
|
59795
|
+
t
|
|
59796
|
+
], 24);
|
|
59797
|
+
}
|
|
59798
|
+
var TreedbCurveV = class extends Cubic {
|
|
59799
|
+
getKeyPath(attributes) {
|
|
59800
|
+
return curve_key_path(this, attributes, true, super.getKeyPath(attributes));
|
|
59801
|
+
}
|
|
59802
|
+
};
|
|
59803
|
+
var TreedbCurveH = class extends CubicHorizontal {
|
|
59804
|
+
getKeyPath(attributes) {
|
|
59805
|
+
return curve_key_path(this, attributes, false, super.getKeyPath(attributes));
|
|
59806
|
+
}
|
|
59807
|
+
};
|
|
59664
59808
|
var TreedbCompactLayout = class extends BaseLayout {
|
|
59665
59809
|
async execute(data, options) {
|
|
59666
59810
|
let input = treedb_layout_input(data);
|
package/package.json
CHANGED
package/src/c_g6_nodes_tree.js
CHANGED
|
@@ -133,7 +133,10 @@ import {
|
|
|
133
133
|
fold_root_group_key,
|
|
134
134
|
} from "./treedb_fold_model.js";
|
|
135
135
|
import {layout_tree, layout_radial, layout_compact} from "./treedb_layout.js";
|
|
136
|
-
import {
|
|
136
|
+
import {
|
|
137
|
+
elbow_lane, elbow_rank, elbow_route, elbow_combs, curve_hits, rounded_path, CURVE_RADIUS,
|
|
138
|
+
ELBOW_STEP,
|
|
139
|
+
} from "./treedb_elbow.js";
|
|
137
140
|
|
|
138
141
|
import {
|
|
139
142
|
BaseLayout,
|
|
@@ -148,6 +151,8 @@ import {
|
|
|
148
151
|
Toolbar,
|
|
149
152
|
register,
|
|
150
153
|
Polyline,
|
|
154
|
+
Cubic,
|
|
155
|
+
CubicHorizontal,
|
|
151
156
|
} from '@antv/g6';
|
|
152
157
|
|
|
153
158
|
import {Circle as CircleGeometry, Rect as RectGeometry} from '@antv/g';
|
|
@@ -942,6 +947,8 @@ function register_layouts(gobj)
|
|
|
942
947
|
register(ExtensionCategory.LAYOUT, 'treedb-compact', TreedbCompactLayout);
|
|
943
948
|
register(ExtensionCategory.EDGE, 'treedb-elbow-v', TreedbElbowV);
|
|
944
949
|
register(ExtensionCategory.EDGE, 'treedb-elbow-h', TreedbElbowH);
|
|
950
|
+
register(ExtensionCategory.EDGE, 'treedb-curve-v', TreedbCurveV);
|
|
951
|
+
register(ExtensionCategory.EDGE, 'treedb-curve-h', TreedbCurveH);
|
|
945
952
|
register(ExtensionCategory.LAYOUT, 'treedb-radial', TreedbRadialLayout);
|
|
946
953
|
register(ExtensionCategory.NODE, 'light', LightNode);
|
|
947
954
|
register(ExtensionCategory.NODE, 'treedb-card', TreedbCard);
|
|
@@ -2042,16 +2049,20 @@ function layout_direction(gobj)
|
|
|
2042
2049
|
return str_in_list(LR_LAYOUTS, gobj.priv.layout)? "LR" : "TB";
|
|
2043
2050
|
}
|
|
2044
2051
|
|
|
2045
|
-
/*
|
|
2046
|
-
* has rows
|
|
2052
|
+
/* An elbow when the reader asked for one, a curve otherwise -- ours
|
|
2053
|
+
* where the layout has rows, which keeps off the cards; G6's plain
|
|
2054
|
+
* cubic on a layout with no rows to go round by. */
|
|
2047
2055
|
function edge_type_for(gobj)
|
|
2048
2056
|
{
|
|
2049
2057
|
let lr = (layout_direction(gobj) === "LR");
|
|
2050
2058
|
let rowless = gobj_read_attr(gobj, "rowless_layouts") || [];
|
|
2051
|
-
|
|
2052
|
-
|
|
2059
|
+
let rows = !str_in_list(rowless, gobj.priv.layout);
|
|
2060
|
+
if(rows && gobj_read_str_attr(gobj, "edge_shape") === "elbow") {
|
|
2053
2061
|
return lr? "treedb-elbow-h" : "treedb-elbow-v";
|
|
2054
2062
|
}
|
|
2063
|
+
if(rows) {
|
|
2064
|
+
return lr? "treedb-curve-h" : "treedb-curve-v";
|
|
2065
|
+
}
|
|
2055
2066
|
return lr? "cubic-horizontal" : "cubic";
|
|
2056
2067
|
}
|
|
2057
2068
|
|
|
@@ -4388,6 +4399,51 @@ class TreedbElbowH extends Polyline
|
|
|
4388
4399
|
}
|
|
4389
4400
|
}
|
|
4390
4401
|
|
|
4402
|
+
/************************************************************
|
|
4403
|
+
* A CURVED edge that keeps off the cards. G6's cubic, as before,
|
|
4404
|
+
* unless that very curve -- sampled, not guessed from the
|
|
4405
|
+
* rectangle round it -- would cross a card other than its own two,
|
|
4406
|
+
* or when it does not run forward and so would cross its own:
|
|
4407
|
+
* the card above a lower row of a stack, a row between a parent
|
|
4408
|
+
* and a far child. Then it goes the way an elbow would (the comb,
|
|
4409
|
+
* the detour, the route: the same lanes and staggered turns) with
|
|
4410
|
+
* round corners, so it still reads as a curve. `-v` for rows
|
|
4411
|
+
* stacked top to bottom, `-h` for columns.
|
|
4412
|
+
************************************************************/
|
|
4413
|
+
function curve_key_path(edge, attributes, vertical, plain)
|
|
4414
|
+
{
|
|
4415
|
+
let [s, t] = edge.getEndpoints(attributes, false);
|
|
4416
|
+
let along = vertical? 1 : 0;
|
|
4417
|
+
let box_s = elbow_box(edge.sourceNode);
|
|
4418
|
+
let box_t = elbow_box(edge.targetNode);
|
|
4419
|
+
let boxes = elbow_obstacles(edge);
|
|
4420
|
+
/* An edge that does not run forward -- one of every reciprocal
|
|
4421
|
+
* pair, an edge within one row -- runs through its OWN two cards
|
|
4422
|
+
* as a cubic, which curve_hits does not look at: it goes round
|
|
4423
|
+
* them, as its elbow does. */
|
|
4424
|
+
let forward = (t[along] - s[along] > 2 * ELBOW_STEP);
|
|
4425
|
+
if(forward && !curve_hits(plain, boxes, box_s, box_t)) {
|
|
4426
|
+
return plain;
|
|
4427
|
+
}
|
|
4428
|
+
let pts = elbow_route(s, t, box_s, box_t, elbow_lane_of(edge), vertical, boxes,
|
|
4429
|
+
elbow_stagger_of(edge, vertical));
|
|
4430
|
+
return rounded_path([s, ...pts, t], CURVE_RADIUS);
|
|
4431
|
+
}
|
|
4432
|
+
|
|
4433
|
+
class TreedbCurveV extends Cubic
|
|
4434
|
+
{
|
|
4435
|
+
getKeyPath(attributes) {
|
|
4436
|
+
return curve_key_path(this, attributes, true, super.getKeyPath(attributes));
|
|
4437
|
+
}
|
|
4438
|
+
}
|
|
4439
|
+
|
|
4440
|
+
class TreedbCurveH extends CubicHorizontal
|
|
4441
|
+
{
|
|
4442
|
+
getKeyPath(attributes) {
|
|
4443
|
+
return curve_key_path(this, attributes, false, super.getKeyPath(attributes));
|
|
4444
|
+
}
|
|
4445
|
+
}
|
|
4446
|
+
|
|
4391
4447
|
class TreedbCompactLayout extends BaseLayout
|
|
4392
4448
|
{
|
|
4393
4449
|
async execute(data, options) {
|
package/src/treedb_elbow.js
CHANGED
|
@@ -40,6 +40,10 @@
|
|
|
40
40
|
* channel, so its edge runs down the corridor in a lane of
|
|
41
41
|
* its own -- a COMB -- and turns into the gap above its card.
|
|
42
42
|
*
|
|
43
|
+
* And for CURVED edges (curve_hits, rounded_path): a curve
|
|
44
|
+
* that would cross another card follows the same way an elbow
|
|
45
|
+
* would, with round corners, so it reads as a curve.
|
|
46
|
+
*
|
|
43
47
|
* Written for the top-down reading; left to right is the same
|
|
44
48
|
* geometry with the axes swapped.
|
|
45
49
|
*
|
|
@@ -609,3 +613,112 @@ export function elbow_route(s, t, box_s, box_t, lane, vertical, boxes, stagger)
|
|
|
609
613
|
}
|
|
610
614
|
return route || simple;
|
|
611
615
|
}
|
|
616
|
+
|
|
617
|
+
/*----------------------------------------------------------------*
|
|
618
|
+
* CURVED edges that would cross a card
|
|
619
|
+
*----------------------------------------------------------------*/
|
|
620
|
+
export const CURVE_RADIUS = 24; /* the corners of a curve that goes round */
|
|
621
|
+
export const CURVE_STEPS = 16; /* samples of each curved stretch */
|
|
622
|
+
|
|
623
|
+
/* Points along a G6 path: the ends of its runs and CURVE_STEPS
|
|
624
|
+
* samples of each quadratic or cubic stretch. */
|
|
625
|
+
function path_points(path)
|
|
626
|
+
{
|
|
627
|
+
let pts = [];
|
|
628
|
+
let cur = null;
|
|
629
|
+
for(let c of path) {
|
|
630
|
+
if(c[0] === 'M' || c[0] === 'L') {
|
|
631
|
+
cur = [c[1], c[2]];
|
|
632
|
+
pts.push(cur);
|
|
633
|
+
} else if(c[0] === 'C' && cur) {
|
|
634
|
+
let [x0, y0] = cur;
|
|
635
|
+
for(let k = 1; k <= CURVE_STEPS; k++) {
|
|
636
|
+
let u = k / CURVE_STEPS;
|
|
637
|
+
let v = 1 - u;
|
|
638
|
+
pts.push([
|
|
639
|
+
v * v * v * x0 + 3 * v * v * u * c[1] + 3 * v * u * u * c[3] + u * u * u * c[5],
|
|
640
|
+
v * v * v * y0 + 3 * v * v * u * c[2] + 3 * v * u * u * c[4] + u * u * u * c[6],
|
|
641
|
+
]);
|
|
642
|
+
}
|
|
643
|
+
cur = [c[5], c[6]];
|
|
644
|
+
} else if(c[0] === 'Q' && cur) {
|
|
645
|
+
let [x0, y0] = cur;
|
|
646
|
+
for(let k = 1; k <= CURVE_STEPS; k++) {
|
|
647
|
+
let u = k / CURVE_STEPS;
|
|
648
|
+
let v = 1 - u;
|
|
649
|
+
pts.push([
|
|
650
|
+
v * v * x0 + 2 * v * u * c[1] + u * u * c[3],
|
|
651
|
+
v * v * y0 + 2 * v * u * c[2] + u * u * c[4],
|
|
652
|
+
]);
|
|
653
|
+
}
|
|
654
|
+
cur = [c[3], c[4]];
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
return pts;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
/************************************************************
|
|
661
|
+
* Does the G6 path `path` of a curved edge cross a card other than
|
|
662
|
+
* its own two? Measured on the curve itself -- the path G6 would
|
|
663
|
+
* draw, sampled -- and not on the rectangle round it, which took
|
|
664
|
+
* every card the curve merely passed near: the ports of a row
|
|
665
|
+
* stick well into the space above it. Its own two cards are left
|
|
666
|
+
* out: the curve starts and ends on their ports.
|
|
667
|
+
************************************************************/
|
|
668
|
+
export function curve_hits(path, boxes, box_s, box_t)
|
|
669
|
+
{
|
|
670
|
+
let pts = path_points(path);
|
|
671
|
+
if(pts.length < 2) {
|
|
672
|
+
return false;
|
|
673
|
+
}
|
|
674
|
+
let bb = {x1: Infinity, y1: Infinity, x2: -Infinity, y2: -Infinity};
|
|
675
|
+
for(let p of pts) {
|
|
676
|
+
bb.x1 = Math.min(bb.x1, p[0]);
|
|
677
|
+
bb.y1 = Math.min(bb.y1, p[1]);
|
|
678
|
+
bb.x2 = Math.max(bb.x2, p[0]);
|
|
679
|
+
bb.y2 = Math.max(bb.y2, p[1]);
|
|
680
|
+
}
|
|
681
|
+
for(let b of (boxes || [])) {
|
|
682
|
+
if(same_box(b, box_s) || same_box(b, box_t) || !box_overlaps(b, box_expand(bb, 1))) {
|
|
683
|
+
continue;
|
|
684
|
+
}
|
|
685
|
+
let inner = box_expand(b, -1);
|
|
686
|
+
for(let k = 0; k + 1 < pts.length; k++) {
|
|
687
|
+
if(segment_hits(pts[k], pts[k + 1], inner)) {
|
|
688
|
+
return true;
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
return false;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
/************************************************************
|
|
696
|
+
* A G6 path (['M'|'L'|'Q', ...]) along `points` with every corner
|
|
697
|
+
* rounded -- by `radius`, or by half the shorter of its two
|
|
698
|
+
* segments, so a short run is never overshot. The rounding is the
|
|
699
|
+
* quadratic G6's own polyline uses.
|
|
700
|
+
************************************************************/
|
|
701
|
+
export function rounded_path(points, radius)
|
|
702
|
+
{
|
|
703
|
+
let path = [['M', points[0][0], points[0][1]]];
|
|
704
|
+
for(let i = 1; i + 1 < points.length; i++) {
|
|
705
|
+
let a = points[i - 1];
|
|
706
|
+
let m = points[i];
|
|
707
|
+
let b = points[i + 1];
|
|
708
|
+
let len_in = Math.hypot(m[0] - a[0], m[1] - a[1]);
|
|
709
|
+
let len_out = Math.hypot(b[0] - m[0], b[1] - m[1]);
|
|
710
|
+
let r = Math.min(radius, len_in / 2, len_out / 2);
|
|
711
|
+
let collinear = Math.abs((m[0] - a[0]) * (b[1] - m[1]) - (m[1] - a[1]) * (b[0] - m[0])) < 1e-9;
|
|
712
|
+
if(r <= 0 || collinear) {
|
|
713
|
+
path.push(['L', m[0], m[1]]);
|
|
714
|
+
continue;
|
|
715
|
+
}
|
|
716
|
+
let p1 = [m[0] - (m[0] - a[0]) / len_in * r, m[1] - (m[1] - a[1]) / len_in * r];
|
|
717
|
+
let p2 = [m[0] + (b[0] - m[0]) / len_out * r, m[1] + (b[1] - m[1]) / len_out * r];
|
|
718
|
+
path.push(['L', p1[0], p1[1]]);
|
|
719
|
+
path.push(['Q', m[0], m[1], p2[0], p2[1]]);
|
|
720
|
+
}
|
|
721
|
+
let last = points[points.length - 1];
|
|
722
|
+
path.push(['L', last[0], last[1]]);
|
|
723
|
+
return path;
|
|
724
|
+
}
|
package/src/treedb_elbow.test.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { describe, test, expect } from "vitest";
|
|
9
9
|
import {
|
|
10
10
|
elbow_lane, elbow_points, elbow_route, elbow_path_hits, elbow_rank, elbow_combs,
|
|
11
|
-
ELBOW_STEP, ELBOW_CLEAR,
|
|
11
|
+
curve_hits, rounded_path, ELBOW_STEP, ELBOW_CLEAR,
|
|
12
12
|
} from "./treedb_elbow.js";
|
|
13
13
|
import { layout_compact } from "./treedb_layout.js";
|
|
14
14
|
|
|
@@ -356,6 +356,50 @@ describe("the comb of a stack", () => {
|
|
|
356
356
|
});
|
|
357
357
|
});
|
|
358
358
|
|
|
359
|
+
describe("a curve that would cross a card", () => {
|
|
360
|
+
/* Whole-node boxes (ports 7px out of top and bottom). */
|
|
361
|
+
const PB = {x1: 0, y1: -7, x2: 172, y2: 103}; /* a parent */
|
|
362
|
+
const R0 = {x1: 0, y1: 183, x2: 116, y2: 237}; /* row 0 of a stack */
|
|
363
|
+
const R1 = {x1: 0, y1: 277, x2: 116, y2: 331}; /* row 1, under it */
|
|
364
|
+
const SIB = {x1: 200, y1: -7, x2: 372, y2: 103}; /* the parent's sibling */
|
|
365
|
+
const S = [86, 96];
|
|
366
|
+
|
|
367
|
+
/* The cubic G6 draws between two vertical ports: tangents along
|
|
368
|
+
* the line, as its default curveOffset gives. */
|
|
369
|
+
const cubic = (s, t) => [["M", s[0], s[1]],
|
|
370
|
+
["C", s[0], (s[1] + t[1]) / 2, t[0], (s[1] + t[1]) / 2, t[0], t[1]]];
|
|
371
|
+
|
|
372
|
+
test("a curve into a card of the next row crosses nothing", () => {
|
|
373
|
+
expect(curve_hits(cubic(S, [58, 190]), [PB, R0, R1, SIB], PB, R0)).toBe(false);
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
test("a curve into a lower row of a stack crosses the card above it", () => {
|
|
377
|
+
expect(curve_hits(cubic(S, [58, 284]), [PB, R0, R1, SIB], PB, R1)).toBe(true);
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
test("a curve that passes NEAR a card, beside its ports, does not count", () => {
|
|
381
|
+
/* N0 in the target row with its port poking 7px up, beside
|
|
382
|
+
* where the curve lands; the rectangle round the curve took it. */
|
|
383
|
+
const T0 = {x1: 250, y1: 183, x2: 366, y2: 237};
|
|
384
|
+
const N0 = {x1: 120, y1: 183, x2: 236, y2: 237};
|
|
385
|
+
expect(curve_hits(cubic(S, [308, 190]), [PB, SIB, T0, N0], PB, T0)).toBe(false);
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
test("the rounded path: a straight line is one run", () => {
|
|
389
|
+
expect(rounded_path([[0, 0], [0, 100]], 24)).toEqual([["M", 0, 0], ["L", 0, 100]]);
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
test("the rounded path: each corner a quadratic, never past half a short run", () => {
|
|
393
|
+
let path = rounded_path([[0, 0], [0, 60], [100, 60], [100, 70]], 24);
|
|
394
|
+
expect(path[0]).toEqual(["M", 0, 0]);
|
|
395
|
+
expect(path[1]).toEqual(["L", 0, 36]); /* 24 before the corner */
|
|
396
|
+
expect(path[2]).toEqual(["Q", 0, 60, 24, 60]);
|
|
397
|
+
expect(path[3]).toEqual(["L", 95, 60]); /* the last run is 10: r = 5 */
|
|
398
|
+
expect(path[4]).toEqual(["Q", 100, 60, 100, 65]);
|
|
399
|
+
expect(path[5]).toEqual(["L", 100, 70]);
|
|
400
|
+
});
|
|
401
|
+
});
|
|
402
|
+
|
|
359
403
|
describe("the ports are obstacles too", () => {
|
|
360
404
|
/* Whole-node boxes: a port of 14px sticks 7px out of the bottom
|
|
361
405
|
* and the top of each card. */
|