Index: third_party/google_input_tools/src/chrome/os/inputview/elements/content/gesturestroke.js |
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/gesturestroke.js b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/gesturestroke.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f29d7fc9123d58bc4a66952d5249cef77c3bf010 |
--- /dev/null |
+++ b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/gesturestroke.js |
@@ -0,0 +1,309 @@ |
+// Copyright 2016 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 A single gesture typing stroke on the canvas. |
+ */ |
+goog.provide('i18n.input.chrome.inputview.elements.content.GestureStroke'); |
+ |
+goog.require('i18n.input.chrome.inputview.elements.content.Point'); |
+ |
+goog.scope(function() { |
+var Point = i18n.input.chrome.inputview.elements.content.Point; |
+ |
+ |
+ |
+/** |
+ * @constructor |
+ */ |
+i18n.input.chrome.inputview.elements.content.GestureStroke = |
+ function() { |
+ /** |
+ * The list of points that make up this stroke. |
+ * |
+ * @private {!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.GestureStroke; |
+ |
+ |
+/** |
+ * Rate at which the ttl should degrade for the fading stroke effect. |
+ * |
+ * @const {number} |
+ * @private |
+ */ |
+GestureStroke.DEGRADATION_RATE_ = 7; |
+ |
+ |
+/** |
+ * Distance threshold for when a stroke is considered active, in pixels. |
+ * TODO(stevet): This is temporary and needs to be updated with a dynamic value |
+ * that considers other parameters like the width of character keys. |
+ * |
+ * @const {number} |
+ * @private |
+ */ |
+GestureStroke.ACTIVE_THRESHOLD_ = 40; |
+ |
+ |
+/** |
+ * Starting red value. |
+ * |
+ * @const {number} |
+ * @private |
+ */ |
+GestureStroke.STARTING_R_VALUE_ = 68; |
+ |
+ |
+/** |
+ * Starting green value. |
+ * |
+ * @const {number} |
+ * @private |
+ */ |
+GestureStroke.STARTING_G_VALUE_ = 132; |
+ |
+ |
+/** |
+ * Starting blue value. |
+ * |
+ * @const {number} |
+ * @private |
+ */ |
+GestureStroke.STARTING_B_VALUE_ = 244; |
+ |
+ |
+/** |
+ * @const {number} |
+ * @private |
+ */ |
+GestureStroke.STROKE_MAX_WIDTH_ = 9; |
+ |
+ |
+/** |
+ * Returns a string that represents the color of the point based on the ttl in |
+ * a format usable as a canvas stroke style. |
+ * |
+ * @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 / Point.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 using the Pythagorean theorem. |
+ * Note that goog.math.Coordinate provides a distance method, but requires that |
+ * points are passed in as Coordinate objects. By defining a simple |
+ * implementation here, we avoid the cost of creating Coordinate objects |
+ * repeatedly. |
+ * |
+ * @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) { |
+ 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 / Point.STARTING_TTL; |
+ if (ratio < 0) { |
+ ratio = 0; |
+ } |
+ // Reduce the max width proportionately with the current ratio. |
+ return GestureStroke.STROKE_MAX_WIDTH_ * 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 allEmpty = true; |
+ for (var i = 0; i < this.points_.length; i++) { |
+ if (this.points_[i].ttl > 0) { |
+ this.points_[i].ttl -= GestureStroke.DEGRADATION_RATE_; |
+ allEmpty = false; |
+ } |
+ } |
+ return !allEmpty; |
+}; |
+ |
+ |
+/** |
+ * 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(); |
+ } |
+}; |
+ |
+ |
+/** |
+ * @param {number} i The index to look up. |
+ * @return {number} The identifier of the point at index i. |
+ */ |
+GestureStroke.prototype.getIdentifierAt = function(i) { |
+ return this.points_[i].identifier; |
+}; |
+ |
+ |
+/** |
+ * @param {number} i The index to look up. |
+ * @return {number} The time of the point at index i. |
+ */ |
+GestureStroke.prototype.getTimeAt = function(i) { |
+ return this.points_[i].time; |
+}; |
+ |
+ |
+/** |
+ * @return {!Array.<!Point>} The points stored in the stroke. |
+ */ |
+GestureStroke.prototype.getPoints = function() { |
+ return this.points_; |
+}; |
+ |
+ |
+/** |
+ * 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_; |
+}; |
+ |
+ |
+/** |
+ * @return {boolean} Whether or not the stroke is degraded. |
+ */ |
+GestureStroke.prototype.isDegraded = function() { |
+ var allPointsDegraded = true; |
+ for (var i = 0; i < this.points_.length; i++) { |
+ if (this.points_[i].ttl > 0) { |
+ allPointsDegraded = false; |
+ break; |
+ } |
+ } |
+ return allPointsDegraded; |
+}; |
+ |
+ |
+/** |
+ * @return {number} The length of the stroke, which is the number of points it |
+ * contains. |
+ */ |
+GestureStroke.prototype.length = function() { |
+ return this.points_.length; |
+}; |
+ |
+ |
+/** |
+ * 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); |
+}; |
+}); // goog.scope |