From 6dad8ab33299306aacb4f6e4494af0cf289e16b5 Mon Sep 17 00:00:00 2001 From: Jamie Lentin Date: Tue, 5 Aug 2025 08:33:27 +0000 Subject: [PATCH 1/6] factory/midnode: Documentation for anchoring-related variables --- .../rawJS/OZTreeModule/src/factory/midnode.js | 16 ++++++++-------- .../rawJS/OZTreeModule/src/position_helper.js | 11 +++++++++++ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/OZprivate/rawJS/OZTreeModule/src/factory/midnode.js b/OZprivate/rawJS/OZTreeModule/src/factory/midnode.js index e3c3acfcd..77e94d674 100755 --- a/OZprivate/rawJS/OZTreeModule/src/factory/midnode.js +++ b/OZprivate/rawJS/OZTreeModule/src/factory/midnode.js @@ -43,9 +43,9 @@ class Midnode { this.arcr = 1.0; this.arcx = 1.0; this.arcy = 1.0; - this.nextr = new Array(config.factory.child_num); - this.nextx = new Array(config.factory.child_num); - this.nexty = new Array(config.factory.child_num); + this.nextr = new Array(config.factory.child_num); // Relative radius/scale to assign to children, as decided by view _pre_calc() functions + this.nextx = new Array(config.factory.child_num); // Relative x-location ... + this.nexty = new Array(config.factory.child_num); // Relative y-location ... this.gxmin = 1.0; // Node bounding box this.gymin = 1.0; // Node bounding box this.hxmin = 1.0; // Node-and-descendants bounding box @@ -55,13 +55,13 @@ class Midnode { this.hxmax = 1.0; // Node-and-descendants bounding box this.hymax = 1.0; // Node-and-descendants bounding box - this.xvar = 1.0; - this.yvar = 1.0; - this.rvar = 1.0; + this.xvar = 1.0; // x-location of node relative to graphref node updated by position_helper:drawreg_target() + this.yvar = 1.0; // y-location of node ... + this.rvar = 1.0; // radius/scale of node ... this.gvar = false; // gvar is true if this node itself needs to be drawn on screen (i.e onezoom.config.debug_bounding_box = 1) this.dvar = false; // dvar is true if this node (or a descendent node) needs to be drawn on the screen (i.e onezoom.config.debug_bounding_box = 4) - this.graphref = false; - this.targeted = false; + this.graphref = false; // true if this node (or a descendent node) is the "referencing node", i.e. the node from which xvar/yvar/rvar are relative to + this.targeted = false; // true if this node (or a descendent node) is the destination for the current flight this.child_leaf_meta_start = new Array(config.factory.child_num); this.child_leaf_meta_end = new Array(config.factory.child_num); diff --git a/OZprivate/rawJS/OZTreeModule/src/position_helper.js b/OZprivate/rawJS/OZTreeModule/src/position_helper.js index f01f40eaf..83c16641d 100755 --- a/OZprivate/rawJS/OZTreeModule/src/position_helper.js +++ b/OZprivate/rawJS/OZTreeModule/src/position_helper.js @@ -132,6 +132,9 @@ function get_xyr_target(node, x2,y2,r2,into_node) { } } +/** + * Walk tree from (node), probably root, turning graphref off + */ function deanchor(node) { if (node.graphref) { let length = node.children.length; @@ -370,6 +373,10 @@ function pan_zoom(prop_p, prop_z) { tree_state.yp = tree_centreY + y_add2*(1-prop_p) + (pre_yp2-y_add2-tree_centreY) * Math.pow(r_mult2,prop_z); } +/** + * Force the anchor to be the given (node), + * (i.e. set graphref on node and all it's ancestors) + */ function reanchor_at_node(node) { node.graphref = true; if (node.upnode) { @@ -377,6 +384,10 @@ function reanchor_at_node(node) { } } +/** + * Walk tree, anchoring to the first node on-screen that has 2.2 < node.rvar < 22000 + * (i.e. set graphref on this node and it's ancestors) + */ function reanchor(node) { if (node.dvar) { node.graphref = true; From dbc39dd6bc036a432f33e913a6e0102aaef4bbd4 Mon Sep 17 00:00:00 2001 From: Jamie Lentin Date: Thu, 7 Aug 2025 16:51:07 +0000 Subject: [PATCH 2/6] shape_manager: Make reality match bitmask mask All the documentation says 0x1 is label, but was actually 0x2. Swap them around. --- .../src/projection/shape_manager.js | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/OZprivate/rawJS/OZTreeModule/src/projection/shape_manager.js b/OZprivate/rawJS/OZTreeModule/src/projection/shape_manager.js index cafe08d41..861d6d9e7 100755 --- a/OZprivate/rawJS/OZTreeModule/src/projection/shape_manager.js +++ b/OZprivate/rawJS/OZTreeModule/src/projection/shape_manager.js @@ -64,6 +64,21 @@ function draw_bounding_box(node, shapes) { } if (debug & 0x2) { // Bounding box for node + parent + s = BezierShape.create(); + s.sx = s.sy = s.ex = s.ey = null; + s.path_points.push(['move', node.xvar + node.rvar * node.gxmin, node.yvar + node.rvar * node.gymin]); + s.path_points.push(['line', node.xvar + node.rvar * node.gxmin, node.yvar + node.rvar * node.gymax]); + s.path_points.push(['line', node.xvar + node.rvar * node.gxmax, node.yvar + node.rvar * node.gymax]); + s.path_points.push(['line', node.xvar + node.rvar * node.gxmax, node.yvar + node.rvar * node.gymin]); + s.path_points.push(['line', node.xvar + node.rvar * node.gxmin, node.yvar + node.rvar * node.gymin]); + s.do_stroke = true; + s.stroke.line_width = 1; + s.height = 0; + s.stroke.color = 'hsl(' + Math.sin(node.metacode) * 360 + ', 100%, 80%)'; + shapes.push(s); + } + + if (debug & 0x1) { // Bounding box text label s = TextShape.create(); s.text = "" + node.latin_name; s.width = (node.xvar + node.rvar * node.gxmax) - (node.xvar + node.rvar * node.gxmin); @@ -79,20 +94,6 @@ function draw_bounding_box(node, shapes) { shapes.push(s); } - if (debug & 0x1) { // Bounding box text label - s = BezierShape.create(); - s.sx = s.sy = s.ex = s.ey = null; - s.path_points.push(['move', node.xvar + node.rvar * node.gxmin, node.yvar + node.rvar * node.gymin]); - s.path_points.push(['line', node.xvar + node.rvar * node.gxmin, node.yvar + node.rvar * node.gymax]); - s.path_points.push(['line', node.xvar + node.rvar * node.gxmax, node.yvar + node.rvar * node.gymax]); - s.path_points.push(['line', node.xvar + node.rvar * node.gxmax, node.yvar + node.rvar * node.gymin]); - s.path_points.push(['line', node.xvar + node.rvar * node.gxmin, node.yvar + node.rvar * node.gymin]); - s.do_stroke = true; - s.stroke.line_width = 1; - s.height = 0; - s.stroke.color = 'hsl(' + Math.sin(node.metacode) * 360 + ', 100%, 80%)'; - shapes.push(s); - } } function height_comparator(a, b) { From e895a9f032709c2e3440b8c97a2ae9194d491773 Mon Sep 17 00:00:00 2001 From: Jamie Lentin Date: Thu, 7 Aug 2025 14:14:21 +0000 Subject: [PATCH 3/6] factory/midnode: toString() implementation for easier debug Add toString() as a repr-like method to use in debugging. Show how to use it in console.log & use it as the default debug label for nodes. --- .../rawJS/OZTreeModule/src/factory/midnode.js | 15 ++++++++++++++- .../OZTreeModule/src/projection/shape_manager.js | 2 +- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/OZprivate/rawJS/OZTreeModule/src/factory/midnode.js b/OZprivate/rawJS/OZTreeModule/src/factory/midnode.js index 77e94d674..dd8025db4 100755 --- a/OZprivate/rawJS/OZTreeModule/src/factory/midnode.js +++ b/OZprivate/rawJS/OZTreeModule/src/factory/midnode.js @@ -291,7 +291,20 @@ class Midnode { this._picID_credit = null; this._detail_fetched = false; } - + + /** + * Text representation of node, for debugging purposes + * + * Use with console log, e.g: console.log("Reanchoring to " + node); + * (NB "+", not ",") + */ + toString() { + return [ + this.cname || this.latin_name || 'Node', + this.ott ? '@=' + this.ott : '@_ozid=' + this.ozid, + ].join(" "); + } + /** * Returns the OZid * i.e. negative metacode for leaf, positive metacode for interior node diff --git a/OZprivate/rawJS/OZTreeModule/src/projection/shape_manager.js b/OZprivate/rawJS/OZTreeModule/src/projection/shape_manager.js index 861d6d9e7..197e41182 100755 --- a/OZprivate/rawJS/OZTreeModule/src/projection/shape_manager.js +++ b/OZprivate/rawJS/OZTreeModule/src/projection/shape_manager.js @@ -80,7 +80,7 @@ function draw_bounding_box(node, shapes) { if (debug & 0x1) { // Bounding box text label s = TextShape.create(); - s.text = "" + node.latin_name; + s.text = "" + node.toString(); s.width = (node.xvar + node.rvar * node.gxmax) - (node.xvar + node.rvar * node.gxmin); s.height = 5; s.x = node.xvar + node.rvar * node.gxmin + (s.width / 2); From 0a5335696c056ebce85f36d610529b4bcd974c99 Mon Sep 17 00:00:00 2001 From: Jamie Lentin Date: Tue, 5 Aug 2025 08:36:45 +0000 Subject: [PATCH 4/6] position_helper: Simplify reanchor Early exit for the unlikely !node.dvar case, remove length assignments, document code blocks. --- .../rawJS/OZTreeModule/src/position_helper.js | 42 ++++++++++--------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/OZprivate/rawJS/OZTreeModule/src/position_helper.js b/OZprivate/rawJS/OZTreeModule/src/position_helper.js index 83c16641d..db119dad9 100755 --- a/OZprivate/rawJS/OZTreeModule/src/position_helper.js +++ b/OZprivate/rawJS/OZTreeModule/src/position_helper.js @@ -389,28 +389,30 @@ function reanchor_at_node(node) { * (i.e. set graphref on this node and it's ancestors) */ function reanchor(node) { - if (node.dvar) { - node.graphref = true; - if (node.gvar || !node.has_child || (node.rvar > 2.2 && node.rvar < 22000)) { - tree_state.xp = node.xvar; - tree_state.yp = node.yvar; - tree_state.ws = node.rvar / 220; - let length = node.children.length; - for (let i=0; i 2.2 && node.rvar < 22000)) { + // Anchor to this node + tree_state.xp = node.xvar; + tree_state.yp = node.yvar; + tree_state.ws = node.rvar / 220; + // Deanchor everything below this node + for (let i=0; i Date: Tue, 5 Aug 2025 08:48:46 +0000 Subject: [PATCH 5/6] position_helper: reanchor_at_node() should deanchor first The main reanchor() doesn't need a deanchor() first, so neither should reanchor_at_node(). This also means that the deanchor export is no longer required. --- .../src/controller/controller_anim.js | 3 +-- .../rawJS/OZTreeModule/src/position_helper.js | 16 +++++++++++----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/OZprivate/rawJS/OZTreeModule/src/controller/controller_anim.js b/OZprivate/rawJS/OZTreeModule/src/controller/controller_anim.js index 0606f652b..4cdba567c 100755 --- a/OZprivate/rawJS/OZTreeModule/src/controller/controller_anim.js +++ b/OZprivate/rawJS/OZTreeModule/src/controller/controller_anim.js @@ -184,8 +184,7 @@ export default function (Controller) { let anchor_node = this.dynamic_load_and_calc(dest_OZid, { generation_at_searched_node: config.generation_at_searched_node }); - position_helper.deanchor(this.root); - position_helper.reanchor_at_node(anchor_node); + position_helper.reanchor_at_node(anchor_node, this.root); this.re_calc(); this.trigger_refresh_loop(); resolve() diff --git a/OZprivate/rawJS/OZTreeModule/src/position_helper.js b/OZprivate/rawJS/OZTreeModule/src/position_helper.js index db119dad9..bd77a234e 100755 --- a/OZprivate/rawJS/OZTreeModule/src/position_helper.js +++ b/OZprivate/rawJS/OZTreeModule/src/position_helper.js @@ -377,11 +377,17 @@ function pan_zoom(prop_p, prop_z) { * Force the anchor to be the given (node), * (i.e. set graphref on node and all it's ancestors) */ -function reanchor_at_node(node) { - node.graphref = true; - if (node.upnode) { - reanchor_at_node(node.upnode); +function reanchor_at_node(node, root_node) { + // Set graphref false everywhere + deanchor(root_node); + + // Walk up tree from (node), setting graphref + while (node.upnode) { + node.graphref = true; + node = node.upnode; } + // Set graphref on root node + node.graphref = true; } /** @@ -429,4 +435,4 @@ function set_anim_speed(val) { global_anim_speed = val; } -export {deanchor, reanchor, reanchor_at_node, target_by_code, clear_target, perform_actual_fly, get_anim_speed, set_anim_speed}; +export {reanchor, reanchor_at_node, target_by_code, clear_target, perform_actual_fly, get_anim_speed, set_anim_speed}; From b8dcc0141d266a7b6a9cc88a40c4dc21de01e8de Mon Sep 17 00:00:00 2001 From: Jamie Lentin Date: Thu, 7 Aug 2025 16:33:05 +0000 Subject: [PATCH 6/6] re_calc: Combine node_descendants_in_screen / node_in_screen Combine them together to reduce mental load. And it doesn't check that the node is *in* (i.e. contained by), but *on* (i.e. a bit is visible). --- .../OZTreeModule/src/projection/re_calc.js | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/OZprivate/rawJS/OZTreeModule/src/projection/re_calc.js b/OZprivate/rawJS/OZTreeModule/src/projection/re_calc.js index 80eac6368..dc15de201 100755 --- a/OZprivate/rawJS/OZTreeModule/src/projection/re_calc.js +++ b/OZprivate/rawJS/OZTreeModule/src/projection/re_calc.js @@ -32,7 +32,7 @@ function drawreg(node, x, y, r) { } } - if(node_descendants_in_screen(node)) { + if(node_on_screen(node, true)) { if (node.rvar > tree_state.threshold) { for (let other=0; other tree_state.threshold) { let length = node.children.length; @@ -101,26 +101,24 @@ function get_dvar_by_children(node) { return dvar; } -/** Does the given node and it's descendants fit on screen? */ -function node_descendants_in_screen(node) { - if ((node.xvar + node.rvar * node.hxmax) < 0) return false; - else if ((node.xvar + node.rvar * node.hxmin) > tree_state.widthres) return false; - else if ((node.yvar + node.rvar * node.hymax) < 0) return false; - else if ((node.yvar + node.rvar * node.hymin) > tree_state.heightres) return false; - else return true; -} +/** + * Does the bounding box of the node / node-and-descendants fit on screen? + */ +function node_on_screen(node, inclDescendants) { + const x1 = node.xvar + node.rvar * (inclDescendants ? node.hxmin : node.gxmin); + const x2 = node.xvar + node.rvar * (inclDescendants ? node.hxmax : node.gxmax); + const y1 = node.yvar + node.rvar * (inclDescendants ? node.hymin : node.gymin); + const y2 = node.yvar + node.rvar * (inclDescendants ? node.hymax : node.gymax); -/** Does the given node fit on screen? */ -function node_in_screen(node) { - if ((node.xvar + node.rvar * node.gxmax) < 0) return false; - else if ((node.xvar + node.rvar * node.gxmin) > tree_state.widthres) return false; - else if ((node.yvar + node.rvar * node.gymax) < 0) return false; - else if ((node.yvar + node.rvar * node.gymin) > tree_state.heightres) return false; - else return true; + if (x2 < 0) return false; + if (x1 > tree_state.widthres) return false; + if (y2 < 0) return false; + if (y1 > tree_state.heightres) return false; + return true; } function set_node_gvar_dvar(node) { - if(node_in_screen(node)) { + if(node_on_screen(node, false)) { node.gvar = true; node.dvar = true; } else {