@yuneta/gobj-ui 7.23.18 → 7.23.19
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/gobj-ui.cjs.js +531 -151
- package/dist/gobj-ui.es.js +523 -143
- package/package.json +1 -1
- package/src/c_g6_nodes_tree.js +135 -3
- package/src/c_yui_gobj_tree_js.js +185 -7
- package/src/c_yui_json_graph.js +200 -10
- package/src/lib_icons.js +7 -0
- package/src/yui_graph_camera.js +95 -0
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -9350,6 +9350,131 @@ function yui_toolbar(attrs = {}, items = []) {
|
|
|
9350
9350
|
return $toolbar;
|
|
9351
9351
|
}
|
|
9352
9352
|
//#endregion
|
|
9353
|
+
//#region src/lib_graph.js
|
|
9354
|
+
/***********************************************************************
|
|
9355
|
+
* lib_graph.js
|
|
9356
|
+
*
|
|
9357
|
+
* Utilities for graph, using Bulma
|
|
9358
|
+
*
|
|
9359
|
+
* Copyright (c) 2025, ArtGins.
|
|
9360
|
+
* All Rights Reserved.
|
|
9361
|
+
***********************************************************************/
|
|
9362
|
+
/************************************************************
|
|
9363
|
+
* Add class to elements selected
|
|
9364
|
+
************************************************************/
|
|
9365
|
+
function addClasses($container, selector, ...classNames) {
|
|
9366
|
+
$container.querySelectorAll(selector).forEach((el) => el.classList.add(...classNames));
|
|
9367
|
+
}
|
|
9368
|
+
/************************************************************
|
|
9369
|
+
* Remove class from elements selected
|
|
9370
|
+
************************************************************/
|
|
9371
|
+
function removeClasses($container, selector, ...classNames) {
|
|
9372
|
+
$container.querySelectorAll(selector).forEach((el) => el.classList.remove(...classNames));
|
|
9373
|
+
}
|
|
9374
|
+
/************************************************************
|
|
9375
|
+
* Toggle class to elements selected
|
|
9376
|
+
************************************************************/
|
|
9377
|
+
function toggleClasses($container, selector, ...classNames) {
|
|
9378
|
+
$container.querySelectorAll(selector).forEach((el) => classNames.forEach((cls) => el.classList.toggle(cls)));
|
|
9379
|
+
}
|
|
9380
|
+
/************************************************************
|
|
9381
|
+
* Remove child elements
|
|
9382
|
+
************************************************************/
|
|
9383
|
+
function removeChildElements($element) {
|
|
9384
|
+
$element.innerHTML = "";
|
|
9385
|
+
}
|
|
9386
|
+
/************************************************************
|
|
9387
|
+
* Disable/Enable elements
|
|
9388
|
+
************************************************************/
|
|
9389
|
+
function disableElements($container, selector) {
|
|
9390
|
+
$container.querySelectorAll(selector).forEach((el) => {
|
|
9391
|
+
el.setAttribute("disabled", "");
|
|
9392
|
+
});
|
|
9393
|
+
}
|
|
9394
|
+
function enableElements($container, selector) {
|
|
9395
|
+
$container.querySelectorAll(selector).forEach((el) => {
|
|
9396
|
+
if (el.hasAttribute("disabled")) el.removeAttribute("disabled");
|
|
9397
|
+
});
|
|
9398
|
+
}
|
|
9399
|
+
/************************************************************
|
|
9400
|
+
* Set or reset the color of 'enable submit action' state
|
|
9401
|
+
* Color green
|
|
9402
|
+
************************************************************/
|
|
9403
|
+
function set_submit_state($container, selector, set) {
|
|
9404
|
+
if (set) addClasses($container, selector, "color_submit_state");
|
|
9405
|
+
else removeClasses($container, selector, "color_submit_state");
|
|
9406
|
+
}
|
|
9407
|
+
/************************************************************
|
|
9408
|
+
* Set or reset the color of 'enable cancel action' state
|
|
9409
|
+
* Color red
|
|
9410
|
+
************************************************************/
|
|
9411
|
+
function set_cancel_state($container, selector, set) {
|
|
9412
|
+
if (set) addClasses($container, selector, "color_cancel_state");
|
|
9413
|
+
else removeClasses($container, selector, "color_cancel_state");
|
|
9414
|
+
}
|
|
9415
|
+
/************************************************************
|
|
9416
|
+
* Set or reset the color of 'enable actived' state
|
|
9417
|
+
* Color orange
|
|
9418
|
+
************************************************************/
|
|
9419
|
+
function set_active_state($container, selector, set) {
|
|
9420
|
+
if (set) addClasses($container, selector, "color_active_state");
|
|
9421
|
+
else removeClasses($container, selector, "color_active_state");
|
|
9422
|
+
}
|
|
9423
|
+
/************************************************************
|
|
9424
|
+
* Set or reset the 'pressed' state of a TOGGLE.
|
|
9425
|
+
*
|
|
9426
|
+
* Not one of the colours above: each of those names a KIND of
|
|
9427
|
+
* action (create, pending, history, destructive), and a toggle
|
|
9428
|
+
* is not an action -- it is a state the control is IN. So it
|
|
9429
|
+
* looks pressed instead of changing category, which also keeps
|
|
9430
|
+
* it out of the way of a neighbour wearing the same hue.
|
|
9431
|
+
************************************************************/
|
|
9432
|
+
function set_pressed_state($container, selector, set) {
|
|
9433
|
+
if (set) addClasses($container, selector, "pressed_state");
|
|
9434
|
+
else removeClasses($container, selector, "pressed_state");
|
|
9435
|
+
}
|
|
9436
|
+
/**
|
|
9437
|
+
* Returns a smart stroke color in `rgba()` format based on:
|
|
9438
|
+
* - The given fill color (hex or rgb[a])
|
|
9439
|
+
* - The current theme ('light' or 'dark')
|
|
9440
|
+
* - The adjustment factor (default 0.2)
|
|
9441
|
+
*
|
|
9442
|
+
* @param {string} fillColor - Fill color string
|
|
9443
|
+
* @param {string} theme - 'light' or 'dark'
|
|
9444
|
+
* @param {number} factor - Lighten/darken factor (default 0.2)
|
|
9445
|
+
* @returns {string} rgba(r, g, b, a)
|
|
9446
|
+
*/
|
|
9447
|
+
function getStrokeColor(fillColor, theme = "light", factor = .2) {
|
|
9448
|
+
let r, g, b, a = 1;
|
|
9449
|
+
if (fillColor.startsWith("#")) {
|
|
9450
|
+
let hex = fillColor.slice(1);
|
|
9451
|
+
if (hex.length === 3 || hex.length === 4) hex = hex.split("").map((c) => c + c).join("");
|
|
9452
|
+
if (hex.length === 6) {
|
|
9453
|
+
r = parseInt(hex.slice(0, 2), 16);
|
|
9454
|
+
g = parseInt(hex.slice(2, 4), 16);
|
|
9455
|
+
b = parseInt(hex.slice(4, 6), 16);
|
|
9456
|
+
} else if (hex.length === 8) {
|
|
9457
|
+
r = parseInt(hex.slice(0, 2), 16);
|
|
9458
|
+
g = parseInt(hex.slice(2, 4), 16);
|
|
9459
|
+
b = parseInt(hex.slice(4, 6), 16);
|
|
9460
|
+
a = parseInt(hex.slice(6, 8), 16) / 255;
|
|
9461
|
+
} else throw new Error("Unsupported hex format");
|
|
9462
|
+
} else if (fillColor.startsWith("rgb")) {
|
|
9463
|
+
const match = fillColor.match(/rgba?\(\s*(\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\s*\)/);
|
|
9464
|
+
if (!match) throw new Error("Invalid rgb()/rgba() format.");
|
|
9465
|
+
r = parseInt(match[1], 10);
|
|
9466
|
+
g = parseInt(match[2], 10);
|
|
9467
|
+
b = parseInt(match[3], 10);
|
|
9468
|
+
if (match[4] !== void 0) a = parseFloat(match[4]);
|
|
9469
|
+
} else throw new Error("Unsupported color format.");
|
|
9470
|
+
const luminance = (.299 * r + .587 * g + .114 * b) / 255;
|
|
9471
|
+
let lighten;
|
|
9472
|
+
if (theme === "dark") lighten = luminance < .7;
|
|
9473
|
+
else lighten = luminance < .3;
|
|
9474
|
+
const adjust = (v) => lighten ? Math.min(255, Math.floor(v + (255 - v) * factor)) : Math.max(0, Math.floor(v * (1 - factor)));
|
|
9475
|
+
return `rgba(${adjust(r)}, ${adjust(g)}, ${adjust(b)}, ${a.toFixed(3)})`;
|
|
9476
|
+
}
|
|
9477
|
+
//#endregion
|
|
9353
9478
|
//#region src/yui_graph_camera.js
|
|
9354
9479
|
/***********************************************************************
|
|
9355
9480
|
* yui_graph_camera.js
|
|
@@ -9498,6 +9623,79 @@ function yui_graph_fold_items(gobj, wide) {
|
|
|
9498
9623
|
return [camera_button(gobj, "yi-chevron-right", "EV_EXPAND_ALL", "expand all", wide, " transform: rotate(90deg);"), camera_button(gobj, "yi-chevron-right", "EV_COLLAPSE_ALL", "collapse all", wide)];
|
|
9499
9624
|
}
|
|
9500
9625
|
/************************************************************
|
|
9626
|
+
* The ANCHOR toggle: pick one element and every camera move
|
|
9627
|
+
* from then on leaves it in the MIDDLE.
|
|
9628
|
+
*
|
|
9629
|
+
* Why it exists: a graph that fits on screen is unreadable at
|
|
9630
|
+
* the zoom that makes it fit, and the zoom that makes it
|
|
9631
|
+
* readable does not fit -- so the useful view is always a
|
|
9632
|
+
* fraction of the document, and which fraction is the whole
|
|
9633
|
+
* question. Without an anchor, `1:1` lands wherever the
|
|
9634
|
+
* layout's origin happens to be and the reader hunts for the
|
|
9635
|
+
* node they were looking at.
|
|
9636
|
+
*
|
|
9637
|
+
* Crosshairs and not a thumbtack. A tack says "do not move
|
|
9638
|
+
* this", which is what a pinned NODE would mean in a graph you
|
|
9639
|
+
* can drag nodes around in; this pins the CAMERA to a target,
|
|
9640
|
+
* which is what a crosshair says and what every map that
|
|
9641
|
+
* offers it draws. It is also in the icon set already, and a
|
|
9642
|
+
* `yi-*` class that is not is a black square.
|
|
9643
|
+
*
|
|
9644
|
+
* Three states, because two would not say what a press does:
|
|
9645
|
+
*
|
|
9646
|
+
* off no target; the camera behaves as it always did
|
|
9647
|
+
* arming waiting for you to click the element you mean
|
|
9648
|
+
* on locked; every zoom re-centres on it
|
|
9649
|
+
************************************************************/
|
|
9650
|
+
function yui_graph_anchor_item(gobj, wide) {
|
|
9651
|
+
return camera_button(gobj, "yi-location-crosshairs", "EV_TOGGLE_ANCHOR", "anchor view", wide);
|
|
9652
|
+
}
|
|
9653
|
+
/************************************************************
|
|
9654
|
+
* Paint the anchor button. `state` is "off" | "arming" | "on".
|
|
9655
|
+
*
|
|
9656
|
+
* Both live states look PRESSED, because both are states the
|
|
9657
|
+
* control is IN rather than actions; what separates them is the
|
|
9658
|
+
* colour, and only the waiting one takes a palette colour --
|
|
9659
|
+
* it is the one that needs the reader to do something next.
|
|
9660
|
+
************************************************************/
|
|
9661
|
+
function yui_graph_update_anchor($container, state) {
|
|
9662
|
+
if (!$container) return;
|
|
9663
|
+
let $btn = $container.querySelector(".EV_TOGGLE_ANCHOR");
|
|
9664
|
+
if (!$btn) return;
|
|
9665
|
+
set_pressed_state($container, ".EV_TOGGLE_ANCHOR", state !== "off");
|
|
9666
|
+
$btn.classList.toggle("color_pending_state", state === "arming");
|
|
9667
|
+
$btn.setAttribute("aria-pressed", state === "on" ? "true" : "false");
|
|
9668
|
+
let key = state === "arming" ? "click the element to centre on" : state === "on" ? "centred: click to release" : "anchor view";
|
|
9669
|
+
$btn.setAttribute("title", (0, i18next.t)(key));
|
|
9670
|
+
$btn.setAttribute("data-i18n-title", key);
|
|
9671
|
+
$btn.setAttribute("aria-label", (0, i18next.t)(key));
|
|
9672
|
+
$btn.setAttribute("data-i18n-aria-label", key);
|
|
9673
|
+
}
|
|
9674
|
+
/************************************************************
|
|
9675
|
+
* Put `node_id` back in the middle of the viewport.
|
|
9676
|
+
*
|
|
9677
|
+
* Called AFTER the camera moved, never instead of moving it:
|
|
9678
|
+
* the zoom is what the reader asked for, the centring is what
|
|
9679
|
+
* keeps the thing they are reading under their eyes.
|
|
9680
|
+
*
|
|
9681
|
+
* Guarded on every side because it runs on every wheel notch:
|
|
9682
|
+
* a graph mid-rebuild, an anchor whose node went away with a
|
|
9683
|
+
* fold, a G6 version without `focusElement` -- none of those is
|
|
9684
|
+
* an error worth a log line per notch, they are all "there is
|
|
9685
|
+
* nothing to centre right now".
|
|
9686
|
+
************************************************************/
|
|
9687
|
+
function yui_graph_center_on(graph, node_id) {
|
|
9688
|
+
if (!graph || !node_id) return false;
|
|
9689
|
+
try {
|
|
9690
|
+
if (typeof graph.getElementData === "function" && !graph.getElementData(node_id)) return false;
|
|
9691
|
+
if (typeof graph.focusElement !== "function") return false;
|
|
9692
|
+
graph.focusElement(node_id);
|
|
9693
|
+
return true;
|
|
9694
|
+
} catch (e) {
|
|
9695
|
+
return false;
|
|
9696
|
+
}
|
|
9697
|
+
}
|
|
9698
|
+
/************************************************************
|
|
9501
9699
|
* A refresh button, for the graphs that offer one.
|
|
9502
9700
|
************************************************************/
|
|
9503
9701
|
function yui_graph_refresh_item(gobj, wide) {
|
|
@@ -10075,7 +10273,11 @@ var PRIVATE_DATA$11 = {
|
|
|
10075
10273
|
$layout_select: null,
|
|
10076
10274
|
$find_input: null,
|
|
10077
10275
|
$find_result: null,
|
|
10078
|
-
$find_count: null
|
|
10276
|
+
$find_count: null,
|
|
10277
|
+
anchor_id: "",
|
|
10278
|
+
anchor_path: "",
|
|
10279
|
+
anchor_state: "off",
|
|
10280
|
+
last_zoom: 1
|
|
10079
10281
|
};
|
|
10080
10282
|
var __gclass__$11 = null;
|
|
10081
10283
|
var __layout_registered__$1 = false;
|
|
@@ -10368,6 +10570,7 @@ function make_toolbar$3(gobj) {
|
|
|
10368
10570
|
]]);
|
|
10369
10571
|
let center_items = [];
|
|
10370
10572
|
center_items = yui_graph_camera_items(gobj, priv.graph, toolbar_wide);
|
|
10573
|
+
center_items.push(yui_graph_anchor_item(gobj, toolbar_wide));
|
|
10371
10574
|
center_items.push(yui_graph_refresh_item(gobj, toolbar_wide));
|
|
10372
10575
|
let current_layout = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "layout") || DEFAULT_LAYOUT;
|
|
10373
10576
|
let options = Object.keys(LAYOUTS$1).map(function(key) {
|
|
@@ -10450,6 +10653,15 @@ function build_graph$3(gobj) {
|
|
|
10450
10653
|
});
|
|
10451
10654
|
graph.on("aftertransform", () => {
|
|
10452
10655
|
yui_graph_update_zoom((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container"), priv.graph);
|
|
10656
|
+
let z = priv.last_zoom;
|
|
10657
|
+
try {
|
|
10658
|
+
z = priv.graph.getZoom();
|
|
10659
|
+
} catch (e) {
|
|
10660
|
+
return;
|
|
10661
|
+
}
|
|
10662
|
+
if (z === priv.last_zoom) return;
|
|
10663
|
+
priv.last_zoom = z;
|
|
10664
|
+
if (priv.anchor_state === "on" && priv.anchor_id) yui_graph_center_on(priv.graph, priv.anchor_id);
|
|
10453
10665
|
});
|
|
10454
10666
|
graph.on(_antv_g6.CanvasEvent.CLICK, (evt) => {});
|
|
10455
10667
|
if (typeof ResizeObserver !== "undefined") {
|
|
@@ -10628,14 +10840,17 @@ function build_json_nodes(gobj, path, kw, nodes, edges, parent_id) {
|
|
|
10628
10840
|
card_matched = true;
|
|
10629
10841
|
priv.match_count++;
|
|
10630
10842
|
}
|
|
10631
|
-
|
|
10632
|
-
|
|
10633
|
-
|
|
10634
|
-
|
|
10635
|
-
|
|
10636
|
-
|
|
10843
|
+
if ((0, _yuneta_gobj_js.is_object)(value) && (0, _yuneta_gobj_js.json_object_size)(value) > 0 || (0, _yuneta_gobj_js.is_array)(value) && value.length > 0) {
|
|
10844
|
+
pending_complex.push({
|
|
10845
|
+
key,
|
|
10846
|
+
value
|
|
10847
|
+
});
|
|
10848
|
+
continue;
|
|
10849
|
+
}
|
|
10850
|
+
lines.push(build_cell_html(key, value, type, dark, matched));
|
|
10637
10851
|
}
|
|
10638
10852
|
let label = get_group_label(path) || (is_dict ? "{}" : "[]");
|
|
10853
|
+
if (pending_complex.length > 0) label += is_dict ? ` {${pending_complex.length}}` : ` [${pending_complex.length}]`;
|
|
10639
10854
|
let foldable = pending_complex.length > 0;
|
|
10640
10855
|
let folded = foldable && priv.collapsed.has(path);
|
|
10641
10856
|
let colors = json_card_style(is_dict ? GROUP_COLORS.dict : GROUP_COLORS.list, dark);
|
|
@@ -10711,13 +10926,22 @@ function load_json(gobj) {
|
|
|
10711
10926
|
let preserve_view = !!priv.pending_preserve_view;
|
|
10712
10927
|
priv.pending_preserve_view = false;
|
|
10713
10928
|
if (nodes.length > 0) {
|
|
10929
|
+
let root_id = nodes[0].id;
|
|
10714
10930
|
graph.setData({
|
|
10715
10931
|
nodes,
|
|
10716
10932
|
edges
|
|
10717
10933
|
});
|
|
10718
10934
|
graph.render().then(() => {
|
|
10719
|
-
|
|
10720
|
-
|
|
10935
|
+
reanchor$1(gobj);
|
|
10936
|
+
if (preserve_view) {
|
|
10937
|
+
yui_graph_update_zoom((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container"), priv.graph);
|
|
10938
|
+
return;
|
|
10939
|
+
}
|
|
10940
|
+
Promise.resolve(graph.zoomTo(1)).then(() => {
|
|
10941
|
+
if (!yui_graph_center_on(graph, priv.anchor_id)) yui_graph_center_on(graph, root_id);
|
|
10942
|
+
priv.last_zoom = 1;
|
|
10943
|
+
yui_graph_update_zoom((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container"), priv.graph);
|
|
10944
|
+
});
|
|
10721
10945
|
});
|
|
10722
10946
|
}
|
|
10723
10947
|
}
|
|
@@ -10980,13 +11204,79 @@ function ac_theme$3(gobj, event, kw, src) {
|
|
|
10980
11204
|
return 0;
|
|
10981
11205
|
}
|
|
10982
11206
|
/************************************************************
|
|
11207
|
+
* Every camera action ends the same way once an anchor is
|
|
11208
|
+
* set: the thing you were reading goes back to the middle.
|
|
11209
|
+
*
|
|
11210
|
+
* Chained on the promise G6 returns rather than run beside it
|
|
11211
|
+
* -- centring before the zoom has finished centres the OLD
|
|
11212
|
+
* view, and the reader watches the node slide away and come
|
|
11213
|
+
* back.
|
|
11214
|
+
************************************************************/
|
|
11215
|
+
function after_camera$2(gobj, moved) {
|
|
11216
|
+
let priv = gobj.priv;
|
|
11217
|
+
if (priv.anchor_state !== "on" || !priv.anchor_id) return;
|
|
11218
|
+
Promise.resolve(moved).then(function() {
|
|
11219
|
+
yui_graph_center_on(priv.graph, priv.anchor_id);
|
|
11220
|
+
}).catch(function() {});
|
|
11221
|
+
}
|
|
11222
|
+
/************************************************************
|
|
11223
|
+
* Point the anchor back at its node after a rebuild.
|
|
11224
|
+
*
|
|
11225
|
+
* Node ids are generated per build, so the id the reader
|
|
11226
|
+
* chose does not survive a refresh, a fold or a layout
|
|
11227
|
+
* change -- the PATH does, and it is what the anchor really
|
|
11228
|
+
* means: "this place in the document", not "this card".
|
|
11229
|
+
*
|
|
11230
|
+
* A path that is no longer drawn (its parent got folded)
|
|
11231
|
+
* releases the anchor rather than leaving a button that says
|
|
11232
|
+
* it is locked onto something invisible.
|
|
11233
|
+
************************************************************/
|
|
11234
|
+
function reanchor$1(gobj) {
|
|
11235
|
+
let priv = gobj.priv;
|
|
11236
|
+
if (priv.anchor_state !== "on" || !priv.anchor_path) return;
|
|
11237
|
+
let found = "";
|
|
11238
|
+
try {
|
|
11239
|
+
for (let node of priv.graph.getNodeData()) if (node && node.data && node.data.path === priv.anchor_path) {
|
|
11240
|
+
found = node.id;
|
|
11241
|
+
break;
|
|
11242
|
+
}
|
|
11243
|
+
} catch (e) {
|
|
11244
|
+
return;
|
|
11245
|
+
}
|
|
11246
|
+
priv.anchor_id = found;
|
|
11247
|
+
if (!found) {
|
|
11248
|
+
priv.anchor_state = "off";
|
|
11249
|
+
priv.anchor_path = "";
|
|
11250
|
+
}
|
|
11251
|
+
yui_graph_update_anchor((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container"), priv.anchor_state);
|
|
11252
|
+
}
|
|
11253
|
+
/************************************************************
|
|
11254
|
+
* Arm the anchor, or let it go.
|
|
11255
|
+
*
|
|
11256
|
+
* Three states and one button, so a press ADVANCES: with no
|
|
11257
|
+
* target it starts waiting for one, and with a target it
|
|
11258
|
+
* releases. Pressing it while it waits is a cancel, which is
|
|
11259
|
+
* what somebody who pressed it by mistake will try.
|
|
11260
|
+
************************************************************/
|
|
11261
|
+
function ac_toggle_anchor$2(gobj, event, kw, src) {
|
|
11262
|
+
let priv = gobj.priv;
|
|
11263
|
+
if (priv.anchor_state === "off") priv.anchor_state = "arming";
|
|
11264
|
+
else {
|
|
11265
|
+
priv.anchor_state = "off";
|
|
11266
|
+
priv.anchor_id = "";
|
|
11267
|
+
priv.anchor_path = "";
|
|
11268
|
+
}
|
|
11269
|
+
yui_graph_update_anchor((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container"), priv.anchor_state);
|
|
11270
|
+
return 0;
|
|
11271
|
+
}
|
|
11272
|
+
/************************************************************
|
|
10983
11273
|
*
|
|
10984
11274
|
************************************************************/
|
|
10985
11275
|
function ac_zoom_in$2(gobj, event, kw, src) {
|
|
10986
11276
|
let graph = gobj.priv.graph;
|
|
10987
11277
|
if (graph) {
|
|
10988
11278
|
let z = graph.getZoom();
|
|
10989
|
-
graph.zoomTo(z * 1.2);
|
|
11279
|
+
after_camera$2(gobj, graph.zoomTo(z * 1.2));
|
|
10990
11280
|
}
|
|
10991
11281
|
return 0;
|
|
10992
11282
|
}
|
|
@@ -10997,7 +11287,7 @@ function ac_zoom_out$2(gobj, event, kw, src) {
|
|
|
10997
11287
|
let graph = gobj.priv.graph;
|
|
10998
11288
|
if (graph) {
|
|
10999
11289
|
let z = graph.getZoom();
|
|
11000
|
-
graph.zoomTo(z * .8);
|
|
11290
|
+
after_camera$2(gobj, graph.zoomTo(z * .8));
|
|
11001
11291
|
}
|
|
11002
11292
|
return 0;
|
|
11003
11293
|
}
|
|
@@ -11005,10 +11295,14 @@ function ac_zoom_out$2(gobj, event, kw, src) {
|
|
|
11005
11295
|
*
|
|
11006
11296
|
************************************************************/
|
|
11007
11297
|
function ac_zoom_reset$2(gobj, event, kw, src) {
|
|
11008
|
-
let
|
|
11298
|
+
let priv = gobj.priv;
|
|
11299
|
+
let graph = priv.graph;
|
|
11009
11300
|
if (graph && graph.rendered) {
|
|
11010
|
-
graph.zoomTo(1);
|
|
11011
|
-
|
|
11301
|
+
if (priv.anchor_state === "on" && priv.anchor_id) after_camera$2(gobj, graph.zoomTo(1));
|
|
11302
|
+
else {
|
|
11303
|
+
graph.zoomTo(1);
|
|
11304
|
+
graph.translateTo([0, 0]);
|
|
11305
|
+
}
|
|
11012
11306
|
}
|
|
11013
11307
|
return 0;
|
|
11014
11308
|
}
|
|
@@ -11027,12 +11321,21 @@ function ac_center$2(gobj, event, kw, src) {
|
|
|
11027
11321
|
*
|
|
11028
11322
|
************************************************************/
|
|
11029
11323
|
function ac_node_click$4(gobj, event, kw, src) {
|
|
11030
|
-
let
|
|
11324
|
+
let priv = gobj.priv;
|
|
11325
|
+
let graph = priv.graph;
|
|
11031
11326
|
let node_id = kw.evt.target.id;
|
|
11032
11327
|
let nodedata;
|
|
11033
11328
|
try {
|
|
11034
11329
|
nodedata = graph.getNodeData(node_id);
|
|
11035
11330
|
} catch (e) {}
|
|
11331
|
+
if (priv.anchor_state === "arming") {
|
|
11332
|
+
priv.anchor_id = node_id;
|
|
11333
|
+
priv.anchor_path = nodedata && nodedata.data ? nodedata.data.path : "";
|
|
11334
|
+
priv.anchor_state = "on";
|
|
11335
|
+
yui_graph_update_anchor((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container"), priv.anchor_state);
|
|
11336
|
+
yui_graph_center_on(graph, node_id);
|
|
11337
|
+
return 0;
|
|
11338
|
+
}
|
|
11036
11339
|
if (nodedata && nodedata.data) (0, _yuneta_gobj_js.gobj_publish_event)(gobj, "EV_JSON_ITEM_CLICKED", {
|
|
11037
11340
|
path: nodedata.data.path,
|
|
11038
11341
|
id: node_id
|
|
@@ -11166,6 +11469,11 @@ function create_gclass$11(gclass_name) {
|
|
|
11166
11469
|
ac_node_click$4,
|
|
11167
11470
|
null
|
|
11168
11471
|
],
|
|
11472
|
+
[
|
|
11473
|
+
"EV_TOGGLE_ANCHOR",
|
|
11474
|
+
ac_toggle_anchor$2,
|
|
11475
|
+
null
|
|
11476
|
+
],
|
|
11169
11477
|
[
|
|
11170
11478
|
"EV_RESIZE",
|
|
11171
11479
|
ac_resize$2,
|
|
@@ -11196,6 +11504,7 @@ function create_gclass$11(gclass_name) {
|
|
|
11196
11504
|
["EV_ZOOM_RESET", 0],
|
|
11197
11505
|
["EV_CENTER", 0],
|
|
11198
11506
|
["EV_NODE_CLICK", 0],
|
|
11507
|
+
["EV_TOGGLE_ANCHOR", 0],
|
|
11199
11508
|
["EV_RESIZE", 0],
|
|
11200
11509
|
["EV_SHOW", 0],
|
|
11201
11510
|
["EV_HIDE", 0],
|
|
@@ -12717,7 +13026,11 @@ var PRIVATE_DATA$9 = {
|
|
|
12717
13026
|
node_by_id: null,
|
|
12718
13027
|
collapse_state: null,
|
|
12719
13028
|
resize_observer: null,
|
|
12720
|
-
_resize_raf: 0
|
|
13029
|
+
_resize_raf: 0,
|
|
13030
|
+
anchor_id: "",
|
|
13031
|
+
anchor_name: "",
|
|
13032
|
+
anchor_state: "off",
|
|
13033
|
+
last_zoom: 1
|
|
12721
13034
|
};
|
|
12722
13035
|
var __gclass__$9 = null;
|
|
12723
13036
|
var __layout_registered__ = false;
|
|
@@ -13110,6 +13423,7 @@ function make_toolbar$1(gobj) {
|
|
|
13110
13423
|
let center_items = [];
|
|
13111
13424
|
let right_items = [];
|
|
13112
13425
|
center_items = yui_graph_camera_items(gobj, priv.graph, toolbar_wide);
|
|
13426
|
+
center_items.push(yui_graph_anchor_item(gobj, toolbar_wide));
|
|
13113
13427
|
center_items.push(yui_graph_refresh_item(gobj, toolbar_wide));
|
|
13114
13428
|
let options = [];
|
|
13115
13429
|
for (let key of Object.keys(LAYOUTS)) {
|
|
@@ -13185,6 +13499,15 @@ function build_graph$2(gobj) {
|
|
|
13185
13499
|
if (priv.theme) graph.setTheme(priv.theme);
|
|
13186
13500
|
graph.on("aftertransform", () => {
|
|
13187
13501
|
yui_graph_update_zoom((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container"), priv.graph);
|
|
13502
|
+
let z = priv.last_zoom;
|
|
13503
|
+
try {
|
|
13504
|
+
z = priv.graph.getZoom();
|
|
13505
|
+
} catch (e) {
|
|
13506
|
+
return;
|
|
13507
|
+
}
|
|
13508
|
+
if (z === priv.last_zoom) return;
|
|
13509
|
+
priv.last_zoom = z;
|
|
13510
|
+
if (priv.anchor_state === "on" && priv.anchor_id) yui_graph_center_on(priv.graph, priv.anchor_id);
|
|
13188
13511
|
});
|
|
13189
13512
|
graph.on(_antv_g6.NodeEvent.CLICK, (evt) => {
|
|
13190
13513
|
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_NODE_CLICK", { evt }, gobj);
|
|
@@ -13472,13 +13795,23 @@ function load_tree(gobj) {
|
|
|
13472
13795
|
let edges = [];
|
|
13473
13796
|
build_gobj_nodes(gobj, yuno, nodes, edges, null, true, layout_cfg.compact);
|
|
13474
13797
|
if (nodes.length > 0) {
|
|
13798
|
+
let root_id = nodes[0].id;
|
|
13475
13799
|
graph.setData({
|
|
13476
13800
|
nodes,
|
|
13477
13801
|
edges
|
|
13478
13802
|
});
|
|
13479
13803
|
graph.render().then(() => {
|
|
13480
|
-
|
|
13481
|
-
|
|
13804
|
+
reanchor(gobj);
|
|
13805
|
+
if (anchor) {
|
|
13806
|
+
restore_view_anchored(gobj, anchor);
|
|
13807
|
+
return;
|
|
13808
|
+
}
|
|
13809
|
+
if (preserve_view) return;
|
|
13810
|
+
Promise.resolve(graph.zoomTo(1)).then(() => {
|
|
13811
|
+
if (!yui_graph_center_on(graph, priv.anchor_id)) yui_graph_center_on(graph, root_id);
|
|
13812
|
+
priv.last_zoom = 1;
|
|
13813
|
+
yui_graph_update_zoom((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container"), priv.graph);
|
|
13814
|
+
});
|
|
13482
13815
|
});
|
|
13483
13816
|
}
|
|
13484
13817
|
}
|
|
@@ -13980,13 +14313,77 @@ function ac_collapse_all(gobj, event, kw, src) {
|
|
|
13980
14313
|
return 0;
|
|
13981
14314
|
}
|
|
13982
14315
|
/************************************************************
|
|
14316
|
+
* Every camera action ends the same way once an anchor is
|
|
14317
|
+
* set: the thing you were reading goes back to the middle.
|
|
14318
|
+
*
|
|
14319
|
+
* Chained on the promise G6 returns rather than run beside it
|
|
14320
|
+
* -- centring before the zoom has finished centres the OLD
|
|
14321
|
+
* view, and the reader watches the node slide away and come
|
|
14322
|
+
* back.
|
|
14323
|
+
************************************************************/
|
|
14324
|
+
function after_camera$1(gobj, moved) {
|
|
14325
|
+
let priv = gobj.priv;
|
|
14326
|
+
if (priv.anchor_state !== "on" || !priv.anchor_id) return;
|
|
14327
|
+
Promise.resolve(moved).then(function() {
|
|
14328
|
+
yui_graph_center_on(priv.graph, priv.anchor_id);
|
|
14329
|
+
}).catch(function() {});
|
|
14330
|
+
}
|
|
14331
|
+
/************************************************************
|
|
14332
|
+
* Point the anchor back at its node after a rebuild.
|
|
14333
|
+
*
|
|
14334
|
+
* Node ids are generated per build, so the id the reader chose
|
|
14335
|
+
* does not survive an expand, a collapse or a refresh -- the
|
|
14336
|
+
* `full_name` does, and it is what the anchor really means:
|
|
14337
|
+
* "this gobj", not "this card".
|
|
14338
|
+
*
|
|
14339
|
+
* A gobj no longer drawn (its branch got collapsed, or it went
|
|
14340
|
+
* away) releases the anchor rather than leaving a button that
|
|
14341
|
+
* claims to be locked onto something invisible.
|
|
14342
|
+
************************************************************/
|
|
14343
|
+
function reanchor(gobj) {
|
|
14344
|
+
let priv = gobj.priv;
|
|
14345
|
+
if (priv.anchor_state !== "on" || !priv.anchor_name) return;
|
|
14346
|
+
let found = "";
|
|
14347
|
+
if (priv.node_by_id) {
|
|
14348
|
+
for (let id of Object.keys(priv.node_by_id)) if (priv.node_by_id[id].full_name === priv.anchor_name) {
|
|
14349
|
+
found = id;
|
|
14350
|
+
break;
|
|
14351
|
+
}
|
|
14352
|
+
}
|
|
14353
|
+
priv.anchor_id = found;
|
|
14354
|
+
if (!found) {
|
|
14355
|
+
priv.anchor_state = "off";
|
|
14356
|
+
priv.anchor_name = "";
|
|
14357
|
+
}
|
|
14358
|
+
yui_graph_update_anchor((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container"), priv.anchor_state);
|
|
14359
|
+
}
|
|
14360
|
+
/************************************************************
|
|
14361
|
+
* Arm the anchor, or let it go.
|
|
14362
|
+
*
|
|
14363
|
+
* Three states and one button, so a press ADVANCES: with no
|
|
14364
|
+
* target it starts waiting for one, and with a target it
|
|
14365
|
+
* releases. Pressing it while it waits is a cancel, which is
|
|
14366
|
+
* what somebody who pressed it by mistake will try.
|
|
14367
|
+
************************************************************/
|
|
14368
|
+
function ac_toggle_anchor$1(gobj, event, kw, src) {
|
|
14369
|
+
let priv = gobj.priv;
|
|
14370
|
+
if (priv.anchor_state === "off") priv.anchor_state = "arming";
|
|
14371
|
+
else {
|
|
14372
|
+
priv.anchor_state = "off";
|
|
14373
|
+
priv.anchor_id = "";
|
|
14374
|
+
priv.anchor_name = "";
|
|
14375
|
+
}
|
|
14376
|
+
yui_graph_update_anchor((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container"), priv.anchor_state);
|
|
14377
|
+
return 0;
|
|
14378
|
+
}
|
|
14379
|
+
/************************************************************
|
|
13983
14380
|
*
|
|
13984
14381
|
************************************************************/
|
|
13985
14382
|
function ac_zoom_in$1(gobj, event, kw, src) {
|
|
13986
14383
|
let graph = gobj.priv.graph;
|
|
13987
14384
|
if (graph) {
|
|
13988
14385
|
let z = graph.getZoom();
|
|
13989
|
-
graph.zoomTo(z * 1.2);
|
|
14386
|
+
after_camera$1(gobj, graph.zoomTo(z * 1.2));
|
|
13990
14387
|
}
|
|
13991
14388
|
return 0;
|
|
13992
14389
|
}
|
|
@@ -13997,7 +14394,7 @@ function ac_zoom_out$1(gobj, event, kw, src) {
|
|
|
13997
14394
|
let graph = gobj.priv.graph;
|
|
13998
14395
|
if (graph) {
|
|
13999
14396
|
let z = graph.getZoom();
|
|
14000
|
-
graph.zoomTo(z * .8);
|
|
14397
|
+
after_camera$1(gobj, graph.zoomTo(z * .8));
|
|
14001
14398
|
}
|
|
14002
14399
|
return 0;
|
|
14003
14400
|
}
|
|
@@ -14005,10 +14402,14 @@ function ac_zoom_out$1(gobj, event, kw, src) {
|
|
|
14005
14402
|
*
|
|
14006
14403
|
************************************************************/
|
|
14007
14404
|
function ac_zoom_reset$1(gobj, event, kw, src) {
|
|
14008
|
-
let
|
|
14405
|
+
let priv = gobj.priv;
|
|
14406
|
+
let graph = priv.graph;
|
|
14009
14407
|
if (graph && graph.rendered) {
|
|
14010
|
-
graph.zoomTo(1);
|
|
14011
|
-
|
|
14408
|
+
if (priv.anchor_state === "on" && priv.anchor_id) after_camera$1(gobj, graph.zoomTo(1));
|
|
14409
|
+
else {
|
|
14410
|
+
graph.zoomTo(1);
|
|
14411
|
+
graph.translateTo([0, 0]);
|
|
14412
|
+
}
|
|
14012
14413
|
}
|
|
14013
14414
|
return 0;
|
|
14014
14415
|
}
|
|
@@ -14036,6 +14437,14 @@ function ac_node_click$3(gobj, event, kw, src) {
|
|
|
14036
14437
|
if (nd && nd.data) node_data = nd.data;
|
|
14037
14438
|
} catch (e) {}
|
|
14038
14439
|
if (!node_data) return 0;
|
|
14440
|
+
if (priv.anchor_state === "arming") {
|
|
14441
|
+
priv.anchor_id = node_id;
|
|
14442
|
+
priv.anchor_name = node_data.full_name || "";
|
|
14443
|
+
priv.anchor_state = "on";
|
|
14444
|
+
yui_graph_update_anchor((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container"), priv.anchor_state);
|
|
14445
|
+
yui_graph_center_on(graph, node_id);
|
|
14446
|
+
return 0;
|
|
14447
|
+
}
|
|
14039
14448
|
let client_x = kw.evt && kw.evt.client ? kw.evt.client.x : 0;
|
|
14040
14449
|
let client_y = kw.evt && kw.evt.client ? kw.evt.client.y : 0;
|
|
14041
14450
|
show_popover(gobj, node_data, client_x, client_y);
|
|
@@ -14116,6 +14525,7 @@ function create_gclass$9(gclass_name) {
|
|
|
14116
14525
|
["EV_ZOOM_RESET", 0],
|
|
14117
14526
|
["EV_CENTER", 0],
|
|
14118
14527
|
["EV_NODE_CLICK", 0],
|
|
14528
|
+
["EV_TOGGLE_ANCHOR", 0],
|
|
14119
14529
|
["EV_RESIZE", 0],
|
|
14120
14530
|
["EV_SHOW", 0],
|
|
14121
14531
|
["EV_HIDE", 0]
|
|
@@ -14175,6 +14585,11 @@ function create_gclass$9(gclass_name) {
|
|
|
14175
14585
|
ac_node_click$3,
|
|
14176
14586
|
null
|
|
14177
14587
|
],
|
|
14588
|
+
[
|
|
14589
|
+
"EV_TOGGLE_ANCHOR",
|
|
14590
|
+
ac_toggle_anchor$1,
|
|
14591
|
+
null
|
|
14592
|
+
],
|
|
14178
14593
|
[
|
|
14179
14594
|
"EV_RESIZE",
|
|
14180
14595
|
ac_resize$1,
|
|
@@ -20737,131 +21152,6 @@ function register_c_yui_treedb_topic_with_form() {
|
|
|
20737
21152
|
return create_gclass$5(GCLASS_NAME$5);
|
|
20738
21153
|
}
|
|
20739
21154
|
//#endregion
|
|
20740
|
-
//#region src/lib_graph.js
|
|
20741
|
-
/***********************************************************************
|
|
20742
|
-
* lib_graph.js
|
|
20743
|
-
*
|
|
20744
|
-
* Utilities for graph, using Bulma
|
|
20745
|
-
*
|
|
20746
|
-
* Copyright (c) 2025, ArtGins.
|
|
20747
|
-
* All Rights Reserved.
|
|
20748
|
-
***********************************************************************/
|
|
20749
|
-
/************************************************************
|
|
20750
|
-
* Add class to elements selected
|
|
20751
|
-
************************************************************/
|
|
20752
|
-
function addClasses($container, selector, ...classNames) {
|
|
20753
|
-
$container.querySelectorAll(selector).forEach((el) => el.classList.add(...classNames));
|
|
20754
|
-
}
|
|
20755
|
-
/************************************************************
|
|
20756
|
-
* Remove class from elements selected
|
|
20757
|
-
************************************************************/
|
|
20758
|
-
function removeClasses($container, selector, ...classNames) {
|
|
20759
|
-
$container.querySelectorAll(selector).forEach((el) => el.classList.remove(...classNames));
|
|
20760
|
-
}
|
|
20761
|
-
/************************************************************
|
|
20762
|
-
* Toggle class to elements selected
|
|
20763
|
-
************************************************************/
|
|
20764
|
-
function toggleClasses($container, selector, ...classNames) {
|
|
20765
|
-
$container.querySelectorAll(selector).forEach((el) => classNames.forEach((cls) => el.classList.toggle(cls)));
|
|
20766
|
-
}
|
|
20767
|
-
/************************************************************
|
|
20768
|
-
* Remove child elements
|
|
20769
|
-
************************************************************/
|
|
20770
|
-
function removeChildElements($element) {
|
|
20771
|
-
$element.innerHTML = "";
|
|
20772
|
-
}
|
|
20773
|
-
/************************************************************
|
|
20774
|
-
* Disable/Enable elements
|
|
20775
|
-
************************************************************/
|
|
20776
|
-
function disableElements($container, selector) {
|
|
20777
|
-
$container.querySelectorAll(selector).forEach((el) => {
|
|
20778
|
-
el.setAttribute("disabled", "");
|
|
20779
|
-
});
|
|
20780
|
-
}
|
|
20781
|
-
function enableElements($container, selector) {
|
|
20782
|
-
$container.querySelectorAll(selector).forEach((el) => {
|
|
20783
|
-
if (el.hasAttribute("disabled")) el.removeAttribute("disabled");
|
|
20784
|
-
});
|
|
20785
|
-
}
|
|
20786
|
-
/************************************************************
|
|
20787
|
-
* Set or reset the color of 'enable submit action' state
|
|
20788
|
-
* Color green
|
|
20789
|
-
************************************************************/
|
|
20790
|
-
function set_submit_state($container, selector, set) {
|
|
20791
|
-
if (set) addClasses($container, selector, "color_submit_state");
|
|
20792
|
-
else removeClasses($container, selector, "color_submit_state");
|
|
20793
|
-
}
|
|
20794
|
-
/************************************************************
|
|
20795
|
-
* Set or reset the color of 'enable cancel action' state
|
|
20796
|
-
* Color red
|
|
20797
|
-
************************************************************/
|
|
20798
|
-
function set_cancel_state($container, selector, set) {
|
|
20799
|
-
if (set) addClasses($container, selector, "color_cancel_state");
|
|
20800
|
-
else removeClasses($container, selector, "color_cancel_state");
|
|
20801
|
-
}
|
|
20802
|
-
/************************************************************
|
|
20803
|
-
* Set or reset the color of 'enable actived' state
|
|
20804
|
-
* Color orange
|
|
20805
|
-
************************************************************/
|
|
20806
|
-
function set_active_state($container, selector, set) {
|
|
20807
|
-
if (set) addClasses($container, selector, "color_active_state");
|
|
20808
|
-
else removeClasses($container, selector, "color_active_state");
|
|
20809
|
-
}
|
|
20810
|
-
/************************************************************
|
|
20811
|
-
* Set or reset the 'pressed' state of a TOGGLE.
|
|
20812
|
-
*
|
|
20813
|
-
* Not one of the colours above: each of those names a KIND of
|
|
20814
|
-
* action (create, pending, history, destructive), and a toggle
|
|
20815
|
-
* is not an action -- it is a state the control is IN. So it
|
|
20816
|
-
* looks pressed instead of changing category, which also keeps
|
|
20817
|
-
* it out of the way of a neighbour wearing the same hue.
|
|
20818
|
-
************************************************************/
|
|
20819
|
-
function set_pressed_state($container, selector, set) {
|
|
20820
|
-
if (set) addClasses($container, selector, "pressed_state");
|
|
20821
|
-
else removeClasses($container, selector, "pressed_state");
|
|
20822
|
-
}
|
|
20823
|
-
/**
|
|
20824
|
-
* Returns a smart stroke color in `rgba()` format based on:
|
|
20825
|
-
* - The given fill color (hex or rgb[a])
|
|
20826
|
-
* - The current theme ('light' or 'dark')
|
|
20827
|
-
* - The adjustment factor (default 0.2)
|
|
20828
|
-
*
|
|
20829
|
-
* @param {string} fillColor - Fill color string
|
|
20830
|
-
* @param {string} theme - 'light' or 'dark'
|
|
20831
|
-
* @param {number} factor - Lighten/darken factor (default 0.2)
|
|
20832
|
-
* @returns {string} rgba(r, g, b, a)
|
|
20833
|
-
*/
|
|
20834
|
-
function getStrokeColor(fillColor, theme = "light", factor = .2) {
|
|
20835
|
-
let r, g, b, a = 1;
|
|
20836
|
-
if (fillColor.startsWith("#")) {
|
|
20837
|
-
let hex = fillColor.slice(1);
|
|
20838
|
-
if (hex.length === 3 || hex.length === 4) hex = hex.split("").map((c) => c + c).join("");
|
|
20839
|
-
if (hex.length === 6) {
|
|
20840
|
-
r = parseInt(hex.slice(0, 2), 16);
|
|
20841
|
-
g = parseInt(hex.slice(2, 4), 16);
|
|
20842
|
-
b = parseInt(hex.slice(4, 6), 16);
|
|
20843
|
-
} else if (hex.length === 8) {
|
|
20844
|
-
r = parseInt(hex.slice(0, 2), 16);
|
|
20845
|
-
g = parseInt(hex.slice(2, 4), 16);
|
|
20846
|
-
b = parseInt(hex.slice(4, 6), 16);
|
|
20847
|
-
a = parseInt(hex.slice(6, 8), 16) / 255;
|
|
20848
|
-
} else throw new Error("Unsupported hex format");
|
|
20849
|
-
} else if (fillColor.startsWith("rgb")) {
|
|
20850
|
-
const match = fillColor.match(/rgba?\(\s*(\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\s*\)/);
|
|
20851
|
-
if (!match) throw new Error("Invalid rgb()/rgba() format.");
|
|
20852
|
-
r = parseInt(match[1], 10);
|
|
20853
|
-
g = parseInt(match[2], 10);
|
|
20854
|
-
b = parseInt(match[3], 10);
|
|
20855
|
-
if (match[4] !== void 0) a = parseFloat(match[4]);
|
|
20856
|
-
} else throw new Error("Unsupported color format.");
|
|
20857
|
-
const luminance = (.299 * r + .587 * g + .114 * b) / 255;
|
|
20858
|
-
let lighten;
|
|
20859
|
-
if (theme === "dark") lighten = luminance < .7;
|
|
20860
|
-
else lighten = luminance < .3;
|
|
20861
|
-
const adjust = (v) => lighten ? Math.min(255, Math.floor(v + (255 - v) * factor)) : Math.max(0, Math.floor(v * (1 - factor)));
|
|
20862
|
-
return `rgba(${adjust(r)}, ${adjust(g)}, ${adjust(b)}, ${a.toFixed(3)})`;
|
|
20863
|
-
}
|
|
20864
|
-
//#endregion
|
|
20865
21155
|
//#region src/treedb_node_label.js
|
|
20866
21156
|
/***********************************************************************
|
|
20867
21157
|
* treedb_node_label.js
|
|
@@ -47729,6 +48019,13 @@ var ICONS = `<svg xmlns="http://www.w3.org/2000/svg">
|
|
|
47729
48019
|
stroke="currentColor" stroke-width="40"
|
|
47730
48020
|
stroke-dasharray="59 36"/>
|
|
47731
48021
|
</symbol>
|
|
48022
|
+
<!-- location-crosshairs (anchor the camera on one element).
|
|
48023
|
+
The SAME path as the DOM toolbars and their yi-location-crosshairs
|
|
48024
|
+
mask: the two toolbars sit in one console, and a control that
|
|
48025
|
+
does one thing has to be drawn one way. -->
|
|
48026
|
+
<symbol id="g6-icon-anchor" viewBox="0 0 576 512">
|
|
48027
|
+
<path fill="currentColor" d="M288-16c17.7 0 32 14.3 32 32l0 18.3c98.1 14 175.7 91.6 189.7 189.7l18.3 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-18.3 0c-14 98.1-91.6 175.7-189.7 189.7l0 18.3c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-18.3C157.9 463.7 80.3 386.1 66.3 288L48 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l18.3 0C80.3 125.9 157.9 48.3 256 34.3L256 16c0-17.7 14.3-32 32-32zM128 256a160 160 0 1 0 320 0 160 160 0 1 0 -320 0zm160-96a96 96 0 1 1 0 192 96 96 0 1 1 0-192z"/>
|
|
48028
|
+
</symbol>
|
|
47732
48029
|
<!-- floppy-disk (save) -->
|
|
47733
48030
|
<symbol id="g6-icon-save" viewBox="0 0 448 512">
|
|
47734
48031
|
<path fill="currentColor" d="M64 32C28.7 32 0 60.7 0 96L0 416c0 35.3 28.7 64 64 64l320 0c35.3 0 64-28.7 64-64l0-242.7c0-17-6.7-33.3-18.7-45.3L352 50.7C340 38.7 323.7 32 306.7 32L64 32zm32 96c0-17.7 14.3-32 32-32l160 0c17.7 0 32 14.3 32 32l0 64c0 17.7-14.3 32-32 32l-160 0c-17.7 0-32-14.3-32-32l0-64zM224 288a64 64 0 1 1 0 128 64 64 0 1 1 0-128z"/>
|
|
@@ -47922,6 +48219,9 @@ var attrs_table$4 = [
|
|
|
47922
48219
|
(0, _yuneta_gobj_js.SDATA_END)()
|
|
47923
48220
|
];
|
|
47924
48221
|
var PRIVATE_DATA$4 = {
|
|
48222
|
+
anchor_id: "",
|
|
48223
|
+
anchor_state: "off",
|
|
48224
|
+
last_zoom: 1,
|
|
47925
48225
|
_xy: 100,
|
|
47926
48226
|
_edge_seq: 0,
|
|
47927
48227
|
_history_paused: false,
|
|
@@ -48218,6 +48518,15 @@ function configure_events(gobj) {
|
|
|
48218
48518
|
update_node_icon_position(gobj);
|
|
48219
48519
|
update_link_icon_position(gobj);
|
|
48220
48520
|
update_zoom_readout(gobj);
|
|
48521
|
+
let z = priv.last_zoom;
|
|
48522
|
+
try {
|
|
48523
|
+
z = priv.graph.getZoom();
|
|
48524
|
+
} catch (e) {
|
|
48525
|
+
return;
|
|
48526
|
+
}
|
|
48527
|
+
if (z === priv.last_zoom) return;
|
|
48528
|
+
priv.last_zoom = z;
|
|
48529
|
+
if (priv.anchor_state === "on" && priv.anchor_id) yui_graph_center_on(priv.graph, priv.anchor_id);
|
|
48221
48530
|
});
|
|
48222
48531
|
priv._on_language_changed = () => {
|
|
48223
48532
|
update_toolbar(gobj);
|
|
@@ -48455,6 +48764,12 @@ function configure_toolbar(gobj) {
|
|
|
48455
48764
|
value: "reset",
|
|
48456
48765
|
className: "EV_ZOOM_RESET",
|
|
48457
48766
|
title: (0, i18next.t)("actual size")
|
|
48767
|
+
},
|
|
48768
|
+
{
|
|
48769
|
+
id: "g6-icon-anchor",
|
|
48770
|
+
value: "anchor",
|
|
48771
|
+
className: "EV_TOGGLE_ANCHOR" + (priv.anchor_state !== "off" ? " pressed_state" : "") + (priv.anchor_state === "arming" ? " color_pending_state" : ""),
|
|
48772
|
+
title: anchor_title(priv.anchor_state)
|
|
48458
48773
|
}
|
|
48459
48774
|
];
|
|
48460
48775
|
if (priv.edit_mode) items.push({
|
|
@@ -48496,6 +48811,9 @@ function configure_toolbar(gobj) {
|
|
|
48496
48811
|
case "reset":
|
|
48497
48812
|
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_ZOOM_RESET", {}, gobj);
|
|
48498
48813
|
break;
|
|
48814
|
+
case "anchor":
|
|
48815
|
+
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_TOGGLE_ANCHOR", {}, gobj);
|
|
48816
|
+
break;
|
|
48499
48817
|
case "auto-fit":
|
|
48500
48818
|
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_AUTO_FIT", {}, gobj);
|
|
48501
48819
|
break;
|
|
@@ -49506,12 +49824,12 @@ function graph_find_nodes(gobj, term) {
|
|
|
49506
49824
|
async function graph_zoom_in(gobj) {
|
|
49507
49825
|
let graph = gobj.priv.graph;
|
|
49508
49826
|
const z = graph.getZoom();
|
|
49509
|
-
|
|
49827
|
+
after_camera(gobj, graph.zoomTo(z * 1.1));
|
|
49510
49828
|
}
|
|
49511
49829
|
async function graph_zoom_out(gobj) {
|
|
49512
49830
|
let graph = gobj.priv.graph;
|
|
49513
49831
|
const z = graph.getZoom();
|
|
49514
|
-
|
|
49832
|
+
after_camera(gobj, graph.zoomTo(z * .9));
|
|
49515
49833
|
}
|
|
49516
49834
|
async function graph_render(gobj) {
|
|
49517
49835
|
await gobj.priv.graph.render();
|
|
@@ -52512,7 +52830,56 @@ function ac_zoom_out(gobj, event, kw, src) {
|
|
|
52512
52830
|
return 0;
|
|
52513
52831
|
}
|
|
52514
52832
|
function ac_zoom_reset(gobj, event, kw, src) {
|
|
52515
|
-
gobj.priv
|
|
52833
|
+
let priv = gobj.priv;
|
|
52834
|
+
let graph = priv.graph;
|
|
52835
|
+
if (priv.anchor_state === "on" && priv.anchor_id) after_camera(gobj, graph.zoomTo(1));
|
|
52836
|
+
else graph.zoomTo(1);
|
|
52837
|
+
return 0;
|
|
52838
|
+
}
|
|
52839
|
+
/************************************************************
|
|
52840
|
+
* What the anchor button says it will do next.
|
|
52841
|
+
************************************************************/
|
|
52842
|
+
function anchor_title(state) {
|
|
52843
|
+
if (state === "arming") return (0, i18next.t)("click the element to centre on");
|
|
52844
|
+
if (state === "on") return (0, i18next.t)("centred: click to release");
|
|
52845
|
+
return (0, i18next.t)("anchor view");
|
|
52846
|
+
}
|
|
52847
|
+
/************************************************************
|
|
52848
|
+
* Every camera action ends the same way once an anchor is
|
|
52849
|
+
* set: the thing you were reading goes back to the middle.
|
|
52850
|
+
*
|
|
52851
|
+
* Chained on the promise G6 returns rather than run beside it
|
|
52852
|
+
* -- centring before the zoom has finished centres the OLD
|
|
52853
|
+
* view, and the reader watches the node slide away and come
|
|
52854
|
+
* back.
|
|
52855
|
+
************************************************************/
|
|
52856
|
+
function after_camera(gobj, moved) {
|
|
52857
|
+
let priv = gobj.priv;
|
|
52858
|
+
if (priv.anchor_state !== "on" || !priv.anchor_id) return;
|
|
52859
|
+
Promise.resolve(moved).then(function() {
|
|
52860
|
+
yui_graph_center_on(priv.graph, priv.anchor_id);
|
|
52861
|
+
}).catch(function() {});
|
|
52862
|
+
}
|
|
52863
|
+
/************************************************************
|
|
52864
|
+
* Arm the anchor, or let it go.
|
|
52865
|
+
*
|
|
52866
|
+
* Three states and one button, so a press ADVANCES: with no
|
|
52867
|
+
* target it starts waiting for one, and with a target it
|
|
52868
|
+
* releases. Pressing it while it waits is a cancel, which is
|
|
52869
|
+
* what somebody who pressed it by mistake will try.
|
|
52870
|
+
*
|
|
52871
|
+
* Unlike the DOM toolbars, the button is not repainted in
|
|
52872
|
+
* place: this toolbar is a G6 plugin that rebuilds its whole
|
|
52873
|
+
* item list, and the pressed classes are baked into that list.
|
|
52874
|
+
************************************************************/
|
|
52875
|
+
function ac_toggle_anchor(gobj, event, kw, src) {
|
|
52876
|
+
let priv = gobj.priv;
|
|
52877
|
+
if (priv.anchor_state === "off") priv.anchor_state = "arming";
|
|
52878
|
+
else {
|
|
52879
|
+
priv.anchor_state = "off";
|
|
52880
|
+
priv.anchor_id = "";
|
|
52881
|
+
}
|
|
52882
|
+
update_toolbar(gobj);
|
|
52516
52883
|
return 0;
|
|
52517
52884
|
}
|
|
52518
52885
|
/************************************************************
|
|
@@ -52686,6 +53053,13 @@ function ac_node_click$2(gobj, event, kw, src) {
|
|
|
52686
53053
|
let priv = gobj.priv;
|
|
52687
53054
|
let graph = priv.graph;
|
|
52688
53055
|
let node_id = kw.evt.target.id;
|
|
53056
|
+
if (priv.anchor_state === "arming") {
|
|
53057
|
+
priv.anchor_id = node_id;
|
|
53058
|
+
priv.anchor_state = "on";
|
|
53059
|
+
update_toolbar(gobj);
|
|
53060
|
+
yui_graph_center_on(graph, node_id);
|
|
53061
|
+
return 0;
|
|
53062
|
+
}
|
|
52689
53063
|
try {
|
|
52690
53064
|
let nodedata = graph.getNodeData(node_id);
|
|
52691
53065
|
if (nodedata && nodedata.data && nodedata.data.desc) {
|
|
@@ -52947,6 +53321,11 @@ function create_gclass$4(gclass_name) {
|
|
|
52947
53321
|
ac_zoom_reset,
|
|
52948
53322
|
null
|
|
52949
53323
|
],
|
|
53324
|
+
[
|
|
53325
|
+
"EV_TOGGLE_ANCHOR",
|
|
53326
|
+
ac_toggle_anchor,
|
|
53327
|
+
null
|
|
53328
|
+
],
|
|
52950
53329
|
[
|
|
52951
53330
|
"EV_TOGGLE_TOOLBARS",
|
|
52952
53331
|
ac_toggle_toolbars,
|
|
@@ -53060,6 +53439,7 @@ function create_gclass$4(gclass_name) {
|
|
|
53060
53439
|
["EV_ZOOM_IN", 0],
|
|
53061
53440
|
["EV_ZOOM_OUT", 0],
|
|
53062
53441
|
["EV_ZOOM_RESET", 0],
|
|
53442
|
+
["EV_TOGGLE_ANCHOR", 0],
|
|
53063
53443
|
["EV_TOGGLE_TOOLBARS", 0],
|
|
53064
53444
|
["EV_AUTO_FIT", 0],
|
|
53065
53445
|
["EV_ZOOM_SELECTION", 0],
|