socmap_adf 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +10 -0
- data/.rvmrc +81 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +17 -0
- data/MIT-LICENSE +20 -0
- data/README.md +3 -0
- data/Rakefile +36 -0
- data/lib/assets/.gitkeep +0 -0
- data/lib/assets/javascripts/.DS_Store +0 -0
- data/lib/assets/javascripts/socmap_adf/.DS_Store +0 -0
- data/lib/assets/javascripts/socmap_adf/init.js.coffee.erb +9 -0
- data/lib/assets/javascripts/socmap_adf/lib/adf_delegate.js.coffee +13 -0
- data/lib/assets/javascripts/socmap_adf/lib/adf_view.js.coffee +7 -0
- data/lib/assets/javascripts/socmap_adf/modules/.DS_Store +0 -0
- data/lib/assets/javascripts/socmap_adf/modules/cluster/init.js.coffee +11 -0
- data/lib/assets/javascripts/socmap_adf/modules/cluster/lib/elycharts.js +3769 -0
- data/lib/assets/javascripts/socmap_adf/modules/cluster/lib/raphael.js +5815 -0
- data/lib/assets/javascripts/socmap_adf/modules/cluster/templates/chart.jst.eco +6 -0
- data/lib/assets/javascripts/socmap_adf/modules/cluster/views/chart.js.coffee +107 -0
- data/lib/assets/javascripts/socmap_adf/modules/cluster/views/chart_icon.js.coffee +106 -0
- data/lib/assets/javascripts/socmap_adf/modules/cluster/views/cluster.js.coffee +127 -0
- data/lib/assets/javascripts/socmap_adf/modules/cluster/views/default_icon.js.coffee +170 -0
- data/lib/assets/javascripts/socmap_adf/modules/cluster/views/main.js.coffee +10 -0
- data/lib/assets/javascripts/socmap_adf/modules/cluster/views/marker_clusterer.js.coffee +358 -0
- data/lib/assets/javascripts/socmap_adf/modules/file_uploader/init.js.coffee +7 -0
- data/lib/assets/javascripts/socmap_adf/modules/file_uploader/templates/existing_file.jst.eco +10 -0
- data/lib/assets/javascripts/socmap_adf/modules/file_uploader/templates/file.jst.eco +3 -0
- data/lib/assets/javascripts/socmap_adf/modules/file_uploader/templates/main.jst.eco +7 -0
- data/lib/assets/javascripts/socmap_adf/modules/file_uploader/templates/uploading.jst.eco +3 -0
- data/lib/assets/javascripts/socmap_adf/modules/file_uploader/views/main.js.coffee +76 -0
- data/lib/assets/javascripts/socmap_adf/modules/form/init.js.coffee +9 -0
- data/lib/assets/javascripts/socmap_adf/modules/form/models/base.js.coffee +73 -0
- data/lib/assets/javascripts/socmap_adf/modules/form/models/error.js.coffee +12 -0
- data/lib/assets/javascripts/socmap_adf/modules/form/models/field_binder.js.coffee +104 -0
- data/lib/assets/javascripts/socmap_adf/modules/form/models/validator.js.coffee +65 -0
- data/lib/assets/javascripts/socmap_adf/modules/form/templates/error_field.jst.eco +7 -0
- data/lib/assets/javascripts/socmap_adf/modules/form/templates/field_set.jst.eco +6 -0
- data/lib/assets/javascripts/socmap_adf/modules/form/templates/field_set_button.jst.eco +1 -0
- data/lib/assets/javascripts/socmap_adf/modules/form/templates/field_sets.jst.eco +2 -0
- data/lib/assets/javascripts/socmap_adf/modules/form/views/base.js.coffee +9 -0
- data/lib/assets/javascripts/socmap_adf/modules/form/views/field_set.js.coffee +88 -0
- data/lib/assets/javascripts/socmap_adf/modules/form/views/field_set_with_button.js.coffee +38 -0
- data/lib/assets/javascripts/socmap_adf/modules/form/views/field_sets.js.coffee +81 -0
- data/lib/assets/javascripts/socmap_adf/modules/gmap/.DS_Store +0 -0
- data/lib/assets/javascripts/socmap_adf/modules/gmap/init.js.coffee +6 -0
- data/lib/assets/javascripts/socmap_adf/modules/gmap/views/.DS_Store +0 -0
- data/lib/assets/javascripts/socmap_adf/modules/gmap/views/custom_marker.js.coffee +36 -0
- data/lib/assets/javascripts/socmap_adf/modules/gmap/views/marker.js.coffee +72 -0
- data/lib/assets/javascripts/socmap_adf/modules/gmap/views/marker_with_label.js +566 -0
- data/lib/assets/javascripts/socmap_adf/modules/gmap/views/overlay.js.coffee +237 -0
- data/lib/assets/javascripts/socmap_adf/modules/gmap/views/overlay_view.js.coffee +143 -0
- data/lib/assets/javascripts/socmap_adf/modules/gmap/views/polygon.js.coffee +107 -0
- data/lib/assets/javascripts/socmap_adf/modules/image_uploader/init.js.coffee +7 -0
- data/lib/assets/javascripts/socmap_adf/modules/image_uploader/templates/main.jst.eco +10 -0
- data/lib/assets/javascripts/socmap_adf/modules/image_uploader/views/main.js.coffee +69 -0
- data/lib/assets/javascripts/socmap_adf/modules/map/.DS_Store +0 -0
- data/lib/assets/javascripts/socmap_adf/modules/map/init.js.coffee +9 -0
- data/lib/assets/javascripts/socmap_adf/modules/map/models/custom_map.js.coffee +1 -0
- data/lib/assets/javascripts/socmap_adf/modules/map/models/map.js.coffee +63 -0
- data/lib/assets/javascripts/socmap_adf/modules/map/templates/main.jst.eco +1 -0
- data/lib/assets/javascripts/socmap_adf/modules/map/templates/moving_pin.jst.eco +11 -0
- data/lib/assets/javascripts/socmap_adf/modules/map/templates/tooltip.jst.eco +1 -0
- data/lib/assets/javascripts/socmap_adf/modules/map/views/google_marker_clusterer.js.coffee +11 -0
- data/lib/assets/javascripts/socmap_adf/modules/map/views/main.js.coffee +79 -0
- data/lib/assets/javascripts/socmap_adf/modules/map/views/moving_pin.js.coffee +47 -0
- data/lib/assets/javascripts/socmap_adf/modules/map/views/tooltip.js.coffee +46 -0
- data/lib/assets/javascripts/socmap_adf/modules/marker/init.js.coffee +6 -0
- data/lib/assets/javascripts/socmap_adf/modules/marker/views/.DS_Store +0 -0
- data/lib/assets/javascripts/socmap_adf/modules/marker/views/main.js.coffee +132 -0
- data/lib/assets/javascripts/socmap_adf/modules/minimap/init.js.coffee +9 -0
- data/lib/assets/javascripts/socmap_adf/modules/minimap/models/minimap.js.coffee +36 -0
- data/lib/assets/javascripts/socmap_adf/modules/minimap/templates/moving_pin.jst.eco +11 -0
- data/lib/assets/javascripts/socmap_adf/modules/minimap/templates/tooltip.jst.eco +1 -0
- data/lib/assets/javascripts/socmap_adf/modules/minimap/views/main.js.coffee +68 -0
- data/lib/assets/javascripts/socmap_adf/modules/minimap/views/moving_pin.js.coffee +55 -0
- data/lib/assets/javascripts/socmap_adf/modules/minimap/views/tooltip.js.coffee +47 -0
- data/lib/assets/javascripts/socmap_adf/modules/mvc/init.js.coffee +6 -0
- data/lib/assets/javascripts/socmap_adf/modules/mvc/views/base.js.coffee +5 -0
- data/lib/assets/javascripts/socmap_adf/modules/overlay/.DS_Store +0 -0
- data/lib/assets/javascripts/socmap_adf/modules/overlay/init.js.coffee +10 -0
- data/lib/assets/javascripts/socmap_adf/modules/overlay/models/overlay.js.coffee +4 -0
- data/lib/assets/javascripts/socmap_adf/modules/overlay/templates/main.jst.eco +1 -0
- data/lib/assets/javascripts/socmap_adf/modules/overlay/templates/polygon_label.jst.eco +1 -0
- data/lib/assets/javascripts/socmap_adf/modules/overlay/views/.DS_Store +0 -0
- data/lib/assets/javascripts/socmap_adf/modules/overlay/views/main.js.coffee +6 -0
- data/lib/assets/javascripts/socmap_adf/modules/overlay/views/overlay.js.coffee +55 -0
- data/lib/assets/javascripts/socmap_adf/modules/overlay/views/polygon_label.js.coffee +17 -0
- data/lib/assets/javascripts/socmap_adf/modules/overlay_push/init.js.coffee +8 -0
- data/lib/assets/javascripts/socmap_adf/modules/overlay_push/templates/colibration.jst.eco +4 -0
- data/lib/assets/javascripts/socmap_adf/modules/overlay_push/views/new.js.coffee +32 -0
- data/lib/assets/javascripts/socmap_adf/modules/popup/init.js.coffee +7 -0
- data/lib/assets/javascripts/socmap_adf/modules/popup/templates/base.jst.eco +5 -0
- data/lib/assets/javascripts/socmap_adf/modules/popup/templates/basic.jst.eco +5 -0
- data/lib/assets/javascripts/socmap_adf/modules/popup/views/base.js.coffee +98 -0
- data/lib/assets/javascripts/socmap_adf/modules/popup/views/basic.js.coffee +86 -0
- data/lib/assets/javascripts/socmap_adf/modules/sidebar/collections/empty +0 -0
- data/lib/assets/javascripts/socmap_adf/modules/sidebar/init.js.coffee +11 -0
- data/lib/assets/javascripts/socmap_adf/modules/sidebar/models/slice.js.coffee +0 -0
- data/lib/assets/javascripts/socmap_adf/modules/sidebar/templates/bottomlink.jst.eco +1 -0
- data/lib/assets/javascripts/socmap_adf/modules/sidebar/templates/bottomlinkaction.jst.eco +2 -0
- data/lib/assets/javascripts/socmap_adf/modules/sidebar/templates/content.jst.eco +2 -0
- data/lib/assets/javascripts/socmap_adf/modules/sidebar/templates/sidebar.jst.eco +3 -0
- data/lib/assets/javascripts/socmap_adf/modules/sidebar/templates/tab.jst.eco +3 -0
- data/lib/assets/javascripts/socmap_adf/modules/sidebar/templates/tabs.jst.eco +3 -0
- data/lib/assets/javascripts/socmap_adf/modules/sidebar/views/bottomlink.js.coffee +41 -0
- data/lib/assets/javascripts/socmap_adf/modules/sidebar/views/content.js.coffee +63 -0
- data/lib/assets/javascripts/socmap_adf/modules/sidebar/views/sidebar.js.coffee +163 -0
- data/lib/assets/javascripts/socmap_adf/modules/sidebar/views/tab.js.coffee +52 -0
- data/lib/assets/javascripts/socmap_adf/modules/sidebar/views/tabcontent.js.coffee +23 -0
- data/lib/assets/javascripts/socmap_adf/modules/sidebar/views/tabs.js.coffee +63 -0
- data/lib/assets/javascripts/socmap_adf/modules/zone/collections/points.js.coffee +1 -0
- data/lib/assets/javascripts/socmap_adf/modules/zone/collections/zones.js.coffee +2 -0
- data/lib/assets/javascripts/socmap_adf/modules/zone/init.js.coffee +11 -0
- data/lib/assets/javascripts/socmap_adf/modules/zone/models/polygon.js.coffee +72 -0
- data/lib/assets/javascripts/socmap_adf/modules/zone/templates/main.jst.eco +0 -0
- data/lib/assets/javascripts/socmap_adf/modules/zone/views/main.js.coffee +6 -0
- data/lib/assets/javascripts/socmap_adf/modules/zone/views/test.js.coffee +17 -0
- data/lib/assets/javascripts/socmap_adf/requiress.js.coffee.erb +3 -0
- data/lib/generators/install_generator.rb +15 -0
- data/lib/generators/templates/socmap.rb.erb +9 -0
- data/lib/socmap_adf/engine.rb +5 -0
- data/lib/socmap_adf/version.rb +3 -0
- data/lib/socmap_adf.rb +17 -0
- data/lib/tasks/socmap-adf_tasks.rake +4 -0
- data/socmap_adf.gemspec +26 -0
- data/test/socmap-adf_test.rb +7 -0
- data/test/test_helper.rb +15 -0
- 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);
|