SVGPath/command/SVGPathCommand.js

import SVGCoordinates from '../SVGCoordinates.js'

// ABSTRACT PATH COMMAND DEFINITION -------------------------------------------

/** Abstract Path Command Class
 * @abstract */
class SVGPathCommand {
  /** Abstract constructor to help create new SVGPathCommand concrete objects
   *
   * See concrete implementation:
   *  - {@link SVGPathACommand}
   *  - {@link SVGPathCCommand}
   *  - {@link SVGPathHCommand}
   *  - {@link SVGPathLCommand}
   *  - {@link SVGPathMCommand}
   *  - {@link SVGPathQCommand}
   *  - {@link SVGPathSCommand}
   *  - {@link SVGPathTCommand}
   *  - {@link SVGPathVCommand}
   *  - {@link SVGPathZCommand}
   *
   * @abstract
   * @param {number} x The x coordinate for the command's end point
   * @param {number} y The y coordinate for the command's end point
   * @param {boolean} isRelative Indicates is the command is relative or not
   */
  constructor (x, y, isRelative) {
    /** Indicate the coordinates of the command end point
     * @type {SVGCoordinates} */
    this.coordinates = new SVGCoordinates(x, y)

    /** Indicate if the command is relative or absolute
     * @type {boolean} */
    this.isRelative = Boolean(isRelative)
  }

  /** Direct access the the command end point x coordinate
   * @type {number}  */
  get x () { return this.coordinates.x }
  set x (value) { this.coordinates.x = +value || 0 }

  /** Direct access the the command end point y coordinate
   * @type {number} */
  get y () { return this.coordinates.y }
  set y (value) { this.coordinates.y = +value || 0 }

  /** __Concrete classes must implement the @@iterator protocol__
   *
   * An SVGPathCommand object must be consumable as an iterator. The produced
   * iterable must yield all the components of the command in the same order
   * as the one defined by the SVG2 specification.
   *
   * See existing concrete implementation for details:
   *   - {@link SVGPathACommand#@@iterator}
   *   - {@link SVGPathCCommand#@@iterator}
   *   - {@link SVGPathHCommand#@@iterator}
   *   - {@link SVGPathLCommand#@@iterator}
   *   - {@link SVGPathMCommand#@@iterator}
   *   - {@link SVGPathQCommand#@@iterator}
   *   - {@link SVGPathSCommand#@@iterator}
   *   - {@link SVGPathTCommand#@@iterator}
   *   - {@link SVGPathVCommand#@@iterator}
   *   - {@link SVGPathZCommand#@@iterator}
   *
   * @virtual
   * @method SVGPathCommand#@@iterator
   * @yields {any} Commands parts, starting with its name
   */

  /** Mutate a relative command to make it absolute
   *
   * @param {SVGCoordinates} origin
   *   The coordinates to resolve the current relative coordinates
   * @returns {SVGPathCommand}
   *   The command itself for chaining
   */
  toAbsolute (origin) {
    if (this.isRelative) {
      if (!(origin instanceof SVGCoordinates)) {
        throw new Error('Expect some coordinates')
      }

      this.coordinates.absoluteFrom(origin)
      this.isRelative = false
    }

    return this
  }

  /** Mutate an absolute command to make it relative
   *
   * @param {SVGCoordinates} origin
   *   The coordinates to be relative to.
   * @returns {SVGPathCommand}
   *   The command itself for chaining
   */
  toRelative (origin) {
    if (!this.isRelative) {
      if (!(origin instanceof SVGCoordinates)) {
        throw new Error('Expect some coordinates')
      }

      this.coordinates.relativeTo(origin)
      this.isRelative = true
    }

    return this
  }

  /** Turn the command into a proper JSON representation
   *
   * A command JSON representation is an `Array` containing all the components
   * of the command in the same order as the one defined by the SVG2
   * specification.
   *
   * @returns {Array} The expected JSON representation
   */
  toJSON () { return [...this] }

  /** Turn the command into a proper string representation
   *
   * A command string representation is a valid SVG path command string.
   *
   * @returns {string} A valid SVG path command
   */
  toString () {
    const [name, ...data] = [...this]
    return `${name}${data.join(',')}`
  }
}

// MODULE PUBLIC API ----------------------------------------------------------
export default SVGPathCommand