PageRenderTime 656ms CodeModel.GetById 122ms app.highlight 408ms RepoModel.GetById 66ms app.codeStats 1ms

/ajax/scripts/graphics.js

http://showslow.googlecode.com/
JavaScript | 653 lines | 389 code | 93 blank | 171 comment | 63 complexity | 4e8a92ef3abc081688fdd96c6b32d9eb MD5 | raw file
  1/**
  2 * @fileOverview Graphics utility functions and constants
  3 * @name SimileAjax.Graphics
  4 */
  5
  6SimileAjax.Graphics = new Object();
  7
  8/**
  9 * A boolean value indicating whether PNG translucency is supported on the
 10 * user's browser or not.
 11 *
 12 * @type Boolean
 13 */
 14SimileAjax.Graphics.pngIsTranslucent = (!SimileAjax.Platform.browser.isIE) || (SimileAjax.Platform.browser.majorVersion > 6);
 15if (!SimileAjax.Graphics.pngIsTranslucent) {
 16    SimileAjax.includeCssFile(document, SimileAjax.urlPrefix + "styles/graphics-ie6.css");
 17}
 18
 19/*==================================================
 20 *  Opacity, translucency
 21 *==================================================
 22 */
 23SimileAjax.Graphics._createTranslucentImage1 = function(url, verticalAlign) {
 24    var elmt = document.createElement("img");
 25    elmt.setAttribute("src", url);
 26    if (verticalAlign != null) {
 27        elmt.style.verticalAlign = verticalAlign;
 28    }
 29    return elmt;
 30};
 31SimileAjax.Graphics._createTranslucentImage2 = function(url, verticalAlign) {
 32    var elmt = document.createElement("img");
 33    elmt.style.width = "1px";  // just so that IE will calculate the size property
 34    elmt.style.height = "1px";
 35    elmt.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + url +"', sizingMethod='image')";
 36    elmt.style.verticalAlign = (verticalAlign != null) ? verticalAlign : "middle";
 37    return elmt;
 38};
 39
 40/**
 41 * Creates a DOM element for an <code>img</code> tag using the URL given. This
 42 * is a convenience method that automatically includes the necessary CSS to
 43 * allow for translucency, even on IE.
 44 * 
 45 * @function
 46 * @param {String} url the URL to the image
 47 * @param {String} verticalAlign the CSS value for the image's vertical-align
 48 * @return {Element} a DOM element containing the <code>img</code> tag
 49 */
 50SimileAjax.Graphics.createTranslucentImage = SimileAjax.Graphics.pngIsTranslucent ?
 51    SimileAjax.Graphics._createTranslucentImage1 :
 52    SimileAjax.Graphics._createTranslucentImage2;
 53
 54SimileAjax.Graphics._createTranslucentImageHTML1 = function(url, verticalAlign) {
 55    return "<img src=\"" + url + "\"" +
 56        (verticalAlign != null ? " style=\"vertical-align: " + verticalAlign + ";\"" : "") +
 57        " />";
 58};
 59SimileAjax.Graphics._createTranslucentImageHTML2 = function(url, verticalAlign) {
 60    var style = 
 61        "width: 1px; height: 1px; " +
 62        "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + url +"', sizingMethod='image');" +
 63        (verticalAlign != null ? " vertical-align: " + verticalAlign + ";" : "");
 64        
 65    return "<img src='" + url + "' style=\"" + style + "\" />";
 66};
 67
 68/**
 69 * Creates an HTML string for an <code>img</code> tag using the URL given.
 70 * This is a convenience method that automatically includes the necessary CSS
 71 * to allow for translucency, even on IE.
 72 * 
 73 * @function
 74 * @param {String} url the URL to the image
 75 * @param {String} verticalAlign the CSS value for the image's vertical-align
 76 * @return {String} a string containing the <code>img</code> tag
 77 */
 78SimileAjax.Graphics.createTranslucentImageHTML = SimileAjax.Graphics.pngIsTranslucent ?
 79    SimileAjax.Graphics._createTranslucentImageHTML1 :
 80    SimileAjax.Graphics._createTranslucentImageHTML2;
 81
 82/**
 83 * Sets the opacity on the given DOM element.
 84 *
 85 * @param {Element} elmt the DOM element to set the opacity on
 86 * @param {Number} opacity an integer from 0 to 100 specifying the opacity
 87 */
 88SimileAjax.Graphics.setOpacity = function(elmt, opacity) {
 89    if (SimileAjax.Platform.browser.isIE) {
 90        elmt.style.filter = "progid:DXImageTransform.Microsoft.Alpha(Style=0,Opacity=" + opacity + ")";
 91    } else {
 92        var o = (opacity / 100).toString();
 93        elmt.style.opacity = o;
 94        elmt.style.MozOpacity = o;
 95    }
 96};
 97
 98/*==================================================
 99 *  Bubble
100 *==================================================
101 */
102
103SimileAjax.Graphics.bubbleConfig = {
104    containerCSSClass:              "simileAjax-bubble-container",
105    innerContainerCSSClass:         "simileAjax-bubble-innerContainer",
106    contentContainerCSSClass:       "simileAjax-bubble-contentContainer",
107    
108    borderGraphicSize:              50,
109    borderGraphicCSSClassPrefix:    "simileAjax-bubble-border-",
110    
111    arrowGraphicTargetOffset:       33,  // from tip of arrow to the side of the graphic that touches the content of the bubble
112    arrowGraphicLength:             100, // dimension of arrow graphic along the direction that the arrow points
113    arrowGraphicWidth:              49,  // dimension of arrow graphic perpendicular to the direction that the arrow points
114    arrowGraphicCSSClassPrefix:     "simileAjax-bubble-arrow-",
115    
116    closeGraphicCSSClass:           "simileAjax-bubble-close",
117    
118    extraPadding:                   20
119};
120
121/**
122 * Creates a nice, rounded bubble popup with the given content in a div,
123 * page coordinates and a suggested width. The bubble will point to the 
124 * location on the page as described by pageX and pageY.  All measurements 
125 * should be given in pixels.
126 *
127 * @param {Element} the content div
128 * @param {Number} pageX the x coordinate of the point to point to
129 * @param {Number} pageY the y coordinate of the point to point to
130 * @param {Number} contentWidth a suggested width of the content
131 * @param {String} orientation a string ("top", "bottom", "left", or "right")
132 *   that describes the orientation of the arrow on the bubble
133 * @param {Number} maxHeight. Add a scrollbar div if bubble would be too tall.
134 *   Default of 0 or null means no maximum
135 */
136SimileAjax.Graphics.createBubbleForContentAndPoint = function(
137       div, pageX, pageY, contentWidth, orientation, maxHeight) {
138    if (typeof contentWidth != "number") {
139        contentWidth = 300;
140    }
141    if (typeof maxHeight != "number") {
142        maxHeight = 0;
143    }
144
145    div.style.position = "absolute";
146    div.style.left = "-5000px";
147    div.style.top = "0px";
148    div.style.width = contentWidth + "px";
149    document.body.appendChild(div);
150    
151    window.setTimeout(function() {
152        var width = div.scrollWidth + 10;
153        var height = div.scrollHeight + 10;
154        var scrollDivW = 0; // width of the possible inner container when we want vertical scrolling
155        if (maxHeight > 0 && height > maxHeight) {
156          height = maxHeight;
157          scrollDivW = width - 25;
158        }  
159       
160        var bubble = SimileAjax.Graphics.createBubbleForPoint(pageX, pageY, width, height, orientation);
161        
162        document.body.removeChild(div);
163        div.style.position = "static";
164        div.style.left = "";
165        div.style.top = "";
166        
167        // create a scroll div if needed
168        if (scrollDivW > 0) {
169          var scrollDiv = document.createElement("div");
170          div.style.width = "";
171          scrollDiv.style.width = scrollDivW + "px";
172          scrollDiv.appendChild(div);
173          bubble.content.appendChild(scrollDiv);
174        } else {
175          div.style.width = width + "px";
176          bubble.content.appendChild(div);
177        }
178    }, 200);
179};
180
181/**
182 * Creates a nice, rounded bubble popup with the given page coordinates and
183 * content dimensions.  The bubble will point to the location on the page
184 * as described by pageX and pageY.  All measurements should be given in
185 * pixels.
186 *
187 * @param {Number} pageX the x coordinate of the point to point to
188 * @param {Number} pageY the y coordinate of the point to point to
189 * @param {Number} contentWidth the width of the content box in the bubble
190 * @param {Number} contentHeight the height of the content box in the bubble
191 * @param {String} orientation a string ("top", "bottom", "left", or "right")
192 *   that describes the orientation of the arrow on the bubble
193 * @return {Element} a DOM element for the newly created bubble
194 */
195SimileAjax.Graphics.createBubbleForPoint = function(pageX, pageY, contentWidth, contentHeight, orientation) {
196    contentWidth = parseInt(contentWidth, 10); // harden against bad input bugs
197    contentHeight = parseInt(contentHeight, 10); // getting numbers-as-strings
198    
199    var bubbleConfig = SimileAjax.Graphics.bubbleConfig;
200    var pngTransparencyClassSuffix = 
201        SimileAjax.Graphics.pngIsTranslucent ? "pngTranslucent" : "pngNotTranslucent";
202    
203    var bubbleWidth = contentWidth + 2 * bubbleConfig.borderGraphicSize;
204    var bubbleHeight = contentHeight + 2 * bubbleConfig.borderGraphicSize;
205    
206    var generatePngSensitiveClass = function(className) {
207        return className + " " + className + "-" + pngTransparencyClassSuffix;
208    };
209    
210    /*
211     *  Render container divs
212     */
213    var div = document.createElement("div");
214    div.className = generatePngSensitiveClass(bubbleConfig.containerCSSClass);
215    div.style.width = contentWidth + "px";
216    div.style.height = contentHeight + "px";
217    
218    var divInnerContainer = document.createElement("div");
219    divInnerContainer.className = generatePngSensitiveClass(bubbleConfig.innerContainerCSSClass);
220    div.appendChild(divInnerContainer);
221    
222    /*
223     *  Create layer for bubble
224     */
225    var close = function() { 
226        if (!bubble._closed) {
227            document.body.removeChild(bubble._div);
228            bubble._doc = null;
229            bubble._div = null;
230            bubble._content = null;
231            bubble._closed = true;
232        }
233    }
234    var bubble = { _closed: false };
235    var layer = SimileAjax.WindowManager.pushLayer(close, true, div);
236    bubble._div = div;
237    bubble.close = function() { SimileAjax.WindowManager.popLayer(layer); }
238    
239    /*
240     *  Render border graphics
241     */
242    var createBorder = function(classNameSuffix) {
243        var divBorderGraphic = document.createElement("div");
244        divBorderGraphic.className = generatePngSensitiveClass(bubbleConfig.borderGraphicCSSClassPrefix + classNameSuffix);
245        divInnerContainer.appendChild(divBorderGraphic);
246    };
247    createBorder("top-left");
248    createBorder("top-right");
249    createBorder("bottom-left");
250    createBorder("bottom-right");
251    createBorder("left");
252    createBorder("right");
253    createBorder("top");
254    createBorder("bottom");
255    
256    /*
257     *  Render content
258     */
259    var divContentContainer = document.createElement("div");
260    divContentContainer.className = generatePngSensitiveClass(bubbleConfig.contentContainerCSSClass);
261    divInnerContainer.appendChild(divContentContainer);
262    bubble.content = divContentContainer;
263    
264    /*
265     *  Render close button
266     */
267    var divClose = document.createElement("div");
268    divClose.className = generatePngSensitiveClass(bubbleConfig.closeGraphicCSSClass);
269    divInnerContainer.appendChild(divClose);
270    SimileAjax.WindowManager.registerEventWithObject(divClose, "click", bubble, "close");
271    
272    (function() {
273        var dims = SimileAjax.Graphics.getWindowDimensions();
274        var docWidth = dims.w;
275        var docHeight = dims.h;
276        
277        var halfArrowGraphicWidth = Math.ceil(bubbleConfig.arrowGraphicWidth / 2);
278        
279        var createArrow = function(classNameSuffix) {
280            var divArrowGraphic = document.createElement("div");
281            divArrowGraphic.className = generatePngSensitiveClass(bubbleConfig.arrowGraphicCSSClassPrefix + "point-" + classNameSuffix);
282            divInnerContainer.appendChild(divArrowGraphic);
283            return divArrowGraphic;
284        };
285        
286        if (pageX - halfArrowGraphicWidth - bubbleConfig.borderGraphicSize - bubbleConfig.extraPadding > 0 &&
287            pageX + halfArrowGraphicWidth + bubbleConfig.borderGraphicSize + bubbleConfig.extraPadding < docWidth) {
288            
289            /*
290             *  Bubble can be positioned above or below the target point.
291             */
292            
293            var left = pageX - Math.round(contentWidth / 2);
294            left = pageX < (docWidth / 2) ?
295                Math.max(left, bubbleConfig.extraPadding + bubbleConfig.borderGraphicSize) : 
296                Math.min(left, docWidth - bubbleConfig.extraPadding - bubbleConfig.borderGraphicSize - contentWidth);
297                
298            if ((orientation && orientation == "top") || 
299                (!orientation && 
300                    (pageY 
301                        - bubbleConfig.arrowGraphicTargetOffset 
302                        - contentHeight 
303                        - bubbleConfig.borderGraphicSize 
304                        - bubbleConfig.extraPadding > 0))) {
305                
306                /*
307                 *  Position bubble above the target point.
308                 */
309                
310                var divArrow = createArrow("down");
311                divArrow.style.left = (pageX - halfArrowGraphicWidth - left) + "px";
312                
313                div.style.left = left + "px";
314                div.style.top = (pageY - bubbleConfig.arrowGraphicTargetOffset - contentHeight) + "px";
315                
316                return;
317            } else if ((orientation && orientation == "bottom") || 
318                (!orientation && 
319                    (pageY 
320                        + bubbleConfig.arrowGraphicTargetOffset 
321                        + contentHeight 
322                        + bubbleConfig.borderGraphicSize 
323                        + bubbleConfig.extraPadding < docHeight))) {
324                        
325                /*
326                 *  Position bubble below the target point.
327                 */
328                
329                var divArrow = createArrow("up");
330                divArrow.style.left = (pageX - halfArrowGraphicWidth - left) + "px";
331                
332                div.style.left = left + "px";
333                div.style.top = (pageY + bubbleConfig.arrowGraphicTargetOffset) + "px";
334                
335                return;
336            }
337        }
338        
339        var top = pageY - Math.round(contentHeight / 2);
340        top = pageY < (docHeight / 2) ?
341            Math.max(top, bubbleConfig.extraPadding + bubbleConfig.borderGraphicSize) : 
342            Math.min(top, docHeight - bubbleConfig.extraPadding - bubbleConfig.borderGraphicSize - contentHeight);
343            
344        if ((orientation && orientation == "left") || 
345            (!orientation && 
346                (pageX 
347                    - bubbleConfig.arrowGraphicTargetOffset 
348                    - contentWidth
349                    - bubbleConfig.borderGraphicSize 
350                    - bubbleConfig.extraPadding > 0))) {
351            
352            /*
353             *  Position bubble left of the target point.
354             */
355            
356            var divArrow = createArrow("right");
357            divArrow.style.top = (pageY - halfArrowGraphicWidth - top) + "px";
358            
359            div.style.top = top + "px";
360            div.style.left = (pageX - bubbleConfig.arrowGraphicTargetOffset - contentWidth) + "px";
361        } else {
362            
363            /*
364             *  Position bubble right of the target point, as the last resort.
365             */
366            
367            var divArrow = createArrow("left");
368            divArrow.style.top = (pageY - halfArrowGraphicWidth - top) + "px";
369            
370            div.style.top = top + "px";
371            div.style.left = (pageX + bubbleConfig.arrowGraphicTargetOffset) + "px";
372        }
373    })();
374    
375    document.body.appendChild(div);
376    
377    return bubble;
378};
379
380SimileAjax.Graphics.getWindowDimensions = function() {
381    if (typeof window.innerHeight == 'number') {
382        return { w:window.innerWidth, h:window.innerHeight }; // Non-IE
383    } else if (document.documentElement && document.documentElement.clientHeight) {
384        return { // IE6+, in "standards compliant mode"
385            w:document.documentElement.clientWidth,
386            h:document.documentElement.clientHeight
387        };
388    } else if (document.body && document.body.clientHeight) {
389        return { // IE 4 compatible
390            w:document.body.clientWidth,
391            h:document.body.clientHeight
392        };
393    }
394};
395
396
397/**
398 * Creates a floating, rounded message bubble in the center of the window for
399 * displaying modal information, e.g. "Loading..."
400 *
401 * @param {Document} doc the root document for the page to render on
402 * @param {Object} an object with two properties, contentDiv and containerDiv,
403 *   consisting of the newly created DOM elements
404 */
405SimileAjax.Graphics.createMessageBubble = function(doc) {
406    var containerDiv = doc.createElement("div");
407    if (SimileAjax.Graphics.pngIsTranslucent) {
408        var topDiv = doc.createElement("div");
409        topDiv.style.height = "33px";
410        topDiv.style.background = "url(" + SimileAjax.urlPrefix + "images/message-top-left.png) top left no-repeat";
411        topDiv.style.paddingLeft = "44px";
412        containerDiv.appendChild(topDiv);
413        
414        var topRightDiv = doc.createElement("div");
415        topRightDiv.style.height = "33px";
416        topRightDiv.style.background = "url(" + SimileAjax.urlPrefix + "images/message-top-right.png) top right no-repeat";
417        topDiv.appendChild(topRightDiv);
418        
419        var middleDiv = doc.createElement("div");
420        middleDiv.style.background = "url(" + SimileAjax.urlPrefix + "images/message-left.png) top left repeat-y";
421        middleDiv.style.paddingLeft = "44px";
422        containerDiv.appendChild(middleDiv);
423        
424        var middleRightDiv = doc.createElement("div");
425        middleRightDiv.style.background = "url(" + SimileAjax.urlPrefix + "images/message-right.png) top right repeat-y";
426        middleRightDiv.style.paddingRight = "44px";
427        middleDiv.appendChild(middleRightDiv);
428        
429        var contentDiv = doc.createElement("div");
430        middleRightDiv.appendChild(contentDiv);
431        
432        var bottomDiv = doc.createElement("div");
433        bottomDiv.style.height = "55px";
434        bottomDiv.style.background = "url(" + SimileAjax.urlPrefix + "images/message-bottom-left.png) bottom left no-repeat";
435        bottomDiv.style.paddingLeft = "44px";
436        containerDiv.appendChild(bottomDiv);
437        
438        var bottomRightDiv = doc.createElement("div");
439        bottomRightDiv.style.height = "55px";
440        bottomRightDiv.style.background = "url(" + SimileAjax.urlPrefix + "images/message-bottom-right.png) bottom right no-repeat";
441        bottomDiv.appendChild(bottomRightDiv);
442    } else {
443        containerDiv.style.border = "2px solid #7777AA";
444        containerDiv.style.padding = "20px";
445        containerDiv.style.background = "white";
446        SimileAjax.Graphics.setOpacity(containerDiv, 90);
447        
448        var contentDiv = doc.createElement("div");
449        containerDiv.appendChild(contentDiv);
450    }
451    
452    return {
453        containerDiv:   containerDiv,
454        contentDiv:     contentDiv
455    };
456};
457
458/*==================================================
459 *  Animation
460 *==================================================
461 */
462
463/**
464 * Creates an animation for a function, and an interval of values.  The word
465 * "animation" here is used in the sense of repeatedly calling a function with
466 * a current value from within an interval, and a delta value.
467 *
468 * @param {Function} f a function to be called every 50 milliseconds throughout
469 *   the animation duration, of the form f(current, delta), where current is
470 *   the current value within the range and delta is the current change.
471 * @param {Number} from a starting value
472 * @param {Number} to an ending value
473 * @param {Number} duration the duration of the animation in milliseconds
474 * @param {Function} [cont] an optional function that is called at the end of
475 *   the animation, i.e. a continuation.
476 * @return {SimileAjax.Graphics._Animation} a new animation object
477 */
478SimileAjax.Graphics.createAnimation = function(f, from, to, duration, cont) {
479    return new SimileAjax.Graphics._Animation(f, from, to, duration, cont);
480};
481
482SimileAjax.Graphics._Animation = function(f, from, to, duration, cont) {
483    this.f = f;
484    this.cont = (typeof cont == "function") ? cont : function() {};
485    
486    this.from = from;
487    this.to = to;
488    this.current = from;
489    
490    this.duration = duration;
491    this.start = new Date().getTime();
492    this.timePassed = 0;
493};
494
495/**
496 * Runs this animation.
497 */
498SimileAjax.Graphics._Animation.prototype.run = function() {
499    var a = this;
500    window.setTimeout(function() { a.step(); }, 50);
501};
502
503/**
504 * Increments this animation by one step, and then continues the animation with
505 * <code>run()</code>.
506 */
507SimileAjax.Graphics._Animation.prototype.step = function() {
508    this.timePassed += 50;
509    
510    var timePassedFraction = this.timePassed / this.duration;
511    var parameterFraction = -Math.cos(timePassedFraction * Math.PI) / 2 + 0.5;
512    var current = parameterFraction * (this.to - this.from) + this.from;
513    
514    try {
515        this.f(current, current - this.current);
516    } catch (e) {
517    }
518    this.current = current;
519    
520    if (this.timePassed < this.duration) {
521        this.run();
522    } else {
523        this.f(this.to, 0);
524        this["cont"]();
525    }
526};
527
528/*==================================================
529 *  CopyPasteButton
530 *
531 *  Adapted from http://spaces.live.com/editorial/rayozzie/demo/liveclip/liveclipsample/techPreview.html.
532 *==================================================
533 */
534
535/**
536 * Creates a button and textarea for displaying structured data and copying it
537 * to the clipboard.  The data is dynamically generated by the given 
538 * createDataFunction parameter.
539 *
540 * @param {String} image an image URL to use as the background for the 
541 *   generated box
542 * @param {Number} width the width in pixels of the generated box
543 * @param {Number} height the height in pixels of the generated box
544 * @param {Function} createDataFunction a function that is called with no
545 *   arguments to generate the structured data
546 * @return a new DOM element
547 */
548SimileAjax.Graphics.createStructuredDataCopyButton = function(image, width, height, createDataFunction) {
549    var div = document.createElement("div");
550    div.style.position = "relative";
551    div.style.display = "inline";
552    div.style.width = width + "px";
553    div.style.height = height + "px";
554    div.style.overflow = "hidden";
555    div.style.margin = "2px";
556    
557    if (SimileAjax.Graphics.pngIsTranslucent) {
558        div.style.background = "url(" + image + ") no-repeat";
559    } else {
560        div.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + image +"', sizingMethod='image')";
561    }
562    
563    var style;
564    if (SimileAjax.Platform.browser.isIE) {
565        style = "filter:alpha(opacity=0)";
566    } else {
567        style = "opacity: 0";
568    }
569    div.innerHTML = "<textarea rows='1' autocomplete='off' value='none' style='" + style + "' />";
570    
571    var textarea = div.firstChild;
572    textarea.style.width = width + "px";
573    textarea.style.height = height + "px";
574    textarea.onmousedown = function(evt) {
575        evt = (evt) ? evt : ((event) ? event : null);
576        if (evt.button == 2) {
577            textarea.value = createDataFunction();
578            textarea.select();
579        }
580    };
581    
582    return div;
583};
584
585/*==================================================
586 *  getWidthHeight
587 *==================================================
588 */
589SimileAjax.Graphics.getWidthHeight = function(el) {
590    // RETURNS hash {width:  w, height: h} in pixels
591    
592    var w, h;
593    // offsetWidth rounds on FF, so doesn't work for us.
594    // See https://bugzilla.mozilla.org/show_bug.cgi?id=458617
595    if (el.getBoundingClientRect == null) {
596    	// use offsetWidth
597      w = el.offsetWidth;
598      h = el.offsetHeight;
599    } else {
600    	// use getBoundingClientRect
601      var rect = el.getBoundingClientRect();
602      w = Math.ceil(rect.right - rect.left);
603    	h = Math.ceil(rect.bottom - rect.top);
604    }
605    return {
606        width:  w,
607        height: h
608    };
609};
610 
611
612/*==================================================
613 *  FontRenderingContext
614 *==================================================
615 */
616SimileAjax.Graphics.getFontRenderingContext = function(elmt, width) {
617    return new SimileAjax.Graphics._FontRenderingContext(elmt, width);
618};
619
620SimileAjax.Graphics._FontRenderingContext = function(elmt, width) {
621    this._elmt = elmt;
622    this._elmt.style.visibility = "hidden";
623    if (typeof width == "string") {
624        this._elmt.style.width = width;
625    } else if (typeof width == "number") {
626        this._elmt.style.width = width + "px";
627    }
628};
629
630SimileAjax.Graphics._FontRenderingContext.prototype.dispose = function() {
631    this._elmt = null;
632};
633
634SimileAjax.Graphics._FontRenderingContext.prototype.update = function() {
635    this._elmt.innerHTML = "A";
636    this._lineHeight = this._elmt.offsetHeight;
637};
638
639SimileAjax.Graphics._FontRenderingContext.prototype.computeSize = function(text, className) {
640    // className arg is optional
641    var el = this._elmt;
642    el.innerHTML = text;
643    el.className = className === undefined ? '' : className;
644    var wh = SimileAjax.Graphics.getWidthHeight(el);
645    el.className = ''; // reset for the next guy
646    
647    return wh;
648};
649
650SimileAjax.Graphics._FontRenderingContext.prototype.getLineHeight = function() {
651    return this._lineHeight;
652};
653