From 104ea052efba68993c5e3cb456ee99a605abdd5b Mon Sep 17 00:00:00 2001 From: Matthew Wells Date: Wed, 11 Sep 2024 17:08:06 -0500 Subject: [PATCH 1/7] metadata is placed, SVG issues persist --- html/table.html | 48 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/html/table.html b/html/table.html index 3ded5f1..4aa5c60 100644 --- a/html/table.html +++ b/html/table.html @@ -131,9 +131,7 @@ var SHOW_METADATA_IN_NAME = false; var LINE_THICKNESS = 2.0; - //var TREE_VAL = 1; // sets defualt tree to draw var TREE_VAL = "Dendrogram"; // sets defualt tree to draw - //var TREE_SWITCH = false; var collapse_subtree = false; // can think of another way to signal state without our larger refactor var focused_element = null; // Focused element to have its colour reset var RADIUS_INCREASED = false; @@ -2249,7 +2247,6 @@ export_metadata_table = function(e){ // Export updated metadata - console.log(e.id) if(!ORIGINAL_DATA){ console.error("No contextual data imported yet"); Swal.fire({ @@ -2330,9 +2327,35 @@ css_export.appendChild(link_style_sheet); svg.insertBefore(css_export, svg.firstChild); + let leaves = svg.querySelectorAll(".leaf-node") + let longest_label = 10 + if(ORIGINAL_DATA){ + leaves.forEach((ele) => { + let [element, circle, text] = SelectedNodes.getNodeData(ele) + let input_text = text.textContent + if(ORIGINAL_DATA.has(input_text) && input_text){ + let row = ORIGINAL_DATA.get(input_text) + let new_label = `${input_text}\t${row.slice(1).join('\t')}` + text.textContent = new_label + if(new_label.length > longest_label){ + longest_label = new_label.length; + } + } + }) + } + const tree_svg = svg.querySelector("#TreeSVG"); + tree_svg.style.overflow = "visible" + const offset_safety_factor = 20; - tree_svg.style.marginLeft = legend_width + offset_safety_factor; + let bbox = tree_svg.getBBox() + //tree_svg.setAttribute("width", bbox.x + bbox.width + bbox.x + longest_label); + //tree_svg.style.marginLeft = legend_width + offset_safety_factor; + //tree_svg.style.width = tree_svg.style.width + longest_label + + tree_svg.setAttribute("width", bbox.x + bbox.width + bbox.x + longest_label); + tree_svg.setAttribute("height", bbox.y + bbox.height + bbox.y); + //tree_svg.setAttribute("viewBox", `${bbox.x} ${bbox.y} ${bbox.width} ${bbox.height}`); const serializer = new window.XMLSerializer; const xml_string = serializer.serializeToString(svg); @@ -2355,6 +2378,18 @@ /*Adapted from https://gist.github.com/tatsuyasusukida/1261585e3422da5645a1cbb9cf8813d6 and https://zooper.pages.dev/articles/how-to-convert-a-svg-to-png-using-canvas*/ export_tree_to_png = function(){ let svg = document.getElementById("TreeSVG") + + let leaves = svg.querySelectorAll(".leaf-node") + if(ORIGINAL_DATA){ + leaves.forEach((ele) => { + let [element, circle, text] = SelectedNodes.getNodeData(ele) + let input_text = text.textContent + if(ORIGINAL_DATA.has(input_text) && input_text){ + let row = ORIGINAL_DATA.get(input_text) + text.textContent = `${input_text}\t${row.slice(1).join('\t')}` + } + }) + } let svg_width = svg.getBoundingClientRect().width; let svg_height = svg.getBoundingClientRect().height; //extract SVG element @@ -2384,11 +2419,6 @@ downloadLink.click(); downloadLink.remove(); } - - - - - } tree_full_screen_mode = function(){ From 68234ff98f2b2a195071709e4330f8de509975d5 Mon Sep 17 00:00:00 2001 From: Matthew Wells Date: Thu, 12 Sep 2024 16:02:48 -0500 Subject: [PATCH 2/7] svg export is looking better, png export started --- html/table.html | 47 ++++++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/html/table.html b/html/table.html index 4aa5c60..b49301a 100644 --- a/html/table.html +++ b/html/table.html @@ -114,7 +114,7 @@ const TREE = __DEADBEEF__; // the '= __DEADFOOD__' is an expression to find and replace and inline tsv string e.g. 'head1\thead2\nv1\tv2\n' const DATA = __DEADFOOD__; - const DEBUG = false; + const DEBUG = true; const TREE_OFFSET = 100; var NEWICK = null; var tree_root = null; @@ -2335,27 +2335,25 @@ let input_text = text.textContent if(ORIGINAL_DATA.has(input_text) && input_text){ let row = ORIGINAL_DATA.get(input_text) - let new_label = `${input_text}\t${row.slice(1).join('\t')}` + let new_label = `${input_text}\t${row.slice(1, -1).join('\t')}` text.textContent = new_label - if(new_label.length > longest_label){ - longest_label = new_label.length; + let text_length = new_label.length; + if(text_length > longest_label){ + longest_label = text_length; } } }) } - + svg.style.overflow = "visible" const tree_svg = svg.querySelector("#TreeSVG"); tree_svg.style.overflow = "visible" - - const offset_safety_factor = 20; - let bbox = tree_svg.getBBox() - //tree_svg.setAttribute("width", bbox.x + bbox.width + bbox.x + longest_label); - //tree_svg.style.marginLeft = legend_width + offset_safety_factor; - //tree_svg.style.width = tree_svg.style.width + longest_label - - tree_svg.setAttribute("width", bbox.x + bbox.width + bbox.x + longest_label); - tree_svg.setAttribute("height", bbox.y + bbox.height + bbox.y); - //tree_svg.setAttribute("viewBox", `${bbox.x} ${bbox.y} ${bbox.width} ${bbox.height}`); + tree_svg.style.paddingLeft = "4em" + tree_svg.style.height = "auto" + tree_svg.style.width = "auto" + tree_svg.width = tree_svg.width.baseVal.value + (longest_label*4); + const attr = tree_svg.getAttributeNode("height") + tree_svg.removeAttributeNode(attr); + tree_svg.setAttribute("viewBox", `${0} -${tree_svg.viewBox.baseVal.height} ${tree_svg.width.baseVal.value + (longest_label*4)} ${tree_svg.viewBox.baseVal.height + (longest_label*4)}`); const serializer = new window.XMLSerializer; const xml_string = serializer.serializeToString(svg); @@ -2377,21 +2375,34 @@ /*Adapted from https://gist.github.com/tatsuyasusukida/1261585e3422da5645a1cbb9cf8813d6 and https://zooper.pages.dev/articles/how-to-convert-a-svg-to-png-using-canvas*/ export_tree_to_png = function(){ - let svg = document.getElementById("TreeSVG") + let svg_ = document.getElementById("TreeSVG"); + svg = svg_.cloneNode(true); + + // SVG value needs to be in DOM to be rendered in the canvas, but we also need ta copy to update the text attributes in the tree + svg.style.zIndex = '-1'; + document.getElementById("TreeData").appendChild(svg); let leaves = svg.querySelectorAll(".leaf-node") + let longest_label = 10 if(ORIGINAL_DATA){ leaves.forEach((ele) => { let [element, circle, text] = SelectedNodes.getNodeData(ele) let input_text = text.textContent if(ORIGINAL_DATA.has(input_text) && input_text){ let row = ORIGINAL_DATA.get(input_text) - text.textContent = `${input_text}\t${row.slice(1).join('\t')}` + let new_label = `${input_text}\t${row.slice(1, -1).join('\t')}` + text.textContent = new_label + let text_length = new_label.length; + if(text_length > longest_label){ + longest_label = text_length; + } } }) } + let svg_width = svg.getBoundingClientRect().width; let svg_height = svg.getBoundingClientRect().height; + //extract SVG element const svgData = new XMLSerializer().serializeToString(svg); @@ -2418,6 +2429,8 @@ downloadLink.href = pngUrl; downloadLink.click(); downloadLink.remove(); + canvas.remove(); + svg.remove(); } } From 05832288dbc1a459c518e41e12ea84491ed91b73 Mon Sep 17 00:00:00 2001 From: Matthew Wells Date: Thu, 12 Sep 2024 16:04:11 -0500 Subject: [PATCH 3/7] added png export option only if metadata is to be exported --- html/table.html | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/html/table.html b/html/table.html index b49301a..7181c63 100644 --- a/html/table.html +++ b/html/table.html @@ -2375,16 +2375,17 @@ /*Adapted from https://gist.github.com/tatsuyasusukida/1261585e3422da5645a1cbb9cf8813d6 and https://zooper.pages.dev/articles/how-to-convert-a-svg-to-png-using-canvas*/ export_tree_to_png = function(){ - let svg_ = document.getElementById("TreeSVG"); - svg = svg_.cloneNode(true); - - // SVG value needs to be in DOM to be rendered in the canvas, but we also need ta copy to update the text attributes in the tree - svg.style.zIndex = '-1'; - document.getElementById("TreeData").appendChild(svg); + let svg = document.getElementById("TreeSVG"); + let leaves = svg.querySelectorAll(".leaf-node") let longest_label = 10 if(ORIGINAL_DATA){ + // SVG value needs to be in DOM to be rendered in the canvas, but we also need ta copy to update the text attributes in the tree + // Copies are only needed if metadata is included as well + svg = svg.cloneNode(true); + svg.style.zIndex = '-1'; + document.getElementById("TreeData").appendChild(svg); leaves.forEach((ele) => { let [element, circle, text] = SelectedNodes.getNodeData(ele) let input_text = text.textContent From 306ed256c8bd187fbaa1935d0f16c32ffb2e2b84 Mon Sep 17 00:00:00 2001 From: Matthew Wells Date: Thu, 12 Sep 2024 16:20:05 -0500 Subject: [PATCH 4/7] updated logic for adding table labels --- html/table.html | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/html/table.html b/html/table.html index 7181c63..cd40beb 100644 --- a/html/table.html +++ b/html/table.html @@ -2327,9 +2327,10 @@ css_export.appendChild(link_style_sheet); svg.insertBefore(css_export, svg.firstChild); - let leaves = svg.querySelectorAll(".leaf-node") + let longest_label = 10 if(ORIGINAL_DATA){ + let leaves = svg.querySelectorAll(".leaf-node") leaves.forEach((ele) => { let [element, circle, text] = SelectedNodes.getNodeData(ele) let input_text = text.textContent @@ -2376,21 +2377,22 @@ /*Adapted from https://gist.github.com/tatsuyasusukida/1261585e3422da5645a1cbb9cf8813d6 and https://zooper.pages.dev/articles/how-to-convert-a-svg-to-png-using-canvas*/ export_tree_to_png = function(){ let svg = document.getElementById("TreeSVG"); - - - let leaves = svg.querySelectorAll(".leaf-node") - let longest_label = 10 + let remove_svg = false; if(ORIGINAL_DATA){ // SVG value needs to be in DOM to be rendered in the canvas, but we also need ta copy to update the text attributes in the tree // Copies are only needed if metadata is included as well + let leaves = svg.querySelectorAll(".leaf-node") + let longest_label = 10 svg = svg.cloneNode(true); svg.style.zIndex = '-1'; document.getElementById("TreeData").appendChild(svg); + remove_svg = true; leaves.forEach((ele) => { let [element, circle, text] = SelectedNodes.getNodeData(ele) let input_text = text.textContent if(ORIGINAL_DATA.has(input_text) && input_text){ let row = ORIGINAL_DATA.get(input_text) + // End is not included in the slice, as it is simply a bool added on the program to track changed values let new_label = `${input_text}\t${row.slice(1, -1).join('\t')}` text.textContent = new_label let text_length = new_label.length; @@ -2431,7 +2433,7 @@ downloadLink.click(); downloadLink.remove(); canvas.remove(); - svg.remove(); + if(remove_svg) svg.remove(); } } From fd4955eadebfa48cb1d3b2c563d07a512e2c5777 Mon Sep 17 00:00:00 2001 From: Matthew Wells Date: Fri, 13 Sep 2024 10:38:38 -0500 Subject: [PATCH 5/7] updated png export, getting help to do this properly however --- html/table.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/html/table.html b/html/table.html index cd40beb..b8ee4cd 100644 --- a/html/table.html +++ b/html/table.html @@ -2379,7 +2379,9 @@ let svg = document.getElementById("TreeSVG"); let remove_svg = false; if(ORIGINAL_DATA){ - // SVG value needs to be in DOM to be rendered in the canvas, but we also need ta copy to update the text attributes in the tree + // SVG value needs to be in DOM to be rendered in the canvas, + // but we also need ta copy to update the text attributes in the tree + // or else the displayed tree is modified // Copies are only needed if metadata is included as well let leaves = svg.querySelectorAll(".leaf-node") let longest_label = 10 From 7bf7d1d0b86440e4f910087d7590abaa49c6cd63 Mon Sep 17 00:00:00 2001 From: Matthew Wells Date: Tue, 9 Dec 2025 15:25:13 -0600 Subject: [PATCH 6/7] fixed mis-sized svg export --- html/table.html | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/html/table.html b/html/table.html index b0be7df..94ae9f4 100644 --- a/html/table.html +++ b/html/table.html @@ -1679,7 +1679,7 @@ class SelectedNodes { static nodes = new Map(); static #circle_pos = 1; - static #name_pos = 3; + static #name_pos = 0; static #circle_size_selected = LEAF_NODE_SIZE * 1.5; static #circle_size_default = LEAF_NODE_SIZE; static #default_color = "#999"; @@ -3563,7 +3563,7 @@ let leaves = svg.querySelectorAll(".leaf-node") leaves.forEach((ele) => { let [element, circle, text] = SelectedNodes.getNodeData(ele) - let input_text = text.textContent + let input_text = text.textContent; if(ORIGINAL_DATA.has(input_text) && input_text){ let row = ORIGINAL_DATA.get(input_text) let new_label = `${input_text}\t${row.slice(1, -1).join('\t')}` @@ -3597,6 +3597,7 @@ let downloadLink = document.createElement("a"); downloadLink.download = 'tree_snapshot_'+date.getDate()+'-'+ (date.getMonth()+1)+'-'+date.getFullYear()+'_'+date.getHours()+'h.svg'; + let svg = document.getElementById("TreeData").cloneNode(true) //remove duplicated leaf nodes text duplication for more accurate searches svg.querySelectorAll('g .tree-node').forEach(node => { @@ -3605,8 +3606,15 @@ text_nodes_leafs[0].remove() } }) - svg.querySelector("#TreeSVG").style.overflow = "visible" - const blob = serialize2svg(svg)[0]; + + const tree_svg = svg.querySelector("#TreeSVG"); + const [minX, minY, width, height] = tree_svg.getAttribute("viewBox").split(/[\s,]+/).map(Number); + svg.style.height = `${height*1.15}px` + svg.style.width = `${width*1.05}px` + + svg.style.overflow = "visible"; + + const blob = serialize2svg(svg)[0]; downloadLink.href = window.URL.createObjectURL(blob); downloadLink.click(); //Trigger a click on the element downloadLink.remove(); @@ -3614,7 +3622,7 @@ /*Adapted from https://gist.github.com/tatsuyasusukida/1261585e3422da5645a1cbb9cf8813d6 and https://zooper.pages.dev/articles/how-to-convert-a-svg-to-png-using-canvas*/ export_tree_to_png = function(){ - let svg = document.getElementById("TreeSVG"); + let svg = document.getElementById("TreeSVG").cloneNode(true); let remove_svg = false; if(ORIGINAL_DATA){ // SVG value needs to be in DOM to be rendered in the canvas, @@ -3629,7 +3637,7 @@ remove_svg = true; leaves.forEach((ele) => { let [element, circle, text] = SelectedNodes.getNodeData(ele) - let input_text = text.textContent + let input_text = text.textContent; if(ORIGINAL_DATA.has(input_text) && input_text){ let row = ORIGINAL_DATA.get(input_text) // End is not included in the slice, as it is simply a bool added on the program to track changed values @@ -3642,9 +3650,11 @@ } }) } - - let svg_width = svg.getBoundingClientRect().width; - let svg_height = svg.getBoundingClientRect().height; + // Get the view box required for setting the correct output size + const viewbox = svg.getAttribute("viewBox"); + const [minX, minY, width, height] = viewbox.split(/[\s,]+/).map(Number); + let svg_width = width; + let svg_height = height; //extract SVG element const svgData = new XMLSerializer().serializeToString(svg); From 03600df6912ac13d806ad35bb41e53d042bc19d1 Mon Sep 17 00:00:00 2001 From: Matthew Wells Date: Tue, 6 Jan 2026 13:42:09 -0600 Subject: [PATCH 7/7] turned off debug --- html/table.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/html/table.html b/html/table.html index 94ae9f4..28afd1a 100644 --- a/html/table.html +++ b/html/table.html @@ -200,7 +200,7 @@ const TREE = __DEADBEEF__; // the '= __DEADFOOD__' is an expression to find and replace and inline tsv string e.g. 'head1\thead2\nv1\tv2\n's const DATA = __DEADFOOD__; - const DEBUG = true; + const DEBUG = false; const TREE_OFFSET = 100; var METDATA_TABLE_NON_FULL_SCREEEN_HEIGTH = null; //before changing to full screen mode save the current size of the metadata table var NEWICK = null;