import {
  axisstyle,
  bulk_badline,
  font,
  make_table_2col,
  newpane,
  newpane3,
  renderSandboxFormDiv,
  sayerror,
  to_svg
} from "./chunk-SA7APTJR.js";
import "./chunk-HJ6L54YS.js";
import "./chunk-LSEFWW72.js";
import "./chunk-SKREEF3H.js";
import {
  Menu
} from "./chunk-HYOEWQ5P.js";
import "./chunk-HBW42TDT.js";
import "./chunk-G6O3URDN.js";
import "./chunk-FN5XPUPH.js";
import "./chunk-IIT367QZ.js";
import "./chunk-RZGEKL77.js";
import "./chunk-UI7OCM2A.js";
import "./chunk-YZK37YCC.js";
import "./chunk-7EMWHCVW.js";
import "./chunk-7IYJZZQI.js";
import "./chunk-M3J4MINX.js";
import "./chunk-PF4DSFDR.js";
import "./chunk-QH6W3NVF.js";
import "./chunk-NOEAT6CX.js";
import {
  mclass,
  mclassnonstandard
} from "./chunk-4UWS5Y3N.js";
import "./chunk-DD4R5P6W.js";
import "./chunk-JNITUVXP.js";
import {
  Symbol,
  circle_default,
  cross_default,
  diamond_default,
  square_default,
  star_default,
  triangle_default,
  wye_default
} from "./chunk-KSGA62R2.js";
import {
  axisBottom,
  axisLeft,
  axisTop
} from "./chunk-LOZEKOES.js";
import "./chunk-TOU7EVFQ.js";
import {
  format,
  linear
} from "./chunk-OAWQ6LOO.js";
import "./chunk-TLT4YIG3.js";
import "./chunk-KYBIQBXE.js";
import {
  select_default
} from "./chunk-I6Y4O3RR.js";
import "./chunk-OMR2DT66.js";
import "./chunk-DQC5FFGV.js";
import "./chunk-HFNDKYVF.js";

// src/2dmaf.anchors.js
var Anchors = class {
  constructor(opts) {
    this.opts = opts;
    this.anchorType = opts.anchorType;
    this.shareheight = opts.shareheight;
    this.sharewidth = opts.sharewidth;
    const x = "x" in opts ? opts.x : 0;
    const y = "y" in opts ? opts.y : 0;
    this.settings = {
      visible: true,
      opacity: 0.3,
      x,
      y,
      xOffset: opts.axiswidth + opts.sp + opts.sample2height,
      yOffset: opts.shareheight,
      currX: opts.axiswidth + opts.sp + opts.sample2height + x,
      currY: opts.shareheight - y,
      strokeWidth: "strokeWidth" in opts ? opts.strokeWidth : 5,
      stroke: "stroke" in opts ? opts.stroke : "red",
      xarmlen: "xarmlen" in opts ? opts.xarmlen : 25
    };
    this.addControls(this.anchorType ? null : this.opts.headerdiv);
  }
  setWrapper(g) {
    this.opts.wrapper = g;
  }
  addControls(headerdiv = null) {
    if (headerdiv) {
      const anchorbtn = headerdiv.append("button").text("Anchors").on("click", (event) => {
        this.anchormenu.showunder(event.target);
        this.xInput.property("value", (this.settings.x / this.sharewidth).toFixed(2));
        this.yInput.property("value", (this.settings.y / this.sharewidth).toFixed(2));
      });
    }
    this.anchormenu = new Menu({ border: "solid 1px black" });
    this.anchormenu.d.style("text-align", "center");
    this.addCoordInput();
    this.addColorInput();
    this.addOpacityInput();
    if (!this.anchorType) this.addSubmitBtns();
    else this.addDeleteBtn();
  }
  addColorInput() {
    const div = this.anchormenu.d.append("div");
    div.append("label").html("Color:&nbsp;");
    this.strokeInput = div.append("input");
    this.strokeInput.attr("this.anchorType", "text").property("value", this.settings.stroke).style("width", "50px");
  }
  addOpacityInput() {
    const div = this.anchormenu.d.append("div");
    div.append("label").html("Opacity:&nbsp;");
    this.opacityInput = div.append("input");
    this.opacityInput.attr("this.anchorType", "number").attr("min", 0).attr("max", 1).attr("step", 0.01).property("value", this.settings.opacity).style("width", "50px");
  }
  addSubmitBtns() {
    if (this.anchorType) return;
    const div = this.anchormenu.d.append("div");
    div.append("label").html("Add Anchor: ");
    div.append("button").html("R").on("click", () => {
      new SyncedAnchors(this.getSettings("r"));
      this.anchormenu.hide();
    });
    div.append("button").html("D").on("click", () => {
      new SyncedAnchors(this.getSettings("d"));
      this.anchormenu.hide();
    });
    div.append("button").html("X").on("click", () => {
      new SyncedAnchors(this.getSettings("x"));
      this.anchormenu.hide();
    });
    div.append("button").html("synced").on("click", () => {
      new SyncedAnchors(this.getSettings("synced"));
      this.anchormenu.hide();
    });
  }
  getSettings(anchorType) {
    return Object.assign({}, this.opts, {
      anchorType,
      opacity: this.opacityInput.property("value"),
      x: this.xInput.property("value") * this.sharewidth,
      y: this.yInput.property("value") * this.shareheight,
      stroke: this.strokeInput.property("value")
    });
  }
  addCoordInput() {
    const xdiv = this.anchormenu.d.append("div");
    xdiv.append("label").html("X:&nbsp;");
    this.xInput = xdiv.append("input");
    this.xInput.attr("this.anchorType", "number").attr("min", 0).attr("max", 1).attr("step", 0.01).property("value", 0).style("width", "80px");
    const ydiv = this.anchormenu.d.append("div");
    ydiv.append("label").html("Y:&nbsp;");
    this.yInput = ydiv.append("input");
    this.yInput.attr("this.anchorType", "number").attr("min", 0).attr("max", 1).attr("step", 0.01).property("value", 0).style("width", "80px");
  }
  addDeleteBtn() {
    if (!this.anchorType) return;
    const div = this.anchormenu.d.append("div");
    div.append("button").html("Delete").on("click", () => {
      this.g_anchor.remove();
      this.anchormenu.hide();
    });
  }
};
var SyncedAnchors = class extends Anchors {
  constructor(opts) {
    super(opts);
    this.render();
    this.strokeInput.on("change", () => {
      this.settings.stroke = this.strokeInput.property("value");
      this.g_anchor.style("stroke", this.settings.stroke);
      this.anchormenu.hide();
    });
    this.opacityInput.on("change", () => {
      this.settings.opacity = input.property("value");
      this.g_anchor.style("opacity", this.settings.opacity);
      this.anchormenu.hide();
    });
    this.xInput.on("change", () => {
      this.settings.x = +this.xInput.property("value") * this.sharewidth;
      this.settings.currX = this.settings.x + this.settings.xOffset;
      if (this.d_anchor) {
        this.d_anchor.transition().duration(1e3).attr("x1", this.settings.currX).attr("x2", this.settings.currX);
      }
      if (this.x_anchor) {
        this.x_anchor.transition().duration(1e3).attr("transform", "translate(" + this.settings.currX + "," + this.settings.currY + ")");
      }
      this.anchormenu.hide();
    });
    this.yInput.on("change", () => {
      this.settings.y = +this.yInput.property("value") * this.shareheight;
      this.settings.currY = -this.settings.y + this.settings.yOffset;
      if (this.r_anchor) {
        this.r_anchor.transition().duration(1e3).attr("y1", this.settings.currY).attr("y2", this.settings.currY);
      }
      if (this.x_anchor) {
        this.x_anchor.transition().duration(1e3).attr("transform", "translate(" + this.settings.currX + "," + this.settings.currY + ")");
      }
      this.anchormenu.hide();
    });
  }
  render() {
    this.g_anchor = this.opts.wrapper.append("g").style("stroke", this.settings.stroke).style("opacity", this.settings.opacity).style("display", this.settings.visible ? "" : "none").style("stroke-width", this.settings.strokeWidth).on(
      "click",
      this.anchorType == "synced" ? null : (event) => {
        this.anchormenu.showunder(event.target);
      }
    );
    this.renderD();
    this.renderR();
    this.renderX();
  }
  renderD() {
    if (!["synced", "d"].includes(this.anchorType)) return;
    this.d_anchor = this.g_anchor.append("line");
    const o = this.opts;
    this.updateD(o.shareheight + o.sp2, o.shareheight + o.sample1height);
  }
  updateD(y1, y2) {
    if (!["synced", "d"].includes(this.anchorType)) return;
    this.settings.D = { y1, y2 };
    this.d_anchor.attr("x1", this.settings.currX).attr("x2", this.settings.currX).attr("y1", y1).attr("y2", y2);
  }
  renderR() {
    if (!["synced", "r"].includes(this.anchorType)) return;
    this.r_anchor = this.g_anchor.append("line");
    const o = this.opts;
    this.updateR(o.axiswidth + o.sp, o.sample2height + o.sp);
  }
  updateR(x1, x2) {
    if (!["synced", "r"].includes(this.anchorType)) return;
    this.settings.R = { x1, x2 };
    this.r_anchor.attr("x1", x1).attr("x2", x2).attr("y1", this.settings.currY).attr("y2", this.settings.currY);
  }
  renderX() {
    if (!["synced", "x"].includes(this.anchorType)) return;
    this.x_anchor = this.g_anchor.append("g").attr("transform", "translate(" + this.settings.currX + "," + this.settings.currY + ")");
    this.bindXDrag();
    this.x_anchor.append("circle").attr("cx", 0).attr("cy", 0).attr("r", this.settings.xarmlen).style("opacity", 0);
    this.x_anchor.append("line").attr("x1", -this.settings.xarmlen).attr("x2", this.settings.xarmlen).attr("y1", 0).attr("y2", 0);
    this.x_anchor.append("line").attr("x1", 0).attr("x2", 0).attr("y1", this.settings.xarmlen).attr("y2", -this.settings.xarmlen);
  }
  bindXDrag() {
    if (!["synced"].includes(this.anchorType)) return;
    this.x_anchor.on("mousedown", (event) => {
      const x = event.clientX;
      const y = event.clientY;
      let _x = this.settings.currX, _y = this.settings.currY;
      this.x_anchor.on("mousemove", (event2) => {
        _x = this.settings.currX - x + event2.clientX;
        _y = this.settings.currY - y + event2.clientY;
        this.r_anchor.attr("y1", _y).attr("y2", _y);
        this.d_anchor.attr("x1", _x).attr("x2", _x);
        this.x_anchor.attr("transform", "translate(" + _x + "," + _y + ")");
      }).on("mouseup", (event2) => {
        this.x_anchor.on("mousemove", null);
        _x = this.settings.currX - x + event2.clientX;
        _y = this.settings.currY - y + event2.clientY;
        if (_x == this.settings.currX && _y == this.settings.currY) {
          this.g_anchor.remove();
          return;
        }
        this.settings.x = _x < this.settings.xOffset ? 0 : _x - this.settings.xOffset;
        this.settings.y = _y > this.settings.yOffset ? 0 : -(_y - this.settings.yOffset);
        this.settings.currX = this.settings.x + this.settings.xOffset;
        this.settings.currY = -this.settings.y + this.settings.yOffset;
        this.r_anchor.transition().duration(100).attr("y1", this.settings.currY).attr("y2", this.settings.currY);
        this.d_anchor.transition().duration(100).attr("x1", this.settings.currX).attr("x2", this.settings.currX);
        this.x_anchor.transition().duration(100).attr("transform", "translate(" + this.settings.currX + "," + this.settings.currY + ")");
      }).on("mouseleave", () => {
        this.x_anchor.on("mousemove", null);
      });
    });
  }
};

