Source: axis/Axis.js

import {mergeOptions, newDiv} from "Util";
import Element from "Element";
import {AxisDefs, testAxisLocation, AxisLocation} from "axis/AxisDefs";
import AxisTitle from "axis/AxisTitle";
import AxisLabels from "axis/AxisLabels";
import AxisScale from "axis/AxisScale";
export default Axis;

/**
  * @constructor
  * @extends Element
  * @description
  * HTML element for drawing an axis with rules and labels. An axis can reside in any of the four border
  * locations around a plot body. (see {@link AxisLocation})
  *
  * @param {Axis.Options} userOptions Options for the axis which extends {@link Element.Options}
  */
function Axis(userOptions) {

  let _ = this;

  /**
    * @typedef Axis.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 axis labels.
    * @property {Number} numMajorTicks    Number of major ticks
    * @property {Number} numMinorTicks    Number of minor ticks (ticks between major ticks)
    **/
  const defaultOptions = {
    axis: AxisLocation.X_AXIS_BOTTOM,
    range:[-1, 1],
    flipDirection: false,
    numLabels: 5,
    numMajorTicks: 5,
    numMinorTicks: 3,

    /* Default options for base classes */
    visible:true,
    class:"pgAxis",
    style: {
      display:"flex",
    },
  }

  let options = mergeOptions(defaultOptions, userOptions);

  /* Flex direction depends on axis location. Modify this before calling parent constructor */
  testAxisLocation(options.axis);
  switch(options.axis) {
    case AxisLocation.X_AXIS_BOTTOM: /* fallthrough */
    case AxisLocation.X_AXIS_TOP:
      options.style.flexDirection = "column";
      break;
    case AxisLocation.Y_AXIS_LEFT: /* fallthrough */
    case AxisLocation.Y_AXIS_RIGHT:
      options.style.flexDirection = "row";
      break;
  }

  Element.call(this, options);

  /* Pass the same options to subelements, except let them set their own class and style.
   */
  let subOptions = JSON.parse(JSON.stringify(options));
  delete subOptions.class;
  delete subOptions.style;

  let axisScale = new AxisScale(subOptions);
  let axisLabels = new AxisLabels(subOptions);
  let axisTitle = new AxisTitle(subOptions);
  this.add([axisScale, axisLabels, axisTitle]);

  /* Append subelements in order, depending on axis location */
  let elements = [];
  switch(options.axis) {
    case AxisLocation.X_AXIS_BOTTOM: /* fallthrough */
    case AxisLocation.Y_AXIS_RIGHT:
      elements.push(axisScale.element, axisLabels.element, axisTitle.element);
      break;
    case AxisLocation.Y_AXIS_LEFT: /* fallthrough */
    case AxisLocation.X_AXIS_TOP:
      elements.push(axisTitle.element, axisLabels.element, axisScale.element);
      break;
  }

  for (let element of elements) {
    this.element.appendChild(element);
  }

  /**
   * @instance
   * @member title Axis title, drawn vertically or horizontally.
   * @memberof Axis
   **/
  Object.defineProperty(this, "title", {
    set: function(value){
      axisTitle.title = value;
    },
    get: function() {
      return axisTitle.title;
    }
  });

  /**
   * @member range Axis range
   * @memberof Axis
   * @instance
   * @type Number[]
   * @description A two element array containing the axis min and max values [min, max] as floating point numbers.
   **/
  Object.defineProperty(this, "range", {
    set: function(value) {
      options.range = value.slice();
      axisLabels.deserialize(options);
      _.onAxisChange();
    },
    get: function() {
      return options.range.slice();
    }
  });

  /**
   * @member flipDirection
   * @memberof Axis
   * @instance
   * @type Boolean
   * @description If set to true, axis scale will be flipped with respect to the default.
   *              The default axis direction increases left to right, and bottom to top.
   **/
  Object.defineProperty(this, "flipDirection", {
    set: function(value) {
      options.flipDirection = value;
      axisLabels.deserialize(options);
      _.onAxisChange();

    },
    get: function() {
      return options.flipDirection;
    }
  });

  /* Set default handlers */
  this.onAxisChange = function(){};
};

Axis.prototype = Object.assign( Object.create(Element.prototype), {});