src/InteractEvent.js

import extend      from './utils/extend';
import getOriginXY from './utils/getOriginXY';
import defaults    from './defaultOptions';

class InteractEvent {
  /** */
  constructor (interaction, event, actionName, phase, element, related, preEnd, type) {
    element = element || interaction.element;

    const target      = interaction.target;
    const deltaSource = (target && target.options || defaults).deltaSource;
    const origin      = getOriginXY(target, element, actionName);
    const starting    = phase === 'start';
    const ending      = phase === 'end';
    const prevEvent   = starting? this : interaction.prevEvent;
    const coords      = starting
      ? interaction.startCoords
      : ending
        ? { page: prevEvent.page, client: prevEvent.client, timeStamp: interaction.curCoords.timeStamp }
        : interaction.curCoords;

    this.page      = extend({}, coords.page);
    this.client    = extend({}, coords.client);
    this.timeStamp = coords.timeStamp;

    if (!ending) {
      this.page.x -= origin.x;
      this.page.y -= origin.y;

      this.client.x -= origin.x;
      this.client.y -= origin.y;
    }

    this.ctrlKey       = event.ctrlKey;
    this.altKey        = event.altKey;
    this.shiftKey      = event.shiftKey;
    this.metaKey       = event.metaKey;
    this.button        = event.button;
    this.buttons       = event.buttons;
    this.target        = element;
    this.currentTarget = element;
    this.relatedTarget = related || null;
    this.preEnd        = preEnd;
    this.type          = type || (actionName + (phase || ''));
    this.interaction   = interaction;
    this.interactable  = target;

    this.t0 = starting
      ? interaction.pointers[interaction.pointers.length - 1].downTime
      : prevEvent.t0;

    this.x0       = interaction.startCoords.page.x - origin.x;
    this.y0       = interaction.startCoords.page.y - origin.y;
    this.clientX0 = interaction.startCoords.client.x - origin.x;
    this.clientY0 = interaction.startCoords.client.y - origin.y;

    if (starting || ending) {
      this.delta = { x: 0, y: 0 };
    }
    else {
      this.delta = {
        x: this[deltaSource].x - prevEvent[deltaSource].x,
        y: this[deltaSource].y - prevEvent[deltaSource].y,
      };
    }

    this.dt        = interaction.pointerDelta.timeStamp;
    this.duration  = this.timeStamp - this.t0;

    // speed and velocity in pixels per second
    this.speed = interaction.pointerDelta[deltaSource].speed;
    this.velocity = {
      x: interaction.pointerDelta[deltaSource].vx,
      y: interaction.pointerDelta[deltaSource].vy,
    };

    this.swipe = (ending || phase === 'inertiastart')? this.getSwipe() : null;
  }

  get pageX () { return this.page.x; }
  get pageY () { return this.page.y; }
  set pageX (value) { this.page.x = value; }
  set pageY (value) { this.page.y = value; }

  get clientX () { return this.client.x; }
  get clientY () { return this.client.y; }
  set clientX (value) { this.client.x = value; }
  set clientY (value) { this.client.y = value; }

  get dx () { return this.delta.x; }
  get dy () { return this.delta.y; }
  set dx (value) { this.delta.x = value; }
  set dy (value) { this.delta.y = value; }

  get velocityX () { return this.velocity.x; }
  get velocityY () { return this.velocity.y; }
  set velocityX (value) { this.velocity.x = value; }
  set velocityY (value) { this.velocity.y = value; }

  getSwipe () {
    const interaction = this.interaction;

    if (interaction.prevEvent.speed < 600
        || this.timeStamp - interaction.prevEvent.timeStamp > 150) {
      return null;
    }

    let angle = 180 * Math.atan2(interaction.prevEvent.velocityY, interaction.prevEvent.velocityX) / Math.PI;
    const overlap = 22.5;

    if (angle < 0) {
      angle += 360;
    }

    const left = 135 - overlap <= angle && angle < 225 + overlap;
    const up   = 225 - overlap <= angle && angle < 315 + overlap;

    const right = !left && (315 - overlap <= angle || angle <  45 + overlap);
    const down  = !up   &&   45 - overlap <= angle && angle < 135 + overlap;

    return {
      up,
      down,
      left,
      right,
      angle,
      speed: interaction.prevEvent.speed,
      velocity: {
        x: interaction.prevEvent.velocityX,
        y: interaction.prevEvent.velocityY,
      },
    };
  }

  preventDefault () {}

  /** */
  stopImmediatePropagation () {
    this.immediatePropagationStopped = this.propagationStopped = true;
  }

  /** */
  stopPropagation () {
    this.propagationStopped = true;
  }
}

export default InteractEvent;