1 //= require "object.class" 2 3 (function(global) { 4 5 "use strict"; 6 7 var fabric = global.fabric || (global.fabric = { }), 8 extend = fabric.util.object.extend, 9 clone = fabric.util.object.clone; 10 11 if (fabric.Text) { 12 fabric.warn('fabric.Text is already defined'); 13 return; 14 } 15 if (!fabric.Object) { 16 fabric.warn('fabric.Text requires fabric.Object'); 17 return; 18 } 19 20 /** 21 * @class Text 22 * @extends fabric.Object 23 */ 24 fabric.Text = fabric.util.createClass(fabric.Object, /** @scope fabric.Text.prototype */ { 25 26 /** 27 * @property 28 * @type Object 29 */ 30 options: { 31 top: 10, 32 left: 10, 33 fontsize: 20, 34 fontweight: 100, 35 fontfamily: 'Modernist_One_400', 36 path: null 37 }, 38 39 /** 40 * @property 41 * @type String 42 */ 43 type: 'text', 44 45 /** 46 * Constructor 47 * @method initialize 48 * @param {String} text 49 * @param {Object} [options] 50 * @return {fabric.Text} thisArg 51 */ 52 initialize: function(text, options) { 53 this.originalState = { }; 54 this._initStateProperties(); 55 this.text = text; 56 this.setOptions(options); 57 extend(this, this.options); 58 this.theta = this.angle * (Math.PI/180); 59 this.width = this.getWidth(); 60 this.setCoords(); 61 }, 62 63 /** 64 * Creates `stateProperties` list on an instance, and adds `fabric.Text` -specific ones to it (such as "fontfamily", "fontweight", etc.) 65 * @private 66 * @method initStateProperties 67 */ 68 _initStateProperties: function() { 69 var o; 70 if ((o = this.constructor) && 71 (o = o.superclass) && 72 (o = o.prototype) && 73 (o = o.stateProperties) && 74 o.clone) { 75 this.stateProperties = o.clone(); 76 this.stateProperties.push('fontfamily', 'fontweight', 'path'); 77 } 78 }, 79 80 /** 81 * Returns string representation of an instance 82 * @method toString 83 * @return {String} String representation of text object 84 */ 85 toString: function() { 86 return '#<fabric.Text ('+ this.complexity() +'): ' + 87 JSON.stringify({ text: this.text, fontfamily: this.fontfamily }) + '>'; 88 }, 89 90 /** 91 * @private 92 * @method _render 93 * @param {CanvasRenderingContext2D} ctx Context to render on 94 */ 95 _render: function(context) { 96 var o = Cufon.textOptions || (Cufon.textOptions = { }); 97 98 // export options to be used by cufon.js 99 o.left = this.left; 100 o.top = this.top; 101 o.context = context; 102 o.color = this.fill; 103 104 var el = this._initDummyElement(); 105 106 // set "cursor" to top/left corner 107 this.transform(context); 108 109 // draw text 110 Cufon.replaceElement(el, { 111 separate: 'none', 112 fontFamily: this.fontfamily 113 }); 114 115 // update width, height 116 this.width = o.width; 117 this.height = o.height; 118 }, 119 120 /** 121 * @private 122 * @method _initDummyElement 123 */ 124 _initDummyElement: function() { 125 var el = document.createElement('div'); 126 el.innerHTML = this.text; 127 128 // need to specify these manually, since Jaxer doesn't support retrieving computed style 129 el.style.fontSize = '40px'; 130 el.style.fontWeight = '400'; 131 el.style.fontStyle = 'normal'; 132 el.style.letterSpacing = 'normal'; 133 el.style.color = '#000000'; 134 el.style.fontWeight = '600'; 135 el.style.fontFamily = 'Verdana'; 136 137 return el; 138 }, 139 140 /** 141 * Renders text instance on a specified context 142 * @method render 143 * @param ctx {CanvasRenderingContext2D} context to render on 144 */ 145 render: function(context) { 146 context.save(); 147 this._render(context); 148 if (this.active) { 149 this.drawBorders(context); 150 this.drawCorners(context); 151 } 152 context.restore(); 153 }, 154 155 /** 156 * Returns object representation of an instance 157 * @method toObject 158 * @return {Object} Object representation of text object 159 */ 160 toObject: function() { 161 return extend(this.callSuper('toObject'), { 162 text: this.text, 163 fontsize: this.fontsize, 164 fontweight: this.fontweight, 165 fontfamily: this.fontfamily, 166 path: this.path 167 }); 168 }, 169 170 /** 171 * Sets "color" of an instance (alias of `set('fill', …)`) 172 * @method setColor 173 * @param {String} value 174 * @return {fabric.Text} thisArg 175 * @chainable 176 */ 177 setColor: function(value) { 178 this.set('fill', value); 179 return this; 180 }, 181 182 /** 183 * Sets fontsize of an instance and updates its coordinates 184 * @method setFontsize 185 * @param {Number} value 186 * @return {fabric.Text} thisArg 187 * @chainable 188 */ 189 setFontsize: function(value) { 190 this.set('fontsize', value); 191 this.setCoords(); 192 return this; 193 }, 194 195 /** 196 * Returns actual text value of an instance 197 * @method getText 198 * @return {String} 199 */ 200 getText: function() { 201 return this.text; 202 }, 203 204 /** 205 * Sets text of an instance, and updates its coordinates 206 * @method setText 207 * @param {String} value 208 * @return {fabric.Text} thisArg 209 * @chainable 210 */ 211 setText: function(value) { 212 this.set('text', value); 213 this.setCoords(); 214 return this; 215 }, 216 217 /** 218 * Sets specified property to a specified value 219 * @method set 220 * @param {String} name 221 * @param {Any} value 222 * @return {fabric.Text} thisArg 223 * @chainable 224 */ 225 set: function(name, value) { 226 this[name] = value; 227 if (name === 'fontfamily') { 228 this.path = this.path.replace(/(.*?)([^\/]*)(\.font\.js)/, '$1' + value + '$3'); 229 } 230 return this; 231 } 232 }); 233 234 /** 235 * Returns fabric.Text instance from an object representation 236 * @static 237 * @method fromObject 238 * @param {Object} object to create an instance from 239 * @return {fabric.Text} an instance 240 */ 241 fabric.Text.fromObject = function(object) { 242 return new fabric.Text(object.text, clone(object)); 243 }; 244 245 /** 246 * Returns fabric.Text instance from an SVG element (<b>not yet implemented</b>) 247 * @static 248 * @method fabric.Text.fromElement 249 * @return {fabric.Text} an instance 250 */ 251 fabric.Text.fromElement = function(element) { 252 // TODO (kangax): implement this 253 }; 254 })(this);