1 var TextRenderer, getLinesToRender, getNextLine, parseFontString;
3 require('./fontmetrics.js');
5 parseFontString = function(font) {
6 var fontFamily, fontItems, fontSize, item, j, len, maybeSize, remainingFontString;
7 fontItems = font.split(' ');
9 for (j = 0, len = fontItems.length; j < len; j++) {
11 maybeSize = parseInt(item.replace("px", ""), 10);
12 if (!isNaN(maybeSize)) {
17 throw "Font size not found";
19 remainingFontString = font.substring(fontItems[0].length + 1).replace('bold ', '').replace('italic ', '').replace('underline ', '');
20 fontFamily = remainingFontString;
23 fontFamily: fontFamily
27 getNextLine = function(ctx, text, forcedWidth) {
28 var doesSubstringFit, endIndex, isEndOfString, isNonWord, isWhitespace, lastGoodIndex, lastOkayIndex, nextWordStartIndex, textToHere, wasInWord;
38 isEndOfString = endIndex >= text.length;
39 isWhitespace = (!isEndOfString) && text[endIndex].match(/\s/);
40 isNonWord = isWhitespace || isEndOfString;
41 textToHere = text.substring(0, endIndex);
42 doesSubstringFit = forcedWidth ? ctx.measureTextWidth(textToHere).width <= forcedWidth : true;
43 if (doesSubstringFit) {
44 lastOkayIndex = endIndex;
46 if (isNonWord && wasInWord) {
48 if (doesSubstringFit) {
49 lastGoodIndex = endIndex;
52 wasInWord = !isWhitespace;
53 if (isEndOfString || !doesSubstringFit) {
54 if (doesSubstringFit) {
56 } else if (lastGoodIndex > 0) {
57 nextWordStartIndex = lastGoodIndex + 1;
58 while (nextWordStartIndex < text.length && text[nextWordStartIndex].match('/\s/')) {
59 nextWordStartIndex += 1;
61 return [text.substring(0, lastGoodIndex), text.substring(nextWordStartIndex)];
63 return [text.substring(0, lastOkayIndex), text.substring(lastOkayIndex)];
69 getLinesToRender = function(ctx, text, forcedWidth) {
70 var j, len, lines, nextLine, ref, ref1, remainingText, textLine, textSplitOnLines;
71 textSplitOnLines = text.split(/\r\n|\r|\n/g);
73 for (j = 0, len = textSplitOnLines.length; j < len; j++) {
74 textLine = textSplitOnLines[j];
75 ref = getNextLine(ctx, textLine, forcedWidth), nextLine = ref[0], remainingText = ref[1];
79 ref1 = getNextLine(ctx, remainingText, forcedWidth), nextLine = ref1[0], remainingText = ref1[1];
88 TextRenderer = (function() {
89 function TextRenderer(ctx, text1, font1, forcedWidth1, forcedHeight) {
90 var fontFamily, fontSize, ref;
93 this.forcedWidth = forcedWidth1;
94 this.forcedHeight = forcedHeight;
95 ref = parseFontString(this.font), fontFamily = ref.fontFamily, fontSize = ref.fontSize;
97 ctx.textBaseline = 'baseline';
98 this.emDashWidth = ctx.measureTextWidth('—', fontSize, fontFamily).width;
99 this.caratWidth = ctx.measureTextWidth('|', fontSize, fontFamily).width;
100 this.lines = getLinesToRender(ctx, this.text, this.forcedWidth);
101 this.metricses = this.lines.map((function(_this) {
102 return function(line) {
103 return ctx.measureText2(line || 'X', fontSize, _this.font);
107 ascent: Math.max.apply(Math, this.metricses.map(function(arg) {
112 descent: Math.max.apply(Math, this.metricses.map(function(arg) {
114 descent = arg.descent;
117 fontsize: Math.max.apply(Math, this.metricses.map(function(arg) {
119 fontsize = arg.fontsize;
122 leading: Math.max.apply(Math, this.metricses.map(function(arg) {
124 leading = arg.leading;
127 width: Math.max.apply(Math, this.metricses.map(function(arg) {
132 height: Math.max.apply(Math, this.metricses.map(function(arg) {
138 minx: Math.min.apply(Math, this.metricses.map(function(arg) {
143 miny: Math.min.apply(Math, this.metricses.map(function(arg) {
148 maxx: Math.max.apply(Math, this.metricses.map(function(arg) {
153 maxy: Math.max.apply(Math, this.metricses.map(function(arg) {
160 this.boundingBoxWidth = Math.ceil(this.metrics.width);
163 TextRenderer.prototype.draw = function(ctx, x, y) {
164 var i, j, len, line, ref, results;
165 ctx.textBaseline = 'top';
166 ctx.font = this.font;
170 for (j = 0, len = ref.length; j < len; j++) {
172 ctx.fillText(line, x, y + i * this.metrics.leading);
173 results.push(i += 1);
178 TextRenderer.prototype.getWidth = function(isEditing) {
179 if (isEditing == null) {
182 if (this.forcedWidth) {
183 return this.forcedWidth;
186 return this.metrics.bounds.maxx + this.caratWidth;
188 return this.metrics.bounds.maxx;
193 TextRenderer.prototype.getHeight = function() {
194 return this.forcedHeight || (this.metrics.leading * this.lines.length);
201 module.exports = TextRenderer;