positionErrorBarsAsLabels()

in code/bias-variance/js/ErrorBar.js [501:641]


  positionErrorBarsAsLabels() {
    const that = this;
    const nodeWidth = (d) => d.getBBox().width;
    // const rectOffset = window.innerWidth <= 600 ? 4 : 8;
    const rectOffsetX = window.innerWidth <= 600 ? 4 : 8;
    const rectOffsetY = window.innerWidth <= 600 ? 4 : 8;
    const symbolSpace =
      window.innerWidth <= 600 ? rectOffsetX * 1.5 : rectOffsetX * 2;
    const errorTransTime = 800;

    // update y-axis
    this.yScale.domain(["Test"]);

    // hide label rects behind main rect
    selectAll("rect.stacked").style("opacity", 0.7);
    selectAll(".decomp-text").style("opacity", 1);

    // position label rects
    selectAll("rect.stacked")
      .transition()
      .attr("x", (d) => this.textBox[d.error].x - rectOffsetX)
      .attr("y", (d) => this.textBox[d.error].y - rectOffsetY)
      .attr("width", (d) =>
        window.innerWidth <= 600
          ? this.textBox[d.error].width + 1.5 * rectOffsetX
          : this.textBox[d.error].width + 2 * rectOffsetX
      )
      .attr("height", (d) => this.textBox[d.error].height + 2 * rectOffsetY);

    let offset = 0;
    this.decompGs
      .transition()
      .duration(errorTransTime)
      .attr("transform", function (d) {
        // resolve x position for transition
        let x = offset;
        offset += that.textBox[d.error].width + 2.5 * rectOffsetX + symbolSpace;
        let currentxPos = that.decompAxis(d.error) - rectOffsetX * 2;
        let xPos = that.WIDTH / 10 - currentxPos;
        xPos += x;
        xPos = window.innerWidth <= 600 ? xPos - that.MARGIN.LEFT / 2.5 : xPos;
        // resolve y position for transition
        let currentYPos = that.yScale.bandwidth() / 2 + that.MARGIN.TOP;
        // that.yScale.bandwidth() / 2 + this.MARGIN.TOP
        const yPos = -currentYPos;
        // transition
        return `translate(${xPos}, ${yPos})`;
      })
      .selectAll(".decomp-text")
      .attr("text-anchor", "right");

    this.decompLegend.attr("transform", function () {
      return `translate(${(that.WIDTH - nodeWidth(this)) / 2}, 0)`;
    });

    // init error legend text to get position/bbox
    let errorText = this.decompLegend
      .append("text")
      .attr("id", "error-text")
      .attr("x", this.biasX)
      .attr("y", this.MARGIN.TOP)
      .text("Error")
      .style("font-family", "AmazonEmberDisplayHeavy")
      .style("opacity", 0);

    // get bbox balues of text
    let errorCoords = {};
    select("#error-text").each(function (d, i) {
      const textBox = this.getBBox();
      const width = textBox.width + 2 * rectOffsetX;
      const height = textBox.height + 2 * rectOffsetY;
      errorCoords["x"] = that.biasX - width;
      errorCoords["width"] = width;
      errorCoords["height"] = height;
      errorCoords["y"] = textBox.y;
    });
    // translate text to correct position given other elements and bbox
    errorText
      .transition()
      .attr(
        "x",
        window.innerWidth <= 600
          ? errorCoords.x - rectOffsetX - that.MARGIN.LEFT / 2.5
          : errorCoords.x - rectOffsetX
      )
      .attr("y", 0);
    // add background rectangle
    const errorTextRect = this.decompLegend
      .append("rect")
      .attr("class", "stacked-error")
      .attr("fill", "red")
      .attr(
        "x",
        window.innerWidth <= 600
          ? errorCoords.x - 2 * rectOffsetX - that.MARGIN.LEFT / 2.5
          : errorCoords.x - 2 * rectOffsetX
      )
      .attr("y", errorCoords.y - rectOffsetY - that.MARGIN.TOP)
      .attr("width", errorCoords.width)
      .attr("height", errorCoords.height)
      .lower()
      .style("opacity", 0);

    // ADD MATH SYMBOLS TO LEGEND
    // add '=' sign after error
    let errorTextEquals = this.decompLegend
      .append("text")
      .attr("class", "error-symbol")
      .attr(
        "x",
        window.innerWidth <= 600
          ? errorCoords.x +
              errorCoords.width -
              rectOffsetX -
              that.MARGIN.LEFT / 2.5
          : errorCoords.x + errorCoords.width - rectOffsetX
      )
      .attr("y", 0)
      .text("=")
      .style("font-family", "AmazonEmberDisplayHeavy")
      .style("opacity", 0);

    // add '+' signs
    let errorTextPlus = this.decompGs
      .filter((d, i) => i !== 0)
      .append("text")
      .attr("class", "error-symbol")
      .attr("x", (d) => this.textBox[d.error].x - rectOffsetX - symbolSpace)
      .attr("dx", window.innerWidth <= 600 ? -2 : 0)
      .attr("y", that.yScale.bandwidth() / 2 + this.MARGIN.TOP)
      .text("+")
      .style("font-family", "AmazonEmberDisplayHeavy")
      .style("opacity", 0);

    // transition elements to visibility
    const errorTextT = transition().delay(errorTransTime);

    errorText.transition(errorTextT).style("opacity", 1);
    selectAll(".error-symbol").transition(errorTextT).style("opacity", 0.9);
    errorTextRect.transition(errorTextT).style("opacity", 0.7);
  }