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