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