PageRenderTime 39ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

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