| // Copyright 2007 The Closure Library Authors. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS-IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| |
| /** |
| * @fileoverview Objects representing shapes drawn on a canvas. |
| * @author robbyw@google.com (Robby Walker) |
| */ |
| |
| goog.provide('goog.graphics.CanvasEllipseElement'); |
| goog.provide('goog.graphics.CanvasGroupElement'); |
| goog.provide('goog.graphics.CanvasImageElement'); |
| goog.provide('goog.graphics.CanvasPathElement'); |
| goog.provide('goog.graphics.CanvasRectElement'); |
| goog.provide('goog.graphics.CanvasTextElement'); |
| |
| |
| goog.require('goog.array'); |
| goog.require('goog.dom'); |
| goog.require('goog.dom.TagName'); |
| goog.require('goog.dom.safe'); |
| goog.require('goog.graphics.EllipseElement'); |
| goog.require('goog.graphics.GroupElement'); |
| goog.require('goog.graphics.ImageElement'); |
| goog.require('goog.graphics.Path'); |
| goog.require('goog.graphics.PathElement'); |
| goog.require('goog.graphics.RectElement'); |
| goog.require('goog.graphics.TextElement'); |
| goog.require('goog.html.SafeHtml'); |
| goog.require('goog.html.uncheckedconversions'); |
| goog.require('goog.math'); |
| goog.require('goog.string'); |
| goog.require('goog.string.Const'); |
| |
| |
| |
| /** |
| * Object representing a group of objects in a canvas. |
| * This is an implementation of the goog.graphics.GroupElement interface. |
| * You should not construct objects from this constructor. The graphics |
| * will return the object for you. |
| * @param {goog.graphics.CanvasGraphics} graphics The graphics creating |
| * this element. |
| * @constructor |
| * @extends {goog.graphics.GroupElement} |
| * @deprecated goog.graphics is deprecated. It existed to abstract over browser |
| * differences before the canvas tag was widely supported. See |
| * http://en.wikipedia.org/wiki/Canvas_element for details. |
| * @final |
| */ |
| goog.graphics.CanvasGroupElement = function(graphics) { |
| goog.graphics.GroupElement.call(this, null, graphics); |
| |
| |
| /** |
| * Children contained by this group. |
| * @type {Array<goog.graphics.Element>} |
| * @private |
| */ |
| this.children_ = []; |
| }; |
| goog.inherits(goog.graphics.CanvasGroupElement, goog.graphics.GroupElement); |
| |
| |
| /** |
| * Remove all drawing elements from the group. |
| * @override |
| */ |
| goog.graphics.CanvasGroupElement.prototype.clear = function() { |
| if (this.children_.length) { |
| this.children_.length = 0; |
| this.getGraphics().redraw(); |
| } |
| }; |
| |
| |
| /** |
| * Set the size of the group element. |
| * @param {number|string} width The width of the group element. |
| * @param {number|string} height The height of the group element. |
| * @override |
| */ |
| goog.graphics.CanvasGroupElement.prototype.setSize = function(width, height) { |
| // Do nothing. |
| }; |
| |
| |
| /** |
| * Append a child to the group. Does not draw it |
| * @param {goog.graphics.Element} element The child to append. |
| */ |
| goog.graphics.CanvasGroupElement.prototype.appendChild = function(element) { |
| this.children_.push(element); |
| }; |
| |
| |
| /** |
| * Draw the group. |
| * @param {CanvasRenderingContext2D} ctx The context to draw the element in. |
| */ |
| goog.graphics.CanvasGroupElement.prototype.draw = function(ctx) { |
| for (var i = 0, len = this.children_.length; i < len; i++) { |
| this.getGraphics().drawElement(this.children_[i]); |
| } |
| }; |
| |
| |
| |
| /** |
| * Thin wrapper for canvas ellipse elements. |
| * This is an implementation of the goog.graphics.EllipseElement interface. |
| * You should not construct objects from this constructor. The graphics |
| * will return the object for you. |
| * @param {Element} element The DOM element to wrap. |
| * @param {goog.graphics.CanvasGraphics} graphics The graphics creating |
| * this element. |
| * @param {number} cx Center X coordinate. |
| * @param {number} cy Center Y coordinate. |
| * @param {number} rx Radius length for the x-axis. |
| * @param {number} ry Radius length for the y-axis. |
| * @param {goog.graphics.Stroke} stroke The stroke to use for this element. |
| * @param {goog.graphics.Fill} fill The fill to use for this element. |
| * @constructor |
| * @extends {goog.graphics.EllipseElement} |
| * @final |
| */ |
| goog.graphics.CanvasEllipseElement = function(element, graphics, |
| cx, cy, rx, ry, stroke, fill) { |
| goog.graphics.EllipseElement.call(this, element, graphics, stroke, fill); |
| |
| /** |
| * X coordinate of the ellipse center. |
| * @type {number} |
| * @private |
| */ |
| this.cx_ = cx; |
| |
| |
| /** |
| * Y coordinate of the ellipse center. |
| * @type {number} |
| * @private |
| */ |
| this.cy_ = cy; |
| |
| |
| /** |
| * Radius length for the x-axis. |
| * @type {number} |
| * @private |
| */ |
| this.rx_ = rx; |
| |
| |
| /** |
| * Radius length for the y-axis. |
| * @type {number} |
| * @private |
| */ |
| this.ry_ = ry; |
| |
| |
| /** |
| * Internal path approximating an ellipse. |
| * @type {goog.graphics.Path} |
| * @private |
| */ |
| this.path_ = new goog.graphics.Path(); |
| this.setUpPath_(); |
| |
| /** |
| * Internal path element that actually does the drawing. |
| * @type {goog.graphics.CanvasPathElement} |
| * @private |
| */ |
| this.pathElement_ = new goog.graphics.CanvasPathElement(null, graphics, |
| this.path_, stroke, fill); |
| }; |
| goog.inherits(goog.graphics.CanvasEllipseElement, goog.graphics.EllipseElement); |
| |
| |
| /** |
| * Sets up the path. |
| * @private |
| */ |
| goog.graphics.CanvasEllipseElement.prototype.setUpPath_ = function() { |
| this.path_.clear(); |
| this.path_.moveTo(this.cx_ + goog.math.angleDx(0, this.rx_), |
| this.cy_ + goog.math.angleDy(0, this.ry_)); |
| this.path_.arcTo(this.rx_, this.ry_, 0, 360); |
| this.path_.close(); |
| }; |
| |
| |
| /** |
| * Update the center point of the ellipse. |
| * @param {number} cx Center X coordinate. |
| * @param {number} cy Center Y coordinate. |
| * @override |
| */ |
| goog.graphics.CanvasEllipseElement.prototype.setCenter = function(cx, cy) { |
| this.cx_ = cx; |
| this.cy_ = cy; |
| this.setUpPath_(); |
| this.pathElement_.setPath(/** @type {!goog.graphics.Path} */ (this.path_)); |
| }; |
| |
| |
| /** |
| * Update the radius of the ellipse. |
| * @param {number} rx Center X coordinate. |
| * @param {number} ry Center Y coordinate. |
| * @override |
| */ |
| goog.graphics.CanvasEllipseElement.prototype.setRadius = function(rx, ry) { |
| this.rx_ = rx; |
| this.ry_ = ry; |
| this.setUpPath_(); |
| this.pathElement_.setPath(/** @type {!goog.graphics.Path} */ (this.path_)); |
| }; |
| |
| |
| /** |
| * Draw the ellipse. Should be treated as package scope. |
| * @param {CanvasRenderingContext2D} ctx The context to draw the element in. |
| */ |
| goog.graphics.CanvasEllipseElement.prototype.draw = function(ctx) { |
| this.pathElement_.draw(ctx); |
| }; |
| |
| |
| |
| /** |
| * Thin wrapper for canvas rectangle elements. |
| * This is an implementation of the goog.graphics.RectElement interface. |
| * You should not construct objects from this constructor. The graphics |
| * will return the object for you. |
| * @param {Element} element The DOM element to wrap. |
| * @param {goog.graphics.CanvasGraphics} graphics The graphics creating |
| * this element. |
| * @param {number} x X coordinate (left). |
| * @param {number} y Y coordinate (top). |
| * @param {number} w Width of rectangle. |
| * @param {number} h Height of rectangle. |
| * @param {goog.graphics.Stroke} stroke The stroke to use for this element. |
| * @param {goog.graphics.Fill} fill The fill to use for this element. |
| * @constructor |
| * @extends {goog.graphics.RectElement} |
| * @final |
| */ |
| goog.graphics.CanvasRectElement = function(element, graphics, x, y, w, h, |
| stroke, fill) { |
| goog.graphics.RectElement.call(this, element, graphics, stroke, fill); |
| |
| /** |
| * X coordinate of the top left corner. |
| * @type {number} |
| * @private |
| */ |
| this.x_ = x; |
| |
| |
| /** |
| * Y coordinate of the top left corner. |
| * @type {number} |
| * @private |
| */ |
| this.y_ = y; |
| |
| |
| /** |
| * Width of the rectangle. |
| * @type {number} |
| * @private |
| */ |
| this.w_ = w; |
| |
| |
| /** |
| * Height of the rectangle. |
| * @type {number} |
| * @private |
| */ |
| this.h_ = h; |
| }; |
| goog.inherits(goog.graphics.CanvasRectElement, goog.graphics.RectElement); |
| |
| |
| /** |
| * Update the position of the rectangle. |
| * @param {number} x X coordinate (left). |
| * @param {number} y Y coordinate (top). |
| * @override |
| */ |
| goog.graphics.CanvasRectElement.prototype.setPosition = function(x, y) { |
| this.x_ = x; |
| this.y_ = y; |
| if (this.drawn_) { |
| this.getGraphics().redraw(); |
| } |
| }; |
| |
| |
| /** |
| * Whether the rectangle has been drawn yet. |
| * @type {boolean} |
| * @private |
| */ |
| goog.graphics.CanvasRectElement.prototype.drawn_ = false; |
| |
| |
| /** |
| * Update the size of the rectangle. |
| * @param {number} width Width of rectangle. |
| * @param {number} height Height of rectangle. |
| * @override |
| */ |
| goog.graphics.CanvasRectElement.prototype.setSize = function(width, height) { |
| this.w_ = width; |
| this.h_ = height; |
| if (this.drawn_) { |
| this.getGraphics().redraw(); |
| } |
| }; |
| |
| |
| /** |
| * Draw the rectangle. Should be treated as package scope. |
| * @param {CanvasRenderingContext2D} ctx The context to draw the element in. |
| */ |
| goog.graphics.CanvasRectElement.prototype.draw = function(ctx) { |
| this.drawn_ = true; |
| ctx.beginPath(); |
| ctx.moveTo(this.x_, this.y_); |
| ctx.lineTo(this.x_, this.y_ + this.h_); |
| ctx.lineTo(this.x_ + this.w_, this.y_ + this.h_); |
| ctx.lineTo(this.x_ + this.w_, this.y_); |
| ctx.closePath(); |
| }; |
| |
| |
| |
| /** |
| * Thin wrapper for canvas path elements. |
| * This is an implementation of the goog.graphics.PathElement interface. |
| * You should not construct objects from this constructor. The graphics |
| * will return the object for you. |
| * @param {Element} element The DOM element to wrap. |
| * @param {goog.graphics.CanvasGraphics} graphics The graphics creating |
| * this element. |
| * @param {!goog.graphics.Path} path The path object to draw. |
| * @param {goog.graphics.Stroke} stroke The stroke to use for this element. |
| * @param {goog.graphics.Fill} fill The fill to use for this element. |
| * @constructor |
| * @extends {goog.graphics.PathElement} |
| * @final |
| */ |
| goog.graphics.CanvasPathElement = function(element, graphics, path, stroke, |
| fill) { |
| goog.graphics.PathElement.call(this, element, graphics, stroke, fill); |
| |
| this.setPath(path); |
| }; |
| goog.inherits(goog.graphics.CanvasPathElement, goog.graphics.PathElement); |
| |
| |
| /** |
| * Whether the shape has been drawn yet. |
| * @type {boolean} |
| * @private |
| */ |
| goog.graphics.CanvasPathElement.prototype.drawn_ = false; |
| |
| |
| /** |
| * The path to draw. |
| * @type {goog.graphics.Path} |
| * @private |
| */ |
| goog.graphics.CanvasPathElement.prototype.path_; |
| |
| |
| /** |
| * Update the underlying path. |
| * @param {!goog.graphics.Path} path The path object to draw. |
| * @override |
| */ |
| goog.graphics.CanvasPathElement.prototype.setPath = function(path) { |
| this.path_ = path.isSimple() ? path : |
| goog.graphics.Path.createSimplifiedPath(path); |
| if (this.drawn_) { |
| this.getGraphics().redraw(); |
| } |
| }; |
| |
| |
| /** |
| * Draw the path. Should be treated as package scope. |
| * @param {CanvasRenderingContext2D} ctx The context to draw the element in. |
| * @suppress {deprecated} goog.graphics is deprecated. |
| */ |
| goog.graphics.CanvasPathElement.prototype.draw = function(ctx) { |
| this.drawn_ = true; |
| |
| ctx.beginPath(); |
| this.path_.forEachSegment(function(segment, args) { |
| switch (segment) { |
| case goog.graphics.Path.Segment.MOVETO: |
| ctx.moveTo(args[0], args[1]); |
| break; |
| case goog.graphics.Path.Segment.LINETO: |
| for (var i = 0; i < args.length; i += 2) { |
| ctx.lineTo(args[i], args[i + 1]); |
| } |
| break; |
| case goog.graphics.Path.Segment.CURVETO: |
| for (var i = 0; i < args.length; i += 6) { |
| ctx.bezierCurveTo(args[i], args[i + 1], args[i + 2], |
| args[i + 3], args[i + 4], args[i + 5]); |
| } |
| break; |
| case goog.graphics.Path.Segment.ARCTO: |
| throw Error('Canvas paths cannot contain arcs'); |
| case goog.graphics.Path.Segment.CLOSE: |
| ctx.closePath(); |
| break; |
| } |
| }); |
| }; |
| |
| |
| |
| /** |
| * Thin wrapper for canvas text elements. |
| * This is an implementation of the goog.graphics.TextElement interface. |
| * You should not construct objects from this constructor. The graphics |
| * will return the object for you. |
| * @param {!goog.graphics.CanvasGraphics} graphics The graphics creating |
| * this element. |
| * @param {string} text The text to draw. |
| * @param {number} x1 X coordinate of start of line. |
| * @param {number} y1 Y coordinate of start of line. |
| * @param {number} x2 X coordinate of end of line. |
| * @param {number} y2 Y coordinate of end of line. |
| * @param {?string} align Horizontal alignment: left (default), center, right. |
| * @param {!goog.graphics.Font} font Font describing the font properties. |
| * @param {goog.graphics.Stroke} stroke The stroke to use for this element. |
| * @param {goog.graphics.Fill} fill The fill to use for this element. |
| * @constructor |
| * @extends {goog.graphics.TextElement} |
| * @final |
| */ |
| goog.graphics.CanvasTextElement = function(graphics, text, x1, y1, x2, y2, |
| align, font, stroke, fill) { |
| var element = goog.dom.createDom(goog.dom.TagName.DIV, { |
| 'style': 'display:table;position:absolute;padding:0;margin:0;border:0' |
| }); |
| goog.graphics.TextElement.call(this, element, graphics, stroke, fill); |
| |
| /** |
| * The text to draw. |
| * @type {string} |
| * @private |
| */ |
| this.text_ = text; |
| |
| /** |
| * X coordinate of the start of the line the text is drawn on. |
| * @type {number} |
| * @private |
| */ |
| this.x1_ = x1; |
| |
| /** |
| * Y coordinate of the start of the line the text is drawn on. |
| * @type {number} |
| * @private |
| */ |
| this.y1_ = y1; |
| |
| /** |
| * X coordinate of the end of the line the text is drawn on. |
| * @type {number} |
| * @private |
| */ |
| this.x2_ = x2; |
| |
| /** |
| * Y coordinate of the end of the line the text is drawn on. |
| * @type {number} |
| * @private |
| */ |
| this.y2_ = y2; |
| |
| /** |
| * Horizontal alignment: left (default), center, right. |
| * @type {string} |
| * @private |
| */ |
| this.align_ = align || 'left'; |
| |
| /** |
| * Font object describing the font properties. |
| * @type {goog.graphics.Font} |
| * @private |
| */ |
| this.font_ = font; |
| |
| /** |
| * The inner element that contains the text. |
| * @type {Element} |
| * @private |
| */ |
| this.innerElement_ = goog.dom.createDom('DIV', { |
| 'style': 'display:table-cell;padding: 0;margin: 0;border: 0' |
| }); |
| |
| this.updateStyle_(); |
| this.updateText_(); |
| |
| // Append to the DOM. |
| graphics.getElement().appendChild(element); |
| element.appendChild(this.innerElement_); |
| }; |
| goog.inherits(goog.graphics.CanvasTextElement, goog.graphics.TextElement); |
| |
| |
| /** |
| * Update the displayed text of the element. |
| * @param {string} text The text to draw. |
| * @override |
| */ |
| goog.graphics.CanvasTextElement.prototype.setText = function(text) { |
| this.text_ = text; |
| this.updateText_(); |
| }; |
| |
| |
| /** |
| * Sets the fill for this element. |
| * @param {goog.graphics.Fill} fill The fill object. |
| * @override |
| */ |
| goog.graphics.CanvasTextElement.prototype.setFill = function(fill) { |
| this.fill = fill; |
| var element = this.getElement(); |
| if (element) { |
| element.style.color = fill.getColor() || fill.getColor1(); |
| } |
| }; |
| |
| |
| /** |
| * Sets the stroke for this element. |
| * @param {goog.graphics.Stroke} stroke The stroke object. |
| * @override |
| */ |
| goog.graphics.CanvasTextElement.prototype.setStroke = function(stroke) { |
| // Ignore stroke |
| }; |
| |
| |
| /** |
| * Draw the text. Should be treated as package scope. |
| * @param {CanvasRenderingContext2D} ctx The context to draw the element in. |
| */ |
| goog.graphics.CanvasTextElement.prototype.draw = function(ctx) { |
| // Do nothing - the text is already drawn. |
| }; |
| |
| |
| /** |
| * Update the styles of the DIVs. |
| * @private |
| */ |
| goog.graphics.CanvasTextElement.prototype.updateStyle_ = function() { |
| var x1 = this.x1_; |
| var x2 = this.x2_; |
| var y1 = this.y1_; |
| var y2 = this.y2_; |
| var align = this.align_; |
| var font = this.font_; |
| var style = this.getElement().style; |
| var scaleX = this.getGraphics().getPixelScaleX(); |
| var scaleY = this.getGraphics().getPixelScaleY(); |
| |
| if (x1 == x2) { |
| // Special case vertical text |
| style.lineHeight = '90%'; |
| |
| this.innerElement_.style.verticalAlign = align == 'center' ? 'middle' : |
| align == 'left' ? (y1 < y2 ? 'top' : 'bottom') : |
| y1 < y2 ? 'bottom' : 'top'; |
| style.textAlign = 'center'; |
| |
| var w = font.size * scaleX; |
| style.top = Math.round(Math.min(y1, y2) * scaleY) + 'px'; |
| style.left = Math.round((x1 - w / 2) * scaleX) + 'px'; |
| style.width = Math.round(w) + 'px'; |
| style.height = Math.abs(y1 - y2) * scaleY + 'px'; |
| |
| style.fontSize = font.size * 0.6 * scaleY + 'pt'; |
| } else { |
| style.lineHeight = '100%'; |
| this.innerElement_.style.verticalAlign = 'top'; |
| style.textAlign = align; |
| |
| style.top = Math.round(((y1 + y2) / 2 - font.size * 2 / 3) * scaleY) + 'px'; |
| style.left = Math.round(x1 * scaleX) + 'px'; |
| style.width = Math.round(Math.abs(x2 - x1) * scaleX) + 'px'; |
| style.height = 'auto'; |
| |
| style.fontSize = font.size * scaleY + 'pt'; |
| } |
| |
| style.fontWeight = font.bold ? 'bold' : 'normal'; |
| style.fontStyle = font.italic ? 'italic' : 'normal'; |
| style.fontFamily = font.family; |
| |
| var fill = this.getFill(); |
| style.color = fill.getColor() || fill.getColor1(); |
| }; |
| |
| |
| /** |
| * Update the text content. |
| * @private |
| */ |
| goog.graphics.CanvasTextElement.prototype.updateText_ = function() { |
| if (this.x1_ == this.x2_) { |
| // Special case vertical text |
| var html = |
| goog.array.map( |
| this.text_.split(''), |
| function(entry) { return goog.string.htmlEscape(entry); }) |
| .join('<br>'); |
| // Creating a SafeHtml for each character would be quite expensive, and it's |
| // obvious that this is safe, so an unchecked conversion is appropriate. |
| var safeHtml = goog.html.uncheckedconversions |
| .safeHtmlFromStringKnownToSatisfyTypeContract( |
| goog.string.Const.from('Concatenate escaped chars and <br>'), |
| html); |
| goog.dom.safe.setInnerHtml( |
| /** @type {!Element} */ (this.innerElement_), safeHtml); |
| } else { |
| goog.dom.safe.setInnerHtml( |
| /** @type {!Element} */ (this.innerElement_), |
| goog.html.SafeHtml.htmlEscape(this.text_)); |
| } |
| }; |
| |
| |
| |
| /** |
| * Thin wrapper for canvas image elements. |
| * This is an implementation of the goog.graphics.ImageElement interface. |
| * You should not construct objects from this constructor. The graphics |
| * will return the object for you. |
| * @param {Element} element The DOM element to wrap. |
| * @param {goog.graphics.CanvasGraphics} graphics The graphics creating |
| * this element. |
| * @param {number} x X coordinate (left). |
| * @param {number} y Y coordinate (top). |
| * @param {number} w Width of rectangle. |
| * @param {number} h Height of rectangle. |
| * @param {string} src Source of the image. |
| * @constructor |
| * @extends {goog.graphics.ImageElement} |
| * @final |
| */ |
| goog.graphics.CanvasImageElement = function(element, graphics, x, y, w, h, |
| src) { |
| goog.graphics.ImageElement.call(this, element, graphics); |
| |
| /** |
| * X coordinate of the top left corner. |
| * @type {number} |
| * @private |
| */ |
| this.x_ = x; |
| |
| |
| /** |
| * Y coordinate of the top left corner. |
| * @type {number} |
| * @private |
| */ |
| this.y_ = y; |
| |
| |
| /** |
| * Width of the rectangle. |
| * @type {number} |
| * @private |
| */ |
| this.w_ = w; |
| |
| |
| /** |
| * Height of the rectangle. |
| * @type {number} |
| * @private |
| */ |
| this.h_ = h; |
| |
| |
| /** |
| * URL of the image source. |
| * @type {string} |
| * @private |
| */ |
| this.src_ = src; |
| }; |
| goog.inherits(goog.graphics.CanvasImageElement, goog.graphics.ImageElement); |
| |
| |
| /** |
| * Whether the image has been drawn yet. |
| * @type {boolean} |
| * @private |
| */ |
| goog.graphics.CanvasImageElement.prototype.drawn_ = false; |
| |
| |
| /** |
| * Update the position of the image. |
| * @param {number} x X coordinate (left). |
| * @param {number} y Y coordinate (top). |
| * @override |
| */ |
| goog.graphics.CanvasImageElement.prototype.setPosition = function(x, y) { |
| this.x_ = x; |
| this.y_ = y; |
| if (this.drawn_) { |
| this.getGraphics().redraw(); |
| } |
| }; |
| |
| |
| /** |
| * Update the size of the image. |
| * @param {number} width Width of rectangle. |
| * @param {number} height Height of rectangle. |
| * @override |
| */ |
| goog.graphics.CanvasImageElement.prototype.setSize = function(width, height) { |
| this.w_ = width; |
| this.h_ = height; |
| if (this.drawn_) { |
| this.getGraphics().redraw(); |
| } |
| }; |
| |
| |
| /** |
| * Update the source of the image. |
| * @param {string} src Source of the image. |
| * @override |
| */ |
| goog.graphics.CanvasImageElement.prototype.setSource = function(src) { |
| this.src_ = src; |
| if (this.drawn_) { |
| // TODO(robbyw): Probably need to reload the image here. |
| this.getGraphics().redraw(); |
| } |
| }; |
| |
| |
| /** |
| * Draw the image. Should be treated as package scope. |
| * @param {CanvasRenderingContext2D} ctx The context to draw the element in. |
| */ |
| goog.graphics.CanvasImageElement.prototype.draw = function(ctx) { |
| if (this.img_) { |
| if (this.w_ && this.h_) { |
| // If the image is already loaded, draw it. |
| ctx.drawImage(this.img_, this.x_, this.y_, this.w_, this.h_); |
| } |
| this.drawn_ = true; |
| |
| } else { |
| // Otherwise, load it. |
| var img = new Image(); |
| img.onload = goog.bind(this.handleImageLoad_, this, img); |
| // TODO(robbyw): Handle image load errors. |
| img.src = this.src_; |
| } |
| }; |
| |
| |
| /** |
| * Handle an image load. |
| * @param {Element} img The image element that finished loading. |
| * @private |
| */ |
| goog.graphics.CanvasImageElement.prototype.handleImageLoad_ = function(img) { |
| this.img_ = img; |
| |
| // TODO(robbyw): Add a small delay to catch batched images |
| this.getGraphics().redraw(); |
| }; |