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