@yuneta/gobj-ui 7.23.104 → 7.23.106

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 CHANGED
@@ -962,13 +962,18 @@ Two mechanisms, because the question is not the same in the two cases:
962
962
  folds have always used. It keeps the zoom because it only translates, and it
963
963
  survives a relayout that moves everything, which restoring raw coordinates
964
964
  would not.
965
- - **Across a RELOAD** there is no node to hold on to yet, so the viewport itself
966
- is restored: `{zoom, x, y}` as G6 reports them (`getZoom()` + `getPosition()`,
967
- the documented pair of `zoomTo()` + `translateTo()`).
965
+ - **Across a RELOAD** the same thing is saved and replayed: the zoom, a NODE,
966
+ and the viewport pixel that node was on. **Not G6's own position** — an
967
+ absolute `translateTo()` leaves the camera at `canvasCentre - T/zoom`, so
968
+ `getPosition()` and `translateTo()` are each other's inverse only at zoom 1,
969
+ and restoring one with the other brings the zoom back and puts the graph
970
+ somewhere else. That is the whole reason `yui_graph_place_at()` exists.
968
971
 
969
972
  Wiring: `C_G6_NODES_TREE` takes a `camera` attr — the viewport to restore on its
970
973
  FIRST draw, empty meaning *open fitted* — and publishes **`EV_CAMERA_CHANGED
971
- {zoom, x, y}`** once a move has settled. The settle is a real time (700 ms of
974
+ {zoom, node, x, y}`** once a move has settled. A saved node this load does not
975
+ have leaves the graph to its opening fit, checked before the zoom is touched:
976
+ a zoom with no framing to go with it is worse than a fit. The settle is a real time (700 ms of
972
977
  the browser's `setTimeout`, not a `C_TIMER`): a wheel notch, a pinch and a drag
973
978
  each fire `aftertransform` many times, and what is worth saving is where the
974
979
  gesture ENDED. It fires for a PAN as well as a zoom — a pan is the reader's just
@@ -54825,7 +54825,7 @@ var attrs_table$4 = [
54825
54825
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "node_labels", 0, true, "A `shape` node says its name under the figure. Off, it is a coloured figure and nothing else"),
54826
54826
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "confirm_delete_node", 0, true, "Ask confirmation before deleting a node"),
54827
54827
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "confirm_unlink_edge", 0, true, "Ask confirmation before unlinking an edge"),
54828
- (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_DICT, "camera", 0, "{}", "Where the reader left the viewport: {zoom, x, y}. Empty = the graph opens fitted. Restored on the FIRST draw and published back as EV_CAMERA_CHANGED once a move settles, so a host can persist it"),
54828
+ (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_DICT, "camera", 0, "{}", "Where the reader left the viewport: {zoom, node, x, y} -- a NODE at a viewport pixel, not G6's own position, which does not restore. Empty = the graph opens fitted. Restored on the FIRST draw and published back as EV_CAMERA_CHANGED once a move settles, so a host can persist it"),
54829
54829
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "wide", 0, "40px", "Height of header"),
54830
54830
  (0, _yuneta_gobj_js.SDATA_END)()
54831
54831
  ];
@@ -56711,15 +56711,17 @@ var MIN_READABLE_ZOOM = .5;
56711
56711
  var CAMERA_SETTLE_MS = 700;
56712
56712
  function read_camera(gobj) {
56713
56713
  let graph = gobj.priv.graph;
56714
- if (!graph || typeof graph.getZoom !== "function" || typeof graph.getPosition !== "function") return null;
56714
+ if (!graph || typeof graph.getZoom !== "function") return null;
56715
56715
  try {
56716
56716
  let z = graph.getZoom();
56717
- let p = graph.getPosition();
56718
- if (!(0, _yuneta_gobj_js.is_number)(z) || !p || !(0, _yuneta_gobj_js.is_number)(p[0]) || !(0, _yuneta_gobj_js.is_number)(p[1])) return null;
56717
+ let node = fold_keep_node(gobj);
56718
+ let vp = node ? yui_graph_viewport_of(graph, node) : null;
56719
+ if (!(0, _yuneta_gobj_js.is_number)(z) || !node || !vp || !(0, _yuneta_gobj_js.is_number)(vp[0]) || !(0, _yuneta_gobj_js.is_number)(vp[1])) return null;
56719
56720
  return {
56720
56721
  zoom: z,
56721
- x: p[0],
56722
- y: p[1]
56722
+ node,
56723
+ x: vp[0],
56724
+ y: vp[1]
56723
56725
  };
56724
56726
  } catch (e) {
56725
56727
  return null;
@@ -56729,11 +56731,12 @@ async function restore_camera(gobj) {
56729
56731
  let priv = gobj.priv;
56730
56732
  let graph = priv.graph;
56731
56733
  let cam = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "camera");
56732
- if (!graph || (0, _yuneta_gobj_js.empty_json)(cam) || !(0, _yuneta_gobj_js.is_number)(cam.zoom)) return false;
56734
+ if (!graph || (0, _yuneta_gobj_js.empty_json)(cam) || !(0, _yuneta_gobj_js.is_number)(cam.zoom) || !cam.node || !(0, _yuneta_gobj_js.is_number)(cam.x) || !(0, _yuneta_gobj_js.is_number)(cam.y)) return false;
56735
+ if (!yui_graph_viewport_of(graph, cam.node)) return false;
56733
56736
  priv._camera_restoring = true;
56734
56737
  try {
56735
56738
  await graph.zoomTo(cam.zoom);
56736
- if ((0, _yuneta_gobj_js.is_number)(cam.x) && (0, _yuneta_gobj_js.is_number)(cam.y)) await graph.translateTo([cam.x, cam.y]);
56739
+ await yui_graph_place_at(graph, cam.node, [cam.x, cam.y]);
56737
56740
  return true;
56738
56741
  } catch (e) {
56739
56742
  (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: cannot restore the camera: ${e}`);
