| Index: third_party/google_input_tools/src/chrome/os/inputview/elements/content/gesturecanvasview.js
|
| diff --git a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/gesturecanvasview.js b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/gesturecanvasview.js
|
| index c6e391c880a3e9c5475ffacebc794c9dc61b5639..d3ae3340b796edbd70bee6e65458f976c44c783a 100644
|
| --- a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/gesturecanvasview.js
|
| +++ b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/gesturecanvasview.js
|
| @@ -11,21 +11,25 @@
|
| // you may not use this file except in compliance with the License.
|
| // Licensed under the Apache License, Version 2.0 (the "License");
|
| //
|
| +/**
|
| + * @fileoverview The canvas that handles gesture typing for inputview.
|
| + */
|
| goog.provide('i18n.input.chrome.inputview.elements.content.GestureCanvasView');
|
| -goog.provide('i18n.input.chrome.inputview.elements.content.GestureCanvasView.GestureStroke');
|
| -goog.provide('i18n.input.chrome.inputview.elements.content.GestureCanvasView.Point');
|
|
|
| -goog.require('goog.async.Delay');
|
| goog.require('goog.dom.TagName');
|
| goog.require('goog.dom.classlist');
|
| goog.require('goog.style');
|
| +goog.require('i18n.input.chrome.ElementType');
|
| goog.require('i18n.input.chrome.inputview.Css');
|
| goog.require('i18n.input.chrome.inputview.elements.Element');
|
| -goog.require('i18n.input.chrome.inputview.elements.ElementType');
|
| +goog.require('i18n.input.chrome.inputview.elements.content.GestureStroke');
|
| +goog.require('i18n.input.chrome.inputview.elements.content.Point');
|
|
|
| goog.scope(function() {
|
| var Css = i18n.input.chrome.inputview.Css;
|
| -var ElementType = i18n.input.chrome.inputview.elements.ElementType;
|
| +var ElementType = i18n.input.chrome.ElementType;
|
| +var GestureStroke = i18n.input.chrome.inputview.elements.content.GestureStroke;
|
| +var Point = i18n.input.chrome.inputview.elements.content.Point;
|
| var TagName = goog.dom.TagName;
|
|
|
|
|
| @@ -33,7 +37,8 @@ var TagName = goog.dom.TagName;
|
| /**
|
| * The gesture canvas view.
|
| *
|
| - * This view is used to display the strokes for gesture typing.
|
| + * This view is used to display the strokes for gesture typing, and handles
|
| + * stroke lifetime management and rendering logic.
|
| *
|
| * @param {goog.events.EventTarget=} opt_eventTarget The parent event target.
|
| * @constructor
|
| @@ -68,332 +73,17 @@ i18n.input.chrome.inputview.elements.content.GestureCanvasView =
|
| /**
|
| * A list of list of gesture points to be rendered on the canvas as strokes.
|
| *
|
| - * @private {!Array<GestureStroke>}
|
| + * @private {!Array<!GestureStroke>}
|
| */
|
| this.strokeList_ = [];
|
| -
|
| - /** @private {!goog.async.Delay} */
|
| - this.animator_ = new goog.async.Delay(this.animateGestureTrail_, 0, this);
|
| };
|
| var GestureCanvasView =
|
| i18n.input.chrome.inputview.elements.content.GestureCanvasView;
|
| goog.inherits(GestureCanvasView, i18n.input.chrome.inputview.elements.Element);
|
|
|
|
|
| -
|
| -/**
|
| - * A single stroke on the canvas.
|
| - *
|
| - * @constructor
|
| - */
|
| -i18n.input.chrome.inputview.elements.content.GestureCanvasView.GestureStroke =
|
| - function() {
|
| - /**
|
| - * The list of points that make up this stroke.
|
| - *
|
| - * @type {!Array.<!Point>}
|
| - */
|
| - this.points = [];
|
| -
|
| - /**
|
| - * Whether or not this stroke is considered active. i.e. whether or not it
|
| - * should be considered for rendering and decoding.
|
| - *
|
| - * @private {boolean}
|
| - */
|
| - this.isActive_ = false;
|
| -
|
| - /**
|
| - * The time the first point was added to this stroke. Used to keep all points
|
| - * relative to the first point.
|
| - *
|
| - * @private {number}
|
| - */
|
| - this.firstTime_ = 0;
|
| -};
|
| -var GestureStroke =
|
| - i18n.input.chrome.inputview.elements.content.GestureCanvasView
|
| - .GestureStroke;
|
| -
|
| -
|
| -/**
|
| - * Rate at which the ttl should degrade for the fading stroke effect.
|
| - *
|
| - * @const {number}
|
| - */
|
| -GestureStroke.DEGRADATION_RATE = 5;
|
| -
|
| -
|
| -/**
|
| - * Starting time-to-live value.
|
| - *
|
| - * @const {number}
|
| - */
|
| -GestureStroke.STARTING_TTL = 255;
|
| -
|
| -
|
| -// TODO(stevet): This is temporary and needs to be updated with a dynamic value
|
| -// that considers other parameters like the width of character keys.
|
| -/**
|
| - * Distance threshold for when a stroke is considered active, in pixels.
|
| - *
|
| - * @const {number}
|
| - */
|
| -GestureStroke.ACTIVE_THRESHOLD = 40;
|
| -
|
| -
|
| -/**
|
| - * Starting red value.
|
| - *
|
| - * @const {number}
|
| - */
|
| -GestureStroke.STARTING_R_VALUE = 0;
|
| -
|
| -
|
| -/**
|
| - * Starting green value.
|
| - *
|
| - * @const {number}
|
| - */
|
| -GestureStroke.STARTING_G_VALUE = 180;
|
| -
|
| -
|
| -/**
|
| - * Starting blue value.
|
| - *
|
| - * @const {number}
|
| - */
|
| -GestureStroke.STARTING_B_VALUE = 204;
|
| -
|
| -
|
| -/**
|
| - * Calculates the color of the point based on the ttl.
|
| - *
|
| - * @param {number} ttl The time to live of the point.
|
| - * @return {string} The color to use for the point.
|
| - * @private
|
| - */
|
| -GestureStroke.calculateColor_ = function(ttl) {
|
| - // TODO(maxw): Use this percentage to fade the stroke color.
|
| - var remainingTtlPercentage = ttl / GestureStroke.STARTING_TTL;
|
| - var rValue = GestureStroke.STARTING_R_VALUE;
|
| - var gValue = GestureStroke.STARTING_G_VALUE;
|
| - var bValue = GestureStroke.STARTING_B_VALUE;
|
| - return 'rgb(' + rValue + ', ' + gValue + ', ' + bValue + ')';
|
| -};
|
| -
|
| -
|
| -/**
|
| - * Calculates the distance between two points.
|
| - *
|
| - * @param {!Point} first The first point.
|
| - * @param {!Point} second The second point.
|
| - * @return {number} The number of pixels between first and second.
|
| - * @private
|
| - */
|
| -GestureStroke.calculateDistance_ = function(first, second) {
|
| - // Simply use the Pythagorean.
|
| - var a = Math.abs(first.x - second.x);
|
| - var b = Math.abs(first.y - second.y);
|
| - return Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));
|
| -};
|
| -
|
| -
|
| -/**
|
| - * Calculates the line width of the point based on the ttl.
|
| - *
|
| - * @param {number} ttl The time to live of the point.
|
| - * @return {number} The line width to use for the point.
|
| - * @private
|
| - */
|
| -GestureStroke.calculateLineWidth_ = function(ttl) {
|
| - var ratio = ttl / GestureStroke.STARTING_TTL;
|
| - if (ratio < 0) {
|
| - ratio = 0;
|
| - }
|
| - return 9 * ratio;
|
| -};
|
| -
|
| -
|
| -/**
|
| - * Degrades all the points in this stroke.
|
| - *
|
| - * @return {boolean} Returns true if it was possible to degrade one or more
|
| - * points, otherwise it means that this stroke is now empty.
|
| - */
|
| -GestureStroke.prototype.degrade = function() {
|
| - var all_empty = true;
|
| - for (var i = 0; i < this.points.length; i++) {
|
| - if (this.points[i].ttl > 0) {
|
| - this.points[i].ttl -= GestureStroke.DEGRADATION_RATE;
|
| - all_empty = false;
|
| - }
|
| - }
|
| - return !all_empty;
|
| -};
|
| -
|
| -
|
| -/**
|
| - * Draw the gesture trail for this stroke onto the canvas context.
|
| - *
|
| - * @param {!CanvasRenderingContext2D} context The drawing context to render to.
|
| - */
|
| -GestureStroke.prototype.draw = function(context) {
|
| - // Only start drawing active strokes. Note that TTL still updates even if a
|
| - // stroke is not yet active.
|
| - if (!this.isActive()) {
|
| - return;
|
| - }
|
| -
|
| - for (var i = 1; i < this.points.length; i++) {
|
| - var first = this.points[i - 1];
|
| - var second = this.points[i];
|
| - // All rendering calculations are based on the second point in the segment
|
| - // because there must be at least two points for something to be rendered.
|
| - var ttl = second.ttl;
|
| - if (ttl <= 0) {
|
| - continue;
|
| - }
|
| -
|
| - context.beginPath();
|
| - context.moveTo(first.x, first.y);
|
| - context.lineTo(second.x, second.y);
|
| - context.strokeStyle = GestureStroke.calculateColor_(ttl);
|
| - context.fillStyle = 'none';
|
| - context.lineWidth = GestureStroke.calculateLineWidth_(ttl);
|
| - context.lineCap = 'round';
|
| - context.lineJoin = 'round';
|
| - context.stroke();
|
| - }
|
| -};
|
| -
|
| -
|
| /**
|
| - * Returns true iff this stroke is considered "active". This means that it has
|
| - * passed a certain threshold and should be considered for rendering and
|
| - * decoding.
|
| - *
|
| - * @return {boolean} Whether or not the stroke is active.
|
| - */
|
| -GestureStroke.prototype.isActive = function() {
|
| - // Once a stroke is active, it remains active.
|
| - if (this.isActive_) {
|
| - return this.isActive_;
|
| - }
|
| -
|
| - if (this.points.length < 2) {
|
| - return false;
|
| - }
|
| -
|
| - // Calculate the distance between the first point and the latest one.
|
| - this.isActive_ = GestureStroke.calculateDistance_(
|
| - this.points[0], this.points[this.points.length - 1]) >
|
| - GestureStroke.ACTIVE_THRESHOLD;
|
| -
|
| - return this.isActive_;
|
| -};
|
| -
|
| -
|
| -/**
|
| - * Add a point to this stroke.
|
| - *
|
| - * @param {Point} p The point to add to this stroke.
|
| - */
|
| -GestureStroke.prototype.pushPoint = function(p) {
|
| - if (this.points.length == 0) {
|
| - this.firstTime_ = p.time;
|
| - }
|
| - // Convert the timestamp so it is relative to the first point, including
|
| - // setting the first point to zero.
|
| - p.time -= this.firstTime_;
|
| - this.points.push(p);
|
| -};
|
| -
|
| -
|
| -
|
| -/**
|
| - * One point in the gesture stroke.
|
| - *
|
| - * This class is used for both rendering the gesture stroke, and also for
|
| - * transmitting the stroke coordinates to the recognizer for decoding.
|
| - *
|
| - * @param {number} x The x coordinate.
|
| - * @param {number} y The y coordinate.
|
| - * @param {number} identifier The pointer event identifier.
|
| - * @constructor
|
| - */
|
| -i18n.input.chrome.inputview.elements.content.GestureCanvasView.Point =
|
| - function(x, y, identifier) {
|
| - /**
|
| - * The left offset relative to the canvas.
|
| - *
|
| - * @type {number}
|
| - */
|
| - this.x = x;
|
| -
|
| - /**
|
| - * The top offset relative to the canvas.
|
| - *
|
| - * @type {number}
|
| - */
|
| - this.y = y;
|
| -
|
| - /**
|
| - * The pointer ID.
|
| - *
|
| - * @type {number}
|
| - */
|
| - this.pointer = 0;
|
| -
|
| - /**
|
| - * The time-to-live value of the point, used to render the trail fading
|
| - * effect.
|
| - *
|
| - * @type {number}
|
| - */
|
| - this.ttl = GestureStroke.STARTING_TTL;
|
| -
|
| - /**
|
| - * The time this point was created, in ms since epoch.
|
| - *
|
| - * @type {number}
|
| - */
|
| - this.time = Date.now();
|
| -
|
| - /**
|
| - * The action type of the point.
|
| - *
|
| - * @type {i18n.input.chrome.inputview.elements.content.GestureCanvasView.
|
| - * Point.Action}
|
| - */
|
| - this.action = i18n.input.chrome.inputview.elements.content.GestureCanvasView.
|
| - Point.Action.ACTION_MOVE;
|
| -
|
| - /**
|
| - * The pointer event identifier associated with this point.
|
| - *
|
| - * @type {number}
|
| - */
|
| - this.identifier = identifier;
|
| -};
|
| -var Point =
|
| - i18n.input.chrome.inputview.elements.content.GestureCanvasView.Point;
|
| -
|
| -
|
| -/**
|
| - * Enum describing the type of action for a given point.
|
| - *
|
| - * @enum {number}
|
| - */
|
| -Point.Action = {
|
| - ACTION_DOWN: 0,
|
| - ACTION_UP: 1,
|
| - ACTION_MOVE: 2
|
| -};
|
| -
|
| -
|
| -/**
|
| - * Draw the gesture trail.
|
| + * Draws the gesture trail.
|
| *
|
| * @private
|
| */
|
| @@ -410,7 +100,8 @@ GestureCanvasView.prototype.draw_ = function() {
|
|
|
| /** @override */
|
| GestureCanvasView.prototype.createDom = function() {
|
| - goog.base(this, 'createDom');
|
| + GestureCanvasView.base(this, 'createDom');
|
| +
|
| var dom = this.getDomHelper();
|
| var elem = this.getElement();
|
| goog.dom.classlist.add(elem, Css.GESTURE_CANVAS_VIEW);
|
| @@ -420,7 +111,7 @@ GestureCanvasView.prototype.createDom = function() {
|
| this.drawingContext_ = this.drawingCanvas_.getContext('2d');
|
| dom.appendChild(elem, this.drawingCanvas_);
|
|
|
| - this.animator_.start();
|
| + window.requestAnimationFrame(this.animateGestureTrail_.bind(this));
|
| };
|
|
|
|
|
| @@ -446,14 +137,13 @@ GestureCanvasView.prototype.addPoint = function(e) {
|
| // if the user is gesturing. Only check the last stroke and not all the
|
| // strokes because all previous strokes might be rendering/degrading, but that
|
| // does not determine if the user is currently gesturing.
|
| - var was_active = this.latestStrokeActive_();
|
| + var wasActive = this.latestStrokeActive_();
|
|
|
| if (this.strokeList_.length == 0) {
|
| this.strokeList_.push(new GestureStroke());
|
| }
|
| var lastStroke = this.strokeList_[this.strokeList_.length - 1];
|
| - if (lastStroke.points.length > 0 &&
|
| - e.identifier != lastStroke.points[0].identifier) {
|
| + if (lastStroke.length() > 0 && !this.isActiveIdentifier(e.identifier)) {
|
| // Should only add new points with the same identifier. This ignores pointer
|
| // events created by, say, a second finger interacting with the screen while
|
| // an existing gesture is going on.
|
| @@ -462,14 +152,14 @@ GestureCanvasView.prototype.addPoint = function(e) {
|
| lastStroke.pushPoint(this.createGesturePoint_(e));
|
|
|
| // If the new point |e| activated the last stroke, set gesturing to true.
|
| - if (!was_active && this.latestStrokeActive_()) {
|
| + if (!wasActive && this.latestStrokeActive_()) {
|
| this.isGesturing = true;
|
| }
|
| };
|
|
|
|
|
| /**
|
| - * Clear the view.
|
| + * Clears the view.
|
| */
|
| GestureCanvasView.prototype.clear = function() {
|
| this.strokeList_ = [];
|
| @@ -478,8 +168,6 @@ GestureCanvasView.prototype.clear = function() {
|
|
|
|
|
| /**
|
| - * Returns true iff the last stroke is currently active.
|
| - *
|
| * @return {boolean} Whether or not the last stroke is active.
|
| * @private
|
| */
|
| @@ -495,24 +183,23 @@ GestureCanvasView.prototype.latestStrokeActive_ = function() {
|
| * Begins a new gesture.
|
| *
|
| * @param {!i18n.input.chrome.inputview.events.PointerEvent} e Drag event to
|
| - * draw.
|
| + * draw.
|
| */
|
| GestureCanvasView.prototype.startStroke = function(e) {
|
| // If there is currently a stroke and it does not match the identifier of this
|
| // new point, then ignore this call. This is to prevent a second finger from
|
| // interrupting an existing stroke.
|
| - if (this.strokeList_.length > 0 &&
|
| - e.identifier != this.strokeList_[this.strokeList_.length - 1].points[0]
|
| - .identifier) {
|
| + if (this.strokeList_.length > 0 && !this.isActiveIdentifier(e.identifier)) {
|
| return;
|
| }
|
| // Always start a new array to separate previous strokes from this new one.
|
| this.strokeList_.push(new GestureStroke());
|
| var point = this.createGesturePoint_(e);
|
| - point.action = Point.Action.ACTION_DOWN;
|
| - // TODO: This line is a NOP since createGesturePoint_ already assigns the
|
| - // pointer value, but it must be called to prevent closure from optimizing out
|
| - // the pointer member. This needs to be fixed to use the true pointer ID of e.
|
| + point.action = Point.Action.DOWN;
|
| + // TODO(stevet): This line is a NOP since createGesturePoint_ already assigns
|
| + // the pointer value, but it must be called to prevent closure from optimizing
|
| + // out the pointer member. This needs to be fixed to use the true pointer ID
|
| + // of e.
|
| point.pointer = 0;
|
| this.strokeList_[this.strokeList_.length - 1].pushPoint(point);
|
| };
|
| @@ -525,18 +212,18 @@ GestureCanvasView.prototype.startStroke = function(e) {
|
| * event to handle.
|
| */
|
| GestureCanvasView.prototype.endStroke = function(e) {
|
| - // TODO: Ensure that this gets called even when the final touch event
|
| - // is not on the client.
|
| + // TODO(stevet): Ensure that this gets called even when the final touch event
|
| + // is not on the client.
|
|
|
| // Ignore points that do not have the same identifier.
|
| if (e.identifier !=
|
| - this.strokeList_[this.strokeList_.length - 1].points[0].identifier) {
|
| + this.strokeList_[this.strokeList_.length - 1].getIdentifierAt(0)) {
|
| return;
|
| }
|
|
|
| // Send the final event.
|
| var point = this.createGesturePoint_(e);
|
| - point.action = Point.Action.ACTION_UP;
|
| + point.action = Point.Action.UP;
|
| this.strokeList_[this.strokeList_.length - 1].pushPoint(point);
|
| this.isGesturing = false;
|
| };
|
| @@ -556,18 +243,41 @@ GestureCanvasView.prototype.getLastStroke = function() {
|
|
|
|
|
| /**
|
| - * The gesture trail animation function.
|
| + * @param {number} identifier The identifier to check.
|
| + * @return {boolean} Whether or not identifier is the same as the identifier of
|
| + * the current active stroke.
|
| + */
|
| +GestureCanvasView.prototype.isActiveIdentifier = function(identifier) {
|
| + return identifier == this.strokeList_[this.strokeList_.length - 1]
|
| + .getIdentifierAt(0);
|
| +};
|
| +
|
| +
|
| +/**
|
| + * Removes only empty strokes from the stroke list.
|
| + */
|
| +GestureCanvasView.prototype.removeEmptyStrokes = function() {
|
| + for (var i = 0; i < this.strokeList_.length; i++) {
|
| + if (this.strokeList_[i].isDegraded()) {
|
| + this.strokeList_.splice(i, 1);
|
| + i--;
|
| + }
|
| + }
|
| +};
|
| +
|
| +
|
| +/**
|
| + * Animates the gesture trail.
|
| *
|
| * @private
|
| */
|
| GestureCanvasView.prototype.animateGestureTrail_ = function() {
|
| - // TODO(stevet): This approximates drawing at 60fps. Refactor this and the
|
| - // voice input code to use a common call to requestRenderFrame.
|
| - var timeStep = 16;
|
| -
|
| + // TODO(stevet): Currently these two methods assume callback at 60fps. They
|
| + // should technically be modified to re-draw and update based on the actual
|
| + // time passed.
|
| this.draw_();
|
| this.degradeStrokes_();
|
| - this.animator_.start(timeStep);
|
| + window.requestAnimationFrame(this.animateGestureTrail_.bind(this));
|
| };
|
|
|
|
|
| @@ -575,9 +285,9 @@ GestureCanvasView.prototype.animateGestureTrail_ = function() {
|
| * Returns a gesture point for a given event, with the correct coordinates.
|
| *
|
| * @param {!i18n.input.chrome.inputview.events.DragEvent|
|
| - * i18n.input.chrome.inputview.events.PointerEvent} e The event to
|
| - * convert.
|
| - * @return {Point} The converted gesture point.
|
| + * i18n.input.chrome.inputview.events.PointerEvent} e The event to
|
| + * convert.
|
| + * @return {!Point} The converted gesture point.
|
| * @private
|
| */
|
| GestureCanvasView.prototype.createGesturePoint_ = function(e) {
|
| @@ -593,13 +303,7 @@ GestureCanvasView.prototype.createGesturePoint_ = function(e) {
|
| */
|
| GestureCanvasView.prototype.degradeStrokes_ = function() {
|
| for (var i = 0; i < this.strokeList_.length; i++) {
|
| - // In the case where all points in the list are empty, dispose of the first.
|
| - if (!this.strokeList_[i].degrade()) {
|
| - this.strokeList_.splice(i, 1);
|
| - i--;
|
| - }
|
| + this.strokeList_[i].degrade();
|
| }
|
| };
|
| -
|
| -
|
| }); // goog.scope
|
|
|