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 })();