123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 |
- /*
- This library rewrites the Canvas2D "measureText" function
- so that it returns a more complete metrics object.
- ** -----------------------------------------------------------------------------
- CHANGELOG:
- 2012-01-21 - Whitespace handling added by Joe Turner
- (https://github.com/oampo)
- ** -----------------------------------------------------------------------------
- */
- /**
- @license
- fontmetrics.js - https://github.com/Pomax/fontmetrics.js
- Copyright (C) 2011 by Mike "Pomax" Kamermans
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- **/
- /*global define*/
- define(function() {
- /*jshint strict:false*/
- /*
- var NAME = "FontMetrics Library"
- var VERSION = "1-2012.0121.1300";
- // if there is no getComputedStyle, this library won't work.
- if(!document.defaultView.getComputedStyle) {
- throw("ERROR: 'document.defaultView.getComputedStyle' not found. This library only works in browsers that can report computed CSS values.");
- }
- // store the old text metrics function on the Canvas2D prototype
- CanvasRenderingContext2D.prototype.measureTextWidth = CanvasRenderingContext2D.prototype.measureText;
- */
- /**
- * shortcut function for getting computed CSS values
- */
- var getCSSValue = function(element, property) {
- return document.defaultView.getComputedStyle(element,null).getPropertyValue(property);
- };
- /*
- // debug function
- var show = function(canvas, ctx, xstart, w, h, metrics)
- {
- document.body.appendChild(canvas);
- ctx.strokeStyle = 'rgba(0, 0, 0, 0.5)';
- ctx.beginPath();
- ctx.moveTo(xstart,0);
- ctx.lineTo(xstart,h);
- ctx.closePath();
- ctx.stroke();
- ctx.beginPath();
- ctx.moveTo(xstart+metrics.bounds.maxx,0);
- ctx.lineTo(xstart+metrics.bounds.maxx,h);
- ctx.closePath();
- ctx.stroke();
- ctx.beginPath();
- ctx.moveTo(0,h/2-metrics.ascent);
- ctx.lineTo(w,h/2-metrics.ascent);
- ctx.closePath();
- ctx.stroke();
- ctx.beginPath();
- ctx.moveTo(0,h/2+metrics.descent);
- ctx.lineTo(w,h/2+metrics.descent);
- ctx.closePath();
- ctx.stroke();
- }
- */
- /**
- * The new text metrics function
- */
- var measureText = function(context2D, textstring, stroke, fill) {
- var metrics = context2D.measureText(textstring),
- fontFamily = getCSSValue(context2D.canvas,"font-family"),
- fontSize = getCSSValue(context2D.canvas,"font-size").replace("px",""),
- isSpace = !(/\S/.test(textstring));
- metrics.fontsize = fontSize;
- // for text lead values, we meaure a multiline text container.
- var leadDiv = document.createElement("div");
- leadDiv.style.position = "absolute";
- leadDiv.style.opacity = 0;
- leadDiv.style.font = fontSize + "px " + fontFamily;
- leadDiv.innerHTML = textstring + "<br/>" + textstring;
- document.body.appendChild(leadDiv);
- // make some initial guess at the text leading (using the standard TeX ratio)
- metrics.leading = 1.2 * fontSize;
- // then we try to get the real value from the browser
- var leadDivHeight = getCSSValue(leadDiv,"height");
- leadDivHeight = leadDivHeight.replace("px","");
- if (leadDivHeight >= fontSize * 2) { metrics.leading = (leadDivHeight/2) | 0; }
- document.body.removeChild(leadDiv);
- // if we're not dealing with white space, we can compute metrics
- if (!isSpace) {
- // Have characters, so measure the text
- var canvas = document.createElement("canvas");
- var padding = 100;
- canvas.width = metrics.width + padding;
- canvas.height = 3*fontSize;
- canvas.style.opacity = 1;
- canvas.style.fontFamily = fontFamily;
- canvas.style.fontSize = fontSize;
- var ctx = canvas.getContext("2d");
- ctx.font = fontSize + "px " + fontFamily;
- var w = canvas.width,
- h = canvas.height,
- baseline = h/2;
- // Set all canvas pixeldata values to 255, with all the content
- // data being 0. This lets us scan for data[i] != 255.
- ctx.fillStyle = "white";
- ctx.fillRect(-1, -1, w + 2, h + 2);
- if (stroke) {
- ctx.strokeStyle = "black";
- ctx.lineWidth = context2D.lineWidth;
- ctx.strokeText(textstring, (padding / 2), baseline);
- }
- if (fill) {
- ctx.fillStyle = "black";
- ctx.fillText(textstring, padding / 2, baseline);
- }
- var pixelData = ctx.getImageData(0, 0, w, h).data;
- // canvas pixel data is w*4 by h*4, because R, G, B and A are separate,
- // consecutive values in the array, rather than stored as 32 bit ints.
- var i = 0,
- w4 = w * 4,
- len = pixelData.length;
- // Finding the ascent uses a normal, forward scanline
- while (++i < len && pixelData[i] === 255) {}
- var ascent = (i/w4)|0;
- // Finding the descent uses a reverse scanline
- i = len - 1;
- while (--i > 0 && pixelData[i] === 255) {}
- var descent = (i/w4)|0;
- // find the min-x coordinate
- for(i = 0; i<len && pixelData[i] === 255; ) {
- i += w4;
- if(i>=len) { i = (i-len) + 4; }}
- var minx = ((i%w4)/4) | 0;
- // find the max-x coordinate
- var step = 1;
- for(i = len-3; i>=0 && pixelData[i] === 255; ) {
- i -= w4;
- if(i<0) { i = (len - 3) - (step++)*4; }}
- var maxx = ((i%w4)/4) + 1 | 0;
- // set font metrics
- metrics.ascent = (baseline - ascent);
- metrics.descent = (descent - baseline);
- metrics.bounds = { minx: minx - (padding/2),
- maxx: maxx - (padding/2),
- miny: 0,
- maxy: descent-ascent };
- metrics.height = 1+(descent - ascent);
- }
- // if we ARE dealing with whitespace, most values will just be zero.
- else {
- // Only whitespace, so we can't measure the text
- metrics.ascent = 0;
- metrics.descent = 0;
- metrics.bounds = { minx: 0,
- maxx: metrics.width, // Best guess
- miny: 0,
- maxy: 0 };
- metrics.height = 0;
- }
- return metrics;
- };
- return measureText;
- });
|