source: extensions/GrumPluginClasses/js/canvasDraw.ui.drawingGraph.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: 78.3 KB
Line 
1/**
2 * -----------------------------------------------------------------------------
3 * file: CanvasDraw.ui.drawingGraph.js
4 * file version: 1.0.0
5 * date: 2011-10-17
6 *
7 * A jQuery plugin provided by the piwigo's plugin "GrumPluginClasses"
8 *
9 * -----------------------------------------------------------------------------
10 * Author     : Grum
11 *   email    : grum@piwigo.com
12 *   website  : http://photos.grum.fr
13 *   PWG user : http://forum.phpwebgallery.net/profile.php?id=3706
14 *
15 *   << May the Little SpaceFrog be with you ! >>
16 * -----------------------------------------------------------------------------
17 *
18 * The drawing graph provide all methods and properties to draw charts
19 *
20 * It use:
21 *  - 1 layer for graphs
22 *  - 1 layer for the grid & axis
23 *  - 1 layer for the cursor
24 *
25 * :: HISTORY ::
26 *
27 * | release | date       |
28 * | 1.0.0   | 2011-10-17 | first release
29 * |         |            |
30 * |         |            |
31 * |         |            |
32 * |         |            |
33 * |         |            |
34 * |         |            |
35 *
36 */
37
38
39
40(
41  function($)
42  {
43    /*
44     * plugin 'public' functions
45     */
46    var publicMethods =
47    {
48      /**
49       * initialize the object
50       *
51       * @param Object opt : options
52       */
53      init : function (opt)
54        {
55          return this.each(function()
56            {
57              // default values for the plugin
58              var $this=$(this),
59                  data = $this.data('options'),
60                  objects = $this.data('objects'),
61                  properties = $this.data('properties'),
62                  canvasObjects = $this.data('canvasObjects'),
63                  options =
64                    {
65                      margins:new CDMargins(),
66                      legend:new CDLegend(),
67                      axis:{
68                          front:new CDAxis(),
69                          back:null
70                        },
71                      cursor:
72                        {
73                          visible:true,
74                          color:'rgba(128,128,128,0.2)',
75                          verticalType:'bar'  // 'bar' or 'line'
76                        },
77                      display:
78                        {
79                          width:320,
80                          height:200,
81                          legend:false,
82                        },
83                      events:
84                        {
85                          mousePositionChange:null,
86                          mouseEnter:null,
87                          mouseLeave:null,
88                          mouseClick:null
89                        },
90                    };
91
92              // if options given, merge it
93              // if(opt) $.extend(options, opt); ==> options are set by setters
94
95              $this.data('options', options);
96
97              if(!properties)
98              {
99                $this.data('properties',
100                  {
101                    initialized:false,
102                    mouseIsOver:false,
103                    cursor:{
104                        x:0,
105                        y:0,
106                        axis:{
107                          XY:{
108                            front:{H:-1, V:-1},
109                            back:{H:-1, V:-1}
110                          }
111                        },
112                      },
113                    typeGraph:'xy',  // 'xy', 'pie'
114                  }
115                );
116                properties=$this.data('properties');
117              }
118
119              if(!objects)
120              {
121                objects =
122                  {
123                    viewport:$('<div/>', { 'class':'ui-drawingGraph-viewport' } ),
124                    sheet:$('<div/>', { 'class':'ui-drawingGraph-sheet' } )
125                      .bind('mousemove',
126                            function (event)
127                              {
128                                privateMethods.mousePositionUpdate($this, event.originalEvent.layerX, event.originalEvent.layerY);
129                              }
130                          )
131                      .bind('mouseleave',
132                            function (event)
133                              {
134                                privateMethods.mouseLeave($this);
135                              }
136                          )
137                      .bind('mouseenter',
138                            function (event)
139                              {
140                                privateMethods.mouseEnter($this, event.originalEvent.layerX, event.originalEvent.layerY);
141                              }
142                          )
143                      .bind('click',
144                            function (event)
145                              {
146                                privateMethods.mouseClick($this, event.originalEvent.layerX, event.originalEvent.layerY);
147                              }
148                          ),
149                    canvasCursor:$('<canvas/>',  { 'class':'ui-drawingGraph-cursor' } ),
150                    canvasAxis:$('<canvas/>', { 'class':'ui-drawingGraph-axis' } ),
151                    canvasGraph:$('<canvas/>', { 'class':'ui-drawingGraph-graph' } )
152                  };
153
154                canvasObjects = {
155                    cursor:new CDDrawing(objects.canvasCursor.get(0)),
156                    axis:new CDDrawing(objects.canvasAxis.get(0)),
157                    graph:new CDDrawing(objects.canvasGraph.get(0)),
158                  };
159
160                $this
161                  .html('')
162                  .addClass('ui-drawingGraph')
163                  .bind('click.drawingGraph',
164                      function ()
165                      {
166                        //
167                      }
168                    )
169                  .bind('mouseenter.drawingGraph',
170                      function ()
171                      {
172                        properties.mouseIsOver=true;
173                      }
174                    )
175                  .bind('mouseleave.drawingGraph',
176                      function ()
177                      {
178                        properties.mouseIsOver=false;
179                      }
180                    )
181                  .append(objects.viewport.append(objects.sheet.append(objects.canvasAxis).append(objects.canvasCursor).append(objects.canvasGraph)));
182
183                $this.data('objects', objects);
184                $this.data('canvasObjects', canvasObjects);
185              }
186
187              privateMethods.setOptions($this, opt);
188            }
189          );
190        }, // init
191
192      /**
193       * object destroy methods to clean memory
194       */
195      destroy : function ()
196        {
197          return this.each(
198            function()
199            {
200              // default values for the plugin
201              var $this=$(this);
202              $this
203                .unbind('.drawingGraph')
204                .css(
205                  {
206                    width:'',
207                    height:''
208                  }
209                );
210            }
211          );
212        }, // destroy
213
214      /**
215       * initialize the options
216       *
217       * @param Object value : options properties as an object
218       */
219      options: function (value)
220        {
221          return this.each(function()
222            {
223              privateMethods.setOptions($(this), value);
224            }
225          );
226        }, // options
227
228      /**
229       * define the size (witdh & height) of the current drawing area
230       *
231       * @param Object value : an object with width&height properties
232       * @return Object : if no parameter are given, returns an object with the
233       *                  width & height properties
234       */
235      display : function (value)
236        {
237          if(value!=null)
238          {
239            // set selected value
240            return this.each(function()
241              {
242                privateMethods.setDisplay($(this), value);
243              }
244            );
245          }
246          else
247          {
248            // return the selected value
249            var options=this.data('options');
250
251            if(options)
252            {
253              return(options.display);
254            }
255            else
256            {
257              return(null);
258            }
259          }
260        },
261
262      /**
263       * define the cursor state
264       *
265       * @param Object value : an object with the cursor properties (visible,
266       *                       color)
267       * @return Object : if no parameter are given, returns an object with the
268       *                  cursor properties
269       */
270      cursor : function (value)
271        {
272          if(value!=null)
273          {
274            // set selected value
275            return this.each(function()
276              {
277                privateMethods.setCursor($(this), value);
278              }
279            );
280          }
281          else
282          {
283            // return the selected value
284            var options=this.data('options');
285
286            if(options)
287            {
288              return(options.cursor);
289            }
290            else
291            {
292              return(null);
293            }
294          }
295        },
296
297      /**
298       * define the margins
299       *
300       * @param Object value : a CDMargins object or an object with left, top, right, bottom properties
301       * @return Object : if no parameter are given, returns a CDMargins object
302       */
303      margins : function (value)
304        {
305          if(value!=null && value instanceof CDMargins)
306          {
307            // set selected value
308            return this.each(function()
309              {
310                privateMethods.setMargins($(this), value);
311              }
312            );
313          }
314          else
315          {
316            // return the selected value
317            var options=this.data('options');
318
319            if(options)
320            {
321              return(options.margins);
322            }
323            else
324            {
325              return(null);
326            }
327          }
328        },
329
330      /**
331       * define the legend
332       *
333       * @param Object value : a CDLegend object or an object with left, top, right, bottom properties
334       * @return Object : if no parameter are given, returns a CDLegend object
335       */
336      legend : function (value)
337        {
338          if(value!=null && value instanceof CDLegend)
339          {
340            // set selected value
341            return this.each(function()
342              {
343                privateMethods.setLegend($(this), value);
344              }
345            );
346          }
347          else
348          {
349            // return the selected value
350            var options=this.data('options');
351
352            if(options)
353            {
354              return(options.legend);
355            }
356            else
357            {
358              return(null);
359            }
360          }
361        },
362
363      /**
364       * define the front axis
365       *
366       * @param Object value : a CDAxis object
367       * @return Object : if no parameter are given, returns a CDAxis object
368       */
369      axisFront : function (value)
370        {
371          if(value!=null && value instanceof CDAxis)
372          {
373            // set selected value
374            return this.each(function()
375              {
376                privateMethods.setAxis($(this), value, true);
377              }
378            );
379          }
380          else
381          {
382            // return the selected value
383            var options=this.data('options');
384
385            if(options)
386            {
387              return(options.axis.front);
388            }
389            else
390            {
391              return(null);
392            }
393          }
394        },
395
396      /**
397       * define the back axis
398       *
399       * @param Object value : a CDAxis object
400       * @return Object : if no parameter are given, returns a CDAxis object
401       */
402      axisBack : function (value)
403        {
404          if(value!=null && value instanceof CDAxis)
405          {
406            // set selected value
407            return this.each(function()
408              {
409                privateMethods.setAxis($(this), value, false);
410              }
411            );
412          }
413          else
414          {
415            // return the selected value
416            var options=this.data('options');
417
418            if(options)
419            {
420              return(options.axis.back);
421            }
422            else
423            {
424              return(null);
425            }
426          }
427        },
428
429      /**
430       * return the canvas objects
431       *
432       * @return Object : an object with axis, graph and cursor canvas
433       */
434      canvasObjects : function ()
435        {
436          var canvasObjects=this.data('canvasObjects');
437
438          if(canvasObjects)
439          {
440            return(canvasObjects);
441          }
442          else
443          {
444            return(
445              {
446                cursor:null,
447                axis:null,
448                graph:null
449              }
450            );
451          }
452        },
453
454      /**
455       * define the function to be triggered when the mouse moves on the drawing
456       * area
457       *
458       * @param Function value : a function to be triggered
459       * @return Function : if no paramater is given, return the function
460       */
461      mousePositionChange: function (value)
462        {
463          if(value!=null && $.isFunction(value))
464          {
465            // set selected value
466            return this.each(function()
467              {
468                privateMethods.setEventMousePositionChange($(this), value);
469              }
470            );
471          }
472          else
473          {
474            // return the selected value
475            var options=this.data('options');
476
477            if(options)
478            {
479              return(options.events.mousePositionChange);
480            }
481            else
482            {
483              return(null);
484            }
485          }
486        }, // mousePositionChange
487
488      /**
489       * define the function to be triggered when the mouse enter on the drawing
490       * area
491       *
492       * @param Function value : a function to be triggered
493       * @return Function : if no paramater is given, return the function
494       */
495      mouseEnter: function (value)
496        {
497          if(value!=null && $.isFunction(value))
498          {
499            // set selected value
500            return this.each(function()
501              {
502                privateMethods.setEventMouseEnter($(this), value);
503              }
504            );
505          }
506          else
507          {
508            // return the selected value
509            var options=this.data('options');
510
511            if(options)
512            {
513              return(options.events.mouseEnter);
514            }
515            else
516            {
517              return(null);
518            }
519          }
520        }, // mouseEnter
521
522      /**
523       * define the function to be triggered when the mouse leaves the drawing
524       * area
525       *
526       * @param Function value : a function to be triggered
527       * @return Function : if no paramater is given, return the function
528       */
529      mouseLeave: function (value)
530        {
531          if(value!=null && $.isFunction(value))
532          {
533            // set selected value
534            return this.each(function()
535              {
536                privateMethods.setEventMouseLeave($(this), value);
537              }
538            );
539          }
540          else
541          {
542            // return the selected value
543            var options=this.data('options');
544
545            if(options)
546            {
547              return(options.events.mouseLeave);
548            }
549            else
550            {
551              return(null);
552            }
553          }
554        }, // mouseLeave
555
556      /**
557       * define the function to be triggered when the mouse is clicked on the
558       * drawing area
559       *
560       * @param Function value : a function to be triggered
561       * @return Function : if no paramater is given, return the function
562       */
563      mouseClick: function (value)
564        {
565          if(value!=null && $.isFunction(value))
566          {
567            // set selected value
568            return this.each(function()
569              {
570                privateMethods.setEventMouseClick($(this), value);
571              }
572            );
573          }
574          else
575          {
576            // return the selected value
577            var options=this.data('options');
578
579            if(options)
580            {
581              return(options.events.mouseClick);
582            }
583            else
584            {
585              return(null);
586            }
587          }
588        }, // mouseClick
589
590      /**
591       * force the drawing area to refresh display
592       */
593      refresh: function ()
594        {
595          return this.each(function()
596            {
597              privateMethods.draw($(this));
598            }
599          );
600        }
601    }, // methods
602
603
604    /*
605     * plugin 'private' methods
606     */
607    privateMethods =
608    {
609      /**
610       * initialise the object with given options
611       *
612       * @param object value: options to be set
613       */
614      setOptions : function (object, value)
615        {
616          var properties=object.data('properties'),
617              options=object.data('options');
618
619          if(!$.isPlainObject(value)) return(false);
620
621          properties.initialized=false;
622
623          if(value.axis==null) value.axis={};
624          if(value.events==null) value.events={};
625
626          privateMethods.setMargins(object, (value.margins!=null)?value.margins:options.margins);
627          privateMethods.setLegend(object, (value.legend!=null)?value.legend:options.legend);
628          privateMethods.setCursor(object, (value.cursor!=null)?value.cursor:options.cursor);
629          privateMethods.setAxis(object, (value.axis.front!=null)?value.axis.front:options.axis.front, true);
630          privateMethods.setAxis(object, (value.axis.back!=null)?value.axis.back:options.axis.back, false);
631          privateMethods.setDisplay(object, (value.display!=null)?value.display:options.display);
632
633          privateMethods.setEventMousePositionChange(object, (value.events.mousePositionChange!=null)?value.events.mousePositionChange:options.events.mousePositionChange);
634          privateMethods.setEventMouseLeave(object, (value.events.mouseLeave!=null)?value.events.mouseLeave:options.events.mouseLeave);
635          privateMethods.setEventMouseEnter(object, (value.events.mouseEnter!=null)?value.events.mouseEnter:options.events.mouseEnter);
636          privateMethods.setEventMouseClick(object, (value.events.mouseClick!=null)?value.events.mouseClick:options.events.mouseClick);
637
638          properties.initialized=true;
639
640          privateMethods.draw(object);
641        },
642
643
644      /**
645       * setDisplay allows to resize the sheetSizeport
646       *
647       * @param object value: an object with width&height properties
648       * @return object: display options properties
649       */
650      setDisplay : function (object, value)
651        {
652          var properties=object.data('properties'),
653              objects=object.data('objects'),
654              options=object.data('options'),
655              canvasObjects=object.data('canvasObjects'),
656              triggerSize=false,
657              axisBox={
658                width:0,
659                height:0
660              };
661
662
663
664          if(value.width==null) value.width=options.display.width;
665          if(value.height==null) value.height=options.display.height;
666
667          if(value.width>0 &&
668             value.height>0 &&
669             (value.width!=options.display.width ||
670              value.height!=options.display.height ||
671              !properties.initialized)
672            )
673          {
674            delete canvasObjects.cursor;
675            delete canvasObjects.axis;
676            delete canvasObjects.graph;
677
678            options.display.width=value.width;
679            options.display.height=value.height;
680
681            objects.sheet.css(
682              {
683                width:options.display.width+'px',
684                height:options.display.height+'px'
685              }
686            );
687
688            objects.viewport.attr("height", options.display.height).attr("width", options.display.width);
689            objects.canvasCursor.attr("height", options.display.height).attr("width", options.display.width);
690            objects.canvasAxis.attr("height", options.display.height).attr("width", options.display.width);
691            objects.canvasGraph.attr("height", options.display.height).attr("width", options.display.width);
692            object.attr("height", options.display.height).attr("width", options.display.width);
693            object.css(
694              {
695                width:options.display.width+'px',
696                height:options.display.height+'px'
697              }
698            );//attr("height", options.display.height).attr("width", options.display.width);
699
700            canvasObjects.cursor=new CDDrawing(objects.canvasCursor.get(0));
701            canvasObjects.axis=new CDDrawing(objects.canvasAxis.get(0));
702            canvasObjects.graph=new CDDrawing(objects.canvasGraph.get(0));
703
704            axisBox=privateMethods.axisBox(object);
705
706            if(options.axis.front!=null)
707              options.axis.front.set(
708                {
709                  size:{
710                      width:axisBox.width, //options.display.width-options.margins.get().left-options.margins.get().right,
711                      height:axisBox.height //options.display.height-options.margins.get().top-options.margins.get().bottom
712                    }
713                }
714              );
715
716            if(options.axis.back!=null)
717              options.axis.back.set(
718                {
719                  size:{
720                      width:axisBox.width, //options.display.width-options.margins.get().left-options.margins.get().right,
721                      height:axisBox.height //options.display.height-options.margins.get().top-options.margins.get().bottom
722                    }
723                }
724              );
725
726            if(properties.initialized)
727            {
728              /*
729               * redraw graph
730               */
731            }
732          }
733
734          return(options.display);
735        }, // setDisplay
736
737
738      /**
739       * define the cursor properties
740       *
741       * @param object value: the cursor properties (color, visible, verticalType)
742       * @return object: cursor options values
743       */
744      setCursor : function (object, value)
745        {
746          var properties=object.data('properties'),
747              objects=object.data('objects'),
748              options=object.data('options'),
749              redraw=false;
750
751          if(value.color==null) value.color=options.cursor.color;
752          if(value.visible==null) value.visible=options.cursor.visible;
753          if(value.verticalType==null) value.verticalType=options.cursor.verticalType;
754
755          if((value.visible===true || value.visible===false) &&
756             (value.verticalType=='bar' || value.verticalType=='line') &&
757             (value.visible!=options.cursor.visible ||
758              value.color!=options.cursor.color ||
759              value.verticalType!=options.cursor.verticalType ||
760              !properties.initialized)
761            )
762          {
763            if(options.cursor.color!=value.color ||
764               options.cursor.verticalType!=value.verticalType ||
765               options.cursor.visible!=value.visible) redraw=true;
766
767            options.cursor.visible=value.visible;
768            options.cursor.color=value.color;
769            options.cursor.verticalType=value.verticalType;
770
771            objects.canvasCursor.css('display', options.cursor.visible?'block':'none');
772
773            if(options.cursor.visible && redraw) privateMethods.drawCursor(object);
774          }
775          return(options.cursor);
776        }, // setCursor
777
778      /**
779       * define the margins
780       *
781       * @param CDMargins value: a CDMargins object
782       * @return CDMargins: the CDMargins applied
783       */
784      setMargins : function (object, value)
785        {
786          var properties=object.data('properties'),
787              objects=object.data('objects'),
788              options=object.data('options');
789
790          if(value instanceof CDMargins &&
791             (!options.margins.equals(value) ||
792              !properties.initialized)
793            )
794          {
795            options.margins.set(value);
796            privateMethods.draw(object);
797          }
798          return(options.margins);
799        }, // setMargins
800
801      /**
802       * define the legend
803       *
804       * @param CDLegend value: a CDLegend object
805       * @return CDLegend: current CDLegend applied
806       */
807      setLegend : function (object, value)
808        {
809          var properties=object.data('properties'),
810              objects=object.data('objects'),
811              options=object.data('options');
812
813          if(value instanceof CDLegend &&
814             (!options.legend.equals(value) ||
815              !properties.initialized)
816            )
817          {
818            options.legend.set(value);
819            privateMethods.draw(object);
820          }
821          return(options.legend);
822        }, // setLegend
823
824      /**
825       * define the axis
826       *
827       * @param CDAxis value: a CDAxis object
828       * @param boolean front: true if function is called to define the front axis,
829       *                       false if function is called to define the baxk axis
830       * @return CDAxis: the CDAxis object applied
831       */
832      setAxis : function (object, value, front)
833        {
834          var properties=object.data('properties'),
835              objects=object.data('objects'),
836              options=object.data('options');
837
838          if(value instanceof CDAxis)
839          {
840            if(front)
841            {
842              delete options.axis.front;
843              options.axis.front=value;
844            }
845            else
846            {
847              delete options.axis.back;
848              options.axis.back=value;
849            }
850
851            privateMethods.draw(object);
852          }
853          return(front?options.axis.front:options.axis.back);
854        }, // setAxis
855
856
857      /**
858       * this function is used to set a callback when mouse position changed over
859       * the viewport
860       */
861      setEventMousePositionChange : function (object, value)
862        {
863          var properties=object.data('properties'),
864              options=object.data('options');
865
866          options.events.mousePositionChange=value;
867          object.unbind('drawingGraphMousePositionChange');
868          if(value) object.bind('drawingGraphMousePositionChange', options.events.mousePositionChange);
869          return(options.events.mousePositionChange);
870        }, //setEventMousePositionChange
871
872      /**
873       * this function is used to set a callback when mouse leave the viewport
874       */
875      setEventMouseLeave : function (object, value)
876        {
877          var properties=object.data('properties'),
878              options=object.data('options');
879
880          options.events.mouseLeave=value;
881          object.unbind('drawingGraphMouseLeave');
882          if(value) object.bind('drawingGraphMouseLeave', options.events.mouseLeave);
883          return(options.events.mouseLeave);
884        }, //setEventMouseLeave
885
886
887      /**
888       * this function is used to set a callback when mouse enter the viewport
889       */
890      setEventMouseEnter : function (object, value)
891        {
892          var properties=object.data('properties'),
893              options=object.data('options');
894
895          options.events.mouseEnter=value;
896          object.unbind('drawingGraphMouseEnter');
897          if(value) object.bind('drawingGraphMouseEnter', options.events.mouseEnter);
898          return(options.events.mouseEnter);
899        }, //setEventMouseEnter
900
901
902      /**
903       * this function is used to set a callback when mouse is clicked on the
904       * viewport
905       */
906      setEventMouseClick : function (object, value)
907        {
908          var properties=object.data('properties'),
909              options=object.data('options');
910
911          options.events.mouseClick=value;
912          object.unbind('drawingGraphMouseClick');
913          if(value) object.bind('drawingGraphMouseClick', options.events.mouseClick);
914          return(options.events.mouseClick);
915        }, // setEventMouseClick
916
917
918      /**
919       * this function is called when the mouse moves on the drawing area
920       *  - calculate the axis position
921       *  - draw cursor
922       *  - trigger function event if any
923       *
924       * Note: works only if the axis mode is 'XY'.
925       *
926       * @param integer valueX: x position on the canvas
927       * @param integer valueY: y position on the canvas
928       */
929      mousePositionUpdate : function (object, valueX, valueY)
930        {
931          var properties=object.data('properties'),
932              options=object.data('options'),
933              work={
934                margins:options.margins.get(),
935                legend:options.legend.get(),
936                axis:{
937                  front:(options.axis.front!=null)?options.axis.front.get():null,
938                  back:(options.axis.back!=null)?options.axis.back.get():null
939                },
940                values:[],
941                axisValues:{},
942                axisPos:{
943                  x:0,
944                  y:0
945                },
946                updated:false
947              },
948              /**
949               * returns for each series, the value associated with the cursor's position
950               *
951               * @param Array series: series
952               * @param integer position: horinzontal cursor position
953               * @return Array: array of series values
954               */
955              calculateSeriesValues = function (series, position)
956                {
957                  var tmpSerie=null,
958                      returned=[];
959
960                  for(var i=0;i<series.length;i++)
961                  {
962                    tmpSerie=series[i].get();
963
964                    if(position>=0 && position<tmpSerie.values.length)
965                      returned.push(
966                        {
967                          name:tmpSerie.name,
968                          value:tmpSerie.values[position]
969                        }
970                      );
971                  }
972                  return(returned);
973                };
974
975          properties.cursor.x=valueX;
976          properties.cursor.y=valueY;
977
978
979          if(work.axis.back!=null && work.axis.back.properties.mode=='XY')
980          {
981            // get relative position to the axis
982            work.axisPos=privateMethods.axisXYRelativePosition(object, properties.cursor.x+((options.cursor.verticalType=='bar' || work.axis.back.properties.XY.ticks.H.offset0)?0:work.axis.back.data.XY.H.space/2), properties.cursor.y);
983
984            work.axisValues=options.axis.back.getXYAxisValues(work.axisPos.x, work.axisPos.y);
985            if(work.axisValues.H!=properties.cursor.axis.XY.back.H || work.axisValues.V!=properties.cursor.axis.XY.back.V)
986            {
987              if(work.axisValues.H!=properties.cursor.axis.XY.back.H) work.updated=true;
988              properties.cursor.axis.XY.back.H=work.axisValues.H;
989              properties.cursor.axis.XY.back.V=work.axisValues.V;
990            }
991            work.values=work.values.concat(calculateSeriesValues(options.axis.back.get().properties.series, work.axisValues.H));
992          }
993
994          if(work.axis.front!=null && work.axis.front.properties.mode=='XY')
995          {
996            // get relative position to the axis
997            work.axisPos=privateMethods.axisXYRelativePosition(object, properties.cursor.x+((options.cursor.verticalType=='bar' || work.axis.front.properties.XY.ticks.H.offset0)?0:work.axis.front.data.XY.H.space/2), properties.cursor.y);
998
999            work.axisValues=options.axis.front.getXYAxisValues(work.axisPos.x, work.axisPos.y);
1000            if(work.axisValues.H!=properties.cursor.axis.XY.front.H || work.axisValues.V!=properties.cursor.axis.XY.front.V)
1001            {
1002              if(work.axisValues.H!=properties.cursor.axis.XY.front.H) work.updated=true;
1003              properties.cursor.axis.XY.front.H=work.axisValues.H;
1004              properties.cursor.axis.XY.front.V=work.axisValues.V;
1005            }
1006            work.values=work.values.concat(calculateSeriesValues(options.axis.front.get().properties.series, work.axisValues.H));
1007          }
1008
1009          if(options.cursor.visible)
1010            privateMethods.drawCursor(object);
1011
1012          if(options.events.mousePositionChange && work.updated && work.values.length>0)
1013            object.trigger('drawingGraphMousePositionChange',
1014              {
1015                position:{
1016                  x:properties.cursor.x,
1017                  y:properties.cursor.y
1018                },
1019                values:work.values
1020              }
1021            );
1022        }, // mousePositionUpdate
1023
1024
1025      /**
1026       * this function is called when the mouse moves on the drawing area
1027       *  - hide cursor
1028       *  - trigger function event if any
1029       */
1030      mouseLeave : function (object)
1031        {
1032          var objects=object.data('objects'),
1033              options=object.data('options'),
1034              properties=object.data('properties');
1035
1036          objects.canvasCursor.css('display', 'none');
1037
1038          properties.cursor.axis.XY.front.H=-1;
1039          properties.cursor.axis.XY.front.V=-1;
1040          properties.cursor.axis.XY.back.H=-1;
1041          properties.cursor.axis.XY.back.V=-1;
1042
1043          if(options.events.mouseLeave)
1044            object.trigger('drawingGraphMouseLeave');
1045        },
1046
1047      /**
1048       * this function is called when the mouse moves on the drawing area
1049       *  - show cursor
1050       *  - trigger function event if any
1051       */
1052      mouseEnter : function (object)
1053        {
1054          var objects=object.data('objects'),
1055              options=object.data('options');
1056
1057          objects.canvasCursor.css('display', options.cursor.visible?'block':'none');
1058
1059          if(options.events.mouseEnter)
1060            object.trigger('drawingGraphMouseEnter');
1061        },
1062
1063
1064      /**
1065       * this function is called when the mouse click on the drawing area
1066       */
1067      mouseClick : function (object)
1068        {
1069          var options=object.data('options');
1070
1071          if(options.events.mouseClick)
1072            object.trigger('drawingGraphMouseClick');
1073        },
1074
1075      /**
1076       * return position relative to the axis
1077       *
1078       * @param integer x: x position
1079       * @param integer y: y position
1080       * @return object: a {x,y} object; coordinates relative to the axis
1081       */
1082      axisXYRelativePosition : function (object, x, y)
1083        {
1084          var properties=object.data('properties'),
1085              options=object.data('options'),
1086              work={
1087                margins:options.margins.get(),
1088                legend:options.legend.get(),
1089                returned:{
1090                  x:0,
1091                  y:0
1092                }
1093              };
1094          work.returned.y=options.display.height-y-work.margins.bottom;
1095          work.returned.x=x-work.margins.left;
1096          if(work.legend.visible && work.legend.position=='left') work.returned.x-=options.legend.getRealWidth()+work.margins.right;
1097          return(work.returned);
1098        }, //axisXYRelativePosition
1099
1100      /**
1101       * calculate the axis box
1102       *
1103       * @return object: axis dimensions
1104       */
1105      axisBox : function (object)
1106        {
1107          var properties=object.data('properties'),
1108              objects=object.data('objects'),
1109              options=object.data('options'),
1110              work={
1111                margins:options.margins.get(),
1112                legend:options.legend.get(),
1113                returned:{
1114                  width:0,
1115                  height:0
1116                }
1117              };
1118
1119          work.returned.height=options.display.height-options.margins.get().top-options.margins.get().bottom;
1120          work.returned.width=options.display.width-options.margins.get().left-options.margins.get().right;
1121          if(work.legend.visible) work.returned.width-=options.legend.getRealWidth()+options.margins.get().right;
1122
1123          return(work.returned);
1124        },
1125
1126      /**
1127       * this function draws the cursor
1128       */
1129      drawCursor : function (object)
1130        {
1131          var properties=object.data('properties'),
1132              objects=object.data('objects'),
1133              options=object.data('options'),
1134              canvasObjects=object.data('canvasObjects'),
1135              work={
1136                  margins:options.margins.get(),
1137                  axis:{
1138                    front:(options.axis.front!=null)?options.axis.front.get():null,
1139                    back:(options.axis.back!=null)?options.axis.back.get():null
1140                  },
1141                  width:options.display.width,
1142                  height:options.display.height,
1143                  nearest:0,
1144                  step:0,
1145                  axisValues:
1146                    {
1147                      front:{H:0, V:0},
1148                      back:{H:0, V:0}
1149                    }
1150                };
1151          // draw the cursor only if at least, one of the axis mode equals XY
1152          if(!(work.axis.front!=null && work.axis.front.properties.mode=='XY' ||
1153               work.axis.back!=null && work.axis.back.properties.mode=='XY')) return(false);
1154
1155          // prepare canvas area
1156          canvasObjects.cursor.drawingManageCrisp(true);
1157
1158          canvasObjects.cursor.shapeClearRect(0,0,work.width, work.height);
1159          canvasObjects.cursor.styleStrokeColor(options.cursor.color);
1160          canvasObjects.cursor.styleFillColor(options.cursor.color);
1161          canvasObjects.cursor.styleStrokeDraw({width:1, cap:'butt', joints:'miter'});
1162
1163          //save canvas state
1164          canvasObjects.cursor.drawingStatePush();
1165
1166          // get relative position to the axis
1167          work.axisPos=privateMethods.axisXYRelativePosition(object, 0, 0);
1168
1169          // flip canvas vertically & translate (zero in vertical position is localized at the bottom)
1170          canvasObjects.cursor.transformScale({y:-1});
1171          canvasObjects.cursor.transformTranslate(
1172            {
1173              x:-work.axisPos.x,
1174              y:-work.axisPos.y
1175            }
1176          );
1177
1178
1179          // front axis managment
1180          if(work.axis.front!=null &&
1181             work.axis.front.properties.mode=='XY' &&
1182             (work.axis.front.properties.display.visible.XY.cursorH ||
1183              work.axis.front.properties.display.visible.XY.cursorV)
1184            )
1185          {
1186            if(work.axis.front.properties.display.visible.XY.cursorH &&
1187               properties.cursor.axis.XY.front.H>=0 &&
1188               properties.cursor.axis.XY.front.H<work.axis.front.properties.XY.values.H.length
1189              )
1190            {
1191              // draw the period rectangle
1192              pH=options.axis.front.getXYHPos(properties.cursor.axis.XY.front.H, false);
1193              if(options.cursor.verticalType=='bar')
1194              {
1195                canvasObjects.cursor.shapeRect(pH, 0, work.axis.front.data.XY.H.space, work.axis.front.properties.size.height);
1196              }
1197              else
1198              {
1199                if(work.axis.front.properties.XY.ticks.H.offset0) pH+=work.axis.front.data.XY.H.space/2;
1200                canvasObjects.cursor.shapeLine(pH, 0, pH, work.axis.front.properties.size.height);
1201              }
1202            }
1203
1204            // calculate the nearest y value (tick's frequency adjusted)
1205            if(work.axis.front.properties.XY.ticks.V.frequency.small==0)
1206            {
1207              work.step=work.axis.front.properties.XY.ticks.V.frequency.big;
1208            }
1209            else
1210            {
1211              work.step=work.axis.front.properties.XY.ticks.V.frequency.small;
1212            }
1213            work.nearest=(work.step==0)?0:options.axis.front.getXYVStepPos(work.step*Math.round(properties.cursor.axis.XY.front.V/work.step));
1214
1215            if(work.axis.front.properties.display.visible.XY.cursorV &&
1216               work.nearest>=0 && work.nearest<=work.axis.front.properties.size.height
1217              )
1218            {
1219              // draw the value line
1220              canvasObjects.cursor.shapeLine(0, work.nearest, work.axis.front.properties.size.width, work.nearest);
1221            }
1222          } // front axis managment
1223
1224          // back axis managment
1225          if(work.axis.back!=null &&
1226             work.axis.back.properties.mode=='XY' &&
1227             (work.axis.back.properties.display.visible.XY.cursorH ||
1228              work.axis.back.properties.display.visible.XY.cursorV)
1229            )
1230          {
1231            if(work.axis.back.properties.display.visible.XY.cursorH &&
1232               properties.cursor.axis.XY.back.H>=0 &&
1233               properties.cursor.axis.XY.back.H<work.axis.back.properties.XY.values.H.length
1234              )
1235            {
1236              // draw the period rectangle
1237              pH=options.axis.back.getXYHPos(properties.cursor.axis.XY.back.H, false);
1238
1239              if(options.cursor.verticalType=='bar')
1240              {
1241                canvasObjects.cursor.shapeRect(pH, 0, work.axis.back.data.XY.H.space, work.axis.back.properties.size.height);
1242              }
1243              else
1244              {
1245                if(work.axis.back.properties.XY.ticks.H.offset0) pH+=work.axis.back.data.XY.H.space/2;
1246                canvasObjects.cursor.shapeLine(pH, 0, pH, work.axis.back.properties.size.height);
1247              }
1248            }
1249
1250            // calculate the nearest y value (tick's frequency adjusted)
1251            if(work.axis.back.properties.XY.ticks.V.frequency.small==0)
1252            {
1253              work.step=work.axis.back.properties.XY.ticks.V.frequency.big;
1254            }
1255            else
1256            {
1257              work.step=work.axis.back.properties.XY.ticks.V.frequency.small;
1258            }
1259            work.nearest=(work.step==0)?0:options.axis.back.getXYVStepPos(work.step*Math.round(properties.cursor.axis.XY.back.V/work.step));
1260            if(work.axis.back.properties.display.visible.XY.cursorV &&
1261               work.nearest>=0 && work.nearest<=work.axis.back.properties.size.height)
1262            {
1263              canvasObjects.cursor.shapeLine(0, work.nearest, work.axis.back.properties.size.width, work.nearest);
1264            }
1265          } // back axis managment
1266
1267
1268          //restore the canvas state
1269          canvasObjects.cursor.drawingStatePop();
1270        }, //drawCursor
1271
1272      /**
1273       * this function draws the graphs
1274       */
1275      draw : function (object)
1276        {
1277          var properties=object.data('properties'),
1278              canvasObjects=object.data('canvasObjects'),
1279              options=object.data('options'),
1280              work={
1281                  margins:options.margins.get(),
1282                  axis:{
1283                    front:(options.axis.front!=null)?options.axis.front.get():null,
1284                    back:(options.axis.back!=null)?options.axis.back.get():null
1285                  },
1286                  width:canvasObjects.axis.getContextWidth(),
1287                  height:canvasObjects.axis.getContextHeight(),
1288                  legendBox:null
1289                };
1290
1291          if(!properties.initialized) return(false);
1292
1293          canvasObjects.axis.shapeClearRect(0,0,work.width, work.height);
1294          canvasObjects.graph.shapeClearRect(0,0,work.width, work.height);
1295
1296          canvasObjects.axis.drawingManageCrisp(true);
1297          canvasObjects.graph.drawingManageCrisp(true);
1298
1299          canvasObjects.axis.drawingStatePush();
1300          canvasObjects.graph.drawingStatePush();
1301
1302          canvasObjects.axis.transformScale({y:-1});
1303          canvasObjects.graph.transformScale({y:-1});
1304
1305          canvasObjects.axis.transformTranslate({x:work.margins.left, y:work.margins.bottom-work.height});
1306          canvasObjects.graph.transformTranslate({x:work.margins.left, y:work.margins.bottom-work.height});
1307
1308          privateMethods.drawLegend(object);
1309          if(work.axis.back!=null) privateMethods.drawGraph(object, options.axis.back);
1310          if(work.axis.front!=null) privateMethods.drawGraph(object, options.axis.front);
1311
1312          canvasObjects.axis.drawingStatePop();
1313          canvasObjects.graph.drawingStatePop();
1314
1315          return(true);
1316        },
1317
1318      drawGraph : function (object, axis)
1319        {
1320          var properties=object.data('properties'),
1321              canvasObjects=object.data('canvasObjects'),
1322              options=object.data('options'),
1323              work={
1324                  axis:axis.get(),
1325                  margins:options.margins.get(),
1326                  width:canvasObjects.axis.getContextWidth(),
1327                  height:canvasObjects.axis.getContextHeight()
1328                };
1329
1330          privateMethods.drawAxis(object, axis);
1331          for(var i=work.axis.properties.series.length-1;i>=0;i--)
1332          {
1333            switch(work.axis.properties.series[i].get().options.get().type)
1334            {
1335              case 'bar':
1336                privateMethods.drawSerieBar(object, axis, work.axis.properties.series[i]);
1337                break;
1338              case 'area':
1339                privateMethods.drawSerieArea(object, axis, work.axis.properties.series[i]);
1340                break;
1341              case 'line':
1342                privateMethods.drawSerieLine(object, axis, work.axis.properties.series[i]);
1343                break;
1344              case 'pie':
1345                privateMethods.drawSeriePie(object, axis, work.axis.properties.series[i]);
1346                break;
1347            }
1348          }
1349
1350        },
1351
1352      /**
1353       * draw the axis; canvas must be ready before calling this function
1354       */
1355      drawAxis : function (object, axis)
1356        {
1357          var properties=object.data('properties'),
1358              canvasObjects=object.data('canvasObjects'),
1359              options=object.data('options'),
1360              work={
1361                  margins:options.margins.get(),
1362                  axis:axis.get(),
1363                  width:canvasObjects.axis.getContextWidth(),
1364                  height:canvasObjects.axis.getContextHeight()
1365                };
1366
1367          if(
1368              work.axis.properties.mode=='pie' && !work.axis.properties.display.visible.pie
1369                ||
1370              work.axis.properties.mode=='XY' &&
1371             !work.axis.properties.display.visible.XY.H && !work.axis.properties.display.visible.XY.V
1372            ) return(false);
1373
1374          // prepare canvas
1375          canvasObjects.axis.styleFillColor(work.axis.properties.display.color);
1376          canvasObjects.axis.styleStrokeColor(work.axis.properties.display.color);
1377          canvasObjects.axis.styleStrokeDraw({width:1, cap:'butt', joints:'miter'});
1378
1379          /*
1380           * -------------------------------------------------------------------
1381           * drawing horizontal ticks&values
1382           * -------------------------------------------------------------------
1383           */
1384          if(work.axis.properties.mode=='XY' && work.axis.properties.display.visible.XY.H)
1385          {
1386            canvasObjects.axis.shapeLine(0,0,work.axis.properties.size.width,0);
1387
1388            // prepare values
1389            switch(work.axis.properties.XY.ticks.H.value.rotate)
1390            {
1391              case 0:
1392                canvasObjects.axis.textStyle(
1393                  {
1394                    font:work.axis.properties.XY.ticks.H.value.fontName+' '+work.axis.properties.XY.ticks.H.value.fontSize+'px',
1395                    alignH:'center',
1396                    alignV:'top'
1397                  }
1398                );
1399                break;
1400              case 90:
1401                canvasObjects.axis.textStyle(
1402                  {
1403                    font:work.axis.properties.XY.ticks.H.value.fontName+' '+work.axis.properties.XY.ticks.H.value.fontSize+'px',
1404                    alignH:'right',
1405                    alignV:'center'
1406                  }
1407                );
1408                break;
1409              default:
1410                canvasObjects.axis.textStyle(
1411                  {
1412                    font:work.axis.properties.XY.ticks.H.value.fontName+' '+work.axis.properties.XY.ticks.H.value.fontSize+'px',
1413                    alignH:'right',
1414                    alignV:'top'
1415                  }
1416                );
1417                break;
1418            }
1419            // draw
1420            for(var i=0;i<work.axis.properties.XY.values.H.length;i++)
1421            {
1422              p=axis.getXYHPos(i);
1423              if(work.axis.properties.XY.ticks.H.frequency.big>0 &&
1424                 work.axis.properties.XY.ticks.H.visible.big &&
1425                 i%work.axis.properties.XY.ticks.H.frequency.big==0)
1426              {
1427                canvasObjects.axis.shapeLine(p,0,p,-work.axis.properties.XY.ticks.H.size.big);
1428
1429                if(work.axis.properties.XY.ticks.H.value.visible)
1430                {
1431                  canvasObjects.axis.drawingStatePush();
1432                  canvasObjects.axis.transformScale({y:-1});
1433                  canvasObjects.axis.transformTranslate(
1434                    {
1435                      x:p,
1436                      y:work.axis.properties.XY.ticks.H.size.big+2
1437                    }
1438                  );
1439                  canvasObjects.axis.transformRotate({angle:work.axis.properties.XY.ticks.H.value.rotate, mode:'degree'})
1440                  canvasObjects.axis.textPrint(work.axis.properties.XY.values.H[i],0,0,'fill');
1441                  canvasObjects.axis.drawingStatePop();
1442                }
1443              }
1444              else if(work.axis.properties.XY.ticks.H.frequency.small>0 &&
1445                 work.axis.properties.XY.ticks.H.visible.small &&
1446                 i%work.axis.properties.XY.ticks.H.frequency.small==0)
1447              {
1448                canvasObjects.axis.shapeLine(p,0,p,-work.axis.properties.XY.ticks.H.size.small);
1449              }
1450            }
1451          }
1452
1453          /*
1454           * -------------------------------------------------------------------
1455           * drawing vertical ticks&values
1456           * -------------------------------------------------------------------
1457           */
1458          if(work.axis.properties.mode=='XY' && work.axis.properties.display.visible.XY.V)
1459          {
1460            canvasObjects.axis.shapeLine(0,0,0,work.axis.properties.size.height);
1461
1462            // prepare values
1463            switch(work.axis.properties.XY.ticks.V.value.rotate)
1464            {
1465              case 0:
1466                canvasObjects.axis.textStyle(
1467                  {
1468                    font:work.axis.properties.XY.ticks.V.value.fontName+' '+work.axis.properties.XY.ticks.V.value.fontSize+'px',
1469                    alignH:'right',
1470                    alignV:'center'
1471                  }
1472                );
1473                break;
1474              case 90:
1475                canvasObjects.axis.textStyle(
1476                  {
1477                    font:work.axis.properties.XY.ticks.V.value.fontName+' '+work.axis.properties.XY.ticks.V.value.fontSize+'px',
1478                    alignH:'center',
1479                    alignV:'bottom'
1480                  }
1481                );
1482                break;
1483              default:
1484                canvasObjects.axis.textStyle(
1485                  {
1486                    font:work.axis.properties.XY.ticks.V.value.fontName+' '+work.axis.properties.XY.ticks.V.value.fontSize+'px',
1487                    alignH:'right',
1488                    alignV:'bottom'
1489                  }
1490                );
1491                break;
1492            }
1493            //draw small ticks
1494            if(work.axis.properties.XY.ticks.V.value.visible &&
1495               work.axis.properties.XY.ticks.V.frequency.small>0 &&
1496               work.axis.properties.XY.ticks.V.visible.small)
1497            {
1498              i=0;
1499              while(i<=work.axis.properties.XY.ticks.V.steps)
1500              {
1501                p=axis.getXYVStepPos(i);
1502                canvasObjects.axis.shapeLine(0,p,-work.axis.properties.XY.ticks.V.size.small,p);
1503                i+=work.axis.properties.XY.ticks.V.frequency.small;
1504              }
1505            }
1506
1507            //draw big ticks
1508            if(work.axis.properties.XY.ticks.V.value.visible &&
1509               work.axis.properties.XY.ticks.V.frequency.big >0 &&
1510               work.axis.properties.XY.ticks.V.visible.big)
1511            {
1512              i=0;
1513              while(i<=work.axis.properties.XY.ticks.V.steps)
1514              {
1515                p=axis.getXYVStepPos(i);
1516
1517                canvasObjects.axis.shapeLine(0,p,-work.axis.properties.XY.ticks.V.size.big,p);
1518
1519                if(work.axis.properties.XY.ticks.V.value.visible)
1520                {
1521                  canvasObjects.axis.drawingStatePush();
1522                  canvasObjects.axis.transformScale({y:-1});
1523                  canvasObjects.axis.transformTranslate(
1524                    {
1525                      x:-(work.axis.properties.XY.ticks.V.size.big+2),
1526                      y:-(p+work.axis.properties.XY.ticks.V.value.fontSize/2)
1527                    }
1528                  );
1529                  canvasObjects.axis.transformRotate({angle:work.axis.properties.XY.ticks.V.value.rotate, mode:'degree'})
1530                  canvasObjects.axis.textPrint(i,0,0,'fill');
1531                  canvasObjects.axis.drawingStatePop();
1532                }
1533                i+=work.axis.properties.XY.ticks.V.frequency.big;
1534              }
1535            }
1536          }
1537
1538          /*
1539           * -------------------------------------------------------------------
1540           * drawing values for pies
1541           * -------------------------------------------------------------------
1542           */
1543          if(work.axis.properties.mode=='pie' && work.axis.properties.display.visible.pie)
1544          {
1545            var drawSerieValues = function (serie)
1546                  {
1547                    var pieWork={
1548                            serieProp:serie.get(),
1549                            tmp:0,
1550                            angle:0,
1551                            angle2:0,
1552                            angCnv:Math.PI/180,
1553                            pV:0,
1554                            pH:0,
1555                            textWidth:0,
1556                            radiusList:[],
1557                            distance:0,
1558                            distance2:0,
1559                            sumDistance:0,
1560                            minDistance:10,
1561                            endRadius:0,
1562                            startRadius:0,
1563                            lastZero:0
1564                          };
1565
1566                    for(var i=0;i<pieWork.serieProp.values.length;i++)
1567                    {
1568                      pieWork.tmp+=pieWork.serieProp.values[i];
1569                    }
1570                    pieWork.tmp=360/pieWork.tmp;
1571
1572                    pieWork.endRadius=work.axis.properties.pie.outerRadius*pieWork.serieProp.options.get().outerRadius;
1573                    pieWork.startRadius=pieWork.serieProp.options.get().innerRadius+work.axis.properties.pie.innerRadius*(pieWork.serieProp.options.get().outerRadius-pieWork.serieProp.options.get().innerRadius);
1574
1575                    // calculate radius list
1576                    for(var i=0;i<pieWork.serieProp.values.length;i++)
1577                    {
1578                      if(i==0)
1579                      {
1580                        pieWork.radiusList.push({radius:0, distance:0});
1581                      }
1582                      else
1583                      {
1584                        pieWork.distance2=Math.pow(pieWork.endRadius*Math.sin(pieWork.angle*pieWork.angCnv) ,2) + Math.pow(pieWork.endRadius*(1-Math.cos(pieWork.angle*pieWork.angCnv)) ,2);
1585                        pieWork.distance=Math.sqrt(pieWork.distance2);
1586                        pieWork.sumDistance+=pieWork.distance;
1587
1588                        if(pieWork.sumDistance<2*pieWork.minDistance)
1589                        {
1590                          pieWork.radiusList.push({radius:Math.sqrt(pieWork.distance2 + 4*pieWork.minDistance*pieWork.minDistance) , distance:pieWork.distance});
1591                        }
1592                        else
1593                        {
1594                          pieWork.radiusList.push({radius:0, distance:pieWork.distance});
1595                          pieWork.sumDistance=0;
1596                          pieWork.lastZero=i;
1597                        }
1598                      }
1599
1600                      pieWork.angle=pieWork.serieProp.values[i]*pieWork.tmp;
1601                      pieWork.angle2+=pieWork.angle
1602                    }
1603
1604                    canvasObjects.axis.drawingStatePush();
1605                    canvasObjects.axis.styleFillColor(work.axis.properties.display.color);
1606                    // draw lines
1607                    for(var i=0;i<pieWork.serieProp.values.length;i++)
1608                    {
1609                      if(i==0)
1610                      {
1611                        canvasObjects.axis.transformRotate({angle:pieWork.serieProp.values[i]*pieWork.tmp/2, mode:'degree'});
1612                      }
1613                      else
1614                      {
1615                        canvasObjects.axis.transformRotate({angle:(pieWork.serieProp.values[i]*pieWork.tmp+pieWork.serieProp.values[i-1]*pieWork.tmp)/2, mode:'degree'});
1616                      }
1617                      canvasObjects.axis.shapeLine(pieWork.startRadius, 0, pieWork.endRadius+pieWork.radiusList[i].radius, 0);
1618                      canvasObjects.axis.shapeCircle(pieWork.startRadius, 0, 2, {fill:true, stroke:false});
1619                    }
1620                    canvasObjects.axis.drawingStatePop();
1621
1622                    // draw values
1623                    canvasObjects.axis.textStyle(
1624                      {
1625                        font:work.axis.properties.pie.fontName+' '+work.axis.properties.pie.fontSize+'px',
1626                        alignH:'center',
1627                        alignV:'center'
1628                      }
1629                    );
1630
1631                    canvasObjects.axis.drawingStatePush();
1632                    canvasObjects.axis.transformRotate({angle:90, mode:'degree'});
1633                    canvasObjects.axis.transformScale({y:-1});
1634                    pieWork.angle=-90;
1635                    for(var i=0;i<pieWork.serieProp.values.length;i++)
1636                    {
1637                      if(i==0)
1638                      {
1639                        pieWork.angle+=pieWork.serieProp.values[i]*pieWork.tmp/2;
1640                      }
1641                      else
1642                      {
1643                        pieWork.angle+=(pieWork.serieProp.values[i]*pieWork.tmp+pieWork.serieProp.values[i-1]*pieWork.tmp)/2;
1644                      }
1645
1646                      pieWork.pH=(pieWork.endRadius+pieWork.radiusList[i].radius)*Math.cos(pieWork.angle*pieWork.angCnv);
1647                      pieWork.pV=(pieWork.endRadius+pieWork.radiusList[i].radius)*Math.sin(pieWork.angle*pieWork.angCnv)+work.axis.properties.pie.fontSize/2;
1648
1649                      pieWork.textWidth=canvasObjects.axis.textWidth(pieWork.serieProp.values[i]);
1650                      canvasObjects.axis.shapeClearRect(pieWork.pH-pieWork.textWidth.width/2-1, pieWork.pV-work.axis.properties.pie.fontSize-1, pieWork.textWidth.width+2, work.axis.properties.pie.fontSize+2);
1651
1652                      canvasObjects.axis.textPrint(pieWork.serieProp.values[i],pieWork.pH,pieWork.pV,'fill');
1653                    }
1654                    canvasObjects.axis.drawingStatePop();
1655
1656                  };
1657
1658            // save canvas state
1659            canvasObjects.axis.drawingStatePush();
1660
1661            canvasObjects.axis.transformTranslate({x:work.axis.data.pie.H.center, y:work.axis.data.pie.V.center});
1662            canvasObjects.axis.transformRotate({angle:-90, mode:'degree'});
1663
1664            // prepare canvas
1665            canvasObjects.axis.styleStrokeColor(work.axis.properties.display.color);
1666            canvasObjects.axis.styleStrokeDraw({width:1, cap:'butt', joints:'round'});
1667
1668            // draw values
1669            for(var i=work.axis.properties.series.length-1;i>=0;i--)
1670            {
1671              drawSerieValues(work.axis.properties.series[i]);
1672            }
1673            //restore canvas state
1674            canvasObjects.axis.drawingStatePop();
1675          }
1676
1677
1678          return(true);
1679        }, // drawAxis
1680
1681        /**
1682         * calculate the legend width, draw the legend
1683         */
1684        drawLegend : function (object)
1685          {
1686            var properties=object.data('properties'),
1687                canvasObjects=object.data('canvasObjects'),
1688                options=object.data('options'),
1689                work={
1690                    axis:{
1691                      front:(options.axis.front!=null)?options.axis.front.get():null,
1692                      back:(options.axis.back!=null)?options.axis.back.get():null
1693                    },
1694                    margins:options.margins.get(),
1695                    legend:options.legend.get(),
1696                    legendBox:{width:0, height:0, margin:0},
1697                    width:canvasObjects.axis.getContextWidth(),
1698                    height:canvasObjects.axis.getContextHeight(),
1699                    tmpTop:0
1700                  },
1701
1702                calculateLegendBox = function (axis, canvas, legend, currentHeight, currentWidth)
1703                  {
1704                    var returned={width:currentWidth, height:currentHeight, margin:0},
1705                        itemHeight=12,
1706                        tmp=0;
1707
1708                    if(axis!=null)
1709                    {
1710                      if(legend.fontSize>itemHeight) itemHeight=legend.fontSize+4;
1711                      canvasObjects.axis.textStyle({font:legend.fontSize+'px '+legend.fontName});
1712
1713                      for(var i=0; i<axis.properties.series.length;i++)
1714                      {
1715                        returned.height+=itemHeight;
1716                        tmp=canvas.textWidth(axis.properties.series[i].get().name);
1717                        if(tmp.width>returned.width) returned.width=tmp.width;
1718
1719                        // if serie type is 'pie', use valuesLabels in the legend
1720                        if(axis.properties.series[i].get().options.get().type=='pie')
1721                        {
1722                          for(var j=0;j<axis.properties.series[i].get().valuesLabels.length;j++)
1723                          {
1724                            returned.height+=itemHeight;
1725                            tmp=canvas.textWidth(axis.properties.series[i].get().valuesLabels[j]);
1726                            if(tmp.width>returned.width) returned.width=tmp.width;
1727                          }
1728                          if(i<axis.properties.series.length-1) returned.height+=itemHeight/2;
1729                        }
1730                      }
1731                    }
1732
1733                    return(returned);
1734                  },
1735
1736                drawLegendNames = function (axis, canvas, legend, currentTop)
1737                  {
1738                    var top=currentTop,
1739                        itemHeight=12,
1740                        tmp=0;
1741
1742                    if(axis!=null)
1743                    {
1744                      canvas.drawingStatePush();
1745                      canvas.transformScale({y:-1});
1746                      canvas.transformTranslate({y:4-work.legendBox.height});
1747
1748                      canvasObjects.axis.textStyle(
1749                        {
1750                          font:legend.fontSize+'px '+legend.fontName,
1751                          alignH:'left',
1752                          alignV:'top'
1753                        }
1754                      );
1755
1756                      canvas.styleFillColor(work.legend.borderColor);
1757
1758                      if(legend.fontSize>itemHeight) itemHeight=legend.fontSize+4;
1759
1760                      for(var i=0; i<axis.properties.series.length;i++)
1761                      {
1762                        if(axis.properties.series[i].get().options.get().type=='pie')
1763                        {
1764                          canvas.textPrint(axis.properties.series[i].get().name,4,top,'fill');
1765                          top+=itemHeight;
1766
1767                          for(var j=0;j<axis.properties.series[i].get().valuesLabels.length;j++)
1768                          {
1769                            canvas.textPrint(axis.properties.series[i].get().valuesLabels[j],26,top,'fill');
1770                            drawLegendStyle(canvas, new CDSerie({options: new CDSerieOptionsBar({backgroundColor:axis.properties.series[i].get().options.get().backgroundColors[j]}) }).get(), top+itemHeight/2);
1771                            top+=itemHeight;
1772                          }
1773                          if(i<axis.properties.series.length-1) top+=itemHeight/2;
1774                        }
1775                        else
1776                        {
1777                          canvas.textPrint(axis.properties.series[i].get().name,26,top,'fill');
1778                          drawLegendStyle(canvas, axis.properties.series[i].get(), top+itemHeight/2);
1779                          top+=itemHeight;
1780                        }
1781                      }
1782                      canvas.drawingStatePop();
1783                    }
1784
1785                    return(top);
1786                  },
1787
1788                drawLegendStyle = function (canvas, serie, top)
1789                  {
1790                    canvas.drawingStatePush();
1791                    switch(serie.options.get().type)
1792                    {
1793                      case 'bar':
1794                      case 'area':
1795                        canvas.styleFillColor(serie.options.get().backgroundColor);
1796                        canvas.shapeRect(11,top-6,6,6, {fill:true, stroke:false});
1797                        break;
1798                      case 'line':
1799                        canvas.styleFillColor(serie.options.get().color);
1800                        canvas.styleStrokeColor(serie.options.get().color);
1801                        canvas.styleStrokeDraw({width:serie.options.width, cap:'butt', joints:'miter'});
1802                        canvas.shapeLine(6,top,22,top);
1803                        tmpSize=serie.options.get().dotSize/2.0;
1804                        switch(serie.options.get().dot)
1805                        {
1806                          case 'circle':
1807                            canvas.shapeCircle(14,top,tmpSize,{fill:true, stroke:false});
1808                            break;
1809                          case 'square':
1810                            canvas.shapeRect(14-tmpSize,top-tmpSize,serie.options.get().dotSize,serie.options.get().dotSize,{fill:true, stroke:false});
1811                            break;
1812                          case 'diamond':
1813                            canvas.shapeSimpleShape("close",[14,top-tmpSize,14+tmpSize,top,14,top+tmpSize,14-tmpSize,top],{fill:true, stroke:false});
1814                            break;
1815                          default:
1816                            // 'none'
1817                            break;
1818                        }
1819                        break;
1820                      case 'pie':
1821                        break;
1822                    }
1823                    canvas.drawingStatePop();
1824                  },
1825
1826                setAxisSize = function ()
1827                  {
1828                    var w=0;
1829
1830                    if(work.legend.visible) w=work.legendBox.width+work.legendBox.margin;
1831
1832                    if(options.axis.front!=null)
1833                      options.axis.front.set(
1834                        {
1835                          size:{
1836                              width:options.display.width-options.margins.get().left-options.margins.get().right-w
1837                            }
1838                        }
1839                      );
1840
1841                    if(options.axis.back!=null)
1842                      options.axis.back.set(
1843                        {
1844                          size:{
1845                              width:options.display.width-options.margins.get().left-options.margins.get().right-w
1846                            }
1847                        }
1848                      );
1849                  };
1850
1851            if(!work.legend.visible) return(false);
1852
1853            canvasObjects.axis.drawingStatePush();
1854
1855            work.legendBox=calculateLegendBox(work.axis.front, canvasObjects.axis, work.legend, 0, 0);
1856            work.legendBox=calculateLegendBox(work.axis.back, canvasObjects.axis, work.legend, work.legendBox.height, work.legendBox.width);
1857            work.legendBox.width+=32; //6+16+4+6
1858            work.legendBox.height+=8;
1859
1860            if(work.legend.width!=0) work.legendBox.width=work.legend.width;
1861
1862            options.legend.setRealWidth(work.legendBox.width);
1863
1864            canvasObjects.axis.styleFillColor(work.legend.backgroundColor);
1865            canvasObjects.axis.styleStrokeColor(work.legend.borderColor);
1866            canvasObjects.axis.styleStrokeDraw({width:work.legend.borderWidth, cap:'butt', joints:'miter'});
1867
1868            work.legendBox.margin=work.margins.right;
1869            if(work.legend.position=='right')
1870            {
1871              canvasObjects.axis.transformTranslate(
1872                {
1873                  x:work.width-(work.margins.left+work.margins.right+work.legendBox.width),
1874                  y:work.height-(work.margins.top+work.margins.bottom+work.legendBox.height)
1875                }
1876              );
1877            }
1878            else
1879              canvasObjects.axis.transformTranslate(
1880                {
1881                  x:work.legendBox.margin-work.margins.left,
1882                  y:work.height-(work.margins.top+work.margins.bottom+work.legendBox.height)
1883                }
1884              );
1885
1886
1887            canvasObjects.axis.shapeRect(0,0,work.legendBox.width, work.legendBox.height, {fill:true, stroke:(work.legend.borderWidth>0)});
1888
1889            tmpTop=drawLegendNames(work.axis.front, canvasObjects.axis, work.legend, 0);
1890            tmpTop=drawLegendNames(work.axis.back, canvasObjects.axis, work.legend, tmpTop);
1891
1892            // restore canvas state
1893            canvasObjects.axis.drawingStatePop();
1894
1895            if(work.legend.position=='left')
1896            {
1897              canvasObjects.axis.transformTranslate({x:work.legendBox.width+work.legendBox.margin});
1898              canvasObjects.graph.transformTranslate({x:work.legendBox.width+work.legendBox.margin});
1899              //canvasObjects.cursor.transformTranslate({x:work.legendBox.width+work.legendBox.margin});
1900            }
1901
1902            setAxisSize();
1903
1904            return(true);
1905          }, // drawLegend
1906
1907        drawSerieBar : function (object, axis, serie)
1908          {
1909            var properties=object.data('properties'),
1910                canvasObjects=object.data('canvasObjects'),
1911                options=object.data('options'),
1912                work={
1913                    margins:options.margins.get(),
1914                    axis:axis.get(),
1915                    width:canvasObjects.axis.getContextWidth(),
1916                    height:canvasObjects.axis.getContextHeight(),
1917                    serieProp:serie.get(),
1918                    opt:serie.get().options.get()
1919                  };
1920
1921            // save canvas state
1922            canvasObjects.graph.drawingStatePush();
1923
1924            // prepare canvas
1925            canvasObjects.graph.styleFillColor(work.opt.backgroundColor);
1926            canvasObjects.graph.styleStrokeColor(work.opt.borderColor);
1927            canvasObjects.graph.styleStrokeDraw({width:work.opt.borderWidth, cap:'butt', joints:'miter'});
1928
1929            for(var i=0;i<work.serieProp.values.length;i++)
1930            {
1931              // calculate horizontal & vertical values
1932              var pH=axis.getXYHPos(i),
1933                  pV=axis.getXYVStepPos((work.opt.mode=='normal')?work.serieProp.values[i]:work.opt.cumulativesValues[i]);
1934
1935              bWidth=work.axis.data.XY.H.space*work.opt.width;
1936
1937              // adjust horizontal value (using H axis offset0 or not)
1938              if(work.axis.properties.XY.ticks.H.offset0)
1939              {
1940                pH-=Math.floor(bWidth/2);
1941              }
1942              else
1943              {
1944                pH+=Math.floor((work.axis.data.XY.H.space-bWidth)/2);
1945              }
1946              // adjust horizontal value (using offset bar or not)
1947              if(work.opt.mode=='normal') pH+=Math.floor(work.opt.offset*bWidth);
1948
1949              //draw bar !
1950              canvasObjects.graph.shapeRect(pH,0,Math.ceil(bWidth),pV, {fill:true, stroke:work.opt.borderWidth>0});
1951            }
1952
1953            // restore canvas state
1954            canvasObjects.graph.drawingStatePop();
1955          },
1956        drawSerieArea : function (object, axis, serie)
1957          {
1958            var properties=object.data('properties'),
1959                canvasObjects=object.data('canvasObjects'),
1960                options=object.data('options'),
1961                work={
1962                    margins:options.margins.get(),
1963                    axis:axis.get(),
1964                    width:canvasObjects.axis.getContextWidth(),
1965                    height:canvasObjects.axis.getContextHeight(),
1966                    serieProp:serie.get(),
1967                    opt:serie.get().options.get(),
1968                    points:[]
1969                  };
1970
1971            // save canvas state
1972            canvasObjects.graph.drawingStatePush();
1973
1974            // prepare canvas
1975            canvasObjects.graph.styleFillColor(work.opt.backgroundColor);
1976            canvasObjects.graph.styleStrokeColor(work.opt.borderColor);
1977            canvasObjects.graph.styleStrokeDraw({width:work.opt.borderWidth, cap:'butt', joints:'miter'});
1978
1979            //start point
1980            work.points=[axis.getXYHPos(0),axis.getXYVStepPos(0)];
1981
1982            for(var i=0;i<work.serieProp.values.length;i++)
1983            {
1984              // calculate horizontal & vertical values
1985              work.points.push(axis.getXYHPos(i));
1986              work.points.push(axis.getXYVStepPos((work.opt.mode=='normal')?work.serieProp.values[i]:work.opt.cumulativesValues[i]));
1987            }
1988            work.points.push(axis.getXYHPos(i-1));
1989            work.points.push(axis.getXYVStepPos(0));
1990
1991            //draw area !
1992            canvasObjects.graph.shapeSimpleShape('close', work.points, {fill:true, stroke:false});
1993
1994            if(work.opt.borderWidth>0)
1995            {
1996              work.points.splice(0,2);
1997              work.points.splice(-1,2);
1998              canvasObjects.graph.shapeSimpleShape('open', work.points, {fill:false, stroke:true});
1999            }
2000
2001            // restore canvas state
2002            canvasObjects.graph.drawingStatePop();
2003          },
2004        drawSerieLine : function (object, axis, serie)
2005          {
2006            var properties=object.data('properties'),
2007                canvasObjects=object.data('canvasObjects'),
2008                options=object.data('options'),
2009                work={
2010                    margins:options.margins.get(),
2011                    axis:axis.get(),
2012                    width:canvasObjects.axis.getContextWidth(),
2013                    height:canvasObjects.axis.getContextHeight(),
2014                    serieProp:serie.get(),
2015                    opt:serie.get().options.get(),
2016                    points:[]
2017                  },
2018                tmpSize=work.opt.dotSize/2.0;
2019
2020            // save canvas state
2021            canvasObjects.graph.drawingStatePush();
2022
2023            // prepare canvas
2024            canvasObjects.graph.styleFillColor(work.opt.color);
2025            canvasObjects.graph.styleStrokeColor(work.opt.color);
2026            canvasObjects.graph.styleStrokeDraw({width:work.opt.width, cap:'butt', joints:'miter'});
2027
2028
2029            for(var i=0;i<work.serieProp.values.length;i++)
2030            {
2031              var pH=axis.getXYHPos(i),
2032                  pV=axis.getXYVStepPos(work.serieProp.values[i]);
2033
2034              switch(work.opt.dot)
2035              {
2036                case 'circle':
2037                  canvasObjects.graph.shapeCircle(pH,pV,tmpSize,{fill:true, stroke:false});
2038                  break;
2039                case 'square':
2040                  canvasObjects.graph.shapeRect(pH-tmpSize,pV-tmpSize,work.opt.dotSize,work.opt.dotSize,{fill:true, stroke:false});
2041                  break;
2042                case 'diamond':
2043                  canvasObjects.graph.shapeSimpleShape("close",[pH,pV-tmpSize,pH+tmpSize,pV,pH,pV+tmpSize,pH-tmpSize,pV],{fill:true, stroke:false});
2044                  break;
2045                default:
2046                  // 'none'
2047                  break;
2048              }
2049
2050              // calculate horizontal & vertical values
2051              work.points.push(pH);
2052              work.points.push(pV);
2053            }
2054
2055            canvasObjects.graph.shapeSimpleShape('open', work.points, {fill:false, stroke:true});
2056
2057            // restore canvas state
2058            canvasObjects.graph.drawingStatePop();
2059          },
2060        drawSeriePie : function (object, axis, serie)
2061          {
2062            var properties=object.data('properties'),
2063                canvasObjects=object.data('canvasObjects'),
2064                options=object.data('options'),
2065                work={
2066                    margins:options.margins.get(),
2067                    axis:axis.get(),
2068                    width:canvasObjects.axis.getContextWidth(),
2069                    height:canvasObjects.axis.getContextHeight(),
2070                    serieProp:serie.get(),
2071                    opt:serie.get().options.get(),
2072                    points:[],
2073                    tmp:0,
2074                    angle:0,
2075                    angle2:0,
2076                    pH:0,
2077                    pV:0,
2078                    angCnv:Math.PI/180
2079                  };
2080
2081
2082            for(var i=0;i<work.serieProp.values.length;i++)
2083            {
2084              work.tmp+=work.serieProp.values[i];
2085            }
2086            work.tmp=360/work.tmp;
2087            work.pH=work.axis.data.pie.H.center;
2088            work.pV=work.axis.data.pie.V.center;
2089
2090            // save canvas state
2091            canvasObjects.graph.drawingStatePush();
2092
2093            canvasObjects.graph.transformTranslate({x:work.pH, y:work.pV});
2094            canvasObjects.graph.transformRotate({angle:-90, mode:'degree'});
2095
2096            // prepare canvas
2097            canvasObjects.graph.styleStrokeColor(work.opt.borderColor);
2098            canvasObjects.graph.styleStrokeDraw({width:work.opt.borderWidth, cap:'butt', joints:'round'});
2099
2100
2101            for(var i=0;i<work.serieProp.values.length;i++)
2102            {
2103              work.angle2+=work.serieProp.values[i]*work.tmp;
2104
2105              canvasObjects.graph.styleFillColor(work.opt.backgroundColors[i]);
2106              canvasObjects.graph.shapePathBegin();
2107
2108              if(work.opt.innerRadius>0)
2109              {
2110                canvasObjects.graph.shapePathArc(0,0,work.opt.innerRadius,work.angle, work.angle2, true,'degree');
2111                canvasObjects.graph.shapePathArc(0,0,work.opt.outerRadius,work.angle2, work.angle, false,'degree');
2112              }
2113              else
2114              {
2115                canvasObjects.graph.shapePathMoveTo(0,0);
2116                canvasObjects.graph.shapePathArc(0,0,work.opt.outerRadius,work.angle, work.angle2, true,'degree');
2117              }
2118              canvasObjects.graph.shapePathEnd(false, true);
2119
2120              work.angle=work.angle2;
2121            }
2122
2123            if(work.opt.borderWidth>0)
2124            {
2125              work.angle=0;
2126              work.angle2=0;
2127              for(var i=0;i<work.serieProp.values.length;i++)
2128              {
2129                work.angle2+=work.serieProp.values[i]*work.tmp;
2130
2131                canvasObjects.graph.shapePathBegin();
2132                if(work.opt.innerRadius>0)
2133                {
2134                  canvasObjects.graph.shapePathArc(0,0,work.opt.innerRadius,work.angle, work.angle2, true,'degree');
2135                  canvasObjects.graph.shapePathArc(0,0,work.opt.outerRadius,work.angle2, work.angle, false,'degree');
2136                }
2137                else
2138                {
2139                  canvasObjects.graph.shapePathMoveTo(0,0);
2140                  canvasObjects.graph.shapePathArc(0,0,work.opt.outerRadius,work.angle, work.angle2, true,'degree');
2141                }
2142                canvasObjects.graph.shapePathEnd(false, false);
2143
2144                work.angle=work.angle2;
2145              }
2146            }
2147
2148            // restore canvas state
2149            canvasObjects.graph.drawingStatePop();
2150          }
2151    };
2152
2153    $.fn.drawingGraph = function(method)
2154    {
2155      if(publicMethods[method])
2156      {
2157        return publicMethods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
2158      }
2159      else if(typeof method === 'object' || ! method)
2160      {
2161        return publicMethods.init.apply(this, arguments);
2162      }
2163      else
2164      {
2165        $.error( 'Method ' +  method + ' does not exist on jQuery.drawingGraph' );
2166      }
2167    } // $.fn.inputNum
2168
2169  }
2170)(jQuery);
Note: See TracBrowser for help on using the repository browser.