socmap_adf 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. data/.gitignore +10 -0
  2. data/.rvmrc +81 -0
  3. data/CHANGELOG.md +5 -0
  4. data/Gemfile +17 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.md +3 -0
  7. data/Rakefile +36 -0
  8. data/lib/assets/.gitkeep +0 -0
  9. data/lib/assets/javascripts/.DS_Store +0 -0
  10. data/lib/assets/javascripts/socmap_adf/.DS_Store +0 -0
  11. data/lib/assets/javascripts/socmap_adf/init.js.coffee.erb +9 -0
  12. data/lib/assets/javascripts/socmap_adf/lib/adf_delegate.js.coffee +13 -0
  13. data/lib/assets/javascripts/socmap_adf/lib/adf_view.js.coffee +7 -0
  14. data/lib/assets/javascripts/socmap_adf/modules/.DS_Store +0 -0
  15. data/lib/assets/javascripts/socmap_adf/modules/cluster/init.js.coffee +11 -0
  16. data/lib/assets/javascripts/socmap_adf/modules/cluster/lib/elycharts.js +3769 -0
  17. data/lib/assets/javascripts/socmap_adf/modules/cluster/lib/raphael.js +5815 -0
  18. data/lib/assets/javascripts/socmap_adf/modules/cluster/templates/chart.jst.eco +6 -0
  19. data/lib/assets/javascripts/socmap_adf/modules/cluster/views/chart.js.coffee +107 -0
  20. data/lib/assets/javascripts/socmap_adf/modules/cluster/views/chart_icon.js.coffee +106 -0
  21. data/lib/assets/javascripts/socmap_adf/modules/cluster/views/cluster.js.coffee +127 -0
  22. data/lib/assets/javascripts/socmap_adf/modules/cluster/views/default_icon.js.coffee +170 -0
  23. data/lib/assets/javascripts/socmap_adf/modules/cluster/views/main.js.coffee +10 -0
  24. data/lib/assets/javascripts/socmap_adf/modules/cluster/views/marker_clusterer.js.coffee +358 -0
  25. data/lib/assets/javascripts/socmap_adf/modules/file_uploader/init.js.coffee +7 -0
  26. data/lib/assets/javascripts/socmap_adf/modules/file_uploader/templates/existing_file.jst.eco +10 -0
  27. data/lib/assets/javascripts/socmap_adf/modules/file_uploader/templates/file.jst.eco +3 -0
  28. data/lib/assets/javascripts/socmap_adf/modules/file_uploader/templates/main.jst.eco +7 -0
  29. data/lib/assets/javascripts/socmap_adf/modules/file_uploader/templates/uploading.jst.eco +3 -0
  30. data/lib/assets/javascripts/socmap_adf/modules/file_uploader/views/main.js.coffee +76 -0
  31. data/lib/assets/javascripts/socmap_adf/modules/form/init.js.coffee +9 -0
  32. data/lib/assets/javascripts/socmap_adf/modules/form/models/base.js.coffee +73 -0
  33. data/lib/assets/javascripts/socmap_adf/modules/form/models/error.js.coffee +12 -0
  34. data/lib/assets/javascripts/socmap_adf/modules/form/models/field_binder.js.coffee +104 -0
  35. data/lib/assets/javascripts/socmap_adf/modules/form/models/validator.js.coffee +65 -0
  36. data/lib/assets/javascripts/socmap_adf/modules/form/templates/error_field.jst.eco +7 -0
  37. data/lib/assets/javascripts/socmap_adf/modules/form/templates/field_set.jst.eco +6 -0
  38. data/lib/assets/javascripts/socmap_adf/modules/form/templates/field_set_button.jst.eco +1 -0
  39. data/lib/assets/javascripts/socmap_adf/modules/form/templates/field_sets.jst.eco +2 -0
  40. data/lib/assets/javascripts/socmap_adf/modules/form/views/base.js.coffee +9 -0
  41. data/lib/assets/javascripts/socmap_adf/modules/form/views/field_set.js.coffee +88 -0
  42. data/lib/assets/javascripts/socmap_adf/modules/form/views/field_set_with_button.js.coffee +38 -0
  43. data/lib/assets/javascripts/socmap_adf/modules/form/views/field_sets.js.coffee +81 -0
  44. data/lib/assets/javascripts/socmap_adf/modules/gmap/.DS_Store +0 -0
  45. data/lib/assets/javascripts/socmap_adf/modules/gmap/init.js.coffee +6 -0
  46. data/lib/assets/javascripts/socmap_adf/modules/gmap/views/.DS_Store +0 -0
  47. data/lib/assets/javascripts/socmap_adf/modules/gmap/views/custom_marker.js.coffee +36 -0
  48. data/lib/assets/javascripts/socmap_adf/modules/gmap/views/marker.js.coffee +72 -0
  49. data/lib/assets/javascripts/socmap_adf/modules/gmap/views/marker_with_label.js +566 -0
  50. data/lib/assets/javascripts/socmap_adf/modules/gmap/views/overlay.js.coffee +237 -0
  51. data/lib/assets/javascripts/socmap_adf/modules/gmap/views/overlay_view.js.coffee +143 -0
  52. data/lib/assets/javascripts/socmap_adf/modules/gmap/views/polygon.js.coffee +107 -0
  53. data/lib/assets/javascripts/socmap_adf/modules/image_uploader/init.js.coffee +7 -0
  54. data/lib/assets/javascripts/socmap_adf/modules/image_uploader/templates/main.jst.eco +10 -0
  55. data/lib/assets/javascripts/socmap_adf/modules/image_uploader/views/main.js.coffee +69 -0
  56. data/lib/assets/javascripts/socmap_adf/modules/map/.DS_Store +0 -0
  57. data/lib/assets/javascripts/socmap_adf/modules/map/init.js.coffee +9 -0
  58. data/lib/assets/javascripts/socmap_adf/modules/map/models/custom_map.js.coffee +1 -0
  59. data/lib/assets/javascripts/socmap_adf/modules/map/models/map.js.coffee +63 -0
  60. data/lib/assets/javascripts/socmap_adf/modules/map/templates/main.jst.eco +1 -0
  61. data/lib/assets/javascripts/socmap_adf/modules/map/templates/moving_pin.jst.eco +11 -0
  62. data/lib/assets/javascripts/socmap_adf/modules/map/templates/tooltip.jst.eco +1 -0
  63. data/lib/assets/javascripts/socmap_adf/modules/map/views/google_marker_clusterer.js.coffee +11 -0
  64. data/lib/assets/javascripts/socmap_adf/modules/map/views/main.js.coffee +79 -0
  65. data/lib/assets/javascripts/socmap_adf/modules/map/views/moving_pin.js.coffee +47 -0
  66. data/lib/assets/javascripts/socmap_adf/modules/map/views/tooltip.js.coffee +46 -0
  67. data/lib/assets/javascripts/socmap_adf/modules/marker/init.js.coffee +6 -0
  68. data/lib/assets/javascripts/socmap_adf/modules/marker/views/.DS_Store +0 -0
  69. data/lib/assets/javascripts/socmap_adf/modules/marker/views/main.js.coffee +132 -0
  70. data/lib/assets/javascripts/socmap_adf/modules/minimap/init.js.coffee +9 -0
  71. data/lib/assets/javascripts/socmap_adf/modules/minimap/models/minimap.js.coffee +36 -0
  72. data/lib/assets/javascripts/socmap_adf/modules/minimap/templates/moving_pin.jst.eco +11 -0
  73. data/lib/assets/javascripts/socmap_adf/modules/minimap/templates/tooltip.jst.eco +1 -0
  74. data/lib/assets/javascripts/socmap_adf/modules/minimap/views/main.js.coffee +68 -0
  75. data/lib/assets/javascripts/socmap_adf/modules/minimap/views/moving_pin.js.coffee +55 -0
  76. data/lib/assets/javascripts/socmap_adf/modules/minimap/views/tooltip.js.coffee +47 -0
  77. data/lib/assets/javascripts/socmap_adf/modules/mvc/init.js.coffee +6 -0
  78. data/lib/assets/javascripts/socmap_adf/modules/mvc/views/base.js.coffee +5 -0
  79. data/lib/assets/javascripts/socmap_adf/modules/overlay/.DS_Store +0 -0
  80. data/lib/assets/javascripts/socmap_adf/modules/overlay/init.js.coffee +10 -0
  81. data/lib/assets/javascripts/socmap_adf/modules/overlay/models/overlay.js.coffee +4 -0
  82. data/lib/assets/javascripts/socmap_adf/modules/overlay/templates/main.jst.eco +1 -0
  83. data/lib/assets/javascripts/socmap_adf/modules/overlay/templates/polygon_label.jst.eco +1 -0
  84. data/lib/assets/javascripts/socmap_adf/modules/overlay/views/.DS_Store +0 -0
  85. data/lib/assets/javascripts/socmap_adf/modules/overlay/views/main.js.coffee +6 -0
  86. data/lib/assets/javascripts/socmap_adf/modules/overlay/views/overlay.js.coffee +55 -0
  87. data/lib/assets/javascripts/socmap_adf/modules/overlay/views/polygon_label.js.coffee +17 -0
  88. data/lib/assets/javascripts/socmap_adf/modules/overlay_push/init.js.coffee +8 -0
  89. data/lib/assets/javascripts/socmap_adf/modules/overlay_push/templates/colibration.jst.eco +4 -0
  90. data/lib/assets/javascripts/socmap_adf/modules/overlay_push/views/new.js.coffee +32 -0
  91. data/lib/assets/javascripts/socmap_adf/modules/popup/init.js.coffee +7 -0
  92. data/lib/assets/javascripts/socmap_adf/modules/popup/templates/base.jst.eco +5 -0
  93. data/lib/assets/javascripts/socmap_adf/modules/popup/templates/basic.jst.eco +5 -0
  94. data/lib/assets/javascripts/socmap_adf/modules/popup/views/base.js.coffee +98 -0
  95. data/lib/assets/javascripts/socmap_adf/modules/popup/views/basic.js.coffee +86 -0
  96. data/lib/assets/javascripts/socmap_adf/modules/sidebar/collections/empty +0 -0
  97. data/lib/assets/javascripts/socmap_adf/modules/sidebar/init.js.coffee +11 -0
  98. data/lib/assets/javascripts/socmap_adf/modules/sidebar/models/slice.js.coffee +0 -0
  99. data/lib/assets/javascripts/socmap_adf/modules/sidebar/templates/bottomlink.jst.eco +1 -0
  100. data/lib/assets/javascripts/socmap_adf/modules/sidebar/templates/bottomlinkaction.jst.eco +2 -0
  101. data/lib/assets/javascripts/socmap_adf/modules/sidebar/templates/content.jst.eco +2 -0
  102. data/lib/assets/javascripts/socmap_adf/modules/sidebar/templates/sidebar.jst.eco +3 -0
  103. data/lib/assets/javascripts/socmap_adf/modules/sidebar/templates/tab.jst.eco +3 -0
  104. data/lib/assets/javascripts/socmap_adf/modules/sidebar/templates/tabs.jst.eco +3 -0
  105. data/lib/assets/javascripts/socmap_adf/modules/sidebar/views/bottomlink.js.coffee +41 -0
  106. data/lib/assets/javascripts/socmap_adf/modules/sidebar/views/content.js.coffee +63 -0
  107. data/lib/assets/javascripts/socmap_adf/modules/sidebar/views/sidebar.js.coffee +163 -0
  108. data/lib/assets/javascripts/socmap_adf/modules/sidebar/views/tab.js.coffee +52 -0
  109. data/lib/assets/javascripts/socmap_adf/modules/sidebar/views/tabcontent.js.coffee +23 -0
  110. data/lib/assets/javascripts/socmap_adf/modules/sidebar/views/tabs.js.coffee +63 -0
  111. data/lib/assets/javascripts/socmap_adf/modules/zone/collections/points.js.coffee +1 -0
  112. data/lib/assets/javascripts/socmap_adf/modules/zone/collections/zones.js.coffee +2 -0
  113. data/lib/assets/javascripts/socmap_adf/modules/zone/init.js.coffee +11 -0
  114. data/lib/assets/javascripts/socmap_adf/modules/zone/models/polygon.js.coffee +72 -0
  115. data/lib/assets/javascripts/socmap_adf/modules/zone/templates/main.jst.eco +0 -0
  116. data/lib/assets/javascripts/socmap_adf/modules/zone/views/main.js.coffee +6 -0
  117. data/lib/assets/javascripts/socmap_adf/modules/zone/views/test.js.coffee +17 -0
  118. data/lib/assets/javascripts/socmap_adf/requiress.js.coffee.erb +3 -0
  119. data/lib/generators/install_generator.rb +15 -0
  120. data/lib/generators/templates/socmap.rb.erb +9 -0
  121. data/lib/socmap_adf/engine.rb +5 -0
  122. data/lib/socmap_adf/version.rb +3 -0
  123. data/lib/socmap_adf.rb +17 -0
  124. data/lib/tasks/socmap-adf_tasks.rake +4 -0
  125. data/socmap_adf.gemspec +26 -0
  126. data/test/socmap-adf_test.rb +7 -0
  127. data/test/test_helper.rb +15 -0
  128. metadata +202 -0
