blob: 773942a5ca39a77ef975e4a7d72dc630547641a5 [file] [log] [blame]
// 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 fengyuan@google.com (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);