JSDoc: Source: runner/path/star.js

define([
  './path',
  './special_attr_path',
  './polygon',
  '../../tools'
], function(Path, SpecialAttrPath, Polygon, tools) {
  'use strict';
  Path.star = function(x, y, radius, rays, factor) {
    return new Path(new Star(x, y, radius, rays, factor).segments()).attr({
      x: x,
      y: y
    });
  };
  /**
   * Creates a star
   *
   * @constructor
   * @name Star
   * @memberOf module:path
   * @extends module:path.SpecialAttrPath
   * @param {Number} x The horizontal offset/translation of the star center.
   * @param {Number} y The vertical offset/translation of the star center.
   * @param {Number} radius The radius of the star
   * @param {Number} rays The number of rays of the star. Must be > 3
   * @param {Number} [factor] determines the star "pointiness".
   *    0: all rays start at (0, 0)
   *    1: the star looks like a regular polygon: 3 vertices are on a line.
   *    If omitted, a regular star is created
   */
  function Star(x, y, radius, rays, factor) {
    SpecialAttrPath.call(this, {
      radius: 0,
      rays: 0,
      factor: 0
    });
    this.attr({
      x: x,
      y: y,
      radius: radius,
      rays: rays,
      factor: factor
    });
  }
  /** @lends module:path.Star.prototype **/
  var proto = Star.prototype = Object.create(SpecialAttrPath.prototype);
  /**
   * Generates shape as per Star's properties in _attributes
   *
   * @private
   */
  proto._make = function() {
    var attr = this._attributes,
        x = attr.x,
        y = attr.y,
        rays = 0 | attr.rays,
        factor = attr.factor,
        radius = attr.radius;
    if (!(rays >= 3)) { // >= catches NaN, null, etc.
      throw RangeError('A star needs at least 3 rays.');
    }
    // use a polygon as starting point
    this.segments(new Polygon(x, y, radius, rays).segments());
    // make a star from it by inserting points
    var segments = this.segments();
    var from = segments[0], to;
    var starSegments = [from.slice()];
    /*
      If factor is not given, we default to a regular star.
      We create a regular star by connecting every `floor((rays - 1) / 2)` ray
      end point verteces.
    */
    if (!(factor >= 0 || factor < 0)) { // catches NaN, undefined etc.
      var b = segments[rays / 2 - .5 | 0];
      var ax = 0, ay = from[2], bx = b[1], by = b[2];
      to = segments[1];
      var qx = (ax + to[1]) / 2, qy = (ay + to[2]) / 2;
      //     y = x * (by - ay) / bx - radius
      //  && y = x * qy / qx
      //  => x * qy / qx = x * (by - ay) / bx + radius
      // <=> x = (qx * bx * -radius) / (qy * bx - qx * by + qx * ay)
      var ix = (qx * bx * -radius) / (qy * bx - qx * by + qx * ay);
      factor = ix / qx;
    }
    for (var i = 0; i < rays; i++) {
      to = segments[(i + 1) % rays];
      var fromX = from[1], fromY = from[2],
          toX = to[1], toY = to[2];
      starSegments.push(
        ['lineTo', (fromX + toX) / 2 * factor, (fromY + toY) / 2 * factor],
        to
      );
      from = to;
    }
    to[0] = 'closePath';
    to.length = 1;
    this.segments(starSegments);
  };
  return Star;
});