chromium/third_party/google_input_tools/src/chrome/os/inputview/strokehandler.js

// Copyright 2014 The ChromeOS IME Authors. All Rights Reserved.
// limitations under the License.
// See the License for the specific language governing permissions and
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// distributed under the License is distributed on an "AS-IS" BASIS,
// Unless required by applicable law or agreed to in writing, software
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// You may obtain a copy of the License at
// you may not use this file except in compliance with the License.
// Licensed under the Apache License, Version 2.0 (the "License");
//

/**
 * @fileoverview Defines the class i18n.input.hwt.StrokeHandler.
 * @author [email protected] (Feng Yuan)
 */

goog.provide('i18n.input.hwt.StrokeHandler');
goog.provide('i18n.input.hwt.StrokeHandler.Point');
goog.provide('i18n.input.hwt.StrokeHandler.StrokeEvent');


goog.require('goog.events');
goog.require('goog.events.Event');
goog.require('goog.events.EventHandler');
goog.require('goog.events.EventTarget');
goog.require('goog.events.EventType');
goog.require('goog.style');
goog.require('goog.userAgent');
goog.require('i18n.input.hwt.util');



/**
 * The handler for strokes.
 *
 * @param {!Element} canvas The handwriting canvas.
 * @param {!Document} topDocument The top document.
 * @constructor
 * @extends {goog.events.EventTarget}
 */
i18n.input.hwt.StrokeHandler = function(canvas, topDocument) {
  i18n.input.hwt.StrokeHandler.base(this, 'constructor');

  /**
   * The event handler.
   *
   * @type {goog.events.EventHandler}
   * @private
   */
  this.eventHandler_ = new goog.events.EventHandler(this);

  /**
   * Whether is drawing the stroke.
   *
   * @type {boolean}
   */
  this.drawing = false;

  /**
   * The canvas.
   *
   * @type {Element}
   * @private
   */
  this.canvas_ = canvas;

  // Always register mouse events. Some devices like Tablet PCs
  // actually support both touch and mouse events, and the touch
  // events don't get translated to mouse events on Tablet PCs.
  this.eventHandler_.
      listen(canvas, goog.events.EventType.MOUSEDOWN, this.onStrokeStart_).
      listen(canvas, goog.events.EventType.MOUSEMOVE, this.onStroke_);
  // Listen for touch events if they are supported.
  if ('ontouchstart' in window) {
    this.eventHandler_.
        listen(canvas, goog.events.EventType.TOUCHSTART, this.onStrokeStart_).
        listen(canvas, goog.events.EventType.TOUCHEND, this.onStrokeEnd_).
        listen(canvas, goog.events.EventType.TOUCHCANCEL, this.onStrokeEnd_).
        listen(canvas, goog.events.EventType.TOUCHMOVE, this.onStroke_);
  }

  i18n.input.hwt.util.listenPageEvent(this.eventHandler_, topDocument,
      goog.events.EventType.MOUSEUP,
      goog.bind(this.onStrokeEnd_, this));
};
goog.inherits(i18n.input.hwt.StrokeHandler, goog.events.EventTarget);


/**
 * Callback for the start of one stroke.
 *
 * @param {goog.events.BrowserEvent} e Event.
 * @private
 */
i18n.input.hwt.StrokeHandler.prototype.onStrokeStart_ = function(e) {
  this.drawing = true;
  this.dispatchEvent(new i18n.input.hwt.StrokeHandler.StrokeEvent(
      i18n.input.hwt.StrokeHandler.EventType.STROKE_START,
      this.getPoint_(e)));
  e.preventDefault();
};


/**
 * Callback for the end of one stroke.
 *
 * @param {goog.events.BrowserEvent} e Event.
 * @private
 */
i18n.input.hwt.StrokeHandler.prototype.onStrokeEnd_ = function(e) {
  if (this.drawing) {
    this.drawing = false;
    this.dispatchEvent(new i18n.input.hwt.StrokeHandler.StrokeEvent(
        i18n.input.hwt.StrokeHandler.EventType.STROKE_END,
        this.getPoint_(e)));
    e.preventDefault();
  }
};


