46169b41deecd48121198e1911c41dc0a3f96b47
chmalee
  Tue Jan 19 18:12:04 2021 -0800
Allow variable size data tables on hgc. Allow these tables to be JSON or
pipe and semi-colon encoded. Add more support for external data
references in bigBeds: allow relevant trackDb settings like
skipEmptyFields, allow variable size tables in external files, allow
gzip compressed external files.

diff --git src/hg/js/hgc.js src/hg/js/hgc.js
new file mode 100644
index 0000000..64df3d1
--- /dev/null
+++ src/hg/js/hgc.js
@@ -0,0 +1,168 @@
+// "use strict";
+
+// insert a node after the reference node
+function insertAfter(newNode, referenceNode) {
+    referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
+}
+
+// a generic table with no headers or sortable rows:
+function makeGenericTable(data) {
+    var table = document.createElement("table");
+    table.classList.add("jsonTable");
+    var val, i, j;
+    var keys = Object.keys(data);
+    for (i = 0; i < keys.length; i++) {
+        key = keys[i];
+        val = data[key];
+        var row = table.insertRow();
+        if (Array.isArray(val)) {
+            for (j = 0; j < val.length; j++) {
+                cell = row.insertCell();
+                if (j < val.length) {
+                    cell.appendChild(document.createTextNode(val[j]));
+                } else {
+                    cell.appendChild(document.createTextNode(""));
+                }
+            }
+        } else {
+            var rowLabel = document.createTextNode(key);
+            var labelCell = row.insertCell();
+            var cell;
+            labelCell.appendChild(rowLabel);
+
+            if (typeof(val) == "object" && !Array.isArray(val)) {
+                cell = row.insertCell();
+                cell.appendChild(makeGenericTable(val));
+            } else {
+                if (val === null) {
+                    cell = row.insertCell();
+                    cell.appendChild(document.createTextNode(""));
+                } else {
+                    cell = row.insertCell();
+                    cell.appendChild(document.createTextNode(val));
+                }
+            }
+        }
+    }
+    return table;
+}
+
+// make the vep table, which is limited to 2x2 for the vep fields
+function makeVepTable(data) {
+    var table = document.createElement("table");
+    table.classList.add("jsonTable");
+    var gene;
+    for (gene in data) {
+        var geneRow = table.insertRow();
+        var newLabel = document.createTextNode(gene);
+        var labelCell = geneRow.insertCell();
+        labelCell.appendChild(newLabel);
+
+        // a 2x2 sub table for the vep info:
+        var subTable = document.createElement("table");
+        subTable.classList.add("jsonTable");
+        var annot;
+        for (annot in data[gene]) {
+            var annotRow = subTable.insertRow();
+            var annotLabel = document.createTextNode(annot);
+            var annotCell = annotRow.insertCell();
+            annotCell.appendChild(annotLabel);
+            annotCell = annotRow.insertCell();
+            var dataLabel = document.createTextNode(data[gene][annot].join(", "));
+            annotCell.appendChild(dataLabel);
+        }
+        labelCell = geneRow.insertCell();
+        labelCell.appendChild(subTable);
+    }
+    return table;
+}
+
+// make the pop frequencies or haplotype frequencies table
+function makePopTable(data) {
+    var table = document.createElement("table");
+    table.classList.add("jsonTable");
+    var pop;
+    var thead, tfoot, tbody;
+    for (pop in data) {
+        if (pop === "Populations" || pop === "Haplogroup") {
+            thead = table.createTHead();
+            theadRow = thead.insertRow();
+            th = theadRow.insertCell();
+            th.appendChild(document.createTextNode(pop));
+            var header;
+            for (header in data[pop]) {
+                th = theadRow.insertCell();
+                th.appendChild(document.createTextNode(data[pop][header]));
+            }
+        } else if (pop === "Total") {
+            tfoot = table.createTFoot();
+            tfootRow = tfoot.insertRow();
+            th = tfootRow.insertCell();
+            th.appendChild(document.createTextNode(pop));
+            var footer;
+            for (footer in data[pop]) {
+                th = tfootRow.insertCell();
+                th.appendChild(document.createTextNode(data[pop][footer]));
+            }
+        } else {
+            if (table.tBodies.length === 0) {
+                tbody = table.createTBody();
+            }
+            var popRow = tbody.insertRow();
+            var newLabel = document.createTextNode(pop);
+            var labelCell = popRow.insertCell();
+            labelCell.appendChild(newLabel);
+
+            // a 5x5 sub table for the population freqs or 6x6 for haplotypes:
+            var vals;
+            for (vals in data[pop]) {
+                var valsLabel = document.createTextNode(data[pop][vals]);
+                var valsCell = popRow.insertCell();
+                valsCell.appendChild(valsLabel);
+            }
+        }
+    }
+    return table;
+}
+
+// turn a json object into an html table
+function dataToTable(label, data) {
+    var subTable = document.createElement("table");
+    subTable.classList.add("jsonTable");
+    var subRow = subTable.insertRow();
+    var newTableNode;
+    if (label === "Variant Effect Predictor")
+        newTableNode  = makeVepTable(data);
+    else if (label === "Population Frequencies" || label === "Haplotype Frequencies")
+        newTableNode  = makePopTable(data);
+    else
+        newTableNode  = makeGenericTable(data);
+    return newTableNode ;
+}
+
+// on page load initialize VEP, Population Frequency and Haplotype Tables
+// for gnomAD v3.1.1 track
+$(document).ready(function() {
+    if (_jsonHgcLabels !== null) {
+        var obj, o;
+        for (obj in _jsonHgcLabels) {
+            // build up the new table:
+            var newTable = document.createElement("table");
+            var newRow = newTable.insertRow();
+            var newCell = newRow.insertCell();
+            var label = _jsonHgcLabels[obj].label;
+            var data = _jsonHgcLabels[obj].data;
+            var newText = document.createTextNode(label);
+            newCell.appendChild(newText);
+            newCell = newRow.insertCell();
+            newCell.appendChild(dataToTable(label, data));
+            // find the last details table and add a new table on:
+            var currTbl = $(".bedExtraTbl");
+            l = currTbl.length;
+            var last = currTbl[l-1];
+            insertAfter(newTable, last);
+            newTable.classList.add("bedExtraTbl");
+            last.parentNode.insertBefore(document.createElement("br"), newTable);
+        }
+    }
+});