// src/2dmaf.js
var color1 = "#f9766c";
var color2 = "#609cff";
var colorshare = "#01b937";
var symbols = {
  circle: circle_default,
  cross: cross_default,
  diamond: diamond_default,
  square: square_default,
  star: star_default,
  triangle: triangle_default,
  wye: wye_default
};
var symbolFilters = {
  path: (d) => d.symbol,
  circle: (d) => !d.symbol
};
var sharedFilters = {
  path: (d) => d.symbol,
  ellipse: (d) => !d.symbol
};
function d2mafui(genomes, holder) {
  let pane, inputdiv, gselect, filediv, saydiv, visualdiv;
  if (holder !== void 0) [inputdiv, gselect, filediv, saydiv, visualdiv] = renderSandboxFormDiv(holder, genomes);
  else {
    ;
    [pane, inputdiv, gselect, filediv, saydiv, visualdiv] = newpane3(100, 100, genomes);
    pane.header.text("2DMAF: mutant allele fraction plot between a pair of samples");
    pane.body.style("margin", "10px");
  }
  inputdiv.append("div").style("margin-top", "20px").html(
    '<ul><li><a href="https://docs.google.com/document/d/1anyEDMcW1lTSf8399Li2G9r57V-Fqp2591WvoODY7n4/edit#heading=h.mne2ecmp9m13" target=_blank>File format</a></li><li>To define samples differently than "Diagnosis/Relapse", <a href=https://plus.google.com/+XinZhou_s/posts/WqBVvmd3wYR target=_blank>see how</a>.</li></ul>'
  );
  inputdiv.append("p").html("<a href=https://proteinpaint.stjude.org/ppdemo/hg19/2dmaf/2dmaf.txt target=_blank>Example file</a>");
  function cmt(t, red) {
    saydiv.style("color", red ? "red" : "black").html(t);
  }
  const fileui = () => {
    filediv.selectAll("*").remove();
    const input2 = filediv.append("input").attr("type", "file").on("change", (event) => {
      const file = event.target.files[0];
      if (!file) {
        fileui();
        return;
      }
      if (!file.size) {
        cmt("Invalid file " + file.name);
        fileui();
        return;
      }
      const reader = new FileReader();
      reader.onload = (event2) => {
        const usegenome = gselect.options[gselect.selectedIndex].innerHTML;
        const err = parseraw(event2.target.result.trim().split(/\r?\n/), genomes[usegenome], file.name, visualdiv);
        if (err) {
          cmt(err, 1);
          fileui();
          return;
        }
        inputdiv.remove();
        filediv.remove();
        saydiv.remove();
      };
      reader.onerror = function() {
        cmt("Error reading file " + file.name, 1);
        fileui();
        return;
      };
      reader.readAsText(file, "utf8");
    });
    setTimeout(() => input2.node().focus(), 1100);
  };
  fileui();
}
function d2mafparseinput(obj, holder) {
  if (!obj.genome) {
    sayerror(holder, ".genome missing for 2dmaf");
    return;
  }
  if (!obj.input) {
    sayerror(holder, ".input missing for 2dmaf");
    return;
  }
  const err = parseraw(obj.input.trim().split(/\r?\n/), obj.genome, obj.datasetname || "unnamed dataset", holder);
  if (err) {
    sayerror(holder, "2DMAF data error: " + err);
  }
}
function parseraw(lines, genome, filename, holder) {
  const [headererror, header, headerattrlst] = parseheader(lines[0].trim());
  if (headererror) {
    return headererror;
  }
  const pairs = {};
  const g2mlst = {};
  const peoplehash = {};
  const genehash = {};
  const flag = {
    good: 0,
    purity1set: false,
    purity2set: false,
    pairsetname: {}
  };
  const badlines = [];
  const mclasslabel2key = {};
  for (const k in mclass) {
    mclasslabel2key[mclass[k].label.toUpperCase()] = k;
  }
  for (let i = 1; i < lines.length; i++) {
    if (lines[i] == "") continue;
    if (lines[i][0] == "#") {
      if (lines[i].startsWith("##samplename")) {
        const l = lines[i].trim().split(/[\s\t]+/);
        if (l.length == 4) {
          flag.pairsetname[l[1]] = { 1: l[2], 2: l[3] };
        } else {
          return "Line " + (i + 1) + ': invalid samplename line: must be "##samplename [patient] [sample1] [sample2]"';
        }
      }
      continue;
    }
    const lst = lines[i].trim().split("	");
    const m = {};
    for (let j = 0; j < header.length; j++) {
      if (lst[j] != void 0 && lst[j] != "") {
        m[header[j]] = lst[j];
      }
    }
    if (!m.sample) {
      return "Line " + (i + 1) + ": missing sample";
    }
    if (m.chr) {
      if (m.chr.indexOf("chr") != 0) {
        m.chr = "chr" + m.chr;
      }
    }
    if (m.chrstart) {
      m.chrstart = Number.parseInt(m.chrstart);
      if (Number.isNaN(m.chrstart)) {
        return "Line " + (i + 1) + ": invalid chromosome position";
      }
    }
    if (m.Dcnvloh) {
      m.Dcnvlohraw = m.Dcnvloh;
      const s2 = m.Dcnvloh.toLowerCase();
      if (s2 == "yes" || s2 != "diploid" && s2 != "haploid") {
        m.Dcnvloh = true;
      } else {
        m.Dcnvloh = false;
      }
    }
    if (m.Rcnvloh) {
      m.Rcnvlohraw = m.Rcnvloh;
      const s2 = m.Rcnvloh.toLowerCase();
      if (s2 == "yes" || s2 != "diploid" && s2 != "haploid") {
        m.Rcnvloh = true;
      } else {
        m.Rcnvloh = false;
      }
    }
    if (!m.call_d) {
      badlines.push([i, "missing call_d", lst]);
      continue;
    }
    if (m.call_d != "somatic" && m.call_d != "wildtype") {
      badlines.push([i, "call_d is neither somatic nor wildtype", lst]);
      continue;
    }
    if (!m.call_r) {
      badlines.push([i, "missing call_r", lst]);
      continue;
    }
    if (m.call_r != "somatic" && m.call_r != "wildtype") {
      badlines.push([i, "call_r is neither somatic nor wildtype", lst]);
      continue;
    }
    if (m.call_d == "somatic") {
      if (m.call_r == "somatic") {
        m.set_share = true;
      } else {
        m.set_1 = true;
      }
    } else {
      if (m.call_r == "somatic") {
        m.set_2 = true;
      }
    }
    if (!m.type) {
      badlines.push([i, "missing type", lst]);
      continue;
    }
    const s = m.type.toLowerCase();
    if (s == "snv" || s == "snp" || s == "mnv" || s == "complex") {
      m.issnv = true;
    } else if (s == "indel" || s == "ins" || s == "del") {
      m.isindel = true;
    } else {
      badlines.push([i, "type must be either SNV or INDEL", lst]);
      continue;
    }
    let key = "MinD.D";
    let a = Number.parseInt(m[key]);
    if (Number.isNaN(a) || a < 0) {
      badlines.push([i, "invalid " + key + " value", lst]);
      continue;
    }
    m[key] = a;
    key = "TinD.D";
    a = Number.parseInt(m[key]);
    if (Number.isNaN(a) || a < 0) {
      badlines.push([i, "invalid " + key + " value", lst]);
      continue;
    }
    m[key] = a;
    if (m["TinD.D"] < m["MinD.D"]) {
      badlines.push([i, "TinD.D value lower than MinD.D", lst]);
      continue;
    }
    key = "MinN.D";
    if (key in m) {
      a = Number.parseInt(m[key]);
      if (Number.isNaN(a) || a < 0) {
        delete m[key];
      } else {
        m[key] = a;
      }
    }
    key = "TinN.D";
    if (key in m) {
      a = Number.parseInt(m[key]);
      if (Number.isNaN(a) || a < 0) {
        delete m[key];
      } else {
        m[key] = a;
      }
    }
    key = "MinD.R";
    a = Number.parseInt(m[key]);
    if (Number.isNaN(a) || a < 0) {
      badlines.push([i, "invalid " + key + " value", lst]);
      continue;
    }
    m[key] = a;
    key = "TinD.R";
    a = Number.parseInt(m[key]);
    if (Number.isNaN(a) || a < 0) {
      badlines.push([i, "invalid " + key + " value", lst]);
      continue;
    }
    m[key] = a;
    if (m["TinD.R"] < m["MinD.R"]) {
      badlines.push([i, "TinD.R value lower than MinD.R", lst]);
      continue;
    }
    key = "MinN.R";
    if (key in m) {
      a = Number.parseInt(m[key]);
      if (Number.isNaN(a) || a < 0) {
        delete m[key];
      } else {
        m[key] = a;
      }
    }
    key = "TinN.R";
    if (key in m) {
      a = Number.parseInt(m[key]);
      if (Number.isNaN(a) || a < 0) {
        delete m[key];
      } else {
        m[key] = a;
      }
    }
    if (m.symbol) {
      if (!symbols[m.symbol]) {
        badlines.push([i, "Invalid symbol value='" + m.symbol + "'", lst]);
        continue;
      }
    }
    if (m.class) {
      const s2 = m.class.toUpperCase();
      if (s2 in mclasslabel2key) {
        m.class = mclasslabel2key[s2];
      } else {
        badlines.push([i, "invalid mutation class " + m.class, lst]);
        continue;
      }
    }
    m.style = {
      fill: m.issnv ? "white" : "black",
      fillhl: m.class ? mclass[m.class].color : "#ccc",
      stroke: m.chr == "chrX" ? "black" : m.issnv ? "black" : "none",
      strokehl: m.class ? mclass[m.class].color : "black",
      fillopacity: m.issnv ? 0 : 0.2,
      strokeopacity: 0.2
    };
    if (m["TinD.D"] > 0) {
      m.maf1 = m["MinD.D"] / m["TinD.D"];
    }
    if (m["TinD.R"] > 0) {
      m.maf2 = m["MinD.R"] / m["TinD.R"];
    }
    peoplehash[m.sample] = 1;
    if (m.gene) {
      genehash[m.gene] = 1;
    }
    if (!(m.sample in pairs)) {
      pairs[m.sample] = {
        name: m.sample,
        shown: false,
        header,
        mlst: []
      };
    }
    const v = pairs[m.sample];
    v.mlst.push(m);
    if (m.purity1) {
      let p = Number.parseFloat(m.purity1);
      if (Number.isNaN(p)) {
        badlines.push([i, "diagnosis tumor purity should be a number"]);
        p = 0;
      } else {
        if (p > 1) {
          p /= 100;
        }
      }
      if (p > 0) {
        if (v.purity1 == void 0) {
          v.purity1 = p;
          flag.purity1set = true;
        } else if (v.purity1 != p) {
          badlines.push([
            i,
            "diagnosis tumor purity value " + p + " is different from existing value " + v.purity1 + " in " + m.sample,
            lst
          ]);
        }
      }
    }
    if (m.purity2) {
      let p = Number.parseFloat(m.purity2);
      if (Number.isNaN(p)) {
        badlines.push([i, "relapse tumor purity should be a number"]);
        p = 0;
      } else {
        if (p > 1) {
          p /= 100;
        }
      }
      if (p > 0) {
        if (v.purity2 == void 0) {
          v.purity2 = p;
          flag.purity2set = true;
        } else if (v.purity2 != p) {
          badlines.push([
            i,
            "relapse tumor purity value " + p + " is different from existing value " + v.purity2 + " in " + m.sample,
            lst
          ]);
        }
      }
    }
    flag.good++;
  }
  if (badlines.length > 0) {
    bulk_badline(header, badlines);
  }
  if (flag.good == 0) {
    return "No valid data.";
  }
  holder.append("p").text("File: " + filename);
  let peopletotal = 0;
  for (const n in peoplehash) peopletotal++;
  let genetotal = 0;
  for (const n in genehash) genetotal++;
  const boxh = 16;
  const table = holder.append("table");
  const tr = table.append("tr");
  const td = tr.append("td").attr("valign", "top");
  td.append("div").html(
    '<div style="display:inline-block;width:' + boxh + "px;height:" + boxh + "px;background-color:" + color1 + '"></div> Diagnosis only <div style="display:inline-block;width:' + boxh + "px;height:" + boxh + "px;background-color:" + colorshare + '"></div> Shared <div style="display:inline-block;width:' + boxh + "px;height:" + boxh + "px;background-color:" + color2 + '"></div> Relapse only'
  );
  const peopleholder = td.append("div").style("margin-top", "10px").style("height", "200px").style("width", "300px").style("padding", "5px").style("overflow-y", "scroll").style("resize", "both").style("border", "solid 1px #ccc");
  const geneholder = td.append("div").style("margin-top", "10px").style("height", "200px").style("width", "300px").style("padding", "5px").style("overflow-y", "scroll").style("resize", "both").style("border", "solid 1px #ccc");
  const showholder = tr.append("td").style("vertical-align", "top");
  for (const n in pairs) {
    const ss = flag.pairsetname[n];
    if (ss) {
      pairs[n].setname = ss;
    } else {
      pairs[n].setname = { 1: "Diagnosis", 2: "Relapse" };
    }
  }
  const odata = {
    genome,
    //dsname:dsname,
    pairs,
    color1,
    color2,
    colorshare,
    rowh: boxh,
    peoplewidth: 150,
    genewidth: 150,
    showholder,
    //peoplelimit:Math.min(20,peopletotal),
    genelimit: Math.min(20, genetotal),
    purity1set: flag.purity1set,
    purity2set: flag.purity2set
  };
  d2maf_peopletable(odata, peopleholder);
}
function parseheader(line) {
  const lower = line.toLowerCase().split("	");
  const header = line.split("	");
  if (header.length <= 1) {
    return ["invalid file header"];
  }
  const htry = (...lst) => {
    for (const i2 of lst) {
      const j = lower.indexOf(i2);
      if (j != -1) return j;
    }
    return -1;
  };
  let i = htry("person", "sample", "samplename", "patient");
  if (i == -1) return ["sample missing from header"];
  header[i] = "sample";
  i = htry("type");
  if (i == -1) return ["type missing from header"];
  header[i] = "type";
  i = htry("mind.d1_g1", "mind.d", "mind");
  if (i == -1) return ["MinD.D missing from header"];
  header[i] = "MinD.D";
  i = htry("tind.d1_g1", "tind.d", "tind");
  if (i == -1) return ["TinD.D missing from header"];
  header[i] = "TinD.D";
  i = htry("mind.r1_g1", "mind.r", "minr");
  if (i == -1) return ["MinD.R missing from header"];
  header[i] = "MinD.R";
  i = htry("tind.r1_g1", "tind.r", "tinr");
  if (i == -1) return ["TinD.R missing from header"];
  header[i] = "TinD.R";
  i = htry("call_d1_g1", "call_d");
  if (i == -1) return ["call_d missing from header"];
  header[i] = "call_d";
  i = htry("call_r1_g1", "call_r");
  if (i == -1) return ["call_r missing from header"];
  header[i] = "call_r";
  i = htry("genename", "gene");
  if (i == -1) return ["gene missing from header"];
  header[i] = "gene";
  i = htry("amino_acid_change", "annovar_sj_aachange", "aachange", "protein_change");
  if (i == -1) return ["amino_acid_change missing from header"];
  header[i] = "mname";
  i = htry("class", "mclass", "variant_class", "variant_classification", "annovar_sj_class");
  if (i == -1) return ["variant_class missing from header"];
  header[i] = "class";
  i = htry("chromosome", "chr");
  if (i == -1) return ["chromosome missing from header"];
  header[i] = "chr";
  i = htry("start", "start_position", "wu_hg19_pos", "chr_position");
  if (i == -1) return ["start missing from header"];
  header[i] = "chrstart";
  i = htry("minn.d1_g1", "minn.d");
  if (i != -1) header[i] = "MinN.D";
  i = htry("tinn.d1_g1", "tinn.d");
  if (i != -1) header[i] = "TinN.D";
  i = htry("minn.r1_g1", "minn.r");
  if (i != -1) header[i] = "MinN.R";
  i = htry("tinn.r1_g1", "tinn.r");
  if (i != -1) header[i] = "TinN.R";
  i = htry("mrna_accession", "refseq_mrna_id", "annovar_sj_filter_isoform", "refseq");
  if (i != -1) header[i] = "isoform";
  i = htry("primary_purity", "purity_d");
  if (i != -1) header[i] = "purity1";
  i = htry("relapse_purity", "purity_r");
  if (i != -1) header[i] = "purity2";
  i = htry("tag_d_cnvloh", "cnvloh_d");
  if (i != -1) header[i] = "Dcnvloh";
  i = htry("tag_r_cnvloh", "cnvloh_r");
  if (i != -1) header[i] = "Rcnvloh";
  const atlst = [];
  for (const j of header) {
    switch (j) {
      case "Dcnvloh":
        atlst.push({
          label: "D. CNV/LOH",
          get: (m) => m.Dcnvlohraw
        });
        break;
      case "Rcnvloh":
        atlst.push({
          label: "R. CNV/LOH",
          get: (m) => m.Rcnvlohraw
        });
        break;
      case "type":
        atlst.push({
          label: "Type",
          get: (m) => m.type
        });
        break;
      case "chr":
        break;
      case "chrstart":
        atlst.push({
          label: "Genome Loc.",
          get: (m) => m.chr + ":" + (m.chrstart + 1)
        });
        break;
      case "class":
        atlst.push({
          label: "Class",
          get: (m) => {
            if (m.class == mclassnonstandard) {
              return m.originalclasslabel ? m.originalclasslabel : mclass[m.class].label;
            }
            return mclass[m.class].label;
          }
        });
        break;
      case "mname":
        atlst.push({
          label: "Mutation",
          get: (m) => {
            let s = m.mname;
            if (!s) s = m.cdna_change;
            return s;
          }
        });
        break;
      case "MinD.D":
        atlst.push({
          ismaf: true,
          width: 60,
          height: 14,
          readcountcredible: 30,
          get: (m) => m.maf_diagnosis,
          label: "D. tumor MAF",
          fill: "#F7483B",
          fillbg: "#FCBAB6"
        });
        break;
      case "TinD.D":
        break;
      case "MinD.R":
        atlst.push({
          ismaf: true,
          width: 60,
          height: 14,
          readcountcredible: 30,
          get: (m) => m.maf_relapse,
          label: "R. tumor MAF",
          fill: "#146EFF",
          fillbg: "#B6D5FC"
        });
        break;
      case "TinD.R":
        break;
      case "MinN.D":
        atlst.push({
          ismaf: true,
          width: 60,
          height: 14,
          readcountcredible: 30,
          get: (m) => m.maf_diagnosis_normal,
          label: "D. normal MAF",
          fill: "#F7483B",
          fillbg: "#FCBAB6"
        });
        break;
      case "TinN.D":
        break;
      case "MinN.R":
        atlst.push({
          ismaf: true,
          width: 60,
          height: 14,
          readcountcredible: 30,
          get: (m) => m.maf_relapse_normal,
          label: "R. normal MAF",
          fill: "#146EFF",
          fillbg: "#B6D5FC"
        });
        break;
      case "TinN.R":
        break;
      case "call_d":
        atlst.push({
          label: "D. call",
          get: (m) => m.call_d
        });
        break;
      case "call_r":
        atlst.push({
          label: "R. call",
          get: (m) => m.call_r
        });
        break;
      case "purity1":
        atlst.push({
          label: "D. purity",
          get: (m) => m.purity1
        });
        break;
      case "purity2":
        atlst.push({
          label: "R. purity",
          get: (m) => m.purity2
        });
        break;
      default:
        atlst.push({
          label: j,
          get: (m) => m[j]
        });
    }
  }
  return [null, header, atlst];
}
function d2maf_render(showholder, pdata) {
  const tooltip = new Menu({ border: "solid 1px black" });
  const set_1 = [];
  const set_2 = [];
  const set_share = [];
  const mlst = pdata.mlst;
  const person = mlst[0].sample;
  const symbolgen = Symbol();
  let maxtotal = 0;
  let bysymbol = {};
  const mclasses = {};
  for (const m of mlst) {
    if (m["TinD.D"] > 0) {
      maxtotal = Math.max(maxtotal, m["TinD.D"]);
    }
    if (m["TinD.R"] > 0) {
      maxtotal = Math.max(maxtotal, m["TinD.R"]);
    }
    if (m.set_share) {
      set_share.push(m);
    } else if (m.set_1) {
      set_1.push(m);
    } else if (m.set_2) {
      set_2.push(m);
    }
    if (!(m.class in mclasses)) {
      mclasses[m.class] = 0;
    }
    if (m.symbol) {
      if (!bysymbol[m.symbol]) {
        bysymbol[m.symbol] = { numlines: 0, label: m.symbollabel, hidden: false };
      }
      bysymbol[m.symbol].numlines++;
    }
    mclasses[m.class]++;
  }
  const a = Math.min(window.innerWidth, window.innerHeight);
  const axiswidth = 50, sharewidth = a * 0.5, shareheight = a * 0.5, sample1height = shareheight / 2, sample2height = sharewidth / 2, sp = axiswidth / 3, sp2 = sample1height / 5, labelfontsize = Math.min(20, 12 * a / 500), radius = a / 40, indelboxw = radius * 0.7, r_cnvloh = 3;
  const radiusscale = linear().domain([0, maxtotal]).range([radius / 2, radius]);
  const radiustoarea = (d) => Math.PI * Math.pow(radiusscale(d), 2);
  for (const m of mlst) {
    m.radius = Math.max(m["TinD.D"] ? radiusscale(m["TinD.D"]) : 0, m["TinD.R"] ? radiusscale(m["TinD.R"]) : 0);
  }
  const outtable = showholder.append("table");
  const tr = outtable.append("tr");
  const tdgraph = tr.append("td").style("vertical-align", "top");
  const tdgenetable = tr.append("td").style("vertical-align", "top");
  tdgenetable.append("div").style("margin", "10px").text("Name: " + person);
  const headerdiv = tdgraph.append("div");
  headerdiv.append("button").text("Hide").on("click", () => {
    pdata.shown = false;
    if (pdata.handle) {
      pdata.handle.attr("font-weight", "normal");
    }
    outtable.remove();
  });
  const anchors = new Anchors({ axiswidth, sp, sp2, sample1height, sample2height, shareheight, sharewidth, headerdiv });
  headerdiv.append("button").text("Screenshot").on("click", () => {
    to_svg(svg.node(), "2dmaf_" + pdata.name);
  });
  {
    const mcselect = headerdiv.append("select").on("change", (event) => {
      const v = event.target.options[event.target.selectedIndex].value;
      if (v == "all") {
        select_share.transition().attr("transform", (d) => d.posstring + " scale(1)");
        select_set1.transition().attr("transform", (d) => d.posstring + " scale(1)");
        select_set2.transition().attr("transform", (d) => d.posstring + " scale(1)");
        return;
      }
      select_share.transition().attr("transform", (d) => d.posstring + " scale(" + (d.class == v ? 1 : 0) + ")");
      select_set1.transition().attr("transform", (d) => d.posstring + " scale(" + (d.class == v ? 1 : 0) + ")");
      select_set2.transition().attr("transform", (d) => d.posstring + " scale(" + (d.class == v ? 1 : 0) + ")");
    });
    mcselect.append("option").text("Show all mutation classes").property("value", "all");
    const lst = [];
    for (const c3 in mclasses) {
      lst.push([c3, mclasses[c3]]);
    }
    lst.sort((a2, b) => b[1] - a2[1]);
    for (const i of lst) {
      mcselect.append("option").text((i[0] in mclass ? mclass[i[0]].label : i[0]) + " (" + i[1] + ")").property("value", i[0]);
    }
  }
  const svg = tdgraph.append("svg").attr("width", axiswidth + sp + sample2height + sharewidth + sp * 2).attr("height", axiswidth + sp + sample1height + shareheight + sp * 2);
  const g = svg.append("g").attr("transform", "translate(" + sp + "," + sp + ")");
  anchors.setWrapper(g.append("g"));
  const scale1 = linear().domain([0, 1]).range([0, sharewidth]);
  const scalediv1 = g.append("g").attr("transform", "translate(" + (axiswidth + sp + sample2height) + "," + (shareheight + sample1height + sp) + ")").call(axisBottom().scale(scale1).tickSize(5));
  axisstyle({ axis: scalediv1, showline: true, fontsize: labelfontsize * 0.8 });
  const c = set_1.length + set_share.length;
  scalediv1.append("text").text(pdata.setname[1] + ", n=" + c + (pdata.purity1 ? ", purity=" + pdata.purity1 : "")).attr("x", sharewidth / 2).attr("y", axiswidth - 4).attr("text-anchor", "middle").attr("font-size", labelfontsize);
  const scale2 = linear().domain([0, 1]).range([shareheight, 0]);
  const scalediv2 = g.append("g").attr("transform", "translate(" + axiswidth + ",0)").call(axisLeft().scale(scale2).tickSize(5));
  axisstyle({ axis: scalediv2, showline: true, fontsize: labelfontsize * 0.8 });
  const c2 = set_2.length + set_share.length;
  scalediv2.append("text").text(pdata.setname[2] + ", n=" + c2 + (pdata.purity2 ? ", purity=" + pdata.purity2 : "")).attr("transform", "translate(" + (labelfontsize - axiswidth - 10) + "," + shareheight / 2 + ") rotate(-90)").attr("text-anchor", "middle").attr("font-size", labelfontsize);
  g.append("path").attr(
    "d",
    "M" + (axiswidth + sp) + ",0h" + (sample2height + sharewidth) + "v" + (shareheight + sample1height) + "h-" + sharewidth + "v-" + (sample1height + shareheight) + "M" + (axiswidth + sp) + ",0v" + shareheight + "h" + (sample2height + sharewidth) + "M" + (axiswidth + sp + sample2height) + "," + shareheight + "l" + sharewidth + ",-" + shareheight
  ).attr("fill", "none").attr("stroke", "black").attr("shape-rendering", "crispEdges").attr("stroke-dasharray", "5,5");
  const select_share = g.append("g").attr("transform", "translate(" + (axiswidth + sp + sample2height) + ",0)").selectAll().data(set_share).enter().append("g").attr("transform", (d) => {
    d.posstring = "translate(" + scale1(d.maf1) + "," + scale2(d.maf2) + ")";
    return d.posstring;
  });
  select_share.filter((d) => d.Dcnvloh).append("circle").attr("cy", (d) => {
    return d.issnv ? radiusscale(d["TinD.R"]) : indelboxw / 2;
  }).attr("fill", "#858585").attr("r", r_cnvloh);
  select_share.filter((d) => d.Rcnvloh).append("circle").attr("cx", (d) => {
    return d.issnv ? -radiusscale(d["TinD.D"]) : -indelboxw / 2;
  }).attr("fill", "#858585").attr("r", r_cnvloh);
  let snv = select_share;
  for (const tagName in sharedFilters) {
    snv.filter(sharedFilters[tagName]).append(tagName).attr("rx", (d) => d.symbol ? null : radiusscale(d["TinD.D"])).attr("ry", (d) => d.symbol ? null : radiusscale(d["TinD.R"])).attr(
      "d",
      (d) => !d.symbol ? null : symbolgen.type(symbols[d.symbol]).size(radiustoarea(d["TinD.D"]) + radiustoarea(d["TinD.R"]) / 2)()
    ).attr("fill", (d) => d.style.fill).attr("fill-opacity", (d) => d.style.fillopacity).attr("stroke", (d) => d.style.stroke).attr("stroke-opacity", (d) => d.style.strokeopacity).attr("stroke-dasharray", (d) => d.chr == "chrX" ? "5,5" : "none").on("mouseover", (event, d) => d2maf_dotmover(event, d, tooltip)).on("mouseout", (event, d) => d2maf_dotmout(event, d, tooltip)).on("click", (event, d) => d2maf_minfo(event, pdata.header, d));
  }
  snv.append("line").attr("stroke", (d) => d.style.stroke).attr("stroke-opacity", (d) => d.style.strokeopacity).attr("x1", -3).attr("y1", -3).attr("x2", 3).attr("y2", 3);
  snv.append("line").attr("stroke", (d) => d.style.stroke).attr("stroke-opacity", (d) => d.style.strokeopacity).attr("x1", -3).attr("y1", 3).attr("x2", 3).attr("y2", -3);
  const set1totalscale = linear().domain([0, maxtotal]).range([sample1height - sp2, 0]);
  const g_set1 = g.append("g").attr("transform", "translate(" + (axiswidth + sp + sample2height) + "," + (shareheight + sp2) + ")");
  const emaflinecolor = "#FFBEAD";
  const emafline_1 = g_set1.append("rect").attr("fill", emaflinecolor).attr("fill-opacity", 0).attr("x", 0).attr("width", 3).attr("height", sample1height - sp2);
  axisstyle({
    axis: g_set1.call(axisLeft().scale(set1totalscale).tickValues([0, maxtotal])),
    showline: true,
    fontsize: labelfontsize * 0.8
  });
  g_set1.append("g").attr("transform", "translate(-" + labelfontsize / 2 + "," + (sample1height - sp2) / 2 + ")").append("text").text("D total").attr("font-size", labelfontsize * 0.8).attr("font-family", font).attr("fill", "black").attr("text-anchor", "middle").attr("dominant-baseline", "middle").attr("transform", "rotate(-90)");
  const select_set1 = g_set1.selectAll().data(set_1).enter().append("g").attr("transform", (d) => {
    d.posstring = "translate(" + scale1(d.maf1) + "," + set1totalscale(d["TinD.D"]) + ")";
    return d.posstring;
  });
  select_set1.filter((d) => d.Dcnvloh).append("circle").attr("cy", (d) => {
    return d.issnv ? radiusscale(d["TinD.R"]) : indelboxw / 2;
  }).attr("fill", "#858585").attr("r", r_cnvloh);
  select_set1.filter((d) => d.Rcnvloh).append("circle").attr("cx", (d) => d.issnv ? -radiusscale(d["TinD.D"]) : -indelboxw / 2).attr("fill", "#858585").attr("r", r_cnvloh);
  snv = select_set1;
  for (const tagName in symbolFilters) {
    snv.filter(symbolFilters[tagName]).append(tagName).attr("class", (d) => d.symbol ? "twodmaf-" + d.symbol : null).attr("r", (d) => d.symbol ? null : radiusscale(d["TinD.R"])).attr("d", (d) => !d.symbol ? null : symbolgen.type(symbols[d.symbol]).size(radiustoarea(d["TinD.R"]))()).attr("fill", (d) => d.style.fill).attr("fill-opacity", (d) => d.style.fillopacity).attr("stroke", (d) => d.style.stroke).attr("stroke-opacity", (d) => d.style.strokeopacity).attr("stroke-dasharray", (d) => d.chr == "chrX" ? "5,5" : "none").on("mouseover", (event, d) => d2maf_dotmover(event, d, tooltip)).on("mouseout", (event, d) => d2maf_dotmout(event, d, tooltip)).on("click", (event, d) => d2maf_minfo(event, pdata.header, d));
  }
  snv.append("line").attr("stroke", (d) => d.style.stroke).attr("stroke-opacity", (d) => d.style.strokeopacity).attr("x1", -3).attr("y1", -3).attr("x2", 3).attr("y2", 3);
  snv.append("line").attr("stroke", (d) => d.style.stroke).attr("stroke-opacity", (d) => d.style.strokeopacity).attr("x1", -3).attr("y1", 3).attr("x2", 3).attr("y2", -3);
  const set2totalscale = linear().domain([0, maxtotal]).range([0, sample2height - sp2]);
  const g_set2 = g.append("g").attr("transform", "translate(" + (axiswidth + sp) + ",0)");
  const emafline_2 = g_set2.append("rect").attr("fill", emaflinecolor).attr("fill-opacity", 0).attr("y", shareheight).attr("width", sample2height - sp2).attr("height", 3);
  const g_set2_axis = g_set2.append("g").attr("transform", "translate(0," + shareheight + ")").call(axisBottom().scale(set2totalscale).tickValues([0, maxtotal]));
  axisstyle({
    axis: g_set2_axis,
    showline: true,
    fontsize: labelfontsize * 0.8
  });
  g_set2.append("text").text("R total").attr("font-size", labelfontsize * 0.8).attr("font-family", font).attr("fill", "black").attr("x", (sample2height - sp2) / 2).attr("y", shareheight + labelfontsize).attr("text-anchor", "middle");
  const select_set2 = g_set2.selectAll().data(set_2).enter().append("g").attr("transform", (d) => {
    d.posstring = "translate(" + set2totalscale(d["TinD.R"]) + "," + scale2(d.maf2) + ")";
    return d.posstring;
  });
  select_set2.filter((d) => d.Dcnvloh).append("circle").attr("cy", (d) => d.issnv ? radiusscale(d["TinD.R"]) : indelboxw / 2).attr("fill", "#858585").attr("r", r_cnvloh);
  select_set2.filter((d) => d.Rcnvloh).append("circle").attr("cx", (d) => d.issnv ? -radiusscale(d["TinD.D"]) : -indelboxw / 2).attr("fill", "#858585").attr("r", r_cnvloh);
  snv = select_set2;
  for (const tagName in symbolFilters) {
    snv.filter(symbolFilters[tagName]).append(tagName).attr("class", (d) => d.symbol ? "twodmaf-" + d.symbol : null).attr("r", (d) => d.symbol ? null : radiusscale(d["TinD.D"])).attr("d", (d) => !d.symbol ? null : symbolgen.type(symbols[d.symbol]).size(radiustoarea(d["TinD.R"]))()).attr("fill", (d) => d.style.fill).attr("fill-opacity", (d) => d.style.fillopacity).attr("stroke", (d) => d.style.stroke).attr("stroke-opacity", (d) => d.style.strokeopacity).attr("stroke-dasharray", (d) => d.chr == "chrX" ? "5,5" : "none").on("mouseover", (event, d) => d2maf_dotmover(event, d, tooltip)).on("mouseout", (event, d) => d2maf_dotmout(event, d, tooltip)).on("click", (event, d) => d2maf_minfo(event, pdata.header, d));
  }
  snv.append("line").attr("stroke", (d) => d.style.stroke).attr("stroke-opacity", (d) => d.style.strokeopacity).attr("x1", -3).attr("y1", -3).attr("x2", 3).attr("y2", 3);
  snv.append("line").attr("stroke", (d) => d.style.stroke).attr("stroke-opacity", (d) => d.style.strokeopacity).attr("x1", -3).attr("y1", 3).attr("x2", 3).attr("y2", -3);
  const leng = g.append("g").attr("transform", "translate(0," + (shareheight + sp2) + ")");
  let y = labelfontsize;
  leng.append("text").text(person).attr("font-size", labelfontsize).attr("y", y);
  const r1 = radiusscale(20), r2 = radiusscale(maxtotal);
  y += labelfontsize + r2;
  let x;
  leng.append("text").text("SNV coverage").attr("y", y).attr("dominant-baseline", "middle").each(function() {
    x = this.getBBox().width;
  });
  x += r1 + 10;
  leng.append("circle").attr("cx", x).attr("cy", y).attr("r", r1).attr("stroke", "black").attr("fill", "none");
  leng.append("text").text(20).attr("x", x).attr("y", y).attr("text-anchor", "middle").attr("dominant-baseline", "middle");
  x += r1 + r2 + 10;
  leng.append("circle").attr("cx", x).attr("cy", y).attr("r", r2).attr("stroke", "black").attr("fill", "none");
  leng.append("text").text(maxtotal).attr("x", x).attr("y", y).attr("text-anchor", "middle").attr("dominant-baseline", "middle");
  y += r2 + 10;
  leng.append("text").text("Indel").attr("y", y).attr("dominant-baseline", "middle").each(function() {
    x = this.getBBox().width;
  });
  leng.append("circle").attr("cx", x + 10 + indelboxw / 2).attr("cy", y).attr("r", indelboxw / 2).attr("fill", "black").attr("fill-opacity", 0.3);
  y += 30;
  leng.append("text").text("chrX").attr("y", y).attr("dominant-baseline", "middle").each(function() {
    x = this.getBBox().width;
  });
  x += r1 + 10;
  leng.append("circle").attr("cx", x).attr("cy", y).attr("r", 10).attr("stroke", "black").attr("stroke-dasharray", "5,5").attr("fill", "none");
  y += 30;
  leng.append("text").text("D. CNV/LOH").attr("y", y).attr("dominant-baseline", "middle").each(function() {
    x = this.getBBox().width;
  });
  x += r1 + 10;
  leng.append("circle").attr("cx", x).attr("cy", y).attr("r", 10).attr("stroke", "black").attr("fill", "none");
  leng.append("circle").attr("cx", x).attr("cy", y + 10).attr("r", r_cnvloh).attr("fill", "black");
  y += 30;
  leng.append("text").text("R. CNV/LOH").attr("y", y).attr("dominant-baseline", "central").each(function() {
    x = this.getBBox().width;
  });
  x += r1 + 10;
  leng.append("circle").attr("cx", x).attr("cy", y).attr("r", 10).attr("stroke", "black").attr("fill", "none");
  leng.append("circle").attr("cx", x - 10).attr("cy", y).attr("r", r_cnvloh).attr("fill", "black");
  y += 30;
  if (pdata.purity1 != void 0 || pdata.purity2 != void 0) {
    leng.append("text").text("Expected MAF").attr("y", y).attr("dominant-baseline", "middle").each(function() {
      x = this.getBBox().width;
    });
    x += 10;
    leng.append("rect").attr("fill", emaflinecolor).attr("x", x).attr("y", y).attr("width", 40).attr("height", 3);
    y += 30;
  }
  const renderedsymbols = Object.keys(bysymbol);
  if (renderedsymbols.length) {
    leng.append("text").text("Symbols").attr("y", y).attr("dominant-baseline", "middle").each(function() {
      x = this.getBBox().width;
    });
    let x1;
    for (const symbolname in bysymbol) {
      const s = bysymbol[symbolname];
      const g3 = leng.append("g").on("click", () => {
        s.hidden = !s.hidden;
        svg.selectAll(".twodmaf-" + symbolname).style("display", s.hidden ? "none" : "");
        label.style("text-decoration", s.hidden ? "line-through" : "");
      });
      x1 = x + 20;
      g3.append("path").attr("transform", "translate(" + x1 + "," + y + ")").attr("d", symbolgen.type(symbols[symbolname]).size(100)()).attr("stroke", "black").attr("fill", "none").each(function() {
        x1 += this.getBBox().width;
      });
      const label = g3.append("text").text(s.label ? s.label + " (" + s.numlines + ")" : "").attr("y", y + 2).attr("x", x1).attr("dominant-baseline", "middle").style("text-decoration", s.hidden ? "line-through" : "");
      y += 30;
    }
    y += 30;
  }
  const g2m = {}, g1 = {}, g2 = {}, gs = {};
  for (const m of mlst) {
    if (!m.gene) continue;
    if (!(m.gene in g2m)) {
      g2m[m.gene] = [];
    }
    g2m[m.gene].push(m);
    if (m.set_1) {
      g1[m.gene] = 1;
    } else if (m.set_2) {
      g2[m.gene] = 1;
    } else if (m.set_share) {
      gs[m.gene] = 1;
    }
  }
  const genelst = [];
  for (const n in g1) {
    genelst.push(n);
  }
  for (const n in g2) {
    if (!(n in g1)) {
      genelst.push(n);
    }
  }
  for (const n in gs) {
    if (!(n in g1) && !(n in g2)) {
      genelst.push(n);
    }
  }
  const table = tdgenetable.append("div").style("height", shareheight + sample1height + "px").style("margin", "10px").style("padding", "10px").style("border", "solid 1px #ccc").style("overflow-y", "scroll").style("resize", "both").append("table");
  {
    const tr2 = table.append("tr");
    tr2.append("td").text("Gene");
    tr2.append("td").text(pdata.setname[1] + " only");
    tr2.append("td").text(pdata.setname[2] + " only");
    tr2.append("td").text("Shared");
  }
  let bg = true;
  for (const name of genelst) {
    const tr2 = table.append("tr");
    if (bg) {
      tr2.style("background-color", "#f3f3f3");
    }
    bg = !bg;
    tr2.append("td").text(name);
    let mlst2 = [];
    if (name in g2m) {
      mlst2 = g2m[name];
    }
    const s1 = [], s2 = [], ss = [];
    for (const m of mlst2) {
      if (m.set_share) ss.push(m);
      else if (m.set_1) s1.push(m);
      else if (m.set_2) s2.push(m);
    }
    let td = tr2.append("td");
    if (s1.length) {
      for (const m of s1) {
        const div = td.append("div").attr("class", "sja_clbtext").style("color", m.style.fillhl).text(m.mname || "").on("click", (event) => {
          click(event.target, m, select_set1);
        });
        if (m.labelIsVisible) {
          click(div.node(), m, select_set1);
        }
      }
    }
    td = tr2.append("td");
    if (s2.length) {
      for (const m of s2) {
        const div = td.append("div").attr("class", "sja_clbtext").style("color", m.style.fillhl).text(m.mname || "").on("click", (event) => {
          click(event.target, m, select_set2);
        });
        if (m.labelIsVisible) {
          click(div.node(), m, select_set1);
        }
      }
    }
    td = tr2.append("td");
    if (ss.length) {
      for (const m of ss) {
        const div = td.append("div").attr("class", "sja_clbtext").style("color", m.style.fillhl).text(m.mname || "").on("click", (event) => {
          click(event.target, m, select_share);
        });
        if (m.labelIsVisible) {
          click(div.node(), m, select_set1);
        }
      }
    }
  }
  function click(butt, m, select) {
    if (m.selected) {
      butt.style.border = "";
      m.selected = false;
    } else {
      butt.style.border = "solid 1px black";
      m.selected = true;
    }
    const found = select.filter((d) => {
      return d.gene == m.gene && d.class == m.class && d.mname == m.mname;
    });
    found.selectAll("rect").attr("fill-opacity", m.selected ? 0.5 : m.style.fillopacity).attr("fill", m.selected ? m.style.fillhl : m.style.fill);
    found.selectAll("circle,ellipse,line").attr("stroke-opacity", m.selected ? 1 : m.style.strokeopacity).attr("stroke", m.selected ? m.style.strokehl : m.style.stroke).attr("stroke-width", m.selected ? 2 : 1);
    if (m.selected) {
      let x2 = Math.max(20, m.radius), y2 = 0;
      if ((m.set_1 || m.set_share) && m.maf1 >= 0.8) {
        x2 = -m.radius;
        y2 = m.radius * 2;
      }
      const g3 = found.append("g").attr("class", "sja_2dmaf_mlabel").attr("transform", "translate(" + x2 + "," + y2 + ")");
      let w;
      g3.append("text").text(m.labelAs ? m.labelAs : m.gene + " " + m.mname).attr("fill", m.style.fillhl).attr("dominant-baseline", "middle").attr("text-anchor", "start").attr("font-size", m.radius).each(function() {
        w = this.getBBox().width;
      });
      g3.append("rect").attr("y", -m.radius / 2).attr("width", w).attr("height", m.radius).attr("fill", "black").attr("fill-opacity", 0).on("mouseover", (event) => select_default(event.target).attr("fill-opacity", 0.2)).on("mouseout", (event) => select_default(event.target).attr("fill-opacity", 0)).on("mousedown", (event) => {
        const x0 = x2, y0 = y2, mx = event.clientX, my = event.clientY, body = select_default(document.body);
        body.on("mousemove", (event2) => {
          event2.preventDefault();
          x2 = x0 + event2.clientX - mx;
          y2 = y0 + event2.clientY - my;
          g3.attr("transform", "translate(" + x2 + "," + y2 + ")");
        });
        body.on("mouseup", () => {
          body.on("mousemove", null).on("mouseup", null);
        });
      });
    } else {
      found.select(".sja_2dmaf_mlabel").remove();
    }
  }
  return outtable;
}
function d2maf_dotmover(event, m, tooltip) {
  if (!m.selected) {
    select_default(event.target).attr("fill", m.style.fillhl).attr("fill-opacity", 0.2);
  }
  tooltip.clear();
  tooltip.show(event.clientX, event.clientY);
  tooltip.d.append("div").html(
    (m.gene || "no gene") + ' <span style="color:' + m.style.fillhl + '">' + (m.mname || "") + "</span>" + (m.class ? ' <span style="font-size:70%">' + mclass[m.class].label + "</span>" : "")
  );
}
function d2maf_dotmout(event, m, tooltip) {
  if (!m.selected) {
    select_default(event.ele).attr("fill", m.style.fill).attr("fill-opacity", m.style.fillopacity).attr("stroke", m.style.stroke);
  }
  tooltip.hide();
}
function d2maf_minfo(event, header, m) {
  const pane = newpane({ x: event.clientX + 30, y: event.clientY - 30 });
  pane.header.text((m.gene ? m.gene : "No gene") + " " + (m.mname ? m.mname : ""));
  var data = [];
  for (let i = 0; i < header.length; i++) {
    data.push({ k: header[i], v: m[header[i]] });
  }
  make_table_2col(pane.body, data);
}
function d2maf_click(data, person) {
  const v = data.pairs[person];
  if (v.shown) {
    v.shown = false;
    v.holder.remove();
    if (v.handle) {
      v.handle.attr("font-weight", "normal");
    }
  } else {
    v.shown = true;
    if (v.holder) {
      data.showholder.node().appendChild(v.holder.node());
    } else {
      v.holder = d2maf_render(data.showholder, v);
    }
    if (v.handle) {
      v.handle.attr("font-weight", "bold");
    }
  }
}
function d2maf_peopletable(data, holder) {
  const plst = [];
  for (const n in data.pairs) {
    plst.push([n, data.pairs[n].mlst.length]);
  }
  holder.selectAll("*").remove();
  const searchrow = holder.append("div").style("margin-bottom", "5px");
  searchrow.append("span").text(plst.length + " individual" + (plst.length > 1 ? "s" : ""));
  const svg = holder.append("svg");
  const space = 5, axish = 20, rowh = data.rowh;
  let maxlabelw = 0;
  for (const s of plst) {
    svg.append("text").text(s[0]).attr("font-size", rowh).attr("font-family", font).each(function() {
      maxlabelw = Math.max(maxlabelw, this.getBBox().width);
    }).remove();
  }
  svg.attr("width", maxlabelw + space + data.peoplewidth + 30).attr("height", axish + space + rowh * plst.length);
  plst.sort((a, b) => b[1] - a[1]);
  let maxmcount = 0;
  for (const k in data.pairs) {
    maxmcount = Math.max(maxmcount, data.pairs[k].mlst.length);
  }
  const ag = svg.append("g").attr("transform", "translate(" + (maxlabelw + space) + "," + axish + ")").call(
    axisTop().scale(linear().domain([0, maxmcount]).range([0, data.peoplewidth])).tickFormat(format("d")).ticks(3)
  );
  axisstyle({
    axis: ag,
    showline: true,
    color: "black"
  });
  const wsf = data.peoplewidth / maxmcount;
  let y = axish + space;
  for (const s of plst) {
    const person = s[0];
    data.pairs[person].handle = svg.append("text").text(person).attr("class", "sja_svgtext2").attr("font-size", rowh - 2).attr("font-family", font).attr("x", maxlabelw).attr("y", y + space + rowh / 2).attr("text-anchor", "end").on("click", () => {
      d2maf_click(data, person);
    });
    let m1 = 0, m2 = 0, ms = 0;
    for (const m of data.pairs[person].mlst) {
      if (m.set_1) m1++;
      else if (m.set_2) m2++;
      else if (m.set_share) ms++;
    }
    const g = svg.append("g").attr("transform", "translate(" + (maxlabelw + space) + "," + y + ")");
    if (m1 > 0) {
      g.append("rect").attr("width", wsf * m1).attr("height", rowh - 1).attr("fill", data.color1);
    }
    if (ms > 0) {
      g.append("rect").attr("x", wsf * m1).attr("width", wsf * ms).attr("height", rowh - 1).attr("fill", data.colorshare);
    }
    if (m2 > 0) {
      g.append("rect").attr("x", wsf * (m1 + ms)).attr("width", wsf * m2).attr("height", rowh - 1).attr("fill", data.color2);
    }
    y += rowh;
  }
}
export {
  d2mafparseinput,
  d2mafui
};
//# sourceMappingURL=2dmaf-Z3D2M3FB.js.map
