Home Reference Source

src/divisions/Cross.js

import Division from '../division';
import * as Utilities from '../utilities';
import settings from '../settings';

/**
 * Cross pattern.
 *
 * @class
 * @classdesc The Cross pattern describes two intersecting divisions of the field.
 * @augments Division
 * @namespace Divisions.Pales
 */
export default class Cross extends Division {

  constructor(params = {crossType, color, width, border: false, borderWidth, borderColor}) {
    const count = 1;
    const limit = 1;
    super({seed: params.seed, count, limit, color: params.color});
    this.crossType = typeof params.crossType !== 'undefined' ? params.crossType : this.generateCrossType(this.seed, this.seedMultiplier);
    this.crossWidth = params.width || this.generateCrossWidth(this.seed, this.seedMultiplier);
    this.border = params.border;
    this.borderWidth = params.borderWidth || this.generateBorderWidth(this.seed + this.seedMultiplier); // @todo Generate a border width
    // this.borderColor = params.border !== false ?
    this.borderColor = Utilities.generateColor(params.borderColor) || Utilities.generateColor(undefined, this.seed * this.seedMultiplier, this.seedMultiplier);
  }

  /**
   * Generates a "crossType" string.
   *
   * @example
   * // Returns 'greek'.
   * const newCross = new Cross();
   * newCross.generateCrossType(.123, .1);
   * @param {number} seed - A number less than one and more than 0 is expected.
   * @param {number} seedMultiplier - A number less than one and more than 0 is expected.
   * @returns {string} One of the available crossTypes: nordic, greek, symmetric.
   */
  generateCrossType(seed, seedMultiplier) {
    const crossTypes = ['nordic', 'greek', 'symmetric']
    // Generate a number between 0 & 2 to choose from the list of crossTypes.
    let choice = (seed * seedMultiplier * seed);
    let returnedChoice;
    // Let's be weird and loop over every digit in the multiplier and pick the last 0, 1, or 2.
    ('' + choice).split('').map((v, i) => {
      if (parseInt(v) === 0 || parseInt(v) === 1 || parseInt(v) === 2) {
        returnedChoice = crossTypes[parseInt(v)];
      }
    })
    return returnedChoice;
  }

  generateCrossWidth(seed, seedMultiplier) {
    const funcSeed = seed || this.seed;
    const funcSeedMultiplier = seedMultiplier || this.seedMultiplier;
    let width;
    width = Math.ceil(Utilities.modifySeed(funcSeed, funcSeedMultiplier) * 100) + 1; // Add one so we never have 0.
    if (width >= 100) {
      width = width / 2; // Cap width at 100, any larger and we lose the shape.
    }
    return width;
  }

  generateBorderWidth() {
    return this.crossWidth + (this.crossWidth * .6); // Return a border that's +6% of the cross' width.
  }

  draw(ctx) {
    switch(this.crossType) {
    case 'nordic':
      this.drawNordicCross(ctx);
      break;
    case 'greek':
      this.drawGreekCross(ctx);
      break;
    case 'symmetric':
      this.drawSymmetricCross(ctx);
      break;
    }
  }

  drawNordicCross(ctx) {

    const drawCross = (width, color) => {
      ctx.beginPath();
      // straight across.
      ctx.moveTo(0, settings.flagHeight/2);
      ctx.lineTo(settings.flagWidth, settings.flagHeight/2);
      // the vertical line.
      ctx.moveTo(settings.flagWidth / 3, 0);
      ctx.lineTo(settings.flagWidth / 3, settings.flagHeight);

      ctx.strokeStyle = color;
      ctx.lineWidth = width;
      ctx.stroke();
    }

    if (this.border === true && this.borderWidth > 0 && /^#/.test(this.borderColor.color)) {
      drawCross(this.borderWidth, this.borderColor.color);
      drawCross(this.crossWidth, this.color.color);
    } else {
      drawCross(this.crossWidth, this.color.color);
    }

  }

  drawGreekCross(ctx) {
    const lineLength = Utilities.findGreaterNumber(settings.flagWidth, settings.flagHeight) * .20; // 20% of either the flag height or width, whichever is greater.
    const borderLineLength = (lineLength + (this.borderWidth / 12)); // Divide by twelve because that's the number of edges.

    const drawCross = (width, color, extra = 0) => {
      ctx.beginPath();
      ctx.moveTo(settings.flagWidth / 2, settings.flagHeight/2); // move to center.
      ctx.lineTo((settings.flagWidth / 2) - (extra + +(extra - lineLength)), (settings.flagHeight / 2));
      ctx.moveTo(settings.flagWidth / 2, settings.flagHeight/2); // move to center.
      ctx.lineTo((settings.flagWidth / 2) + (extra + +(extra - lineLength)), (settings.flagHeight / 2));
      ctx.moveTo(settings.flagWidth / 2, settings.flagHeight / 2); // move to center.
      ctx.lineTo((settings.flagWidth / 2), (settings.flagHeight / 2) - (extra + +(extra - lineLength)));
      ctx.moveTo(settings.flagWidth / 2, settings.flagHeight / 2); // move to center.
      ctx.lineTo((settings.flagWidth / 2), (settings.flagHeight / 2) + (extra + +(extra - lineLength)));
      ctx.strokeStyle = color;
      ctx.lineWidth = width;
      ctx.stroke();
    }

    if (this.border === true && this.borderWidth > 0 && /^#/.test(this.borderColor.color)) {
      drawCross(this.borderWidth, this.borderColor.color, borderLineLength);
      drawCross(this.crossWidth, this.color.color);
    } else {
      drawCross(this.crossWidth, this.color.color);
    }

  }

  drawSymmetricCross(ctx) {

    const drawCross = (width, color) => {
      ctx.beginPath();
      // straight across.
      ctx.moveTo(0, settings.flagHeight/2);
      ctx.lineTo(settings.flagWidth, settings.flagHeight/2);
      // the vertical line.
      ctx.moveTo(settings.flagWidth / 2, 0);
      ctx.lineTo(settings.flagWidth / 2, settings.flagHeight);
      ctx.strokeStyle = color;
      ctx.lineWidth = width;
      ctx.stroke();
    }

    if (this.border === true && this.borderWidth > 0 && /^#/.test(this.borderColor.color)) {
      drawCross(this.borderWidth, this.borderColor.color);
      drawCross(this.crossWidth, this.color.color);
    } else {
      drawCross(this.crossWidth, this.color.color);
    }
  }

}