Source: axis/AxisLabels.js

import {appendNewDiv, mergeOptions} from "Util";
import {AxisDefs, testAxisLocation, AxisLocation} from "axis/AxisDefs";
import Element from "Element";
export default AxisLabels;

/**
  * @constructor
  * @extends module:Element
  * @description
  * HTML element containing evenly spaced labels intended to be used as a subelement for {@link Axis}.
  * @todo We need some way to control precision, or at least provide an automatic human-readable value for label text
  * @param {AxisLabels.Options} userOptions User provided options for the axis which extends {@link module:Element~Options}
  */
function AxisLabels (userOptions) {

  /**
    * @typedef AxisLabels.Options
    *
    * @description
    * These are the options specific to this class. Other options provided by {@link Element.Options} can also be passed
    * to create an Axis.
    *
    * @property {AxisLocation} axis       Axis location
    * @property {Number[]} range          Min and max values of axis scale [min, max]
    * @property {Boolean} flipDirection   If true, the axis direction will be flipped with respect to the default
    *                                     direction
    * @property {Number} numLabels        Number of labels that will be displayed on the axis
    **/
  let options = mergeOptions({
    axis: AxisLocation.X_AXIS_BOTTOM,
    range: [-1, 1],
    flipDirection: false,
    numLabels: 5,

    /* Default options for base classes */
    class: "pgAxisLabels",
    style: {
      display: "flex",
      justifyContent: "space-between",
    }
  }, userOptions);

  /* @todo need to figure out this deserialization stuff in a consistent way. Right now, calling
  deserialize won't give the same result as creating an AxisLabels instance, due to parent deserializations
  not getting called */
  Element.call(this, options);
  this.deserialize(options);
}

AxisLabels.prototype = Object.assign( Object.create(Element.prototype), {

  /**
   * @memberof AxisLabels
   * @member
   * @description
   * Clear any existing, then append an equal number of labels, spaced evenly, to this element.
   *
   * @param {AxisLabels.Options} options User provided options for the axis
   */
  deserialize(options) {

    let _ = this;

    /* Labels are added left to right, and top to bottom. */
    testAxisLocation(options.axis);
    switch(options.axis) {
      case AxisLocation.X_AXIS_BOTTOM: /* fallthrough */
      case AxisLocation.X_AXIS_TOP:
        Object.assign(options.style, {
          flexDirection : "row",
          margin:"0px -1em 0px -1em"
        });
        /* X-axis, standard label direction is increasing to the right */
        this._largestFirst = options.flipDirection || false;
        break;
      case AxisLocation.Y_AXIS_LEFT: /* fallthrough */
      case AxisLocation.Y_AXIS_RIGHT:
        Object.assign(options.style, {
          flexDirection : "column",
          margin:"-0.5em 0px -0.5em 0px"
        });
        /* Y-axis, standard label direction is decreasing down */
        this._largestFirst = !(options.flipDirection || false);
        break;
    };
    Object.assign(this.element.style, options.style);

    this.element.innerHTML = "";
    console.assert(options.range.length == 2, "Range must be a [min, max] pair array.");
    let min = options.range[0];
    let max = options.range[1];
    let bounds = this.element.getBoundingClientRect();
    let axisSep = bounds.width/(options.numLabels-1);
    Object.assign(this.element.style, {"justify-content": "space-between"});

    for (let i =0; i < options.numLabels; i++) {
      let label = appendNewDiv(this.element, { style: {}});
      let magnitude = max - min;
      let text = this._largestFirst
        ? (max - magnitude * i/(options.numLabels-1)).toFixed(2)
        : (min + magnitude * i/(options.numLabels-1)).toFixed(2);
      label.innerHTML = text;
    }

  },
});