@yuneta/gobj-ui 7.23.26 → 7.23.28

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.
@@ -9726,13 +9726,14 @@ async function yui_graph_center_on(graph, node_id) {
9726
9726
  if (typeof graph.getElementData === "function" && !graph.getElementData(node_id)) return false;
9727
9727
  if (typeof graph.getElementPosition !== "function" || typeof graph.getViewportByCanvas !== "function" || typeof graph.getCanvasCenter !== "function" || typeof graph.translateTo !== "function") return false;
9728
9728
  for (let i = 0; i < 3; i++) {
9729
+ let z = graph.getZoom() || 1;
9729
9730
  let at = graph.getViewportByCanvas(graph.getElementPosition(node_id));
9730
9731
  let want = graph.getCanvasCenter();
9731
9732
  let dx = want[0] - at[0];
9732
9733
  let dy = want[1] - at[1];
9733
9734
  if (Math.abs(dx) < 1 && Math.abs(dy) < 1) break;
9734
- let pos = graph.getPosition();
9735
- await graph.translateTo([pos[0] + dx, pos[1] + dy]);
9735
+ let n = graph.getElementPosition(node_id);
9736
+ await graph.translateTo([(want[0] - n[0]) * z, (want[1] - n[1]) * z]);
9736
9737
  }
9737
9738
  return true;
9738
9739
  } catch (e) {
@@ -10590,7 +10591,8 @@ var PRIVATE_DATA$11 = {
10590
10591
  anchor_id: "",
10591
10592
  anchor_path: "",
10592
10593
  anchor_state: "off",
10593
- last_zoom: 1
10594
+ last_zoom: 1,
10595
+ center_posted: false
10594
10596
  };
10595
10597
  var __gclass__$11 = null;
10596
10598
  var __layout_registered__$1 = false;
@@ -10974,7 +10976,10 @@ function build_graph$3(gobj) {
10974
10976
  }
10975
10977
  if (z === priv.last_zoom) return;
10976
10978
  priv.last_zoom = z;
10977
- if (priv.anchor_state === "on" && priv.anchor_id) yui_graph_center_on(priv.graph, priv.anchor_id);
10979
+ if (priv.anchor_state === "on" && priv.anchor_id && !priv.center_posted) {
10980
+ priv.center_posted = true;
10981
+ (0, _yuneta_gobj_js.gobj_post_event)(gobj, "EV_CENTER_ANCHOR", {}, gobj);
10982
+ }
10978
10983
  });
10979
10984
  graph.on(_antv_g6.CanvasEvent.CLICK, (evt) => {});