@@ -63916,6 +63919,7 @@ function ac_layout_autoset(gobj, event, kw, src) {
63916
63919
  function ac_camera_changed(gobj, event, kw, src) {
63917
63920
  (0, _yuneta_gobj_js.gobj_write_attr)(gobj, "camera", {
63918
63921
  zoom: kw.zoom,
63922
+ node: kw.node,
63919
63923
  x: kw.x,
63920
63924
  y: kw.y
63921
63925
  });
@@ -54820,7 +54820,7 @@ var attrs_table$4 = [
54820
54820
  SDATA(data_type_t.DTP_BOOLEAN, "node_labels", 0, true, "A `shape` node says its name under the figure. Off, it is a coloured figure and nothing else"),
54821
54821
  SDATA(data_type_t.DTP_BOOLEAN, "confirm_delete_node", 0, true, "Ask confirmation before deleting a node"),
54822
54822
  SDATA(data_type_t.DTP_BOOLEAN, "confirm_unlink_edge", 0, true, "Ask confirmation before unlinking an edge"),
54823
- SDATA(data_type_t.DTP_DICT, "camera", 0, "{}", "Where the reader left the viewport: {zoom, x, y}. Empty = the graph opens fitted. Restored on the FIRST draw and published back as EV_CAMERA_CHANGED once a move settles, so a host can persist it"),
54823
+ SDATA(data_type_t.DTP_DICT, "camera", 0, "{}", "Where the reader left the viewport: {zoom, node, x, y} -- a NODE at a viewport pixel, not G6's own position, which does not restore. Empty = the graph opens fitted. Restored on the FIRST draw and published back as EV_CAMERA_CHANGED once a move settles, so a host can persist it"),
54824
54824
  SDATA(data_type_t.DTP_STRING, "wide", 0, "40px", "Height of header"),
54825
54825
  SDATA_END()
54826
54826
  ];
@@ -56706,15 +56706,17 @@ var MIN_READABLE_ZOOM = .5;
56706
56706
  var CAMERA_SETTLE_MS = 700;
56707
56707
  function read_camera(gobj) {
56708
56708
  let graph = gobj.priv.graph;
56709
- if (!graph || typeof graph.getZoom !== "function" || typeof graph.getPosition !== "function") return null;
56709
+ if (!graph || typeof graph.getZoom !== "function") return null;
56710
56710
  try {
56711
56711
  let z = graph.getZoom();
56712
- let p = graph.getPosition();
56713
- if (!is_number(z) || !p || !is_number(p[0]) || !is_number(p[1])) return null;
56712
+ let node = fold_keep_node(gobj);
56713
+ let vp = node ? yui_graph_viewport_of(graph, node) : null;
56714
+ if (!is_number(z) || !node || !vp || !is_number(vp[0]) || !is_number(vp[1])) return null;
56714
56715
  return {
56715
56716
  zoom: z,
56716
- x: p[0],
56717
- y: p[1]
56717
+ node,
56718
+ x: vp[0],
56719
+ y: vp[1]
56718
56720
  };
56719
56721
  } catch (e) {
56720
56722
  return null;
@@ -56724,11 +56726,12 @@ async function restore_camera(gobj) {
56724
56726
  let priv = gobj.priv;
56725
56727
  let graph = priv.graph;
56726
56728
  let cam = gobj_read_attr(gobj, "camera");
56727
- if (!graph || empty_json(cam) || !is_number(cam.zoom)) return false;
56729
+ if (!graph || empty_json(cam) || !is_number(cam.zoom) || !cam.node || !is_number(cam.x) || !is_number(cam.y)) return false;
56730
+ if (!yui_graph_viewport_of(graph, cam.node)) return false;
56728
56731
  priv._camera_restoring = true;
56729
56732
  try {
56730
56733
  await graph.zoomTo(cam.zoom);
56731
- if (is_number(cam.x) && is_number(cam.y)) await graph.translateTo([cam.x, cam.y]);
56734
+ await yui_graph_place_at(graph, cam.node, [cam.x, cam.y]);
56732
56735
  return true;
56733
56736
  } catch (e) {
56734
56737
  log_error(`${gobj_short_name(gobj)}: cannot restore the camera: ${e}`);
@@ -63911,6 +63914,7 @@ function ac_layout_autoset(gobj, event, kw, src) {
63911
63914
  function ac_camera_changed(gobj, event, kw, src) {
63912
63915
  gobj_write_attr(gobj, "camera", {
63913
63916
  zoom: kw.zoom,
63917
+ node: kw.node,
63914
63918
  x: kw.x,
63915
63919
  y: kw.y
63916
63920
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuneta/gobj-ui",
3
- "version": "7.23.104",
3
+ "version": "7.23.106",
4
4
  "type": "module",
5
5
  "main": "dist/gobj-ui.cjs.js",
6
6
  "module": "dist/gobj-ui.es.js",
@@ -444,7 +444,7 @@ SDATA(data_type_t.DTP_BOOLEAN, "confirm_delete_node", 0, true, "Ask confirm
444
444
  SDATA(data_type_t.DTP_BOOLEAN, "confirm_unlink_edge", 0, true, "Ask confirmation before unlinking an edge"),
445
445
 
446
446
  /*---------------- Camera ----------------*/
447
- SDATA(data_type_t.DTP_DICT, "camera", 0, "{}", "Where the reader left the viewport: {zoom, x, y}. Empty = the graph opens fitted. Restored on the FIRST draw and published back as EV_CAMERA_CHANGED once a move settles, so a host can persist it"),
447
+ SDATA(data_type_t.DTP_DICT, "camera", 0, "{}", "Where the reader left the viewport: {zoom, node, x, y} -- a NODE at a viewport pixel, not G6's own position, which does not restore. Empty = the graph opens fitted. Restored on the FIRST draw and published back as EV_CAMERA_CHANGED once a move settles, so a host can persist it"),
448
448
 
449
449
  SDATA(data_type_t.DTP_STRING, "wide", 0, "40px", "Height of header"),
450
450
 
@@ -3370,21 +3370,35 @@ const MIN_READABLE_ZOOM = 0.5;
3370
3370
  ************************************************************/
3371
3371
  const CAMERA_SETTLE_MS = 700;
3372
3372
 
3373
+ /* A camera is saved as a NODE at a VIEWPORT PIXEL, plus the zoom --
3374
+ * never as G6's own position.
3375
+ *
3376
+ * `translateTo()` does not take viewport pixels: an absolute translate
3377
+ * leaves the camera at `canvasCentre - T/zoom`, so `getPosition()` and
3378
+ * `translateTo()` are only each other's inverse at zoom 1. Restoring
3379
+ * one with the other brought the zoom back and put the graph somewhere
3380
+ * else, which is exactly what it looks like -- and the reason to write
3381
+ * the pair down (`yui_graph_place_at`, gobj-ui 7.23.29) was that it
3382
+ * had already cost fifteen iterations once.
3383
+ *
3384
+ * A node and a pixel is also the SAME thing the folds keep across a
3385
+ * rebuild. One idea, used twice. */
3373
3386
  function read_camera(gobj)
3374
3387
  {
3375
3388
  let priv = gobj.priv;
3376
3389
  let graph = priv.graph;
3377
3390
 
3378
- if(!graph || typeof graph.getZoom !== "function" || typeof graph.getPosition !== "function") {
3391
+ if(!graph || typeof graph.getZoom !== "function") {
3379
3392
  return null;
3380
3393
  }
3381
3394
  try {
3382
3395
  let z = graph.getZoom();
3383
- let p = graph.getPosition();
3384
- if(!is_number(z) || !p || !is_number(p[0]) || !is_number(p[1])) {
3396
+ let node = fold_keep_node(gobj);
3397
+ let vp = node? yui_graph_viewport_of(graph, node) : null;
3398
+ if(!is_number(z) || !node || !vp || !is_number(vp[0]) || !is_number(vp[1])) {
3385
3399
  return null;
3386
3400
  }
3387
- return {zoom: z, x: p[0], y: p[1]};
3401
+ return {zoom: z, node: node, x: vp[0], y: vp[1]};
3388
3402
  } catch(e) {
3389
3403
  return null; /* between renders: there is no camera to read */
3390
3404
  }
@@ -3398,15 +3412,21 @@ async function restore_camera(gobj)
3398
3412
  let graph = priv.graph;
3399
3413
  let cam = gobj_read_attr(gobj, "camera");
3400
3414
 
3401
- if(!graph || empty_json(cam) || !is_number(cam.zoom)) {
3415
+ if(!graph || empty_json(cam) || !is_number(cam.zoom) ||
3416
+ !cam.node || !is_number(cam.x) || !is_number(cam.y)) {
3417
+ return false; /* nothing saved, or saved by a version that wrote
3418
+ G6's own position -- which never restored */
3419
+ }
3420
+ /* Checked BEFORE the zoom is touched: a saved node that this load
3421
+ * does not have (the treedb changed under it) must leave the graph
3422
+ * to its opening fit, not at a zoom with no framing to go with it. */
3423
+ if(!yui_graph_viewport_of(graph, cam.node)) {
3402
3424
  return false;
3403
3425
  }
3404
3426
  priv._camera_restoring = true;
3405
3427
  try {
3406
3428
  await graph.zoomTo(cam.zoom);
3407
- if(is_number(cam.x) && is_number(cam.y)) {
3408
- await graph.translateTo([cam.x, cam.y]);
3409
- }
3429
+ await yui_graph_place_at(graph, cam.node, [cam.x, cam.y]);
3410
3430
  return true;
3411
3431
  } catch(e) {
3412
3432
  log_error(`${gobj_short_name(gobj)}: cannot restore the camera: ${e}`);
@@ -2900,8 +2900,13 @@ function ac_layout_autoset(gobj, event, kw, src)
2900
2900
  ************************************************************/
2901
2901
  function ac_camera_changed(gobj, event, kw, src)
2902
2902
  {
2903
+ /* `node` travels with the rest and is not optional: a camera is a
2904
+ * NODE at a viewport pixel, and one rebuilt here as `{zoom, x, y}`
2905
+ * -- which is what this did -- is a camera the engine refuses to
2906
+ * restore, so the graph came back at the right zoom in the wrong
2907
+ * place. Copy the fields the contract names, all of them. */
2903
2908
  gobj_write_attr(gobj, "camera", {
2904
- zoom: kw.zoom, x: kw.x, y: kw.y
2909
+ zoom: kw.zoom, node: kw.node, x: kw.x, y: kw.y
2905
2910
  });
2906
2911
  gobj_save_persistent_attrs(gobj, "camera");
2907
2912
  return 0;