import {
  violinRenderer
} from "./chunk-DD4R5P6W.js";
import {
  linear
} from "./chunk-OAWQ6LOO.js";
import {
  drag_default
} from "./chunk-KYBIQBXE.js";
import {
  pointer_default,
  select_default
} from "./chunk-I6Y4O3RR.js";

// termsetting/handlers/NumericDensity.ts
var NumericDensity = class {
  constructor(opts) {
    this.dom = {};
    // WeakMap allows deletion of value when the object/DOM key is deleted,
    // so better for avoiding memory leak
    this.vrByDiv = /* @__PURE__ */ new WeakMap();
    this.ranges = [];
    this.no_density_data = false;
    this.brushes = [];
    this.plot_size = {
      width: 500,
      height: 100,
      xpad: 10,
      ypad: 20,
      radius: 8
    };
    this.opts = opts;
    this.termsetting = opts.termsetting;
    this.tw = opts.termsetting.tw;
  }
  async setData() {
    const self = this.termsetting;
    const d = await self.vocabApi.getViolinBox(
      {
        plotType: "violin",
        tw: { term: self.term, q: self.q },
        svgw: this.plot_size.width,
        radius: this.plot_size.radius,
        filter: self.filter
      },
      self.opts.getBodyParams?.()
    );
    if (d.error) throw d;
    this.density_data = d;
    return this.density_data;
  }
  async showViolin(div, boundaryOpts) {
    await this.setData();
    if (!this.vrByDiv.has(div)) {
      div.style("padding", "5px").selectAll("*").remove();
      const loadingDiv = div.append("div").style("padding", "10px").style("text-align", "center").html("Getting distribution data ...<br/>");
      const densityDiv = div.append("div");
      loadingDiv.remove();
      const vr = new violinRenderer({
        holder: densityDiv,
        rd: this.density_data,
        width: this.plot_size.width,
        height: this.plot_size.height,
        radius: this.plot_size.radius
      });
      this.vrByDiv.set(div, vr);
    }
    this.vr = this.vrByDiv.get(div);
    this.dom.svg = this.vr.svg;
    this.vr.render();
    if (boundaryOpts) await this.setBinLines(boundaryOpts);
    return this.density_data;
  }
  async setBinLines(boundaryOpts) {
    if (this.density_data.max == this.density_data.min) {
      this.handleNoDensity();
    } else {
      if (this.dom.binsize_g) this.dom.binsize_g.selectAll("*").remove();
      this.dom.binsize_g = this.dom.svg.append("g").attr("transform", `translate(${this.plot_size.xpad}, ${this.plot_size.ypad})`).attr("class", "binsize_g");
      const maxvalue = this.density_data.max;
      const minvalue = this.density_data.min;
      this.xscale = linear().domain([minvalue, maxvalue]).range([this.plot_size.xpad, this.plot_size.width + this.plot_size.xpad]);
      this.ranges = [];
      this.brushes = [];
      this.renderBinLines(boundaryOpts);
    }
  }
  handleNoDensity() {
    this.no_density_data = true;
    this.ranges = [];
    this.brushes = [];
  }
  renderBinLines(boundaryOpts) {
    const { density_data, plot_size, tw, xscale } = this;
    if (!this.density_data) throw `Missing .density_data [density.ts, renderBinLines()]`;
    const scaledMinX = Math.round(this.xscale(density_data.min));
    const scaledMaxX = Math.round(this.xscale(density_data.max));
    const lines = [];
    for (const [index, v] of boundaryOpts.values.entries()) {
      lines.push({ ...v, index, scaledX: Math.round(this.xscale(v.x)) });
    }
    const lastVisibleLine = lines.find((l) => l.isLastVisibleLine);
    const lastVisibleScaledX = lastVisibleLine ? lastVisibleLine.scaledX : scaledMaxX;
    const dragger = drag_default().on("drag", onDrag).on("end", onDrag);
    this.dom.binsize_g.selectAll("line").remove();
    this.dom.binsize_g.selectAll("line").data(lines).enter().append("line").style("stroke", (d) => d.isDraggable ? "#cc0000" : "#555").style("stroke-width", 1).attr("x1", (d) => d.scaledX).attr("y1", 0).attr("x2", (d) => d.scaledX).attr("y2", plot_size.height).style("cursor", (d) => d.isDraggable ? "ew-resize" : "").attr("display", (d) => !d.isDraggable && d.scaledX > lastVisibleScaledX ? "none" : "").on("mouseover", function(_, d) {
      if (d.isDraggable) select_default(this).style("stroke-width", 3);
    }).on("mouseout", function() {
      select_default(this).style("stroke-width", 1);
    }).each(function(d) {
      if (d.isDraggable) select_default(this).call(dragger);
    });
    const lineElems = this.dom.binsize_g.node().querySelectorAll("line");
    function onDrag(event, _d) {
      const draggedX = pointer_default(event, this)[0];
      if (draggedX <= scaledMinX || draggedX >= scaledMaxX) return;
      const d = _d;
      d.draggedX = draggedX;
      select_default(this).attr("x1", d.draggedX).attr("y1", 0).attr("x2", d.draggedX).attr("y2", plot_size.height);
      const lastVisibleScaledX2 = lastVisibleLine?.draggedX ?? lastVisibleLine?.scaledX ?? scaledMaxX;
      const xOffset = d.draggedX - d.scaledX;
      if (xOffset) {
        for (const elem of lineElems) {
          const c = elem.__data__;
          if (c.movesWithLineIndex !== d.index) continue;
          c.draggedX = c.scaledX + xOffset;
          select_default(elem).attr("x1", c.draggedX).attr("x2", c.draggedX).style("display", c.draggedX >= lastVisibleScaledX2 ? "none" : "");
        }
        const inverted = xscale.invert(d.draggedX);
        const value = tw.term.type == "integer" ? Math.round(inverted) : inverted.toFixed(3);
        boundaryOpts.callback(d, Number(value));
      }
    }
  }
  destroy() {
    for (const [k, v] of Object.entries(this.dom)) {
      delete this.dom[k];
      if (typeof v.remove == "function") v.remove();
    }
  }
};

export {
  NumericDensity
};
//# sourceMappingURL=chunk-WHI6466S.js.map
