source: extensions/GrumPluginClasses/js/CanvasDraw.Drawing.js @ 17562

Last change on this file since 17562 was 17562, checked in by grum, 12 years ago

bug:2723
+ improve some GPC framework functionnalities

File size: 51.7 KB
Line 
1/** ----------------------------------------------------------------------------
2 * file         : CanvasDraw.Drawing.js
3 * file version : 1.0
4 * date         : 2010-09-25
5 * -----------------------------------------------------------------------------
6 * author: grum at grum.fr
7 * << May the Little SpaceFrog be with you >>
8 *
9 * This program is free software and is published under the terms of the GNU GPL
10 * Please read CanvasDraw.ReadMe.txt file for more information
11 *
12 * -----------------------------------------------------------------------------
13 *
14 * dependencies : jquery.js
15 *                CanvasDraw.CommonClasses.js
16 *
17 * -----------------------------------------------------------------------------
18 *
19 * The Drawing classes are designed to provide function allowing to draw on a
20 * canvas context
21 *
22 * provided classes :
23 *  - CDDrawing
24 *    . properties
25 *    . constructor(canvas)
26 *    . setContextFromCanvasId(canvasId)
27 *    . setContextFromCanvas(canvas)
28 *    . getContext()
29 *    . getContextWidth()
30 *    . getContextHeight()
31 *    . drawingManageCrisp(manage)
32 *    . drawingStatePush()
33 *    . drawingStatePop()
34 *    . transformTranslate(param)
35 *    . transformScale(param)
36 *    . transformRotate(param)
37 *    . transformMatrix(reset, m11, m12, m21, m22, dx, dy)
38 *    . imageCount()
39 *    . imageLoad(url)
40 *    . imageLoaded(url)
41 *    . imageLoadSetOnProgressEvent(eventFunction))
42 *    . imageLoadSetOnEndEvent(eventFunction))
43 *    . imageDraw(url, x, y)
44 *    . imageDrawScaled(url, x, y, width, height)
45 *    . imageDrawSliced(url, sX, sY, sWidth, sHeight, dX, dY, dWidth, dHeight)
46 *    . shapeClearRect(x, y, width, height)
47 *    . shapePathBegin()
48 *    . shapePathEnd(close, fill)
49 *    . shapePathMoveTo(x, y)
50 *    . shapePathLineTo(x, y)
51 *    . shapePathArc(x, y, radius, startAngle, endAngle, antiClockwise, mode)
52 *    . shapePathCurveBezier(cp1x, cp1y, cp2x, cp2y, x, y)
53 *    . shapePathCurveQuadratic(cp1x, cp1y, x, y)
54 *    . shapeLine(xs, ys, xe, ye)
55 *    . shapeRect(x, y, width, height, fill)
56 *    . shapeRoundRect(x, y, width, height, radiusWidth, radiusHeight, fill)
57 *    . shapeEllipse(x, y, width, height, fill)
58 *    . shapeCircle(x,y,radius, fill)
59 *    . shapeStar(x,y,outerRadius,innerRadius,numVertices, fill)
60 *    . shapePolygon(x,y,radius,numEdges, fill)
61 *    . shapeArrow(xs, ys, xe, ye, width, numHead, lengthHead, angleHead, styleHead, fill)
62 *    . shapeSimpleShape(mode, points, fill)
63 *    . shapeComplexShape(mode, points, fill)
64 *    . styleStrokeColor(color)
65 *    . styleStrokeGradient(mode, start, end, gradients)
66 *    . styleStrokePattern(url, mode)
67 *    . styleStrokeDraw(param)
68 *    . styleFillColor(color)
69 *    . styleFillGradient(mode, start, end, gradients)
70 *    . styleFillPattern(url, mode)
71 *    . styleGlobalAlpha(opacity)
72 *    . styleShadow(offsetX, offsetY, blur, color)
73 *    . styleShadowReset()
74 *    . textPrint(text, x, y, mode)
75 *    . textStyle(param)
76 *    . textWidth(text)
77 *
78 * -----------------------------------------------------------------------------
79 */
80
81
82
83
84function CDDrawing(canvasContext) {
85
86  var properties = {
87    isCanvasContext:false,
88    canvasContext:null,
89    canvas:null,
90    imagesUrl:new Array(),
91    imagesObj:new Array(),
92    imagesLoaded:0,
93    imagesLoadOnProgress:null,
94    imagesLoadOnEnd:null,
95    manageCrisp:false,
96  }
97
98  /**
99   * constructor for the object need one parameter : a canvas Id or a canvas
100   * object
101   *
102   * if the given canvas don't allow to return a canvas context, the object
103   * don't allow to draw
104   *
105   * @param String canvas : a canvas Id
106   *
107   * or
108   *
109   * @param Object canvas : a canvas object
110   */
111  this.constructor = function (canvas)
112  {
113    if(canvas!=null)
114    {
115      if(typeof(canvas)=='string')
116      {
117        this.setContextFromCanvasId(canvas);
118      }
119      else if(typeof(canvas)=='object')
120      {
121        this.setContextFromCanvas(canvas);
122      }
123    }
124  }
125
126
127  /**
128   * this function allows to change the canvas context from a canvas Id
129   *
130   * if the the given canvas Id don't allow the get a canvas context, the
131   * previous canvas context is kept
132   *
133   * @param String canvasId : Id of the canvas
134   * @return Bool : true if canvas is Ok, otherwise false
135   */
136  this.setContextFromCanvasId = function (canvasId)
137  {
138    var canvas = $('#'+canvasId).get(0);
139    return(this.setContextFromCanvas(canvas));
140  }
141
142
143  /**
144   * this function allows to change the canvas context from a canvas object
145   *
146   * if the the given canvas object don't allow the get a canvas context, the
147   * previous canvas context is kept
148   *
149   * @param Object canvas : the canvas
150   * @return Bool : true if canvas is Ok, otherwise false
151   */
152  this.setContextFromCanvas = function (canvas)
153  {
154    if(canvas!=null)
155    {
156      if(canvas.getContext)
157      {
158        properties.canvas=canvas;
159        properties.isCanvasContext=true;
160        properties.canvasContext=canvas.getContext('2d');
161        return(true);
162      }
163    }
164    return(false);
165  }
166
167  /**
168   * returns the canvas context
169   *
170   * @return
171   */
172  this.getContext = function ()
173  {
174    return(properties.canvasContext);
175  }
176
177  /**
178   * returns the canvas context width
179   *
180   * @return Integer
181   */
182  this.getContextWidth = function ()
183  {
184    return(properties.canvas.width);
185  }
186
187  /**
188   * returns the canvas context height
189   *
190   * @return Integer
191   */
192  this.getContextHeight = function ()
193  {
194    return(properties.canvas.height);
195  }
196
197  /**
198   * allows to define if crisp have to be managed
199   *
200   * @param Bool manage
201   * @return Bool : the value actually set
202   */
203  this.drawingManageCrisp = function(manage)
204  {
205    if(!properties.isCanvasContext) return(false);
206
207    if(manage==true || manage==false)
208    {
209      if(!properties.manageCrisp && manage)
210      {
211        properties.canvasContext.translate(0.5,0.5);
212        properties.manageCrisp=manage;
213        return(true);
214      }
215      else if(properties.manageCrisp && !manage)
216      {
217        properties.canvasContext.translate(-0.5,-0.5);
218        properties.manageCrisp=manage;
219        return(true);
220      }
221    }
222
223    return(false);
224  }
225
226
227
228
229  /**
230   *
231   * @return Bool : true if can draw, otherwise false
232   */
233  this.drawingStatePush = function ()
234  {
235    if(properties.canvasContext==null) return (false);
236    properties.canvasContext.save();
237    return(true);
238  }
239
240  /**
241   *
242   * @return Bool : true if can draw, otherwise false
243   */
244  this.drawingStatePop = function ()
245  {
246    if(properties.canvasContext==null) return (false);
247    properties.canvasContext.restore();
248    return(true);
249  }
250
251  /**
252   * this function apply a translation on the canvas.
253   * one object is given as parameter, and can have two properties
254   *  x : the absissa translation
255   *  y : the ordinate translation
256   *
257   * if a parameter is not given, assuming the defaut translation values
258   *  x : 0
259   *  y : 0
260   *
261   * @param Object param : an object with properties x and y
262   * @return Bool : true if can draw, otherwise false
263   */
264  this.transformTranslate = function (param)
265  {
266    if(properties.canvasContext==null) return (false);
267
268    if(param==null || param.constructor!=Object) param = { x:0, y:0 }
269    if(param.x==null) param.x=0;
270    if(param.y==null) param.y=0;
271    properties.canvasContext.translate(param.x,param.y);
272    return(true);
273  }
274
275  /**
276   * this function apply a scaling on the canvas.
277   * one object is given as parameter, and can have two properties
278   *  x : the absissa scaling
279   *  y : the ordinate scaling
280   *
281   * if a parameter is not given, assuming the defaut scaling values
282   *  x : 1
283   *  y : 1
284   *
285   * @param Object param : an object with properties x and y
286   * @return Bool : true if can draw, otherwise false
287   */
288
289  this.transformScale = function (param)
290  {
291    if(properties.canvasContext==null) return (false);
292
293    if(param==null || param.constructor!=Object) param = { x:1, y:1 }
294    if(param.x==null) param.x=1;
295    if(param.y==null) param.y=1;
296    properties.canvasContext.scale(param.x,param.y);
297    return(true);
298  }
299
300
301  /**
302   * this function apply a rotation on the canvas.
303   * one object is given as parameter, and can have two properties
304   *  angle : the rotation angle
305   *  mode : the expression of angle 'degree' or 'radian'
306   *
307   * if a parameter is not given, assuming the defaut rotating values
308   *  angle : 0
309   *  mode  : 'degree'
310   *
311   * @param Object param : an object with properties x and y
312   * @return Bool : true if can draw, otherwise false
313   */
314  this.transformRotate = function (param)
315  {
316    if(properties.canvasContext==null) return (false);
317
318    if(param==null || param.constructor!=Object) param = { angle:0, mode:'degree' }
319    if(param.angle==null) param.angle=0;
320    if(!(param.mode=='degree' || param.mode=='radian')) param.mode='degree';
321
322    param.angle=-param.angle;
323
324    if(param.mode=='degree') param.angle=param.angle*Math.PI/180;
325    properties.canvasContext.rotate(param.angle);
326    return(true);
327  }
328
329  /**
330   * this function apply a transformation matrix on the canvas.
331   * one object is given as parameter, and can have 7 properties
332   *  reset : reset the transformation matrix or no
333   *  m11, m12, m21, m22, dx, dy : the matrix values
334   *            [ m11  m21  dx ]
335   *            [ m12  m22  dy ]
336   *            [ 0    0    1  ]
337   *
338   * @param Bool reset : if true, the matrix values are reseted before applying
339   *                     new values
340   * @param Float m11, m12, m21, m22, dx, dy : matrix values
341   * @return Bool : true if can draw, otherwise false
342   */
343  this.transformMatrix = function (reset, m11, m12, m21, m22, dx, dy)
344  {
345    if(properties.canvasContext==null) return (false);
346
347    if(reset)
348    {
349      properties.canvasContext.setTransform(m11, m12, m21, m22, dx, dy);
350    }
351    else
352    {
353      properties.canvasContext.transform(m11, m12, m21, m22, dx, dy);
354    }
355
356    return(true);
357  }
358
359  /**
360   * this function returns the number of pictures
361   *
362   * @return Integer :
363   */
364  this.imageCount = function ()
365  {
366    return(properties.imagesUrl.length);
367  }
368
369  /**
370   * this function loads images in an array, allowing to manage image by their
371   * url
372   *
373   * @param Object param : an object with properties x and y
374   * @return Bool : true if can draw, otherwise false
375   */
376  this.imageLoad = function (url)
377  {
378    if($.inArray(url, properties.imagesUrl)==-1)
379    {
380      img=new Image();
381      $(img).bind('load', {url:url}, imageLoadProgressEvent);
382      img.src=url;
383
384      properties.imagesUrl.push(url);
385      properties.imagesObj.push(img);
386
387      delete img;
388    }
389  }
390
391  /**
392   * this function returns true if the image is loaded
393   *
394   * if no url is given (url is an empty string or null), the function checks
395   * if all images are loaded
396   *
397   * @param String url : the image to check
398   * @return Object|Bool :
399   */
400  this.imageLoaded = function (url)
401  {
402    if(url=='' || url==null)
403    {
404      if(properties.imagesObj.length!=properties.imagesLoaded)
405      {
406        return(false);
407      }
408      return(true);
409    }
410    else
411    {
412      index=$.inArray(url, properties.imagesUrl);
413      if(index!=-1)
414      {
415        if(properties.imagesObj[index].complete)
416        {
417          return(
418            {
419              index:index,
420              width:properties.imagesObj[index].width,
421              height:properties.imagesObj[index].height
422            }
423          );
424        }
425      }
426      return(
427        {
428          index:-1,
429          width:0,
430          height:0
431        }
432      );
433    }
434  }
435
436  /**
437   * this method allows to define a callback function wich will be called each
438   * time a picture is loaded
439   *
440   * the given function must have 2 parameters :
441   *  - percent : percent of loading
442   *  - url     : url of the loaded picture
443   *
444   * @param Function eventFunction : the function to set
445   * @return Bool : true is set is Ok, otherwise false
446   */
447  this.imageLoadSetOnProgressEvent = function (eventFunction)
448  {
449    if($.isFunction(eventFunction))
450    {
451      properties.imagesLoadOnProgress = eventFunction;
452      return(true);
453    }
454    return(false);
455  }
456
457  /**
458   * this method allows to define a callback function wich will be called when
459   * all given pictures are loaded
460   *
461   * the given function don't need parameters
462   *
463   * @param Function eventFunction : the function to set
464   * @return Bool : true is set is Ok, otherwise false
465   */
466  this.imageLoadSetOnEndEvent = function (eventFunction)
467  {
468    if($.isFunction(eventFunction))
469    {
470      properties.imagesLoadOnEnd = eventFunction;
471      return(true);
472    }
473    return(false);
474  }
475
476
477  /**
478   * called each time a picture is loaded, and trigger the imageLoadOnProgress()
479   * and imageLoadOnEnd() function if defined
480   */
481  var imageLoadProgressEvent = function (event) {
482    properties.imagesLoaded++;
483
484    if($.isFunction(properties.imagesLoadOnProgress))
485    {
486      properties.imagesLoadOnProgress(100*properties.imagesLoaded/properties.imagesUrl.length,
487        {
488         url: event.data.url,
489         fullUrl:event.target.src,
490         handler:event.target
491        });
492    }
493
494    if(properties.imagesLoaded==properties.imagesUrl.length && $.isFunction(properties.imagesLoadOnEnd))
495    {
496      properties.imagesLoadOnEnd();
497    }
498  }
499
500
501  /**
502   * draw an image on the canvas from its url
503   *
504   * @param String url : the url of image
505   * @param Integer x : the x position on the canvas
506   * @param Integer y : the y position on the canvas
507   * @return Bool : true if drawed, otherwise false
508   */
509  this.imageDraw = function (url, x, y)
510  {
511    if(properties.canvasContext==null) return (false);
512
513    imageIndex=this.imageLoaded(url);
514    if(imageIndex.index==-1) return(false);
515
516
517    if(properties.manageCrisp)
518    {
519      properties.canvasContext.save();
520      properties.canvasContext.translate(-0.5,-0.5);
521      properties.canvasContext.drawImage(properties.imagesObj[imageIndex.index], x, y);
522      properties.canvasContext.restore();
523    }
524    else
525    {
526      properties.canvasContext.drawImage(properties.imagesObj[imageIndex.index], x, y);
527    }
528
529    return(true);
530  }
531
532  /**
533   * draw an image on the canvas from its url, with given dimensions
534   *
535   * @param String url : the url of image
536   * @param Integer x : the x position on the canvas
537   * @param Integer y : the y position on the canvas
538   * @param Integer width  : the width of the image on the canvas
539   * @param Integer height : the height of the image on the canvas
540   * @return Bool : true if drawed, otherwise false
541   */
542  this.imageDrawScaled = function (url, x, y, width, height)
543  {
544    if(properties.canvasContext==null) return (false);
545
546    imageIndex=this.imageLoaded(url);
547    if(imageIndex.index==-1) return(false);
548
549
550    if(properties.manageCrisp)
551    {
552      properties.canvasContext.save();
553      properties.canvasContext.translate(-0.5,-0.5);
554      properties.canvasContext.drawImage(properties.imagesObj[imageIndex.index], x, y, width, height);
555      properties.canvasContext.restore();
556    }
557    else
558    {
559      properties.canvasContext.drawImage(properties.imagesObj[imageIndex.index], x, y, width, height);
560    }
561
562    return(true);
563  }
564
565  /**
566   * draw a portion of an image on the canvas from its url, with given dimensions
567   *
568   * @param String url : the url of image
569   * @param Integer sX : the x position on the source image
570   * @param Integer sY : the y position on the source image
571   * @param Integer sWidth  : the width of the source image
572   * @param Integer sHeight : the height of the source image
573   * @param Integer dX : the x position on the canvas
574   * @param Integer dY : the y position on the canvas
575   * @param Integer dWidth  : the width of the image on the canvas
576   * @param Integer dHeight : the height of the image on the canvas
577   * @return Bool : true if drawed, otherwise false
578   */
579  this.imageDrawSliced = function (url, sX, sY, sWidth, sHeight, dX, dY, dWidth, dHeight)
580  {
581    if(properties.canvasContext==null) return (false);
582
583    imageIndex=this.imageLoaded(url);
584    if(imageIndex.index==-1) return(false);
585
586    if(properties.manageCrisp)
587    {
588      properties.canvasContext.save();
589      properties.canvasContext.translate(-0.5,-0.5);
590      properties.canvasContext.drawImage(properties.imagesObj[imageIndex.index], sX, sY, sWidth, sHeight, dX, dY, dWidth, dHeight);
591      properties.canvasContext.restore();
592    }
593    else
594    {
595      properties.canvasContext.drawImage(properties.imagesObj[imageIndex.index], sX, sY, sWidth, sHeight, dX, dY, dWidth, dHeight);
596    }
597
598    return(true);
599  }
600
601
602  /**
603   * clear (set transparency) a rectangular area
604   *
605   * @param Integer x : the left coordinate
606   * @param Integer y : the top coordinate
607   * @param Integer width  : the rectangle width
608   * @param Integer height : the rectangle height
609   * @return Bool : true if drawed, otherwise false
610   */
611  this.shapeClearRect = function (x, y, width, height)
612  {
613    if(properties.canvasContext==null) return (false);
614
615    properties.canvasContext.clearRect(x,y,width,height);
616    return(true);
617  }
618
619  /**
620   * begins a new path
621   *
622   * @return Bool : true if drawed, otherwise false
623   */
624  this.shapePathBegin = function ()
625  {
626    if(properties.canvasContext==null) return (false);
627
628    properties.canvasContext.beginPath();
629    return(true);
630  }
631
632  /**
633   * ends a path
634   *
635   * @param Bool close : if set to true, close the path by drawing a line
636   *                     otherwise the path stays open
637   * @param Bool fill  : if set to true, fill the path with current fill
638   *                      properties, otherwise the path stays empty
639   * @return Bool : true if drawed, otherwise false
640   */
641  this.shapePathEnd = function(close, fill)
642  {
643    if(properties.canvasContext==null) return (false);
644
645    if(close) properties.canvasContext.closePath();
646    if(fill)
647    {
648      properties.canvasContext.fill();
649    }
650    else
651    {
652      properties.canvasContext.stroke();
653    }
654    return(true);
655  }
656
657  /**
658   * move pen to the given coordinates
659   *
660   * @param Integer x :
661   * @param Integer y :
662   * @return Bool : true if drawed, otherwise false
663   */
664  this.shapePathMoveTo = function (x, y)
665  {
666    if(properties.canvasContext==null) return (false);
667
668    properties.canvasContext.moveTo(x,y);
669    return(true);
670  }
671
672  /**
673   * draws a line from current point to the given coordinates
674   *
675   * @param Integer x :
676   * @param Integer y :
677   * @return Bool : true if drawed, otherwise false
678   */
679  this.shapePathLineTo = function (x, y)
680  {
681    if(properties.canvasContext==null) return (false);
682
683    properties.canvasContext.lineTo(x,y);
684    return(true);
685  }
686
687  /**
688   * draws an arc
689   *
690   * @param Integer x : x coordinate
691   * @param Integer y : y coordinate
692   * @param Integer radius : arc radius
693   * @param Float startAngle :
694   * @param Float endAngle :
695   * @param Bool antiClockwise : if true, arc is drawn in anticlockwise direction
696   * @param String mode : define the expression of given angles 'degree' or 'radian'
697   * @return Bool : true if drawed, otherwise false
698   */
699  this.shapePathArc = function(x, y, radius, startAngle, endAngle, antiClockwise, mode)
700  {
701    if(properties.canvasContext==null) return (false);
702
703    if(!(mode=='degree' || mode=='radian')) mode='degree';
704    if(mode=='degree')
705    {
706      startAngle=startAngle*Math.PI/180;
707      endAngle=endAngle*Math.PI/180;
708    }
709    startAngle=-startAngle;
710    endAngle=-endAngle;
711
712    properties.canvasContext.arc(x, y, radius, startAngle, endAngle, antiClockwise);
713    return(true);
714  }
715
716
717  /**
718   * draws a bezier curve from the current point to the given coordinate
719   * you can have more information about how this function works on this page :
720   *    https://developer.mozilla.org/en/Canvas_tutorial/Drawing_shapes
721   *
722   * @param Integer cp1x : control point 1 x coordinate
723   * @param Integer cp1y : control point 1 y coordinate
724   * @param Integer cp1x : control point 2 x coordinate
725   * @param Integer cp1y : control point 2 y coordinate
726   * @param Integer x : destination x coordinate
727   * @param Integer y : destination y coordinate
728   * @return Bool : true if drawed, otherwise false
729   */
730  this.shapePathCurveBezier = function(cp1x, cp1y, cp2x, cp2y, x, y)
731  {
732    if(properties.canvasContext==null) return (false);
733
734    properties.canvasContext.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
735    return(true);
736  }
737
738  /**
739   * draws a quadratic curve from the current point to the given coordinate
740   * you can have more information about how this function works on this page :
741   *    https://developer.mozilla.org/en/Canvas_tutorial/Drawing_shapes
742   *
743   * @param Integer cp1x : control point 1 x coordinate
744   * @param Integer cp1y : control point 1 y coordinate
745   * @param Integer x : destination x coordinate
746   * @param Integer y : destination y coordinate
747   * @return Bool : true if drawed, otherwise false
748   */
749  this.shapePathCurveQuadratic = function(cp1x, cp1y, x, y)
750  {
751    if(properties.canvasContext==null) return (false);
752
753    properties.canvasContext.quadraticCurveTo(cp1x, cp1y, x, y);
754    return(true);
755  }
756
757  /**
758   * draws a line between two points
759   *
760   * @param Integer xs : start x coordinate
761   * @param Integer ys : start y coordinate
762   * @param Integer xe : end x coordinate
763   * @param Integer ye : end y coordinate
764   * @return Bool : true if drawed, otherwise false
765   */
766  this.shapeLine = function(xs, ys, xe, ye)
767  {
768    if(properties.canvasContext==null) return (false);
769
770    properties.canvasContext.beginPath();
771    properties.canvasContext.moveTo(xs, ys);
772    properties.canvasContext.lineTo(xe, ye);
773    properties.canvasContext.stroke();
774    return(true);
775  }
776
777  /**
778   * draws a rectangle
779   *
780   * @param Integer x : the left coordinate
781   * @param Integer y : the top coordinate
782   * @param Integer width  : the rectangle width
783   * @param Integer height : the rectangle height
784   * @param Object mode : 2 properties
785   *                        fill: true or false (default:true)
786   *                        stroke: true or false (default:true)
787   * @return Bool : true if drawed, otherwise false
788   */
789  this.shapeRect = function(x, y, width, height, mode)
790  {
791    if(properties.canvasContext==null) return (false);
792
793    if(mode==null) mode={fill:true, stroke:true};
794    if(mode.fill==null) mode.fill=true;
795    if(mode.stroke==null) mode.stroke=true;
796    modeLoop=new Array();
797    if(mode.fill) modeLoop.push('fill');
798    if(mode.stroke) modeLoop.push('stroke');
799
800    for(this.loop=0;this.loop<modeLoop.length;this.loop++)
801    {
802      if(modeLoop[this.loop]=='fill')
803      {
804        properties.canvasContext.fillRect(x, y, width, height);
805      }
806      else
807      {
808        properties.canvasContext.save();
809        if(mode.fill) properties.canvasContext.shadowColor='rgba(0,0,0,0)';
810        properties.canvasContext.strokeRect(x, y, width, height);
811        properties.canvasContext.restore();
812      }
813    }
814    return(true);
815  }
816
817  /**
818   * draws a rectangle with rounded corner
819   *
820   * @param Integer x : the left coordinate
821   * @param Integer y : the top coordinate
822   * @param Integer width  : the rectangle width
823   * @param Integer height : the rectangle height
824   * @param Integer radiusWidth :
825   * @param Integer radiusHeight :
826   * @param Object mode : 2 properties
827   *                        fill: true or false (default:true)
828   *                        stroke: true or false (default:true)
829   * @return Bool : true if drawed, otherwise false
830   */
831  this.shapeRoundRect = function(x, y, width, height, radiusWidth, radiusHeight, mode)
832  {
833    if(properties.canvasContext==null) return (false);
834
835    if(mode.fill==null) mode.fill=true;
836    if(mode.stroke==null) mode.stroke=true;
837    modeLoop=new Array();
838    if(mode.fill) modeLoop.push('fill');
839    if(mode.stroke) modeLoop.push('stroke');
840
841    for(this.loop=0;this.loop<modeLoop.length;this.loop++)
842    {
843      properties.canvasContext.beginPath();
844      properties.canvasContext.moveTo(x+radiusWidth,y);
845      properties.canvasContext.lineTo(x+width-radiusWidth,y);
846      properties.canvasContext.quadraticCurveTo(x+width,y,x+width,y+radiusHeight);
847      properties.canvasContext.lineTo(x+width,y+height-radiusHeight);
848      properties.canvasContext.quadraticCurveTo(x+width,y+height,x+width-radiusWidth,y+height);
849      properties.canvasContext.lineTo(x+radiusWidth,y+height);
850      properties.canvasContext.quadraticCurveTo(x,y+height,x,y+height-radiusHeight);
851      properties.canvasContext.lineTo(x,y+radiusHeight);
852      properties.canvasContext.quadraticCurveTo(x,y,x+radiusWidth,y);
853
854      if(modeLoop[this.loop]=='fill')
855      {
856        properties.canvasContext.fill();
857      }
858      else
859      {
860        properties.canvasContext.save();
861        if(mode.fill) properties.canvasContext.shadowColor='rgba(0,0,0,0)';
862        properties.canvasContext.stroke();
863        properties.canvasContext.restore();
864      }
865    }
866    return(true);
867  }
868
869
870  /**
871   * draws an ellipse (defined by a rectangle limits)
872   *
873   * @param Integer x : the left coordinate
874   * @param Integer y : the top coordinate
875   * @param Integer width  : the rectangle width
876   * @param Integer height : the rectangle height
877   * @param Object mode : 2 properties
878   *                        fill: true or false (default:true)
879   *                        stroke: true or false (default:true)
880   * @return Bool : true if drawed, otherwise false
881   */
882  this.shapeEllipse = function(x, y, width, height, mode)
883  {
884    if(properties.canvasContext==null || width==0 || height==0) return (false);
885
886    if(mode.fill==null) mode.fill=true;
887    if(mode.stroke==null) mode.stroke=true;
888    modeLoop=new Array();
889    if(mode.fill) modeLoop.push('fill');
890    if(mode.stroke) modeLoop.push('stroke');
891
892    ratio=width/height;
893
894    for(this.loop=0;this.loop<modeLoop.length;this.loop++)
895    {
896      properties.canvasContext.save();
897      properties.canvasContext.translate(x,y);
898      properties.canvasContext.scale(ratio,1);
899      properties.canvasContext.beginPath();
900      properties.canvasContext.arc(height/2,height/2, height/2, 0, Math.PI*2, true);
901
902      if(modeLoop[this.loop]=='fill')
903      {
904        properties.canvasContext.fill();
905      }
906      else
907      {
908        properties.canvasContext.save();
909        if(mode.fill) properties.canvasContext.shadowColor='rgba(0,0,0,0)';
910        properties.canvasContext.stroke();
911        properties.canvasContext.restore();
912      }
913      properties.canvasContext.restore();
914    }
915    return(true);
916  }
917
918  /**
919   * draws a circle (defined by a center point + radius)
920   *
921   * @param Integer x : the x center coordinate
922   * @param Integer y : the y center coordinate
923   * @param Integer radius : the circle radius
924   * @param Object mode : 2 properties
925   *                        fill: true or false (default:true)
926   *                        stroke: true or false (default:true)
927   * @return Bool : true if drawed, otherwise false
928   */
929  this.shapeCircle = function(x,y,radius, mode)
930  {
931    if(properties.canvasContext==null) return (false);
932
933    if(mode.fill==null) mode.fill=true;
934    if(mode.stroke==null) mode.stroke=true;
935    modeLoop=new Array();
936    if(mode.fill) modeLoop.push('fill');
937    if(mode.stroke) modeLoop.push('stroke');
938
939    for(this.loop=0;this.loop<modeLoop.length;this.loop++)
940    {
941      properties.canvasContext.beginPath();
942      properties.canvasContext.arc(x,y,radius, 0, Math.PI*2, true);
943
944      if(modeLoop[this.loop]=='fill')
945      {
946        properties.canvasContext.fill();
947      }
948      else
949      {
950        properties.canvasContext.save();
951        if(mode.fill) properties.canvasContext.shadowColor='rgba(0,0,0,0)';
952        properties.canvasContext.stroke();
953        properties.canvasContext.restore();
954      }
955
956    }
957    return(true);
958  }
959
960
961  /**
962   * draws a star (defined by a center point)
963   *
964   * @param Integer x : the x center coordinate
965   * @param Integer y : the y center coordinate
966   * @param Integer outerRadius : the outer radius of vertices star
967   * @param Integer innerRadius : the inner radius of vertices star
968   *                                if innerRadius = 0, the inner radius is
969   *                                computed automatically
970   * @param Integer numVertices : the number of vertices
971   * @param Object mode : 2 properties
972   *                        fill: true or false (default:true)
973   *                        stroke: true or false (default:true)
974   * @return Bool : true if drawed, otherwise false
975   */
976  this.shapeStar = function(x,y,outerRadius,innerRadius,numVertices, mode)
977  {
978    if(properties.canvasContext==null) return (false);
979
980    if(mode.fill==null) mode.fill=true;
981    if(mode.stroke==null) mode.stroke=true;
982    modeLoop=new Array();
983    if(mode.fill) modeLoop.push('fill');
984    if(mode.stroke) modeLoop.push('stroke');
985
986
987    if(numVertices<5) numVertices=5;
988
989    for(this.loop=0;this.loop<modeLoop.length;this.loop++)
990    {
991      properties.canvasContext.beginPath();
992
993      angle=2*Math.PI/numVertices;
994      if(innerRadius<=0) innerRadius=Math.abs(outerRadius*Math.sin(Math.PI/2-angle)/Math.cos(angle/2));
995
996
997      properties.canvasContext.moveTo(x, y-outerRadius);
998
999      for(this.i=0;this.i<numVertices;this.i++)
1000      {
1001        xc=x+innerRadius*Math.cos(Math.PI/2-angle*(this.i+1)+angle/2);
1002        yc=y-innerRadius*Math.sin(Math.PI/2-angle*(this.i+1)+angle/2);
1003        properties.canvasContext.lineTo(xc, yc);
1004
1005        xc=x+outerRadius*Math.cos(Math.PI/2-angle*(this.i+1));
1006        yc=y-outerRadius*Math.sin(Math.PI/2-angle*(this.i+1));
1007        properties.canvasContext.lineTo(xc, yc);
1008      }
1009
1010      if(modeLoop[this.loop]=='fill')
1011      {
1012        properties.canvasContext.fill();
1013      }
1014      else
1015      {
1016        properties.canvasContext.stroke();
1017      }
1018    }
1019    return(true);
1020  }
1021
1022
1023  /**
1024   * draws a star (defined by a center point)
1025   *
1026   * @param Integer x : the x center coordinate
1027   * @param Integer y : the y center coordinate
1028   * @param Integer outerRadius : the outer radius of vertices star
1029   * @param Integer innerRadius : the inner radius of vertices star
1030   *                                if innerRadius = 0xFFFF, the inner radius is
1031   *                                computed automatically
1032   * @param Integer numVertices : the number of vertices
1033   * @param Object mode : 2 properties
1034   *                        fill: true or false (default:true)
1035   *                        stroke: true or false (default:true)
1036   * @return Bool : true if drawed, otherwise false
1037   */
1038  this.shapePolygon = function(x,y,radius,numEdges, mode)
1039  {
1040    if(properties.canvasContext==null) return (false);
1041
1042    if(mode.fill==null) mode.fill=true;
1043    if(mode.stroke==null) mode.stroke=true;
1044    modeLoop=new Array();
1045    if(mode.fill) modeLoop.push('fill');
1046    if(mode.stroke) modeLoop.push('stroke');
1047
1048    if(numEdges<3) numEdges=3;
1049
1050    for(this.loop=0;this.loop<modeLoop.length;this.loop++)
1051    {
1052      properties.canvasContext.beginPath();
1053
1054      angle=2*Math.PI/numEdges;
1055
1056      properties.canvasContext.moveTo(x, y-radius);
1057
1058      for(this.i=0;this.i<numEdges;this.i++)
1059      {
1060        xc=x+radius*Math.cos(Math.PI/2-angle*(this.i+1));
1061        yc=y-radius*Math.sin(Math.PI/2-angle*(this.i+1));
1062        properties.canvasContext.lineTo(xc, yc);
1063      }
1064
1065      if(modeLoop[this.loop]=='fill')
1066      {
1067        properties.canvasContext.fill();
1068      }
1069      else
1070      {
1071        properties.canvasContext.stroke();
1072      }
1073    }
1074    return(true);
1075  }
1076
1077  /**
1078   * draws an arrow
1079   *
1080   * @param Integer xs : start x coordinate
1081   * @param Integer ys : start y coordinate
1082   * @param Integer xe : end x coordinate
1083   * @param Integer ye : end y coordinate
1084   * @param Integer width : width of the arrow, used if styleHead is set to 0x0012
1085   *                        if width is set to 0xFFFF, width is computed automatically
1086   * @param Integer numHead : number of head (1 or 2)
1087   * @param Integer lengthHead : length (size) of head in pixel
1088   * @param Integer angleHead : angle (in degree) of head, , allowing to choose
1089   *                            an acute or obtuse look
1090   * @param Integer styleHead : 0x0010 : body is a line, head is line
1091   *                            0x0011 : body is a line, head is a closed triangle
1092   *                            0x0012 : body is an area, head is an area
1093   * @param Object mode : 2 properties
1094   *                        fill: true or false (default:true)
1095   *                        stroke: true or false (default:true)
1096   * @return Bool : true if drawed, otherwise false
1097   */
1098  this.shapeArrow = function(xs, ys, xe, ye, width, numHead, lengthHead, angleHead, styleHead, mode)
1099  {
1100    if(properties.canvasContext==null) return (false);
1101
1102    if(mode.fill==null) mode.fill=true;
1103    if(mode.stroke==null) mode.stroke=true;
1104    modeLoop=new Array();
1105    if(mode.fill) modeLoop.push('fill');
1106    if(mode.stroke) modeLoop.push('stroke');
1107
1108
1109    if(numHead<1)
1110    {
1111      numHead=1;
1112    }
1113    else if(numHead>2)
1114    {
1115      numHead=2;
1116    }
1117
1118    angleHead=angleHead*Math.PI/180;
1119
1120    points=[
1121      new CDPoint(),
1122      new CDPoint(),
1123      new CDPoint(),
1124      new CDPoint(),
1125      new CDPoint(),
1126      new CDPoint(),
1127      new CDPoint(),
1128      new CDPoint()];
1129
1130
1131    //first head (end point)
1132    points[0].x=lengthHead*Math.cos(Math.PI-angleHead);
1133    points[0].y=lengthHead*Math.sin(Math.PI-angleHead);
1134    points[1].x=points[0].x;
1135    points[1].y=-points[0].y;
1136
1137    //second head (start point)
1138    if(numHead==2)
1139    {
1140      points[2].x=lengthHead*Math.cos(angleHead);
1141      points[2].y=lengthHead*Math.sin(angleHead);
1142      points[3].x=points[2].x;
1143      points[3].y=-points[2].y;
1144    }
1145
1146    if(styleHead==0x0010 || styleHead==0x0011)
1147    {
1148      properties.canvasContext.beginPath();
1149      properties.canvasContext.moveTo(xs, ys);
1150      properties.canvasContext.lineTo(xe, ye);
1151      properties.canvasContext.stroke();
1152
1153      if(numHead==2)
1154      {
1155        for(this.i=0;this.i<modeLoop.length;this.i++)
1156        {
1157          properties.canvasContext.save();
1158          properties.canvasContext.translate(xs, ys);
1159          properties.canvasContext.rotate(Math.atan2(ye-ys, xe-xs));
1160
1161          properties.canvasContext.beginPath();
1162          properties.canvasContext.moveTo(points[2].x, points[2].y);
1163          properties.canvasContext.lineTo(0, 0);
1164          properties.canvasContext.lineTo(points[3].x, points[3].y);
1165
1166          if(styleHead==0x0010)
1167          {
1168            properties.canvasContext.stroke();
1169          }
1170          else
1171          {
1172            properties.canvasContext.closePath();
1173            if(modeLoop[this.i]=='fill')
1174            {
1175              properties.canvasContext.fill();
1176            }
1177            else
1178            {
1179              properties.canvasContext.save();
1180              if(mode.fill) properties.canvasContext.shadowColor='rgba(0,0,0,0)';
1181              properties.canvasContext.stroke();
1182              properties.canvasContext.restore();
1183            }
1184          }
1185          properties.canvasContext.restore();
1186        }
1187      }
1188
1189      for(this.i=0;this.i<modeLoop.length;this.i++)
1190      {
1191        properties.canvasContext.save();
1192        properties.canvasContext.translate(xe, ye);
1193        properties.canvasContext.rotate(Math.atan2(ye-ys, xe-xs));
1194
1195        properties.canvasContext.beginPath();
1196        properties.canvasContext.moveTo(points[0].x, points[0].y);
1197        properties.canvasContext.lineTo(0, 0);
1198        properties.canvasContext.lineTo(points[1].x, points[1].y);
1199        if(styleHead==0x0010)
1200        {
1201          properties.canvasContext.stroke();
1202        }
1203        else
1204        {
1205          properties.canvasContext.closePath();
1206          if(modeLoop[this.i]=='fill')
1207          {
1208            properties.canvasContext.fill();
1209          }
1210          else
1211          {
1212            properties.canvasContext.save();
1213            if(mode.fill) properties.canvasContext.shadowColor='rgba(0,0,0,0)';
1214            properties.canvasContext.stroke();
1215            properties.canvasContext.restore();
1216
1217          }
1218        }
1219        properties.canvasContext.restore();
1220      }
1221    }
1222    else
1223    {
1224      if(width==0xFFFF) width=2*lengthHead;
1225
1226      arrowLength=distance(xs,ys,xe,ye);
1227
1228      points[4].x=points[0].x;
1229      points[4].y=width/2;
1230      points[5].x=points[4].x;
1231      points[5].y=-points[4].y;
1232
1233      points[6].x=points[2].x;
1234      points[6].y=points[4].y;
1235      points[7].x=points[6].x;
1236      points[7].y=-points[6].y;
1237
1238      for(this.i=0;this.i<modeLoop.length;this.i++)
1239      {
1240        properties.canvasContext.save();
1241        properties.canvasContext.translate(xs, ys);
1242        properties.canvasContext.rotate(Math.atan2(ye-ys, xe-xs));
1243
1244        properties.canvasContext.beginPath();
1245        properties.canvasContext.moveTo(0, 0);
1246        properties.canvasContext.lineTo(points[2].x, points[2].y);
1247        properties.canvasContext.lineTo(points[6].x, points[6].y);
1248        properties.canvasContext.lineTo(arrowLength+points[4].x, points[4].y);
1249        properties.canvasContext.lineTo(arrowLength+points[0].x, points[0].y);
1250        properties.canvasContext.lineTo(arrowLength,0);
1251        properties.canvasContext.lineTo(arrowLength+points[1].x, points[1].y);
1252        properties.canvasContext.lineTo(arrowLength+points[5].x, points[5].y);
1253        properties.canvasContext.lineTo(points[7].x, points[7].y);
1254        properties.canvasContext.lineTo(points[3].x, points[3].y);
1255
1256        properties.canvasContext.closePath();
1257        if(modeLoop[this.i]=='fill')
1258        {
1259          properties.canvasContext.fill();
1260        }
1261        else
1262        {
1263          properties.canvasContext.stroke();
1264        }
1265        properties.canvasContext.restore();
1266      }
1267    }
1268
1269    return(true);
1270  }
1271
1272
1273
1274  /**
1275   * draw a path from a point list ; each point are joined with a line
1276   *
1277   * @param String mode : can take values
1278   *                      "open"  = the shape is not closed, close it manually
1279   *                      "close" = the shape is automatically closed
1280   * @param Array points : array of float <num1,num2,num3,num4,...,numN-1,numN>
1281   *                        each number have to be taken by couples (each couple
1282   *                        is one point coordinates)
1283   *                          num1,num2
1284   *                          num3,num4
1285   *                          ...
1286   *                          numN-1,numN
1287   *                        first value  : x coordinate
1288   *                        second value : y coordinate
1289   * @param Object mode : 2 properties
1290   *                        fill: true or false (default:true)
1291   *                        stroke: true or false (default:true)
1292   * @return Bool : true if drawed, otherwise false
1293   */
1294  this.shapeSimpleShape = function (pathMode, points, mode)
1295  {
1296    var ptnum=0;
1297
1298    if(properties.canvasContext==null) return (false);
1299
1300    if(mode.fill==null) mode.fill=true;
1301    if(mode.stroke==null) mode.stroke=true;
1302    modeLoop=new Array();
1303    if(mode.fill) modeLoop.push('fill');
1304    if(mode.stroke) modeLoop.push('stroke');
1305
1306
1307    for(this.loop=0;this.loop<modeLoop.length;this.loop++)
1308    {
1309      ptnum=0;
1310      properties.canvasContext.beginPath();
1311
1312      for(this.i=0;this.i<Math.floor(points.length/2);this.i++)
1313      {
1314        if(ptnum==0)
1315        {
1316          properties.canvasContext.moveTo(points[ptnum], points[ptnum+1]);
1317        }
1318        else
1319        {
1320          properties.canvasContext.lineTo(points[ptnum], points[ptnum+1]);
1321        }
1322        ptnum+=2;
1323      }
1324
1325      if(pathMode=="close") properties.canvasContext.closePath();
1326
1327      if(modeLoop[this.loop]=='fill')
1328      {
1329        properties.canvasContext.fill();
1330      }
1331      else
1332      {
1333        properties.canvasContext.save();
1334        if(mode.fill) properties.canvasContext.shadowColor='rgba(0,0,0,0)';
1335        properties.canvasContext.stroke();
1336        properties.canvasContext.restore();
1337      }
1338
1339    }
1340    return(true);
1341  }
1342
1343  /**
1344   * draw a path from a point list ; each point are joined with a line
1345   *
1346   * @param String mode : can take values
1347   *                      "open"  = the shape is not closed, close it manually
1348   *                      "close" = the shape is automatically closed
1349   * points : array of float <num1,num2,num3,...,numN-2,numN-1,numN>
1350   *              num1,num2,num3
1351   *              ...
1352   *              numN-2,numN-1,numN
1353   *                1st value  : method ; 0:move to, 1:line to, 2:quadratic curve to, 3:bezier curve to
1354   *                2nd & 3rd values : x & y coordinate
1355   *                4th & 5th values : x & y coordinate (quadratic curve : control point, bezier curve : 1st control point)
1356   *                6th & 7th values : x & y coordinate (bezier curve : 2nd control point)
1357   * @param Object mode : 2 properties
1358   *                        fill: true or false (default:true)
1359   *                        stroke: true or false (default:true)
1360   * @return Bool : true if drawed, otherwise false
1361   */
1362  this.shapeComplexShape = function(pathMode, points, mode)
1363  {
1364    var ptnum=0;
1365
1366    if(properties.canvasContext==null) return (false);
1367
1368    if(mode.fill==null) mode.fill=true;
1369    if(mode.stroke==null) mode.stroke=true;
1370    modeLoop=new Array();
1371    if(mode.fill) modeLoop.push('fill');
1372    if(mode.stroke) modeLoop.push('stroke');
1373
1374    for(this.loop=0;this.loop<modeLoop.length;this.loop++)
1375    {
1376      ptnum=0;
1377      properties.canvasContext.beginPath();
1378      while(ptnum<points.length)
1379      {
1380        if(points[ptnum]==0) //moveTo
1381        {
1382          properties.canvasContext.moveTo(points[ptnum+1], points[ptnum+2]);
1383          ptnum+=3;
1384        }
1385        else if(points[ptnum]==1) //lineTo
1386        {
1387          properties.canvasContext.lineTo(points[ptnum+1], points[ptnum+2]);
1388          ptnum+=3;
1389        }
1390        else if(points[ptnum]==2)  //quadraticCurveTo
1391        {
1392          properties.canvasContext.quadraticCurveTo(points[ptnum+1], points[ptnum+2], points[ptnum+3],points[ptnum+4]);
1393          ptnum+=5;
1394        }
1395        else if(points[ptnum]==3)  //bezierCurveTo
1396        {
1397          properties.canvasContext.bezierCurveTo(points[ptnum+1], points[ptnum+2],points[ptnum+3],points[ptnum+4],points[ptnum+5],points[ptnum+6]);
1398          ptnum+=7;
1399        }
1400        else break; // if pt!=0|1|2|3 there is a problem, so stop drawing the shape
1401      }
1402
1403      if(pathMode=="close") properties.canvasContext.closePath();
1404
1405      if(modeLoop[this.loop]=='fill')
1406      {
1407        properties.canvasContext.fill();
1408      }
1409      else
1410      {
1411        properties.canvasContext.save();
1412        if(mode.fill) properties.canvasContext.shadowColor='rgba(0,0,0,0)';
1413        properties.canvasContext.stroke();
1414        properties.canvasContext.restore();
1415      }
1416    }
1417    return(true);
1418  }
1419
1420
1421  /**
1422   * define a color for lines
1423   *
1424   * @param String color : a color
1425   *                        '#rrggbb' with rr,gg,bb [0x00..0xFF]
1426   *                        'rgb(r,g,b)' with r,g,b [0..255]
1427   *                        'rgba(r,g,b,a)' with r,g,b [0..255] and a [0..1]
1428   * @return Bool : true if drawed, otherwise false
1429   */
1430  this.styleStrokeColor = function (color)
1431  {
1432    if(properties.canvasContext==null) return (false);
1433
1434    properties.canvasContext.strokeStyle=color;
1435    return(true);
1436  }
1437
1438  /**
1439   * define a gradient for lines
1440   * you can have more information about how this function works on this page :
1441   *    https://developer.mozilla.org/en/Canvas_tutorial%3aApplying_styles_and_colors
1442   *
1443   * @param String mode : kind of gradient 'linear' or 'radial'
1444   * @param CDPoint|CDRpoint start : start coordinate for the gradient
1445   *                                    a CDPoint for 'linear' mode
1446   *                                    a CDRPoint for 'radial' mode
1447   * @param CDPoint|CDRpoint end   : end coordinate for the gradient
1448   *                                    a CDPoint for 'linear' mode
1449   *                                    a CDRPoint for 'radial' mode
1450   * @param Array<CDGradientStep> gradients : an array of CDGradientStep
1451   * @return Bool : true if drawed, otherwise false
1452   */
1453  this.styleStrokeGradient = function (mode, start, end, gradients)
1454  {
1455    if(properties.canvasContext==null) return (false);
1456
1457    gradient=null;
1458    if(mode=='linear')
1459    {
1460      gradient=properties.canvasContext.createLinearGradient(start.x, start.y, end.x, end.y);
1461    }
1462    else if(mode=='radial')
1463    {
1464      gradient=properties.canvasContext.createRadialGradient(start.x, start.y, start.r, end.x, end.y, end.r);
1465    }
1466
1467    if(gradient!=null)
1468    {
1469      for(this.i=0;this.i<gradients.length;this.i++)
1470      {
1471        gradient.addColorStop(gradients[this.i].step, gradients[this.i].color);
1472      }
1473
1474      properties.canvasContext.strokeStyle=gradient;
1475      return(true);
1476    }
1477
1478    return(false);
1479  }
1480
1481  /**
1482   * define a pattern for lines
1483   * you can have more information about how this function works on this page :
1484   *    https://developer.mozilla.org/en/Canvas_tutorial%3aApplying_styles_and_colors
1485   *
1486   * @param String url  : the url of image pattern
1487   * @param String mode : the repeat mode 'repeat' 'repeat-x' 'repeat-y' 'no-repeat'
1488   * @return Bool : true if drawed, otherwise false
1489   */
1490  this.styleStrokePattern = function (url, mode)
1491  {
1492    if(properties.canvasContext==null) return (false);
1493
1494    imageIndex=this.imageLoaded(url);
1495    if(imageIndex.index==-1) return(false);
1496
1497    if(!(mode=='repeat' || mode=='repeat-x' || mode=='repeat-y' || mode=='no-repeat')) mode='repeat';
1498
1499    properties.canvasContext.strokeStyle=properties.canvasContext.createPattern(properties.imagesObj[imageIndex.index], mode);
1500    return(true);
1501  }
1502
1503  /**
1504   * define stroke line properties for drawing
1505   *
1506   * if a properties is not given, current style is kept.
1507   *
1508   * @param Object param : object with properties
1509   *                        width  : width of lines
1510   *                        cap    : 'butt', 'round', 'square'
1511   *                        joints : 'round', 'bevel', 'miter'
1512   * @return Bool : true if drawed, otherwise false
1513   */
1514  this.styleStrokeDraw = function (param)
1515  {
1516    if(properties.canvasContext==null) return (false);
1517
1518    if(param.width!= null) properties.canvasContext.lineWidth=param.width;
1519    if(param.cap!=null && (param.cap=='butt' || param.cap=='round' || param.cap=='square')) properties.canvasContext.lineCap=param.cap;
1520    if(param.joints!=null && (param.joints=='round' || param.joints=='bevel' || param.joints=='miter')) properties.canvasContext.lineJoin=param.joints;
1521
1522    return(true);
1523  }
1524
1525
1526
1527  /**
1528   * define a color for fill
1529   *
1530   * @param String color : a color
1531   *                        '#rrggbb' with rr,gg,bb [0x00..0xFF]
1532   *                        'rgb(r,g,b)' with r,g,b [0..255]
1533   *                        'rgba(r,g,b,a)' with r,g,b [0..255] and a [0..1]
1534   * @return Bool : true if drawed, otherwise false
1535   */
1536  this.styleFillColor = function (color)
1537  {
1538    if(properties.canvasContext==null) return (false);
1539
1540    properties.canvasContext.fillStyle=color;
1541    return(true);
1542  }
1543
1544  /**
1545   * define a gradient for fill
1546   * you can have more information about how this function works on this page :
1547   *    https://developer.mozilla.org/en/Canvas_tutorial%3aApplying_styles_and_colors
1548   *
1549   * @param String mode : kind of gradient 'linear' or 'radial'
1550   * @param CDPoint|CDRpoint start : start coordinate for the gradient
1551   *                                    a CDPoint for 'linear' mode
1552   *                                    a CDRPoint for 'radial' mode
1553   * @param CDPoint|CDRpoint end   : end coordinate for the gradient
1554   *                                    a CDPoint for 'linear' mode
1555   *                                    a CDRPoint for 'radial' mode
1556   * @param Array<CDGradientStep> gradients : an array of CDGradientStep
1557   * @return Bool : true if drawed, otherwise false
1558   */
1559  this.styleFillGradient = function (mode, start, end, gradients)
1560  {
1561    if(properties.canvasContext==null) return (false);
1562
1563    gradient=null;
1564    if(mode=='linear')
1565    {
1566      gradient=properties.canvasContext.createLinearGradient(start.x, start.y, end.x, end.y);
1567    }
1568    else if(mode=='radial')
1569    {
1570      gradient=properties.canvasContext.createRadialGradient(start.x, start.y, start.r, end.x, end.y, end.r);
1571    }
1572
1573    if(gradient!=null)
1574    {
1575      for(this.i=0;this.i<gradients.length;this.i++)
1576      {
1577        gradient.addColorStop(gradients[this.i].step, gradients[this.i].color);
1578      }
1579
1580      properties.canvasContext.fillStyle=gradient;
1581      return(true);
1582    }
1583
1584    return(false);
1585  }
1586
1587  /**
1588   * define a pattern for fill
1589   * you can have more information about how this function works on this page :
1590   *    https://developer.mozilla.org/en/Canvas_tutorial%3aApplying_styles_and_colors
1591   *
1592   * @param String url  : the url of image pattern
1593   * @param String mode : the repeat mode 'repeat' 'repeat-x' 'repeat-y' 'no-repeat'
1594   * @return Bool : true if drawed, otherwise false
1595   */
1596  this.styleFillPattern = function (url, mode)
1597  {
1598    if(properties.canvasContext==null) return (false);
1599
1600    imageIndex=this.imageLoaded(url);
1601    if(imageIndex.index==-1) return(false);
1602
1603    if(!(mode=='repeat' || mode=='repeat-x' || mode=='repeat-y' || mode=='no-repeat')) mode='repeat';
1604
1605    properties.canvasContext.fillStyle=properties.canvasContext.createPattern(properties.imagesObj[imageIndex.index], mode);
1606    return(true);
1607  }
1608
1609
1610  /**
1611   * define the global opacity
1612   *
1613   * @param Float opacity : 0:transparent, 1:opaque
1614   * @return Bool : true if drawed, otherwise false
1615   */
1616  this.styleGlobalAlpha = function (opacity)
1617  {
1618    if(properties.canvasContext==null) return (false);
1619
1620    if(opacity<0)
1621    {
1622      opacity=0;
1623    }
1624    else if(opacity > 1)
1625    {
1626      opacity=1;
1627    }
1628
1629    properties.canvasContext.globalAlpha=opacity;
1630    return(true);
1631  }
1632
1633
1634  /**
1635   * define a shadow
1636   *
1637   * @return Bool : true if drawed, otherwise false
1638   */
1639  this.styleShadow = function (offsetX, offsetY, blur, color)
1640  {
1641    if(properties.canvasContext==null) return (false);
1642    if(properties.canvasContext.shadowOffsetX==null) return(false);
1643
1644    properties.canvasContext.shadowOffsetX=offsetX;
1645    properties.canvasContext.shadowOffsetY=offsetY;
1646    properties.canvasContext.shadowBlur=blur;
1647    properties.canvasContext.shadowColor=color;
1648
1649    return(true);
1650  }
1651
1652  /**
1653   * reset the shadow (remove it)
1654   *
1655   * @return Bool : true if drawed, otherwise false
1656   */
1657  this.styleShadowReset = function ()
1658  {
1659    return(this.styleShadow(0,0,0,'rgba(0,0,0,0)'));
1660  }
1661
1662
1663  /**
1664   * print a text
1665   *
1666   * @param String text : text to print
1667   * @param Integer x : x coordinate
1668   * @param Integer y : y coordinate
1669   * @param String mode : 'fill' 'stroke' 'both'
1670   * @return Bool : true if drawed, otherwise false
1671   */
1672  this.textPrint = function (text, x, y, mode)
1673  {
1674    if(properties.canvasContext==null) return (false);
1675
1676    /* a bad trick for a strange bug...
1677     *
1678     * when using the strokeText() function, it seems that the last drawn path
1679     * is drawn again...
1680     *
1681     * so, making a dummy path to avoid this problem
1682     *
1683     * >>
1684     */
1685    properties.canvasContext.beginPath();
1686    properties.canvasContext.moveTo(x,y);
1687    properties.canvasContext.fill();
1688    /*
1689     * <<
1690     */
1691
1692    if(mode=='fill' || mode=='both') properties.canvasContext.fillText(text,x,y);
1693    if(mode=='stroke' || mode=='both') properties.canvasContext.strokeText(text,x,y);
1694
1695    return(true);
1696  }
1697
1698  /**
1699   * print a text
1700   *
1701   * @param Object param : object with properties
1702   *                        font : a string like '20px sans' (css format)
1703   *                        alignH : 'left', 'right', 'center', 'start', 'end'
1704   *                        alignV : 'top', 'bottom', 'middle', 'alphabetic'
1705   * @return Bool : true if drawed, otherwise false
1706   */
1707  this.textStyle = function (param)
1708  {
1709    if(properties.canvasContext==null) return (false);
1710
1711    if(param.font!=null) properties.canvasContext.font=param.font;
1712    if(param.alignH=='left' ||
1713       param.alignH=='right' ||
1714       param.alignH=='center' ||
1715       param.alignH=='start' ||
1716       param.alignH=='end') properties.canvasContext.textAlign=param.alignH;
1717    if(param.alignV=='top' ||
1718       param.alignV=='bottom' ||
1719       param.alignV=='middle' ||
1720       param.alignV=='alphabetic') properties.canvasContext.textBaseline=param.alignV;
1721
1722    return(true);
1723  }
1724
1725  /**
1726   * mesure the width for a given text
1727   *
1728   * @param String text : text to print
1729   * @return Integer :
1730   */
1731  this.textWidth = function (text)
1732  {
1733    if(properties.canvasContext==null) return (-1);
1734
1735    return(properties.canvasContext.measureText(text));
1736  }
1737
1738
1739
1740
1741
1742  /**
1743   * calculate the distance between 2 points
1744   */
1745  var distance = function(x1, y1, x2, y2)
1746  {
1747    return(Math.sqrt( Math.pow(x1-x2,2) + Math.pow(y1-y2,2)));
1748  }
1749
1750
1751  this.constructor(canvasContext);
1752
1753} //CDDrawing class
1754
1755/*
1756 * transformMatrix()
1757 * shapeDot(x,y)
1758 *
1759 */
Note: See TracBrowser for help on using the repository browser.