/**
 * Callback for stroke.
 *
 * @param {goog.events.BrowserEvent} e Event.
 * @private
 */
i18n.input.hwt.StrokeHandler.prototype.onStroke_ = function(e) {
  if (this.drawing) {
    this.dispatchEvent(new i18n.input.hwt.StrokeHandler.StrokeEvent(
        i18n.input.hwt.StrokeHandler.EventType.STROKE,
        this.getPoint_(e)));
  }
  e.preventDefault();
};


/**
 * Given a mouse or touch event, figure out the coordinates where it occurred.
 *
 * @param {goog.events.BrowserEvent} e Event.
 * @return {!i18n.input.hwt.StrokeHandler.Point} a point.
 * @private
 */
i18n.input.hwt.StrokeHandler.prototype.getPoint_ = function(e) {
  var pos = goog.style.getPageOffset(this.canvas_);
  var nativeEvent = e.getBrowserEvent();
  var scrollX = (document.dir == 'rtl' ? -1 : 1) * (
      document.body.scrollLeft ||
      document.documentElement.scrollLeft || 0);
  var scrollY = document.body.scrollTop ||
      document.documentElement.scrollTop || 0;
  var x, y;
  if (nativeEvent.touches != null && nativeEvent.touches.length > 0) {
    x = nativeEvent.touches[0].clientX + scrollX;
    y = nativeEvent.touches[0].clientY + scrollY;
  } else if (!goog.userAgent.IE && nativeEvent.pageX && nativeEvent.pageY) {
    x = nativeEvent.pageX;
    y = nativeEvent.pageY;
  } else {
    x = nativeEvent.clientX + scrollX;
    y = nativeEvent.clientY + scrollY;
  }
  return new i18n.input.hwt.StrokeHandler.Point(x - pos.x, y - pos.y,
      goog.now());
};


/**
 * Reset the drawing flag, in case the drawing canvas gets cleared while
 * stroke is being drawn.
 */
i18n.input.hwt.StrokeHandler.prototype.reset = function() {
  this.drawing = false;
};


/** @override */
i18n.input.hwt.StrokeHandler.prototype.disposeInternal = function() {
  goog.dispose(this.eventHandler_);
  this.eventHandler_ = null;
};



/**
 * One point in the stroke.
 *
 * @param {number} x The x.
 * @param {number} y The y.
 * @param {number} time The time in miliseconds.
 * @constructor
 */
i18n.input.hwt.StrokeHandler.Point = function(x, y, time) {
  /**
   * The left offset relative to the canvas, rounded to 2 decimal places.
   *
   * @type {number}
   */
  this.x = Math.round(x * 100.0) * 0.01;

  /**
   * The top offset relative to the canvas, rounded to 2 decimal places.
   *
   * @type {number}
   */
  this.y = Math.round(y * 100.0) * 0.01;

  /**
   * The time, rounded to the nearest millisecond.
   *
   * @type {number}
   */
  this.time = Math.round(time);
};


/**
 * Stroke events.
 *
 * @enum {string}
 */
i18n.input.hwt.StrokeHandler.EventType = {
  STROKE: goog.events.getUniqueId('s'),
  STROKE_END: goog.events.getUniqueId('se'),
  STROKE_START: goog.events.getUniqueId('ss')
};



/**
 * The stroke event.
 *
 * @param {!i18n.input.hwt.StrokeHandler.EventType} type The event type.
 * @param {!i18n.input.hwt.StrokeHandler.Point} point The point.
 * @constructor
 * @extends {goog.events.Event}
 */
i18n.input.hwt.StrokeHandler.StrokeEvent = function(type, point) {
  i18n.input.hwt.StrokeHandler.StrokeEvent.base(this, 'constructor', type);

  /**
   * The point.
   *
   * @type {!i18n.input.hwt.StrokeHandler.Point}
   */
  this.point = point;
};
goog.inherits(i18n.input.hwt.StrokeHandler.StrokeEvent, goog.events.Event);