import {
  dofetch3
} from "./chunk-7EMWHCVW.js";
import "./chunk-7IYJZZQI.js";
import {
  copyMerge,
  getCompInit
} from "./chunk-M3J4MINX.js";
import "./chunk-PF4DSFDR.js";
import "./chunk-QH6W3NVF.js";
import "./chunk-NOEAT6CX.js";
import "./chunk-4UWS5Y3N.js";
import "./chunk-JNITUVXP.js";
import "./chunk-KSGA62R2.js";
import "./chunk-LOZEKOES.js";
import "./chunk-TOU7EVFQ.js";
import "./chunk-OAWQ6LOO.js";
import "./chunk-TLT4YIG3.js";
import "./chunk-KYBIQBXE.js";
import "./chunk-I6Y4O3RR.js";
import {
  rgb_default
} from "./chunk-OMR2DT66.js";
import "./chunk-HFNDKYVF.js";

// plots/geneExpression.js
var defaultConfig = {
  clusterMethod: "average",
  distanceMethod: "euclidean"
};
var clusterMethodLst = [
  "average",
  "complete",
  "mcquitty"
  //'single', very slow
  //'median', 'centroid', crashes R with "No connections found!"
  //'ward.D','ward.D2', crashes client
];
var distanceMethodLst = ["euclidean", "maximum", "manhattan", "canberra"];
var GeneExpression = class _GeneExpression {
  static type = "geneExpression";
  constructor() {
    this.type = _GeneExpression.type;
  }
  async init(opts) {
    const holder = this.opts.holder.append("div");
    this.dom = {
      holder,
      controlsDiv: holder.append("div"),
      canvas: holder.append("canvas"),
      colorScaleDiv: holder.append("div")
    };
    this.makeControls();
    this.components = {};
  }
  getState(appState) {
    const config = appState.plots.find((p) => p.id === this.id);
    if (!config) {
      throw `No plot with id='${this.id}' found`;
    }
    return {
      config
    };
  }
  async main() {
    const body = this.getParam();
    const data = await dofetch3("mds3", { body });
    plotHeatmap_R(data, this);
  }
  getParam() {
    console.log(this.state.config.genes);
    const body = {
      genome: this.app.opts.state.vocab.genome,
      dslabel: this.app.opts.state.vocab.dslabel,
      geneExpression: 1,
      genes: this.state.config.genes,
      clusterMethod: this.state.config.clusterMethod
    };
    return body;
  }
  makeControls() {
    const s = this.dom.controlsDiv.append("select");
    for (const n of clusterMethodLst) s.append("option").text(n);
    this.dom.clusterMethodSelect = s;
    s.on("change", () => {
      this.app.dispatch({
        type: "plot_edit",
        id: this.id,
        config: { clusterMethod: clusterMethodLst[s.property("selectedIndex")] }
      });
    });
  }
};
async function getPlotConfig(opts, app) {
  try {
    const config = structuredClone(defaultConfig);
    return copyMerge(config, opts);
  } catch (e) {
    throw `${e} [geneExpression getPlotConfig()]`;
  }
}
var geneExpressionInit = getCompInit(GeneExpression);
var componentInit = geneExpressionInit;
function makeChartBtnMenu(holder, chartsInstance) {
  holder.append("div").attr("class", "sja_menuoption sja_sharp_border").text("Clustering analysis").on("click", () => {
    chartsInstance.dom.tip.hide();
    chartsInstance.prepPlot({
      config: {
        chartType: "geneExpression"
      }
    });
  });
}
function plotHeatmap_R(data, self) {
  self.dom.clusterMethodSelect.property("selectedIndex", clusterMethodLst.indexOf(self.state.config.clusterMethod));
  self.dom.distanceMethodSelect.property("selectedIndex", distanceMethodLst.indexOf(self.state.config.distanceMethod));
  const obj = data.clustering;
  console.log(obj);
  obj.d = {
    minColor: "#0c306b",
    maxColor: "#ffcc00",
    xDendrogramHeight: 150,
    yDendrogramHeight: 150
  };
  obj.d.colorScale = rgb_default(obj.d.minColor, obj.d.maxColor);
  const ctx = self.dom.canvas.node().getContext("2d");
  obj.d.rowHeight = getRowHeight(obj);
  obj.d.colWidth = getColWidth(obj);
  getLabHeight(ctx, obj);
  self.dom.canvas.attr("width", obj.d.xDendrogramHeight + obj.d.xLabHeight + obj.d.colWidth * obj.matrix[0].length).attr("height", obj.d.yDendrogramHeight + obj.d.yLabHeight + obj.d.rowHeight * obj.matrix.length);
  plotNames(obj, ctx);
  drawHeatmap(obj, ctx);
  plotDendrogram_R(ctx, obj);
  plotHmColorScale(self, obj);
}
function plotDendrogram_R(ctx, obj) {
  try {
    obj.row_dendro.map(validateRline);
  } catch (e) {
    throw "row_dendro error: " + e;
  }
  try {
    obj.col_dendro.map(validateRline);
  } catch (e) {
    throw "col_dendro error: " + e;
  }
  for (const r of obj.row_dendro) {
    let t = r.x1;
    r.x1 = r.y1;
    r.y1 = t;
    t = r.x2;
    r.x2 = r.y2;
    r.y2 = t;
  }
  {
    let max = 0;
    for (const r of obj.row_dendro) max = Math.max(max, r.x1, r.x2);
    const sf = obj.d.xDendrogramHeight / max;
    for (const r of obj.row_dendro) {
      r.x1 = sf * (max - r.x1);
      r.x2 = sf * (max - r.x2);
      r.y1 *= obj.d.rowHeight;
      r.y2 *= obj.d.rowHeight;
    }
  }
  {
    let max = 0;
    for (const r of obj.col_dendro) max = Math.max(max, r.y1, r.y2);
    const sf = obj.d.yDendrogramHeight / max;
    for (const r of obj.col_dendro) {
      r.y1 = sf * (max - r.y1);
      r.y2 = sf * (max - r.y2);
      r.x1 *= obj.d.colWidth;
      r.x2 *= obj.d.colWidth;
    }
  }
  ctx.strokeStyle = "black";
  let F = obj.d.yDendrogramHeight + obj.d.yLabHeight;
  for (const r of obj.row_dendro) {
    ctx.beginPath();
    const x1 = Math.min(r.x1, r.x2), x2 = Math.max(r.x1, r.x2), y1 = Math.min(r.y1, r.y2), y2 = Math.max(r.y1, r.y2);
    ctx.moveTo(x1, y1 + F);
    ctx.lineTo(x1, y2 + F);
    if (r.x1 > r.x2 && r.y1 > r.y2 || r.x1 < r.x2 && r.y1 < r.y2) {
      ctx.lineTo(x2, y2 + F);
    } else {
      ctx.moveTo(x1, y1 + F);
      ctx.lineTo(x2, y1 + F);
    }
    ctx.stroke();
    ctx.closePath();
  }
  F = obj.d.xDendrogramHeight + obj.d.xLabHeight;
  for (const r of obj.col_dendro) {
    ctx.beginPath();
    const x1 = Math.min(r.x1, r.x2), x2 = Math.max(r.x1, r.x2), y1 = Math.min(r.y1, r.y2), y2 = Math.max(r.y1, r.y2);
    ctx.moveTo(F + x1, y1);
    ctx.lineTo(F + x2, y1);
    if (r.x1 > r.x2 && r.y1 > r.y2 || r.x1 < r.x2 && r.y1 < r.y2) {
      ctx.lineTo(F + x2, y2);
    } else {
      ctx.moveTo(F + x1, y1);
      ctx.lineTo(F + x1, y2);
    }
    ctx.stroke();
    ctx.closePath();
  }
}
function validateRline(r) {
  if (r.r1 < 0) throw `r.r1<0 ${r.r1}`;
  if (r.r2 < 0) throw `r.r2<0 ${r.r2}`;
  if (r.x1 < 1) throw `r.x1<1 ${r.x1}`;
  if (r.x2 < 1) throw `r.x2<1 ${r.x2}`;
  r.x1 -= 0.5;
  r.x2 -= 0.5;
  if (r.y1 < 0) throw `r.y1<0 ${r.y1}`;
  if (r.y2 < 0) throw `r.y2<0 ${r.y2}`;
}
function plotNames(obj, ctx) {
  if (obj.d.xLabHeight) {
    ctx.font = obj.d.rowHeight + "px Arial";
    ctx.textAlign = "end";
    ctx.fillStyle = "black";
    for (const [rowIdx, geneIdx] of obj.row_names_index.entries()) {
      ctx.fillText(
        obj.geneNameLst[geneIdx - 1],
        obj.d.xDendrogramHeight + obj.d.xLabHeight,
        obj.d.yDendrogramHeight + obj.d.yLabHeight + obj.d.rowHeight * (rowIdx + 1)
      );
    }
  }
}
function drawHeatmap(obj, ctx) {
  for (let i = 0; i < obj.row_names_index.length; i++) {
    const sampleValues = obj.matrix[obj.row_names_index[i] - 1];
    const [min, max] = getMinMax(sampleValues);
    for (let j = 0; j < obj.col_names_index.length; j++) {
      const v = sampleValues[obj.col_names_index[j] - 1];
      ctx.fillStyle = obj.d.colorScale((v - min) / (max - min));
      ctx.fillRect(
        obj.d.xDendrogramHeight + obj.d.xLabHeight + obj.d.colWidth * j,
        obj.d.yDendrogramHeight + obj.d.yLabHeight + obj.d.rowHeight * i,
        obj.d.colWidth,
        obj.d.rowHeight
      );
    }
  }
}
function getRowHeight(obj) {
  const h = 500 / obj.matrix.length;
  if (h > 20) return 20;
  if (h < 10) return 10;
  return Math.ceil(h);
}
function getColWidth(obj) {
  const w = 2e3 / obj.matrix[0].length;
  if (w > 10) return 10;
  return Math.ceil(w);
}
function getLabHeight(ctx, obj) {
  if (obj.geneNameLst && obj.d.rowHeight >= 7) {
    ctx.font = obj.d.rowHeight + "px Arial";
    let max = 0;
    for (const n of obj.geneNameLst) {
      max = Math.max(max, ctx.measureText(n).width);
    }
    obj.d.xLabHeight = max;
  } else {
    obj.d.xLabHeight = 0;
  }
  if (obj.sampleNameLst && obj.d.colWidth >= 7) {
    ctx.font = obj.d.colWidth + "px Arial";
    let max = 0;
    for (const n of obj.sampleNameLst) {
      max = Math.max(max, ctx.measureText(n).width);
    }
    obj.d.yLabHeight = max;
  } else {
    obj.d.yLabHeight = 0;
  }
}
function getMinMax(row) {
  let min = null, max;
  for (const v of row) {
    if (min == null) {
      min = v;
      max = v;
    } else {
      min = Math.min(min, v);
      max = Math.max(max, v);
    }
  }
  return [min, max];
}
function plotHmColorScale(self, obj) {
  self.dom.colorScaleDiv.selectAll("*").remove();
  const width = 100, height = 20;
  self.dom.colorScaleDiv.append("span").text("Min");
  const svg = self.dom.colorScaleDiv.append("svg");
  self.dom.colorScaleDiv.append("span").text("Max");
  const grad = svg.append("defs").append("linearGradient").attr("id", "grad");
  grad.append("stop").attr("offset", "0%").attr("stop-color", obj.d.minColor);
  grad.append("stop").attr("offset", "100%").attr("stop-color", obj.d.maxColor);
  svg.append("rect").attr("width", width).attr("height", height).attr("fill", "url(#grad)");
  svg.attr("width", width).attr("height", height);
}
export {
  componentInit,
  geneExpressionInit,
  getPlotConfig,
  makeChartBtnMenu
};
//# sourceMappingURL=geneExpression-2OPFWV2K.js.map