@@ -0,0 +1,3769 @@
1
+ /********* Source File: src/elycharts_defaults.js*********/
2
+ /*!*********************************************************************
3
+ * ELYCHARTS v2.1.4-SNAPSHOT $Id: elycharts.js 52 2011-08-07 19:57:09Z stefano.bagnara@gmail.com $
4
+ * A Javascript library to generate interactive charts with vectorial graphics.
5
+ *
6
+ * Copyright (c) 2010 Void Labs s.n.c. (http://void.it)
7
+ * Licensed under the MIT (http://creativecommons.org/licenses/MIT/) license.
8
+ **********************************************************************/
9
+
10
+ (function($) {
11
+ if (!$.elycharts)
12
+ $.elycharts = {};
13
+
14
+ /***********************************************************************
15
+ * DEFAULT OPTIONS
16
+ **********************************************************************/
17
+
18
+ $.elycharts.templates = {
19
+
20
+ common : {
21
+ // Tipo di grafico
22
+ // type : 'line|pie|funnel|barline'
23
+
24
+ // Permette di specificare una configurazione di default da utilizzare (definita in $.elycharts.templates.NOME)
25
+ // La configurazione completa � quindi data da tutti i valori della conf di default alla quale viene unita (con sovrascrittura) la conf corrente
26
+ // Il parametro � ricorsivo (la configurazione di default puo' a sua volta avere una configurazione di default)
27
+ // Se non specificato, la configurazione di default � quella con lo stesso nome del tipo di grafico
28
+ // template : 'NOME',
29
+
30
+ /* DATI:
31
+ // I valori associati a ogni serie del grafico. Ogni serie � associata a una chiave dell'oggetto value, il cui
32
+ // valore � l'array di dati relativi
33
+ values : {},
34
+
35
+ // Label associate ai valori del grafico
36
+ // Solo in caso di label gestite da labelmanager (quindi per pie e funnel) e per label.html = true e' possibile inserire
37
+ // degli elementi DOM/JQUERY che verranno presi e posizionati correttament.
38
+ labels : [],
39
+
40
+ // Anchor per la gestione mediante anchormanager. Possono essere stringhe e oggetti DOM/JQUERY che verranno riposizionati
41
+ anchors : {},
42
+
43
+ tooltips : {},
44
+
45
+ legend : [],
46
+ */
47
+
48
+ // Per impostare una dimensione diversa da quella del container settare width e height
49
+ //width : x,
50
+ //height : y
51
+
52
+ // I margini del grafico rispetto al frame complessivo. Da notare che riguardano la posizione del grafico
53
+ // principale, e NON degli elementi aggiuntivi (legenda, label e titoli degli assi...). Quindi i margini devono
54
+ // essere impostati in genere proprio per lasciare lo spazio per questi elementi
55
+ // Sintassi: [top, right, bottom, left]
56
+ margins: [10, 10, 10, 10],
57
+
58
+ // style : {},
59
+
60
+ // Per gestire al meglio l'interattivita' del grafico (tooltip, highlight, anchor...) viene inserito un secondo
61
+ // layer per le parti sensibili al mouse. Se si sa che il grafico non avra' alcuna interattivita' si puo' impostare
62
+ // questo valore a false per evitare di creare il layer (ottimizzando leggermente la pagina)
63
+ interactive : true,
64
+
65
+ // Dati da applicare a tutte le serie del grafico
66
+ defaultSeries : {
67
+ // Impostare a false per disabilitare la visualizzazione della serie
68
+ visible : true,
69
+
70
+ // Impostare color qui permette di impostare velocemente plotProps.stroke+fill, tooltip.frameProps.stroke, dotProps.stroke e fillProps.fill (se non specificati)
71
+ //color: 'blue',
72
+
73
+ //plotProps : { },
74
+
75
+ // Impostazioni dei tooltip
76
+ tooltip : {
77
+ active : true,
78
+ // Se width ed height vengono impostati a 0 o ad "auto" (equivalenti) non vengono fissate dimensioni, quindi il contenuto si autodimensiona in funzione del tooltip
79
+ // Impostare a 0|auto � incompatibile con il frame SVG, quindi viene automaticamente disabilitato (come se frameProps = false)
80
+ width: 100, height: 50,
81
+ roundedCorners: 5,
82
+ padding: [6, 6] /* y, x */,
83
+ offset: [20, 0] /* y, x */,
84
+ // Se frameProps = false non disegna la cornice del tooltip (ad es. per permettere di definire la propria cornice HTML)
85
+ frameProps : { fill: "white", "stroke-width": 2 },
86
+ contentStyle : { "font-family": "Arial", "font-size": "12px", "line-height": "16px", color: "black" }
87
+ },
88
+
89
+ // Highlight feature
90
+ highlight : {
91
+ // Cambia le dimensioni dell'elemento quando deve essere evidenziato
92
+ //scale : [x, y],
93
+ // Opzioni di animazione effetto "scale"
94
+ scaleSpeed : 100, scaleEasing : '',
95
+ // Cambia gli attributi dell'elemento quando evidenziato
96
+ //newProps : { opacity : 1 },
97
+ // Inserisce un layer con gli attributi specificati sopra quello da evidenziare
98
+ //overlayProps : {"fill" : "white", "fill-opacity" : .3, "stroke-width" : 0}
99
+ // Muove l'area evidenziata. E' possibile specificare un valore X o un array [X, Y]
100
+ //move : 10,
101
+ // Opzioni di animazione effetto "move"
102
+ moveSpeed : 100, moveEasing : '',
103
+ // Opzioni di animazione da usare per riportare l'oggetto alle situazione iniziale
104
+ restoreSpeed : 0, restoreEasing : ''
105
+ },
106
+
107
+ anchor : {
108
+ // Aggiunge alle anchor esterne la classe selezionata quando il mouse passa sull'area
109
+ //addClass : "",
110
+ // Evidenzia la serie al passaggio del mouse
111
+ //highlight : "",
112
+ // Se impostato a true usa gli eventi mouseenter/mouseleave invece di mouseover/mouseout per l'highlight
113
+ //useMouseEnter : false,
114
+ },
115
+
116
+ // Opzioni per la generazione animata dei grafici
117
+ startAnimation : {
118
+ //active : true,
119
+ type : 'simple',
120
+ speed : 600,
121
+ delay : 0,
122
+ propsFrom : {}, // applicate a tutte le props di plot
123
+ propsTo : {}, // applicate a tutte le props di plot
124
+ easing : '' // easing raphael: >, <, <>, backIn, backOut, bounce, elastic
125
+
126
+ // Opzionale per alcune animazioni, permette di specificare un sotto-tipo
127
+ // subType : 0|1|2
128
+ },
129
+
130
+ // Opzioni per le transizioni dei grafici durante un cambiamento di configurazione
131
+ /* stepAnimation : {
132
+ speed : 600,
133
+ delay : 0,
134
+ easing : '' // easing raphael: >, <, <>, backIn, backOut, bounce, elastic
135
+ },*/
136
+
137
+ label : {
138
+ // Disegna o meno la label interna al grafico
139
+ active : false,
140
+ // Imposta un offset [X,Y] per la label (le coordinate sono relative al sistema di assi dello specifico settore disegnato.
141
+ // Ad es. per il piechart la X � la distanza dal centro, la Y lo spostamento ortogonale
142
+ //offset : [x, y],
143
+ html : false,
144
+ // Proprieta' della label (per HTML = false)
145
+ props : { fill: 'black', stroke: "none", "font-family": 'Arial', "font-size": "16px" },
146
+ // Stile CSS della label (per HTML = true)
147
+ style : { cursor : 'default' }
148
+ // Posizionamento della label rispetto al punto centrale (+offset) identificato
149
+ //frameAnchor : ['start|middle|end', 'top|middle|bottom']
150
+ }
151
+
152
+ /*legend : {
153
+ dotType : 'rect',
154
+ dotWidth : 10, dotHeight : 10, dotR : 4,
155
+ dotProps : { },
156
+ textProps : { font: '12px Arial', fill: "#000" }
157
+ }*/
158
+ },
159
+
160
+ series : {
161
+ // Serie specifica usata quando ci sono "dati vuoti" (ad esempio quando un piechart e' a 0)
162
+ empty : {
163
+ //plotProps : { fill : "#D0D0D0" },
164
+ label : { active : false },
165
+ tooltip : { active : false }
166
+ }
167
+ /*root : {
168
+ values : []
169
+ }*/
170
+ },
171
+
172
+ features : {
173
+ tooltip : {
174
+ // Imposta una posizione fissa per tutti i tooltip
175
+ //fixedPos : [ x, y]
176
+ // Velocita' del fade
177
+ fadeDelay : 100,
178
+ // Velocita' dello spostamento del tip da un'area all'altra
179
+ moveDelay : 300
180
+ // E' possibile specificare una funzione che filtra le coordinate del tooltip prima di mostrarlo, permettendo di modificarle
181
+ // Nota: le coordinate del mouse sono in mouseAreaData.event.pageX/pageY, e nel caso va ritornato [mouseAreaData.event.pageX, mouseAreaData.event.pageY, true] per indicare che il sistema e' relativo alla pagina)
182
+ //positionHandler : function(env, tooltipConf, mouseAreaData, suggestedX, suggestedY) { return [suggestedX, suggestedY] }
183
+ },
184
+ mousearea : {
185
+ // 'single' le aree sensibili sono relative a ogni valore di ogni serie, se 'index' il mouse attiva tutte le serie per un indice
186
+ type : 'single',
187
+ // In caso di type = 'index', indica se le aree si basano sulle barre ('bar') o sui punti di una linea ('line'). Specificare 'auto' per scegliere automaticamente
188
+ indexCenter : 'auto',
189
+ // Quanto tempo puo' passare nel passaggio da un'area all'altra per considerarlo uno spostamento di puntatore
190
+ areaMoveDelay : 500,
191
+ // Se diversi chart specificano lo stesso syncTag quando si attiva l'area di uno si disattivano quelle degli altri
192
+ syncTag: false,
193
+ // Callback for mouse actions. Parameters passed: (env, serie, index, mouseAreaData)
194
+ onMouseEnter : false,
195
+ onMouseExit : false,
196
+ onMouseChanged : false,
197
+ onMouseOver : false,
198
+ onMouseOut : false
199
+ },
200
+ highlight : {
201
+ // Evidenzia tutto l'indice con una barra ("bar"), una linea ("line") o una linea centrata sulle barre ("barline"). Se "auto" decide in autonomia tra bar e line
202
+ //indexHighlight : 'barline',
203
+ indexHighlightProps : { opacity : 1 /*fill : 'yellow', opacity : .3, scale : ".5 1"*/ }
204
+ },
205
+ animation : {
206
+ // Valore di default per la generazione animata degli elementi del grafico (anche per le non-serie: label, grid...)
207
+ startAnimation : {
208
+ //active : true,
209
+ //propsFrom : {}, // applicate a tutte le props di plot
210
+ //propsTo : {}, // applicate a tutte le props di plot
211
+ speed : 600,
212
+ delay : 0,
213
+ easing : '' // easing raphael: >, <, <>, backIn, backOut, bounce, elastic
214
+ },
215
+ // Valore di default per la transizione animata degli elementi del grafico (anche per le non-serie: label, grid...)
216
+ stepAnimation : {
217
+ speed : 600,
218
+ delay : 0,
219
+ easing : '' // easing raphael: >, <, <>, backIn, backOut, bounce, elastic
220
+ }
221
+ },
222
+ frameAnimation : {
223
+ active : false,
224
+ cssFrom : { opacity : 0},
225
+ cssTo : { opacity: 1 },
226
+ speed : 'slow',
227
+ easing : 'linear' // easing jQuery: 'linear' o 'swing'
228
+ },
229
+ pixelWorkAround : {
230
+ active : true
231
+ },
232
+ label : {},
233
+ shadows : {
234
+ active : false,
235
+ offset : [2, 2], // Per attivare l'ombra, [y, x]
236
+ props : {"stroke-width": 0, "stroke-opacity": 0, "fill": "black", "fill-opacity": .3}
237
+ },
238
+ // BALLOONS: Applicabile solo al funnel (per ora)
239
+ balloons : {
240
+ active : false,
241
+ // Width: se non specificato e' automatico
242
+ //width : 200,
243
+ // Height: se non specificato e' automatico
244
+ //height : 50,
245
+ // Lo stile CSS da applicare a ogni balloon
246
+ style : { },
247
+ // Padding
248
+ padding : [ 5, 5 ],
249
+ // La distanza dal bordo sinistro
250
+ left : 10,
251
+ // Percorso della linea: [ [ x, y iniziali (rispetto al punto di inizio standard)], ... [x, y intermedi (rispetto al punto di inizio standard)] ..., [x, y finale (rispetto all'angolo del balloon pi� vicino al punto di inizio)] ]
252
+ line : [ [ 0, 0 ], [0, 0] ],
253
+ // Propriet� della linea
254
+ lineProps : { }
255
+ },
256
+ legend : {
257
+ horizontal : false,
258
+ x : 'auto', // X | auto, (auto solo per horizontal = true)
259
+ y : 10,
260
+ width : 'auto', // X | auto, (auto solo per horizontal = true)
261
+ height : 20,
262
+ itemWidth : "fixed", // fixed | auto, solo per horizontal = true
263
+ margins : [0, 0, 0, 0],
264
+ dotMargins : [10, 5], // sx, dx
265
+ borderProps : { fill : "white", stroke : "black", "stroke-width" : 1 },
266
+ dotType : 'rect',
267
+ dotWidth : 10, dotHeight : 10, dotR : 4,
268
+ dotProps : { type : "rect", width : 10, height : 10 },
269
+ textProps : { font: '12px Arial', fill: "#000" }
270
+ },
271
+ debug : {
272
+ active : false
273
+ }
274
+ },
275
+
276
+ nop : 0
277
+ },
278
+
279
+ line : {
280
+ template : 'common',
281
+
282
+ barMargins : 0,
283
+
284
+ // Axis
285
+ defaultAxis : {
286
+ // [non per asse x] Normalizza il valore massimo dell'asse in modo che tutte le label abbiamo al massimo N cifre significative
287
+ // (Es: se il max e' 135 e normalize = 2 verra' impostato il max a 140, ma se il numero di label in y e' 3 verr� impostato 150)
288
+ normalize: 2,
289
+ // Permette di impostare i valori minimi e massimi di asse (invece di autorilevarli)
290
+ min: 0, //max: x,
291
+ // Imposta un testo da usare come prefisso e suffisso delle label
292
+ //prefix : "", suffix : "",
293
+ // Visualizza o meno le label dell'asse
294
+ labels: false,
295
+ // Distanza tra le label e l'asse relativo
296
+ labelsDistance: 8,
297
+ // [solo asse x] Rotazione (in gradi) delle label. Se specificato ignora i valori di labelsAnchor e labelsProps['text-anchor']
298
+ labelsRotate: 0,
299
+ // Proprieta' grafiche delle label
300
+ labelsProps : {font: '10px Arial', fill: "#000"},
301
+ // Compatta il numero mostrato nella label usando i suffissi specificati per migliaia, milioni...
302
+ //labelsCompactUnits : ['k', 'M'],
303
+ // Permette di specificare una funzione esterna che si occupa di formattare (o in generale trasformare) la label
304
+ //labelsFormatHandler : function (label) { return label },
305
+ // Salta le prime N label
306
+ //labelsSkip : 0,
307
+ // Force alignment for the label. Auto will automatically center it for x axis (also considering labelsRotate), "end" for l axis, "start" for the right axis.
308
+ //labelsAnchor : "auto"
309
+ // [solo asse x] Force an alternative position for the X axis labels. Auto will automatically choose the right position depending on "labelsCenter", the type of charts (bars vs lines), and labelsRotate.
310
+ //labelsPos : "auto",
311
+ // Automatically hide labels that would overlap previous labels.
312
+ //labelsHideCovered : true,
313
+ // Inserisce un margine alla label (a sinistra se in asse x, in alto se in altri assi)
314
+ //labelsMargin: 10,
315
+ // [solo asse x] If labelsHideCovered = true, make sure each label have at least this space before the next one.
316
+ //labelsMarginRight: 0,
317
+ // Distanza del titolo dall'asse
318
+ titleDistance : 25, titleDistanceIE : .75,
319
+ // Proprieta' grafiche del titolo
320
+ titleProps : {font: '12px Arial', fill: "#000", "font-weight": "bold"}
321
+ },
322
+ axis : {
323
+ x : { titleDistanceIE : 1.2 }
324
+ },
325
+
326
+ defaultSeries : {
327
+ // Tipo di serie, puo' essere 'line' o 'bar'
328
+ type : 'line',
329
+ // L'asse di riferimento della serie. Gli assi "l" ed "r" sono i 2 assi visibili destro e sinistro.
330
+ // E' possibile inserire anche un asse arbitrario (che non sar� visibile)
331
+ axis : 'l',
332
+ // Specificare cumulative = true se i valori inseriti per la serie sono cumulativi
333
+ cumulative : false,
334
+ // In caso di type="line" indica l'arrotondamento della linea
335
+ rounded : 1,
336
+ // Mette il punto di intersezione al centro dell'intervallo invece che al limite (per allineamento con bars). Se 'auto' decide autonomamente
337
+ lineCenter : 'auto',
338
+ // Permette di impilare le serie (i valori di uno iniziano dove finiscono quelli del precedente) con un altra (purche' dello stesso tipo)
339
+ // Specificare "true" per impilare con la serie visibile precedente, oppure il nome della serie sulla quale impilare
340
+ // stacked : false,
341
+
342
+ plotProps : {"stroke-width": 1, "stroke-linejoin": "round"},
343
+
344
+ barWidthPerc: 100,
345
+ //DELETED: barProps : {"width-perc" : 100, "stroke-width": 1, "fill-opacity" : .3},
346
+
347
+ // Attiva o disattiva il riempimento
348
+ fill : false,
349
+ fillProps : {stroke: "none", "stroke-width" : 0, "stroke-opacity": 0, opacity: .3},
350
+
351
+ dot : false,
352
+ dotProps : {size: 4, stroke: "#000", zindex: 5},
353
+ dotShowOnNull : false,
354
+
355
+ mouseareaShowOnNull : false,
356
+
357
+ startAnimation : {
358
+ plotPropsFrom : false,
359
+ // DELETED linePropsFrom : false,
360
+ fillPropsFrom : false,
361
+ dotPropsFrom : false,
362
+ //DELETED barPropsFrom : false,
363
+ shadowPropsFrom : false
364
+ }
365
+
366
+ },
367
+
368
+ features : {
369
+ grid : {
370
+ // N. di divisioni sull'asse X. Se "auto" si basa sulla label da visualizzare. Se "0" imposta draw[vertical] = false
371
+ // Da notare che se "auto" allora la prima e l'ultima linea (bordi) le fa vedere sempre (se ci sono le label). Se invece e' un numero si comporta come ny: fa vedere i bordi solo se forzato con forceBorder
372
+ nx : "auto",
373
+ // N. di divisione sull'asse Y. Se "0" imposta draw[horizontal] = false
374
+ ny : 4,
375
+ // Disegna o meno la griglia. Si puo' specificare un array [horizontal, vertical]
376
+ draw : false,
377
+ // Forza la visualizzazione dei bordi/assi. Se true disegna comunque i bordi (anche se draw = false o se non ci sono label),
378
+ // altrimenti si basa sulle regole standard di draw e presenza label (per asse x)
379
+ // Puo' essere un booleano singolo o un array di bordi [up, dx, down, sx]
380
+ forceBorder : false,
381
+ // Proprieta' di visualizzazione griglia
382
+ props : {stroke: '#e0e0e0', "stroke-width": 1},
383
+ // Dimensioni extra delle rette [up, dx, down, sx]
384
+ extra : [0, 0, 0, 0],
385
+ // Indica se le label (e le rispettive linee del grid) vanno centrate sulle barre (true), quindi tra 2 linee, o sui punti della serie (false), quindi su una sola linea
386
+ // Se specificato "auto" decide in autonomia
387
+ labelsCenter : "auto",
388
+
389
+ // Display a rectangular region with properties specied for every even/odd vertical/horizontal grid division
390
+ evenVProps : false,
391
+ oddVProps : false,
392
+ evenHProps : false,
393
+ oddHProps : false,
394
+
395
+ ticks : {
396
+ // Attiva le barrette sugli assi [x, l, r]
397
+ active : [false, false, false],
398
+ // Dimensioni da prima dell'asse a dopo l'asse
399
+ size : [10, 10],
400
+ // Proprieta' di visualizzazione griglia
401
+ props : {stroke: '#e0e0e0', "stroke-width": 1}
402
+ }
403
+ }
404
+ },
405
+
406
+ nop : 0
407
+ },
408
+
409
+ pie : {
410
+ template : 'common',
411
+
412
+ // Coordinate del centro, se non specificate vengono autodeterminate
413
+ //cx : 0, cy : 0,
414
+ // Raggio della torta, se non specificato viene autodeterminato
415
+ //r : 0
416
+ // Angolo dal quale iniziare a disegnare le fette, in gradi
417
+ startAngle : 0,
418
+ // Disegna la torta con le fette in senso orario (invece dell'orientamento standard per gradi, in senso antiorario)
419
+ clockwise : false,
420
+ // Soglia (rapporto sul totale) entro la quale una fetta non viene visualizzata
421
+ valueThresold : 0.006,
422
+
423
+ defaultSeries : {
424
+ // r: .5, raggio usato solo per questo spicchio, se <=1 e' in rapporto al raggio generale
425
+ // inside: X, inserisce questo spicchio dentro un altro (funziona solo inside: precedente, e non gestisce + spicchi dentro l'altro)
426
+ }
427
+ },
428
+
429
+ funnel : {
430
+ template : 'common',
431
+
432
+ rh: 0, // height of ellipsis (for top and bottom cuts)
433
+ method: 'width', // width/cutarea
434
+ topSector: 0, // height factor of top cylinder
435
+ topSectorProps : { fill: "#d0d0d0" },
436
+ bottomSector: .1, // height factor of bottom cylinder
437
+ bottomSectorProps : { fill: "#d0d0d0" },
438
+ edgeProps : { fill: "#c0c0c0", "stroke-width": 1, opacity: 1 },
439
+
440
+ nop : 0
441
+ },
442
+
443
+ barline : {
444
+ template : 'common',
445
+
446
+ // Imposta il valore massimo per la scala (altrimenti prende il valore + alto)
447
+ // max : X
448
+
449
+ // Impostare direction = rtl per creare un grafico che va da destra a sinistra
450
+ direction : 'ltr'
451
+ }
452
+ }
453
+
454
+ })(jQuery);
455
+ /********* Source File: src/elycharts_core.js*********/
456
+ /**********************************************************************
457
+ * ELYCHARTS
458
+ * A Javascript library to generate interactive charts with vectorial graphics.
459
+ *
460
+ * Copyright (c) 2010 Void Labs s.n.c. (http://void.it)
461
+ * Licensed under the MIT (http://creativecommons.org/licenses/MIT/) license.
462
+ **********************************************************************/
463
+
464
+ (function($) {
465
+ if (!$.elycharts)
466
+ $.elycharts = {};
467
+
468
+ $.elycharts.lastId = 0;
469
+
470
+ /***********************************************************************
471
+ * INITIALIZATION / MAIN CALL
472
+ **********************************************************************/
473
+
474
+ $.fn.chart = function($options) {
475
+ if (!this.length)
476
+ return this;
477
+
478
+ var $env = this.data('elycharts_env');
479
+
480
+ if (typeof $options == "string") {
481
+ if ($options.toLowerCase() == "config")
482
+ return $env ? $env.opt : false;
483
+ if ($options.toLowerCase() == "clear") {
484
+ if ($env) {
485
+ // TODO Bisogna chiamare il destroy delle feature?
486
+ $env.paper.clear();
487
+ this.html("");
488
+ this.data('elycharts_env', false);
489
+ }
490
+ }
491
+ }
492
+ else if (!$env) {
493
+ // First call, initialization
494
+
495
+ if ($options)
496
+ $options = _extendAndNormalizeOptions($options);
497
+
498
+ if (!$options || !$options.type || !$.elycharts.templates[$options.type]) {
499
+ alert('ElyCharts ERROR: chart type is not specified');
500
+ return false;
501
+ }
502
+ $env = _initEnv(this, $options);
503
+
504
+ _processGenericConfig($env, $options);
505
+ $env.pieces = $.elycharts[$env.opt.type].draw($env);
506
+
507
+ this.data('elycharts_env', $env);
508
+
509
+ } else {
510
+ $options = _normalizeOptions($options, $env.opt);
511
+
512
+ // Already initialized
513
+ $env.oldopt = common._clone($env.opt);
514
+ $env.opt = $.extend(true, $env.opt, $options);
515
+ $env.newopt = $options;
516
+
517
+ _processGenericConfig($env, $options);
518
+ $env.pieces = $.elycharts[$env.opt.type].draw($env);
519
+ }
520
+
521
+ return this;
522
+ }
523
+
524
+ /**
525
+ * Must be called only in first call to .chart, to initialize elycharts environment.
526
+ */
527
+ function _initEnv($container, $options) {
528
+ if (!$options.width)
529
+ $options.width = $container.width();
530
+ if (!$options.height)
531
+ $options.height = $container.height();
532
+
533
+ var $env = {
534
+ id : $.elycharts.lastId ++,
535
+ paper : common._RaphaelInstance($container.get()[0], $options.width, $options.height),
536
+ container : $container,
537
+ plots : [],
538
+ opt : $options
539
+ };
540
+
541
+ // Rendering a transparent pixel up-left. Thay way SVG area is well-covered (else the position starts at first real object, and that mess-ups everything)
542
+ $env.paper.rect(0,0,1,1).attr({opacity: 0});
543
+
544
+ $.elycharts[$options.type].init($env);
545
+
546
+ return $env;
547
+ }
548
+
549
+ function _processGenericConfig($env, $options) {
550
+ if ($options.style)
551
+ $env.container.css($options.style);
552
+ }
553
+
554
+ /**
555
+ * Must be called in first call to .chart, to build the full config structure and normalize it.
556
+ */
557
+ function _extendAndNormalizeOptions($options) {
558
+ var k;
559
+ // Compatibility with old $.elysia_charts.default_options and $.elysia_charts.templates
560
+ if ($.elysia_charts) {
561
+ if ($.elysia_charts.default_options)
562
+ for (k in $.elysia_charts.default_options)
563
+ $.elycharts.templates[k] = $.elysia_charts.default_options[k];
564
+ if ($.elysia_charts.templates)
565
+ for (k in $.elysia_charts.templates)
566
+ $.elycharts.templates[k] = $.elysia_charts.templates[k];
567
+ }
568
+
569
+ // TODO Optimize extend cicle
570
+ while ($options.template) {
571
+ var d = $options.template;
572
+ delete $options.template;
573
+ $options = $.extend(true, {}, $.elycharts.templates[d], $options);
574
+ }
575
+ if (!$options.template && $options.type) {
576
+ $options.template = $options.type;
577
+ while ($options.template) {
578
+ d = $options.template;
579
+ delete $options.template;
580
+ $options = $.extend(true, {}, $.elycharts.templates[d], $options);
581
+ }
582
+ }
583
+
584
+ return _normalizeOptions($options, $options);
585
+ }
586
+
587
+ /**
588
+ * Normalize options passed (primarly for backward compatibility)
589
+ */
590
+ function _normalizeOptions($options, $fullopt) {
591
+ if ($options.type == 'pie' || $options.type == 'funnel') {
592
+ if ($options.values && $.isArray($options.values) && !$.isArray($options.values[0]))
593
+ $options.values = { root : $options.values };
594
+ if ($options.tooltips && $.isArray($options.tooltips) && !$.isArray($options.tooltips[0]))
595
+ $options.tooltips = { root : $options.tooltips };
596
+ if ($options.anchors && $.isArray($options.anchors) && !$.isArray($options.anchors[0]))
597
+ $options.anchors = { root : $options.anchors };
598
+ if ($options.balloons && $.isArray($options.balloons) && !$.isArray($options.balloons[0]))
599
+ $options.balloons = { root : $options.balloons };
600
+ if ($options.legend && $.isArray($options.legend) && !$.isArray($options.legend[0]))
601
+ $options.legend = { root : $options.legend };
602
+ }
603
+
604
+ if ($options.defaultSeries) {
605
+ var deftype = $fullopt.type != 'line' ? $fullopt.type : ($options.defaultSeries.type ? $options.defaultSeries.type : ($fullopt.defaultSeries.type ? $fullopt.defaultSeries.type : 'line'));
606
+ _normalizeOptionsColor($options.defaultSeries, deftype, $fullopt);
607
+ if ($options.defaultSeries.stackedWith) {
608
+ $options.defaultSeries.stacked = $options.defaultSeries.stackedWith;
609
+ delete $options.defaultSeries.stackedWith;
610
+ }
611
+ }
612
+
613
+ if ($options.series)
614
+ for (var serie in $options.series) {
615
+ var type = $fullopt.type != 'line' ? $fullopt.type : ($options.series[serie].type ? $options.series[serie].type : ($fullopt.series[serie].type ? $fullopt.series[serie].type : (deftype ? deftype : 'line')));
616
+ _normalizeOptionsColor($options.series[serie], type, $fullopt);
617
+ if ($options.series[serie].values)
618
+ for (var value in $options.series[serie].values)
619
+ _normalizeOptionsColor($options.series[serie].values[value], type, $fullopt);
620
+
621
+ if ($options.series[serie].stackedWith) {
622
+ $options.series[serie].stacked = $options.series[serie].stackedWith;
623
+ delete $options.series[serie].stackedWith;
624
+ }
625
+ }
626
+
627
+ if ($options.type == 'line') {
628
+ if (!$options.features)
629
+ $options.features = {};
630
+ if (!$options.features.grid)
631
+ $options.features.grid = {};
632
+
633
+ if (typeof $options.gridNX != 'undefined') {
634
+ $options.features.grid.nx = $options.gridNX;
635
+ delete $options.gridNX;
636
+ }
637
+ if (typeof $options.gridNY != 'undefined') {
638
+ $options.features.grid.ny = $options.gridNY;
639
+ delete $options.gridNY;
640
+ }
641
+ if (typeof $options.gridProps != 'undefined') {
642
+ $options.features.grid.props = $options.gridProps;
643
+ delete $options.gridProps;
644
+ }
645
+ if (typeof $options.gridExtra != 'undefined') {
646
+ $options.features.grid.extra = $options.gridExtra;
647
+ delete $options.gridExtra;
648
+ }
649
+ if (typeof $options.gridForceBorder != 'undefined') {
650
+ $options.features.grid.forceBorder = $options.gridForceBorder;
651
+ delete $options.gridForceBorder;
652
+ }
653
+
654
+ if ($options.defaultAxis && $options.defaultAxis.normalize && ($options.defaultAxis.normalize == 'auto' || $options.defaultAxis.normalize == 'autony'))
655
+ $options.defaultAxis.normalize = 2;
656
+
657
+ if ($options.axis)
658
+ for (var axis in $options.axis)
659
+ if ($options.axis[axis] && $options.axis[axis].normalize && ($options.axis[axis].normalize == 'auto' || $options.axis[axis].normalize == 'autony'))
660
+ $options.axis[axis].normalize = 2;
661
+ }
662
+
663
+ return $options;
664
+ }
665
+
666
+ /**
667
+ * Manage "color" attribute.
668
+ * @param $section Section part of external conf passed
669
+ * @param $type Type of plot (for line chart can be "line" or "bar", for other types is equal to chart type)
670
+ */
671
+ function _normalizeOptionsColor($section, $type, $fullopt) {
672
+ if ($section.color) {
673
+ var color = $section.color;
674
+
675
+ if (!$section.plotProps)
676
+ $section.plotProps = {};
677
+
678
+ if ($type == 'line') {
679
+ if ($section.plotProps && !$section.plotProps.stroke && !$fullopt.defaultSeries.plotProps.stroke)
680
+ $section.plotProps.stroke = color;
681
+ } else {
682
+ if ($section.plotProps && !$section.plotProps.fill && !$fullopt.defaultSeries.plotProps.fill)
683
+ $section.plotProps.fill = color;
684
+ }
685
+
686
+ if (!$section.tooltip)
687
+ $section.tooltip = {};
688
+ // Is disabled in defaultSetting i should not set color
689
+ if (!$section.tooltip.frameProps && $fullopt.defaultSeries.tooltip.frameProps)
690
+ $section.tooltip.frameProps = {};
691
+ if ($section.tooltip && $section.tooltip.frameProps && !$section.tooltip.frameProps.stroke && !$fullopt.defaultSeries.tooltip.frameProps.stroke)
692
+ $section.tooltip.frameProps.stroke = color;
693
+
694
+ if (!$section.legend)
695
+ $section.legend = {};
696
+ if (!$section.legend.dotProps)
697
+ $section.legend.dotProps = {};
698
+ if ($section.legend.dotProps && !$section.legend.dotProps.fill)
699
+ $section.legend.dotProps.fill = color;
700
+
701
+ if ($type == 'line') {
702
+ if (!$section.dotProps)
703
+ $section.dotProps = {};
704
+ if ($section.dotProps && !$section.dotProps.fill && !$fullopt.defaultSeries.dotProps.fill)
705
+ $section.dotProps.fill = color;
706
+
707
+ if (!$section.fillProps)
708
+ $section.fillProps = {};
709
+ if ($section.fillProps && !$section.fillProps.fill && !$fullopt.defaultSeries.fillProps.fill)
710
+ $section.fillProps.fill = color;
711
+ }
712
+ }
713
+ }
714
+
715
+ /***********************************************************************
716
+ * COMMON
717
+ **********************************************************************/
718
+
719
+ $.elycharts.common = {
720
+ _RaphaelInstance : function(c, w, h) {
721
+ var r = Raphael(c, w, h);
722
+
723
+ r.customAttributes.slice = function (cx, cy, r, rint, aa1, aa2) {
724
+ // Method body is for clockwise angles, but parameters passed are ccw
725
+ a1 = 360 - aa2; a2 = 360 - aa1;
726
+ //a1 = aa1; a2 = aa2;
727
+ var flag = (a2 - a1) > 180;
728
+ a1 = (a1 % 360) * Math.PI / 180;
729
+ a2 = (a2 % 360) * Math.PI / 180;
730
+ // a1 == a2 (but they where different before) means that there is a complete round (eg: 0-360). This should be shown
731
+ if (a1 == a2 && aa1 != aa2)
732
+ a2 += 359.99 * Math.PI / 180;
733
+
734
+ return { path : rint ? [
735
+ ["M", cx + r * Math.cos(a1), cy + r * Math.sin(a1)],
736
+ ["A", r, r, 0, +flag, 1, cx + r * Math.cos(a2), cy + r * Math.sin(a2)],
737
+ ["L", cx + rint * Math.cos(a2), cy + rint * Math.sin(a2)],
738
+ //["L", cx + rint * Math.cos(a1), cy + rint * Math.sin(a1)],
739
+ ["A", rint, rint, 0, +flag, 0, cx + rint * Math.cos(a1), cy + rint * Math.sin(a1)],
740
+ ["z"]
741
+ ] : [
742
+ ["M", cx, cy],
743
+ ["l", r * Math.cos(a1), r * Math.sin(a1)],
744
+ ["A", r, r, 0, +flag, 1, cx + r * Math.cos(a2), cy + r * Math.sin(a2)],
745
+ ["z"]
746
+ ] };
747
+ };
748
+
749
+ return r;
750
+ },
751
+
752
+ _clone : function(obj){
753
+ if(obj == null || typeof(obj) != 'object')
754
+ return obj;
755
+ if (obj.constructor == Array)
756
+ return [].concat(obj);
757
+ var temp = new obj.constructor(); // changed (twice)
758
+ for(var key in obj)
759
+ temp[key] = this._clone(obj[key]);
760
+ return temp;
761
+ },
762
+
763
+ _mergeObjects : function(o1, o2) {
764
+ return $.extend(true, o1, o2);
765
+ /*
766
+ if (typeof o1 == 'undefined')
767
+ return o2;
768
+ if (typeof o2 == 'undefined')
769
+ return o1;
770
+
771
+ for (var idx in o2)
772
+ if (typeof o1[idx] == 'undefined')
773
+ o1[idx] = this._clone(o2[idx]);
774
+ else if (typeof o2[idx] == 'object') {
775
+ if (typeof o1[idx] == 'object')
776
+ o1[idx] = this._mergeObjects(o1[idx], o2[idx]);
777
+ else
778
+ o1[idx] = this._mergeObjects({}, o2[idx]);
779
+ }
780
+ else
781
+ o1[idx] = this._clone(o2[idx]);
782
+ return o1;*/
783
+ },
784
+
785
+ compactUnits : function(val, units) {
786
+ for (var i = units.length - 1; i >= 0; i--) {
787
+ var v = val / Math.pow(1000, i + 1);
788
+ //console.warn(i, units[i], v, v * 10 % 10);
789
+ if (v >= 1 && v * 10 % 10 == 0)
790
+ return v + units[i];
791
+ }
792
+ return val;
793
+ },
794
+
795
+ getElementOriginalAttrs : function(element) {
796
+ var attr = $(element.node).data('original-attr');
797
+ if (!attr) {
798
+ attr = element.attr();
799
+ $(element.node).data('original-attr', attr);
800
+ }
801
+ return attr;
802
+ },
803
+
804
+ findInPieces : function(pieces, section, serie, index, subsection) {
805
+ for (var i = 0; i < pieces.length; i++) {
806
+ if (
807
+ (typeof section == undefined || section == -1 || section == false || pieces[i].section == section) &&
808
+ (typeof serie == undefined || serie == -1 || serie == false || pieces[i].serie == serie) &&
809
+ (typeof index == undefined || index == -1 || index == false || pieces[i].index == index) &&
810
+ (typeof subsection == undefined || subsection == -1 || subsection == false || pieces[i].subSection == subsection)
811
+ )
812
+ return pieces[i];
813
+ }
814
+ return false;
815
+ },
816
+
817
+ samePiecePath : function(piece1, piece2) {
818
+ return (((typeof piece1.section == undefined || piece1.section == -1 || piece1.section == false) && (typeof piece2.section == undefined || piece2.section == -1 || piece2.section == false)) || piece1.section == piece2.section) &&
819
+ (((typeof piece1.serie == undefined || piece1.serie == -1 || piece1.serie == false) && (typeof piece2.serie == undefined || piece2.serie == -1 || piece2.serie == false)) || piece1.serie == piece2.serie) &&
820
+ (((typeof piece1.index == undefined || piece1.index == -1 || piece1.index == false) && (typeof piece2.index == undefined || piece2.index == -1 || piece2.index == false)) || piece1.index == piece2.index) &&
821
+ (((typeof piece1.subSection == undefined || piece1.subSection == -1 || piece1.subSection == false) && (typeof piece2.subSection == undefined || piece2.subSection == -1 || piece2.subSection == false)) || piece1.subSection == piece2.subSection);
822
+ },
823
+
824
+ executeIfChanged : function(env, changes) {
825
+ if (!env.newopt)
826
+ return true;
827
+
828
+ for (var i = 0; i < changes.length; i++) {
829
+ if (changes[i][changes[i].length - 1] == "*") {
830
+ for (var j in env.newopt)
831
+ if (j.substring(0, changes[i].length - 1) + "*" == changes[i])
832
+ return true;
833
+ }
834
+ else if (changes[i] == 'series' && (env.newopt.series || env.newopt.defaultSeries))
835
+ return true;
836
+ else if (changes[i] == 'axis' && (env.newopt.axis || env.newopt.defaultAxis))
837
+ return true;
838
+ else if (changes[i].substring(0, 9) == "features.") {
839
+ changes[i] = changes[i].substring(9);
840
+ if (env.newopt.features && env.newopt.features[changes[i]])
841
+ return true;
842
+ }
843
+ else if (typeof env.newopt[changes[i]] != 'undefined')
844
+ return true;
845
+ }
846
+ return false;
847
+ },
848
+
849
+ /**
850
+ * Ottiene le proprietà di una "Area" definita nella configurazione (options),
851
+ * identificata da section / serie / index / subsection, e facendo il merge
852
+ * di tutti i defaults innestati.
853
+ */
854
+ areaProps : function(env, section, serie, index, subsection) {
855
+ var props;
856
+
857
+ // TODO fare una cache e fix del toLowerCase (devono solo fare la prima lettera
858
+ if (!subsection) {
859
+ if (typeof serie == 'undefined' || !serie)
860
+ props = env.opt[section.toLowerCase()];
861
+
862
+ else {
863
+ props = this._clone(env.opt['default' + section]);
864
+ if (env.opt[section .toLowerCase()] && env.opt[section.toLowerCase()][serie])
865
+ props = this._mergeObjects(props, env.opt[section.toLowerCase()][serie]);
866
+
867
+ if ((typeof index != 'undefined') && index >= 0 && props['values'] && props['values'][index])
868
+ props = this._mergeObjects(props, props['values'][index]);
869
+ }
870
+
871
+ } else {
872
+ props = this._clone(env.opt[subsection.toLowerCase()]);
873
+
874
+ if (typeof serie == 'undefined' || !serie) {
875
+ if (env.opt[section.toLowerCase()] && env.opt[section.toLowerCase()][subsection.toLowerCase()])
876
+ props = this._mergeObjects(props, env.opt[section.toLowerCase()][subsection.toLowerCase()]);
877
+
878
+ } else {
879
+ if (env.opt['default' + section] && env.opt['default' + section][subsection.toLowerCase()])
880
+ props = this._mergeObjects(props, env.opt['default' + section][subsection.toLowerCase()]);
881
+
882
+ if (env.opt[section .toLowerCase()] && env.opt[section.toLowerCase()][serie] && env.opt[section.toLowerCase()][serie][subsection.toLowerCase()])
883
+ props = this._mergeObjects(props, env.opt[section.toLowerCase()][serie][subsection.toLowerCase()]);
884
+
885
+ if (props && (typeof index != 'undefined') && index > 0 && props['values'] && props['values'][index])
886
+ props = this._mergeObjects(props, props['values'][index]);
887
+ }
888
+ }
889
+
890
+ return props;
891
+ },
892
+
893
+ absrectpath : function(x1, y1, x2, y2, r) {
894
+ // TODO Supportare r
895
+ return [['M', x1, y1], ['L', x1, y2], ['L', x2, y2], ['L', x2, y1], ['z']];
896
+ },
897
+
898
+ linepathAnchors : function(p1x, p1y, p2x, p2y, p3x, p3y, rounded) {
899
+ var method = 1;
900
+ if (rounded && rounded.length) {
901
+ method = rounded[1];
902
+ rounded = rounded[0];
903
+ }
904
+ if (!rounded)
905
+ rounded = 1;
906
+ var l1 = (p2x - p1x) / 2,
907
+ l2 = (p3x - p2x) / 2,
908
+ a = Math.atan((p2x - p1x) / Math.abs(p2y - p1y)),
909
+ b = Math.atan((p3x - p2x) / Math.abs(p2y - p3y));
910
+ a = p1y < p2y ? Math.PI - a : a;
911
+ b = p3y < p2y ? Math.PI - b : b;
912
+ if (method == 2) {
913
+ // If added by Bago to avoid curves beyond min or max
914
+ if ((a - Math.PI / 2) * (b - Math.PI / 2) > 0) {
915
+ a = 0;
916
+ b = 0;
917
+ } else {
918
+ if (Math.abs(a - Math.PI / 2) < Math.abs(b - Math.PI / 2))
919
+ b = Math.PI - a;
920
+ else
921
+ a = Math.PI - b;
922
+ }
923
+ }
924
+
925
+ var alpha = Math.PI / 2 - ((a + b) % (Math.PI * 2)) / 2,
926
+ dx1 = l1 * Math.sin(alpha + a) / 2 / rounded,
927
+ dy1 = l1 * Math.cos(alpha + a) / 2 / rounded,
928
+ dx2 = l2 * Math.sin(alpha + b) / 2 / rounded,
929
+ dy2 = l2 * Math.cos(alpha + b) / 2 / rounded;
930
+ return {
931
+ x1: p2x - dx1,
932
+ y1: p2y + dy1,
933
+ x2: p2x + dx2,
934
+ y2: p2y + dy2
935
+ };
936
+ },
937
+
938
+ linepathRevert : function(path) {
939
+ var rev = [], anc = false;
940
+ for (var i = path.length - 1; i >= 0; i--) {
941
+ switch (path[i][0]) {
942
+ case "M" : case "L" :
943
+ if (!anc)
944
+ rev.push( [ rev.length ? "L" : "M", path[i][1], path[i][2] ] );
945
+ else
946
+ rev.push( [ "C", anc[0], anc[1], anc[2], anc[3], path[i][1], path[i][2] ] );
947
+ anc = false;
948
+
949
+ break;
950
+ case "C" :
951
+ if (!anc)
952
+ rev.push( [ rev.length ? "L" : "M", path[i][5], path[i][6] ] );
953
+ else
954
+ rev.push( [ "C", anc[0], anc[1], anc[2], anc[3], path[i][5], path[i][6] ] );
955
+ anc = [ path[i][3], path[i][4], path[i][1], path[i][2] ];
956
+ }
957
+ }
958
+ return rev;
959
+ },
960
+
961
+ linepath : function ( points, rounded ) {
962
+ var path = [];
963
+ if (rounded) {
964
+ var anc = false;
965
+ for (var j = 0, jj = points.length - 1; j < jj ; j++) {
966
+ if (j) {
967
+ var a = this.linepathAnchors(points[j - 1][0], points[j - 1][1], points[j][0], points[j][1], points[j + 1][0], points[j + 1][1], rounded);
968
+ path.push([ "C", anc[0], anc[1], a.x1, a.y1, points[j][0], points[j][1] ]);
969
+ anc = [ a.x2, a.y2 ];
970
+ } else {
971
+ path.push([ "M", points[j][0], points[j][1] ]);
972
+ anc = [ points[j][0], points[j][1] ];
973
+ }
974
+ }
975
+ if (anc)
976
+ path.push([ "C", anc[0], anc[1], points[jj][0], points[jj][1], points[jj][0], points[jj][1] ]);
977
+
978
+ } else
979
+ for (var i = 0; i < points.length; i++) {
980
+ var x = points[i][0], y = points[i][1];
981
+ path.push([i == 0 ? "M" : "L", x, y]);
982
+ }
983
+
984
+ return path;
985
+ },
986
+
987
+ lineareapath : function (points1, points2, rounded) {
988
+ var path = this.linepath(points1, rounded), path2 = this.linepathRevert(this.linepath(points2, rounded));
989
+
990
+ for (var i = 0; i < path2.length; i++)
991
+ path.push( !i ? [ "L", path2[0][1], path2[0][2] ] : path2[i] );
992
+
993
+ if (path.length)
994
+ path.push(['z']);
995
+
996
+ return path;
997
+ },
998
+
999
+ /**
1000
+ * Prende la coordinata X di un passo di un path
1001
+ */
1002
+ getX : function(p, pos) {
1003
+ switch (p[0]) {
1004
+ case 'CIRCLE':
1005
+ return p[1];
1006
+ case 'RECT':
1007
+ return p[!pos ? 1 : 3];
1008
+ case 'SLICE':
1009
+ return p[1];
1010
+ default:
1011
+ return p[p.length - 2];
1012
+ }
1013
+ },
1014
+
1015
+ /**
1016
+ * Prende la coordinata Y di un passo di un path
1017
+ */
1018
+ getY : function(p, pos) {
1019
+ switch (p[0]) {
1020
+ case 'CIRCLE':
1021
+ return p[2];
1022
+ case 'RECT':
1023
+ return p[!pos ? 2 : 4];
1024
+ case 'SLICE':
1025
+ return p[2];
1026
+ default:
1027
+ return p[p.length - 1];
1028
+ }
1029
+ },
1030
+
1031
+ /**
1032
+ * Prende il centro di un path
1033
+ *
1034
+ * @param offset un offset [x,y] da applicare. Da notare che gli assi potrebbero essere dipendenti dalla figura
1035
+ * (ad esempio per lo SLICE x e' l'asse che passa dal centro del cerchio, y l'ortogonale).
1036
+ */
1037
+ getCenter: function(path, offset) {
1038
+ if (!path.path)
1039
+ return false;
1040
+ if (path.path.length == 0)
1041
+ return false;
1042
+ if (!offset)
1043
+ offset = [0, 0];
1044
+
1045
+ if (path.center)
1046
+ return [path.center[0] + offset[0], path.center[1] + offset[1]];
1047
+
1048
+ var p = path.path[0];
1049
+ switch (p[0]) {
1050
+ case 'CIRCLE':
1051
+ return [p[1] + offset[0], p[2] + offset[1]];
1052
+ case 'RECT':
1053
+ return [(p[1] + p[2])/2 + offset[0], (p[3] + p[4])/2 + offset[1]];
1054
+ case 'SLICE':
1055
+ var popangle = p[5] + (p[6] - p[5]) / 2;
1056
+ var rad = Math.PI / 180;
1057
+ return [
1058
+ p[1] + (p[4] + ((p[3] - p[4]) / 2) + offset[0]) * Math.cos(-popangle * rad) + offset[1] * Math.cos((-popangle-90) * rad),
1059
+ p[2] + (p[4] + ((p[3] - p[4]) / 2) + offset[0]) * Math.sin(-popangle * rad) + offset[1] * Math.sin((-popangle-90) * rad)
1060
+ ];
1061
+ }
1062
+
1063
+ // WARN Complex paths not supported
1064
+ alert('ElyCharts: getCenter with complex path not supported');
1065
+
1066
+ return false;
1067
+ },
1068
+
1069
+ /**
1070
+ * Sposta il path passato di un offset [x,y]
1071
+ * Il risultato e' il nuovo path
1072
+ *
1073
+ * @param offset un offset [x,y] da applicare. Da notare che gli assi potrebbero essere dipendenti dalla figura
1074
+ * (ad esempio per lo SLICE x e' l'asse che passa dal centro del cerchio, y l'ortogonale).
1075
+ * @param marginlimit se true non sposta oltre i margini del grafico (applicabile solo su path standard o RECT)
1076
+ * @param simple se true lo spostamento e' sempre fatto sul sistema [x, y] complessivo (altrimenti alcuni elementi, come lo SLICE,
1077
+ * si muovono sul proprio sistema di coordinate - la x muove lungo il raggio e la y lungo l'ortogonale)
1078
+ */
1079
+ movePath : function(env, path, offset, marginlimit, simple) {
1080
+ var p = [], i;
1081
+ if (path.length == 1 && path[0][0] == 'RECT')
1082
+ return [ [path[0][0], this._movePathX(env, path[0][1], offset[0], marginlimit), this._movePathY(env, path[0][2], offset[1], marginlimit), this._movePathX(env, path[0][3], offset[0], marginlimit), this._movePathY(env, path[0][4], offset[1], marginlimit)] ];
1083
+ if (path.length == 1 && path[0][0] == 'SLICE') {
1084
+ if (!simple) {
1085
+ var popangle = path[0][5] + (path[0][6] - path[0][5]) / 2;
1086
+ var rad = Math.PI / 180;
1087
+ var x = path[0][1] + offset[0] * Math.cos(- popangle * rad) + offset[1] * Math.cos((-popangle-90) * rad);
1088
+ var y = path[0][2] + offset[0] * Math.sin(- popangle * rad) + offset[1] * Math.cos((-popangle-90) * rad);
1089
+ return [ [path[0][0], x, y, path[0][3], path[0][4], path[0][5], path[0][6] ] ];
1090
+ }
1091
+ else
1092
+ return [ [ path[0][0], path[0][1] + offset[0], path[0][2] + offset[1], path[0][3], path[0][4], path[0][5], path[0][6] ] ];
1093
+ }
1094
+ if (path.length == 1 && path[0][0] == 'CIRCLE')
1095
+ return [ [ path[0][0], path[0][1] + offset[0], path[0][2] + offset[1], path[0][3] ] ];
1096
+ if (path.length == 1 && path[0][0] == 'TEXT')
1097
+ return [ [ path[0][0], path[0][1], path[0][2] + offset[0], path[0][3] + offset[1] ] ];
1098
+ if (path.length == 1 && path[0][0] == 'LINE') {
1099
+ for (i = 0; i < path[0][1].length; i++)
1100
+ p.push( [ this._movePathX(env, path[0][1][i][0], offset[0], marginlimit), this._movePathY(env, path[0][1][i][1], offset[1], marginlimit) ] );
1101
+ return [ [ path[0][0], p, path[0][2] ] ];
1102
+ }
1103
+ if (path.length == 1 && path[0][0] == 'LINEAREA') {
1104
+ for (i = 0; i < path[0][1].length; i++)
1105
+ p.push( [ this._movePathX(env, path[0][1][i][0], offset[0], marginlimit), this._movePathY(env, path[0][1][i][1], offset[1], marginlimit) ] );
1106
+ var pp = [];
1107
+ for (i = 0; i < path[0][2].length; i++)
1108
+ pp.push( [ this._movePathX(env, path[0][2][i][0], offset[0], marginlimit), this._movePathY(env, path[0][2][i][1], offset[1], marginlimit) ] );
1109
+ return [ [ path[0][0], p, pp, path[0][3] ] ];
1110
+ }
1111
+
1112
+ var newpath = [];
1113
+ // http://www.w3.org/TR/SVG/paths.html#PathData
1114
+ for (var j = 0; j < path.length; j++) {
1115
+ var o = path[j];
1116
+ switch (o[0]) {
1117
+ case 'M': case 'm': case 'L': case 'l': case 'T': case 't':
1118
+ // (x y)+
1119
+ newpath.push([o[0], this._movePathX(env, o[1], offset[0], marginlimit), this._movePathY(env, o[2], offset[1], marginlimit)]);
1120
+ break;
1121
+ case 'A': case 'a':
1122
+ // (rx ry x-axis-rotation large-arc-flag sweep-flag x y)+
1123
+ newpath.push([o[0], o[1], o[2], o[3], o[4], o[5], this._movePathX(env, o[6], offset[0], marginlimit), this._movePathY(env, o[7], offset[1], marginlimit)]);
1124
+ break;
1125
+ case 'C': case 'c':
1126
+ // (x1 y1 x2 y2 x y)+
1127
+ newpath.push([o[0], o[1], o[2], o[3], o[4], this._movePathX(env, o[5], offset[0], marginlimit), this._movePathY(env, o[6], offset[1], marginlimit)]);
1128
+ break;
1129
+ case 'S': case 's': case 'Q': case 'q':
1130
+ // (x1 y1 x y)+
1131
+ newpath.push([o[0], o[1], o[2], this._movePathX(env, o[3], offset[0], marginlimit), this._movePathY(env, o[4], offset[1], marginlimit)]);
1132
+ break;
1133
+ case 'z': case 'Z':
1134
+ newpath.push([o[0]]);
1135
+ break;
1136
+ }
1137
+ }
1138
+
1139
+ return newpath;
1140
+ },
1141
+
1142
+ _movePathX : function(env, x, dx, marginlimit) {
1143
+ if (!marginlimit)
1144
+ return x + dx;
1145
+ x = x + dx;
1146
+ return dx > 0 && x > env.opt.width - env.opt.margins[1] ? env.opt.width - env.opt.margins[1] : (dx < 0 && x < env.opt.margins[3] ? env.opt.margins[3] : x);
1147
+ },
1148
+
1149
+ _movePathY : function(env, y, dy, marginlimit) {
1150
+ if (!marginlimit)
1151
+ return y + dy;
1152
+ y = y + dy;
1153
+ return dy > 0 && y > env.opt.height - env.opt.margins[2] ? env.opt.height - env.opt.margins[2] : (dy < 0 && y < env.opt.margins[0] ? env.opt.margins[0] : y);
1154
+ },
1155
+
1156
+ /**
1157
+ * Ritorna le proprieta SVG da impostare per visualizzare il path non SVG passato (se applicabile, per CIRCLE e TEXT non lo e')
1158
+ */
1159
+ getSVGProps : function(path, prevprops) {
1160
+ var props = prevprops ? prevprops : {};
1161
+ var type = 'path', value;
1162
+
1163
+ if (path.length == 1 && path[0][0] == 'RECT')
1164
+ value = common.absrectpath(path[0][1], path[0][2], path[0][3], path[0][4], path[0][5]);
1165
+ else if (path.length == 1 && path[0][0] == 'SLICE') {
1166
+ type = 'slice';
1167
+ value = [ path[0][1], path[0][2], path[0][3], path[0][4], path[0][5], path[0][6] ];
1168
+ } else if (path.length == 1 && path[0][0] == 'LINE')
1169
+ value = common.linepath( path[0][1], path[0][2] );
1170
+ else if (path.length == 1 && path[0][0] == 'LINEAREA')
1171
+ value = common.lineareapath( path[0][1], path[0][2], path[0][3] );
1172
+ else if (path.length == 1 && (path[0][0] == 'CIRCLE' || path[0][0] == 'TEXT' || path[0][0] == 'DOMELEMENT' || path[0][0] == 'RELEMENT'))
1173
+ return prevprops ? prevprops : false;
1174
+ else
1175
+ value = path;
1176
+
1177
+ if (type != 'path' || (value && value.length > 0))
1178
+ props[type] = value;
1179
+ else if (!prevprops)
1180
+ return false;
1181
+ return props;
1182
+ },
1183
+
1184
+ /**
1185
+ * Disegna il path passato
1186
+ * Gestisce la feature pixelWorkAround
1187
+ */
1188
+ showPath : function(env, path, paper) {
1189
+ path = this.preparePathShow(env, path);
1190
+
1191
+ if (!paper)
1192
+ paper = env.paper;
1193
+ if (path.length == 1 && path[0][0] == 'CIRCLE')
1194
+ return paper.circle(path[0][1], path[0][2], path[0][3]);
1195
+ if (path.length == 1 && path[0][0] == 'TEXT')
1196
+ return paper.text(path[0][2], path[0][3], path[0][1]);
1197
+ var props = this.getSVGProps(path);
1198
+
1199
+ // Props must be with some data in it
1200
+ var hasdata = false;
1201
+ for (var k in props) {
1202
+ hasdata = true;
1203
+ break;
1204
+ }
1205
+
1206
+ return props && hasdata ? paper.path().attr(props) : false;
1207
+ },
1208
+
1209
+ /**
1210
+ * Applica al path le modifiche per poterlo visualizzare
1211
+ * Per ora applica solo pixelWorkAround
1212
+ */
1213
+ preparePathShow : function(env, path) {
1214
+ return env.opt.features.pixelWorkAround.active ? this.movePath(env, this._clone(path), [.5, .5], false, true) : path;
1215
+ },
1216
+
1217
+ /**
1218
+ * Ritorna gli attributi Raphael completi di un piece
1219
+ * Per attributi completi si intende l'insieme di attributi specificato,
1220
+ * assieme a tutti gli attributi calcolati che determinano lo stato
1221
+ * iniziale di un piece (e permettono di farlo ritornare a tale stato).
1222
+ * In genere viene aggiunto il path SVG, per il circle vengono aggiunti
1223
+ * i dati x,y,r
1224
+ */
1225
+ getPieceFullAttr : function(env, piece) {
1226
+ if (!piece.fullattr) {
1227
+ piece.fullattr = this._clone(piece.attr);
1228
+ if (piece.path)
1229
+ switch (piece.path[0][0]) {
1230
+ case 'CIRCLE':
1231
+ var ppath = this.preparePathShow(env, piece.path);
1232
+ piece.fullattr.cx = ppath[0][1];
1233
+ piece.fullattr.cy = ppath[0][2];
1234
+ piece.fullattr.r = ppath[0][3];
1235
+ break;
1236
+ case 'TEXT': case 'DOMELEMENT': case 'RELEMENT':
1237
+ break;
1238
+ default:
1239
+ piece.fullattr = this.getSVGProps(this.preparePathShow(env, piece.path), piece.fullattr);
1240
+ }
1241
+ if (typeof piece.fullattr.opacity == 'undefined')
1242
+ piece.fullattr.opacity = 1;
1243
+ }
1244
+ return piece.fullattr;
1245
+ },
1246
+
1247
+
1248
+ show : function(env, pieces) {
1249
+ pieces = this.getSortedPathData(pieces);
1250
+
1251
+ common.animationStackStart(env);
1252
+
1253
+ var previousElement = false;
1254
+ for (var i = 0; i < pieces.length; i++) {
1255
+ var piece = pieces[i];
1256
+
1257
+ if (typeof piece.show == 'undefined' || piece.show) {
1258
+ // If there is piece.animation.element, this is the old element that must be transformed to the new one
1259
+ piece.element = piece.animation && piece.animation.element ? piece.animation.element : false;
1260
+ piece.hide = false;
1261
+
1262
+ if (!piece.path) {
1263
+ // Element should not be shown or must be hidden: nothing to prepare
1264
+ piece.hide = true;
1265
+
1266
+ } else if (piece.path.length == 1 && piece.path[0][0] == 'TEXT') {
1267
+ // TEXT
1268
+ // Animation is not supported, so if there's an old element i must hide it (with force = true to hide it for sure, even if there's a new version of same element)
1269
+ if (piece.element) {
1270
+ common.animationStackPush(env, piece, piece.element, false, piece.animation.speed, piece.animation.easing, piece.animation.delay, true);
1271
+ piece.animation.element = false;
1272
+ }
1273
+ piece.element = this.showPath(env, piece.path);
1274
+ // If this is a transition i must position new element
1275
+ if (piece.element && env.newopt && previousElement)
1276
+ piece.element.insertAfter(previousElement);
1277
+
1278
+ } else if (piece.path.length == 1 && piece.path[0][0] == 'DOMELEMENT') {
1279
+ // DOMELEMENT
1280
+ // Already shown
1281
+ // Animation not supported
1282
+
1283
+ } else if (piece.path.length == 1 && piece.path[0][0] == 'RELEMENT') {
1284
+ // RAPHAEL ELEMENT
1285
+ // Already shown
1286
+ // Animation is not supported, so if there's an old element i must hide it (with force = true to hide it for sure, even if there's a new version of same element)
1287
+ if (piece.element) {
1288
+ common.animationStackPush(env, piece, piece.element, false, piece.animation.speed, piece.animation.easing, piece.animation.delay, true);
1289
+ piece.animation.element = false;
1290
+ }
1291
+
1292
+ piece.element = piece.path[0][1];
1293
+ if (piece.element && previousElement)
1294
+ piece.element.insertAfter(previousElement);
1295
+ piece.attr = false;
1296
+
1297
+ } else {
1298
+ // OTHERS
1299
+ if (!piece.element) {
1300
+ if (piece.animation && piece.animation.startPath && piece.animation.startPath.length)
1301
+ piece.element = this.showPath(env, piece.animation.startPath);
1302
+ else
1303
+ piece.element = this.showPath(env, piece.path);
1304
+
1305
+ // If this is a transition i must position new element
1306
+ if (piece.element && env.newopt && previousElement)
1307
+ piece.element.insertAfter(previousElement);
1308
+ }
1309
+ }
1310
+
1311
+ if (piece.element) {
1312
+ if (piece.attr) {
1313
+ if (!piece.animation) {
1314
+ // Standard piece visualization
1315
+ if (typeof piece.attr.opacity == 'undefined')
1316
+ piece.attr.opacity = 1;
1317
+ piece.element.attr(piece.attr);
1318
+
1319
+ } else {
1320
+ // Piece animation
1321
+ if (!piece.animation.element)
1322
+ piece.element.attr(piece.animation.startAttr ? piece.animation.startAttr : piece.attr);
1323
+ //if (typeof animationAttr.opacity == 'undefined')
1324
+ // animationAttr.opacity = 1;
1325
+ common.animationStackPush(env, piece, piece.element, this.getPieceFullAttr(env, piece), piece.animation.speed, piece.animation.easing, piece.animation.delay);
1326
+ }
1327
+ } else if (piece.hide)
1328
+ // Hide the piece
1329
+ common.animationStackPush(env, piece, piece.element, false, piece.animation.speed, piece.animation.easing, piece.animation.delay);
1330
+
1331
+ previousElement = piece.element;
1332
+ }
1333
+ }
1334
+ }
1335
+
1336
+ common.animationStackEnd(env);
1337
+ },
1338
+
1339
+ /**
1340
+ * Given an array of pieces, return an array of single pathdata contained in pieces, sorted by zindex
1341
+ */
1342
+ getSortedPathData : function(pieces) {
1343
+ res = [];
1344
+
1345
+ for (var i = 0; i < pieces.length; i++) {
1346
+ var piece = pieces[i];
1347
+ if (piece.paths) {
1348
+ for (var j = 0; j < piece.paths.length; j++) {
1349
+ piece.paths[j].pos = res.length;
1350
+ piece.paths[j].parent = piece;
1351
+ res.push(piece.paths[j]);
1352
+ }
1353
+ } else {
1354
+ piece.pos = res.length;
1355
+ piece.parent = false;
1356
+ res.push(piece);
1357
+ }
1358
+ }
1359
+ return res.sort(function (a, b) {
1360
+ var za = typeof a.attr == 'undefined' || typeof a.attr.zindex == 'undefined' ? ( !a.parent || typeof a.parent.attr == 'undefined' || typeof a.parent.attr.zindex == 'undefined' ? 0 : a.parent.attr.zindex ) : a.attr.zindex;
1361
+ var zb = typeof b.attr == 'undefined' || typeof b.attr.zindex == 'undefined' ? ( !b.parent || typeof b.parent.attr == 'undefined' || typeof b.parent.attr.zindex == 'undefined' ? 0 : b.parent.attr.zindex ) : b.attr.zindex;
1362
+ return za < zb ? -1 : (za > zb ? 1 : (a.pos < b.pos ? -1 : (a.pos > b.pos ? 1 : 0)));
1363
+ });
1364
+ },
1365
+
1366
+ animationStackStart : function(env) {
1367
+ if (!env.animationStackDepth || env.animationStackDepth == 0) {
1368
+ env.animationStackDepth = 0;
1369
+ env.animationStack = {};
1370
+ }
1371
+ env.animationStackDepth ++;
1372
+ },
1373
+
1374
+ animationStackEnd : function(env) {
1375
+ env.animationStackDepth --;
1376
+ if (env.animationStackDepth == 0) {
1377
+ for (var delay in env.animationStack) {
1378
+ this._animationStackAnimate(env.animationStack[delay], delay);
1379
+ delete env.animationStack[delay];
1380
+ }
1381
+ env.animationStack = {};
1382
+ }
1383
+ },
1384
+
1385
+ /**
1386
+ * Inserisce l'animazione richiesta nello stack di animazioni.
1387
+ * Nel caso lo stack non sia inizializzato esegue subito l'animazione.
1388
+ */
1389
+ animationStackPush : function(env, piece, element, newattr, speed, easing, delay, force) {
1390
+ if (typeof delay == 'undefined')
1391
+ delay = 0;
1392
+
1393
+ if (!env.animationStackDepth || env.animationStackDepth == 0) {
1394
+ this._animationStackAnimate([{piece : piece, object : element, props : newattr, speed: speed, easing : easing, force : force}], delay);
1395
+
1396
+ } else {
1397
+ if (!env.animationStack[delay])
1398
+ env.animationStack[delay] = [];
1399
+
1400
+ env.animationStack[delay].push({piece : piece, object : element, props : newattr, speed: speed, easing : easing, force : force});
1401
+ }
1402
+ },
1403
+
1404
+ _animationStackAnimate : function(stack, delay) {
1405
+ var caller = this;
1406
+ var func = function() {
1407
+ var a = stack.pop();
1408
+ caller._animationStackAnimateElement(a);
1409
+
1410
+ while (stack.length > 0) {
1411
+ var b = stack.pop();
1412
+ caller._animationStackAnimateElement(b, a);
1413
+ }
1414
+ }
1415
+ if (delay > 0)
1416
+ setTimeout(func, delay);
1417
+ else
1418
+ func();
1419
+ },
1420
+
1421
+ _animationStackAnimateElement : function (a, awith) {
1422
+ //console.warn('call', a.piece.animationInProgress, a.force, a.piece.path, a.piece);
1423
+
1424
+ if (a.force || !a.piece.animationInProgress) {
1425
+
1426
+ // Metodo non documentato per bloccare l'animazione corrente
1427
+ a.object.stop();
1428
+ if (!a.props)
1429
+ a.props = { opacity : 0 }; // TODO Sarebbe da rimuovere l'elemento alla fine
1430
+
1431
+ if (!a.speed || a.speed <= 0) {
1432
+ //console.warn('direct');
1433
+ a.object.attr(a.props);
1434
+ a.piece.animationInProgress = false;
1435
+ return;
1436
+ }
1437
+
1438
+ a.piece.animationInProgress = true;
1439
+ //console.warn('START', a.piece.animationInProgress, a.piece.path, a.piece);
1440
+
1441
+ // NOTA onEnd non viene chiamato se l'animazione viene bloccata con stop
1442
+ var onEnd = function() {
1443
+ //console.warn('END', a.piece.animationInProgress, a.piece);
1444
+ a.piece.animationInProgress = false
1445
+ }
1446
+
1447
+ if (awith)
1448
+ a.object.animateWith(awith, a.props, a.speed, a.easing ? a.easing : 'linear', onEnd);
1449
+ else
1450
+ a.object.animate(a.props, a.speed, a.easing ? a.easing : 'linear', onEnd);
1451
+ }
1452
+ //else console.warn('SKIP', a.piece.animationInProgress, a.piece.path, a.piece);
1453
+ }
1454
+ }
1455
+
1456
+ var common = $.elycharts.common;
1457
+
1458
+ /***********************************************************************
1459
+ * FEATURESMANAGER
1460
+ **********************************************************************/
1461
+
1462
+ $.elycharts.featuresmanager = {
1463
+
1464
+ managers : [],
1465
+ initialized : false,
1466
+
1467
+ register : function(manager, priority) {
1468
+ $.elycharts.featuresmanager.managers.push([priority, manager]);
1469
+ $.elycharts.featuresmanager.initialized = false;
1470
+ },
1471
+
1472
+ init : function() {
1473
+ $.elycharts.featuresmanager.managers.sort(function(a, b) { return a[0] < b[0] ? -1 : (a[0] == b[0] ? 0 : 1) });
1474
+ $.elycharts.featuresmanager.initialized = true;
1475
+ },
1476
+
1477
+ beforeShow : function(env, pieces) {
1478
+ if (!$.elycharts.featuresmanager.initialized)
1479
+ this.init();
1480
+ for (var i = 0; i < $.elycharts.featuresmanager.managers.length; i++)
1481
+ if ($.elycharts.featuresmanager.managers[i][1].beforeShow)
1482
+ $.elycharts.featuresmanager.managers[i][1].beforeShow(env, pieces);
1483
+ },
1484
+
1485
+ afterShow : function(env, pieces) {
1486
+ if (!$.elycharts.featuresmanager.initialized)
1487
+ this.init();
1488
+ for (var i = 0; i < $.elycharts.featuresmanager.managers.length; i++)
1489
+ if ($.elycharts.featuresmanager.managers[i][1].afterShow)
1490
+ $.elycharts.featuresmanager.managers[i][1].afterShow(env, pieces);
1491
+ },
1492
+
1493
+ onMouseOver : function(env, serie, index, mouseAreaData) {
1494
+ if (!$.elycharts.featuresmanager.initialized)
1495
+ this.init();
1496
+ for (var i = 0; i < $.elycharts.featuresmanager.managers.length; i++)
1497
+ if ($.elycharts.featuresmanager.managers[i][1].onMouseOver)
1498
+ $.elycharts.featuresmanager.managers[i][1].onMouseOver(env, serie, index, mouseAreaData);
1499
+ },
1500
+
1501
+ onMouseOut : function(env, serie, index, mouseAreaData) {
1502
+ if (!$.elycharts.featuresmanager.initialized)
1503
+ this.init();
1504
+ for (var i = 0; i < $.elycharts.featuresmanager.managers.length; i++)
1505
+ if ($.elycharts.featuresmanager.managers[i][1].onMouseOut)
1506
+ $.elycharts.featuresmanager.managers[i][1].onMouseOut(env, serie, index, mouseAreaData);
1507
+ },
1508
+
1509
+ onMouseEnter : function(env, serie, index, mouseAreaData) {
1510
+ if (!$.elycharts.featuresmanager.initialized)
1511
+ this.init();
1512
+ for (var i = 0; i < $.elycharts.featuresmanager.managers.length; i++)
1513
+ if ($.elycharts.featuresmanager.managers[i][1].onMouseEnter)
1514
+ $.elycharts.featuresmanager.managers[i][1].onMouseEnter(env, serie, index, mouseAreaData);
1515
+ },
1516
+
1517
+ onMouseChanged : function(env, serie, index, mouseAreaData) {
1518
+ if (!$.elycharts.featuresmanager.initialized)
1519
+ this.init();
1520
+ for (var i = 0; i < $.elycharts.featuresmanager.managers.length; i++)
1521
+ if ($.elycharts.featuresmanager.managers[i][1].onMouseChanged)
1522
+ $.elycharts.featuresmanager.managers[i][1].onMouseChanged(env, serie, index, mouseAreaData);
1523
+ },
1524
+
1525
+ onMouseExit : function(env, serie, index, mouseAreaData) {
1526
+ if (!$.elycharts.featuresmanager.initialized)
1527
+ this.init();
1528
+ for (var i = 0; i < $.elycharts.featuresmanager.managers.length; i++)
1529
+ if ($.elycharts.featuresmanager.managers[i][1].onMouseExit)
1530
+ $.elycharts.featuresmanager.managers[i][1].onMouseExit(env, serie, index, mouseAreaData);
1531
+ }
1532
+ }
1533
+
1534
+ })(jQuery);
1535
+
1536
+ /***********************************************
1537
+
1538
+ * OGGETTI USATI:
1539
+
1540
+ PIECE:
1541
+ Contiene un elemento da visualizzare nel grafico. E' un oggetto con queste proprietà :
1542
+
1543
+ - section,[serie],[index],[subsection]: Dati che permettono di identificare che tipo
1544
+ di elemento è e a quale blocco della configurazione appartiene.
1545
+ Ad esempio gli elementi principali del chart hanno
1546
+ section="Series", serie=nome della serie, subSection = 'Plot'
1547
+ - [paths]: Contiene un array di pathdata, nel caso questo piece è costituito da
1548
+ piu' sottoelementi (ad esempio i Dots, o gli elementi di un Pie o Funnel)
1549
+ - [PATHDATA.*]: Se questo piece e' costituito da un solo elemento, i suoi dati sono
1550
+ memorizzati direttamente nella root di PIECE.
1551
+ - show: Proprieta' usata internamente per decidere se questo piece dovrà essere
1552
+ visualizzato o meno (in genere nel caso di una transizione che non ha variato
1553
+ questo piece, che quindi puo' essere lasciato allo stato precedente)
1554
+ - hide: Proprieta' usata internamente per decidere se l'elemento va nascosto,
1555
+ usato in caso di transizione se l'elemento non è piu' presente.
1556
+
1557
+ PATHDATA:
1558
+ I dati utili per visualizzare un path nel canvas:
1559
+
1560
+ - PATH: Il path che permette di disegnare l'elemento. Se NULL l'elemento è vuoto/ da
1561
+ non visualizzare (instanziato solo come placeholder)
1562
+ - attr: gli attributi Raphael dell'elemento. NULL se path è NULL.
1563
+ - [center]: centro del path
1564
+ - [rect]: rettangolo che include il path
1565
+
1566
+ PATH:
1567
+ Un array in cui ogni elemento determina un passo del percorso per disegnare il grafico.
1568
+ E' una astrazione sul PATH SVG effettivo, e puo' avere alcuni valori speciali:
1569
+ [ [ 'TEXT', testo, x, y ] ]
1570
+ [ [ 'CIRCLE', x, y, raggio ] ]
1571
+ [ [ 'RECT', x1, y1, x2, y2, rounded ] ] (x1,y1 dovrebbero essere sempre le coordinate in alto a sx)
1572
+ [ [ 'SLICE', x, y, raggio, raggio int, angolo1, angolo2 ] ] (gli angoli sono in gradi)
1573
+ [ [ 'RELEMENT', element ] ] (elemento Raphael gia' disegnato)
1574
+ [ [ 'DOMELEMENT', element ] ] (elemento DOM - in genere un DIV html - già disegnato)
1575
+ [ ... Path SVG ... ]
1576
+
1577
+ ------------------------------------------------------------------------
1578
+
1579
+ Z-INDEX:
1580
+ 0 : base
1581
+ 10 : tooltip
1582
+ 20 : interactive area (tutti gli elementi innescati dalla interactive area dovrebbero essere < 20)
1583
+ 25 : label / balloons (potrebbero essere resi cliccabili dall'esterno, quindi > 20)
1584
+
1585
+ ------------------------------------------------------------------------
1586
+
1587
+ USEFUL RESOURCES:
1588
+
1589
+ http://docs.jquery.com/Plugins/Authoring
1590
+ http://www.learningjquery.com/2007/10/a-plugin-development-pattern
1591
+ http://dean.edwards.name/packer/2/usage/#special-chars
1592
+
1593
+ http://raphaeljs.com/reference.html#attr
1594
+
1595
+ TODO
1596
+ * ottimizzare common.areaProps
1597
+ * rifare la posizione del tooltip del pie
1598
+ * ripristinare shadow
1599
+
1600
+ *********************************************/
1601
+ /********* Source File: src/elycharts_manager_anchor.js*********/
1602
+ /**********************************************************************
1603
+ * ELYCHARTS
1604
+ * A Javascript library to generate interactive charts with vectorial graphics.
1605
+ *
1606
+ * Copyright (c) 2010 Void Labs s.n.c. (http://void.it)
1607
+ * Licensed under the MIT (http://creativecommons.org/licenses/MIT/) license.
1608
+ **********************************************************************/
1609
+
1610
+ (function($) {
1611
+
1612
+ var featuresmanager = $.elycharts.featuresmanager;
1613
+ var common = $.elycharts.common;
1614
+
1615
+ /***********************************************************************
1616
+ * FEATURE: ANCHOR
1617
+ *
1618
+ * Permette di collegare i dati del grafico con delle aree esterne,
1619
+ * identificate dal loro selettore CSS, e di interagire con esse.
1620
+ **********************************************************************/
1621
+
1622
+ $.elycharts.anchormanager = {
1623
+
1624
+ afterShow : function(env, pieces) {
1625
+ // Prendo le aree gestite da mouseAreas, e metto i miei listener
1626
+ // Non c'e' bisogno di gestire il clean per una chiamata successiva, lo fa gia' il mouseareamanager
1627
+ // Tranne per i bind degli eventi jquery
1628
+
1629
+ if (!env.opt.anchors)
1630
+ return;
1631
+
1632
+ if (!env.anchorBinds)
1633
+ env.anchorBinds = [];
1634
+
1635
+ while (env.anchorBinds.length) {
1636
+ var b = env.anchorBinds.pop();
1637
+ $(b[0]).unbind(b[1], b[2]);
1638
+ }
1639
+
1640
+ for (var i = 0; i < env.mouseAreas.length; i++) {
1641
+ var serie = env.mouseAreas[i].piece ? env.mouseAreas[i].piece.serie : false;
1642
+ var anc;
1643
+ if (serie)
1644
+ anc = env.opt.anchors[serie][env.mouseAreas[i].index];
1645
+ else
1646
+ anc = env.opt.anchors[env.mouseAreas[i].index];
1647
+
1648
+ if (anc && env.mouseAreas[i].props.anchor && env.mouseAreas[i].props.anchor.highlight) {
1649
+
1650
+ (function(env, mouseAreaData, anc, caller) {
1651
+
1652
+ var f1 = function() { caller.anchorMouseOver(env, mouseAreaData); };
1653
+ var f2 = function() { caller.anchorMouseOut(env, mouseAreaData); };
1654
+ if (!env.mouseAreas[i].props.anchor.useMouseEnter) {
1655
+ env.anchorBinds.push([anc, 'mouseover', f1]);
1656
+ env.anchorBinds.push([anc, 'mouseout', f2]);
1657
+ $(anc).mouseover(f1);
1658
+ $(anc).mouseout(f2);
1659
+ } else {
1660
+ env.anchorBinds.push([anc, 'mouseenter', f1]);
1661
+ env.anchorBinds.push([anc, 'mouseleave', f2]);
1662
+ $(anc).mouseenter(f1);
1663
+ $(anc).mouseleave(f2);
1664
+ }
1665
+ })(env, env.mouseAreas[i], anc, this);
1666
+ }
1667
+ }
1668
+
1669
+ env.onAnchors = [];
1670
+ },
1671
+
1672
+ anchorMouseOver : function(env, mouseAreaData) {
1673
+ $.elycharts.highlightmanager.onMouseOver(env, mouseAreaData.piece ? mouseAreaData.piece.serie : false, mouseAreaData.index, mouseAreaData);
1674
+ },
1675
+
1676
+ anchorMouseOut : function(env, mouseAreaData) {
1677
+ $.elycharts.highlightmanager.onMouseOut(env, mouseAreaData.piece ? mouseAreaData.piece.serie : false, mouseAreaData.index, mouseAreaData);
1678
+ },
1679
+
1680
+ onMouseOver : function(env, serie, index, mouseAreaData) {
1681
+ if (!env.opt.anchors)
1682
+ return;
1683
+
1684
+ if (mouseAreaData.props.anchor && mouseAreaData.props.anchor.addClass) {
1685
+ //var serie = mouseAreaData.piece ? mouseAreaData.piece.serie : false;
1686
+ var anc;
1687
+ if (serie)
1688
+ anc = env.opt.anchors[serie][mouseAreaData.index];
1689
+ else
1690
+ anc = env.opt.anchors[mouseAreaData.index];
1691
+ if (anc) {
1692
+ $(anc).addClass(mouseAreaData.props.anchor.addClass);
1693
+ env.onAnchors.push([anc, mouseAreaData.props.anchor.addClass]);
1694
+ }
1695
+ }
1696
+ },
1697
+
1698
+ onMouseOut : function(env, serie, index, mouseAreaData) {
1699
+ if (!env.opt.anchors)
1700
+ return;
1701
+
1702
+ while (env.onAnchors.length > 0) {
1703
+ var o = env.onAnchors.pop();
1704
+ $(o[0]).removeClass(o[1]);
1705
+ }
1706
+ }
1707
+ }
1708
+
1709
+ $.elycharts.featuresmanager.register($.elycharts.anchormanager, 30);
1710
+
1711
+ })(jQuery);
1712
+ /********* Source File: src/elycharts_manager_animation.js*********/
1713
+ /**********************************************************************
1714
+ * ELYCHARTS
1715
+ * A Javascript library to generate interactive charts with vectorial graphics.
1716
+ *
1717
+ * Copyright (c) 2010 Void Labs s.n.c. (http://void.it)
1718
+ * Licensed under the MIT (http://creativecommons.org/licenses/MIT/) license.
1719
+ **********************************************************************/
1720
+
1721
+ (function($) {
1722
+
1723
+ //var featuresmanager = $.elycharts.featuresmanager;
1724
+ var common = $.elycharts.common;
1725
+
1726
+ /***********************************************************************
1727
+ * ANIMATIONMANAGER
1728
+ **********************************************************************/
1729
+
1730
+ $.elycharts.animationmanager = {
1731
+
1732
+ beforeShow : function(env, pieces) {
1733
+ if (!env.newopt)
1734
+ this.startAnimation(env, pieces);
1735
+ else
1736
+ this.stepAnimation(env, pieces);
1737
+ },
1738
+
1739
+ stepAnimation : function(env, pieces) {
1740
+ // env.pieces sono i vecchi pieces, ed e' sempre un array completo di tutte le sezioni
1741
+ // pieces sono i nuovi pezzi da mostrare, e potrebbe essere parziale
1742
+ //console.warn('from1', common._clone(env.pieces));
1743
+ //console.warn('from2', common._clone(pieces));
1744
+ pieces = this._stepAnimationInt(env, env.pieces, pieces);
1745
+ //console.warn('to', common._clone(pieces));
1746
+ },
1747
+
1748
+ _stepAnimationInt : function(env, pieces1, pieces2, section, serie, internal) {
1749
+ // Se pieces2 == null deve essere nascosto tutto pieces1
1750
+
1751
+ var newpieces = [], newpiece;
1752
+ var j = 0;
1753
+ for (var i = 0; i < pieces1.length; i ++) {
1754
+ var animationProps = common.areaProps(env, section ? section : pieces1[i].section, serie ? serie : pieces1[i].serie);
1755
+ if (animationProps && animationProps.stepAnimation)
1756
+ animationProps = animationProps.stepAnimation;
1757
+ else
1758
+ animationProps = env.opt.features.animation.stepAnimation;
1759
+
1760
+ // Se il piece attuale c'e' solo in pieces2 lo riporto nei nuovi, impostando come gia' mostrato
1761
+ // A meno che internal = true (siamo in un multipath, nel caso se una cosa non c'e' va considerata da togliere)
1762
+ if (pieces2 && (j >= pieces2.length || !common.samePiecePath(pieces1[i], pieces2[j]))) {
1763
+ if (!internal) {
1764
+ pieces1[i].show = false;
1765
+ newpieces.push(pieces1[i]);
1766
+ } else {
1767
+ newpiece = { path : false, attr : false, show : true };
1768
+ newpiece.animation = {
1769
+ element : pieces1[i].element ? pieces1[i].element : false,
1770
+ speed : animationProps && animationProps.speed ? animationProps.speed : 300,
1771
+ easing : animationProps && animationProps.easing ? animationProps.easing : '',
1772
+ delay : animationProps && animationProps.delay ? animationProps.delay : 0
1773
+ }
1774
+ newpieces.push(newpiece);
1775
+ }
1776
+ }
1777
+ // Bisogna gestire la transizione dal vecchio piece al nuovo
1778
+ else {
1779
+ newpiece = pieces2 ? pieces2[j] : { path : false, attr : false };
1780
+ newpiece.show = true;
1781
+ if (typeof pieces1[i].paths == 'undefined') {
1782
+ // Piece a singolo path
1783
+ newpiece.animation = {
1784
+ element : pieces1[i].element ? pieces1[i].element : false,
1785
+ speed : animationProps && animationProps.speed ? animationProps.speed : 300,
1786
+ easing : animationProps && animationProps.easing ? animationProps.easing : '',
1787
+ delay : animationProps && animationProps.delay ? animationProps.delay : 0
1788
+ }
1789
+ // Se non c'era elemento precedente deve gestire il fadeIn
1790
+ if (!pieces1[i].element)
1791
+ newpiece.animation.startAttr = {opacity : 0};
1792
+
1793
+ } else {
1794
+ // Multiple path piece
1795
+ newpiece.paths = this._stepAnimationInt(env, pieces1[i].paths, pieces2[j].paths, pieces1[i].section, pieces1[i].serie, true);
1796
+ }
1797
+ newpieces.push(newpiece);
1798
+ j++;
1799
+ }
1800
+ }
1801
+ // If there are pieces left in pieces2 i must add them unchanged
1802
+ if (pieces2)
1803
+ for (; j < pieces2.length; j++)
1804
+ newpieces.push(pieces2[j]);
1805
+
1806
+ return newpieces;
1807
+ },
1808
+
1809
+ startAnimation : function(env, pieces) {
1810
+ for (var i = 0; i < pieces.length; i++)
1811
+ if (pieces[i].paths || pieces[i].path) {
1812
+ var props = common.areaProps(env, pieces[i].section, pieces[i].serie);
1813
+ if (props && props.startAnimation)
1814
+ props = props.startAnimation;
1815
+ else
1816
+ props = env.opt.features.animation.startAnimation;
1817
+
1818
+ if (props.active) {
1819
+ if (props.type == 'simple' || pieces[i].section != 'Series')
1820
+ this.animationSimple(env, props, pieces[i]);
1821
+ if (props.type == 'grow')
1822
+ this.animationGrow(env, props, pieces[i]);
1823
+ if (props.type == 'avg')
1824
+ this.animationAvg(env, props, pieces[i]);
1825
+ if (props.type == 'reg')
1826
+ this.animationReg(env, props, pieces[i]);
1827
+ }
1828
+ }
1829
+ },
1830
+
1831
+ /**
1832
+ * Inserisce i dati base di animazione del piece e la transizione di attributi
1833
+ */
1834
+ _animationPiece : function(piece, animationProps, subSection) {
1835
+ if (piece.paths) {
1836
+ for (var i = 0; i < piece.paths.length; i++)
1837
+ this._animationPiece(piece.paths[i], animationProps, subSection);
1838
+ } else if (piece.path) {
1839
+ piece.animation = {
1840
+ speed : animationProps.speed,
1841
+ easing : animationProps.easing,
1842
+ delay : animationProps.delay,
1843
+ startPath : [],
1844
+ startAttr : common._clone(piece.attr)
1845
+ };
1846
+ if (animationProps.propsTo)
1847
+ piece.attr = common._mergeObjects(piece.attr, animationProps.propsTo);
1848
+ if (animationProps.propsFrom)
1849
+ piece.animation.startAttr = common._mergeObjects(piece.animation.startAttr, animationProps.propsFrom);
1850
+ if (subSection && animationProps[subSection.toLowerCase() + 'PropsFrom'])
1851
+ piece.animation.startAttr = common._mergeObjects(piece.animation.startAttr, animationProps[subSection.toLowerCase() + 'PropsFrom']);
1852
+
1853
+ if (typeof piece.animation.startAttr.opacity != 'undefined' && typeof piece.attr.opacity == 'undefined')
1854
+ piece.attr.opacity = 1;
1855
+ }
1856
+ },
1857
+
1858
+ animationSimple : function(env, props, piece) {
1859
+ this._animationPiece(piece, props, piece.subSection);
1860
+ },
1861
+
1862
+ animationGrow : function(env, props, piece) {
1863
+ this._animationPiece(piece, props, piece.subSection);
1864
+ var i, npath, y;
1865
+
1866
+ switch (env.opt.type) {
1867
+ case 'line':
1868
+ y = env.opt.height - env.opt.margins[2];
1869
+ switch (piece.subSection) {
1870
+ case 'Plot':
1871
+ if (!piece.paths) {
1872
+ npath = [ 'LINE', [], piece.path[0][2]];
1873
+ for (i = 0; i < piece.path[0][1].length; i++)
1874
+ npath[1].push([ piece.path[0][1][i][0], y ]);
1875
+ piece.animation.startPath.push(npath);
1876
+
1877
+ } else {
1878
+ for (i = 0; i < piece.paths.length; i++)
1879
+ if (piece.paths[i].path)
1880
+ piece.paths[i].animation.startPath.push([ 'RECT', piece.paths[i].path[0][1], y, piece.paths[i].path[0][3], y ]);
1881
+ }
1882
+ break;
1883
+ case 'Fill':
1884
+ npath = [ 'LINEAREA', [], [], piece.path[0][3]];
1885
+ for (i = 0; i < piece.path[0][1].length; i++) {
1886
+ npath[1].push([ piece.path[0][1][i][0], y ]);
1887
+ npath[2].push([ piece.path[0][2][i][0], y ]);
1888
+ }
1889
+ piece.animation.startPath.push(npath);
1890
+
1891
+ break;
1892
+ case 'Dot':
1893
+ for (i = 0; i < piece.paths.length; i++)
1894
+ if (piece.paths[i].path)
1895
+ piece.paths[i].animation.startPath.push(['CIRCLE', piece.paths[i].path[0][1], y, piece.paths[i].path[0][3]]);
1896
+ break;
1897
+ }
1898
+ break;
1899
+
1900
+ case 'pie':
1901
+ if (piece.subSection == 'Plot')
1902
+ for (i = 0; i < piece.paths.length; i++)
1903
+ if (piece.paths[i].path && piece.paths[i].path[0][0] == 'SLICE')
1904
+ piece.paths[i].animation.startPath.push([ 'SLICE', piece.paths[i].path[0][1], piece.paths[i].path[0][2], piece.paths[i].path[0][4] + piece.paths[i].path[0][3] * 0.1, piece.paths[i].path[0][4], piece.paths[i].path[0][5], piece.paths[i].path[0][6] ]);
1905
+
1906
+ break;
1907
+
1908
+ case 'funnel':
1909
+ alert('Unsupported animation GROW for funnel');
1910
+ break;
1911
+
1912
+ case 'barline':
1913
+ var x;
1914
+ if (piece.section == 'Series' && piece.subSection == 'Plot') {
1915
+ if (!props.subType)
1916
+ x = env.opt.direction != 'rtl' ? env.opt.margins[3] : env.opt.width - env.opt.margins[1];
1917
+ else if (props.subType == 1)
1918
+ x = env.opt.direction != 'rtl' ? env.opt.width - env.opt.margins[1] : env.opt.margins[3];
1919
+ for (i = 0; i < piece.paths.length; i++)
1920
+ if (piece.paths[i].path) {
1921
+ if (!props.subType || props.subType == 1)
1922
+ piece.paths[i].animation.startPath.push([ 'RECT', x, piece.paths[i].path[0][2], x, piece.paths[i].path[0][4], piece.paths[i].path[0][5] ]);
1923
+ else {
1924
+ y = (piece.paths[i].path[0][2] + piece.paths[i].path[0][4]) / 2;
1925
+ piece.paths[i].animation.startPath.push([ 'RECT', piece.paths[i].path[0][1], y, piece.paths[i].path[0][3], y, piece.paths[i].path[0][5] ]);
1926
+ }
1927
+ }
1928
+ }
1929
+
1930
+ break;
1931
+ }
1932
+ },
1933
+
1934
+ _animationAvgXYArray : function(arr) {
1935
+ var res = [], avg = 0, i;
1936
+ for (i = 0; i < arr.length; i++)
1937
+ avg += arr[i][1];
1938
+ avg = avg / arr.length;
1939
+ for (i = 0; i < arr.length; i++)
1940
+ res.push([ arr[i][0], avg ]);
1941
+ return res;
1942
+ },
1943
+
1944
+ animationAvg : function(env, props, piece) {
1945
+ this._animationPiece(piece, props, piece.subSection);
1946
+
1947
+ var avg = 0, i, l;
1948
+ switch (env.opt.type) {
1949
+ case 'line':
1950
+ switch (piece.subSection) {
1951
+ case 'Plot':
1952
+ if (!piece.paths) {
1953
+ // LINE
1954
+ piece.animation.startPath.push([ 'LINE', this._animationAvgXYArray(piece.path[0][1]), piece.path[0][2] ]);
1955
+
1956
+ } else {
1957
+ // BAR
1958
+ l = 0;
1959
+ for (i = 0; i < piece.paths.length; i++)
1960
+ if (piece.paths[i].path) {
1961
+ l ++;
1962
+ avg += piece.paths[i].path[0][2];
1963
+ }
1964
+ avg = avg / l;
1965
+ for (i = 0; i < piece.paths.length; i++)
1966
+ if (piece.paths[i].path)
1967
+ piece.paths[i].animation.startPath.push([ "RECT", piece.paths[i].path[0][1], avg, piece.paths[i].path[0][3], piece.paths[i].path[0][4] ]);
1968
+ }
1969
+ break;
1970
+
1971
+ case 'Fill':
1972
+ piece.animation.startPath.push([ 'LINEAREA', this._animationAvgXYArray(piece.path[0][1]), this._animationAvgXYArray(piece.path[0][2]), piece.path[0][3] ]);
1973
+
1974
+ break;
1975
+
1976
+ case 'Dot':
1977
+ l = 0;
1978
+ for (i = 0; i < piece.paths.length; i++)
1979
+ if (piece.paths[i].path) {
1980
+ l ++;
1981
+ avg += piece.paths[i].path[0][2];
1982
+ }
1983
+ avg = avg / l;
1984
+ for (i = 0; i < piece.paths.length; i++)
1985
+ if (piece.paths[i].path)
1986
+ piece.paths[i].animation.startPath.push(['CIRCLE', piece.paths[i].path[0][1], avg, piece.paths[i].path[0][3]]);
1987
+ break;
1988
+ }
1989
+ break;
1990
+
1991
+ case 'pie':
1992
+ var delta = 360 / piece.paths.length;
1993
+
1994
+ if (piece.subSection == 'Plot')
1995
+ for (i = 0; i < piece.paths.length; i++)
1996
+ if (piece.paths[i].path && piece.paths[i].path[0][0] == 'SLICE')
1997
+ piece.paths[i].animation.startPath.push([ 'SLICE', piece.paths[i].path[0][1], piece.paths[i].path[0][2], piece.paths[i].path[0][3], piece.paths[i].path[0][4], i * delta, (i + 1) * delta ]);
1998
+
1999
+ break;
2000
+
2001
+ case 'funnel':
2002
+ alert('Unsupported animation AVG for funnel');
2003
+ break;
2004
+
2005
+ case 'barline':
2006
+ alert('Unsupported animation AVG for barline');
2007
+ break;
2008
+ }
2009
+ },
2010
+
2011
+ _animationRegXYArray : function(arr) {
2012
+ var res = [];
2013
+ var c = arr.length;
2014
+ var y1 = arr[0][1];
2015
+ var y2 = arr[c - 1][1];
2016
+
2017
+ for (var i = 0; i < arr.length; i++)
2018
+ res.push([arr[i][0], y1 + (y2 - y1) / (c - 1) * i]);
2019
+
2020
+ return res;
2021
+ },
2022
+
2023
+ animationReg : function(env, props, piece) {
2024
+ this._animationPiece(piece, props, piece.subSection);
2025
+ var i, c, y1, y2;
2026
+
2027
+ switch (env.opt.type) {
2028
+ case 'line':
2029
+ switch (piece.subSection) {
2030
+ case 'Plot':
2031
+ if (!piece.paths) {
2032
+ // LINE
2033
+ piece.animation.startPath.push([ 'LINE', this._animationRegXYArray(piece.path[0][1]), piece.path[0][2] ]);
2034
+
2035
+ } else {
2036
+ // BAR
2037
+ c = piece.paths.length;
2038
+ if (c > 1) {
2039
+ for (i = 0; !piece.paths[i].path && i < piece.paths.length; i++) {}
2040
+ y1 = piece.paths[i].path ? common.getY(piece.paths[i].path[0]) : 0;
2041
+ for (i = piece.paths.length - 1; !piece.paths[i].path && i >= 0; i--) {}
2042
+ y2 = piece.paths[i].path ? common.getY(piece.paths[i].path[0]) : 0;
2043
+
2044
+ for (i = 0; i < piece.paths.length; i++)
2045
+ if (piece.paths[i].path)
2046
+ piece.paths[i].animation.startPath.push([ "RECT", piece.paths[i].path[0][1], y1 + (y2 - y1) / (c - 1) * i, piece.paths[i].path[0][3], piece.paths[i].path[0][4] ]);
2047
+ }
2048
+ }
2049
+ break;
2050
+
2051
+ case 'Fill':
2052
+ piece.animation.startPath.push([ 'LINEAREA', this._animationRegXYArray(piece.path[0][1]), this._animationRegXYArray(piece.path[0][2]), piece.path[0][3] ]);
2053
+ break;
2054
+
2055
+ case 'Dot':
2056
+ c = piece.paths.length;
2057
+ if (c > 1) {
2058
+ for (i = 0; !piece.paths[i].path && i < piece.paths.length; i++) {}
2059
+ y1 = piece.paths[i].path ? common.getY(piece.paths[i].path[0]) : 0;
2060
+ for (i = piece.paths.length - 1; !piece.paths[i].path && i >= 0; i--) {}
2061
+ y2 = piece.paths[i].path ? common.getY(piece.paths[i].path[0]) : 0;
2062
+
2063
+ for (i = 0; i < piece.paths.length; i++)
2064
+ if (piece.paths[i].path)
2065
+ piece.paths[i].animation.startPath.push(['CIRCLE', piece.paths[i].path[0][1], y1 + (y2 - y1) / (c - 1) * i, piece.paths[i].path[0][3]]);
2066
+ }
2067
+ break;
2068
+ }
2069
+ break;
2070
+
2071
+ case 'pie':
2072
+ alert('Unsupported animation REG for pie');
2073
+ break;
2074
+
2075
+ case 'funnel':
2076
+ alert('Unsupported animation REG for funnel');
2077
+ break;
2078
+
2079
+ case 'barline':
2080
+ alert('Unsupported animation REG for barline');
2081
+ break;
2082
+ }
2083
+ }
2084
+ }
2085
+
2086
+ $.elycharts.featuresmanager.register($.elycharts.animationmanager, 10);
2087
+
2088
+ /***********************************************************************
2089
+ * FRAMEANIMATIONMANAGER
2090
+ **********************************************************************/
2091
+
2092
+ $.elycharts.frameanimationmanager = {
2093
+
2094
+ beforeShow : function(env, pieces) {
2095
+ if (env.opt.features.frameAnimation.active)
2096
+ $(env.container.get(0)).css(env.opt.features.frameAnimation.cssFrom);
2097
+ },
2098
+
2099
+ afterShow : function(env, pieces) {
2100
+ if (env.opt.features.frameAnimation.active)
2101
+ env.container.animate(env.opt.features.frameAnimation.cssTo, env.opt.features.frameAnimation.speed, env.opt.features.frameAnimation.easing);
2102
+ }
2103
+ };
2104
+
2105
+ $.elycharts.featuresmanager.register($.elycharts.frameanimationmanager, 90);
2106
+
2107
+ })(jQuery);
2108
+ /********* Source File: src/elycharts_manager_highlight.js*********/
2109
+ /**********************************************************************
2110
+ * ELYCHARTS
2111
+ * A Javascript library to generate interactive charts with vectorial graphics.
2112
+ *
2113
+ * Copyright (c) 2010 Void Labs s.n.c. (http://void.it)
2114
+ * Licensed under the MIT (http://creativecommons.org/licenses/MIT/) license.
2115
+ **********************************************************************/
2116
+
2117
+ (function($) {
2118
+
2119
+ //var featuresmanager = $.elycharts.featuresmanager;
2120
+ var common = $.elycharts.common;
2121
+
2122
+ /***********************************************************************
2123
+ * FEATURE: HIGHLIGHT
2124
+ *
2125
+ * Permette di evidenziare in vari modi l'area in cui si passa con il
2126
+ * mouse.
2127
+ **********************************************************************/
2128
+
2129
+ $.elycharts.highlightmanager = {
2130
+
2131
+ removeHighlighted : function(env, full) {
2132
+ if (env.highlighted)
2133
+ while (env.highlighted.length > 0) {
2134
+ var o = env.highlighted.pop();
2135
+ if (o.piece) {
2136
+ if (full)
2137
+ common.animationStackPush(env, o.piece, o.piece.element, common.getPieceFullAttr(env, o.piece), o.cfg.restoreSpeed, o.cfg.restoreEasing, 0, true);
2138
+ } else
2139
+ o.element.remove();
2140
+ }
2141
+ },
2142
+
2143
+ afterShow : function(env, pieces) {
2144
+ if (env.highlighted && env.highlighted.length > 0)
2145
+ this.removeHighlighted(env, false);
2146
+ env.highlighted = [];
2147
+ },
2148
+
2149
+ onMouseOver : function(env, serie, index, mouseAreaData) {
2150
+ var path, element;
2151
+ // TODO Se non e' attivo l'overlay (per la serie o per tutto) e' inutile fare il resto
2152
+
2153
+ // Cerco i piece da evidenziare (tutti quelli che sono costituiti da path multipli)
2154
+ for (var i = 0; i < mouseAreaData.pieces.length; i++)
2155
+
2156
+ // Il loop sotto estrae solo i pieces con array di path (quindi non i line o i fill del linechart ... ma il resto si)
2157
+ if (mouseAreaData.pieces[i].section == 'Series' && mouseAreaData.pieces[i].paths
2158
+ && (!serie || mouseAreaData.pieces[i].serie == serie)
2159
+ && mouseAreaData.pieces[i].paths[index] && mouseAreaData.pieces[i].paths[index].element) {
2160
+ var piece = mouseAreaData.pieces[i].paths[index];
2161
+ element = piece.element;
2162
+ path = piece.path;
2163
+ var attr = common.getElementOriginalAttrs(element);
2164
+ var newattr = false; // In caso la geometria dell'oggetto è modificata mediante attr (es: per circle) qui memorizza i nuovi attributi
2165
+ var props = serie ? mouseAreaData.props : common.areaProps(env, mouseAreaData.pieces[i].section, mouseAreaData.pieces[i].serie);
2166
+ var pelement, ppiece, ppath;
2167
+ if (path && props.highlight) {
2168
+ if (props.highlight.scale) {
2169
+ var scale = props.highlight.scale;
2170
+ if (typeof scale == 'number')
2171
+ scale = [scale, scale];
2172
+
2173
+ if (path[0][0] == 'RECT') {
2174
+ var w = path[0][3] - path[0][1];
2175
+ var h = path[0][4] - path[0][2];
2176
+ path = [ [ 'RECT', path[0][1], path[0][2] - h * (scale[1] - 1), path[0][3] + w * (scale[0] - 1), path[0][4] ] ];
2177
+ common.animationStackPush(env, piece, element, common.getSVGProps(common.preparePathShow(env, path)), props.highlight.scaleSpeed, props.highlight.scaleEasing);
2178
+ }
2179
+ else if (path[0][0] == 'CIRCLE') {
2180
+ // I pass directly new radius
2181
+ newattr = {r : path[0][3] * scale[0]};
2182
+ common.animationStackPush(env, piece, element, newattr, props.highlight.scaleSpeed, props.highlight.scaleEasing);
2183
+ }
2184
+ else if (path[0][0] == 'SLICE') {
2185
+ // Per lo slice x e' il raggio, y e' l'angolo
2186
+ var d = (path[0][6] - path[0][5]) * (scale[1] - 1) / 2;
2187
+ if (d > 90)
2188
+ d = 90;
2189
+ path = [ [ 'SLICE', path[0][1], path[0][1], path[0][3] * scale[0], path[0][4], path[0][5] - d, path[0][6] + d ] ];
2190
+ common.animationStackPush(env, piece, element, common.getSVGProps(common.preparePathShow(env, path)), props.highlight.scaleSpeed, props.highlight.scaleEasing);
2191
+
2192
+ } else if (env.opt.type == 'funnel') {
2193
+ var dx = (piece.rect[2] - piece.rect[0]) * (scale[0] - 1) / 2;
2194
+ var dy = (piece.rect[3] - piece.rect[1]) * (scale[1] - 1) / 2;
2195
+
2196
+ // Specifico di un settore del funnel
2197
+ common.animationStackStart(env);
2198
+ path = [ common.movePath(env, [ path[0]], [-dx, -dy])[0],
2199
+ common.movePath(env, [ path[1]], [+dx, -dy])[0],
2200
+ common.movePath(env, [ path[2]], [+dx, +dy])[0],
2201
+ common.movePath(env, [ path[3]], [-dx, +dy])[0],
2202
+ path[4] ];
2203
+ common.animationStackPush(env, piece, element, common.getSVGProps(common.preparePathShow(env, path)), props.highlight.scaleSpeed, props.highlight.scaleEasing, 0, true);
2204
+
2205
+ // Se c'e' un piece precedente lo usa, altrimenti cerca un topSector per la riduzione
2206
+ pelement = false;
2207
+ if (index > 0) {
2208
+ ppiece = mouseAreaData.pieces[i].paths[index - 1];
2209
+ pelement = ppiece.element;
2210
+ ppath = ppiece.path;
2211
+ } else {
2212
+ ppiece = common.findInPieces(mouseAreaData.pieces, 'Sector', 'top');
2213
+ if (ppiece) {
2214
+ pelement = ppiece.element;
2215
+ ppath = ppiece.path;
2216
+ }
2217
+ }
2218
+ if (pelement) {
2219
+ //pattr = common.getElementOriginalAttrs(pelement);
2220
+ ppath = [
2221
+ ppath[0], ppath[1],
2222
+ common.movePath(env, [ ppath[2]], [+dx, -dy])[0],
2223
+ common.movePath(env, [ ppath[3]], [-dx, -dy])[0],
2224
+ ppath[4] ];
2225
+ common.animationStackPush(env, ppiece, pelement, common.getSVGProps(common.preparePathShow(env, ppath)), props.highlight.scaleSpeed, props.highlight.scaleEasing, 0, true);
2226
+ env.highlighted.push({piece : ppiece, cfg : props.highlight});
2227
+ }
2228
+
2229
+ // Se c'e' un piece successivo lo usa, altrimenti cerca un bottomSector per la riduzione
2230
+ pelement = false;
2231
+ if (index < mouseAreaData.pieces[i].paths.length - 1) {
2232
+ ppiece = mouseAreaData.pieces[i].paths[index + 1];
2233
+ pelement = ppiece.element;
2234
+ ppath = ppiece.path;
2235
+ } else {
2236
+ ppiece = common.findInPieces(mouseAreaData.pieces, 'Sector', 'bottom');
2237
+ if (ppiece) {
2238
+ pelement = ppiece.element;
2239
+ ppath = ppiece.path;
2240
+ }
2241
+ }
2242
+ if (pelement) {
2243
+ //var pattr = common.getElementOriginalAttrs(pelement);
2244
+ ppath = [
2245
+ common.movePath(env, [ ppath[0]], [-dx, +dy])[0],
2246
+ common.movePath(env, [ ppath[1]], [+dx, +dy])[0],
2247
+ ppath[2], ppath[3],
2248
+ ppath[4] ];
2249
+ common.animationStackPush(env, ppiece, pelement, common.getSVGProps(common.preparePathShow(env, ppath)), props.highlight.scaleSpeed, props.highlight.scaleEasing, 0, true);
2250
+ env.highlighted.push({piece : ppiece, cfg : props.highlight});
2251
+ }
2252
+
2253
+ common.animationStackEnd(env);
2254
+ }
2255
+ /* Con scale non va bene
2256
+ if (!attr.scale)
2257
+ attr.scale = [1, 1];
2258
+ element.attr({scale : [scale[0], scale[1]]}); */
2259
+ }
2260
+ if (props.highlight.newProps) {
2261
+ for (var a in props.highlight.newProps)
2262
+ if (typeof attr[a] == 'undefined')
2263
+ attr[a] = false;
2264
+ common.animationStackPush(env, piece, element, props.highlight.newProps);
2265
+ }
2266
+ if (props.highlight.move) {
2267
+ var offset = $.isArray(props.highlight.move) ? props.highlight.move : [props.highlight.move, 0];
2268
+ path = common.movePath(env, path, offset);
2269
+ common.animationStackPush(env, piece, element, common.getSVGProps(common.preparePathShow(env, path)), props.highlight.moveSpeed, props.highlight.moveEasing);
2270
+ }
2271
+
2272
+ //env.highlighted.push({element : element, attr : attr});
2273
+ env.highlighted.push({piece : piece, cfg : props.highlight});
2274
+
2275
+ if (props.highlight.overlayProps) {
2276
+ // NOTA: path e' il path modificato dai precedenti (cosi' l'overlay tiene conto della cosa), deve guardare anche a newattr
2277
+ //BIND: mouseAreaData.listenerDisabled = true;
2278
+ element = common.showPath(env, path);
2279
+ if (newattr)
2280
+ element.attr(newattr);
2281
+ element.attr(props.highlight.overlayProps);
2282
+ //BIND: $(element.node).unbind().mouseover(mouseAreaData.mouseover).mouseout(mouseAreaData.mouseout);
2283
+ // Se metto immediatamente il mouseAreaData.listenerDisabled poi va comunque un mouseout dalla vecchia area e va
2284
+ // in loop. TODO Rivedere e sistemare anche per tooltip
2285
+ //BIND: setTimeout(function() { mouseAreaData.listenerDisabled = false; }, 10);
2286
+ attr = false;
2287
+ env.highlighted.push({element : element, attr : attr, cfg : props.highlight});
2288
+ }
2289
+ }
2290
+ }
2291
+
2292
+ if (env.opt.features.highlight.indexHighlight && env.opt.type == 'line') {
2293
+ var t = env.opt.features.highlight.indexHighlight;
2294
+ if (t == 'auto')
2295
+ t = (env.indexCenter == 'bar' ? 'bar' : 'line');
2296
+
2297
+ var delta1 = (env.opt.width - env.opt.margins[3] - env.opt.margins[1]) / (env.opt.labels.length > 0 ? env.opt.labels.length : 1);
2298
+ var delta2 = (env.opt.width - env.opt.margins[3] - env.opt.margins[1]) / (env.opt.labels.length > 1 ? env.opt.labels.length - 1 : 1);
2299
+ var lineCenter = true;
2300
+
2301
+ switch (t) {
2302
+ case 'bar':
2303
+ path = [ ['RECT', env.opt.margins[3] + index * delta1, env.opt.margins[0] ,
2304
+ env.opt.margins[3] + (index + 1) * delta1, env.opt.height - env.opt.margins[2] ] ];
2305
+ break;
2306
+
2307
+ case 'line':
2308
+ lineCenter = false;
2309
+ case 'barline':
2310
+ var x = Math.round((lineCenter ? delta1 / 2 : 0) + env.opt.margins[3] + index * (lineCenter ? delta1 : delta2));
2311
+ path = [[ 'M', x, env.opt.margins[0]], ['L', x, env.opt.height - env.opt.margins[2]]];
2312
+ }
2313
+ if (path) {
2314
+ //BIND: mouseAreaData.listenerDisabled = true;
2315
+ element = common.showPath(env, path).attr(env.opt.features.highlight.indexHighlightProps);
2316
+ //BIND: $(element.node).unbind().mouseover(mouseAreaData.mouseover).mouseout(mouseAreaData.mouseout);
2317
+ //BIND: setTimeout(function() { mouseAreaData.listenerDisabled = false; }, 10);
2318
+ env.highlighted.push({element : element, attr : false, cfg : env.opt.features.highlight});
2319
+ }
2320
+ }
2321
+ },
2322
+
2323
+ onMouseOut : function(env, serie, index, mouseAreaData) {
2324
+ this.removeHighlighted(env, true);
2325
+ }
2326
+
2327
+ };
2328
+
2329
+ $.elycharts.featuresmanager.register($.elycharts.highlightmanager, 21);
2330
+
2331
+ })(jQuery);
2332
+ /********* Source File: src/elycharts_manager_label.js*********/
2333
+ /**********************************************************************
2334
+ * ELYCHARTS
2335
+ * A Javascript library to generate interactive charts with vectorial graphics.
2336
+ *
2337
+ * Copyright (c) 2010 Void Labs s.n.c. (http://void.it)
2338
+ * Licensed under the MIT (http://creativecommons.org/licenses/MIT/) license.
2339
+ **********************************************************************/
2340
+
2341
+ (function($) {
2342
+
2343
+ //var featuresmanager = $.elycharts.featuresmanager;
2344
+ var common = $.elycharts.common;
2345
+
2346
+ /***********************************************************************
2347
+ * FEATURE: LABELS
2348
+ *
2349
+ * Permette di visualizzare in vari modi le label del grafico.
2350
+ * In particolare per pie e funnel permette la visualizzazione all'interno
2351
+ * delle fette.
2352
+ * Per i line chart le label sono visualizzate già nella gestione assi.
2353
+ *
2354
+ * TODO:
2355
+ * - Comunque per i line chart si potrebbe gestire la visualizzazione
2356
+ * all'interno delle barre, o sopra i punti.
2357
+ **********************************************************************/
2358
+
2359
+ $.elycharts.labelmanager = {
2360
+
2361
+ beforeShow : function(env, pieces) {
2362
+
2363
+ if (!common.executeIfChanged(env, ['labels', 'values', 'series']))
2364
+ return;
2365
+
2366
+ if (env.opt.labels && (env.opt.type == 'pie' || env.opt.type == 'funnel')) {
2367
+ var /*lastSerie = false, */lastIndex = false;
2368
+ var paths;
2369
+
2370
+ for (var i = 0; i < pieces.length; i++) {
2371
+ if (pieces[i].section == 'Series' && pieces[i].subSection == 'Plot') {
2372
+ var props = common.areaProps(env, 'Series', pieces[i].serie);
2373
+ if (env.emptySeries && env.opt.series.empty)
2374
+ props.label = $.extend(true, props.label, env.opt.series.empty.label);
2375
+ if (props && props.label && props.label.active) {
2376
+ paths = [];
2377
+ for (var index = 0; index < pieces[i].paths.length; index++)
2378
+ if (pieces[i].paths[index].path) {
2379
+ //lastSerie = pieces[i].serie;
2380
+ lastIndex = index;
2381
+ paths.push(this.showLabel(env, pieces[i], pieces[i].paths[index], pieces[i].serie, index, pieces));
2382
+ } else
2383
+ paths.push({ path : false, attr : false });
2384
+ pieces.push({ section : pieces[i].section, serie : pieces[i].serie, subSection : 'Label', paths: paths });
2385
+ }
2386
+ }
2387
+ else if (pieces[i].section == 'Sector' && pieces[i].serie == 'bottom' && !pieces[i].subSection && lastIndex < env.opt.labels.length - 1) {
2388
+ paths = [];
2389
+ paths.push(this.showLabel(env, pieces[i], pieces[i], 'Series', env.opt.labels.length - 1, pieces));
2390
+ pieces.push({ section : pieces[i].section, serie : pieces[i].serie, subSection : 'Label', paths: paths });
2391
+ }
2392
+ }
2393
+
2394
+ }
2395
+ },
2396
+
2397
+ showLabel : function(env, piece, path, serie, index, pieces) {
2398
+ var pp = common.areaProps(env, 'Series', serie, index);
2399
+ if (env.opt.labels[index] || pp.label.label) {
2400
+ var p = path;
2401
+ var label = pp.label.label ? pp.label.label : env.opt.labels[index];
2402
+ var center = common.getCenter(p, pp.label.offset);
2403
+ if (!pp.label.html) {
2404
+ var attr = pp.label.props;
2405
+ if (pp.label.frameAnchor) {
2406
+ attr = common._clone(pp.label.props);
2407
+ attr['text-anchor'] = pp.label.frameAnchor[0];
2408
+ attr['alignment-baseline'] = pp.label.frameAnchor[1];
2409
+ }
2410
+ /*pieces.push({
2411
+ path : [ [ 'TEXT', label, center[0], center[1] ] ], attr : attr,
2412
+ section: 'Series', serie : serie, index : index, subSection : 'Label'
2413
+ });*/
2414
+ return { path : [ [ 'TEXT', label, center[0], center[1] ] ], attr : attr };
2415
+
2416
+ } else {
2417
+ var opacity = 1;
2418
+ var style = common._clone(pp.label.style);
2419
+ var set_opacity = (typeof style.opacity != 'undefined')
2420
+ if (set_opacity) {
2421
+ opacity = style.opacity;
2422
+ style.opacity = 0;
2423
+ }
2424
+ style.position = 'absolute';
2425
+ style['z-index'] = 25;
2426
+
2427
+ var el;
2428
+ if (typeof label == 'string')
2429
+ el = $('<div>' + label + '</div>').css(style).prependTo(env.container);
2430
+ else
2431
+ el = $(label).css(style).prependTo(env.container);
2432
+
2433
+ // Centramento corretto label
2434
+ if (env.opt.features.debug.active && el.height() == 0)
2435
+ alert('DEBUG: Al gestore label e\' stata passata una label ancora senza dimensioni, quindi ancora non disegnata. Per questo motivo il posizionamento potrebbe non essere correto.');
2436
+ var posX = center[0];
2437
+ var posY = center[1];
2438
+ if (!pp.label.frameAnchor || pp.label.frameAnchor[0] == 'middle')
2439
+ posX -= el.width() / 2;
2440
+ else if (pp.label.frameAnchor && pp.label.frameAnchor[0] == 'end')
2441
+ posX -= el.width();
2442
+ if (!pp.label.frameAnchor || pp.label.frameAnchor[1] == 'middle')
2443
+ posY -= el.height() / 2;
2444
+ else if (pp.label.frameAnchor && pp.label.frameAnchor[1] == 'top')
2445
+ posY -= el.height();
2446
+ if (set_opacity)
2447
+ el.css({ margin: posY + 'px 0 0 ' + posX + 'px', opacity : opacity});
2448
+ else
2449
+ el.css({ margin: posY + 'px 0 0 ' + posX + 'px'});
2450
+
2451
+ /*pieces.push({
2452
+ path : [ [ 'DOMELEMENT', el ] ], attr : false,
2453
+ section: 'Series', serie : serie, index : index, subSection : 'Label'
2454
+ });*/
2455
+ return { path : [ [ 'DOMELEMENT', el ] ], attr : false };
2456
+
2457
+ }
2458
+ }
2459
+ return false;
2460
+ }
2461
+ }
2462
+
2463
+ $.elycharts.featuresmanager.register($.elycharts.labelmanager, 5);
2464
+
2465
+ })(jQuery);
2466
+ /********* Source File: src/elycharts_manager_legend.js*********/
2467
+ /**********************************************************************
2468
+ * ELYCHARTS
2469
+ * A Javascript library to generate interactive charts with vectorial graphics.
2470
+ *
2471
+ * Copyright (c) 2010 Void Labs s.n.c. (http://void.it)
2472
+ * Licensed under the MIT (http://creativecommons.org/licenses/MIT/) license.
2473
+ **********************************************************************/
2474
+
2475
+ (function($) {
2476
+
2477
+ //var featuresmanager = $.elycharts.featuresmanager;
2478
+ var common = $.elycharts.common;
2479
+
2480
+ /***********************************************************************
2481
+ * FEATURE: LEGEND
2482
+ **********************************************************************/
2483
+
2484
+ $.elycharts.legendmanager = {
2485
+
2486
+ afterShow : function(env, pieces) {
2487
+ if (!env.opt.legend || env.opt.legend.length == 0)
2488
+ return;
2489
+
2490
+ var props = env.opt.features.legend;
2491
+
2492
+ if (props.x == 'auto') {
2493
+ var autox = 1;
2494
+ props.x = 0;
2495
+ }
2496
+ if (props.width == 'auto') {
2497
+ var autowidth = 1;
2498
+ props.width = env.opt.width;
2499
+ }
2500
+
2501
+ var borderPath = [ [ 'RECT', props.x, props.y, props.x + props.width, props.y + props.height, props.r ] ];
2502
+ var border = common.showPath(env, borderPath).attr(props.borderProps);
2503
+ if (autox || autowidth)
2504
+ border.hide();
2505
+
2506
+ var wauto = 0;
2507
+ var items = [];
2508
+ // env.opt.legend normalmente è { serie : 'Legend', ... }, per i pie invece { serie : ['Legend', ...], ... }
2509
+ var legendCount = 0;
2510
+ var serie, data, h, w, x, y, xd;
2511
+ for (serie in env.opt.legend) {
2512
+ if (env.opt.type != 'pie')
2513
+ legendCount ++;
2514
+ else
2515
+ legendCount += env.opt.legend[serie].length;
2516
+ }
2517
+ var i = 0;
2518
+ for (serie in env.opt.legend) {
2519
+ if (env.opt.type != 'pie')
2520
+ data = [ env.opt.legend[serie] ];
2521
+ else
2522
+ data = env.opt.legend[serie];
2523
+
2524
+ for (var j = 0; j < data.length; j++) {
2525
+ var sprops = common.areaProps(env, 'Series', serie, env.opt.type == 'pie' ? j : false);
2526
+ var dprops = $.extend(true, {}, props.dotProps);
2527
+ if (sprops.legend && sprops.legend.dotProps)
2528
+ dprops = $.extend(true, dprops, sprops.legend.dotProps);
2529
+ if (!dprops.fill && env.opt.type == 'pie') {
2530
+ if (sprops.color)
2531
+ dprops.fill = sprops.color;
2532
+ if (sprops.plotProps && sprops.plotProps.fill)
2533
+ dprops.fill = sprops.plotProps.fill;
2534
+ }
2535
+ var dtype = sprops.legend && sprops.legend.dotType ? sprops.legend.dotType : props.dotType;
2536
+ var dwidth = sprops.legend && sprops.legend.dotWidth ? sprops.legend.dotWidth : props.dotWidth;
2537
+ var dheight = sprops.legend && sprops.legend.dotHeight ? sprops.legend.dotHeight : props.dotHeight;
2538
+ var dr = sprops.legend && sprops.legend.dotR ? sprops.legend.dotR : props.dotR;
2539
+ var tprops = sprops.legend && sprops.legend.textProps ? sprops.legend.textProps : props.textProps;
2540
+
2541
+ if (!props.horizontal) {
2542
+ // Posizione dell'angolo in alto a sinistra
2543
+ h = (props.height - props.margins[0] - props.margins[2]) / legendCount;
2544
+ w = props.width - props.margins[1] - props.margins[3];
2545
+ x = Math.floor(props.x + props.margins[3]);
2546
+ y = Math.floor(props.y + props.margins[0] + h * i);
2547
+ } else {
2548
+ h = props.height - props.margins[0] - props.margins[2];
2549
+ if (!props.itemWidth || props.itemWidth == 'fixed') {
2550
+ w = (props.width - props.margins[1] - props.margins[3]) / legendCount;
2551
+ x = Math.floor(props.x + props.margins[3] + w * i);
2552
+ } else {
2553
+ w = (props.width - props.margins[1] - props.margins[3]) - wauto;
2554
+ x = props.x + props.margins[3] + wauto;
2555
+ }
2556
+ y = Math.floor(props.y + props.margins[0]);
2557
+ }
2558
+
2559
+ if (dtype == "rect") {
2560
+ items.push(common.showPath(env, [ [ 'RECT', props.dotMargins[0] + x, y + Math.floor((h - dheight) / 2), props.dotMargins[0] + x + dwidth, y + Math.floor((h - dheight) / 2) + dheight, dr ] ]).attr(dprops));
2561
+ xd = props.dotMargins[0] + dwidth + props.dotMargins[1];
2562
+ } else if (dtype == "circle") {
2563
+ items.push(common.showPath(env, [ [ 'CIRCLE', props.dotMargins[0] + x + dr, y + (h / 2), dr ] ]).attr(dprops));
2564
+ xd = props.dotMargins[0] + dr * 2 + props.dotMargins[1];
2565
+ }
2566
+
2567
+ var text = data[j];
2568
+ var t = common.showPath(env, [ [ 'TEXT', text, x + xd, y + Math.ceil(h / 2) + ($.browser.msie ? 2 : 0) ] ]).attr({"text-anchor" : "start"}).attr(tprops); //.hide();
2569
+ items.push(t);
2570
+ while (t.getBBox().width > (w - xd) && t.getBBox().width > 10) {
2571
+ text = text.substring(0, text.length - 1);
2572
+ t.attr({text : text});
2573
+ }
2574
+ t.show();
2575
+
2576
+ if (props.horizontal && props.itemWidth == 'auto')
2577
+ wauto += xd + t.getBBox().width + 4;
2578
+ else if (!props.horizontal && autowidth)
2579
+ wauto = t.getBBox().width + xd > wauto ? t.getBBox().width + xd : wauto;
2580
+ else
2581
+ wauto += w;
2582
+
2583
+ i++;
2584
+ }
2585
+ }
2586
+
2587
+ if (autowidth)
2588
+ props.width = wauto + props.margins[3] + props.margins[1] - 1;
2589
+ if (autox) {
2590
+ props.x = Math.floor((env.opt.width - props.width) / 2);
2591
+ for (i in items) {
2592
+ if (items[i].attrs.x)
2593
+ items[i].attr('x', items[i].attrs.x + props.x);
2594
+ else
2595
+ items[i].attr('path', common.movePath(env, items[i].attrs.path, [props.x, 0]));
2596
+ }
2597
+ }
2598
+ if (autowidth || autox) {
2599
+ borderPath = [ [ 'RECT', props.x, props.y, props.x + props.width, props.y + props.height, props.r ] ];
2600
+ border.attr(common.getSVGProps(common.preparePathShow(env, borderPath)));
2601
+ //border.attr({path : common.preparePathShow(env, common.getSVGPath(borderPath))});
2602
+ border.show();
2603
+ }
2604
+ }
2605
+ }
2606
+
2607
+ $.elycharts.featuresmanager.register($.elycharts.legendmanager, 90);
2608
+
2609
+ })(jQuery);
2610
+ /********* Source File: src/elycharts_manager_mouse.js*********/
2611
+ /**********************************************************************
2612
+ * ELYCHARTS
2613
+ * A Javascript library to generate interactive charts with vectorial graphics.
2614
+ *
2615
+ * Copyright (c) 2010 Void Labs s.n.c. (http://void.it)
2616
+ * Licensed under the MIT (http://creativecommons.org/licenses/MIT/) license.
2617
+ **********************************************************************/
2618
+
2619
+ (function($) {
2620
+
2621
+ var featuresmanager = $.elycharts.featuresmanager;
2622
+ var common = $.elycharts.common;
2623
+
2624
+ /***********************************************************************
2625
+ * MOUSEMANAGER
2626
+ **********************************************************************/
2627
+
2628
+ $.elycharts.mousemanager = {
2629
+
2630
+ afterShow : function(env, pieces) {
2631
+ if (!env.opt.interactive)
2632
+ return;
2633
+
2634
+ if (env.mouseLayer) {
2635
+ env.mouseLayer.remove();
2636
+ env.mouseLayer = null;
2637
+ env.mousePaper.remove();
2638
+ env.mousePaper = null;
2639
+ env.mouseTimer = null;
2640
+ env.mouseAreas = null;
2641
+ // Meglio fare anche l'unbind???
2642
+ }
2643
+
2644
+ env.mouseLayer = $('<div></div>').css({position : 'absolute', 'z-index' : 20, opacity : 0}).prependTo(env.container);
2645
+ env.mousePaper = common._RaphaelInstance(env.mouseLayer.get(0), env.opt.width, env.opt.height);
2646
+ var paper = env.mousePaper;
2647
+
2648
+ if (env.opt.features.debug.active && typeof DP_Debug != 'undefined') {
2649
+ env.paper.text(env.opt.width, env.opt.height - 5, 'DEBUG').attr({ 'text-anchor' : 'end', stroke: 'red', opacity: .1 });
2650
+ paper.text(env.opt.width, env.opt.height - 5, 'DEBUG').attr({ 'text-anchor' : 'end', stroke: 'red', opacity: .1 }).click(function() {
2651
+ DP_Debug.dump(env.opt, '', false, 4);
2652
+ });
2653
+ }
2654
+
2655
+ var i, j;
2656
+
2657
+ // Adding mouseover only in right area, based on pieces
2658
+ env.mouseAreas = [];
2659
+ if (env.opt.features.mousearea.type == 'single') {
2660
+ // SINGLE: Every serie's index is an area
2661
+ for (i = 0; i < pieces.length; i++) {
2662
+ if (pieces[i].mousearea) {
2663
+ // pathstep
2664
+ if (!pieces[i].paths) {
2665
+ // path standard, generating an area for each point
2666
+ if (pieces[i].path.length >= 1 && (pieces[i].path[0][0] == 'LINE' || pieces[i].path[0][0] == 'LINEAREA'))
2667
+ for (j = 0; j < pieces[i].path[0][1].length; j++) {
2668
+ var props = common.areaProps(env, pieces[i].section, pieces[i].serie);
2669
+ if (props.mouseareaShowOnNull || pieces[i].section != 'Series' || env.opt.values[pieces[i].serie][j] != null)
2670
+ env.mouseAreas.push({
2671
+ path : [ [ 'CIRCLE', pieces[i].path[0][1][j][0], pieces[i].path[0][1][j][1], 10 ] ],
2672
+ piece : pieces[i],
2673
+ pieces : pieces,
2674
+ index : j,
2675
+ props : props
2676
+ });
2677
+ }
2678
+
2679
+ else // Code below is only for standard path - it should be useless now (now there are only LINE and LINEAREA)
2680
+ // TODO DELETE
2681
+ for (j = 0; j < pieces[i].path.length; j++) {
2682
+ env.mouseAreas.push({
2683
+ path : [ [ 'CIRCLE', common.getX(pieces[i].path[j]), common.getY(pieces[i].path[j]), 10 ] ],
2684
+ piece : pieces[i],
2685
+ pieces : pieces,
2686
+ index : j,
2687
+ props : common.areaProps(env, pieces[i].section, pieces[i].serie)
2688
+ });
2689
+ }
2690
+
2691
+ // paths
2692
+ } else if (pieces[i].paths) {
2693
+ // Set of paths (bar graph?), generating overlapped areas
2694
+ for (j = 0; j < pieces[i].paths.length; j++)
2695
+ if (pieces[i].paths[j].path)
2696
+ env.mouseAreas.push({
2697
+ path : pieces[i].paths[j].path,
2698
+ piece : pieces[i],
2699
+ pieces : pieces,
2700
+ index : j,
2701
+ props : common.areaProps(env, pieces[i].section, pieces[i].serie)
2702
+ });
2703
+ }
2704
+ }
2705
+ }
2706
+ } else {
2707
+ // INDEX: Each index (in every serie) is an area
2708
+ var indexCenter = env.opt.features.mousearea.indexCenter;
2709
+ if (indexCenter == 'auto')
2710
+ indexCenter = env.indexCenter;
2711
+ var start, delta;
2712
+ if (indexCenter == 'bar') {
2713
+ delta = (env.opt.width - env.opt.margins[3] - env.opt.margins[1]) / (env.opt.labels.length > 0 ? env.opt.labels.length : 1);
2714
+ start = env.opt.margins[3];
2715
+ } else {
2716
+ delta = (env.opt.width - env.opt.margins[3] - env.opt.margins[1]) / (env.opt.labels.length > 1 ? env.opt.labels.length - 1 : 1);
2717
+ start = env.opt.margins[3] - delta / 2;
2718
+ }
2719
+
2720
+ for (var index in env.opt.labels) {
2721
+ env.mouseAreas.push({
2722
+ path : [ [ 'RECT', start + index * delta, env.opt.margins[0], start + (index + 1) * delta, env.opt.height - env.opt.margins[2] ] ],
2723
+ piece : false,
2724
+ pieces : pieces,
2725
+ index : parseInt(index),
2726
+ props : env.opt.defaultSeries // TODO common.areaProps(env, 'Plot')
2727
+ });
2728
+ }
2729
+ }
2730
+
2731
+ var syncenv = false;
2732
+ if (!env.opt.features.mousearea.syncTag) {
2733
+ env.mouseareaenv = { chartEnv : false, mouseObj : false, caller : false, inArea : -1, timer : false };
2734
+ syncenv = env.mouseareaenv;
2735
+ } else {
2736
+ if (!$.elycharts.mouseareaenv)
2737
+ $.elycharts.mouseareaenv = {};
2738
+ if (!$.elycharts.mouseareaenv[env.opt.features.mousearea.syncTag])
2739
+ $.elycharts.mouseareaenv[env.opt.features.mousearea.syncTag] = { chartEnv : false, mouseObj : false, caller : false, inArea : -1, timer : false };
2740
+ syncenv = $.elycharts.mouseareaenv[env.opt.features.mousearea.syncTag];
2741
+ }
2742
+ for (i = 0; i < env.mouseAreas.length; i++) {
2743
+ env.mouseAreas[i].area = common.showPath(env, env.mouseAreas[i].path, paper).attr({stroke: "none", fill: "#fff", opacity: 0});
2744
+
2745
+ (function(env, obj, objidx, caller, syncenv) {
2746
+ var piece = obj.piece;
2747
+ var index = obj.index;
2748
+
2749
+ obj.mouseover = function(e) {
2750
+ //BIND: if (obj.listenerDisabled) return;
2751
+ obj.event = e;
2752
+ clearTimeout(syncenv.timer);
2753
+ caller.onMouseOverArea(env, piece, index, obj);
2754
+
2755
+ if (syncenv.chartEnv && syncenv.chartEnv.id != env.id) {
2756
+ // Chart changed, removing old one
2757
+ syncenv.caller.onMouseExitArea(syncenv.chartEnv, syncenv.mouseObj.piece, syncenv.mouseObj.index, syncenv.mouseObj);
2758
+ caller.onMouseEnterArea(env, piece, index, obj);
2759
+ }
2760
+ else if (syncenv.inArea != objidx) {
2761
+ if (syncenv.inArea < 0)
2762
+ caller.onMouseEnterArea(env, piece, index, obj);
2763
+ else
2764
+ caller.onMouseChangedArea(env, piece, index, obj);
2765
+ }
2766
+ syncenv.chartEnv = env;
2767
+ syncenv.mouseObj = obj;
2768
+ syncenv.caller = caller;
2769
+ syncenv.inArea = objidx;
2770
+ };
2771
+ obj.mouseout = function(e) {
2772
+ //BIND: if (obj.listenerDisabled) return;
2773
+ obj.event = e;
2774
+ clearTimeout(syncenv.timer);
2775
+ caller.onMouseOutArea(env, piece, index, obj);
2776
+ syncenv.timer = setTimeout(function() {
2777
+ syncenv.timer = false;
2778
+ caller.onMouseExitArea(env, piece, index, obj);
2779
+ syncenv.chartEnv = false;
2780
+ syncenv.inArea = -1;
2781
+ }, env.opt.features.mousearea.areaMoveDelay);
2782
+ };
2783
+
2784
+ $(obj.area.node).mouseover(obj.mouseover);
2785
+ $(obj.area.node).mouseout(obj.mouseout);
2786
+ })(env, env.mouseAreas[i], i, this, syncenv);
2787
+ }
2788
+ },
2789
+
2790
+ // Called when mouse enter an area
2791
+ onMouseOverArea : function(env, piece, index, mouseAreaData) {
2792
+ //console.warn('over', piece.serie, index);
2793
+ if (env.opt.features.mousearea.onMouseOver)
2794
+ env.opt.features.mousearea.onMouseOver(env, mouseAreaData.piece ? mouseAreaData.piece.serie : false, mouseAreaData.index, mouseAreaData);
2795
+ featuresmanager.onMouseOver(env, mouseAreaData.piece ? mouseAreaData.piece.serie : false, mouseAreaData.index, mouseAreaData);
2796
+ },
2797
+
2798
+ // Called when mouse exit from an area
2799
+ onMouseOutArea : function(env, piece, index, mouseAreaData) {
2800
+ //console.warn('out', piece.serie, index);
2801
+ if (env.opt.features.mousearea.onMouseOut)
2802
+ env.opt.features.mousearea.onMouseOut(env, mouseAreaData.piece ? mouseAreaData.piece.serie : false, mouseAreaData.index, mouseAreaData);
2803
+ featuresmanager.onMouseOut(env, mouseAreaData.piece ? mouseAreaData.piece.serie : false, mouseAreaData.index, mouseAreaData);
2804
+ },
2805
+
2806
+ // Called when mouse enter an area from empty space (= it was in no area before)
2807
+ onMouseEnterArea : function(env, piece, index, mouseAreaData) {
2808
+ //console.warn('enter', piece.serie, index);
2809
+ if (env.opt.features.mousearea.onMouseEnter)
2810
+ env.opt.features.mousearea.onMouseEnter(env, mouseAreaData.piece ? mouseAreaData.piece.serie : false, mouseAreaData.index, mouseAreaData);
2811
+ featuresmanager.onMouseEnter(env, mouseAreaData.piece ? mouseAreaData.piece.serie : false, mouseAreaData.index, mouseAreaData);
2812
+ },
2813
+
2814
+ // Called when mouse enter an area and it was on another area
2815
+ onMouseChangedArea : function(env, piece, index, mouseAreaData) {
2816
+ //console.warn('changed', piece.serie, index);
2817
+ if (env.opt.features.mousearea.onMouseChanged)
2818
+ env.opt.features.mousearea.onMouseChanged(env, mouseAreaData.piece ? mouseAreaData.piece.serie : false, mouseAreaData.index, mouseAreaData);
2819
+ featuresmanager.onMouseChanged(env, mouseAreaData.piece ? mouseAreaData.piece.serie : false, mouseAreaData.index, mouseAreaData);
2820
+ },
2821
+
2822
+ // Called when mouse leaves an area and does not enter in another one (timeout check)
2823
+ onMouseExitArea : function(env, piece, index, mouseAreaData) {
2824
+ //console.warn('exit', piece.serie, index);
2825
+ if (env.opt.features.mousearea.onMouseExit)
2826
+ env.opt.features.mousearea.onMouseExit(env, mouseAreaData.piece ? mouseAreaData.piece.serie : false, mouseAreaData.index, mouseAreaData);
2827
+ featuresmanager.onMouseExit(env, mouseAreaData.piece ? mouseAreaData.piece.serie : false, mouseAreaData.index, mouseAreaData);
2828
+ }
2829
+
2830
+ }
2831
+
2832
+ $.elycharts.featuresmanager.register($.elycharts.mousemanager, 0);
2833
+
2834
+ })(jQuery);
2835
+ /********* Source File: src/elycharts_manager_tooltip.js*********/
2836
+ /**********************************************************************
2837
+ * ELYCHARTS
2838
+ * A Javascript library to generate interactive charts with vectorial graphics.
2839
+ *
2840
+ * Copyright (c) 2010 Void Labs s.n.c. (http://void.it)
2841
+ * Licensed under the MIT (http://creativecommons.org/licenses/MIT/) license.
2842
+ **********************************************************************/
2843
+
2844
+ (function($) {
2845
+
2846
+ //var featuresmanager = $.elycharts.featuresmanager;
2847
+ var common = $.elycharts.common;
2848
+
2849
+ /***********************************************************************
2850
+ * FEATURE: TOOLTIP
2851
+ **********************************************************************/
2852
+
2853
+ $.elycharts.tooltipmanager = {
2854
+
2855
+ afterShow : function(env, pieces) {
2856
+ if (env.tooltipContainer) {
2857
+ env.tooltipFrame.remove();
2858
+ env.tooltipFrame = null;
2859
+ env.tooltipFrameElement = null;
2860
+ env.tooltipContent.remove();
2861
+ env.tooltipContent = null;
2862
+ env.tooltipContainer.remove();
2863
+ env.tooltipContainer = null;
2864
+ }
2865
+
2866
+ if (!$.elycharts.tooltipid)
2867
+ $.elycharts.tooltipid = 0;
2868
+ $.elycharts.tooltipid ++;
2869
+
2870
+ // Preparo il tooltip
2871
+ env.tooltipContainer = $('<div id="elycharts_tooltip_' + $.elycharts.tooltipid + '" style="position: absolute; top: 100; left: 100; z-index: 10; overflow: hidden; white-space: nowrap; display: none"><div id="elycharts_tooltip_' + $.elycharts.tooltipid + '_frame" style="position: absolute; top: 0; left: 0; z-index: -1"></div><div id="elycharts_tooltip_' + $.elycharts.tooltipid + '_content" style="cursor: default"></div></div>').appendTo(document.body);
2872
+ env.tooltipFrame = common._RaphaelInstance('elycharts_tooltip_' + $.elycharts.tooltipid + '_frame', 500, 500);
2873
+ env.tooltipContent = $('#elycharts_tooltip_' + $.elycharts.tooltipid + '_content');
2874
+ },
2875
+
2876
+ _prepareShow : function(env, props, mouseAreaData, tip) {
2877
+ if (env.tooltipFrameElement)
2878
+ env.tooltipFrameElement.attr(props.frameProps);
2879
+ if (props.padding)
2880
+ env.tooltipContent.css({ padding : props.padding[0] + 'px ' + props.padding[1] + 'px' });
2881
+ env.tooltipContent.css(props.contentStyle);
2882
+ env.tooltipContent.html(tip);
2883
+
2884
+ //BIND: env.tooltipContainer.unbind().mouseover(mouseAreaData.mouseover).mouseout(mouseAreaData.mouseout);
2885
+
2886
+ // WARN: Prendendo env.paper.canvas non va bene...
2887
+ //var offset = $(env.paper.canvas).offset();
2888
+ var offset = $(env.container).offset();
2889
+
2890
+ if (env.opt.features.tooltip.fixedPos) {
2891
+ offset.top += env.opt.features.tooltip.fixedPos[1];
2892
+ offset.left += env.opt.features.tooltip.fixedPos[0];
2893
+
2894
+ } else {
2895
+ var coord = this.getXY(env, props, mouseAreaData);
2896
+ if (!coord[2]) {
2897
+ offset.left += coord[0];
2898
+ while (offset.top + coord[1] < 0)
2899
+ coord[1] += 20;
2900
+ offset.top += coord[1];
2901
+ } else {
2902
+ offset.left = coord[0];
2903
+ offset.top = coord[1];
2904
+ }
2905
+ }
2906
+
2907
+ return { top : offset.top, left : offset.left };
2908
+ },
2909
+
2910
+ /**
2911
+ * Ritorna [x, y] oppure [x, y, true] se le coordinate sono relative alla pagina (e non al grafico)
2912
+ */
2913
+ getXY : function(env, props, mouseAreaData) {
2914
+ // NOTA Posizione mouse: mouseAreaData.event.pageX/pageY
2915
+ var x = 0, y = 0;
2916
+ if (mouseAreaData.path[0][0] == 'RECT') {
2917
+ // L'area e' su un rettangolo (un bar o un indice completo), il tooltip lo faccio subito sopra
2918
+ // Nota: per capire se e' sull'indice completo basta guardare mouseAreaData.piece == null
2919
+ x = common.getX(mouseAreaData.path[0]) - props.offset[1];
2920
+ y = common.getY(mouseAreaData.path[0]) - props.height - props.offset[0];
2921
+ }
2922
+ else if (mouseAreaData.path[0][0] == 'CIRCLE') {
2923
+ // L'area e' su un cerchio (punto di un line)
2924
+ x = common.getX(mouseAreaData.path[0]) - props.offset[1];
2925
+ y = common.getY(mouseAreaData.path[0]) - props.height - props.offset[0];
2926
+ }
2927
+ else if (mouseAreaData.path[0][0] == 'SLICE') {
2928
+ // L'area è su una fetta di torta (pie)
2929
+ var path = mouseAreaData.path[0];
2930
+
2931
+ // Genera la posizione del tip considerando che deve stare all'interno di un cerchio che è sempre dalla parte opposta dell'area
2932
+ // e deve essere il piu' vicino possibile all'area
2933
+ var w = props.width && props.width != 'auto' ? props.width : 100;
2934
+ var h = props.height && props.height != 'auto' ? props.height : 100;
2935
+
2936
+ // Raggio del cerchio che contiene il tip
2937
+ var cr = Math.sqrt(Math.pow(w,2) + Math.pow(h,2)) / 2;
2938
+ if (cr > env.opt.r)
2939
+ cr = env.opt.r;
2940
+
2941
+ var tipangle = path[5] + (path[6] - path[5]) / 2 + 180;
2942
+ var rad = Math.PI / 180;
2943
+ x = path[1] + cr * Math.cos(- tipangle * rad) - w / 2;
2944
+ y = path[2] + cr * Math.sin(- tipangle * rad) - h / 2;
2945
+ }
2946
+ else if (mouseAreaData.piece && mouseAreaData.piece.paths && mouseAreaData.index >= 0 && mouseAreaData.piece.paths[mouseAreaData.index] && mouseAreaData.piece.paths[mouseAreaData.index].rect) {
2947
+ // L'area ha una forma complessa, ma abbiamo il rettangolo di contenimento (funnel)
2948
+ var rect = mouseAreaData.piece.paths[mouseAreaData.index].rect;
2949
+ x = rect[0] - props.offset[1];
2950
+ y = rect[1] - props.height - props.offset[0];
2951
+ }
2952
+
2953
+ if (env.opt.features.tooltip.positionHandler)
2954
+ return env.opt.features.tooltip.positionHandler(env, props, mouseAreaData, x, y);
2955
+ else
2956
+ return [x, y];
2957
+ },
2958
+
2959
+ getTip : function(env, serie, index) {
2960
+ var tip = false;
2961
+ if (env.opt.tooltips) {
2962
+ if (typeof env.opt.tooltips == 'function')
2963
+ tip = env.opt.tooltips(env, serie, index, serie && env.opt.values[serie] && env.opt.values[serie][index] ? env.opt.values[serie][index] : false, env.opt.labels && env.opt.labels[index] ? env.opt.labels[index] : false);
2964
+ else {
2965
+ if (serie && env.opt.tooltips[serie] && env.opt.tooltips[serie][index])
2966
+ tip = env.opt.tooltips[serie][index];
2967
+ else if (!serie && env.opt.tooltips[index])
2968
+ tip = env.opt.tooltips[index];
2969
+ }
2970
+ }
2971
+ return tip;
2972
+ },
2973
+
2974
+ onMouseEnter : function(env, serie, index, mouseAreaData) {
2975
+ var props = mouseAreaData.props.tooltip;
2976
+ if (env.emptySeries && env.opt.series.empty)
2977
+ props = $.extend(true, props, env.opt.series.empty.tooltip);
2978
+ if (!props || !props.active)
2979
+ return false;
2980
+
2981
+ var tip = this.getTip(env, serie, index);
2982
+ if (!tip)
2983
+ return this.onMouseExit(env, serie, index, mouseAreaData);
2984
+
2985
+ //if (!env.opt.tooltips || (serie && (!env.opt.tooltips[serie] || !env.opt.tooltips[serie][index])) || (!serie && !env.opt.tooltips[index]))
2986
+ // return this.onMouseExit(env, serie, index, mouseAreaData);
2987
+ //var tip = serie ? env.opt.tooltips[serie][index] : env.opt.tooltips[index];
2988
+
2989
+ // Il dimensionamento del tooltip e la view del frame SVG, lo fa solo se width ed height sono specificati
2990
+ if (props.width && props.width != 'auto' && props.height && props.height != 'auto') {
2991
+ var delta = props.frameProps && props.frameProps['stroke-width'] ? props.frameProps['stroke-width'] : 0;
2992
+ env.tooltipContainer.width(props.width + delta + 1).height(props.height + delta + 1);
2993
+ if (!env.tooltipFrameElement && props.frameProps)
2994
+ env.tooltipFrameElement = env.tooltipFrame.rect(delta / 2, delta / 2, props.width, props.height, props.roundedCorners);
2995
+ }
2996
+
2997
+ env.tooltipContainer.css(this._prepareShow(env, props, mouseAreaData, tip)).fadeIn(env.opt.features.tooltip.fadeDelay);
2998
+
2999
+ return true;
3000
+ },
3001
+
3002
+ onMouseChanged : function(env, serie, index, mouseAreaData) {
3003
+ var props = mouseAreaData.props.tooltip;
3004
+ if (env.emptySeries && env.opt.series.empty)
3005
+ props = $.extend(true, props, env.opt.series.empty.tooltip);
3006
+ if (!props || !props.active)
3007
+ return false;
3008
+
3009
+ var tip = this.getTip(env, serie, index);
3010
+ if (!tip)
3011
+ return this.onMouseExit(env, serie, index, mouseAreaData);
3012
+
3013
+ /*if (!env.opt.tooltips || (serie && (!env.opt.tooltips[serie] || !env.opt.tooltips[serie][index])) || (!serie && !env.opt.tooltips[index]))
3014
+ return this.onMouseExit(env, serie, index, mouseAreaData);
3015
+ var tip = serie ? env.opt.tooltips[serie][index] : env.opt.tooltips[index];*/
3016
+
3017
+ env.tooltipContainer.clearQueue();
3018
+ // Nota: Non passo da animationStackPush, i tooltip non sono legati a piece
3019
+ env.tooltipContainer.animate(this._prepareShow(env, props, mouseAreaData, tip), env.opt.features.tooltip.moveDelay, 'linear' /*swing*/);
3020
+
3021
+ return true;
3022
+ },
3023
+
3024
+ onMouseExit : function(env, serie, index, mouseAreaData) {
3025
+ var props = mouseAreaData.props.tooltip;
3026
+ if (env.emptySeries && env.opt.series.empty)
3027
+ props = $.extend(true, props, env.opt.series.empty.tooltip);
3028
+ if (!props || !props.active)
3029
+ return false;
3030
+
3031
+ //env.tooltipContainer.unbind();
3032
+ env.tooltipContainer.fadeOut(env.opt.features.tooltip.fadeDelay);
3033
+
3034
+ return true;
3035
+ }
3036
+ }
3037
+
3038
+ $.elycharts.featuresmanager.register($.elycharts.tooltipmanager, 20);
3039
+
3040
+ })(jQuery);
3041
+ /********* Source File: src/elycharts_chart_line.js*********/
3042
+ /**********************************************************************
3043
+ * ELYCHARTS
3044
+ * A Javascript library to generate interactive charts with vectorial graphics.
3045
+ *
3046
+ * Copyright (c) 2010 Void Labs s.n.c. (http://void.it)
3047
+ * Licensed under the MIT (http://creativecommons.org/licenses/MIT/) license.
3048
+ **********************************************************************/
3049
+
3050
+ (function($) {
3051
+
3052
+ var featuresmanager = $.elycharts.featuresmanager;
3053
+ var common = $.elycharts.common;
3054
+
3055
+ /***********************************************************************
3056
+ * CHART: LINE/BAR
3057
+ **********************************************************************/
3058
+
3059
+ $.elycharts.line = {
3060
+ init : function($env) {
3061
+ },
3062
+
3063
+ draw : function(env) {
3064
+ if (common.executeIfChanged(env, ['values', 'series'])) {
3065
+ env.plots = {};
3066
+ env.axis = { x : {} };
3067
+ env.barno = 0;
3068
+ env.indexCenter = 'line';
3069
+ }
3070
+
3071
+ var opt = env.opt;
3072
+ var plots = env.plots;
3073
+ var axis = env.axis;
3074
+ var paper = env.paper;
3075
+
3076
+ var values = env.opt.values;
3077
+ var labels = env.opt.labels;
3078
+ var i, cum, props, serie, plot, labelsCount;
3079
+
3080
+ // Valorizzazione di tutte le opzioni utili e le impostazioni interne di ogni grafico e dell'ambiente di lavoro
3081
+ if (common.executeIfChanged(env, ['values', 'series'])) {
3082
+ var idx = 0;
3083
+ var prevVisibleSerie = false;
3084
+ for (serie in values) {
3085
+ plot = {
3086
+ index : idx,
3087
+ type : false,
3088
+ visible : false
3089
+ };
3090
+ plots[serie] = plot;
3091
+ if (values[serie]) {
3092
+ props = common.areaProps(env, 'Series', serie);
3093
+ plot.type = props.type;
3094
+ if (props.type == 'bar')
3095
+ env.indexCenter = 'bar';
3096
+
3097
+ if (props.visible) {
3098
+ plot.visible = true;
3099
+ if (!labelsCount || labelsCount < values[serie].length)
3100
+ labelsCount = values[serie].length;
3101
+
3102
+ // Values
3103
+ // showValues: manage NULL elements (doing an avg of near points) for line serie
3104
+ var showValues = []
3105
+ for (i = 0; i < values[serie].length; i++) {
3106
+ var val = values[serie][i];
3107
+ if (val == null) {
3108
+ if (props.type == 'bar')
3109
+ val = 0;
3110
+ else {
3111
+ for (var j = i + 1; j < values[serie].length && values[serie][j] == null; j++) {}
3112
+ var next = j < values[serie].length ? values[serie][j] : null;
3113
+ for (var k = i -1; k >= 0 && values[serie][k] == null; k--) {}
3114
+ var prev = k >= 0 ? values[serie][k] : null;
3115
+ val = next != null ? (prev != null ? (next * (i - k) + prev * (j - i)) / (j - k) : next) : prev;
3116
+ }
3117
+ }
3118
+ showValues.push(val);
3119
+ }
3120
+
3121
+ if (props.stacked && !(typeof props.stacked == 'string'))
3122
+ props.stacked = prevVisibleSerie;
3123
+
3124
+ if (typeof props.stacked == 'undefined' || props.stacked == serie || props.stacked < 0 || !plots[props.stacked] || !plots[props.stacked].visible || plots[props.stacked].type != plot.type) {
3125
+ // NOT Stacked
3126
+ plot.ref = serie;
3127
+ if (props.type == 'bar')
3128
+ plot.barno = env.barno ++;
3129
+ plot.from = [];
3130
+ if (!props.cumulative)
3131
+ plot.to = showValues;
3132
+ else {
3133
+ plot.to = [];
3134
+ cum = 0;
3135
+ for (i = 0; i < showValues.length; i++)
3136
+ plot.to.push(cum += showValues[i]);
3137
+ }
3138
+ for (i = 0; i < showValues.length; i++)
3139
+ plot.from.push(0);
3140
+
3141
+ } else {
3142
+ // Stacked
3143
+ plot.ref = props.stacked;
3144
+ if (props.type == 'bar')
3145
+ plot.barno = plots[props.stacked].barno;
3146
+ plot.from = plots[props.stacked].stack;
3147
+ plot.to = [];
3148
+ cum = 0;
3149
+ if (!props.cumulative)
3150
+ for (i = 0; i < showValues.length; i++)
3151
+ plot.to.push(plot.from[i] + showValues[i]);
3152
+ else
3153
+ for (i = 0; i < showValues.length; i++)
3154
+ plot.to.push(plot.from[i] + (cum += showValues[i]));
3155
+ plots[props.stacked].stack = plot.to;
3156
+ }
3157
+
3158
+ plot.stack = plot.to;
3159
+ plot.max = Math.max.apply(Math, plot.from.concat(plot.to));
3160
+ plot.min = Math.min.apply(Math, plot.from.concat(plot.to));
3161
+
3162
+ // Assi (DEP: values, series)
3163
+ if (props.axis) {
3164
+ if (!axis[props.axis])
3165
+ axis[props.axis] = { plots : [] };
3166
+ axis[props.axis].plots.push(serie);
3167
+ if (typeof axis[props.axis].max == 'undefined')
3168
+ axis[props.axis].max = plot.max;
3169
+ else
3170
+ axis[props.axis].max = Math.max(axis[props.axis].max, plot.max);
3171
+ if (typeof axis[props.axis].min == 'undefined')
3172
+ axis[props.axis].min = plot.min;
3173
+ else
3174
+ axis[props.axis].min = Math.min(axis[props.axis].min, plot.min);
3175
+ }
3176
+
3177
+ prevVisibleSerie = serie;
3178
+ }
3179
+ }
3180
+ }
3181
+ }
3182
+
3183
+ // Labels normalization (if not set or less than values)
3184
+ if (!labels)
3185
+ labels = [];
3186
+ while (labelsCount > labels.length)
3187
+ labels.push(null);
3188
+ labelsCount = labels.length;
3189
+ env.opt.labels = labels;
3190
+
3191
+ // Prepare axis scale (values, series, axis)
3192
+ if (common.executeIfChanged(env, ['values', 'series', 'axis'])) {
3193
+ for (var lidx in axis) {
3194
+ props = common.areaProps(env, 'Axis', lidx);
3195
+ axis[lidx].props = props;
3196
+
3197
+ if (typeof props.max != 'undefined')
3198
+ axis[lidx].max = props.max;
3199
+ if (typeof props.min != 'undefined')
3200
+ axis[lidx].min = props.min;
3201
+
3202
+ if (axis[lidx].min == axis[lidx].max)
3203
+ axis[lidx].max = axis[lidx].min + 1;
3204
+
3205
+ if (props.normalize && props.normalize > 0) {
3206
+ var v = Math.abs(axis[lidx].max);
3207
+ if (axis[lidx].min && Math.abs(axis[lidx].min) > v)
3208
+ v = Math.abs(axis[lidx].min);
3209
+ if (v) {
3210
+ var basev = Math.floor(Math.log(v)/Math.LN10) - (props.normalize - 1);
3211
+ // NOTE: On firefox Math.pow(10, -X) sometimes results in number noise (0.89999...), it's better to do 1/Math.pow(10,X)
3212
+ basev = basev >= 0 ? Math.pow(10, basev) : 1 / Math.pow(10, -basev);
3213
+ v = Math.ceil(v / basev / (opt.features.grid.ny ? opt.features.grid.ny : 1)) * basev * (opt.features.grid.ny ? opt.features.grid.ny : 1);
3214
+ // Calculation above, with decimal number sometimes insert some noise in numbers (eg: 8.899999... instead of 0.9), so i need to round result with proper precision
3215
+ v = Math.round(v / basev) * basev;
3216
+ // I need to store the normalization base for further roundin (eg: in axis label, sometimes calculation results in "number noise", so i need to round them with proper precision)
3217
+ axis[lidx].normalizationBase = basev;
3218
+ if (axis[lidx].max)
3219
+ axis[lidx].max = Math.ceil(axis[lidx].max / v) * v;
3220
+ if (axis[lidx].min)
3221
+ axis[lidx].min = Math.floor(axis[lidx].min / v) * v;
3222
+ }
3223
+ }
3224
+ if (axis[lidx].plots)
3225
+ for (var ii = 0; ii < axis[lidx].plots.length; ii++) {
3226
+ plots[axis[lidx].plots[ii]].max = axis[lidx].max;
3227
+ plots[axis[lidx].plots[ii]].min = axis[lidx].min;
3228
+ }
3229
+ }
3230
+ }
3231
+
3232
+ var pieces = [];
3233
+
3234
+ this.grid(env, pieces);
3235
+
3236
+ // DEP: *
3237
+ var deltaX = (opt.width - opt.margins[3] - opt.margins[1]) / (labels.length > 1 ? labels.length - 1 : 1);
3238
+ var deltaBarX = (opt.width - opt.margins[3] - opt.margins[1]) / (labels.length > 0 ? labels.length : 1);
3239
+
3240
+ for (serie in values) {
3241
+ props = common.areaProps(env, 'Series', serie);
3242
+ plot = plots[serie];
3243
+
3244
+ // TODO Settare una props in questo modo potrebbe incasinare la gestione degli update parziali (se iso "lineCenter: auto" e passo da un grafico con indexCenter = bar a uno con indexCenter = line)
3245
+ if (props.lineCenter && props.lineCenter == 'auto')
3246
+ props.lineCenter = (env.indexCenter == 'bar');
3247
+ else if (props.lineCenter && env.indexCenter == 'line')
3248
+ env.indexCenter = 'bar';
3249
+
3250
+ if (values[serie] && props.visible) {
3251
+ var deltaY = (opt.height - opt.margins[2] - opt.margins[0]) / (plot.max - plot.min);
3252
+
3253
+ if (props.type == 'line') {
3254
+ // LINE CHART
3255
+ var linePath = [ 'LINE', [], props.rounded ];
3256
+ var fillPath = [ 'LINEAREA', [], [], props.rounded ];
3257
+ var dotPieces = [];
3258
+
3259
+ for (i = 0, ii = labels.length; i < ii; i++)
3260
+ if (plot.to.length > i) {
3261
+ var indexProps = common.areaProps(env, 'Series', serie, i);
3262
+
3263
+ var d = plot.to[i] > plot.max ? plot.max : (plot.to[i] < plot.min ? plot.min : plot.to[i]);
3264
+ var x = Math.round((props.lineCenter ? deltaBarX / 2 : 0) + opt.margins[3] + i * (props.lineCenter ? deltaBarX : deltaX));
3265
+ var y = Math.round(opt.height - opt.margins[2] - deltaY * (d - plot.min));
3266
+ var dd = plot.from[i] > plot.max ? plot.max : (plot.from[i] < plot.min ? plot.min : plot.from[i]);
3267
+ var yy = Math.round(opt.height - opt.margins[2] - deltaY * (dd - plot.min)) + ($.browser.msie ? 1 : 0);
3268
+
3269
+ linePath[1].push([x, y]);
3270
+
3271
+ if (props.fill) {
3272
+ fillPath[1].push([x, y]);
3273
+ fillPath[2].push([x, yy]);
3274
+ }
3275
+ if (indexProps.dot) {
3276
+ if (values[serie][i] == null && !indexProps.dotShowOnNull)
3277
+ dotPieces.push({path : false, attr : false});
3278
+ else
3279
+ dotPieces.push({path : [ [ 'CIRCLE', x, y, indexProps.dotProps.size ] ], attr : indexProps.dotProps}); // TODO Size should not be in dotProps (not an svg props)
3280
+ }
3281
+ }
3282
+
3283
+ if (props.fill)
3284
+ pieces.push({ section : 'Series', serie : serie, subSection : 'Fill', path : [ fillPath ], attr : props.fillProps });
3285
+ else
3286
+ pieces.push({ section : 'Series', serie : serie, subSection : 'Fill', path : false, attr : false });
3287
+ pieces.push({ section : 'Series', serie : serie, subSection : 'Plot', path : [ linePath ], attr : props.plotProps , mousearea : 'pathsteps'});
3288
+
3289
+ if (dotPieces.length)
3290
+ pieces.push({ section : 'Series', serie : serie, subSection : 'Dot', paths : dotPieces });
3291
+ else
3292
+ pieces.push({ section : 'Series', serie : serie, subSection : 'Dot', path : false, attr : false });
3293
+
3294
+ } else {
3295
+ pieceBar = [];
3296
+
3297
+ // BAR CHART
3298
+ for (i = 0, ii = labels.length; i < ii; i++)
3299
+ if (plot.to.length > i) {
3300
+ if (plot.from[i] != plot.to[i]) {
3301
+ var bwid = Math.floor((deltaBarX - opt.barMargins) / env.barno);
3302
+ var bpad = bwid * (100 - props.barWidthPerc) / 200;
3303
+ var boff = opt.barMargins / 2 + plot.barno * bwid;
3304
+
3305
+ var x1 = Math.floor(opt.margins[3] + i * deltaBarX + boff + bpad);
3306
+ var y1 = Math.round(opt.height - opt.margins[2] - deltaY * (plot.to[i] - plot.min));
3307
+ var y2 = Math.round(opt.height - opt.margins[2] - deltaY * (plot.from[i] - plot.min));
3308
+
3309
+ pieceBar.push({path : [ [ 'RECT', x1, y1, x1 + bwid - bpad * 2, y2 ] ], attr : props.plotProps });
3310
+ } else
3311
+ pieceBar.push({path : false, attr : false });
3312
+ }
3313
+
3314
+ if (pieceBar.length)
3315
+ pieces.push({ section : 'Series', serie : serie, subSection : 'Plot', paths: pieceBar, mousearea : 'paths' });
3316
+ else
3317
+ pieces.push({ section : 'Series', serie : serie, subSection : 'Plot', path: false, attr: false, mousearea : 'paths' });
3318
+ }
3319
+
3320
+ } else {
3321
+ // Grafico non visibile / senza dati, deve comunque inserire i piece vuoti (NELLO STESSO ORDINE SOPRA!)
3322
+ if (props.type == 'line')
3323
+ pieces.push({ section : 'Series', serie : serie, subSection : 'Fill', path : false, attr : false });
3324
+ pieces.push({ section : 'Series', serie : serie, subSection : 'Plot', path: false, attr: false, mousearea : 'paths' });
3325
+ if (props.type == 'line')
3326
+ pieces.push({ section : 'Series', serie : serie, subSection : 'Dot', path : false, attr : false });
3327
+ }
3328
+ }
3329
+ featuresmanager.beforeShow(env, pieces);
3330
+ common.show(env, pieces);
3331
+ featuresmanager.afterShow(env, pieces);
3332
+ return pieces;
3333
+ },
3334
+
3335
+ grid : function(env, pieces) {
3336
+
3337
+ // DEP: axis, [=> series, values], labels, margins, width, height, grid*
3338
+ if (common.executeIfChanged(env, ['values', 'series', 'axis', 'labels', 'margins', 'width', 'height', 'features.grid'])) {
3339
+ var opt = env.opt;
3340
+ var props = env.opt.features.grid;
3341
+ var paper = env.paper;
3342
+ var axis = env.axis;
3343
+ var labels = env.opt.labels;
3344
+ var deltaX = (opt.width - opt.margins[3] - opt.margins[1]) / (labels.length > 1 ? labels.length - 1 : 1);
3345
+ var deltaBarX = (opt.width - opt.margins[3] - opt.margins[1]) / (labels.length > 0 ? labels.length : 1);
3346
+ var i, j, x, y, lw, labx, laby, labe, val, txt;
3347
+ // Label X axis
3348
+ var paths = [];
3349
+ var labelsCenter = props.labelsCenter;
3350
+ if (labelsCenter == 'auto')
3351
+ labelsCenter = (env.indexCenter == 'bar');
3352
+
3353
+ if (axis.x && axis.x.props.labels) {
3354
+ // used in case of labelsHideCovered, contains a "rotated" representation of the rect coordinates occupied by the last shown label
3355
+ var lastShownLabelRect = false;
3356
+ // labelsAnchor is "auto" by default. Can be "start","middle" or "end". If "auto" then it is automatically set depending on labelsRotate.
3357
+ var labelsAnchor = axis.x.props.labelsAnchor || 'auto';
3358
+ // Automatic labelsAnchor is "middle" on no rotation, otherwise the anchor is the higher side of the label.
3359
+ if (labelsAnchor == 'auto')
3360
+ labelsAnchor = axis.x.props.labelsRotate > 0 ? "start" : (axis.x.props.labelsRotate == 0 ? "middle" : "end");
3361
+ // labelsPos is "auto" by default. Can be "start", "middle" or "end". If "auto" then it is automatically set depending on labelsCenter and labelsRotate and labelsAnchor.
3362
+ var labelsPos = axis.x.props.labelsPos || 'auto';
3363
+ // in labelsCenter (bar) it is middle when there is no rotation, equals to labelsAnchor on rotation.
3364
+ // in !labelsCenter (line) is is always 'start';
3365
+ if (labelsPos == 'auto')
3366
+ labelsPos = labelsCenter ? (axis.x.props.labelsRotate == 0 ? labelsAnchor : 'middle') : 'start';
3367
+
3368
+ for (i = 0; i < labels.length; i++)
3369
+ if ((typeof labels[i] != 'boolean' && labels[i] != null) || labels[i]) {
3370
+
3371
+ if (!axis.x.props.labelsSkip || i >= axis.x.props.labelsSkip) {
3372
+ val = labels[i];
3373
+
3374
+ if (axis.x.props.labelsFormatHandler)
3375
+ val = axis.x.props.labelsFormatHandler(val);
3376
+ txt = (axis.x.props.prefix ? axis.x.props.prefix : "") + val + (axis.x.props.suffix ? axis.x.props.suffix : "");
3377
+
3378
+ labx = opt.margins[3] + i * (labelsCenter ? deltaBarX : deltaX) + (axis.x.props.labelsMargin ? axis.x.props.labelsMargin : 0);
3379
+ if (labelsPos == 'middle') labx += (labelsCenter ? deltaBarX : deltaX) / 2;
3380
+ if (labelsPos == 'end') labx += (labelsCenter ? deltaBarX : deltaX);
3381
+
3382
+ laby = opt.height - opt.margins[2] + axis.x.props.labelsDistance;
3383
+ labe = paper.text(labx, laby, txt).attr(axis.x.props.labelsProps).toBack();
3384
+
3385
+ labe.attr({"text-anchor" : labelsAnchor});
3386
+
3387
+ // will contain the boundingbox size, or false if it is hidden.
3388
+ var boundingbox = false;
3389
+ var bbox = labe.getBBox();
3390
+ var p1 = {x: bbox.x, y: bbox.y};
3391
+ var p2 = {x: bbox.x+bbox.width, y: bbox.y+bbox.height};
3392
+ var o1 = {x: labx, y: laby};
3393
+
3394
+ rotate = function (p, rad) {
3395
+ var X = p.x * Math.cos(rad) - p.y * Math.sin(rad),
3396
+ Y = p.x * Math.sin(rad) + p.y * Math.cos(rad);
3397
+ return {x: X, y: Y};
3398
+ };
3399
+ // calculate collision between non rotated rects with vertext p1-p2 and t1-t2
3400
+ // this algorythm works only for horizontal rects (alpha = 0)
3401
+ // "dist" is the length added as a margin to the rects before collision detection
3402
+ collide = function(r1,r2,dist) {
3403
+ xor = function(a,b) {
3404
+ return ( a || b ) && !( a && b );
3405
+ }
3406
+ if (r1.alpha != r2.alpha) throw "collide doens't support rects with different rotations";
3407
+ var r1p1r = rotate({x: r1.p1.x-dist, y:r1.p1.y-dist}, -r1.alpha);
3408
+ var r1p2r = rotate({x: r1.p2.x+dist, y:r1.p2.y+dist}, -r1.alpha);
3409
+ var r2p1r = rotate({x: r2.p1.x-dist, y:r2.p1.y-dist}, -r2.alpha);
3410
+ var r2p2r = rotate({x: r2.p2.x+dist, y:r2.p2.y+dist}, -r2.alpha);
3411
+ return !xor(Math.min(r1p1r.x,r1p2r.x) > Math.max(r2p1r.x,r2p2r.x), Math.max(r1p1r.x,r1p2r.x) < Math.min(r2p1r.x,r2p2r.x)) &&
3412
+ !xor(Math.min(r1p1r.y,r1p2r.y) > Math.max(r2p1r.y,r2p2r.y), Math.max(r1p1r.y,r1p2r.y) < Math.min(r2p1r.y,r2p2r.y));
3413
+ }
3414
+ // compute equivalent orizontal rotated rect
3415
+ rotated = function(rect, origin, alpha) {
3416
+ translate = function (p1, p2) {
3417
+ return {x: p1.x+p2.x, y: p1.y+p2.y};
3418
+ };
3419
+ negate = function(p1) {
3420
+ return {x: -p1.x, y: -p1.y};
3421
+ };
3422
+ var p1trt = translate(rotate(translate(rect.p1,negate(origin)), alpha),origin);
3423
+ var p2trt = translate(rotate(translate(rect.p2,negate(origin)), alpha),origin);
3424
+ return { p1: p1trt, p2: p2trt, alpha: rect.alpha+alpha };
3425
+ }
3426
+ bbox = function(rect) {
3427
+ if (rect.alpha == 0) {
3428
+ return { x: rect.p1.x, y: rect.p1.y, width: rect.p2.x-rect.p1.x, height: rect.p2.y-rect.p1.y };
3429
+ } else {
3430
+ var points = [];
3431
+ points.push({ x: 0, y: 0 });
3432
+ points.push({ x: rect.p2.x-rect.p1.x, y: 0 });
3433
+ points.push({ x: 0, y: rect.p2.y-rect.p1.y });
3434
+ points.push({ x: rect.p2.x-rect.p1.x, y: rect.p2.y-rect.p1.y });
3435
+ var bb = [];
3436
+ bb['left'] = 0; bb['right'] = 0; bb['top'] = 0; bb['bottom'] = 0;
3437
+ for (_px = 0; _px < points.length; _px++) {
3438
+ var p = points[_px];
3439
+ var newX = parseInt((p.x * Math.cos(rect.alpha)) + (p.y * Math.sin(rect.alpha)));
3440
+ var newY = parseInt((p.x * Math.sin(rect.alpha)) + (p.y * Math.cos(rect.alpha)));
3441
+ bb['left'] = Math.min(bb['left'], newX);
3442
+ bb['right'] = Math.max(bb['right'], newX);
3443
+ bb['top'] = Math.min(bb['top'], newY);
3444
+ bb['bottom'] = Math.max(bb['bottom'], newY);
3445
+ }
3446
+ var newWidth = parseInt(Math.abs(bb['right'] - bb['left']));
3447
+ var newHeight = parseInt(Math.abs(bb['bottom'] - bb['top']));
3448
+ var newX = ((rect.p1.x + rect.p2.x) / 2) - newWidth / 2;
3449
+ var newY = ((rect.p1.y + rect.p2.y) / 2) - newHeight / 2;
3450
+ return { x: newX, y: newY, width: newWidth, height: newHeight };
3451
+ }
3452
+ }
3453
+
3454
+ var alpha = Raphael.rad(axis.x.props.labelsRotate);
3455
+ // compute used "rect" so to be able to check if there is overlapping with previous ones.
3456
+ var rect = rotated({p1: p1, p2: p2, alpha: 0}, o1, alpha);
3457
+
3458
+ //console.log('bbox ',p1, p2, rect, props.nx, val, rect.p1, rect.p2, rect.alpha, boundingbox, opt.width);
3459
+ // se collide con l'ultimo mostrato non lo mostro.
3460
+ var dist = axis.x.props.labelsMarginRight ? axis.x.props.labelsMarginRight / 2 : 0;
3461
+ if (axis.x.props.labelsHideCovered && lastShownLabelRect && collide(rect, lastShownLabelRect, dist)) {
3462
+ labe.hide();
3463
+ labels[i] = false;
3464
+ } else {
3465
+ boundingbox = bbox(rect);
3466
+ // Manage label overflow
3467
+ if (props.nx == 'auto' && (boundingbox.x < 0 || boundingbox.x+boundingbox.width > opt.width)) {
3468
+ labe.hide();
3469
+ labels[i] = false;
3470
+ } else {
3471
+ lastShownLabelRect = rect;
3472
+ }
3473
+ }
3474
+
3475
+ // Apply rotation to the element.
3476
+ if (axis.x.props.labelsRotate) {
3477
+ labe.rotate(axis.x.props.labelsRotate, labx, laby).toBack();
3478
+ }
3479
+
3480
+ paths.push({ path : [ [ 'RELEMENT', labe ] ], attr : false });
3481
+ }
3482
+ }
3483
+ }
3484
+ pieces.push({ section : 'Axis', serie : 'x', subSection : 'Label', paths : paths });
3485
+
3486
+ // Title X Axis
3487
+ if (axis.x && axis.x.props.title) {
3488
+ x = opt.margins[3] + Math.floor((opt.width - opt.margins[1] - opt.margins[3]) / 2);
3489
+ y = opt.height - opt.margins[2] + axis.x.props.titleDistance * ($.browser.msie ? axis.x.props.titleDistanceIE : 1);
3490
+ //paper.text(x, y, axis.x.props.title).attr(axis.x.props.titleProps);
3491
+ pieces.push({ section : 'Axis', serie : 'x', subSection : 'Title', path : [ [ 'TEXT', axis.x.props.title, x, y ] ], attr : axis.x.props.titleProps });
3492
+ } else
3493
+ pieces.push({ section : 'Axis', serie : 'x', subSection : 'Title', path : false, attr : false });
3494
+
3495
+ // Label + Title L/R Axis
3496
+ for (var jj in ['l', 'r']) {
3497
+ j = ['l', 'r'][jj];
3498
+ if (axis[j] && axis[j].props.labels && props.ny) {
3499
+ paths = [];
3500
+ for (i = axis[j].props.labelsSkip ? axis[j].props.labelsSkip : 0; i <= props.ny; i++) {
3501
+ var deltaY = (opt.height - opt.margins[2] - opt.margins[0]) / props.ny;
3502
+ if (j == 'r') {
3503
+ labx = opt.width - opt.margins[1] + axis[j].props.labelsDistance;
3504
+ if (!axis[j].props.labelsProps["text-anchor"])
3505
+ axis[j].props.labelsProps["text-anchor"] = "start";
3506
+ } else {
3507
+ labx = opt.margins[3] - axis[j].props.labelsDistance;
3508
+ if (!axis[j].props.labelsProps["text-anchor"])
3509
+ axis[j].props.labelsProps["text-anchor"] = "end";
3510
+ }
3511
+ if (axis[j].props.labelsAnchor && axis[j].props.labelsAnchor != 'auto')
3512
+ axis[j].props.labelsProps["text-anchor"] = axis[j].props.labelsAnchor;
3513
+ // NOTE: Parenthesis () around division are useful to keep right number precision
3514
+ val = (axis[j].min + (i * ((axis[j].max - axis[j].min) / props.ny)));
3515
+ // Rounding with proper precision for "number sharpening"
3516
+ if (axis[j].normalizationBase)
3517
+ // I use (1 / ( 1 / norm ) ) to avoid some noise
3518
+ val = Math.round(val / axis[j].normalizationBase) / ( 1 / axis[j].normalizationBase );
3519
+
3520
+ if (axis[j].props.labelsFormatHandler)
3521
+ val = axis[j].props.labelsFormatHandler(val);
3522
+ if (axis[j].props.labelsCompactUnits)
3523
+ val = common.compactUnits(val, axis[j].props.labelsCompactUnits);
3524
+ txt = (axis[j].props.prefix ? axis[j].props.prefix : "") + val + (axis[j].props.suffix ? axis[j].props.suffix : "");
3525
+ laby = opt.height - opt.margins[2] - i * deltaY;
3526
+ //var labe = paper.text(labx, laby + (axis[j].props.labelsMargin ? axis[j].props.labelsMargin : 0), txt).attr(axis[j].props.labelsProps).toBack();
3527
+ paths.push( { path : [ [ 'TEXT', txt, labx, laby + (axis[j].props.labelsMargin ? axis[j].props.labelsMargin : 0) ] ], attr : axis[j].props.labelsProps });
3528
+ }
3529
+ pieces.push({ section : 'Axis', serie : j, subSection : 'Label', paths : paths });
3530
+ } else
3531
+ pieces.push({ section : 'Axis', serie : j, subSection : 'Label', paths : [] });
3532
+
3533
+ if (axis[j] && axis[j].props.title) {
3534
+ if (j == 'r')
3535
+ x = opt.width - opt.margins[1] + axis[j].props.titleDistance * ($.browser.msie ? axis[j].props.titleDistanceIE : 1);
3536
+ else
3537
+ x = opt.margins[3] - axis[j].props.titleDistance * ($.browser.msie ? axis[j].props.titleDistanceIE : 1);
3538
+ //paper.text(x, opt.margins[0] + Math.floor((opt.height - opt.margins[0] - opt.margins[2]) / 2), axis[j].props.title).attr(axis[j].props.titleProps).attr({rotation : j == 'l' ? 270 : 90});
3539
+ var attr = common._clone(axis[j].props.titleProps);
3540
+ attr.rotation = j == 'l' ? 270 : 90
3541
+ pieces.push({ section : 'Axis', serie : j, subSection : 'Title', path : [ [ 'TEXT', axis[j].props.title, x, opt.margins[0] + Math.floor((opt.height - opt.margins[0] - opt.margins[2]) / 2) ] ], attr : attr });
3542
+ } else
3543
+ pieces.push({ section : 'Axis', serie : j, subSection : 'Title', path : false, attr : false });
3544
+ }
3545
+
3546
+ // Grid
3547
+ if (props.nx || props.ny) {
3548
+ var path = [], bandsH = [], bandsV = [],
3549
+ nx = props.nx == 'auto' ? (labelsCenter ? labels.length : labels.length - 1) : props.nx,
3550
+ ny = props.ny,
3551
+ rowHeight = (opt.height - opt.margins[2] - opt.margins[0]) / (ny ? ny : 1),
3552
+ columnWidth = (opt.width - opt.margins[1] - opt.margins[3]) / (nx ? nx : 1),
3553
+ forceBorderX1 = typeof props.forceBorder == 'object' ? props.forceBorder[3] : props.forceBorder,
3554
+ forceBorderX2 = typeof props.forceBorder == 'object' ? props.forceBorder[1] : props.forceBorder,
3555
+ forceBorderY1 = typeof props.forceBorder == 'object' ? props.forceBorder[0] : props.forceBorder,
3556
+ forceBorderY2 = typeof props.forceBorder == 'object' ? props.forceBorder[2] : props.forceBorder,
3557
+ drawH = ny > 0 ? (typeof props.draw == 'object' ? props.draw[0] : props.draw) : false,
3558
+ drawV = nx > 0 ? typeof props.draw == 'object' ? props.draw[1] : props.draw : false;
3559
+
3560
+ if (ny > 0)
3561
+ for (i = 0; i < ny + 1; i++) {
3562
+ if (
3563
+ forceBorderY1 && i == 0 || // Show top line only if forced
3564
+ forceBorderY2 && i == ny || // Show bottom line only if forced
3565
+ drawH && i > 0 && i < ny // Show other lines if draw = true
3566
+ ) {
3567
+ path.push(["M", opt.margins[3] - props.extra[3], opt.margins[0] + Math.round(i * rowHeight) ]);
3568
+ path.push(["L", opt.width - opt.margins[1] + props.extra[1], opt.margins[0] + Math.round(i * rowHeight)]);
3569
+ }
3570
+ if (i < ny) {
3571
+ if (i % 2 == 0 && props.evenHProps || i % 2 == 1 && props.oddHProps)
3572
+ bandsH.push({path : [ [ 'RECT',
3573
+ opt.margins[3] - props.extra[3], opt.margins[0] + Math.round(i * rowHeight), // x1, y1
3574
+ opt.width - opt.margins[1] + props.extra[1], opt.margins[0] + Math.round((i + 1) * rowHeight) // x2, y2
3575
+ ] ], attr : i % 2 == 0 ? props.evenHProps : props.oddHProps });
3576
+ else
3577
+ bandsH.push({ path : false, attr: false})
3578
+ }
3579
+ }
3580
+
3581
+ for (i = 0; i < nx + 1; i++) {
3582
+ if (
3583
+ forceBorderX1 && i == 0 || // Always show first line if forced
3584
+ forceBorderX2 && i == nx || // Always show last line if forced
3585
+ drawV && ( // To show other lines draw must be true
3586
+ (props.nx != 'auto' && i > 0 && i < nx) || // If nx = [number] show other lines (first and last are managed above with forceBorder)
3587
+ (props.nx == 'auto' && (typeof labels[i] != 'boolean' || labels[i])) // if nx = 'auto' show all lines if a label is associated
3588
+ )
3589
+ // Show all lines if props.nx is a number, or if label != false, AND draw must be true
3590
+ ) {
3591
+ path.push(["M", opt.margins[3] + Math.round(i * columnWidth), opt.margins[0] - props.extra[0] ]); //(t ? props.extra[0] : 0)]);
3592
+ path.push(["L", opt.margins[3] + Math.round(i * columnWidth), opt.height - opt.margins[2] + props.extra[2] ]); //(t ? props.extra[2] : 0)]);
3593
+ }
3594
+ if (i < nx) {
3595
+ if (i % 2 == 0 && props.evenVProps || i % 2 == 1 && props.oddVProps)
3596
+ bandsV.push({path : [ [ 'RECT',
3597
+ opt.margins[3] + Math.round(i * columnWidth), opt.margins[0] - props.extra[0], // x1, y1
3598
+ opt.margins[3] + Math.round((i + 1) * columnWidth), opt.height - opt.margins[2] + props.extra[2], // x2, y2
3599
+ ] ], attr : i % 2 == 0 ? props.evenVProps : props.oddVProps });
3600
+ else
3601
+ bandsV.push({ path : false, attr: false})
3602
+ }
3603
+ }
3604
+
3605
+ pieces.push({ section : 'Grid', path : path.length ? path : false, attr : path.length ? props.props : false });
3606
+ pieces.push({ section : 'GridBandH', paths : bandsH });
3607
+ pieces.push({ section : 'GridBandV', paths : bandsV });
3608
+
3609
+ var tpath = [];
3610
+
3611
+ // Ticks asse X
3612
+ if (props.ticks.active && (typeof props.ticks.active != 'object' || props.ticks.active[0])) {
3613
+ for (i = 0; i < nx + 1; i++) {
3614
+ if (props.nx != 'auto' || typeof labels[i] != 'boolean' || labels[i]) {
3615
+ tpath.push(["M", opt.margins[3] + Math.round(i * columnWidth), opt.height - opt.margins[2] - props.ticks.size[1] ]);
3616
+ tpath.push(["L", opt.margins[3] + Math.round(i * columnWidth), opt.height - opt.margins[2] + props.ticks.size[0] ]);
3617
+ }
3618
+ }
3619
+ }
3620
+ // Ticks asse L
3621
+ if (props.ticks.active && (typeof props.ticks.active != 'object' || props.ticks.active[1]))
3622
+ for (i = 0; i < ny + 1; i++) {
3623
+ tpath.push(["M", opt.margins[3] - props.ticks.size[0], opt.margins[0] + Math.round(i * rowHeight) ]);
3624
+ tpath.push(["L", opt.margins[3] + props.ticks.size[1], opt.margins[0] + Math.round(i * rowHeight)]);
3625
+ }
3626
+ // Ticks asse R
3627
+ if (props.ticks.active && (typeof props.ticks.active != 'object' || props.ticks.active[2]))
3628
+ for (i = 0; i < ny + 1; i++) {
3629
+ tpath.push(["M", opt.width - opt.margins[1] - props.ticks.size[1], opt.margins[0] + Math.round(i * rowHeight) ]);
3630
+ tpath.push(["L", opt.width - opt.margins[1] + props.ticks.size[0], opt.margins[0] + Math.round(i * rowHeight)]);
3631
+ }
3632
+
3633
+ pieces.push({ section : 'Ticks', path : tpath.length ? tpath : false, attr : tpath.length ? props.ticks.props : false });
3634
+ }
3635
+ }
3636
+ }
3637
+ }
3638
+
3639
+ })(jQuery);
3640
+ /********* Source File: src/elycharts_chart_pie.js*********/
3641
+ /**********************************************************************
3642
+ * ELYCHARTS
3643
+ * A Javascript library to generate interactive charts with vectorial graphics.
3644
+ *
3645
+ * Copyright (c) 2010 Void Labs s.n.c. (http://void.it)
3646
+ * Licensed under the MIT (http://creativecommons.org/licenses/MIT/) license.
3647
+ **********************************************************************/
3648
+
3649
+ (function($) {
3650
+
3651
+ var featuresmanager = $.elycharts.featuresmanager;
3652
+ var common = $.elycharts.common;
3653
+
3654
+ /***********************************************************************
3655
+ * CHART: PIE
3656
+ **********************************************************************/
3657
+
3658
+ $.elycharts.pie = {
3659
+ init : function($env) {
3660
+ },
3661
+
3662
+ draw : function(env) {
3663
+ //var paper = env.paper;
3664
+ var opt = env.opt;
3665
+
3666
+ var w = env.opt.width;
3667
+ var h = env.opt.height;
3668
+ var r = env.opt.r ? env.opt.r : Math.floor((w < h ? w : h) / 2);
3669
+ var cx = env.opt.cx ? env.opt.cx : Math.floor(w / 2);
3670
+ var cy = env.opt.cy ? env.opt.cx : Math.floor(h / 2);
3671
+
3672
+ var cnt = 0, i, ii, serie, plot, props;
3673
+ for (serie in opt.values) {
3674
+ plot = {
3675
+ visible : false,
3676
+ total : 0,
3677
+ values : []
3678
+ };
3679
+ env.plots[serie] = plot;
3680
+ var serieProps = common.areaProps(env, 'Series', serie);
3681
+ if (serieProps.visible) {
3682
+ plot.visible = true;
3683
+ cnt ++;
3684
+ plot.values = opt.values[serie];
3685
+ for (i = 0, ii = plot.values.length; i < ii; i++)
3686
+ if (plot.values[i] > 0) {
3687
+ props = common.areaProps(env, 'Series', serie, i);
3688
+ if (typeof props.inside == 'undefined' || props.inside < 0)
3689
+ plot.total += plot.values[i];
3690
+ }
3691
+ for (i = 0; i < ii; i++)
3692
+ if (plot.values[i] < plot.total * opt.valueThresold) {
3693
+ plot.total = plot.total - plot.values[i];
3694
+ plot.values[i] = 0;
3695
+ }
3696
+ }
3697
+ }
3698
+
3699
+ var rstep = r / cnt;
3700
+ var rstart = -rstep, rend = 0;
3701
+
3702
+ var pieces = [];
3703
+ for (serie in opt.values) {
3704
+ plot = env.plots[serie];
3705
+ var paths = [];
3706
+ if (plot.visible) {
3707
+ rstart += rstep;
3708
+ rend += rstep;
3709
+ var angle = env.opt.startAngle, angleplus = 0, anglelimit = 0;
3710
+
3711
+ if (plot.total == 0) {
3712
+ env.emptySeries = true;
3713
+ props = common.areaProps(env, 'Series', 'empty');
3714
+ paths.push({ path : [ [ 'CIRCLE', cx, cy, r ] ], attr : props.plotProps });
3715
+
3716
+ } else {
3717
+ env.emptySeries = false;
3718
+ for (i = 0, ii = plot.values.length; i < ii; i++) {
3719
+ var value = plot.values[i];
3720
+ if (value > 0) {
3721
+ props = common.areaProps(env, 'Series', serie, i);
3722
+ if (typeof props.inside == 'undefined' || props.inside < 0) {
3723
+ angle += anglelimit;
3724
+ angleplus = 360 * value / plot.total;
3725
+ anglelimit = angleplus;
3726
+ } else {
3727
+ angleplus = 360 * values[props.inside] / plot.total * value / values[props.inside];
3728
+ }
3729
+ var rrstart = rstart, rrend = rend;
3730
+ if (props.r) {
3731
+ if (props.r > 0) {
3732
+ if (props.r <= 1)
3733
+ rrend = rstart + rstep * props.r;
3734
+ else
3735
+ rrend = rstart + props.r;
3736
+ } else {
3737
+ if (props.r >= -1)
3738
+ rrstart = rstart + rstep * (-props.r);
3739
+ else
3740
+ rrstart = rstart - props.r;
3741
+ }
3742
+ }
3743
+
3744
+ if (!env.opt.clockwise)
3745
+ paths.push({ path : [ [ 'SLICE', cx, cy, rrend, rrstart, angle, angle + angleplus ] ], attr : props.plotProps });
3746
+ else
3747
+ paths.push({ path : [ [ 'SLICE', cx, cy, rrend, rrstart, - angle - angleplus, - angle ] ], attr : props.plotProps });
3748
+ } else
3749
+ paths.push({ path : false, attr : false });
3750
+ }
3751
+ }
3752
+ } else {
3753
+ // Even if serie is not visible it's better to put some empty path (for better transitions). It's not mandatory, just better
3754
+ if (opt.values[serie] && opt.values[serie].length)
3755
+ for (i = 0, ii = opt.values[serie].length; i < ii; i++)
3756
+ paths.push({ path : false, attr : false });
3757
+ }
3758
+
3759
+ pieces.push({ section : 'Series', serie : serie, subSection : 'Plot', paths : paths , mousearea : 'paths'});
3760
+ }
3761
+
3762
+ featuresmanager.beforeShow(env, pieces);
3763
+ common.show(env, pieces);
3764
+ featuresmanager.afterShow(env, pieces);
3765
+ return pieces;
3766
+ }
3767
+ }
3768
+
3769
+ })(jQuery);