5a34c495d5fe1db2aab6d1785c0b0239dbed2520
angie
  Sat Aug 16 21:21:02 2025 -0700
New track type lorax: details page embeds Lorax multi-tree viewer.
The trees are subtrees of an Ancestral Recombination Graph (ARG).
This commit also adds a track with 1000 Genomes data, tgpLorax.
The details page uses an iframe to embed the Lorax viewer from
a separate server (most likely will run in a docker container on
the GB server hosts; that will make this track more complicated for
mirror operators than other tracks).

diff --git src/hg/hgTracks/loraxTrack.c src/hg/hgTracks/loraxTrack.c
new file mode 100644
index 00000000000..970306b46d9
--- /dev/null
+++ src/hg/hgTracks/loraxTrack.c
@@ -0,0 +1,100 @@
+/* loraxTrack -- handlers for a track that interfaces with a local instance of the Lorax app. */
+/* See https://github.com/pratikkatte/lorax */
+
+/* Copyright (C) 2025 The Regents of the University of California
+ * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */
+
+#include "common.h"
+#include "bbiFile.h"
+#include "bed.h"
+#include "hgTracks.h"
+
+
+static void loraxLoadItems(struct track *tg)
+/* Load Lorax/tskit tree regions items in bigBed format */
+{
+struct lm *lm = lmInit(0);
+struct bbiFile *bbi = fetchBbiForTrack(tg);
+struct bigBedInterval *bb, *bbList = NULL;
+bbList = bigBedSelectRange(tg, chromName, winStart, winEnd, lm);
+char *bedRow[bbi->fieldCount];
+char startBuf[16], endBuf[16];
+struct bed *list = NULL;
+for (bb = bbList; bb != NULL; bb = bb->next)
+    {
+    bigBedIntervalToRow(bb, chromName, startBuf, endBuf, bedRow, ArraySize(bedRow));
+    struct bed *bed = bedLoad3(bedRow);
+    slAddHead(&list, bed);
+    }
+lmCleanup(&lm);
+slReverse(&list);
+tg->items = list;
+}
+
+
+static int loraxTotalHeight(struct track *tg, enum trackVisibility vis)
+/* Return configured height of track. */
+{
+return tg->lineHeight;
+}
+
+
+static void loraxDrawItems(struct track *tg, int seqStart, int seqEnd,
+                    struct hvGfx *hvg, int xOff, int yOff, int width,
+                    MgFont *font, Color color, enum trackVisibility vis)
+/* Draw Lorax/tskit tree regions. */
+{
+static boolean alreadyIncludedJs = FALSE;
+if (!alreadyIncludedJs)
+    {
+    jsIncludeFile("lorax.js", NULL);
+    alreadyIncludedJs = TRUE;
+    }
+double scale = scaleForWindow(width, seqStart, seqEnd);
+struct bed *bedList = tg->items, *bed;
+for (bed = bedList;  bed != NULL;  bed = bed->next)
+    {
+    int height = loraxTotalHeight(tg, vis);
+    int x1 = round((double)((int)bed->chromStart-winStart)*scale) + xOff;
+    int x2 = round((double)((int)bed->chromEnd-winStart)*scale) + xOff;
+    int y1 = yOff;
+    int y2 = yOff + height - 1;
+
+    // For now just draw an empty box.
+    hvGfxLine(hvg, x1, y1, x1, y2, color);
+    hvGfxLine(hvg, x2, y1, x2, y2, color);
+    hvGfxLine(hvg, x1, y1, x2, y1, color);
+    hvGfxLine(hvg, x1, y2, x2, y2, color);
+
+    // Make own map item here (tg->mapsSelf is TRUE)
+    genericMapItem(tg, hvg, bed, "", "", bed->chromStart, bed->chromEnd, x1, y1, (x2 - x1), height);
+    }
+}
+
+
+static void loraxDoLeftLabels(struct track *tg, int seqStart, int seqEnd, struct hvGfx *hvg,
+                              int xOff, int yOff, int width, int height, boolean withCenterLabels,
+                              MgFont *font, Color color, enum trackVisibility vis)
+/* For now, draw no left labels. */
+{
+return;
+}
+
+static void loraxFreeItems(struct track *tg)
+/* Free track items (bed list). */
+{
+bedFreeList((struct bed **)(tg->items));
+}
+
+
+void loraxMethods(struct track *tg)
+/* Lorax track type methods */
+{
+tg->loadItems = loraxLoadItems;
+tg->drawItems = loraxDrawItems;
+tg->totalHeight = loraxTotalHeight;
+tg->drawLeftLabels = loraxDoLeftLabels;
+tg->mapsSelf = TRUE;
+tg->freeItems = loraxFreeItems;
+tg->mapsSelf = 1;
+}