1 /*
  2  *  Copyright 2010 Scriptoid s.r.l
  3  */
  4 
  5 /**
  6  * A simple way of setting the style for a context
  7  * 
  8  * @this {Style}
  9  * @constructor
 10  * @author Zack Newsham <zack_newsham@yahoo.co.uk>
 11  * @author Alex Gheorghiu <alex@scriptoid.com>
 12  */
 13 function Style(){
 14     /**Font used*/
 15     this.font = null;
 16     
 17     /**Stroke/pen style*/
 18     this.strokeStyle = null;
 19     
 20     /**Fill style*/
 21     this.fillStyle = null
 22     
 23     /**Alpha/transparency value*/
 24     this.globalAlpha = null;
 25     
 26     /**Composite value*/
 27     this.globalCompositeOperation = null;
 28     
 29     /**Line width*/
 30     this.lineWidth = null;
 31     
 32     /**
 33      *Line cap style
 34      *
 35      *HTML5 Canvas: 
 36      *The (Canvas's) lineCap property determines how the end points of every line are drawn.
 37      *There are three possible values for this property and those are: butt, round and square.
 38      *By default this property is set to butt.
 39      *@see https://developer.mozilla.org/en/Canvas_tutorial/Applying_styles_and_colors#A_lineCap_example
 40      **/
 41     this.lineCap = this.STYLE_LINE_CAP_BUTT;
 42 
 43     /**
 44      *Line join style
 45      *
 46      *HTML5 Canvas:
 47      *The (Canvas's) lineJoin property determines how two connecting lines in a shape are joined together.
 48      *There are three possible values for this property: round, bevel and miter.
 49      *By default this property is set to miter.
 50      *@see https://developer.mozilla.org/en/Canvas_tutorial/Applying_styles_and_colors#A_lineJoin_example
 51      **/
 52     this.lineJoin = this.STYLE_LINE_JOIN_MITER;
 53     
 54     /**Shadow offset x. Not used yet*/
 55     this.shadowOffsetX = null;
 56     
 57     /**Shadow offset y. Not used yet*/
 58     this.shadowOffsetY = null;
 59     
 60     /**Shadow blur. Not used yet*/
 61     this.shadowBlur = null;
 62     
 63     /**Shadow color. Not used yet*/
 64     this.shadowColor = null;
 65     
 66     /**An {Array} of colors used in gradients*/
 67     this.addColorStop = [];
 68     
 69     /**An {Array} used in gradients*/
 70     this.linearGradient = [];
 71     
 72     /**Dash length used for dashed styles*/
 73     this.dashLength = 0;
 74     
 75     /**Image used*/
 76     this.image = null;
 77     
 78     /**Serialization type*/
 79     this.oType = "Style";
 80 }
 81 
 82 /**Loads a style from a JSONObject
 83  **/
 84 Style.load = function(o){
 85     var newStyle = new Style();
 86 
 87     newStyle.strokeStyle = o.strokeStyle;
 88     newStyle.fillStyle = o.fillStyle
 89     newStyle.globalAlpha = o.globalAlpha;
 90     newStyle.globalCompositeOperation = o.globalCompositeOperation;
 91     newStyle.lineWidth = o.lineWidth;
 92     newStyle.lineCap = o.lineCap;
 93     newStyle.lineJoin = o.lineJoin;
 94     newStyle.shadowOffsetX = o.shadowOffsetX;
 95     newStyle.shadowOffsetY = o.shadowOffsetY;
 96     newStyle.shadowBlur = o.shadowBlur;
 97     newStyle.shadowColor = o.shadowColor;
 98     newStyle.addColorStop = o.addColorStop;
 99     newStyle.linearGradient = o.linearGradient;
100     newStyle.dashLength = o.dashLength;
101     newStyle.image = o.image;
102 
103     return newStyle;
104 }
105 
106 Style.prototype={
107     /**Round join*/
108     STYLE_LINE_JOIN_ROUND: 'round',
109     
110     /**Bevel join*/
111     STYLE_LINE_JOIN_BEVEL: 'bevel',
112     
113     /**Mitter join*/
114     STYLE_LINE_JOIN_MITER: 'miter',
115     
116     /**Butt cap*/
117     STYLE_LINE_CAP_BUTT: 'butt',
118     
119     /**Round cap*/
120     STYLE_LINE_CAP_ROUND: 'round',
121     
122     /**Square cap*/
123     STYLE_LINE_CAP_SQUARE: 'square',
124 
125     /**Setup the style of a context
126      *@param {Context} context - the canvas context
127      **/
128     setupContext:function(context){
129         for(var propertyName in this){
130             if(propertyName != "linearGradient" && propertyName != "addColorStop" && propertyName != "image"){
131                 if(this[propertyName] != null && propertyName != undefined){
132                     context[propertyName] = this[propertyName];
133                 }
134             }
135         }
136 
137         if(this.linearGradient.length !=0 && image == null){
138             var lin = context.createLinearGradient(this.linearGradient[0], this.linearGradient[1], this.linearGradient[2], this.linearGradient[3]);
139 
140             for(var i=0; i<this.addColorStop.length; i++){
141                 lin.addColorStop(i, this.addColorStop[i]);
142             }
143 
144             context.fillStyle = lin;
145             this.fillStyle = lin;
146         }
147 
148         if(this.image != null && IE){
149             var ptrn = context.createPattern(this.image,'no-repeat');
150         //context.fillStyle=ptrn;
151         //this.fillStyle=ptrn;
152         }
153     },
154 
155 
156     clone: function(){
157         var anotherStyle = new Style;
158         for(var propertyName in anotherStyle){
159             if(propertyName!="addColorStop" && propertyName!="linearGradient"){
160                 anotherStyle[propertyName]=this[propertyName];
161             }
162             else{
163                 for(var i=0; i< this[propertyName].length; i++){
164                     anotherStyle[propertyName].push(this[propertyName][i]);
165                 }
166             }
167         }
168         return anotherStyle;
169     },
170 
171 
172     /**Try not to save the properties that are null
173      *The deleted property will be recreated and set to null while .load() method anyway
174      *@author Alex
175      **/
176     toJSON : function(){
177         var aClone = this.clone();
178         for(var propertyName in aClone){
179             if(aClone[propertyName] == null){
180                 delete aClone[propertyName];
181             }
182         }
183 
184         return aClone;
185     },
186 
187 
188     getGradient:function(){
189         return this.addColorStop[0]+"/"+this.addColorStop[1];
190     },
191 
192 
193     setGradient:function(figure, value){
194         this.addColorStop[0] = value.split("/")[0];
195         this.addColorStop[1] = value.split("/")[1];
196     },
197 
198     /**Merge current style with another style.
199      *If current style is missing some of other's feature it will be "enhanced" with them
200      *@param {Style} anotherStyle - the other style
201      *@author Zack Newsham <zack_newsham@yahoo.co.uk>
202      *@author Alex <alex@scriptoid.com>
203      **/
204     merge:function(anotherStyle){
205         for(var propertyName in anotherStyle){
206             if( (this[propertyName] == null || this[propertyName] == undefined) && propertyName != "image"){
207                 this[propertyName] = anotherStyle[propertyName];
208             }
209         }
210     },
211 
212 
213     transform:function(matrix){
214         if(this.linearGradient.length!=0){
215             var p1=new Point(this.linearGradient[0],this.linearGradient[1]);
216             var p2=new Point(this.linearGradient[2],this.linearGradient[3]);
217             p1.transform(matrix);
218             p2.transform(matrix);
219             this.linearGradient[0]=p1.x;
220             this.linearGradient[1]=p1.y;
221             this.linearGradient[2]=p2.x;
222             this.linearGradient[3]=p2.y;
223         }
224         if(this.image){
225             var p1 = new Point(0,0);
226             var p2 = new Point(this.image.width, this.image.height);
227             p1.transform(matrix);
228             p2.transform(matrix);
229             this.image.width = p2.x-p1.x;
230             this.image.height = p2.y-p1.y;
231         }
232     },
233 
234 
235     /**TODO: implement it*/
236     equals:function(anotherStyle){
237         if(!anotherStyle instanceof Style){
238             return false;
239         }
240         
241         //TODO: test members
242 
243         return true;
244     },
245 
246 
247     /**Transform all the style into a SVG style
248      *@author Alex Gheorghiu <alex@scriptoid.com>
249      **/
250     toSVG : function(){
251         var style = ' style="';
252 
253         style += 'stroke:' + ( (this.strokeStyle == null || this.strokeStyle == '') ? 'none' : this.strokeStyle) + ';';
254         style += 'fill:' + ( (this.fillStyle == null || this.fillStyle == '') ? 'none' : this.fillStyle) + ';';
255         style += 'stroke-width:' + ( (this.lineWidth == null || this.lineWidth == '') ? 'none' : this.lineWidth) + ';';
256         style += 'stroke-linecap:' + ( (this.lineCap == null || this.lineCap == '') ? 'inherit' : this.lineCap) + ';';
257         style += 'stroke-linejoin:' + ( (this.lineJoin == null || this.lineJoin == '') ? 'inherit' : this.lineJoin) + ';';
258         style += '" ';
259 
260         return style;
261     }
262 
263 }
264 
265