10980
10985
  if (typeof ResizeObserver !== "undefined") {
@@ -11065,12 +11070,16 @@ function build_cell_html(key, value, type, dark, matched, fold) {
11065
11070
  * forever. `+3` and `−` need no language.
11066
11071
  ************************************************************/
11067
11072
  var FOLD_SPACER = `<span style="width:24px; flex:0 0 auto;"></span>`;
11073
+ var ZOOM_CANVAS$1 = {
11074
+ type: "zoom-canvas",
11075
+ animation: false
11076
+ };
11068
11077
  var BEHAVIORS_READING$1 = [
11069
11078
  "drag-canvas",
11070
- "zoom-canvas",
11079
+ ZOOM_CANVAS$1,
11071
11080
  "drag-element"
11072
11081
  ];
11073
- var BEHAVIORS_PICKING$1 = ["drag-canvas", "zoom-canvas"];
11082
+ var BEHAVIORS_PICKING$1 = ["drag-canvas", ZOOM_CANVAS$1];
11074
11083
  var CARD_HEADER_H$1 = 24;
11075
11084
  var CARD_ROW_H$1 = 22;
11076
11085
  function fold_toggle_html(path, foldable, folded, branches, colors) {
@@ -11674,6 +11683,7 @@ function paint_anchor_mark(gobj) {
11674
11683
  ************************************************************/
11675
11684
  function ac_center_anchor$2(gobj, event, kw, src) {
11676
11685
  let priv = gobj.priv;
11686
+ priv.center_posted = false;
11677
11687
  paint_anchor_mark(gobj);
11678
11688
  if (priv.anchor_state === "on" && priv.anchor_id) yui_graph_center_on(priv.graph, priv.anchor_id);
11679
11689
  return 0;
@@ -13230,12 +13240,16 @@ var attrs_table$9 = [
13230
13240
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_INTEGER, "collapse_threshold", 0, 10, "Auto-collapse a node whose direct children exceed this number. 0 disables auto-collapse."),
13231
13241
  (0, _yuneta_gobj_js.SDATA_END)()
13232
13242
  ];
13243
+ var ZOOM_CANVAS = {
13244
+ type: "zoom-canvas",
13245
+ animation: false
13246
+ };
13233
13247
  var BEHAVIORS_READING = [
13234
13248
  "drag-canvas",
13235
- "zoom-canvas",
13249
+ ZOOM_CANVAS,
13236
13250
  "drag-element"
13237
13251
  ];
13238
- var BEHAVIORS_PICKING = ["drag-canvas", "zoom-canvas"];
13252
+ var BEHAVIORS_PICKING = ["drag-canvas", ZOOM_CANVAS];
13239
13253
  var PRIVATE_DATA$9 = {
13240
13254
  canvas_id: "",
13241
13255
  graph: null,
@@ -13525,7 +13539,7 @@ function build_ui$8(gobj) {
13525
13539
  {
13526
13540
  id: priv.canvas_id,
13527
13541
  class: "gobj-tree-container",
13528
- style: "height:100%; min-height:0; border: 1px solid var(--bulma-border-weak); border-radius:0.2rem; touch-action:none; -webkit-user-select:none; user-select:none;"
13542
+ style: "height:100%; min-height:0; border: 1px solid var(--bulma-border-weak); border-radius:0.2rem;"
13529
13543
  },
13530
13544
  []
13531
13545
  ]]
@@ -49222,6 +49236,26 @@ function configure_behaviour(gobj) {
49222
49236
  graph_write_behaviors(gobj, behaviors);
49223
49237
  }
49224
49238
  /************************************************************
49239
+ * Count hooks and fkeys in topic desc, classify node type
49240
+ ************************************************************/
49241
+ function calculate_hooks_fkeys_counter(desc) {
49242
+ let cols = desc.cols;
49243
+ desc.hooks_counter = 0;
49244
+ desc.fkeys_counter = 0;
49245
+ for (let i = 0; i < cols.length; i++) {
49246
+ let col = cols[i];
49247
+ switch ((0, _yuneta_gobj_js.treedb_get_field_desc)(col).type) {
49248
+ case "hook":
49249
+ desc.hooks_counter++;
49250
+ break;
49251
+ case "fkey": desc.fkeys_counter++;
49252
+ }
49253
+ }
49254
+ if (desc.hooks_counter === 0) desc.node_treedb_type = "child";
49255
+ else if (desc.fkeys_counter === 0) desc.node_treedb_type = "extended";
49256
+ else desc.node_treedb_type = "hierarchical";
49257
+ }
49258
+ /************************************************************
49225
49259
  * Build ports for a topic desc
49226
49260
  ************************************************************/
49227
49261
  function build_ports(gobj, desc) {
@@ -9721,13 +9721,14 @@ async function yui_graph_center_on(graph, node_id) {
9721
9721
  if (typeof graph.getElementData === "function" && !graph.getElementData(node_id)) return false;
9722
9722
  if (typeof graph.getElementPosition !== "function" || typeof graph.getViewportByCanvas !== "function" || typeof graph.getCanvasCenter !== "function" || typeof graph.translateTo !== "function") return false;
9723
9723
  for (let i = 0; i < 3; i++) {
9724
+ let z = graph.getZoom() || 1;
9724
9725
  let at = graph.getViewportByCanvas(graph.getElementPosition(node_id));
9725
9726
  let want = graph.getCanvasCenter();
9726
9727
  let dx = want[0] - at[0];
9727
9728
  let dy = want[1] - at[1];
9728
9729
  if (Math.abs(dx) < 1 && Math.abs(dy) < 1) break;
9729
- let pos = graph.getPosition();
9730
- await graph.translateTo([pos[0] + dx, pos[1] + dy]);
9730
+ let n = graph.getElementPosition(node_id);
9731
+ await graph.translateTo([(want[0] - n[0]) * z, (want[1] - n[1]) * z]);
9731
9732
  }
9732
9733
  return true;
9733
9734
  } catch (e) {
@@ -10585,7 +10586,8 @@ var PRIVATE_DATA$11 = {
10585
10586
  anchor_id: "",
10586
10587
  anchor_path: "",
10587
10588
  anchor_state: "off",
10588
- last_zoom: 1
10589
+ last_zoom: 1,
10590
+ center_posted: false
10589
10591
  };
10590
10592
  var __gclass__$11 = null;
10591
10593
  var __layout_registered__$1 = false;
@@ -10969,7 +10971,10 @@ function build_graph$3(gobj) {
10969
10971
  }
10970
10972
  if (z === priv.last_zoom) return;
10971
10973
  priv.last_zoom = z;
10972
- if (priv.anchor_state === "on" && priv.anchor_id) yui_graph_center_on(priv.graph, priv.anchor_id);
10974
+ if (priv.anchor_state === "on" && priv.anchor_id && !priv.center_posted) {
10975
+ priv.center_posted = true;
10976
+ gobj_post_event(gobj, "EV_CENTER_ANCHOR", {}, gobj);
10977
+ }
10973
10978
  });
10974
10979
  graph.on(CanvasEvent.CLICK, (evt) => {});
10975
10980
  if (typeof ResizeObserver !== "undefined") {
@@ -11060,12 +11065,16 @@ function build_cell_html(key, value, type, dark, matched, fold) {
11060
11065
  * forever. `+3` and `−` need no language.
11061
11066
  ************************************************************/
11062
11067
  var FOLD_SPACER = `<span style="width:24px; flex:0 0 auto;"></span>`;
11068
+ var ZOOM_CANVAS$1 = {
11069
+ type: "zoom-canvas",
11070
+ animation: false
11071
+ };
11063
11072
  var BEHAVIORS_READING$1 = [
11064
11073
  "drag-canvas",
11065
- "zoom-canvas",
11074
+ ZOOM_CANVAS$1,
11066
11075
  "drag-element"
11067
11076
  ];
11068
- var BEHAVIORS_PICKING$1 = ["drag-canvas", "zoom-canvas"];
11077
+ var BEHAVIORS_PICKING$1 = ["drag-canvas", ZOOM_CANVAS$1];
11069
11078
  var CARD_HEADER_H$1 = 24;
11070
11079
  var CARD_ROW_H$1 = 22;
11071
11080
  function fold_toggle_html(path, foldable, folded, branches, colors) {
@@ -11669,6 +11678,7 @@ function paint_anchor_mark(gobj) {
11669
11678
  ************************************************************/
11670
11679
  function ac_center_anchor$2(gobj, event, kw, src) {
11671
11680
  let priv = gobj.priv;
11681
+ priv.center_posted = false;
11672
11682
  paint_anchor_mark(gobj);
11673
11683
  if (priv.anchor_state === "on" && priv.anchor_id) yui_graph_center_on(priv.graph, priv.anchor_id);
11674
11684
  return 0;
@@ -13225,12 +13235,16 @@ var attrs_table$9 = [
13225
13235
  SDATA(data_type_t.DTP_INTEGER, "collapse_threshold", 0, 10, "Auto-collapse a node whose direct children exceed this number. 0 disables auto-collapse."),
13226
13236
  SDATA_END()
13227
13237
  ];
13238
+ var ZOOM_CANVAS = {
13239
+ type: "zoom-canvas",
13240
+ animation: false
13241
+ };
13228
13242
  var BEHAVIORS_READING = [
13229
13243
  "drag-canvas",
13230
- "zoom-canvas",
13244
+ ZOOM_CANVAS,
13231
13245
  "drag-element"
13232
13246
  ];
13233
- var BEHAVIORS_PICKING = ["drag-canvas", "zoom-canvas"];
13247
+ var BEHAVIORS_PICKING = ["drag-canvas", ZOOM_CANVAS];
13234
13248
  var PRIVATE_DATA$9 = {
13235
13249
  canvas_id: "",
13236
13250
  graph: null,
@@ -13520,7 +13534,7 @@ function build_ui$8(gobj) {
13520
13534
  {
13521
13535
  id: priv.canvas_id,
13522
13536
  class: "gobj-tree-container",
13523
- style: "height:100%; min-height:0; border: 1px solid var(--bulma-border-weak); border-radius:0.2rem; touch-action:none; -webkit-user-select:none; user-select:none;"
13537
+ style: "height:100%; min-height:0; border: 1px solid var(--bulma-border-weak); border-radius:0.2rem;"
13524
13538
  },
13525
13539
  []
13526
13540
  ]]
@@ -49217,6 +49231,26 @@ function configure_behaviour(gobj) {
49217
49231
  graph_write_behaviors(gobj, behaviors);
49218
49232
  }
49219
49233
  /************************************************************
49234
+ * Count hooks and fkeys in topic desc, classify node type
49235
+ ************************************************************/
49236
+ function calculate_hooks_fkeys_counter(desc) {
49237
+ let cols = desc.cols;
49238
+ desc.hooks_counter = 0;
49239
+ desc.fkeys_counter = 0;
49240
+ for (let i = 0; i < cols.length; i++) {
49241
+ let col = cols[i];
49242
+ switch (treedb_get_field_desc(col).type) {
49243
+ case "hook":
49244
+ desc.hooks_counter++;
49245
+ break;
49246
+ case "fkey": desc.fkeys_counter++;
49247
+ }
49248
+ }
49249
+ if (desc.hooks_counter === 0) desc.node_treedb_type = "child";
49250
+ else if (desc.fkeys_counter === 0) desc.node_treedb_type = "extended";
49251
+ else desc.node_treedb_type = "hierarchical";
49252
+ }
49253
+ /************************************************************
49220
49254
  * Build ports for a topic desc
49221
49255
  ************************************************************/
49222
49256
  function build_ports(gobj, desc) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuneta/gobj-ui",
3
- "version": "7.23.26",
3
+ "version": "7.23.28",
4
4
  "type": "module",
5
5
  "main": "dist/gobj-ui.cjs.js",
6
6
  "module": "dist/gobj-ui.es.js",
@@ -1600,6 +1600,37 @@ function configure_behaviour(gobj)
1600
1600
  graph_write_behaviors(gobj, behaviors);
1601
1601
  }
1602
1602
 
1603
+ /************************************************************
1604
+ * Count hooks and fkeys in topic desc, classify node type
1605
+ ************************************************************/
1606
+ function calculate_hooks_fkeys_counter(desc)
1607
+ {
1608
+ let cols = desc.cols;
1609
+ desc.hooks_counter = 0;
1610
+ desc.fkeys_counter = 0;
1611
+
1612
+ for(let i=0; i<cols.length; i++) {
1613
+ let col = cols[i];
1614
+ const field_desc = treedb_get_field_desc(col);
1615
+ switch(field_desc.type) {
1616
+ case "hook":
1617
+ desc.hooks_counter++;
1618
+ break;
1619
+ case "fkey":
1620
+ desc.fkeys_counter++;
1621
+ break;
1622
+ }
1623
+ }
1624
+
1625
+ if(desc.hooks_counter === 0) {
1626
+ desc.node_treedb_type = 'child';
1627
+ } else if(desc.fkeys_counter === 0) {
1628
+ desc.node_treedb_type = 'extended';
1629
+ } else {
1630
+ desc.node_treedb_type = 'hierarchical';
1631
+ }
1632
+ }
1633
+
1603
1634
  /************************************************************
1604
1635
  * Build ports for a topic desc
1605
1636
  ************************************************************/
@@ -101,8 +101,24 @@ SDATA_END()
101
101
  * which REPLACES the behavior's own default test rather than adding
102
102
  * to it.
103
103
  */
104
- const BEHAVIORS_READING = ['drag-canvas', 'zoom-canvas', 'drag-element'];
105
- const BEHAVIORS_PICKING = ['drag-canvas', 'zoom-canvas'];
104
+ /*
105
+ * `zoom-canvas` with NO animation, and that is two rules at once.
106
+ *
107
+ * The house rule first: nothing in this GUI slides or fades, and G6's
108
+ * 200ms zoom easing is a transition nobody chose -- it comes with the
109
+ * behavior's defaults.
110
+ *
111
+ * And it is what makes an anchor possible on the WHEEL. `aftertransform`
112
+ * fires while that easing is still running, so the re-centring measured
113
+ * a camera that was still moving: measured, its passes went -272, then
114
+ * +411 the other side, then +183 -- oscillating, because between two
115
+ * reads the easing had moved the ground. With the zoom instantaneous
116
+ * the camera is still by the time anything measures it.
117
+ */
118
+ const ZOOM_CANVAS = {type: 'zoom-canvas', animation: false};
119
+
120
+ const BEHAVIORS_READING = ['drag-canvas', ZOOM_CANVAS, 'drag-element'];
121
+ const BEHAVIORS_PICKING = ['drag-canvas', ZOOM_CANVAS];
106
122
 
107
123
  let PRIVATE_DATA = {
108
124
  canvas_id: "",
@@ -422,13 +438,7 @@ function build_ui(gobj)
422
438
  ['div', {class: 'C_YUI_GOBJ_TREE_JS', style: 'height:100%; display:flex; flex-direction:column; position:relative;'}, [
423
439
  ['div', {class: 'is-flex-grow-0 is-flex toolbar_yui_gobj_tree'}, $toolbar],
424
440
  ['div', {class: 'is-flex-grow-1', style: 'height:100%; min-height:0; overflow:hidden;'}, [
425
- /* `touch-action` and `user-select` inline because this gclass loads no
426
- * stylesheet of its own: G6 puts `touch-action: none` on its canvas and
427
- * nothing on the html nodes over it, so without this a finger dragging a
428
- * card makes a page scroll and stops dead after ~20px; and a card is
429
- * text, so a mouse drag would start a selection. Same two rules
430
- * `lib_graph.css` carries for the treedb graph. */
431
- ['div', {id: priv.canvas_id, class: 'gobj-tree-container', style: 'height:100%; min-height:0; border: 1px solid var(--bulma-border-weak); border-radius:0.2rem; touch-action:none; -webkit-user-select:none; user-select:none;'}, [
441
+ ['div', {id: priv.canvas_id, class: 'gobj-tree-container', style: 'height:100%; min-height:0; border: 1px solid var(--bulma-border-weak); border-radius:0.2rem;'}, [
432
442
  ]]
433
443
  ]]
434
444
  ]]
@@ -293,65 +293,6 @@
293
293
  z-index: 1;
294
294
  }
295
295
 
296
- /*
297
- * Picking the node to anchor. The pointer says a click is expected --
298
- * without it the only sign the graph is waiting for one is a button
299
- * at the far end of a toolbar.
300
- */
301
- .C_YUI_JSON .json-graph-container.JSON_GRAPH_PICKING,
302
- .C_YUI_JSON .json-graph-container.JSON_GRAPH_PICKING * {
303
- cursor: crosshair;
304
- }
305
-
306
- /*
307
- * The card the camera is holding.
308
- *
309
- * It has to say so ON THE CARD: the toolbar button knows an anchor is
310
- * set, and knowing WHICH node it is was left to the reader remembering
311
- * what they clicked -- which is not a mark, it is a memory test.
312
- *
313
- * An outline and not a fill: the card's own colours mean things (a
314
- * dashed border is a dict, a solid one a list, the header carries the
315
- * group's hue), and a mark that repaints any of them would be saying
316
- * two things with one channel. `outline` also draws OUTSIDE the box,
317
- * so it cannot move a single row.
318
- *
319
- * Amber, the same "this one, right now" the toolbar's arming state
320
- * uses. It is not one of the palette's action colours because it is
321
- * not an action.
322
- */
323
- .C_YUI_JSON .JSON_CARD_ANCHORED {
324
- outline: 3px solid #fa8c16;
325
- outline-offset: 2px;
326
- }
327
-
328
- /*
329
- * The graph mount, once its cards can be DRAGGED.
330
- *
331
- * Two problems, both of them the browser's rather than G6's, and both
332
- * already paid for once in the treedb graph (`lib_graph.css`):
333
- *
334
- * G6 puts `touch-action: none` on its CANVAS and NOTHING on the html
335
- * nodes, which are ordinary DIVs layered over it. So a finger landing
336
- * on a card made a page scroll: two `pointermove`s through, then the
337
- * browser decided the gesture was a scroll and killed the stream with
338
- * `pointercancel` -- the card followed for about 20px and stopped dead
339
- * while the page slid.
340
- *
341
- * And a card is text: dragging one starts a text selection, and the
342
- * wash stays until the next click somewhere else. Nothing on this
343
- * canvas is prose.
344
- *
345
- * On the CONTAINER and not the cards: every layer G6 stacks in here is
346
- * a DIV over a canvas that already refuses the browser's gestures, and
347
- * they have to agree.
348
- */
349
- .C_YUI_JSON .json-graph-container {
350
- touch-action: none;
351
- -webkit-user-select: none;
352
- user-select: none;
353
- }
354
-
355
296
  /*
356
297
  * Disable any transition a host stylesheet might inject.
357
298
  */
@@ -205,6 +205,7 @@ let PRIVATE_DATA = {
205
205
  anchor_path: "", // its path, so a rebuild can find it again
206
206
  anchor_state: "off", // "off" | "arming" | "on"
207
207
  last_zoom: 1, // tells a wheel zoom from a drag in aftertransform
208
+ center_posted: false, // one re-centring in flight, never a queue of them
208
209
  };
209
210
 
210
211
  let __gclass__ = null;
@@ -731,8 +732,22 @@ function build_graph(gobj)
731
732
  return;
732
733
  }
733
734
  priv.last_zoom = z;
734
- if(priv.anchor_state === "on" && priv.anchor_id) {
735
- yui_graph_center_on(priv.graph, priv.anchor_id);
735
+
736
+ /*
737
+ * POSTED, like the pick. This runs inside G6's own transform
738
+ * emit, and a camera move made there behaves the way one made
739
+ * inside its click dispatch does: measured, the centring runs,
740
+ * its three passes each fire back here, and the card still ends
741
+ * up hundreds of pixels off -- while the same call from a zoom
742
+ * BUTTON, which lands after the zoom promise resolved, centres
743
+ * exactly. One turn later is out of that stack.
744
+ *
745
+ * At most one in flight: a wheel gesture is a burst of notches,
746
+ * and the queue is not a work queue.
747
+ */
748
+ if(priv.anchor_state === "on" && priv.anchor_id && !priv.center_posted) {
749
+ priv.center_posted = true;
750
+ gobj_post_event(gobj, "EV_CENTER_ANCHOR", {}, gobj);
736
751
  }
737
752
  });
738
753
 
@@ -896,8 +911,24 @@ const FOLD_SPACER = `<span style="width:24px; flex:0 0 auto;"></span>`;
896
911
  * which REPLACES the behavior's own default test rather than adding to
897
912
  * it -- the trap that made a card drag pan the canvas in 7.23.10.
898
913
  */
899
- const BEHAVIORS_READING = ['drag-canvas', 'zoom-canvas', 'drag-element'];
900
- const BEHAVIORS_PICKING = ['drag-canvas', 'zoom-canvas'];
914
+ /*
915
+ * `zoom-canvas` with NO animation, and that is two rules at once.
916
+ *
917
+ * The house rule first: nothing in this GUI slides or fades, and G6's
918
+ * 200ms zoom easing is a transition nobody chose -- it comes with the
919
+ * behavior's defaults.
920
+ *
921
+ * And it is what makes an anchor possible on the WHEEL. `aftertransform`
922
+ * fires while that easing is still running, so the re-centring measured
923
+ * a camera that was still moving: measured, its passes went -272, then
924
+ * +411 the other side, then +183 -- oscillating, because between two
925
+ * reads the easing had moved the ground. With the zoom instantaneous
926
+ * the camera is still by the time anything measures it.
927
+ */
928
+ const ZOOM_CANVAS = {type: 'zoom-canvas', animation: false};
929
+
930
+ const BEHAVIORS_READING = ['drag-canvas', ZOOM_CANVAS, 'drag-element'];
931
+ const BEHAVIORS_PICKING = ['drag-canvas', ZOOM_CANVAS];
901
932
 
902
933
  /*
903
934
  * The card's geometry, in ONE place.
@@ -1900,6 +1931,7 @@ function ac_center_anchor(gobj, event, kw, src)
1900
1931
  {
1901
1932
  let priv = gobj.priv;
1902
1933
 
1934
+ priv.center_posted = false;
1903
1935
  paint_anchor_mark(gobj);
1904
1936
  if(priv.anchor_state === "on" && priv.anchor_id) {
1905
1937
  yui_graph_center_on(priv.graph, priv.anchor_id);
package/src/lib_graph.css CHANGED
@@ -256,12 +256,71 @@
256
256
  * pressed button hands it back to Bulma's rule and the toggle appears
257
257
  * to switch off under the pointer.
258
258
  */
259
- /* Picking the node to anchor, in the gobj tree: the pointer says a
260
- * click is expected, which is otherwise only announced by a button at
261
- * the far end of a toolbar. */
259
+ /*
260
+ * THE OTHER TWO GRAPHS' MOUNTS.
261
+ *
262
+ * They live here, unscoped, and that is the point: these rules first
263
+ * shipped inside `c_yui_json.css` under a `.C_YUI_JSON` ancestor, and
264
+ * a host that mounts `C_YUI_JSON_GRAPH` DIRECTLY -- which the demo
265
+ * does, and any host wanting only the graph -- has no such ancestor.
266
+ * Every one of them silently did nothing there: no crosshair while
267
+ * picking, no mark on the anchored card, and no `touch-action`, so a
268
+ * finger dragging a card made a page scroll. A gclass's stylesheet
269
+ * cannot assume the gclass that usually hosts it.
270
+ *
271
+ * `lib_graph.css` is reached through `lib_graph.js`, which the camera
272
+ * module imports and every one of these graphs uses, so it is loaded
273
+ * wherever a graph is.
274
+ */
275
+
276
+ /*
277
+ * Picking the node to anchor: the pointer says a click is expected,
278
+ * which is otherwise announced only by a button at the far end of a
279
+ * toolbar. `!important` because G6 writes `cursor` onto its own
280
+ * elements from its style props, and a mode has to win over a default.
281
+ */
282
+ .json-graph-container.JSON_GRAPH_PICKING,
283
+ .json-graph-container.JSON_GRAPH_PICKING *,
262
284
  .gobj-tree-container.GOBJ_TREE_PICKING,
263
285
  .gobj-tree-container.GOBJ_TREE_PICKING * {
264
- cursor: crosshair;
286
+ cursor: crosshair !important;
287
+ }
288
+
289
+ /*
290
+ * The card the camera is holding.
291
+ *
292
+ * It has to say so ON THE CARD: the toolbar knows an anchor is set,
293
+ * and knowing WHICH node it is was left to the reader remembering
294
+ * what they clicked -- not a mark, a memory test.
295
+ *
296
+ * An outline and not a fill: the card's own colours already mean
297
+ * things (a dashed border is a dict, a solid one a list, the header
298
+ * carries the group's hue), so repainting any of them would say two
299
+ * things down one channel. `outline` draws OUTSIDE the box, so it
300
+ * cannot move a single row.
301
+ *
302
+ * Amber, the same "this one, right now" the toolbar's arming state
303
+ * uses, and not one of the palette's action colours -- it is not an
304
+ * action.
305
+ */
306
+ .JSON_CARD_ANCHORED {
307
+ outline: 3px solid #fa8c16;
308
+ outline-offset: 2px;
309
+ }
310
+
311
+ /*
312
+ * Once the cards can be DRAGGED. Two problems, both the browser's:
313
+ * G6 puts `touch-action: none` on its CANVAS and nothing on the html
314
+ * nodes, which are ordinary DIVs layered over it, so a finger landing
315
+ * on a card made a page scroll -- two `pointermove`s, then
316
+ * `pointercancel`, the card dead after ~20px while the page slid. And
317
+ * a card is text, so a mouse drag started a selection.
318
+ */
319
+ .json-graph-container,
320
+ .gobj-tree-container {
321
+ touch-action: none;
322
+ -webkit-user-select: none;
323
+ user-select: none;
265
324
  }
266
325
 
267
326
  .button.pressed_state,
package/src/lib_graph.js CHANGED
@@ -218,37 +218,6 @@ function getPointPosition(count, index, margin = 0.2)
218
218
  return start + index * step + step / 2;
219
219
  }
220
220
 
221
- /************************************************************
222
- * Count hooks and fkeys in topic desc, classify node type
223
- ************************************************************/
224
- function calculate_hooks_fkeys_counter(desc)
225
- {
226
- let cols = desc.cols;
227
- desc.hooks_counter = 0;
228
- desc.fkeys_counter = 0;
229
-
230
- for(let i=0; i<cols.length; i++) {
231
- let col = cols[i];
232
- const field_desc = treedb_get_field_desc(col);
233
- switch(field_desc.type) {
234
- case "hook":
235
- desc.hooks_counter++;
236
- break;
237
- case "fkey":
238
- desc.fkeys_counter++;
239
- break;
240
- }
241
- }
242
-
243
- if(desc.hooks_counter === 0) {
244
- desc.node_treedb_type = 'child';
245
- } else if(desc.fkeys_counter === 0) {
246
- desc.node_treedb_type = 'extended';
247
- } else {
248
- desc.node_treedb_type = 'hierarchical';
249
- }
250
- }
251
-
252
221
  export {
253
222
  addClasses,
254
223
  removeClasses,
@@ -274,7 +274,7 @@ export async function yui_graph_center_on(graph, node_id)
274
274
  }
275
275
 
276
276
  /*
277
- * MEASURE, MOVE, MEASURE AGAIN -- up to three times.
277
+ * MOVE BY THE CLOSED FORM, then check -- up to three times.
278
278
  *
279
279
  * Not the arithmetic anybody would write first, and the reason
280
280
  * is worth keeping. The obvious call is `graph.focusElement()`,
@@ -287,18 +287,26 @@ export async function yui_graph_center_on(graph, node_id)
287
287
  * one shot lands short or long by a factor nobody should have
288
288
  * to name.
289
289
  *
290
- * Probing for that factor gives noise: the camera settles
291
- * asynchronously, so a position read straight after a
292
- * translate is a value halfway through. AWAITING each move and
293
- * measuring again needs no factor at all -- the direction is
294
- * right, so the residual falls to nothing in two or three
295
- * passes, and a graph whose maths change under us keeps
296
- * working.
290
+ * Guessing at that factor does not work: stepping by the
291
+ * measured pixel gap OSCILLATES -- measured, its passes went
292
+ * -272, then +411 the other side, then +183, with the zoom
293
+ * stable throughout, so it is not an animation racing the
294
+ * reads. The factor is read off G6's own
295
+ * `getTranslateOptions()` instead: an absolute translate puts
296
+ * the camera at `canvasCentre - T/zoom`, and the camera is
297
+ * what lands on the viewport centre, so
297
298
  *
298
- * The 1px floor is what stops it converging forever on the
299
- * rounding.
299
+ * T = (canvasCentre - nodeWorldPosition) * zoom
300
+ *
301
+ * which lands exactly, in one pass, at any zoom.
302
+ *
303
+ * The loop stays as a guard: it costs one measurement when the
304
+ * first move was right, and it is what would catch this going
305
+ * wrong again rather than shipping a graph that drifts. The
306
+ * 1px floor stops it chasing the rounding.
300
307
  */
301
308
  for(let i = 0; i < 3; i++) {
309
+ let z = graph.getZoom() || 1;
302
310
  let at = graph.getViewportByCanvas(graph.getElementPosition(node_id));
303
311
  let want = graph.getCanvasCenter();
304
312
  let dx = want[0] - at[0];
@@ -307,8 +315,12 @@ export async function yui_graph_center_on(graph, node_id)
307
315
  if(Math.abs(dx) < 1 && Math.abs(dy) < 1) {
308
316
  break;
309
317
  }
310
- let pos = graph.getPosition();
311
- await graph.translateTo([pos[0] + dx, pos[1] + dy]);
318
+ /* Closed form, read off G6's own `getTranslateOptions()`:
319
+ * an ABSOLUTE translate puts the camera at
320
+ * `canvasCentre - T/zoom`, and the camera is what lands on
321
+ * the viewport centre. So T = (centre - node) * zoom. */
322
+ let n = graph.getElementPosition(node_id);
323
+ await graph.translateTo([(want[0] - n[0]) * z, (want[1] - n[1]) * z]);
312
324
  }
313
325
  return true;
314
326
  } catch(e) {