socmap_adf 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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);