@yuneta/gobj-ui 7.23.8 → 7.23.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/README.md +53 -0
- package/dist/gobj-ui.cjs.js +538 -71
- package/dist/gobj-ui.es.js +539 -72
- package/package.json +1 -1
- package/src/c_g6_nodes_tree.js +415 -55
- package/src/c_yui_gobj_tree_js.js +2 -0
- package/src/c_yui_json_graph.js +2 -0
- package/src/g6_drag_canvas_touch.js +21 -0
- package/src/g6_touch_gestures.js +413 -0
- package/src/lib_graph.css +19 -0
- package/src/lib_icons.js +14 -0
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -9504,6 +9504,275 @@ function yui_graph_refresh_item(gobj, wide) {
|
|
|
9504
9504
|
return camera_button(gobj, "yi-arrows-rotate", "EV_REFRESH", "refresh", wide);
|
|
9505
9505
|
}
|
|
9506
9506
|
//#endregion
|
|
9507
|
+
//#region src/g6_touch_gestures.js
|
|
9508
|
+
/***********************************************************************
|
|
9509
|
+
* g6_touch_gestures.js
|
|
9510
|
+
*
|
|
9511
|
+
* The two gestures a G6 graph needs on a touch screen and
|
|
9512
|
+
* does not have: PINCH to zoom, and LONG PRESS to open the
|
|
9513
|
+
* context menu.
|
|
9514
|
+
*
|
|
9515
|
+
* Why this exists
|
|
9516
|
+
* ----------------
|
|
9517
|
+
* G6 v5 draws a graph that reads fine on a phone and cannot
|
|
9518
|
+
* be OPERATED on one. Two gaps, both structural:
|
|
9519
|
+
*
|
|
9520
|
+
* 1. `zoom-canvas` binds the WHEEL and nothing else
|
|
9521
|
+
* (`trigger: []`). There is no wheel on a phone, so the
|
|
9522
|
+
* only zoom is the toolbar's +/- buttons. G6 does ship a
|
|
9523
|
+
* pinch recogniser, and `zoom-canvas` will use it -- with
|
|
9524
|
+
* `trigger: ['pinch']`, which its `bindEvents` treats as
|
|
9525
|
+
* an ALTERNATIVE to the wheel (`if pinch ... else wheel`),
|
|
9526
|
+
* so opting in costs the mouse. Worse, its `PinchHandler`
|
|
9527
|
+
* keeps its instance and its callback list in STATICS: on
|
|
9528
|
+
* a page with two graphs the second one registers its
|
|
9529
|
+
* callback against the FIRST one's emitter, so pinching
|
|
9530
|
+
* graph A zooms both and pinching graph B does nothing.
|
|
9531
|
+
* We recognise the gesture ourselves, per graph.
|
|
9532
|
+
*
|
|
9533
|
+
* 2. The context menu is bound to `contextmenu`, and G6 does
|
|
9534
|
+
* not take that from the DOM: its `BehaviorController`
|
|
9535
|
+
* SYNTHESISES it from `pointerdown` with `button === 2`.
|
|
9536
|
+
* A long press therefore never reaches the plugin on ANY
|
|
9537
|
+
* platform, whatever the browser does with the gesture.
|
|
9538
|
+
* So we synthesise it the same way G6 does, from the same
|
|
9539
|
+
* forwarded event object -- which is why the plugin's
|
|
9540
|
+
* `getItems(e)` receives exactly the shape it expects.
|
|
9541
|
+
*
|
|
9542
|
+
* Both are built on ONE per-graph record of the fingers
|
|
9543
|
+
* on the glass, read from the NATIVE touch events -- see
|
|
9544
|
+
* `touch_state_of` for why the pointer stream, which looks
|
|
9545
|
+
* like the right source, is not. That record is also what
|
|
9546
|
+
* tells `drag-canvas` to stop panning while two fingers are
|
|
9547
|
+
* down (`is_pinching`), the guard G6's own drag-canvas has
|
|
9548
|
+
* and our replacement dropped.
|
|
9549
|
+
*
|
|
9550
|
+
* Copyright (c) 2026, ArtGins.
|
|
9551
|
+
* All Rights Reserved.
|
|
9552
|
+
***********************************************************************/
|
|
9553
|
+
/***************************************************************
|
|
9554
|
+
* Constants
|
|
9555
|
+
***************************************************************/
|
|
9556
|
+
var LONG_PRESS_MS = 500;
|
|
9557
|
+
var LONG_PRESS_SLOP = 10;
|
|
9558
|
+
/***************************************************************
|
|
9559
|
+
* Per-graph record of the fingers on the glass
|
|
9560
|
+
***************************************************************/
|
|
9561
|
+
var __touch_state__ = /* @__PURE__ */ new WeakMap();
|
|
9562
|
+
/************************************************************
|
|
9563
|
+
* The touch record of one graph, installing its listeners
|
|
9564
|
+
* the first time it is asked for.
|
|
9565
|
+
*
|
|
9566
|
+
* Read from the NATIVE touch events, not from G6's
|
|
9567
|
+
* forwarded pointer stream.
|
|
9568
|
+
*
|
|
9569
|
+
* The pointer stream looks like the right source and is
|
|
9570
|
+
* not: @antv/g re-issues pointer ids in the middle of a
|
|
9571
|
+
* two-finger gesture (measured: a pinch that started on
|
|
9572
|
+
* ids 2 and 3 finished on id 1), so anything that keys a
|
|
9573
|
+
* Map on `pointerId` loses one of the two fingers halfway
|
|
9574
|
+
* and reads the gesture as a fraction of what it was.
|
|
9575
|
+
* G6's own `PinchHandler` is built exactly that way.
|
|
9576
|
+
*
|
|
9577
|
+
* `event.touches` needs no bookkeeping at all: it IS the
|
|
9578
|
+
* list of fingers currently down, re-stated on every event.
|
|
9579
|
+
************************************************************/
|
|
9580
|
+
function touch_state_of(graph) {
|
|
9581
|
+
let state = __touch_state__.get(graph);
|
|
9582
|
+
if (state) return state;
|
|
9583
|
+
state = {
|
|
9584
|
+
count: 0,
|
|
9585
|
+
container: null
|
|
9586
|
+
};
|
|
9587
|
+
__touch_state__.set(graph, state);
|
|
9588
|
+
let container = graph.getCanvas?.()?.getContainer?.();
|
|
9589
|
+
if (!container) return state;
|
|
9590
|
+
state.container = container;
|
|
9591
|
+
let read = (event) => {
|
|
9592
|
+
state.count = event.touches ? event.touches.length : 0;
|
|
9593
|
+
};
|
|
9594
|
+
container.addEventListener("touchstart", read, { passive: true });
|
|
9595
|
+
container.addEventListener("touchmove", read, { passive: true });
|
|
9596
|
+
container.addEventListener("touchend", read, { passive: true });
|
|
9597
|
+
container.addEventListener("touchcancel", read, { passive: true });
|
|
9598
|
+
return state;
|
|
9599
|
+
}
|
|
9600
|
+
/************************************************************
|
|
9601
|
+
* Is a two-finger gesture in progress on this graph?
|
|
9602
|
+
*
|
|
9603
|
+
* Read by our `drag-canvas` replacement: panning and zooming
|
|
9604
|
+
* the same drag at the same time fights the user for the
|
|
9605
|
+
* camera.
|
|
9606
|
+
************************************************************/
|
|
9607
|
+
function is_pinching(graph) {
|
|
9608
|
+
if (!graph) return false;
|
|
9609
|
+
let state = __touch_state__.get(graph);
|
|
9610
|
+
if (!state) return false;
|
|
9611
|
+
return state.count >= 2;
|
|
9612
|
+
}
|
|
9613
|
+
/***************************
|
|
9614
|
+
* Pinch to zoom
|
|
9615
|
+
***************************/
|
|
9616
|
+
/************************************************************
|
|
9617
|
+
* `zoom-canvas` that also answers the pinch.
|
|
9618
|
+
*
|
|
9619
|
+
* The base class keeps the wheel; the pinch is added on top
|
|
9620
|
+
* instead of replacing it, so one build serves the mouse and
|
|
9621
|
+
* the finger. The scale is ABSOLUTE against the zoom the
|
|
9622
|
+
* gesture started at -- G6's own pinch feeds `zoom()` an
|
|
9623
|
+
* increment per frame, which drifts away from the fingers
|
|
9624
|
+
* over a long gesture.
|
|
9625
|
+
************************************************************/
|
|
9626
|
+
var ZoomCanvasPinch = class extends _antv_g6.ZoomCanvas {
|
|
9627
|
+
constructor(context, options) {
|
|
9628
|
+
super(context, options);
|
|
9629
|
+
this._pinch_dist0 = 0;
|
|
9630
|
+
this._pinch_zoom0 = 1;
|
|
9631
|
+
this._on_touch_move = null;
|
|
9632
|
+
let { trigger } = this.options;
|
|
9633
|
+
if (Array.isArray(trigger) && trigger.includes(_antv_g6.CommonEvent.PINCH)) return;
|
|
9634
|
+
let graph = this.context.graph;
|
|
9635
|
+
let state = touch_state_of(graph);
|
|
9636
|
+
if (!state.container) return;
|
|
9637
|
+
this._on_touch_move = (event) => {
|
|
9638
|
+
let touches = event.touches;
|
|
9639
|
+
if (!touches || touches.length !== 2) {
|
|
9640
|
+
this._pinch_dist0 = 0;
|
|
9641
|
+
return;
|
|
9642
|
+
}
|
|
9643
|
+
let dx = touches[0].clientX - touches[1].clientX;
|
|
9644
|
+
let dy = touches[0].clientY - touches[1].clientY;
|
|
9645
|
+
let dist = Math.sqrt(dx * dx + dy * dy);
|
|
9646
|
+
if (dist <= 0) return;
|
|
9647
|
+
if (this._pinch_dist0 === 0) {
|
|
9648
|
+
this._pinch_dist0 = dist;
|
|
9649
|
+
this._pinch_zoom0 = graph.getZoom();
|
|
9650
|
+
return;
|
|
9651
|
+
}
|
|
9652
|
+
this._pinch_to(dist / this._pinch_dist0, touches, event);
|
|
9653
|
+
};
|
|
9654
|
+
state.container.addEventListener("touchmove", this._on_touch_move, { passive: true });
|
|
9655
|
+
}
|
|
9656
|
+
/************************************************************
|
|
9657
|
+
* Zoom to `scale` times the zoom the pinch started at,
|
|
9658
|
+
* about the midpoint between the two fingers.
|
|
9659
|
+
*
|
|
9660
|
+
* ABSOLUTE against the start of the gesture, where G6's
|
|
9661
|
+
* own pinch feeds `zoom()` an increment per frame: an
|
|
9662
|
+
* increment drifts away from the fingers over a long
|
|
9663
|
+
* gesture, and cannot come back when they close again.
|
|
9664
|
+
************************************************************/
|
|
9665
|
+
_pinch_to(scale, touches, event) {
|
|
9666
|
+
if (!this.validate(event)) return;
|
|
9667
|
+
let graph = this.context.graph;
|
|
9668
|
+
let state = touch_state_of(graph);
|
|
9669
|
+
let origin = null;
|
|
9670
|
+
let rect = state.container?.getBoundingClientRect();
|
|
9671
|
+
if (rect) origin = [(touches[0].clientX + touches[1].clientX) / 2 - rect.left, (touches[0].clientY + touches[1].clientY) / 2 - rect.top];
|
|
9672
|
+
graph.zoomTo(this._pinch_zoom0 * scale, false, origin);
|
|
9673
|
+
this.options.onFinish?.();
|
|
9674
|
+
}
|
|
9675
|
+
destroy() {
|
|
9676
|
+
if (this._on_touch_move) {
|
|
9677
|
+
__touch_state__.get(this.context.graph)?.container?.removeEventListener("touchmove", this._on_touch_move);
|
|
9678
|
+
this._on_touch_move = null;
|
|
9679
|
+
}
|
|
9680
|
+
super.destroy();
|
|
9681
|
+
}
|
|
9682
|
+
};
|
|
9683
|
+
/************************************************************
|
|
9684
|
+
* Register once, over the built-in `zoom-canvas`, so every
|
|
9685
|
+
* graph (tree, json, treedb, editor) pinches without
|
|
9686
|
+
* touching its behaviors list.
|
|
9687
|
+
************************************************************/
|
|
9688
|
+
var __zoom_canvas_patched__ = false;
|
|
9689
|
+
function ensure_pinch_zoom_patch() {
|
|
9690
|
+
if (__zoom_canvas_patched__) return;
|
|
9691
|
+
(0, _antv_g6.register)(_antv_g6.ExtensionCategory.BEHAVIOR, "zoom-canvas", ZoomCanvasPinch);
|
|
9692
|
+
__zoom_canvas_patched__ = true;
|
|
9693
|
+
}
|
|
9694
|
+
/***************************
|
|
9695
|
+
* Long press
|
|
9696
|
+
***************************/
|
|
9697
|
+
/************************************************************
|
|
9698
|
+
* Make a long press open the context menu.
|
|
9699
|
+
*
|
|
9700
|
+
* Returns the function that uninstalls it.
|
|
9701
|
+
*
|
|
9702
|
+
* The menu the press opens is whatever the `contextmenu`
|
|
9703
|
+
* plugin builds: we re-emit G6's own forwarded event under
|
|
9704
|
+
* the name the plugin listens for, so `getItems(e)` and
|
|
9705
|
+
* `enable(e)` see the same object a right-click would give
|
|
9706
|
+
* them -- same `target`, same `targetType`, same `client`.
|
|
9707
|
+
************************************************************/
|
|
9708
|
+
function install_long_press_contextmenu(graph) {
|
|
9709
|
+
if (!graph) return () => {};
|
|
9710
|
+
let state = touch_state_of(graph);
|
|
9711
|
+
let pending = null;
|
|
9712
|
+
let cancel = () => {
|
|
9713
|
+
if (pending) {
|
|
9714
|
+
clearTimeout(pending.timer);
|
|
9715
|
+
pending = null;
|
|
9716
|
+
}
|
|
9717
|
+
};
|
|
9718
|
+
let fire = (event) => {
|
|
9719
|
+
pending = null;
|
|
9720
|
+
let swallow = (evt) => {
|
|
9721
|
+
evt.stopPropagation();
|
|
9722
|
+
document.removeEventListener("click", swallow, true);
|
|
9723
|
+
};
|
|
9724
|
+
document.addEventListener("click", swallow, true);
|
|
9725
|
+
setTimeout(() => {
|
|
9726
|
+
document.removeEventListener("click", swallow, true);
|
|
9727
|
+
}, 1e3);
|
|
9728
|
+
let container = graph.getCanvas?.()?.getContainer?.();
|
|
9729
|
+
if (container) container.addEventListener("contextmenu", (evt) => {
|
|
9730
|
+
evt.preventDefault();
|
|
9731
|
+
}, {
|
|
9732
|
+
once: true,
|
|
9733
|
+
capture: true
|
|
9734
|
+
});
|
|
9735
|
+
graph.emit(`${event.targetType}:${_antv_g6.CommonEvent.CONTEXT_MENU}`, event);
|
|
9736
|
+
graph.emit(_antv_g6.CommonEvent.CONTEXT_MENU, event);
|
|
9737
|
+
};
|
|
9738
|
+
let on_down = (event) => {
|
|
9739
|
+
cancel();
|
|
9740
|
+
if (event.pointerType !== "touch") return;
|
|
9741
|
+
if (state.count > 1) return;
|
|
9742
|
+
let x = event.client?.x;
|
|
9743
|
+
let y = event.client?.y;
|
|
9744
|
+
if (x === void 0 || y === void 0) return;
|
|
9745
|
+
let frozen = Object.assign({}, event);
|
|
9746
|
+
pending = {
|
|
9747
|
+
x,
|
|
9748
|
+
y,
|
|
9749
|
+
timer: setTimeout(() => {
|
|
9750
|
+
fire(frozen);
|
|
9751
|
+
}, LONG_PRESS_MS)
|
|
9752
|
+
};
|
|
9753
|
+
};
|
|
9754
|
+
let on_move = (event) => {
|
|
9755
|
+
if (!pending) return;
|
|
9756
|
+
if (state.count > 1) {
|
|
9757
|
+
cancel();
|
|
9758
|
+
return;
|
|
9759
|
+
}
|
|
9760
|
+
let x = event.client?.x;
|
|
9761
|
+
let y = event.client?.y;
|
|
9762
|
+
if (x === void 0 || y === void 0) return;
|
|
9763
|
+
if (Math.abs(x - pending.x) > LONG_PRESS_SLOP || Math.abs(y - pending.y) > LONG_PRESS_SLOP) cancel();
|
|
9764
|
+
};
|
|
9765
|
+
graph.on(_antv_g6.CommonEvent.POINTER_DOWN, on_down);
|
|
9766
|
+
graph.on(_antv_g6.CommonEvent.POINTER_MOVE, on_move);
|
|
9767
|
+
graph.on(_antv_g6.CommonEvent.POINTER_UP, cancel);
|
|
9768
|
+
return () => {
|
|
9769
|
+
cancel();
|
|
9770
|
+
graph.off(_antv_g6.CommonEvent.POINTER_DOWN, on_down);
|
|
9771
|
+
graph.off(_antv_g6.CommonEvent.POINTER_MOVE, on_move);
|
|
9772
|
+
graph.off(_antv_g6.CommonEvent.POINTER_UP, cancel);
|
|
9773
|
+
};
|
|
9774
|
+
}
|
|
9775
|
+
//#endregion
|
|
9507
9776
|
//#region src/g6_drag_canvas_touch.js
|
|
9508
9777
|
/***********************************************************************
|
|
9509
9778
|
* g6_drag_canvas_touch.js
|
|
@@ -9548,6 +9817,12 @@ function yui_graph_refresh_item(gobj, wide) {
|
|
|
9548
9817
|
* every graph (tree, json, treedb, editor) is fixed without
|
|
9549
9818
|
* touching each consumer's behaviors list.
|
|
9550
9819
|
*
|
|
9820
|
+
* It also has to keep the ONE guard the base class has and
|
|
9821
|
+
* this replacement dropped: G6's `onDrag` refuses to pan
|
|
9822
|
+
* while a pinch is in progress. See `is_pinching` in
|
|
9823
|
+
* `g6_touch_gestures.js`, which is where the pinch that
|
|
9824
|
+
* matters is now recognised.
|
|
9825
|
+
*
|
|
9551
9826
|
* Copyright (c) 2026, ArtGins.
|
|
9552
9827
|
* All Rights Reserved.
|
|
9553
9828
|
***********************************************************************/
|
|
@@ -9563,6 +9838,10 @@ var DragCanvasTouch = class extends _antv_g6.DragCanvas {
|
|
|
9563
9838
|
this._lastVP = null;
|
|
9564
9839
|
return;
|
|
9565
9840
|
}
|
|
9841
|
+
if (is_pinching(this.context.graph)) {
|
|
9842
|
+
this._lastVP = null;
|
|
9843
|
+
return;
|
|
9844
|
+
}
|
|
9566
9845
|
let vp = event.viewport;
|
|
9567
9846
|
if (!vp || typeof vp.x !== "number" || typeof vp.y !== "number") return;
|
|
9568
9847
|
if (this._lastVP === null) {
|
|
@@ -9792,6 +10071,7 @@ function mt_create$11(gobj) {
|
|
|
9792
10071
|
priv.theme_observer = yui_watch_theme(gobj);
|
|
9793
10072
|
build_ui$10(gobj);
|
|
9794
10073
|
ensure_drag_canvas_patch();
|
|
10074
|
+
ensure_pinch_zoom_patch();
|
|
9795
10075
|
if (!__layout_registered__$1) {
|
|
9796
10076
|
(0, _antv_g6.register)(_antv_g6.ExtensionCategory.LAYOUT, "json-tree-layout", JsonTreeLayout);
|
|
9797
10077
|
__layout_registered__$1 = true;
|
|
@@ -12420,6 +12700,7 @@ function mt_create$9(gobj) {
|
|
|
12420
12700
|
priv.theme_observer = yui_watch_theme(gobj);
|
|
12421
12701
|
build_ui$8(gobj);
|
|
12422
12702
|
ensure_drag_canvas_patch();
|
|
12703
|
+
ensure_pinch_zoom_patch();
|
|
12423
12704
|
if (!__layout_registered__) {
|
|
12424
12705
|
(0, _antv_g6.register)(_antv_g6.ExtensionCategory.LAYOUT, "gobj-tree-v", GobjTreeVLayout);
|
|
12425
12706
|
(0, _antv_g6.register)(_antv_g6.ExtensionCategory.LAYOUT, "gobj-tree-h", GobjTreeHLayout);
|
|
@@ -47198,6 +47479,20 @@ var ICONS = `<svg xmlns="http://www.w3.org/2000/svg">
|
|
|
47198
47479
|
<symbol id="g6-icon-plus" viewBox="0 0 512 512">
|
|
47199
47480
|
<path fill="currentColor" d="M316 32 L316 196 L480 196 L480 316 L316 316 L316 480 L196 480 L196 316 L32 316 L32 196 L196 196 L196 32 Z"/>
|
|
47200
47481
|
</symbol>
|
|
47482
|
+
<!-- ellipsis-vertical (unfold the floating toolbar).
|
|
47483
|
+
The strip it stands for is a vertical stack, and a vertical
|
|
47484
|
+
ellipsis is what "there is more of this here" is drawn as
|
|
47485
|
+
everywhere else. -->
|
|
47486
|
+
<symbol id="g6-icon-toolbar-show" viewBox="0 0 128 512">
|
|
47487
|
+
<path fill="currentColor" d="M64 360a56 56 0 1 0 0 112 56 56 0 1 0 0-112zm0-160a56 56 0 1 0 0 112 56 56 0 1 0 0-112zM120 96A56 56 0 1 0 8 96a56 56 0 1 0 112 0z"/>
|
|
47488
|
+
</symbol>
|
|
47489
|
+
<!-- xmark (fold the floating toolbar away).
|
|
47490
|
+
Not a chevron: the two toolbars sit on OPPOSITE edges, so a
|
|
47491
|
+
direction would point the wrong way on one of them. What the
|
|
47492
|
+
button does is close an overlay, and that is an x. -->
|
|
47493
|
+
<symbol id="g6-icon-toolbar-hide" viewBox="0 0 384 512">
|
|
47494
|
+
<path fill="currentColor" d="M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z"/>
|
|
47495
|
+
</symbol>
|
|
47201
47496
|
<!-- floppy-disk (save) -->
|
|
47202
47497
|
<symbol id="g6-icon-save" viewBox="0 0 448 512">
|
|
47203
47498
|
<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"/>
|
|
@@ -47270,6 +47565,7 @@ var YuiToolbar = class extends _antv_g6.Toolbar {
|
|
|
47270
47565
|
};
|
|
47271
47566
|
(0, _antv_g6.register)(_antv_g6.ExtensionCategory.PLUGIN, "yui-toolbar", YuiToolbar);
|
|
47272
47567
|
ensure_drag_canvas_patch();
|
|
47568
|
+
ensure_pinch_zoom_patch();
|
|
47273
47569
|
/***************************************************************
|
|
47274
47570
|
* Constants
|
|
47275
47571
|
***************************************************************/
|
|
@@ -47389,6 +47685,9 @@ var PRIVATE_DATA$4 = {
|
|
|
47389
47685
|
_focus_topic: null,
|
|
47390
47686
|
_focus_ids: [],
|
|
47391
47687
|
_on_pointerdown_focus: null,
|
|
47688
|
+
_uninstall_long_press: null,
|
|
47689
|
+
toolbar_collapsed: true,
|
|
47690
|
+
_toolbars_could_collapse: null,
|
|
47392
47691
|
_on_focusout_restore: null,
|
|
47393
47692
|
_selected_paint_ids: [],
|
|
47394
47693
|
_pending_focus_topic: null,
|
|
@@ -47474,6 +47773,10 @@ function mt_destroy$4(gobj) {
|
|
|
47474
47773
|
cancelAnimationFrame(priv._resize_raf);
|
|
47475
47774
|
priv._resize_raf = 0;
|
|
47476
47775
|
}
|
|
47776
|
+
if (priv._uninstall_long_press) {
|
|
47777
|
+
priv._uninstall_long_press();
|
|
47778
|
+
priv._uninstall_long_press = null;
|
|
47779
|
+
}
|
|
47477
47780
|
if (priv.graph) {
|
|
47478
47781
|
priv.graph.destroy();
|
|
47479
47782
|
priv.graph = null;
|
|
@@ -47688,6 +47991,8 @@ function configure_plugins(gobj) {
|
|
|
47688
47991
|
return e.targetType === "node" || e.targetType === "edge";
|
|
47689
47992
|
}
|
|
47690
47993
|
});
|
|
47994
|
+
if (priv._uninstall_long_press) priv._uninstall_long_press();
|
|
47995
|
+
priv._uninstall_long_press = install_long_press_contextmenu(priv.graph);
|
|
47691
47996
|
if ((0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "with_toolbar")) {
|
|
47692
47997
|
configure_toolbar(gobj);
|
|
47693
47998
|
configure_toolbar_edit(gobj);
|
|
@@ -47717,6 +48022,55 @@ function update_toolbar(gobj) {
|
|
|
47717
48022
|
* flipping now; the fallbacks are the old forced-light values, so
|
|
47718
48023
|
* a host without Bulma gets exactly what it had.
|
|
47719
48024
|
************************************************************/
|
|
48025
|
+
/************************************************************
|
|
48026
|
+
* Is the canvas too narrow to give both floating toolbars a
|
|
48027
|
+
* strip of it?
|
|
48028
|
+
*
|
|
48029
|
+
* They are drawn INSIDE the canvas, one on each edge. On a
|
|
48030
|
+
* desktop that is a corner; on a 356px-wide phone canvas the
|
|
48031
|
+
* two of them take a third of the drawing area and stand on
|
|
48032
|
+
* top of the nodes -- and a node under a toolbar cannot be
|
|
48033
|
+
* read, tapped or dragged out from under it.
|
|
48034
|
+
*
|
|
48035
|
+
* Measured on the CONTAINER, not on the window: the same
|
|
48036
|
+
* graph is a full page in one app and a card in a column in
|
|
48037
|
+
* another, and it is the box it actually got that decides.
|
|
48038
|
+
************************************************************/
|
|
48039
|
+
var TOOLBAR_COLLAPSE_WIDTH = 480;
|
|
48040
|
+
function toolbars_can_collapse(gobj) {
|
|
48041
|
+
let $container = gobj.priv.$container;
|
|
48042
|
+
if (!$container) return false;
|
|
48043
|
+
let width = $container.getBoundingClientRect().width;
|
|
48044
|
+
if (!width) return false;
|
|
48045
|
+
return width < TOOLBAR_COLLAPSE_WIDTH;
|
|
48046
|
+
}
|
|
48047
|
+
/************************************************************
|
|
48048
|
+
* Are they folded RIGHT NOW? Wide enough and the question
|
|
48049
|
+
* does not arise -- the desktop toolbar never grows a button
|
|
48050
|
+
* it does not need.
|
|
48051
|
+
************************************************************/
|
|
48052
|
+
function toolbars_collapsed(gobj) {
|
|
48053
|
+
if (!toolbars_can_collapse(gobj)) return false;
|
|
48054
|
+
return gobj.priv.toolbar_collapsed !== false;
|
|
48055
|
+
}
|
|
48056
|
+
/************************************************************
|
|
48057
|
+
* The one item a folded toolbar shows, and the one an
|
|
48058
|
+
* unfolded narrow toolbar adds to fold itself again.
|
|
48059
|
+
************************************************************/
|
|
48060
|
+
function toolbar_fold_item(gobj) {
|
|
48061
|
+
if (toolbars_collapsed(gobj)) return {
|
|
48062
|
+
id: "g6-icon-toolbar-show",
|
|
48063
|
+
value: "toolbar-toggle",
|
|
48064
|
+
className: "EV_TOGGLE_TOOLBARS",
|
|
48065
|
+
title: (0, i18next.t)("show toolbar")
|
|
48066
|
+
};
|
|
48067
|
+
return {
|
|
48068
|
+
id: "g6-icon-toolbar-hide",
|
|
48069
|
+
value: "toolbar-toggle",
|
|
48070
|
+
className: "EV_TOGGLE_TOOLBARS",
|
|
48071
|
+
title: (0, i18next.t)("hide toolbar")
|
|
48072
|
+
};
|
|
48073
|
+
}
|
|
47720
48074
|
function toolbar_style(extra) {
|
|
47721
48075
|
return Object.assign({
|
|
47722
48076
|
backgroundColor: "var(--bulma-scheme-main, #f5f5f5)",
|
|
@@ -47774,6 +48128,7 @@ function configure_toolbar(gobj) {
|
|
|
47774
48128
|
marginLeft: "12px"
|
|
47775
48129
|
}),
|
|
47776
48130
|
getItems: () => {
|
|
48131
|
+
if (toolbars_collapsed(gobj)) return [toolbar_fold_item(gobj)];
|
|
47777
48132
|
let items = [
|
|
47778
48133
|
{
|
|
47779
48134
|
id: "g6-icon-zoom-in",
|
|
@@ -47829,6 +48184,10 @@ function configure_toolbar(gobj) {
|
|
|
47829
48184
|
title: (0, i18next.t)("enter full screen")
|
|
47830
48185
|
});
|
|
47831
48186
|
}
|
|
48187
|
+
if (toolbars_can_collapse(gobj)) {
|
|
48188
|
+
items.push({ separator: true });
|
|
48189
|
+
items.push(toolbar_fold_item(gobj));
|
|
48190
|
+
}
|
|
47832
48191
|
return items;
|
|
47833
48192
|
},
|
|
47834
48193
|
onClick: (value) => {
|
|
@@ -47854,7 +48213,10 @@ function configure_toolbar(gobj) {
|
|
|
47854
48213
|
case "request-fullscreen":
|
|
47855
48214
|
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_REQUEST_FULLSCREEN", {}, gobj);
|
|
47856
48215
|
break;
|
|
47857
|
-
case "exit-fullscreen":
|
|
48216
|
+
case "exit-fullscreen":
|
|
48217
|
+
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_EXIT_FULLSCREEN", {}, gobj);
|
|
48218
|
+
break;
|
|
48219
|
+
case "toolbar-toggle": (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_TOGGLE_TOOLBARS", {}, gobj);
|
|
47858
48220
|
}
|
|
47859
48221
|
}
|
|
47860
48222
|
});
|
|
@@ -47864,7 +48226,7 @@ function configure_toolbar(gobj) {
|
|
|
47864
48226
|
* Contains edit-mode buttons: Undo, Redo, Save
|
|
47865
48227
|
************************************************************/
|
|
47866
48228
|
function configure_toolbar_edit(gobj) {
|
|
47867
|
-
if (!gobj.priv.edit_mode) {
|
|
48229
|
+
if (!gobj.priv.edit_mode || toolbars_collapsed(gobj)) {
|
|
47868
48230
|
graph_remove_plugin(gobj, "toolbar-edit");
|
|
47869
48231
|
return;
|
|
47870
48232
|
}
|
|
@@ -47972,6 +48334,7 @@ function configure_behaviour(gobj) {
|
|
|
47972
48334
|
break;
|
|
47973
48335
|
case "operation":
|
|
47974
48336
|
priv.edit_mode = false;
|
|
48337
|
+
behaviors = ["drag-canvas", "zoom-canvas"];
|
|
47975
48338
|
break;
|
|
47976
48339
|
default: (0, _yuneta_gobj_js.log_error)(`operation mode unknown: ${operation_mode}`);
|
|
47977
48340
|
}
|
|
@@ -48934,6 +49297,14 @@ var ManualLayout = class extends _antv_g6.BaseLayout {
|
|
|
48934
49297
|
************************************************************/
|
|
48935
49298
|
var RESIZE_HANDLE_SIZE = 8;
|
|
48936
49299
|
var RESIZE_MIN_VP = 20;
|
|
49300
|
+
var RESIZE_HANDLE_VISUAL_COARSE = 14;
|
|
49301
|
+
var RESIZE_HANDLE_HIT_COARSE = 44;
|
|
49302
|
+
function resize_handle_visual() {
|
|
49303
|
+
return coarse_pointer() ? RESIZE_HANDLE_VISUAL_COARSE : RESIZE_HANDLE_SIZE;
|
|
49304
|
+
}
|
|
49305
|
+
function resize_handle_hit() {
|
|
49306
|
+
return coarse_pointer() ? RESIZE_HANDLE_HIT_COARSE : RESIZE_HANDLE_SIZE;
|
|
49307
|
+
}
|
|
48937
49308
|
/************************************************************
|
|
48938
49309
|
* SVG icons for floating action buttons (28×28 circles).
|
|
48939
49310
|
* Each value is a raw SVG string sized 18×18 in a 24×24 viewBox.
|
|
@@ -48946,7 +49317,50 @@ var SVG_ICONS = {
|
|
|
48946
49317
|
plus: "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"/><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"/></svg>"
|
|
48947
49318
|
};
|
|
48948
49319
|
/************************************************************
|
|
48949
|
-
*
|
|
49320
|
+
* Is the primary pointer a FINGER?
|
|
49321
|
+
*
|
|
49322
|
+
* Everything this gclass draws over the canvas is sized from
|
|
49323
|
+
* this answer. A mouse is a pixel and can hit an 8px square;
|
|
49324
|
+
* a fingertip covers about 40, and the overlay it lands on
|
|
49325
|
+
* decides between "open the properties" and "delete the node".
|
|
49326
|
+
*
|
|
49327
|
+
* Asked per call, not cached: a tablet with a keyboard dock
|
|
49328
|
+
* changes the answer without reloading the page.
|
|
49329
|
+
************************************************************/
|
|
49330
|
+
function coarse_pointer() {
|
|
49331
|
+
if (typeof window.matchMedia !== "function") return false;
|
|
49332
|
+
try {
|
|
49333
|
+
return window.matchMedia("(pointer: coarse)").matches === true;
|
|
49334
|
+
} catch (e) {
|
|
49335
|
+
return false;
|
|
49336
|
+
}
|
|
49337
|
+
}
|
|
49338
|
+
/************************************************************
|
|
49339
|
+
* The size of the round floating buttons (properties,
|
|
49340
|
+
* delete, link), and the GAP between two of them.
|
|
49341
|
+
*
|
|
49342
|
+
* The gap matters as much as the size: `node properties` and
|
|
49343
|
+
* `delete node` are drawn one under the other, and at 28px
|
|
49344
|
+
* with 4px between them a fingertip covers both -- with the
|
|
49345
|
+
* destructive one underneath.
|
|
49346
|
+
************************************************************/
|
|
49347
|
+
function floating_icon_size() {
|
|
49348
|
+
return coarse_pointer() ? 44 : 28;
|
|
49349
|
+
}
|
|
49350
|
+
function floating_icon_gap() {
|
|
49351
|
+
return coarse_pointer() ? 12 : 4;
|
|
49352
|
+
}
|
|
49353
|
+
function floating_icon_dy() {
|
|
49354
|
+
return -floating_icon_size() / 2;
|
|
49355
|
+
}
|
|
49356
|
+
function floating_icon_step() {
|
|
49357
|
+
return floating_icon_size() + floating_icon_gap();
|
|
49358
|
+
}
|
|
49359
|
+
function floating_popover_dx() {
|
|
49360
|
+
return 4 + floating_icon_size() + 4;
|
|
49361
|
+
}
|
|
49362
|
+
/************************************************************
|
|
49363
|
+
* Create a floating circular icon button.
|
|
48950
49364
|
* @param {string} svgKey - key into SVG_ICONS
|
|
48951
49365
|
* @param {string} color - border & text color (e.g. '#1890ff')
|
|
48952
49366
|
* @param {number} left - CSS left in px
|
|
@@ -48956,10 +49370,18 @@ var SVG_ICONS = {
|
|
|
48956
49370
|
* @returns {HTMLElement}
|
|
48957
49371
|
************************************************************/
|
|
48958
49372
|
function create_floating_icon(svgKey, color, left, top, title, onClick) {
|
|
49373
|
+
const size = floating_icon_size();
|
|
48959
49374
|
const el = document.createElement("div");
|
|
48960
49375
|
el.title = title;
|
|
49376
|
+
el.setAttribute("aria-label", title);
|
|
48961
49377
|
el.innerHTML = SVG_ICONS[svgKey] || "";
|
|
48962
|
-
el.style.cssText = "position:absolute;left:" + left + "px;top:" + top + "px;width:
|
|
49378
|
+
el.style.cssText = "position:absolute;left:" + left + "px;top:" + top + "px;width:" + size + "px;height:" + size + "px;display:flex;align-items:center;justify-content:center;background:#fff;border:1px solid " + color + ";border-radius:50%;cursor:pointer;pointer-events:all;z-index:11;touch-action:none;box-shadow:0 2px 6px rgba(0,0,0,0.15);color:" + color + ";";
|
|
49379
|
+
const $svg = el.querySelector("svg");
|
|
49380
|
+
if ($svg) {
|
|
49381
|
+
const glyph = Math.round(size * .5);
|
|
49382
|
+
$svg.setAttribute("width", String(glyph));
|
|
49383
|
+
$svg.setAttribute("height", String(glyph));
|
|
49384
|
+
}
|
|
48963
49385
|
el.addEventListener("click", (e) => {
|
|
48964
49386
|
e.stopPropagation();
|
|
48965
49387
|
onClick();
|
|
@@ -49005,7 +49427,7 @@ function show_dual_icons(gobj, x, y, gear_title, gear_click, trash_title, trash_
|
|
|
49005
49427
|
let priv = gobj.priv;
|
|
49006
49428
|
const icon_el = create_floating_icon("gear", "#1890ff", x, y, gear_title, gear_click);
|
|
49007
49429
|
priv.$container.appendChild(icon_el);
|
|
49008
|
-
const delete_el = create_floating_icon("trash", "#ff4d4f", x, y +
|
|
49430
|
+
const delete_el = create_floating_icon("trash", "#ff4d4f", x, y + floating_icon_step(), trash_title, trash_click);
|
|
49009
49431
|
priv.$container.appendChild(delete_el);
|
|
49010
49432
|
return {
|
|
49011
49433
|
icon_el,
|
|
@@ -49023,6 +49445,21 @@ function create_popover_base(left, top, className, borderColor, minWidth) {
|
|
|
49023
49445
|
popover.addEventListener("pointerdown", (e) => e.stopPropagation());
|
|
49024
49446
|
return popover;
|
|
49025
49447
|
}
|
|
49448
|
+
/************************************************************
|
|
49449
|
+
* Extra CSS every control inside a popover carries on a
|
|
49450
|
+
* touch screen.
|
|
49451
|
+
*
|
|
49452
|
+
* A popover is where the graph is TYPED into -- a colour, a
|
|
49453
|
+
* radius, an id -- and its controls were sized by their
|
|
49454
|
+
* padding alone, which lands them at 25-30px. A finger needs
|
|
49455
|
+
* 44, and the number is not ours: it is the floor both Apple
|
|
49456
|
+
* and Google publish, and the one every native control on the
|
|
49457
|
+
* device already meets.
|
|
49458
|
+
************************************************************/
|
|
49459
|
+
function touch_control_css() {
|
|
49460
|
+
if (!coarse_pointer()) return "";
|
|
49461
|
+
return "min-height:44px;font-size:16px;";
|
|
49462
|
+
}
|
|
49026
49463
|
function create_form_label(parent, text) {
|
|
49027
49464
|
let label = document.createElement("label");
|
|
49028
49465
|
label.textContent = (0, i18next.t)(text);
|
|
@@ -49034,7 +49471,7 @@ function create_form_color_input(parent, value, onInput) {
|
|
|
49034
49471
|
let input = document.createElement("input");
|
|
49035
49472
|
input.type = "color";
|
|
49036
49473
|
input.value = value;
|
|
49037
|
-
input.style.cssText = "width:100%;height:30px;padding:0;border:1px solid var(--bulma-border-weak, #d9d9d9);border-radius:4px;cursor:pointer;margin-bottom:10px;";
|
|
49474
|
+
input.style.cssText = "width:100%;height:30px;padding:0;border:1px solid var(--bulma-border-weak, #d9d9d9);border-radius:4px;cursor:pointer;margin-bottom:10px;" + touch_control_css();
|
|
49038
49475
|
if (onInput) input.addEventListener("input", onInput);
|
|
49039
49476
|
parent.appendChild(input);
|
|
49040
49477
|
return input;
|
|
@@ -49045,14 +49482,14 @@ function create_form_number_input(parent, value, min, max, onInput) {
|
|
|
49045
49482
|
input.min = String(min);
|
|
49046
49483
|
input.max = String(max);
|
|
49047
49484
|
input.value = value;
|
|
49048
|
-
input.style.cssText = "width:100%;padding:4px 6px;background:var(--bulma-scheme-main-bis, #fff);color:var(--bulma-text-strong, #333);border:1px solid var(--bulma-border-weak, #d9d9d9);border-radius:4px;box-sizing:border-box;margin-bottom:10px;";
|
|
49485
|
+
input.style.cssText = "width:100%;padding:4px 6px;background:var(--bulma-scheme-main-bis, #fff);color:var(--bulma-text-strong, #333);border:1px solid var(--bulma-border-weak, #d9d9d9);border-radius:4px;box-sizing:border-box;margin-bottom:10px;" + touch_control_css();
|
|
49049
49486
|
if (onInput) input.addEventListener("input", onInput);
|
|
49050
49487
|
parent.appendChild(input);
|
|
49051
49488
|
return input;
|
|
49052
49489
|
}
|
|
49053
49490
|
function create_form_select(parent, options, marginBottom) {
|
|
49054
49491
|
let select = document.createElement("select");
|
|
49055
|
-
select.style.cssText = "width:100%;padding:4px 6px;background:var(--bulma-scheme-main-bis, #fff);color:var(--bulma-text-strong, #333);border:1px solid var(--bulma-border-weak, #d9d9d9);border-radius:4px;box-sizing:border-box;margin-bottom:" + (marginBottom || "12px") + ";";
|
|
49492
|
+
select.style.cssText = "width:100%;padding:4px 6px;background:var(--bulma-scheme-main-bis, #fff);color:var(--bulma-text-strong, #333);border:1px solid var(--bulma-border-weak, #d9d9d9);border-radius:4px;box-sizing:border-box;margin-bottom:" + (marginBottom || "12px") + ";" + touch_control_css();
|
|
49056
49493
|
for (let opt of options) {
|
|
49057
49494
|
let o = document.createElement("option");
|
|
49058
49495
|
o.value = opt.value;
|
|
@@ -49069,7 +49506,7 @@ function create_form_button_row(parent, buttons) {
|
|
|
49069
49506
|
for (let { text, style, onClick } of buttons) {
|
|
49070
49507
|
let btn = document.createElement("button");
|
|
49071
49508
|
btn.textContent = (0, i18next.t)(text);
|
|
49072
|
-
btn.style.cssText = style;
|
|
49509
|
+
btn.style.cssText = style + touch_control_css();
|
|
49073
49510
|
btn.addEventListener("click", (e) => {
|
|
49074
49511
|
e.stopPropagation();
|
|
49075
49512
|
onClick();
|
|
@@ -49307,7 +49744,7 @@ function show_resize_handles(gobj) {
|
|
|
49307
49744
|
container.style.cssText = "position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:10;";
|
|
49308
49745
|
const selRect = document.createElement("div");
|
|
49309
49746
|
container.appendChild(selRect);
|
|
49310
|
-
|
|
49747
|
+
let handle_defs = [
|
|
49311
49748
|
{
|
|
49312
49749
|
cursor: "nw-resize",
|
|
49313
49750
|
mx: -1,
|
|
@@ -49349,10 +49786,16 @@ function show_resize_handles(gobj) {
|
|
|
49349
49786
|
my: 1
|
|
49350
49787
|
}
|
|
49351
49788
|
];
|
|
49789
|
+
const hit = resize_handle_hit();
|
|
49790
|
+
const visual = resize_handle_visual();
|
|
49791
|
+
if (coarse_pointer()) handle_defs = handle_defs.filter((def) => def.mx !== 0 && def.my !== 0);
|
|
49352
49792
|
const handles = [];
|
|
49353
49793
|
for (const def of handle_defs) {
|
|
49354
49794
|
const el = document.createElement("div");
|
|
49355
|
-
el.style.cssText = "position:absolute;width:
|
|
49795
|
+
el.style.cssText = "position:absolute;width:" + hit + "px;height:" + hit + "px;display:flex;align-items:center;justify-content:center;cursor:" + def.cursor + ";pointer-events:all;touch-action:none;box-sizing:border-box;";
|
|
49796
|
+
const mark = document.createElement("div");
|
|
49797
|
+
mark.style.cssText = "width:" + visual + "px;height:" + visual + "px;background:#fff;border:1px solid #1890ff;pointer-events:none;box-sizing:border-box;";
|
|
49798
|
+
el.appendChild(mark);
|
|
49356
49799
|
el.addEventListener("pointerdown", (e) => {
|
|
49357
49800
|
start_node_resize(gobj, e, def.mx, def.my);
|
|
49358
49801
|
});
|
|
@@ -49392,52 +49835,18 @@ function update_resize_handles_position(gobj) {
|
|
|
49392
49835
|
}
|
|
49393
49836
|
function apply_handles_to_rect(gobj, rect) {
|
|
49394
49837
|
let priv = gobj.priv;
|
|
49395
|
-
const HALF =
|
|
49838
|
+
const HALF = resize_handle_hit() / 2;
|
|
49396
49839
|
const left = rect.left;
|
|
49397
49840
|
const top = rect.top;
|
|
49398
49841
|
const w = rect.right - rect.left;
|
|
49399
49842
|
const h = rect.bottom - rect.top;
|
|
49400
49843
|
const selRect = priv._resize_sel_rect;
|
|
49401
49844
|
if (selRect) selRect.style.cssText = "position:absolute;left:" + left + "px;top:" + top + "px;width:" + w + "px;height:" + h + "px;border:1px dashed #1890ff;pointer-events:none;box-sizing:border-box;";
|
|
49402
|
-
const
|
|
49403
|
-
|
|
49404
|
-
|
|
49405
|
-
|
|
49406
|
-
|
|
49407
|
-
{
|
|
49408
|
-
x: left + w / 2,
|
|
49409
|
-
y: top
|
|
49410
|
-
},
|
|
49411
|
-
{
|
|
49412
|
-
x: left + w,
|
|
49413
|
-
y: top
|
|
49414
|
-
},
|
|
49415
|
-
{
|
|
49416
|
-
x: left,
|
|
49417
|
-
y: top + h / 2
|
|
49418
|
-
},
|
|
49419
|
-
{
|
|
49420
|
-
x: left + w,
|
|
49421
|
-
y: top + h / 2
|
|
49422
|
-
},
|
|
49423
|
-
{
|
|
49424
|
-
x: left,
|
|
49425
|
-
y: top + h
|
|
49426
|
-
},
|
|
49427
|
-
{
|
|
49428
|
-
x: left + w / 2,
|
|
49429
|
-
y: top + h
|
|
49430
|
-
},
|
|
49431
|
-
{
|
|
49432
|
-
x: left + w,
|
|
49433
|
-
y: top + h
|
|
49434
|
-
}
|
|
49435
|
-
];
|
|
49436
|
-
for (let i = 0; i < priv._resize_handles.length; i++) {
|
|
49437
|
-
const handle = priv._resize_handles[i];
|
|
49438
|
-
const p = positions[i];
|
|
49439
|
-
handle.el.style.left = p.x - HALF + "px";
|
|
49440
|
-
handle.el.style.top = p.y - HALF + "px";
|
|
49845
|
+
for (const handle of priv._resize_handles) {
|
|
49846
|
+
const x = left + (handle.mx + 1) / 2 * w;
|
|
49847
|
+
const y = top + (handle.my + 1) / 2 * h;
|
|
49848
|
+
handle.el.style.left = x - HALF + "px";
|
|
49849
|
+
handle.el.style.top = y - HALF + "px";
|
|
49441
49850
|
}
|
|
49442
49851
|
}
|
|
49443
49852
|
function start_node_resize(gobj, e, mx, my) {
|
|
@@ -49513,6 +49922,14 @@ function start_node_resize(gobj, e, mx, my) {
|
|
|
49513
49922
|
* Port selection and individual port resizing
|
|
49514
49923
|
************************************************************/
|
|
49515
49924
|
var PORT_HANDLE_SIZE = 8;
|
|
49925
|
+
var PORT_HANDLE_VISUAL_COARSE = 12;
|
|
49926
|
+
var PORT_HANDLE_HIT_COARSE = 32;
|
|
49927
|
+
function port_handle_visual() {
|
|
49928
|
+
return coarse_pointer() ? PORT_HANDLE_VISUAL_COARSE : PORT_HANDLE_SIZE;
|
|
49929
|
+
}
|
|
49930
|
+
function port_handle_hit() {
|
|
49931
|
+
return coarse_pointer() ? PORT_HANDLE_HIT_COARSE : PORT_HANDLE_SIZE;
|
|
49932
|
+
}
|
|
49516
49933
|
/************************************************************
|
|
49517
49934
|
* Compute the canvas (world) position of a port on a node.
|
|
49518
49935
|
* Returns {x, y} in world coordinates.
|
|
@@ -49545,6 +49962,26 @@ function get_port_radius(gobj, node_id, port_key) {
|
|
|
49545
49962
|
return style.portR || 6;
|
|
49546
49963
|
}
|
|
49547
49964
|
/************************************************************
|
|
49965
|
+
* How much wider than the port itself its hit area is,
|
|
49966
|
+
* measured on the SCREEN and converted to world units.
|
|
49967
|
+
*
|
|
49968
|
+
* It used to be a flat `+4` in WORLD units, which is a
|
|
49969
|
+
* different target on every zoom: at the 50% a phone lands on
|
|
49970
|
+
* after fit, a 6-unit port plus 4 is a 5px radius -- one
|
|
49971
|
+
* fifth of a fingertip, and picking a port is the first step
|
|
49972
|
+
* of every link.
|
|
49973
|
+
************************************************************/
|
|
49974
|
+
function port_hit_slop_world(graph) {
|
|
49975
|
+
let slop = coarse_pointer() ? 22 : 6;
|
|
49976
|
+
let zoom = 1;
|
|
49977
|
+
try {
|
|
49978
|
+
zoom = graph.getZoom() || 1;
|
|
49979
|
+
} catch (e) {
|
|
49980
|
+
zoom = 1;
|
|
49981
|
+
}
|
|
49982
|
+
return slop / zoom;
|
|
49983
|
+
}
|
|
49984
|
+
/************************************************************
|
|
49548
49985
|
* Detect if a click in canvas coordinates hits a port.
|
|
49549
49986
|
* Returns the port key string, or null if no port hit.
|
|
49550
49987
|
************************************************************/
|
|
@@ -49557,6 +49994,7 @@ function detect_port_click(gobj, node_id, canvasX, canvasY) {
|
|
|
49557
49994
|
const defaultR = style.portR || 6;
|
|
49558
49995
|
let best_key = null;
|
|
49559
49996
|
let best_dist = Infinity;
|
|
49997
|
+
let slop = port_hit_slop_world(graph);
|
|
49560
49998
|
for (let i = 0; i < ports.length; i++) {
|
|
49561
49999
|
let pl = ports[i].placement || [.5, .5];
|
|
49562
50000
|
let px = pos[0] + (pl[0] - .5) * w;
|
|
@@ -49565,7 +50003,7 @@ function detect_port_click(gobj, node_id, canvasX, canvasY) {
|
|
|
49565
50003
|
let dx = canvasX - px;
|
|
49566
50004
|
let dy = canvasY - py;
|
|
49567
50005
|
let dist = Math.sqrt(dx * dx + dy * dy);
|
|
49568
|
-
if (dist <= r +
|
|
50006
|
+
if (dist <= r + slop && dist < best_dist) {
|
|
49569
50007
|
best_dist = dist;
|
|
49570
50008
|
best_key = ports[i].key;
|
|
49571
50009
|
}
|
|
@@ -49613,7 +50051,7 @@ function show_link_icon_if_fkey(gobj) {
|
|
|
49613
50051
|
let canvasPos = get_port_canvas_position(gobj, priv._selected_node_id, priv._selected_port_key);
|
|
49614
50052
|
if (!canvasPos) return;
|
|
49615
50053
|
let vp = graph.getViewportByCanvas([canvasPos.x, canvasPos.y]);
|
|
49616
|
-
let icon = create_floating_icon("link", "#52c41a", vp[0] +
|
|
50054
|
+
let icon = create_floating_icon("link", "#52c41a", vp[0] + floating_icon_size() / 2 + 4, vp[1] + floating_icon_dy(), (0, i18next.t)("link to hook"), () => {
|
|
49617
50055
|
if (!priv._linking_mode) enter_linking_mode(gobj);
|
|
49618
50056
|
});
|
|
49619
50057
|
icon.addEventListener("pointerdown", (e) => {
|
|
@@ -49638,8 +50076,8 @@ function update_link_icon_position(gobj) {
|
|
|
49638
50076
|
return;
|
|
49639
50077
|
}
|
|
49640
50078
|
let vp = graph.getViewportByCanvas([canvasPos.x, canvasPos.y]);
|
|
49641
|
-
priv._link_icon_el.style.left = vp[0] +
|
|
49642
|
-
priv._link_icon_el.style.top = vp[1]
|
|
50079
|
+
priv._link_icon_el.style.left = vp[0] + floating_icon_size() / 2 + 4 + "px";
|
|
50080
|
+
priv._link_icon_el.style.top = vp[1] + floating_icon_dy() + "px";
|
|
49643
50081
|
} catch (e) {
|
|
49644
50082
|
hide_link_icon(gobj);
|
|
49645
50083
|
}
|
|
@@ -49907,10 +50345,15 @@ function show_port_resize_handles(gobj) {
|
|
|
49907
50345
|
dy: 0
|
|
49908
50346
|
}
|
|
49909
50347
|
];
|
|
50348
|
+
const hit = port_handle_hit();
|
|
50349
|
+
const visual = port_handle_visual();
|
|
49910
50350
|
const handles = [];
|
|
49911
50351
|
for (const def of handle_defs) {
|
|
49912
50352
|
const el = document.createElement("div");
|
|
49913
|
-
el.style.cssText = "position:absolute;width:
|
|
50353
|
+
el.style.cssText = "position:absolute;width:" + hit + "px;height:" + hit + "px;display:flex;align-items:center;justify-content:center;cursor:" + def.cursor + ";pointer-events:all;touch-action:none;box-sizing:border-box;";
|
|
50354
|
+
const mark = document.createElement("div");
|
|
50355
|
+
mark.style.cssText = "width:" + visual + "px;height:" + visual + "px;background:#fff;border:1px solid #fa8c16;border-radius:50%;pointer-events:none;box-sizing:border-box;";
|
|
50356
|
+
el.appendChild(mark);
|
|
49914
50357
|
el.addEventListener("pointerdown", (e) => {
|
|
49915
50358
|
start_port_resize(gobj, e);
|
|
49916
50359
|
});
|
|
@@ -49964,7 +50407,7 @@ function update_port_resize_handles_position(gobj) {
|
|
|
49964
50407
|
************************************************************/
|
|
49965
50408
|
function apply_port_handles(gobj, cx, cy, vpR) {
|
|
49966
50409
|
let priv = gobj.priv;
|
|
49967
|
-
const HALF =
|
|
50410
|
+
const HALF = port_handle_hit() / 2;
|
|
49968
50411
|
const ring = priv._port_ring;
|
|
49969
50412
|
if (ring) {
|
|
49970
50413
|
const d = vpR * 2;
|
|
@@ -50109,7 +50552,7 @@ function show_edge_icon(gobj) {
|
|
|
50109
50552
|
if (!priv._selected_edge_id) return;
|
|
50110
50553
|
let mid = get_edge_viewport_midpoint(gobj, priv._selected_edge_id);
|
|
50111
50554
|
if (!mid) return;
|
|
50112
|
-
let icons = show_dual_icons(gobj, mid.x + 4, mid.y
|
|
50555
|
+
let icons = show_dual_icons(gobj, mid.x + 4, mid.y + floating_icon_dy(), (0, i18next.t)("edge properties"), () => toggle_edge_popover(gobj), (0, i18next.t)("unlink"), () => request_unlink_edge(gobj));
|
|
50113
50556
|
priv._edge_icon_el = icons.icon_el;
|
|
50114
50557
|
priv._edge_delete_el = icons.delete_el;
|
|
50115
50558
|
}
|
|
@@ -50127,14 +50570,14 @@ function update_edge_icon_position(gobj) {
|
|
|
50127
50570
|
return;
|
|
50128
50571
|
}
|
|
50129
50572
|
priv._edge_icon_el.style.left = mid.x + 4 + "px";
|
|
50130
|
-
priv._edge_icon_el.style.top = mid.y
|
|
50573
|
+
priv._edge_icon_el.style.top = mid.y + floating_icon_dy() + "px";
|
|
50131
50574
|
if (priv._edge_delete_el) {
|
|
50132
50575
|
priv._edge_delete_el.style.left = mid.x + 4 + "px";
|
|
50133
|
-
priv._edge_delete_el.style.top = mid.y +
|
|
50576
|
+
priv._edge_delete_el.style.top = mid.y + floating_icon_dy() + floating_icon_step() + "px";
|
|
50134
50577
|
}
|
|
50135
50578
|
if (priv._edge_popover_el) {
|
|
50136
|
-
priv._edge_popover_el.style.left = mid.x +
|
|
50137
|
-
priv._edge_popover_el.style.top = mid.y
|
|
50579
|
+
priv._edge_popover_el.style.left = mid.x + floating_popover_dx() + "px";
|
|
50580
|
+
priv._edge_popover_el.style.top = mid.y + floating_icon_dy() + "px";
|
|
50138
50581
|
clamp_popover_position(gobj, priv._edge_popover_el);
|
|
50139
50582
|
}
|
|
50140
50583
|
} catch (e) {
|
|
@@ -50172,7 +50615,7 @@ function show_edge_popover(gobj) {
|
|
|
50172
50615
|
});
|
|
50173
50616
|
let mid = get_edge_viewport_midpoint(gobj, edge_id);
|
|
50174
50617
|
if (!mid) return;
|
|
50175
|
-
const popover = create_popover_base(mid.x +
|
|
50618
|
+
const popover = create_popover_base(mid.x + floating_popover_dx(), mid.y + floating_icon_dy(), "g6-edge-popover", "#d9d9d9", 180);
|
|
50176
50619
|
function preview_edge() {
|
|
50177
50620
|
let lw = parseInt(lwInput.value) || 2;
|
|
50178
50621
|
let color = colorInput.value;
|
|
@@ -50259,7 +50702,7 @@ function show_node_icon(gobj) {
|
|
|
50259
50702
|
if (!priv._selected_node_id || priv._selected_port_key) return;
|
|
50260
50703
|
let rect = get_node_viewport_rect(gobj, priv._selected_node_id);
|
|
50261
50704
|
if (!rect) return;
|
|
50262
|
-
let icons = show_dual_icons(gobj, rect.right + 4, rect.top
|
|
50705
|
+
let icons = show_dual_icons(gobj, rect.right + 4, rect.top + floating_icon_dy(), (0, i18next.t)("node properties"), () => toggle_node_popover(gobj), (0, i18next.t)("delete node"), () => request_delete_node(gobj));
|
|
50263
50706
|
priv._node_icon_el = icons.icon_el;
|
|
50264
50707
|
priv._node_delete_el = icons.delete_el;
|
|
50265
50708
|
}
|
|
@@ -50281,14 +50724,14 @@ function update_node_icon_position(gobj) {
|
|
|
50281
50724
|
return;
|
|
50282
50725
|
}
|
|
50283
50726
|
priv._node_icon_el.style.left = rect.right + 4 + "px";
|
|
50284
|
-
priv._node_icon_el.style.top = rect.top
|
|
50727
|
+
priv._node_icon_el.style.top = rect.top + floating_icon_dy() + "px";
|
|
50285
50728
|
if (priv._node_delete_el) {
|
|
50286
50729
|
priv._node_delete_el.style.left = rect.right + 4 + "px";
|
|
50287
|
-
priv._node_delete_el.style.top = rect.top +
|
|
50730
|
+
priv._node_delete_el.style.top = rect.top + floating_icon_dy() + floating_icon_step() + "px";
|
|
50288
50731
|
}
|
|
50289
50732
|
if (priv._node_popover_el) {
|
|
50290
|
-
priv._node_popover_el.style.left = rect.right +
|
|
50291
|
-
priv._node_popover_el.style.top = rect.top
|
|
50733
|
+
priv._node_popover_el.style.left = rect.right + floating_popover_dx() + "px";
|
|
50734
|
+
priv._node_popover_el.style.top = rect.top + floating_icon_dy() + "px";
|
|
50292
50735
|
clamp_popover_position(gobj, priv._node_popover_el);
|
|
50293
50736
|
}
|
|
50294
50737
|
} catch (e) {
|
|
@@ -50321,7 +50764,7 @@ function show_node_popover(gobj) {
|
|
|
50321
50764
|
let origLW = currentLW;
|
|
50322
50765
|
let rect = get_node_viewport_rect(gobj, node_id);
|
|
50323
50766
|
if (!rect) return;
|
|
50324
|
-
const popover = create_popover_base(rect.right +
|
|
50767
|
+
const popover = create_popover_base(rect.right + floating_popover_dx(), rect.top + floating_icon_dy(), "g6-node-popover", "#d9d9d9", 180);
|
|
50325
50768
|
let node_graph_type = nodeData.data && nodeData.data.desc ? nodeData.data.desc.node_treedb_type : null;
|
|
50326
50769
|
function preview_node() {
|
|
50327
50770
|
let fill = fillInput.value;
|
|
@@ -50952,7 +51395,7 @@ function show_create_popover(gobj) {
|
|
|
50952
51395
|
topicLabel.textContent = (0, i18next.t)("topic") + ":";
|
|
50953
51396
|
popover.appendChild(topicLabel);
|
|
50954
51397
|
let topicSelect = document.createElement("select");
|
|
50955
|
-
topicSelect.style.cssText = "width:100%;padding:6px;border:1px solid #d9d9d9;border-radius:4px;font-size:13px;margin-bottom:8px;";
|
|
51398
|
+
topicSelect.style.cssText = "width:100%;padding:6px;border:1px solid #d9d9d9;border-radius:4px;font-size:13px;margin-bottom:8px;" + touch_control_css();
|
|
50956
51399
|
for (let i = 0; i < topics.length; i++) {
|
|
50957
51400
|
let opt = document.createElement("option");
|
|
50958
51401
|
opt.value = topics[i].topic_name;
|
|
@@ -50985,7 +51428,7 @@ function show_create_popover(gobj) {
|
|
|
50985
51428
|
let idInput = document.createElement("input");
|
|
50986
51429
|
idInput.type = "text";
|
|
50987
51430
|
idInput.placeholder = (0, i18next.t)("node id");
|
|
50988
|
-
idInput.style.cssText = "width:100%;padding:6px;border:1px solid #d9d9d9;border-radius:4px;font-size:13px;margin-bottom:10px;box-sizing:border-box;";
|
|
51431
|
+
idInput.style.cssText = "width:100%;padding:6px;border:1px solid #d9d9d9;border-radius:4px;font-size:13px;margin-bottom:10px;box-sizing:border-box;" + touch_control_css();
|
|
50989
51432
|
popover.appendChild(idInput);
|
|
50990
51433
|
let errorEl = document.createElement("div");
|
|
50991
51434
|
errorEl.style.cssText = "color:#ff4d4f;font-size:12px;margin-bottom:8px;display:none;";
|
|
@@ -51675,6 +52118,11 @@ function ac_resize(gobj, event, kw, src) {
|
|
|
51675
52118
|
if (h < 0) h = 80;
|
|
51676
52119
|
graph_resize(gobj, rect.width, h);
|
|
51677
52120
|
}
|
|
52121
|
+
let can_collapse = toolbars_can_collapse(gobj);
|
|
52122
|
+
if (can_collapse !== priv._toolbars_could_collapse) {
|
|
52123
|
+
priv._toolbars_could_collapse = can_collapse;
|
|
52124
|
+
update_toolbar(gobj);
|
|
52125
|
+
}
|
|
51678
52126
|
return 0;
|
|
51679
52127
|
}
|
|
51680
52128
|
/************************************************************
|
|
@@ -51713,6 +52161,19 @@ function ac_zoom_reset(gobj, event, kw, src) {
|
|
|
51713
52161
|
gobj.priv.graph.zoomTo(1);
|
|
51714
52162
|
return 0;
|
|
51715
52163
|
}
|
|
52164
|
+
/************************************************************
|
|
52165
|
+
* Fold / unfold the floating toolbars.
|
|
52166
|
+
*
|
|
52167
|
+
* One flag for BOTH: they are one wall over the canvas, and
|
|
52168
|
+
* the button that unfolds them has to be the same button
|
|
52169
|
+
* whichever edge the user reaches for.
|
|
52170
|
+
************************************************************/
|
|
52171
|
+
function ac_toggle_toolbars(gobj, event, kw, src) {
|
|
52172
|
+
let priv = gobj.priv;
|
|
52173
|
+
priv.toolbar_collapsed = !toolbars_collapsed(gobj);
|
|
52174
|
+
update_toolbar(gobj);
|
|
52175
|
+
return 0;
|
|
52176
|
+
}
|
|
51716
52177
|
function ac_auto_fit(gobj, event, kw, src) {
|
|
51717
52178
|
graph_fitview(gobj);
|
|
51718
52179
|
return 0;
|
|
@@ -52097,6 +52558,11 @@ function create_gclass$4(gclass_name) {
|
|
|
52097
52558
|
ac_zoom_reset,
|
|
52098
52559
|
null
|
|
52099
52560
|
],
|
|
52561
|
+
[
|
|
52562
|
+
"EV_TOGGLE_TOOLBARS",
|
|
52563
|
+
ac_toggle_toolbars,
|
|
52564
|
+
null
|
|
52565
|
+
],
|
|
52100
52566
|
[
|
|
52101
52567
|
"EV_AUTO_FIT",
|
|
52102
52568
|
ac_auto_fit,
|
|
@@ -52200,6 +52666,7 @@ function create_gclass$4(gclass_name) {
|
|
|
52200
52666
|
["EV_ZOOM_IN", 0],
|
|
52201
52667
|
["EV_ZOOM_OUT", 0],
|
|
52202
52668
|
["EV_ZOOM_RESET", 0],
|
|
52669
|
+
["EV_TOGGLE_TOOLBARS", 0],
|
|
52203
52670
|
["EV_AUTO_FIT", 0],
|
|
52204
52671
|
["EV_ZOOM_SELECTION", 0],
|
|
52205
52672
|
["EV_FOCUS_TOPIC", 0],
|