Source: Divider.js

//////////////////////////////////////////////////////////////////////////////
// Divider
//////////////////////////////////////////////////////////////////////////////

import CGObject from './CGObject';
import CGArray from './CGArray';
import Color from './Color';
import utils from './Utils';

/**
 * A divider is the line and spacing that separate tracks and slot.
 *
 * There are two type of dividers: slot and track. They are accessed from the
 * viewer [dividers](Dividers.html) object:
 * - cgv.dividers.track - controlls spacing/lines between tracks.
 * - cgv.dividers.slot - controls spacing/lines betweens slots within a track.
 *
 * If either track or slot has their mirror set to true, then both dividers will be treated as the same.
 * In addition, if only settings for one of the dividers is provided on Viewer creation, then it will be mirrored.
 *
 * ### Action and Events
 *
 * Action                                  | Viewer Method                    | Divider Method      | Event
 * ----------------------------------------|----------------------------------|---------------------|-----
 * [Update](../docs.html#updating-records) | -                                | [update()](#update) | divider-update
 * [Read](../docs.html#reading-records)    | [dividers](Viewer.html#dividers) | -                   | -
 *
 * <a name="attributes"></a>
 * ### Attributes
 *
 * Attribute                        | Type      | Description
 * ---------------------------------|-----------|------------
 * [color](#color)                  | String    | A string describing the color [Default: 'black']. See {@link Color} for details.
 * [thickness](#thickness)          | Number    | Thickness of divider [Default: 1]
 * [spacing](#spacing)              | Number    | Spacing between divider and track/slot content [Default: 1]
 * [mirror](#mirror)<sup>ic</sup>   | Boolean   | If true, the other dividers will use the same settings as this divider.
 * [visible](CGObject.html#visible) | Boolean   | Dividers are visible [Default: true]
 * [meta](CGObject.html#meta)       | Object    | [Meta data](../tutorials/details-meta-data.html) for divider
 * 
 * <sup>ic</sup> Ignored on Record creation
 *
 * ### Examples
 *
 * @extends CGObject
 */
class Divider extends CGObject {

  /**
   * Create a divider
   * @param {Viewer} viewer - The viewer
   * @param {String} name - The name for the divider. One of: track, slot, or mirrored.
   * @param {Object} options - [Attributes](#attributes) used to create the divider
   * @param {Object} [meta] - User-defined [Meta data](../tutorials/details-meta-data.html) to add to the divider
   */
  constructor(viewer, name, options = {}, meta = {}) {
    super(viewer, options, meta);
    this.color = utils.defaultFor(options.color, 'grey');
    this._thickness = utils.defaultFor(options.thickness, 1);
    this._spacing = utils.defaultFor(options.spacing, 1);
    this._name = name;
    this._bbOffsets = new CGArray();
    this.viewer.trigger('divider-update', { divider: this, attributes: this.toJSON({includeDefaults: true}) });
  }

  /**
   * Return the class name as a string.
   * @return {String} - 'Divider'
   */
  toString() {
    return 'Divider';
  }

  /**
   * Return name of divider (e.g. 'track' or 'slot')
   */
  get name() {
    return this._name;
  }

  /**
   * @member {Boolean} - Get or Set the visibility of this object.
   */
  get visible() {
    return this._visible;
  }

  set visible(value) {
    this._visible = value;
    this.viewer.layout && this.viewer.layout._adjustProportions();
  }

  /**
   * @member {Color} - Get or set the divider color. When setting the color, a string representing the color or a {@link Color} object can be used. For details see {@link Color}.
   */
  get color() {
    return this._color;
  }

  set color(value) {
    if (value.toString() === 'Color') {
      this._color = value;
    } else {
      this._color = new Color(value);
    }
  }

  /**
   * @member {Number} - Set or get the divider thickness. This is the unzoomed thickness.
   */
  set thickness(value) {
    if (value !== undefined) {
      // this._thickness = Math.round(value);
      this._thickness = value;
      this.viewer.layout._adjustProportions();
    }
  }

  get thickness() {
    return this._thickness;
  }

  /**
   * @member {Number} - Get the divider thickness adjusted for visibility and zoom level.
   */
  get adjustedThickness() {
    if (!this.visible) { return 0; }
    return (this.viewer.zoomFactor < 1) ? (this._thickness * this.viewer.zoomFactor) : this._thickness;
  }

  /**
   * @member {Number} - Set or get the divider spacing.
   */
  set spacing(value) {
    if (value !== undefined) {
      this._spacing = Math.round(value);
      this.viewer.layout._adjustProportions();
    }
  }

  get spacing() {
    return this._spacing;
  }

  /**
   * @member {Number} - Get the divider spacing adjusted for zoom level. Even if the divider
   * is not visible, there can still be spacing between the slots/tracks.
   */
  get adjustedSpacing() {
    return (this.viewer.zoomFactor < 1) ? (this._spacing * this.viewer.zoomFactor) : this._spacing;
  }

  /**
   * @member {Boolean} - Get or set the mirroring for this divider.
   * When setting to true, the other divider will be mirrored to this one.
   */
  get mirror() {
    return this.viewer.dividers.dividersMirrored;
  }

  set mirror(value) {
    this._mirror = value;
    if (value === true) {
      // Mirror other divider to this one
      this.viewer.dividers.mirrorDivider(this);
    } else {
      // Turns off mirroring
      this.viewer.dividers.mirrorDivider();
    }
  }

  /**
   * Update divider [attributes](#attributes).
   * See [updating records](../docs.html#s.updating-records) for details.
   * @param {Object} attributes - Object describing the properties to change
   */
  update(attributes) {
    const { records: dividers, updates } = this.viewer.updateRecords(this, attributes, {
      recordClass: 'Divider',
      validKeys: ['visible', 'color', 'thickness', 'spacing', 'mirror']
    });
    this.viewer.trigger('divider-update', { divider: this, attributes, updates });
  }

  toJSON() {
    return {
      visible: this.visible,
      color: this.color.rgbaString,
      thickness: this.thickness,
      spacing: this.spacing
    };
  }

}

export default Divider;