├── LICENSE.md
├── README.md
├── bin
└── build.sh
├── dist
├── elycharts-full.js
├── elycharts-full.min.js
├── elycharts.js
└── elycharts.min.js
├── docs
├── changelog_en.txt
├── changelog_it.txt
├── demo.html
├── demo_2.html
└── demo_3.html
├── index.html
├── lib
├── DP_Debug.js
├── jquery.js
└── raphael.js
├── pom.xml
├── resources
└── header.js
└── src
├── elycharts_chart_barline.js
├── elycharts_chart_funnel.js
├── elycharts_chart_line.js
├── elycharts_chart_pie.js
├── elycharts_core.js
├── elycharts_defaults.js
├── elycharts_manager_anchor.js
├── elycharts_manager_animation.js
├── elycharts_manager_balloon.js
├── elycharts_manager_highlight.js
├── elycharts_manager_label.js
├── elycharts_manager_legend.js
├── elycharts_manager_mouse.js
├── elycharts_manager_shadow.js
└── elycharts_manager_tooltip.js
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # elycharts
2 |
3 | Released under the [MIT License](http://en.wikipedia.org/wiki/MIT_License)
4 |
5 | Copyright (c) 2010-2014 Void Labs s.n.c.
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in
15 | all copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # elycharts
2 | Interactive Javascript (SVG|VML) Charting Library
3 |
4 | A Javascript library to generate interactive charts with vectorial graphics (SVG/VML) and a lot of useful features.
5 |
6 | Requires: Raphaël 1.5+, jQuery1.4 Since v2.1.4 is also compatible with: Raphael 2.0/2.1 and jQuery up to 1.10
7 |
8 | Last Stable Version v2.1.5 (2014/02/19)
9 |
--------------------------------------------------------------------------------
/bin/build.sh:
--------------------------------------------------------------------------------
1 | #/bin/sh
2 |
3 | cat src/elycharts_defaults.js src/elycharts_core.js src/elycharts_manager_anchor.js src/elycharts_manager_animation.js src/elycharts_manager_highlight.js src/elycharts_manager_label.js src/elycharts_manager_legend.js src/elycharts_manager_mouse.js src/elycharts_manager_tooltip.js src/elycharts_chart_line.js src/elycharts_chart_pie.js > dist/elycharts.js
4 | yui-compressor dist/elycharts.js -o dist/elycharts.min.js
5 | cat src/elycharts_defaults.js src/elycharts_core.js src/elycharts_manager_* src/elycharts_chart_* > dist/elycharts-full.js
6 | yui-compressor dist/elycharts-full.js -o dist/elycharts-full.min.js
7 |
8 |
--------------------------------------------------------------------------------
/docs/changelog_en.txt:
--------------------------------------------------------------------------------
1 | v2.1.6-SNAPSHOT
2 | - fixed round rects translation (move svg path with relative commands): it happened in rounded legend dots
3 |
4 | v2.1.5 (2014-02-19)
5 | - fixed support for animations for charts with null values
6 | - added support for null values (avgOverNulls: false) in line charts
7 | - changed stepAnimation by adding the "active" parameter to be enabled, otherwise ignored (Issue #35)
8 | - fixed stepAnimation to not be enabled if stepAnimation is declared to false (Issue #35)
9 | - rewritten the update logic to work even without animation manager and to deal with partial updates (Issue #36)
10 | - fixed labels visibility un update (they were hidden but never made visibile on update if needed)
11 | - fixed legend rewriting/updating (Issue #38)
12 | - fixed support for roundedCorners in legend "dots" (adding support for "rounded rects" svg paths and fixing move method for 'Q').
13 | - fixed tooltip visiblity when some tooltip value is missing (compared to number of the serie values) (Issue #37)
14 | - updating values now recompute width/height and correctly adapt the paper and chart to the new size.
15 | - separate computed width from option.width (so empty width is correctly applied on update): plugins should now use env.width instead of env.opt.width.
16 | - added support for rPerc (radius expressed in percentage of available space) for pie charts.
17 | - changed pixelWorkAround to be enabled only on SVG (to be verified)
18 | - fixed tooltip (and mouse) management in IE compatible mode (Issue #10)
19 | - fixed erros when using "legend: false" or legend without margin definitions (Issue #14)
20 | - added support for valuesPalette and seriesPalette feature to automatically assign colors starting from a cycling palette (Issue #9)
21 | - added support for single value coloring in bar charts (each column can be printed with a different color)
22 | - added caching for internal properties "inheritance" computation (enabled by default, disable by setting enableInternalCaching to false)
23 | - added "margins" support to pie chart and fixed cx/cy usage (cy was ignored in favor of cx only) (Issue #31)
24 | - rewrote "color" property inheritance to better deal with mixed line/bar charts, chart updates, have better performances and pie support (Issue #33)
25 | - rewrite "legend" properties management to simplify code (should not change the behaviour)
26 | - added "clear" method to featuresmanager so that features can be properly react to chart "clearing" (Issue #32 hint by pduval@github)
27 | - bar chart: inherit stroke color from serie color if not specified (Issue #30)
28 | - fixed width computation for mouse areas using mousearea: "index" option
29 | - added "barOverlapPerc" property to allow overlapping of columns for the same X in different series
30 | - update old copyright year references to 2010-2014
31 |
32 | v2.1.4 (2014-01-14)
33 | - fix compatibility with RaphaelJs 2.0+: .rotation attribute is no more available so axis titles were not rotated (Issue #27)
34 | - fix compatibility with jQuery 1.9+: $.browser.msie no more available. Switched to Raphael.VML, with the hope this was the intended check (Issue #28)
35 | - fix compatibility with Raphaeljs 2.0+: animations didn't work due to animateWith signature/behaviour changes (Issue #23)
36 | - fix for colors propagation from defaultSeries to single serie (Issue #11)
37 | - added "auto" modes for labelsAnchor and labelsPos so that most use cases it will simply set sensible values for them based on labelsCenter/labelsRotate
38 | - added support for labels hiding (for overlapping and *horizontal* overflow) also for rotated labels
39 | - various fixes for x labels. (mostly rewrote axis labels handling)
40 | - fix for "grid.nx" values when nx < ny and they are not "auto" (Issue #13)
41 | - highlight: improvement in stepAnimation management and overlayprops.
42 | - added support for function as tooltip value
43 |
44 | v2.1.3
45 | - changed default value to "false" for axis.labels
46 | - changed default value to "false" for series.dot
47 | - changed default value to "false" for features.grid.draw
48 | - changed default value to "4" for features.grid.ny
49 | - changed default value to "false" for features.grid.forceBorder
50 | - changed default value to "4" for features.legend.dotR
51 | - added support for command execution via $.chart("COMMAND"). Supported commands: config, clear
52 | - added support for null values in line charts (displayed with an average of near points)
53 | - added series.dotShowOnNull and series.mouseareaShowOnNull (default to false) to support null values and what to do with them
54 | - added features.grid.evenVProps, evenHProps, oddVProps, oddHProps to display grid bands
55 | - added offset tooltip option
56 | - added support for "style" option
57 | - highlight: added support for scale with dots, optimized scale properties to have only one numeric value (not array)
58 | - better configuration handling for templates and subsequent calls
59 | - fix in config colors normalization
60 | - better handling for values and labels (support for null/empty labels)
61 | - fix for labels overflow on X axis
62 | - pie chart: fixed support for serie.r < 0
63 | - fix for tooltip color/frameProps settings where specified with shortcut "serie.color"
64 | - line chart: fixed line chart not rounded
65 | - legend: fixed a lot (was broken in almost all configurations...)
66 | - line chart: changed the way labels are drawn and spaced on x axis (fix for labelsHideCovered)
67 |
68 | v2.1.2
69 | - support for series.empty.tooltip e series.empty.label
70 | - refactoring object visualization phase
71 | - support for "zindex" property, to set the order of the object. It should be specified in every "*Props" settings, like a SVG Attr
72 | - default zIndex for dots in line chart is "5" (so dots are shown above other objects)
73 | - fix #6: Using a simple line chart with a single serie and a single value in that serie breaks elychart.
74 | - cleanup
75 | - fix transitions
76 |
77 | v2.1.1
78 | - REFACTORING: true modular management, code split in several components
79 | - script to build library in single form and in minimized single form
80 | - fix rendering errors
81 | - fix highlight in hidden paths
82 | - fix color management in line chart
83 | - support for "valueThresold" option in pie chart
84 | - fix drawing 360 degrees pie slice
85 | - improvements in anchorManager for bind support (fix when transitions occours)
86 | - fix manager tooltip
87 | - line chart: support for rounded : Array, to set a different method of rounding ( [#, 2] is for method suggested by Bago )
88 | - fix in number precision and sharpening for axis min/max and label calculations [#4]
89 | - fix in reg animation with only 1 value
90 | - fix in label rendering when hiding all series and re-showing one [#1]
91 | - fix in funnel highlight animation [#2]
92 | - code cleanup
93 | - fix in line generation for series with only one value
94 | - moved option labelsCenter to features.grid.labelsCenter
95 | - support for features.mousearea.indexCenter (bar|line|auto). Improvement in serie.lineCenter and features.highlight.indexHighlight, features.grid.labelsCenter (both suppors "auto" value)
96 | - fixes in reg animation
97 | - fix empty pie animations
98 | - added option serie.tooltip.active
--------------------------------------------------------------------------------
/docs/changelog_it.txt:
--------------------------------------------------------------------------------
1 | This is no more updated, please look at the changelog_en.txt english changelog for newer changes.
2 |
3 | v2.1.2
4 | - supporto per series.empty.tooltip e series.empty.label
5 | - migliorie nella fase di visualizzazione degli oggetti
6 | - supporto per nuova proprietà "zindex" (da specificare in qualunque props SVG)
7 | - lo zindex di default per i "dots" nel grafico a linee è 5 (per mostrare i punti sopra gli altri oggetti)
8 | - fix line chart e problemi con serie di un solo valore [#6]
9 | - cleanup codice
10 | - fix transizioni
11 |
12 | v2.1.1
13 | - REFACTORING per gestione modulare effettiva, split del codice nei vari componenti
14 | - script per riunificazione e minimizzazione codice da distribuire
15 | - fix errore rendering
16 | - fix highlight con path nascosti
17 | - fix gestione colori in line chart
18 | - supporto opzione "valueThreshold" per pie chart
19 | - fix pie slice di 360 gradi
20 | - migliorie in anchorManager per gestione bind su elementi (fix in caso di transizioni)
21 | - fix manager tooltip
22 | - line chart: supporto per opzione "rounded" come array. [#, 2] e' per usare il metodo suggerito da Bago ( [#, 1] o solo # è il metodo standard)
23 | - fix in gestione precisione dei numeri in calcolo min/max degli assi e in view label [#4]
24 | - fix in animazione "reg" con serie di un solo valore
25 | - fix in visualizzazione label asse dopo aver nascosto tutte le serie e rivisualizzato una [#1]
26 | - fix in funnel highlight animation [#2]
27 | - cleanup codice
28 | - fix: generazione linea con un solo valore
29 | - spostata opzione labelsCenter in features.grid.labelsCenter
30 | - supporto per features.mousearea.indexCenter (bar|line|auto). Migliorie in serie.lineCenter e features.highlight.indexHighlight, features.grid.labelsCenter (entrambi supportano il valore "auto")
31 | - fix vari in animazione reg
32 | - fix animazioni con pie vuota
33 | - aggiunta opzione serie.tooltip.active
34 |
35 | v2.1.0
36 | - RENAME da elysia_charts a elycharts
37 | - fix hightlight.move
38 | - supporto per serie.anchor.userMouseEnter
39 | - fix transizioni da serie (e parti di serie) non renderizzate
40 | - line chart: cambiato supporto per linee arrotondate
41 |
42 | v2.0.10
43 | - WARN: necessita di aggiornamento a Raphael1.5
44 | - supporto transizioni di configurazione per pie
45 | - supporto pie con serie multiple
46 | - supporto per series.highlight.restoreSpeed e restoreEasing
47 | - supporto per tooltip.width="auto" (= 0) e tooltip.height="auto" (= 0) - Disabilita automaticamente frame SVG
48 | - refactoring gestione slice/archi, con gestione corretta animazione (necessita' feature "customAttribute" di Raphael1.5)
49 | - fix funnel senza dati o con dati tutti 0
50 | - fix transizioni in labelmanager e highlightmanager
51 |
52 | v2.0.9
53 | - bugfix in normalizzazione configurazioni passate
54 | - modificato valore di default di indexHighlightProps
55 | - migliorata gestione positionHandler per tooltip, in modo da gestire la posizione del mouse anche su IE
56 | - fix posizionamento label su IE (che da problemi con impostazioni opacità, e prima impostava opacity: 1 anche se non ce n'era bisogno)
57 |
58 | v2.0.8
59 | - nuova gestione del axis.normalize: ora basato sul numero di cifre significative, i vecchi valori "auto" e "autony" vengono entrambi tradotti con "2"
60 | - aggiunto startAnimation.subType usato da alcune animazioni. Supportato subType = 0,1,2 per animation.grow (subType = 2 sostituisce type = grow2)
61 | - aggiunta opzione features.debug.active per attivare debug
62 | - bugfix nomi serie con maiuscole
63 | - bugfix animazioni con serie non visibili
64 | - bugfix divisione per zero in barline
65 | - bugfix label.frameAnchor top|bottom invertiti
66 |
67 | v2.0.7
68 | - nuova gestione grid. Spostate le impostazioni in opt.features.grid (lasciata compatibilita' con vecchie opzioni),
69 | nuove opzioni grid.draw (per nascondere le linee orizzontali e/o verticali), migliorato supporto forceBorder
70 | nuova opzione grid.ticks.* per supportare le barrette sugli assi
71 | - bugfix pie
72 | - aggiunto startAnimation.type = 'grow' e 'grow2' per barline
73 | - fix animation.grow
74 |
75 | v2.0.6
76 | - supporto per "template", che permette di specificare quale configurazione di default utilizzare (permette quindi di avere dei "template" di configurazioni)
77 | WARN: $.elysia_charts.default_options e' stato rinominato in $.elysia_charts.templates (mantenuta compatibilita' all'indietro)
78 | - aggiunte le opzioni startAngle e clockwise a grafico "pie" per definire l'angolo iniziale e l'orientamento delle fette
79 | - semplificato serie.stackedWith: ora si chiama solo "stacked" (tenuta compatibilita' all'indietro) ed e' possibile specificare solo "true" per impilare automaticamente con la precedente serie visibile
80 | - supporto di serie.labelsAnchor anche per assi l ed r (in modo da poter specificare l'allineamento delle label dell'asse)
81 | - supporto di serie.labelsFormatHandler per specificare una funzione di formattazione delle label (sia per assi l,r che per asse x)
82 | - supporto migliore axis.labelsRotate con valori negativi
83 | - gestione corretta visible=true|false in cambiamenti grafici e per gestione stackedWith
84 | - cambiamento z-index di balloon e label per renderli selezionabili
85 | - impostato { cursor : "default" } in defaultSeries.label.style e tolto da opzioni forzate
86 | - bugfix (major): risolte problematiche in interruzione di animazioni (che provocava problemi in caso di interazione col grafico in vari momenti: animazione iniziale, animazioni intermedie, highlight...)
87 | - bugfix: frameAnchor non funzionava correttamente
88 | - bugfix: frame tooltip spariva dopo un cambiamento di grafico
89 | - bugfix: Indexhighlight:bar con mousearea.type=index non funziona
90 |
91 | v2.0.5
92 | - impostato defaultSeries.axis = 'l', features.balloons.width = 0
93 | - fix stackedWith e startAnimation.grow|avg|reg
94 | - posizionamento relativo invece di assoluto per balloons
95 | - supporto linea balloons mediante features.balloons.line e features.balloons.lineProps
96 | - gestione balloon e label per ultimo indice di un funnel associato a bottom sector
97 | - supporto debug della configurazione attuale mediante libreria DP_Debug (http://www.depressedpress.com/Content/Development/JavaScript/Extensions/DP_DeBug/Index.cfm)
98 | - ripristinato supporto legenda tramite features.legend
99 | - fix titoli assi
100 |
101 | v2.0.4
102 | - migliorato supporto pixelWorkAround
103 | - fix metodi interni
104 | - spostate config fadeDelay e moveDelay in opt.features.tooltip, areaMoveDelay in opt.features.mousearea
105 | - supporto opt.features.mousearea.syncTag per collegare le parti interattive di grafici diversi (se si va su uno si disattivano le altre)
106 | - migliorie posizionamento tooltip
107 | - supporto opt.features.tooltip.positionHandler per definire la propria funzione di posizionamento tooltip
108 | - supporto per passaggio di oggetti DOM/JQUERY come label
109 |
110 | v2.0.3
111 | - ripristinato supporto opzione "color"
112 | - gestione transizioni grafici mediante chiamate successive a $(X).chart(...)
113 | - supporto series.stepAnimation (transizioni grafici), features.animation.startAnimation (generazione elementi non-serie), features.animation.stepAnimation (transizioni elementi non-serie)
114 | - supporto series.visible
115 | - grafico barline: supporto direction = 'rtl'
116 | - fix vari
117 |
118 | v2.0.2
119 | - supporto piechart vuoto e serie "empty"
120 | - fix passaggio width ed height
121 | - nuova opzione "interactive"
122 | - nuove opzioni highlight: scaleSpeed, scaleEasing, moveSpeed, moveEasing
123 | - applicabile highlight "scale" a funnel e piechart (prima implementazione)
124 | - supporto opzione "delay" in startAnimation
125 | - supporto valori cumulativi in line chart, opzione series[x].cumulative
126 | - supporto opzione axis[X].labelsCompactUnits (= ['k','m']) per accorciare le label numeriche con unita' (prima implementazione)
127 | - rename interno strutture codice
128 | - migliorie gestione sync animazioni
129 |
130 | v2.0.1
131 | - ripristinato supporto label in pie e funnel
132 | - label HTML con offset
133 | - supporto passaggio anchor come elementi dom
134 | - ottimizzazione gestione mouseover
135 | - applicabile l'highlight "move" anche al funnel e migliorie ottimizzazioni generali all'highlight
136 | - nuovo grafico barline, e supporto highlight "scale" e "move"
137 | - fix vari
138 |
139 | v2.0.0
140 | - refactoring completo
141 |
--------------------------------------------------------------------------------
/docs/demo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
207 |
208 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
--------------------------------------------------------------------------------
/docs/demo_2.html:
--------------------------------------------------------------------------------
1 |
2 | Elycharts demo 2
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
27 |
28 |
386 |
387 |
438 |
439 |
440 |
441 |
444 |
445 |
41.250
delivered
446 |
447 |
2.500
bounced
448 |
449 |
450 |
15.424
opened
451 |
452 |
32.500
not opened
453 |
454 |
455 |
4.560
clicked
456 |
457 |
12.500
not clicked
458 |
459 |
460 |
461 | AAA
462 |
463 |
464 |
465 | BBB
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
--------------------------------------------------------------------------------
/docs/demo_3.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
34 |
35 |
36 |
37 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
240 | update data
241 | refresh chart
242 | update data 2
243 | update data 3
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 | ElyCharts
3 |
4 | ElyCharts
5 |
6 | elycharts.js
7 | elycharts.min.js
8 | Demo
9 | Demo 2
10 | Changelog
11 | Google Code Project
12 |
13 |
14 |
--------------------------------------------------------------------------------
/lib/DP_Debug.js:
--------------------------------------------------------------------------------
1 | /* DepressedPress.com DP_Debug
2 |
3 | Author: Jim Davis, the Depressed Press of Boston
4 | Date: September 20, 2006
5 | Contact: webmaster@depressedpress.com
6 | Website: www.depressedpress.com
7 |
8 | Full documentation can be found at:
9 | http://www.depressedpress.com/Content/Development/JavaScript/Extensions/DP_Debug/Index.cfm
10 |
11 | DP_Debug provides extensions to JavaScript to assist with debugging.
12 |
13 | + The DP_Debug.dump() method allows you to dump an HTML representation of any JavaScript object to the DP_Debug console. It supports nested objects, recursive references and chained method calls.
14 | + The methods DP_Debug.dumpCookies() and DP_Debug.dumpQueryString dump important browser information to the console.
15 | + The DP_Debug.log() method creates a log entry in the DP_Debug console.
16 | + The methods DP_Debug.logInfo(), DP_Debug.logWarning() and DP_Debug.logError() provide shortcuts for logging specific types of messages.
17 | + The DP_Debug.timer() method provides a simple way to time specific blocks of code.
18 | + The DP_Debug.dpGetType() method provides a more specific answer as to an object type than the native typeof operator.
19 |
20 | Copyright (c) 1996-2006, The Depressed Press of Boston (depressedpress.com)
21 |
22 | All rights reserved.
23 |
24 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
25 |
26 | +) Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
27 |
28 | +) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
29 |
30 | +) Neither the name of the DEPRESSED PRESS OF BOSTON (DEPRESSEDPRESS.COM) nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
31 |
32 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 |
34 | */
35 |
36 | // Add a container for utility methods
37 | DP_Debug = new Object();
38 |
39 | // dumpWindow Management
40 | //
41 | // Opens the window, if it's not already open
42 | DP_Debug.openDebugWindow = function() {
43 |
44 | // Create the Dump Window
45 | DPDebugWin = window.open("","dumpWindow","scrollbars=yes,resizable=yes,width=500,height=400");
46 | var DPW = DPDebugWin.document;
47 |
48 | if ( DPW.getElementById("dpBox") == null ) {
49 |
50 | // Write the HTML
51 | DPW.write( "",
52 | "",
53 | "",
54 | " dpDebug by the DepressedPress ",
55 | " ",
56 | " ",
185 | " ",
334 | "",
335 | "
",
336 | " ",
337 | "
",
338 | "
",
339 | "
",
340 | "
",
341 | " ",
342 | "
DP_Debug Quick Reference ",
343 | "
This is a quick reference guide to the methods available in the dpDebug library. Full documentation is available here .
",
344 | "
DP_Debug.dump(Object, [DevLabel], [ShowFunctions], [MaxRecurseLevel]) ",
345 | "
Dumps a visual representation of a JavaScript Object to the dump console.
",
346 | "
Object : Object, Required. The object which you'd like to dump. ",
347 | " DevLabel : String, Optional (defaults to empty string). An arbitrary developer label to be displayed with the dump output. ",
348 | " ShowFunctions : Boolean, Optional (defaults to false). If set to true user-defined functions, in addition to object properties, will be displayed. ",
349 | " MaxRecurseLevel : Numeric, Optional (defaults to -1 which indicates no limit). This argument determines how deeply an object should be explored. ",
350 | " ",
351 | "
DP_Debug.dumpCookies() ",
352 | "
Dumps the currently accessible browser cookies to the dump console.
",
353 | "
DP_Debug.dumpQueryString() ",
354 | "
Dumps the currently accessible Query String values to the dump console.
",
355 | "
DP_Debug.timer(Name) ",
356 | "
If the specified Name does not exist starts a timer with that name. If the name does exist ends the timer and outputs the duration to the log console.
",
357 | "
Name : String, Optional (defaults to 'timer'). The name of the timer. ",
358 | " ",
359 | "
DP_Debug.logger(Content, Type) ",
360 | "
Creates an entry in the log console.
",
361 | "
Content : String, Required. The message to display. ",
362 | " Type : String, Optional (defaults to 'Info'). The type of message. 'Info', 'Warning', and 'Error' are standard values although any value may be entered. ",
363 | " ",
364 | "
DP_Debug.logInfo(Content) ",
365 | "
Creates an entry in the log console of type 'Info'.
",
366 | "
Content : String, Required. The message to display. ",
367 | " ",
368 | "
DP_Debug.logWarning(Content) ",
369 | "
Creates an entry in the log console of type 'Warning'.
",
370 | "
Content : String, Required. The message to display. ",
371 | " ",
372 | "
DP_Debug.logError(Content) ",
373 | "
Creates an entry in the log console of type 'Error'.
",
374 | "
Content : String, Required. The message to display. ",
375 | " ",
376 | "
DP_Debug.getType(Object) ",
377 | "
Returns the type of the passed object.
",
378 | "
Content : Object, Required. The object to examine. ",
379 | " ",
380 | "
DP_Debug.enable() ",
381 | "
Sets the 'enabled' flag to true.
",
382 | "
DP_Debug.disable() ",
383 | "
Sets the 'enabled' flag to false.
",
384 | "
DP_Debug.isEnabled() ",
385 | "
Returns the current value of the 'enabled' flag.
",
386 | "
",
387 | " ",
388 | "
dump Output
",
389 | "
",
390 | "
",
391 | "
",
392 | "
",
393 | " ",
394 | "
log Output
",
395 | "
",
396 | "
Show: ",
397 | "
Clear ",
398 | "
",
399 | "
",
400 | "
",
401 | "
",
402 | "");
403 | // Close the stream
404 | DPW.close();
405 | };
406 |
407 | };
408 |
409 | // Default Enabled status to "false"
410 | DP_Debug.Enabled = false;
411 | // Methods to indicate enabled/disabled status
412 | DP_Debug.enable = function() {
413 | DP_Debug.Enabled = true;
414 | };
415 | DP_Debug.disable = function() {
416 | DP_Debug.Enabled = false;
417 | };
418 | DP_Debug.isEnabled = function() {
419 | return DP_Debug.Enabled;
420 | };
421 |
422 | // Add convienence methods for common log operations
423 | DP_Debug.logInfo = function(Content) {
424 | DP_Debug.logger(Content, "Info");
425 | };
426 | DP_Debug.logWarning = function(Content) {
427 | DP_Debug.logger(Content, "Warning");
428 | };
429 | DP_Debug.logError = function(Content) {
430 | DP_Debug.logger(Content, "Error");
431 | };
432 | // "log" method
433 | DP_Debug.logger = function(Content, Type) {
434 |
435 | // Manage input params
436 | if ( typeof Content != "string" || Content == "" ) {
437 | var Content = "";
438 | };
439 | if ( typeof Type != "string" || Type == "" ) {
440 | var Type = "Info";
441 | };
442 |
443 | // Open the dumpWindow (if it's not already open)
444 | DP_Debug.openDebugWindow()
445 |
446 | // Get the Current Entries
447 | var CurEntries = DPDebugWin.dpLgEntries;
448 | // Generate an Entry Object
449 | var NewEntry = new Object();
450 | NewEntry.Content = Content;
451 | NewEntry.Type = Type;
452 | NewEntry.Time = new Date();
453 |
454 | // Add the new Entry to the List
455 | CurEntries[CurEntries.length] = NewEntry;
456 |
457 | // Write the Log Entry
458 | DPDebugWin.writeLog();
459 |
460 | // Return
461 | return;
462 |
463 | };
464 |
465 |
466 | // Extend Object with the "log" method
467 | DP_Debug.timer = function(Name) {
468 |
469 | // Manage input params
470 | if ( typeof Name != "string" || Name == "" ) {
471 | var Name = "timer";
472 | };
473 |
474 | // Open the dumpWindow (if it's not already open)
475 | DP_Debug.openDebugWindow();
476 |
477 | // Get the Current Entries
478 | var CurTimers = DPDebugWin.timers;
479 |
480 | // See if this is a new timer
481 | if ( typeof CurTimers[Name] == "undefined" ) {
482 | // Set the Timer Start Point
483 | CurTimers[Name] = new Date();
484 | // Output the log entry
485 | DP_Debug.logger("Timer \"" + Name + "\" started.", "Timer");
486 | } else {
487 | // Get the Timer Start Point
488 | var CurStart = CurTimers[Name];
489 | var CurEnd = new Date();
490 | // Reset the Timer
491 | CurTimers[Name] = undefined;
492 | // Get the duration
493 | var CurTime = CurEnd.getTime() - CurStart.getTime()
494 | // Output the log entry
495 | DP_Debug.logger("Timer \"" + Name + "\" ended. Duration " + CurTime + " ms", "Timer");
496 | };
497 |
498 | // Return
499 | return;
500 |
501 | };
502 |
503 |
504 | // Cookie Dumper
505 | DP_Debug.dumpCookies = function() {
506 |
507 | var AllCookies = new Object;
508 | var Cookies = document.cookie.split(";");
509 |
510 | for ( var Cnt=0; Cnt < Cookies.length; Cnt++ ) {
511 | var CurCookie = Cookies[Cnt].split("=");
512 | if ( CurCookie[0] ) {
513 | if ( CurCookie[1] ) {
514 | AllCookies[CurCookie[0].replace(/^\s*|\s*$/g,"")] = CurCookie[1];
515 | } else {
516 | AllCookies[CurCookie[0].replace(/^\s*|\s*$/g,"")] = "";
517 | };
518 | };
519 | };
520 |
521 | DP_Debug.dump(AllCookies, "Accessible Browser Cookies");
522 |
523 | };
524 |
525 |
526 | // Query String Dumper
527 | DP_Debug.dumpQueryString = function() {
528 |
529 | var QS, AllElements, CurElement, CurName, CurVal
530 |
531 | QS = new Object();
532 | QueryString = location.search;
533 |
534 | // Split the query string on the ampersand (the substring removes the question mark)
535 | AllElements = QueryString.substring(1).split('&');
536 |
537 | // Loop over the elements
538 | for( var Cnt = 0; Cnt < AllElements.length; Cnt++) {
539 | // Split the current element on the equals sign
540 | CurElement = AllElements[Cnt].split('=');
541 | CurName = unescape(CurElement[0]).replace(/^\s*|\s*$/g,"");
542 | // Call the get method to obtain the value
543 | if ( CurName.length > 0 ) {
544 |
545 | if ( !QS[CurName] ) { QS[CurName] = new Array() };
546 | QS[CurName][QS[CurName].length] = CurElement[1];
547 |
548 | };
549 | };
550 |
551 | // Dump the object
552 | DP_Debug.dump(QS, "Accessible Query String Values");
553 |
554 | };
555 |
556 |
557 | // Extend Object with the "dump" method
558 | DP_Debug.dump = function(Ob, DevLabel, ShowFunctions, MaxRecurseLevel) {
559 |
560 | // Grab the Start time
561 | var DumpStart = new Date();
562 |
563 | // Open the dumpWindow (if it's not already open)
564 | DP_Debug.openDebugWindow()
565 |
566 | // Set up the Object Checker
567 | var ParsedObs = new Array();
568 | // Define the current Dump InstanceID
569 | var InstID = DPDebugWin.dumpInstances++;
570 | var ObID = 0;
571 | var ObRefID = 0;
572 |
573 | // Manage input params
574 | if ( typeof DevLabel != "string" || DevLabel == "" ) {
575 | var DevLabel = "";
576 | };
577 | // Only IE can handle local links in popups generated by JavaScript
578 | if ( navigator.appName == "Microsoft Internet Explorer" ) {
579 | LogLabel = "[Dump " + (InstID + 1) + "] " + DevLabel;
580 | } else {
581 | LogLabel = "[Dump " + (InstID + 1) + "] " + DevLabel;
582 | };
583 | // Set the full Dev Label
584 | DevLabel = "[Dump " + (InstID + 1) + "] " + DevLabel;
585 | // Set whether or not to show functions
586 | if ( typeof ShowFunctions != "boolean" ) {
587 | var ShowFunctions = false;
588 | };
589 | // Set the maximum recursive level
590 | if ( typeof MaxRecurseLevel != "number" ) {
591 | var MaxRecurseLevel = -1;
592 | };
593 |
594 | // Set the encoded character dictionary for the conversion to HTML
595 | var EncodedChars = new Array();
596 | // Add simple chars (& must come first!)
597 | EncodedChars["&"] = "&";
598 | EncodedChars["<"] = "<";
599 | EncodedChars[">"] = ">";
600 | EncodedChars["\""] = """;
601 |
602 | // Output the current dump
603 | DPDebugWin.document.getElementById("dpDpDsp").innerHTML += parseToHTML(Ob, DevLabel);
604 |
605 | // Grab the End Time
606 | var DumpEnd = new Date();
607 | // Determine the total time
608 | var DumpTime = DumpEnd.getTime() - DumpStart.getTime()
609 | // Output the log entry
610 | DP_Debug.logger(LogLabel + " (Completed in " + DumpTime + " ms)", "Dump");
611 |
612 | // Return a reference to the object
613 | return Ob;
614 |
615 | // Escape characters using the Encoded Chars tables
616 | function escapeString(CurString) {
617 | var CurRegEx;
618 | for ( var CurChar in EncodedChars ) {
619 | if (typeof EncodedChars[CurChar] != "function") {;
620 | if ( CurChar != "\\" ) {
621 | CurRegEx = new RegExp(CurChar, "g");
622 | } else {
623 | CurRegEx = /\\/g;
624 | };
625 | CurString = CurString.replace(CurRegEx, EncodedChars[CurChar]);
626 | };
627 | };
628 | return CurString;
629 | };
630 |
631 | // Has the object been parsed already?
632 | function checkIfParsedOB(Ob) {
633 | // Check the parsed array
634 | for ( var Cnt = 0; Cnt < ParsedObs.length; Cnt++ ) {
635 | if ( ParsedObs[Cnt] === Ob ) {
636 | return true;
637 | };
638 | };
639 | // Add the passed object to the parsed array
640 | ParsedObs[ParsedObs.length] = Ob;
641 | return false;
642 | };
643 |
644 | // Get the Ref ID
645 | function getObRefID(Ob) {
646 | // Check the parsed array
647 | for ( var Cnt = 0; Cnt < ParsedObs.length; Cnt++ ) {
648 | if ( ParsedObs[Cnt] === Ob ) {
649 | return Cnt;
650 | };
651 | };
652 | return "";
653 | };
654 |
655 | // Parse objects to HTML
656 | function parseToHTML(Ob, ObLabel, RecurseLevel, ForceUnknown) {
657 |
658 | // Manage Arugments
659 | if ( typeof RecurseLevel != "number" ) {
660 | RecurseLevel = 0;
661 | };
662 | if ( typeof ForceUnknown != "boolean" ) {
663 | ForceUnknown = false;
664 | };
665 |
666 | // Update the object ID
667 | ObID = ObID + 1;
668 |
669 | // Initialize results
670 | var Results = "";
671 |
672 | // Set options based on whether this is the first pass or a recursive pass
673 | if ( RecurseLevel == 0 ) {
674 | var StylePrefix = "Inst";
675 | Results += "";
676 | } else {
677 | var StylePrefix = "Ob";
678 | };
679 |
680 | // Get some information about the passed Object and set some display fragments
681 | if ( ForceUnknown ) {
682 | var ObType = "unknown";
683 | } else {
684 | var ObType = DP_Debug.getType(Ob);
685 | };
686 | var ObLabelID = "ObLabel_" + InstID + "_" + ObID;
687 | var ObValueID = "ObValue_" + InstID + "_" + ObID;
688 | var ObIDLink = "";
689 | var ObDisplayed = false;
690 | switch ( ObType ) {
691 | case "object": case "array":
692 | // Check to see if the object has already been displayed
693 | if ( checkIfParsedOB(Ob) ) {
694 | ObDisplayed = true;
695 | };
696 | var CurObRefID = getObRefID(Ob);
697 | if ( ObDisplayed ) {
698 | // Only IE can handle local links in popups generated by JavaScript
699 | if ( navigator.appName == "Microsoft Internet Explorer" ) {
700 | ObIDLink = " (id: " + CurObRefID + ") ";
701 | } else {
702 | ObIDLink = " (id: " + CurObRefID + ")";
703 | };
704 | } else {
705 | ObIDLink = " (id: " + CurObRefID + ") ";
706 | };
707 | };
708 |
709 | // Display Element Header
710 | Results += " ";
711 | Results += "";
712 |
713 | // Display Element Content
714 | switch ( ObType ) {
715 | case "object": case "array":
716 | if ( ObDisplayed ) {
717 | Results += "
( Previously Displayed ) ";
718 | } else if ( RecurseLevel == MaxRecurseLevel ) {
719 | Results += "
( Maximum Recursion Depth Reached ) ";
720 | } else {
721 | // Determine if the object is enumerable
722 | var ObEnumerable = true;
723 | try { for ( var Prop in Ob ) { break; } } catch (CurError) { ObEnumerable = false; };
724 | // Loop over object
725 | if ( ObEnumerable ) {
726 | Results += "
";
727 | for ( var Prop in Ob ) {
728 | PropEnumerable = true;
729 | try { typeof Ob[Prop]; Ob[Prop]; } catch (CurError) {
730 | PropEnumerable = false;
731 | Results += parseToHTML(null, Prop, RecurseLevel + 1, true);
732 | };
733 | if ( PropEnumerable && ( typeof Ob[Prop] != "function" || ShowFunctions ) ) {
734 | Results += parseToHTML(Ob[Prop], Prop, RecurseLevel + 1);
735 | };
736 | };
737 | Results += "
";
738 | } else {
739 | Results += "
( Object is not Enumerable ) ";
740 | };
741 | };
742 | break;
743 | case "function":
744 | Results += escapeString(Ob.toString());
745 | break;
746 | case "null":
747 | Results += "
( null ) ";
748 | break;
749 | case "date":
750 | Results += Ob.toString();
751 | break;
752 | case "number":
753 | Results += Ob.toString();
754 | break;
755 | case "string":
756 | if ( Ob.length == 0 ) {
757 | Results += "
( Empty String ) ";
758 | } else {
759 | Results += escapeString(Ob);
760 | };
761 | break;
762 | case "boolean":
763 | Results += Ob.toString();
764 | break;
765 | case "undefined":
766 | Results += "
( Undefined Entity ) ";
767 | break;
768 | case "unknown":
769 | Results += "
( Entity is not Enumerable ) ";
770 | break;
771 | };
772 |
773 | // Display Element Footer
774 | Results += "
";
775 | if ( RecurseLevel == 0 ) {
776 | Results += "
"
777 | };
778 |
779 | // Return Results
780 | return Results;
781 |
782 | };
783 |
784 | };
785 |
786 |
787 | // Extend Object with the "dpGetType" method
788 | DP_Debug.getType = function(Ob) {
789 |
790 | try {
791 | switch (typeof Ob) {
792 | case "object":
793 | if ( Ob == null ) {
794 | return "null";
795 | } else if ( Ob.constructor == Date ) {
796 | return "date";
797 | } else if ( Ob.constructor == Array ) {
798 | return "array";
799 | } else if ( Ob.constructor == String ) {
800 | return "string";
801 | } else if ( Ob.constructor == Number ) {
802 | return "number";
803 | } else if ( Ob.constructor == Boolean ) {
804 | return "boolean";
805 | } else if ( Ob == undefined ) {
806 | return "undefined";
807 | } else {
808 | return "object";
809 | };
810 | case "function":
811 | return "function";
812 | case "number":
813 | return "number";
814 | case "string":
815 | return "string";
816 | case "boolean":
817 | return "boolean";
818 | case "undefined":
819 | return "undefined";
820 | default:
821 | return "unknown";
822 | };
823 | } catch (CurError) {
824 | return "unknown";
825 | };
826 |
827 | };
828 |
--------------------------------------------------------------------------------
/lib/raphael.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/voidlabs/elycharts/2e17b827d714076e72f066d3cee76534e4a0f7bf/lib/raphael.js
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 | elycharts
5 | elycharts
6 | 2.1.6-SNAPSHOT
7 | Elycharts
8 | pom
9 |
10 |
11 |
12 | croche-releases
13 | http://croche.googlecode.com/svn/repository/releases
14 |
15 |
16 | oss.sonatype.org
17 | http://oss.sonatype.org/content/groups/public
18 |
19 |
20 |
21 |
22 | target/
23 | target/test-scripts
24 |
25 |
26 | maven-resources-plugin
27 | 2.6
28 |
29 |
30 | copy-resources
31 | process-resources
32 |
33 | copy-resources
34 |
35 |
36 | ${basedir}/target/extra-resources
37 |
38 |
39 | resources
40 | true
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | croche.maven
49 | maven-merge-file-plugin
50 | 0.4
51 |
52 |
53 | merge-release-notes
54 | process-resources
55 |
56 | merge
57 |
58 |
59 |
60 |
61 | dist/elycharts-full.js
62 |
63 | src
64 | ${basedir}/target/extra-resources
65 |
66 |
67 | header
68 | elycharts_default
69 | elycharts_core
70 | elycharts_manager
71 | elycharts_chart
72 |
73 |
74 | *.js
75 |
76 | /********* Source File: #{parent.name}/#{file.name}
77 | *********/\n
78 | UTF-8
79 |
80 |
81 | dist/elycharts.js
82 |
83 | src
84 | ${basedir}/target/extra-resources
85 |
86 |
87 | header
88 | elycharts_default
89 | elycharts_core
90 | elycharts_manager
91 | elycharts_chart
92 |
93 |
94 | header.js
95 | elycharts_defaults.js
96 | elycharts_core.js
97 | elycharts_manager_anchor.js
98 | elycharts_manager_animation.js
99 | elycharts_manager_highlight.js
100 | elycharts_manager_label.js
101 | elycharts_manager_legend.js
102 | elycharts_manager_mouse.js
103 | elycharts_manager_tooltip.js
104 | elycharts_chart_line.js
105 | elycharts_chart_pie.js
106 |
107 | /********* Source File: #{parent.name}/#{file.name}
108 | *********/\n
109 | UTF-8
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 | net.alchim31.maven
118 | yuicompressor-maven-plugin
119 | 1.2
120 |
121 |
122 | compress-js
123 | package
124 |
125 | compress
126 |
127 |
128 | dist
129 | dist
130 | .min
131 | -1
132 | true
133 |
134 | *-min.js
135 | *.min.js
136 | *header.js
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
--------------------------------------------------------------------------------
/resources/header.js:
--------------------------------------------------------------------------------
1 | /*!*********************************************************************
2 | * ELYCHARTS v${pom.version} $Id$
3 | * A Javascript library to generate interactive charts with vectorial graphics.
4 | *
5 | * Copyright (c) 2010-2014 Void Labs s.n.c. (http://void.it)
6 | * Licensed under the MIT (http://creativecommons.org/licenses/MIT/) license.
7 | **********************************************************************/
8 |
--------------------------------------------------------------------------------
/src/elycharts_chart_barline.js:
--------------------------------------------------------------------------------
1 | /**********************************************************************
2 | * ELYCHARTS
3 | * A Javascript library to generate interactive charts with vectorial graphics.
4 | *
5 | * Copyright (c) 2010-2014 Void Labs s.n.c. (http://void.it)
6 | * Licensed under the MIT (http://creativecommons.org/licenses/MIT/) license.
7 | **********************************************************************/
8 |
9 | (function($) {
10 |
11 | var common = $.elycharts.common;
12 |
13 | /***********************************************************************
14 | * CHART: BARLINE
15 | *
16 | * Singola barra orizzontale contenente vari valori.
17 | *
18 | * L'idea è che possa essere vista come una linechart orizzontale
19 | * invece di verticale, con solo serie di tipo bar e con un solo valore.
20 | * In futuro (quando sarà possibile far linechart orizzontali) potrebbe
21 | * proprio essere renderizzata in questo modo.
22 | **********************************************************************/
23 |
24 | $.elycharts.barline = {
25 |
26 | init : function($env) {
27 | },
28 |
29 | draw : function(env) {
30 | var paper = env.paper;
31 | var opt = env.opt;
32 |
33 | env.xmin = opt.margins[3];
34 | env.xmax = env.width - opt.margins[1];
35 | env.ymin = opt.margins[0];
36 | env.ymax = env.height - opt.margins[2];
37 |
38 | var maxvalue = 0;
39 | for (var serie in opt.values) {
40 | var values = opt.values[serie];
41 | var value = values[0];
42 | var plot = {
43 | props : common.areaProps(env, 'Series', serie)
44 | };
45 | env.plots[serie] = plot;
46 |
47 | if (!plot.props.stacked || !env.plots[plot.props.stacked]) {
48 | plot.from = 0;
49 | } else {
50 | plot.from = env.plots[plot.props.stacked].to;
51 | }
52 | plot.to = plot.from + value;
53 | if (plot.to > maxvalue)
54 | maxvalue = plot.to;
55 | }
56 | // TODO opt.max dovrebbe essere opt.axis[?].max ?
57 | if (typeof opt.max != 'undefined')
58 | maxvalue = opt.max;
59 | if (!maxvalue)
60 | maxvalue = 1;
61 |
62 | var pieces = [];
63 | for (serie in opt.values) {
64 | plot = env.plots[serie];
65 | var d = (env.xmax - env.xmin) / maxvalue;
66 | if (opt.direction != 'rtl')
67 | pieces.push({
68 | paths : [ { path : [ [ 'RECT', env.xmin + d * plot.from, env.ymin, env.xmin + d * plot.to, env.ymax] ], attr : plot.props.plotProps } ],
69 | section: 'Series', serie: serie, subSection : 'Plot', mousearea : 'paths'
70 | });
71 | else
72 | pieces.push({
73 | paths : [ { path : [ [ 'RECT', env.xmax - d * plot.from, env.ymin, env.xmax - d * plot.to, env.ymax] ], attr : plot.props.plotProps } ],
74 | section: 'Series', serie: serie, subSection : 'Plot', mousearea : 'paths'
75 | });
76 | }
77 |
78 | return pieces;
79 | }
80 | };
81 |
82 | })(jQuery);
83 |
--------------------------------------------------------------------------------
/src/elycharts_chart_funnel.js:
--------------------------------------------------------------------------------
1 | /**********************************************************************
2 | * ELYCHARTS
3 | * A Javascript library to generate interactive charts with vectorial graphics.
4 | *
5 | * Copyright (c) 2010-2014 Void Labs s.n.c. (http://void.it)
6 | * Licensed under the MIT (http://creativecommons.org/licenses/MIT/) license.
7 | **********************************************************************/
8 |
9 | (function($) {
10 |
11 | var common = $.elycharts.common;
12 |
13 | /***********************************************************************
14 | * CHART: FUNNEL
15 | **********************************************************************/
16 |
17 | $.elycharts.funnel = {
18 |
19 | init : function($env) {
20 | },
21 |
22 | draw : function(env) {
23 | var paper = env.paper;
24 | var opt = env.opt;
25 |
26 | env.xmin = opt.margins[3];
27 | env.xmax = env.width - opt.margins[1];
28 | env.ymin = opt.margins[0] + Math.abs(opt.rh);
29 |
30 | for (var serie in opt.values) {
31 | var values = opt.values[serie];
32 |
33 | var lastwidthratio = opt.method == 'width' ? values[values.length - 1] / (values[0] ? values[0] : 1) :
34 | Math.sqrt(values[values.length - 1] / (values[0] ? values[0] : 1) * Math.pow(1 / 2, 2)) * 2;
35 |
36 | env.ymax = env.height - opt.margins[2] - lastwidthratio * Math.abs(opt.rh);
37 |
38 | var pieces = this.pieces(env, serie, 0, 1, 1, values);
39 | }
40 |
41 | return pieces;
42 | },
43 |
44 | pieces : function(env, serie, hstart, hend, wratio, values) {
45 | var path, pieces = [], opt = env.opt;
46 |
47 | var v0 = values[0] ? values[0] : 1;
48 | var h = hstart; // Starting height
49 | var hslices = (hend - hstart - opt.topSector - opt.bottomSector) / (values.length > 1 ? values.length - 1 : 1);
50 | var w = wratio; // Starting width
51 | if ((path = this.edge(env, h, w, true)))
52 | pieces.push({path : path, section: 'Edge', attr : env.opt.edgeProps});
53 | if (opt.topSector > 0 && (path = this.section(env, h, h = h + opt.topSector, w, w)))
54 | pieces.push({path : path.path, center: path.center, rect: path.rect, section: 'Sector', serie: 'top', attr : env.opt.topSectorProps});
55 | var paths = [];
56 | for (var i = 1; i < values.length; i++) {
57 | var v = values[0] ? values[i] : 1;
58 | // METODO "cutarea"
59 | // area taglio attuale / area taglio iniziale = valore attuale / valore iniziare
60 | // => larghezza attuale = sqrt(values[i] / values[0] * pow(larghezza iniziale / 2, 2)) * 2
61 | if ((path = this.section(env, h, h = h + hslices, w,
62 | opt.method == 'width' ? w = v / v0 * wratio : w = Math.sqrt(v / v0 * Math.pow(wratio / 2, 2)) * 2)))
63 | var props = common.areaProps(env, 'Series', serie, i - 1);
64 | paths.push({path : path.path, center: path.center, rect: path.rect, attr : props.plotProps});
65 | }
66 | pieces.push({section: 'Series', serie: serie, paths : paths, subSection : 'Plot', mousearea : 'paths' });
67 |
68 | if (opt.bottomSector > 0 && (path = this.section(env, h, h = h + opt.bottomSector, w, w)))
69 | pieces.push({path : path.path, center: path.center, rect: path.rect, section: 'Sector', serie: 'bottom', attr : env.opt.bottomSectorProps});
70 | if ((path = this.edge(env, h, w, false)))
71 | pieces.push({path : path, section : 'Edge', attr : env.opt.edgeProps});
72 |
73 | return pieces;
74 | },
75 |
76 | section : function(env, hfrom, hto, wfrom, wto) {
77 | x1a = env.xmin + (env.xmax - env.xmin) * (wfrom / -2 + 1/2);
78 | x2a = env.xmin + (env.xmax - env.xmin) * (wfrom / 2 + 1/2);
79 | x1b = env.xmin + (env.xmax - env.xmin) * (wto / -2 + 1/2);
80 | x2b = env.xmin + (env.xmax - env.xmin) * (wto / 2 + 1/2);
81 | y1 = env.ymin + (env.ymax - env.ymin) * hfrom;
82 | y2 = env.ymin + (env.ymax - env.ymin) * hto;
83 | var rwa = (x2a - x1a) / 2;
84 | var rha = rwa / (env.xmax - env.xmin) * 2 * Math.abs(env.opt.rh);
85 | var rwb = (x2b - x1b) / 2;
86 | var rhb = rwb / (env.xmax - env.xmin) * 2 * Math.abs(env.opt.rh);
87 |
88 | var pathLn = [];
89 |
90 | pathLn.push(['M', x1a, y1]);
91 | if (env.opt.rh != 0)
92 | pathLn.push(['A', rwa, rha, 0, 0, env.opt.rh > 0 ? 1 : 0, x2a, y1]);
93 | else
94 | pathLn.push(['L', x2a, y1]);
95 | pathLn.push(['L', x2b, y2]);
96 | if (env.opt.rh != 0)
97 | pathLn.push(['A', rwb, rhb, 0, 0, env.opt.rh > 0 ? 0 : 1, x1b, y2]);
98 | else
99 | pathLn.push(['L', x1b, y2]);
100 | pathLn.push(['z']);
101 |
102 | return {path: pathLn, center: [(x2a + x1a) / 2, (y2 + y1) / 2 + (env.opt.rh > 0 ? -1 : +1) * (rha + rhb) / 2], rect: [x1a, y1, x2a, y2]};
103 | },
104 |
105 | edge : function(env, h, w, isTop) {
106 | if ((isTop && env.opt.rh >= 0) || (!isTop && env.opt.rh <= 0))
107 | return false;
108 |
109 | x1 = env.xmin + (env.xmax - env.xmin) * (w / -2 + 1/2);
110 | x2 = env.xmin + (env.xmax - env.xmin) * (w / 2 + 1/2);
111 | y = env.ymin + (env.ymax - env.ymin) * h;
112 | var rw = (x2 - x1) / 2;
113 | var rh = rw / (env.xmax - env.xmin) * 2 * Math.abs(env.opt.rh);
114 |
115 | var pathLn = [];
116 | pathLn.push(['M', x1, y]);
117 | pathLn.push(['A', rw, rh, 0, 0, env.opt.rh < 0 ? 1 : 0, x2, y]);
118 | pathLn.push(['A', rw, rh, 0, 0, env.opt.rh < 0 ? 1 : 0, x1, y]);
119 | pathLn.push(['z']);
120 | return pathLn;
121 | }
122 | };
123 |
124 | })(jQuery);
125 |
--------------------------------------------------------------------------------
/src/elycharts_chart_pie.js:
--------------------------------------------------------------------------------
1 | /**********************************************************************
2 | * ELYCHARTS
3 | * A Javascript library to generate interactive charts with vectorial graphics.
4 | *
5 | * Copyright (c) 2010-2014 Void Labs s.n.c. (http://void.it)
6 | * Licensed under the MIT (http://creativecommons.org/licenses/MIT/) license.
7 | **********************************************************************/
8 |
9 | (function($) {
10 |
11 | var common = $.elycharts.common;
12 |
13 | /***********************************************************************
14 | * CHART: PIE
15 | **********************************************************************/
16 |
17 | $.elycharts.pie = {
18 | init : function($env) {
19 | },
20 |
21 | draw : function(env) {
22 | //var paper = env.paper;
23 | var opt = env.opt;
24 |
25 | var w = env.width - env.opt.margins[1] - env.opt.margins[3];
26 | var h = env.height - env.opt.margins[0] - env.opt.margins[2];
27 | var r = env.opt.r ? env.opt.r : Math.floor((w < h ? w : h) / 2 * (env.opt.rPerc ? env.opt.rPerc / 100 : 0.8));
28 | var cx = (env.opt.cx ? env.opt.cx : Math.floor(w / 2)) + env.opt.margins[3];
29 | var cy = (env.opt.cy ? env.opt.cy : Math.floor(h / 2)) + env.opt.margins[0];
30 |
31 | var cnt = 0, i, ii, serie, plot, props;
32 | for (serie in opt.values) {
33 | plot = {
34 | visible : false,
35 | total : 0,
36 | values : []
37 | };
38 | env.plots[serie] = plot;
39 | var serieProps = common.areaProps(env, 'Series', serie);
40 | common.colorize(env, serieProps, [['plotProps','stroke'],['plotProps','fill']], common.getItemColor(env, serie));
41 | if (serieProps.visible) {
42 | plot.visible = true;
43 | cnt ++;
44 | plot.values = opt.values[serie];
45 | for (i = 0, ii = plot.values.length; i < ii; i++)
46 | if (plot.values[i] > 0) {
47 | props = common.areaProps(env, 'Series', serie, i);
48 | common.colorize(env, props, [['plotProps','stroke'],['plotProps','fill']], common.getItemColor(env, serie, i));
49 | if (typeof props.inside == 'undefined' || props.inside < 0)
50 | plot.total += plot.values[i];
51 | }
52 | for (i = 0; i < ii; i++)
53 | if (plot.values[i] < plot.total * opt.valueThresold) {
54 | plot.total = plot.total - plot.values[i];
55 | plot.values[i] = 0;
56 | }
57 | }
58 | }
59 |
60 | var rstep = r / cnt;
61 | var rstart = -rstep, rend = 0;
62 |
63 | var pieces = [];
64 | for (serie in opt.values) {
65 | plot = env.plots[serie];
66 | var paths = [];
67 | if (plot.visible) {
68 | rstart += rstep;
69 | rend += rstep;
70 | var angle = env.opt.startAngle, angleplus = 0, anglelimit = 0;
71 |
72 | if (plot.total == 0) {
73 | env.emptySeries = true;
74 | props = common.areaProps(env, 'Series', 'empty');
75 | common.colorize(env, props, [['plotProps','stroke'],['plotProps','fill']], common.getItemColor(env, serie));
76 | paths.push({ path : [ [ 'CIRCLE', cx, cy, r ] ], attr : props.plotProps });
77 |
78 | } else {
79 | env.emptySeries = false;
80 | for (i = 0, ii = plot.values.length; i < ii; i++) {
81 | var value = plot.values[i];
82 | if (value > 0) {
83 | props = common.areaProps(env, 'Series', serie, i);
84 | common.colorize(env, props, [['plotProps','stroke'],['plotProps','fill']], common.getItemColor(env, serie, i));
85 | if (typeof props.inside == 'undefined' || props.inside < 0) {
86 | angle += anglelimit;
87 | angleplus = 360 * value / plot.total;
88 | anglelimit = angleplus;
89 | } else {
90 | angleplus = 360 * values[props.inside] / plot.total * value / values[props.inside];
91 | }
92 | var rrstart = rstart, rrend = rend;
93 | if (props.r) {
94 | if (props.r > 0) {
95 | if (props.r <= 1)
96 | rrend = rstart + rstep * props.r;
97 | else
98 | rrend = rstart + props.r;
99 | } else {
100 | if (props.r >= -1)
101 | rrstart = rstart + rstep * (-props.r);
102 | else
103 | rrstart = rstart - props.r;
104 | }
105 | }
106 | if (!env.opt.clockwise)
107 | paths.push({ path : [ [ 'SLICE', cx, cy, rrend, rrstart, angle, angle + angleplus ] ], attr : props.plotProps });
108 | else
109 | paths.push({ path : [ [ 'SLICE', cx, cy, rrend, rrstart, - angle - angleplus, - angle ] ], attr : props.plotProps });
110 | } else
111 | paths.push({ path : false, attr : false });
112 | }
113 | }
114 | } else {
115 | // Even if serie is not visible it's better to put some empty path (for better transitions). It's not mandatory, just better
116 | if (opt.values[serie] && opt.values[serie].length)
117 | for (i = 0, ii = opt.values[serie].length; i < ii; i++)
118 | paths.push({ path : false, attr : false });
119 | }
120 |
121 | pieces.push({ section : 'Series', serie : serie, subSection : 'Plot', paths : paths , mousearea : 'paths'});
122 | }
123 |
124 | return pieces;
125 | }
126 | }
127 |
128 | })(jQuery);
129 |
--------------------------------------------------------------------------------
/src/elycharts_defaults.js:
--------------------------------------------------------------------------------
1 | /**********************************************************************
2 | * ELYCHARTS
3 | * A Javascript library to generate interactive charts with vectorial graphics.
4 | *
5 | * Copyright (c) 2010-2014 Void Labs s.n.c. (http://void.it)
6 | * Licensed under the MIT (http://creativecommons.org/licenses/MIT/) license.
7 | **********************************************************************/
8 |
9 | (function($) {
10 | if (!$.elycharts)
11 | $.elycharts = {};
12 |
13 | /***********************************************************************
14 | * DEFAULT OPTIONS
15 | **********************************************************************/
16 |
17 | $.elycharts.templates = {
18 |
19 | common : {
20 | // Tipo di grafico
21 | // type : 'line|pie|funnel|barline'
22 |
23 | // Permette di specificare una configurazione di default da utilizzare (definita in $.elycharts.templates.NOME)
24 | // La configurazione completa � quindi data da tutti i valori della conf di default alla quale viene unita (con sovrascrittura) la conf corrente
25 | // Il parametro � ricorsivo (la configurazione di default puo' a sua volta avere una configurazione di default)
26 | // Se non specificato, la configurazione di default � quella con lo stesso nome del tipo di grafico
27 | // template : 'NOME',
28 |
29 | /* DATI:
30 | // I valori associati a ogni serie del grafico. Ogni serie � associata a una chiave dell'oggetto value, il cui
31 | // valore � l'array di dati relativi
32 | values : {},
33 |
34 | // Label associate ai valori del grafico
35 | // Solo in caso di label gestite da labelmanager (quindi per pie e funnel) e per label.html = true e' possibile inserire
36 | // degli elementi DOM/JQUERY che verranno presi e posizionati correttament.
37 | labels : [],
38 |
39 | // Anchor per la gestione mediante anchormanager. Possono essere stringhe e oggetti DOM/JQUERY che verranno riposizionati
40 | anchors : {},
41 |
42 | tooltips : {},
43 |
44 | legend : [],
45 | */
46 |
47 | // Autoresize uses jQuery resize event to automatically resize the chart to the container
48 | // autoresize makes sense only when width or height is not defined.
49 | // autoresize: false,
50 |
51 | // Per impostare una dimensione diversa da quella del container settare width e height
52 | //width : x,
53 | //height : y
54 |
55 | // I margini del grafico rispetto al frame complessivo. Da notare che riguardano la posizione del grafico
56 | // principale, e NON degli elementi aggiuntivi (legenda, label e titoli degli assi...). Quindi i margini devono
57 | // essere impostati in genere proprio per lasciare lo spazio per questi elementi
58 | // Sintassi: [top, right, bottom, left]
59 | margins: [10, 10, 10, 10],
60 |
61 | // style : {},
62 |
63 | // Per gestire al meglio l'interattivita' del grafico (tooltip, highlight, anchor...) viene inserito un secondo
64 | // layer per le parti sensibili al mouse. Se si sa che il grafico non avra' alcuna interattivita' si puo' impostare
65 | // questo valore a false per evitare di creare il layer (ottimizzando leggermente la pagina)
66 | interactive : true,
67 |
68 | // Dati da applicare a tutte le serie del grafico
69 | defaultSeries : {
70 | // Impostare a false per disabilitare la visualizzazione della serie
71 | visible : true,
72 |
73 | // Impostare color qui permette di impostare velocemente plotProps.stroke+fill, tooltip.frameProps.stroke, dotProps.stroke e fillProps.fill (se non specificati)
74 | //color: 'blue',
75 |
76 | //plotProps : { },
77 |
78 | // Impostazioni dei tooltip
79 | tooltip : {
80 | active : true,
81 | // 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
82 | // Impostare a 0|auto � incompatibile con il frame SVG, quindi viene automaticamente disabilitato (come se frameProps = false)
83 | width: 100, height: 50,
84 | roundedCorners: 5,
85 | padding: [6, 6] /* y, x */,
86 | offset: [20, 0] /* y, x */,
87 | // Se frameProps = false non disegna la cornice del tooltip (ad es. per permettere di definire la propria cornice HTML)
88 | frameProps : { fill: "white", "stroke-width": 2 },
89 | contentStyle : { "font-family": "Arial", "font-size": "12px", "line-height": "16px", color: "black" }
90 | },
91 |
92 | // Highlight feature
93 | highlight : {
94 | // Cambia le dimensioni dell'elemento quando deve essere evidenziato
95 | //scale : [x, y],
96 | // Opzioni di animazione effetto "scale"
97 | scaleSpeed : 100, scaleEasing : '',
98 | // Cambia gli attributi dell'elemento quando evidenziato
99 | //newProps : { opacity : 1 },
100 | // Inserisce un layer con gli attributi specificati sopra quello da evidenziare
101 | //overlayProps : {"fill" : "white", "fill-opacity" : .3, "stroke-width" : 0}
102 | // Muove l'area evidenziata. E' possibile specificare un valore X o un array [X, Y]
103 | //move : 10,
104 | // Opzioni di animazione effetto "move"
105 | moveSpeed : 100, moveEasing : '',
106 | // Opzioni di animazione da usare per riportare l'oggetto alle situazione iniziale
107 | restoreSpeed : 0, restoreEasing : ''
108 | },
109 |
110 | anchor : {
111 | // Aggiunge alle anchor esterne la classe selezionata quando il mouse passa sull'area
112 | //addClass : "",
113 | // Evidenzia la serie al passaggio del mouse
114 | //highlight : "",
115 | // Se impostato a true usa gli eventi mouseenter/mouseleave invece di mouseover/mouseout per l'highlight
116 | //useMouseEnter : false,
117 | },
118 |
119 | // Opzioni per la generazione animata dei grafici
120 | startAnimation : {
121 | //active : true,
122 | type : 'simple',
123 | speed : 600,
124 | delay : 0,
125 | propsFrom : {}, // applicate a tutte le props di plot
126 | propsTo : {}, // applicate a tutte le props di plot
127 | easing : '' // easing raphael: >, <, <>, backIn, backOut, bounce, elastic
128 |
129 | // Opzionale per alcune animazioni, permette di specificare un sotto-tipo
130 | // subType : 0|1|2
131 | },
132 |
133 | // Opzioni per le transizioni dei grafici durante un cambiamento di configurazione
134 | /* stepAnimation : {
135 | speed : 600,
136 | delay : 0,
137 | easing : '' // easing raphael: >, <, <>, backIn, backOut, bounce, elastic
138 | },*/
139 |
140 | label : {
141 | // Disegna o meno la label interna al grafico
142 | active : false,
143 | // Imposta un offset [X,Y] per la label (le coordinate sono relative al sistema di assi dello specifico settore disegnato.
144 | // Ad es. per il piechart la X � la distanza dal centro, la Y lo spostamento ortogonale
145 | //offset : [x, y],
146 | html : false,
147 | // Proprieta' della label (per HTML = false)
148 | props : { fill: 'black', stroke: "none", "font-family": 'Arial', "font-size": "16px" },
149 | // Stile CSS della label (per HTML = true)
150 | style : { cursor : 'default' }
151 | // Posizionamento della label rispetto al punto centrale (+offset) identificato
152 | //frameAnchor : ['start|middle|end', 'top|middle|bottom']
153 | }
154 |
155 | /*legend : {
156 | dotType : 'rect',
157 | dotWidth : 10, dotHeight : 10, dotR : 4,
158 | dotProps : { },
159 | textProps : { font: '12px Arial', fill: "#000" }
160 | }*/
161 | },
162 |
163 | series : {
164 | // Serie specifica usata quando ci sono "dati vuoti" (ad esempio quando un piechart e' a 0)
165 | empty : {
166 | //plotProps : { fill : "#D0D0D0" },
167 | label : { active : false },
168 | tooltip : { active : false }
169 | }
170 | /*root : {
171 | values : []
172 | }*/
173 | },
174 |
175 | features : {
176 | tooltip : {
177 | // Imposta una posizione fissa per tutti i tooltip
178 | //fixedPos : [ x, y]
179 | // Velocita' del fade
180 | fadeDelay : 100,
181 | // Velocita' dello spostamento del tip da un'area all'altra
182 | moveDelay : 300
183 | // E' possibile specificare una funzione che filtra le coordinate del tooltip prima di mostrarlo, permettendo di modificarle
184 | // 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)
185 | //positionHandler : function(env, tooltipConf, mouseAreaData, suggestedX, suggestedY) { return [suggestedX, suggestedY] }
186 | },
187 | mousearea : {
188 | // 'single' le aree sensibili sono relative a ogni valore di ogni serie, se 'index' il mouse attiva tutte le serie per un indice
189 | type : 'single',
190 | // 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
191 | indexCenter : 'auto',
192 | // Quanto tempo puo' passare nel passaggio da un'area all'altra per considerarlo uno spostamento di puntatore
193 | areaMoveDelay : 500,
194 | // Se diversi chart specificano lo stesso syncTag quando si attiva l'area di uno si disattivano quelle degli altri
195 | syncTag: false,
196 | // Callback for mouse actions. Parameters passed: (env, serie, index, mouseAreaData)
197 | onMouseEnter : false,
198 | onMouseExit : false,
199 | onMouseChanged : false,
200 | onMouseOver : false,
201 | onMouseOut : false
202 | },
203 | highlight : {
204 | // 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
205 | //indexHighlight : 'barline',
206 | indexHighlightProps : { opacity : 1 /*fill : 'yellow', opacity : .3, scale : ".5 1"*/ }
207 | },
208 | animation : {
209 | // Valore di default per la generazione animata degli elementi del grafico (anche per le non-serie: label, grid...)
210 | startAnimation : {
211 | //active : true,
212 | //propsFrom : {}, // applicate a tutte le props di plot
213 | //propsTo : {}, // applicate a tutte le props di plot
214 | speed : 600,
215 | delay : 0,
216 | easing : '' // easing raphael: >, <, <>, backIn, backOut, bounce, elastic
217 | },
218 | // Valore di default per la transizione animata degli elementi del grafico (anche per le non-serie: label, grid...)
219 | stepAnimation : {
220 | speed : 600,
221 | delay : 0,
222 | easing : '' // easing raphael: >, <, <>, backIn, backOut, bounce, elastic
223 | }
224 | },
225 | frameAnimation : {
226 | active : false,
227 | cssFrom : { opacity : 0},
228 | cssTo : { opacity: 1 },
229 | speed : 'slow',
230 | easing : 'linear' // easing jQuery: 'linear' o 'swing'
231 | },
232 | // used to be true
233 | pixelWorkAround : {
234 | active : Raphael.svg
235 | },
236 | label : {},
237 | shadows : {
238 | active : false,
239 | offset : [2, 2], // Per attivare l'ombra, [y, x]
240 | props : {"stroke-width": 0, "stroke-opacity": 0, "fill": "black", "fill-opacity": .3}
241 | },
242 | // BALLOONS: Applicabile solo al funnel (per ora)
243 | balloons : {
244 | active : false,
245 | // Width: se non specificato e' automatico
246 | //width : 200,
247 | // Height: se non specificato e' automatico
248 | //height : 50,
249 | // Lo stile CSS da applicare a ogni balloon
250 | style : { },
251 | // Padding
252 | padding : [ 5, 5 ],
253 | // La distanza dal bordo sinistro
254 | left : 10,
255 | // 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)] ]
256 | line : [ [ 0, 0 ], [0, 0] ],
257 | // Propriet� della linea
258 | lineProps : { }
259 | },
260 | legend : {
261 | horizontal : false,
262 | x : 'auto', // X | auto, (auto solo per horizontal = true)
263 | y : 10,
264 | width : 'auto', // X | auto, (auto solo per horizontal = true)
265 | height : 20,
266 | itemWidth : "fixed", // fixed | auto, solo per horizontal = true
267 | margins : [0, 0, 0, 0],
268 | dotMargins : [10, 5], // sx, dx
269 | borderProps : { fill : "white", stroke : "black", "stroke-width" : 1 },
270 | dotType : 'rect',
271 | dotWidth : 10, dotHeight : 10,
272 | // radius for the dots (used to be 4 but there also was a bug preventing radius support, so moved to 0)
273 | dotR : 0,
274 | dotProps : { type : "rect", width : 10, height : 10 },
275 | textProps : { font: '12px Arial', fill: "#000" }
276 | },
277 | debug : {
278 | active : false
279 | }
280 | },
281 |
282 | enableInternalCaching : true,
283 |
284 | nop : 0
285 | },
286 |
287 | line : {
288 | template : 'common',
289 |
290 | // absolute margin left to both sides of each column / column group.
291 | barMargins : 0,
292 | // overlap between additional columns over the previous one (ignored for the first serie)
293 | barOverlapPerc : 0,
294 |
295 | // disable this if you want to use null values and want the lines/area to be broken over null values
296 | avgOverNulls: true,
297 |
298 | // Axis
299 | defaultAxis : {
300 | // [non per asse x] Normalizza il valore massimo dell'asse in modo che tutte le label abbiamo al massimo N cifre significative
301 | // (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)
302 | normalize: 2,
303 | // Permette di impostare i valori minimi e massimi di asse (invece di autorilevarli)
304 | min: 0, //max: x,
305 | // Imposta un testo da usare come prefisso e suffisso delle label
306 | //prefix : "", suffix : "",
307 | // Visualizza o meno le label dell'asse
308 | labels: false,
309 | // Distanza tra le label e l'asse relativo
310 | labelsDistance: 8,
311 | // [solo asse x] Rotazione (in gradi) delle label. Se specificato ignora i valori di labelsAnchor e labelsProps['text-anchor']
312 | labelsRotate: 0,
313 | // Proprieta' grafiche delle label
314 | labelsProps : {font: '10px Arial', fill: "#000"},
315 | // Compatta il numero mostrato nella label usando i suffissi specificati per migliaia, milioni...
316 | //labelsCompactUnits : ['k', 'M'],
317 | // Permette di specificare una funzione esterna che si occupa di formattare (o in generale trasformare) la label
318 | //labelsFormatHandler : function (label) { return label },
319 | // Salta le prime N label
320 | //labelsSkip : 0,
321 | // 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.
322 | //labelsAnchor : "auto"
323 | // [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.
324 | //labelsPos : "auto",
325 | // Automatically hide labels that would overlap previous labels.
326 | //labelsHideCovered : true,
327 | // Inserisce un margine alla label (a sinistra se in asse x, in alto se in altri assi)
328 | //labelsMargin: 10,
329 | // [solo asse x] If labelsHideCovered = true, make sure each label have at least this space before the next one.
330 | //labelsMarginRight: 0,
331 | // Distanza del titolo dall'asse
332 | titleDistance : 25, titleDistanceIE : .75,
333 | // Proprieta' grafiche del titolo
334 | titleProps : {font: '12px Arial', fill: "#000", "font-weight": "bold"}
335 | },
336 | axis : {
337 | x : { titleDistanceIE : 1.2 }
338 | },
339 |
340 | defaultSeries : {
341 | // Tipo di serie, puo' essere 'line' o 'bar'
342 | type : 'line',
343 | // L'asse di riferimento della serie. Gli assi "l" ed "r" sono i 2 assi visibili destro e sinistro.
344 | // E' possibile inserire anche un asse arbitrario (che non sar� visibile)
345 | axis : 'l',
346 | // Specificare cumulative = true se i valori inseriti per la serie sono cumulativi
347 | cumulative : false,
348 | // In caso di type="line" indica l'arrotondamento della linea
349 | rounded : 1,
350 | // Mette il punto di intersezione al centro dell'intervallo invece che al limite (per allineamento con bars). Se 'auto' decide autonomamente
351 | lineCenter : 'auto',
352 | // Permette di impilare le serie (i valori di uno iniziano dove finiscono quelli del precedente) con un altra (purche' dello stesso tipo)
353 | // Specificare "true" per impilare con la serie visibile precedente, oppure il nome della serie sulla quale impilare
354 | // stacked : false,
355 |
356 | plotProps : {"stroke-width": 1, "stroke-linejoin": "round"},
357 |
358 | barWidthPerc: 100,
359 | //DELETED: barProps : {"width-perc" : 100, "stroke-width": 1, "fill-opacity" : .3},
360 |
361 | // Attiva o disattiva il riempimento
362 | fill : false,
363 | fillProps : {stroke: "none", "stroke-width" : 0, "stroke-opacity": 0, opacity: .3},
364 |
365 | dot : false,
366 | dotProps : {size: 4, stroke: "#000", zindex: 5},
367 | dotShowOnNull : false,
368 |
369 | mouseareaShowOnNull : false,
370 |
371 | startAnimation : {
372 | plotPropsFrom : false,
373 | // DELETED linePropsFrom : false,
374 | fillPropsFrom : false,
375 | dotPropsFrom : false,
376 | //DELETED barPropsFrom : false,
377 | shadowPropsFrom : false
378 | }
379 |
380 | },
381 |
382 | features : {
383 | grid : {
384 | // N. di divisioni sull'asse X. Se "auto" si basa sulla label da visualizzare. Se "0" imposta draw[vertical] = false
385 | // 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
386 | nx : "auto",
387 | // N. di divisione sull'asse Y. Se "0" imposta draw[horizontal] = false
388 | ny : 4,
389 | // Disegna o meno la griglia. Si puo' specificare un array [horizontal, vertical]
390 | draw : false,
391 | // Forza la visualizzazione dei bordi/assi. Se true disegna comunque i bordi (anche se draw = false o se non ci sono label),
392 | // altrimenti si basa sulle regole standard di draw e presenza label (per asse x)
393 | // Puo' essere un booleano singolo o un array di bordi [up, dx, down, sx]
394 | forceBorder : false,
395 | // Proprieta' di visualizzazione griglia
396 | props : {stroke: '#e0e0e0', "stroke-width": 1},
397 | // Dimensioni extra delle rette [up, dx, down, sx]
398 | extra : [0, 0, 0, 0],
399 | // 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
400 | // Se specificato "auto" decide in autonomia
401 | labelsCenter : "auto",
402 |
403 | // Display a rectangular region with properties specied for every even/odd vertical/horizontal grid division
404 | evenVProps : false,
405 | oddVProps : false,
406 | evenHProps : false,
407 | oddHProps : false,
408 |
409 | ticks : {
410 | // Attiva le barrette sugli assi [x, l, r]
411 | active : [false, false, false],
412 | // Dimensioni da prima dell'asse a dopo l'asse
413 | size : [10, 10],
414 | // Proprieta' di visualizzazione griglia
415 | props : {stroke: '#e0e0e0', "stroke-width": 1}
416 | }
417 | }
418 | },
419 |
420 | nop : 0
421 | },
422 |
423 | pie : {
424 | template : 'common',
425 |
426 | // Coordinate del centro, se non specificate vengono autodeterminate
427 | //cx : 0, cy : 0,
428 | // Raggio della torta, se non specificato viene autodeterminato
429 | //r : 0
430 | // Radius in percentage of the available space
431 | //rPerc : 80
432 | // Angolo dal quale iniziare a disegnare le fette, in gradi
433 | startAngle : 0,
434 | // Disegna la torta con le fette in senso orario (invece dell'orientamento standard per gradi, in senso antiorario)
435 | clockwise : false,
436 | // Soglia (rapporto sul totale) entro la quale una fetta non viene visualizzata
437 | valueThresold : 0.006,
438 |
439 | // @since elycharts 2.1.5 (previously there was no margins support so when we implemented it we had to add a 0 margin
440 | // here to not start adding the common margin to every pie user
441 | margins : [0, 0, 0, 0],
442 |
443 | defaultSeries : {
444 | // r: .5, raggio usato solo per questo spicchio, se <=1 e' in rapporto al raggio generale
445 | // inside: X, inserisce questo spicchio dentro un altro (funziona solo inside: precedente, e non gestisce + spicchi dentro l'altro)
446 | }
447 | },
448 |
449 | funnel : {
450 | template : 'common',
451 |
452 | rh: 0, // height of ellipsis (for top and bottom cuts)
453 | method: 'width', // width/cutarea
454 | topSector: 0, // height factor of top cylinder
455 | topSectorProps : { fill: "#d0d0d0" },
456 | bottomSector: .1, // height factor of bottom cylinder
457 | bottomSectorProps : { fill: "#d0d0d0" },
458 | edgeProps : { fill: "#c0c0c0", "stroke-width": 1, opacity: 1 },
459 |
460 | nop : 0
461 | },
462 |
463 | barline : {
464 | template : 'common',
465 |
466 | // Imposta il valore massimo per la scala (altrimenti prende il valore + alto)
467 | // max : X
468 |
469 | // Impostare direction = rtl per creare un grafico che va da destra a sinistra
470 | direction : 'ltr'
471 | }
472 | }
473 |
474 | })(jQuery);
475 |
--------------------------------------------------------------------------------
/src/elycharts_manager_anchor.js:
--------------------------------------------------------------------------------
1 | /**********************************************************************
2 | * ELYCHARTS
3 | * A Javascript library to generate interactive charts with vectorial graphics.
4 | *
5 | * Copyright (c) 2010-2014 Void Labs s.n.c. (http://void.it)
6 | * Licensed under the MIT (http://creativecommons.org/licenses/MIT/) license.
7 | **********************************************************************/
8 |
9 | (function($) {
10 |
11 | var common = $.elycharts.common;
12 |
13 | /***********************************************************************
14 | * FEATURE: ANCHOR
15 | *
16 | * Permette di collegare i dati del grafico con delle aree esterne,
17 | * identificate dal loro selettore CSS, e di interagire con esse.
18 | **********************************************************************/
19 |
20 | $.elycharts.anchormanager = {
21 |
22 | afterShow : function(env, pieces) {
23 | // Prendo le aree gestite da mouseAreas, e metto i miei listener
24 | // Non c'e' bisogno di gestire il clean per una chiamata successiva, lo fa gia' il mouseareamanager
25 | // Tranne per i bind degli eventi jquery
26 |
27 | if (!env.opt.anchors)
28 | return;
29 |
30 | if (!env.anchorBinds)
31 | env.anchorBinds = [];
32 |
33 | while (env.anchorBinds.length) {
34 | var b = env.anchorBinds.pop();
35 | $(b[0]).unbind(b[1], b[2]);
36 | }
37 |
38 | for (var i = 0; i < env.mouseAreas.length; i++) {
39 | var serie = env.mouseAreas[i].piece ? env.mouseAreas[i].piece.serie : false;
40 | var anc;
41 | if (serie)
42 | anc = env.opt.anchors[serie][env.mouseAreas[i].index];
43 | else
44 | anc = env.opt.anchors[env.mouseAreas[i].index];
45 |
46 | if (anc && env.mouseAreas[i].props.anchor && env.mouseAreas[i].props.anchor.highlight) {
47 |
48 | (function(env, mouseAreaData, anc, caller) {
49 |
50 | var f1 = function() { caller.anchorMouseOver(env, mouseAreaData); };
51 | var f2 = function() { caller.anchorMouseOut(env, mouseAreaData); };
52 | if (!env.mouseAreas[i].props.anchor.useMouseEnter) {
53 | env.anchorBinds.push([anc, 'mouseover', f1]);
54 | env.anchorBinds.push([anc, 'mouseout', f2]);
55 | $(anc).mouseover(f1);
56 | $(anc).mouseout(f2);
57 | } else {
58 | env.anchorBinds.push([anc, 'mouseenter', f1]);
59 | env.anchorBinds.push([anc, 'mouseleave', f2]);
60 | $(anc).mouseenter(f1);
61 | $(anc).mouseleave(f2);
62 | }
63 | })(env, env.mouseAreas[i], anc, this);
64 | }
65 | }
66 |
67 | env.onAnchors = [];
68 | },
69 |
70 | anchorMouseOver : function(env, mouseAreaData) {
71 | $.elycharts.highlightmanager.onMouseOver(env, mouseAreaData.piece ? mouseAreaData.piece.serie : false, mouseAreaData.index, mouseAreaData);
72 | },
73 |
74 | anchorMouseOut : function(env, mouseAreaData) {
75 | $.elycharts.highlightmanager.onMouseOut(env, mouseAreaData.piece ? mouseAreaData.piece.serie : false, mouseAreaData.index, mouseAreaData);
76 | },
77 |
78 | onMouseOver : function(env, serie, index, mouseAreaData) {
79 | if (!env.opt.anchors)
80 | return;
81 |
82 | if (mouseAreaData.props.anchor && mouseAreaData.props.anchor.addClass) {
83 | //var serie = mouseAreaData.piece ? mouseAreaData.piece.serie : false;
84 | var anc;
85 | if (serie)
86 | anc = env.opt.anchors[serie][mouseAreaData.index];
87 | else
88 | anc = env.opt.anchors[mouseAreaData.index];
89 | if (anc) {
90 | $(anc).addClass(mouseAreaData.props.anchor.addClass);
91 | env.onAnchors.push([anc, mouseAreaData.props.anchor.addClass]);
92 | }
93 | }
94 | },
95 |
96 | onMouseOut : function(env, serie, index, mouseAreaData) {
97 | if (!env.opt.anchors)
98 | return;
99 |
100 | while (env.onAnchors.length > 0) {
101 | var o = env.onAnchors.pop();
102 | $(o[0]).removeClass(o[1]);
103 | }
104 | }
105 | }
106 |
107 | $.elycharts.featuresmanager.register($.elycharts.anchormanager, 30);
108 |
109 | })(jQuery);
110 |
--------------------------------------------------------------------------------
/src/elycharts_manager_animation.js:
--------------------------------------------------------------------------------
1 | /**********************************************************************
2 | * ELYCHARTS
3 | * A Javascript library to generate interactive charts with vectorial graphics.
4 | *
5 | * Copyright (c) 2010-2014 Void Labs s.n.c. (http://void.it)
6 | * Licensed under the MIT (http://creativecommons.org/licenses/MIT/) license.
7 | **********************************************************************/
8 |
9 | (function($) {
10 |
11 | var common = $.elycharts.common;
12 |
13 | /***********************************************************************
14 | * ANIMATIONMANAGER
15 | **********************************************************************/
16 |
17 | $.elycharts.animationmanager = {
18 |
19 | beforeShow : function(env, pieces) {
20 | if (!env.newopt)
21 | this.startAnimation(env, pieces);
22 | else
23 | this.stepAnimation(env, pieces);
24 | },
25 |
26 | stepAnimation : function(env, pieces) {
27 | pieces = this._stepAnimationInt(env, pieces);
28 | },
29 |
30 | _stepAnimationInt : function(env, pieces, section, serie, internal) {
31 | for (var i = 0; i < pieces.length; i++) {
32 | var animationProps = common.areaProps(env, section ? section : pieces[i].section, serie ? serie : pieces[i].serie);
33 | if (animationProps && animationProps.stepAnimation)
34 | animationProps = animationProps.stepAnimation;
35 | else
36 | animationProps = env.opt.features.animation.stepAnimation;
37 |
38 | if (typeof pieces[i].paths == 'undefined') {
39 | if (animationProps && animationProps.active && pieces[i].animation) {
40 | pieces[i].animation.speed = animationProps && animationProps.speed ? animationProps.speed : 300;
41 | pieces[i].animation.easing = animationProps && animationProps.easing ? animationProps.easing : '';
42 | pieces[i].animation.delay = animationProps && animationProps.delay ? animationProps.delay : 0;
43 | if (!pieces[i].animation.element)
44 | pieces[i].animation.startAttr = {opacity : 0};
45 | }
46 | } else {
47 | this._stepAnimationInt(env, pieces[i].paths, pieces[i].section, pieces[i].serie, true);
48 | }
49 | }
50 | },
51 |
52 | startAnimation : function(env, pieces) {
53 | for (var i = 0; i < pieces.length; i++)
54 | if (pieces[i].paths || pieces[i].path) {
55 | var props = common.areaProps(env, pieces[i].section, pieces[i].serie);
56 | if (props && props.startAnimation)
57 | props = props.startAnimation;
58 | else
59 | props = env.opt.features.animation.startAnimation;
60 |
61 | if (props && props.active) {
62 | if (props.type == 'simple' || pieces[i].section != 'Series')
63 | this.animationSimple(env, props, pieces[i]);
64 | if (props.type == 'grow')
65 | this.animationGrow(env, props, pieces[i]);
66 | if (props.type == 'avg')
67 | this.animationAvg(env, props, pieces[i]);
68 | if (props.type == 'reg')
69 | this.animationReg(env, props, pieces[i]);
70 | }
71 | }
72 | },
73 |
74 | /**
75 | * Inserisce i dati base di animazione del piece e la transizione di attributi
76 | */
77 | _animationPiece : function(piece, animationProps, subSection) {
78 | if (piece.paths) {
79 | for (var i = 0; i < piece.paths.length; i++)
80 | this._animationPiece(piece.paths[i], animationProps, subSection);
81 | } else if (piece.path) {
82 | piece.animation = {
83 | speed : animationProps.speed,
84 | easing : animationProps.easing,
85 | delay : animationProps.delay,
86 | startPath : [],
87 | startAttr : common._clone(piece.attr)
88 | };
89 | if (animationProps.propsTo)
90 | piece.attr = $.extend(true, piece.attr, animationProps.propsTo);
91 | if (animationProps.propsFrom)
92 | piece.animation.startAttr = $.extend(true, piece.animation.startAttr, animationProps.propsFrom);
93 | if (subSection && animationProps[subSection.toLowerCase() + 'PropsFrom'])
94 | piece.animation.startAttr = $.extend(true, piece.animation.startAttr, animationProps[subSection.toLowerCase() + 'PropsFrom']);
95 |
96 | if (typeof piece.animation.startAttr.opacity != 'undefined' && typeof piece.attr.opacity == 'undefined')
97 | piece.attr.opacity = 1;
98 | }
99 | },
100 |
101 | animationSimple : function(env, props, piece) {
102 | this._animationPiece(piece, props, piece.subSection);
103 | },
104 |
105 | animationGrow : function(env, props, piece) {
106 | this._animationPiece(piece, props, piece.subSection);
107 | var i, npath, y;
108 |
109 | switch (env.opt.type) {
110 | case 'line':
111 | y = env.height - env.opt.margins[2];
112 | switch (piece.subSection) {
113 | case 'Plot':
114 | if (!piece.paths) {
115 | npath = [ 'LINE', [], piece.path[0][2]];
116 | for (i = 0; i < piece.path[0][1].length; i++)
117 | npath[1].push([ piece.path[0][1][i][0], piece.path[0][1][i][1] == null ? null : y ]);
118 | piece.animation.startPath.push(npath);
119 |
120 | } else {
121 | for (i = 0; i < piece.paths.length; i++)
122 | if (piece.paths[i].path)
123 | piece.paths[i].animation.startPath.push([ 'RECT', piece.paths[i].path[0][1], y, piece.paths[i].path[0][3], y ]);
124 | }
125 | break;
126 | case 'Fill':
127 | npath = [ 'LINEAREA', [], [], piece.path[0][3]];
128 | for (i = 0; i < piece.path[0][1].length; i++) {
129 | npath[1].push([ piece.path[0][1][i][0], piece.path[0][1][i][1] == null ? null : y ]);
130 | npath[2].push([ piece.path[0][2][i][0], piece.path[0][2][i][1] == null ? null : y ]);
131 | }
132 | piece.animation.startPath.push(npath);
133 |
134 | break;
135 | case 'Dot':
136 | for (i = 0; i < piece.paths.length; i++)
137 | if (piece.paths[i].path)
138 | piece.paths[i].animation.startPath.push(['CIRCLE', piece.paths[i].path[0][1], y, piece.paths[i].path[0][3]]);
139 | break;
140 | }
141 | break;
142 |
143 | case 'pie':
144 | if (piece.subSection == 'Plot')
145 | for (i = 0; i < piece.paths.length; i++)
146 | if (piece.paths[i].path && piece.paths[i].path[0][0] == 'SLICE')
147 | 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] ]);
148 |
149 | break;
150 |
151 | case 'funnel':
152 | alert('Unsupported animation GROW for funnel');
153 | break;
154 |
155 | case 'barline':
156 | var x;
157 | if (piece.section == 'Series' && piece.subSection == 'Plot') {
158 | if (!props.subType)
159 | x = env.opt.direction != 'rtl' ? env.opt.margins[3] : env.width - env.opt.margins[1];
160 | else if (props.subType == 1)
161 | x = env.opt.direction != 'rtl' ? env.width - env.opt.margins[1] : env.opt.margins[3];
162 | for (i = 0; i < piece.paths.length; i++)
163 | if (piece.paths[i].path) {
164 | if (!props.subType || props.subType == 1)
165 | 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] ]);
166 | else {
167 | y = (piece.paths[i].path[0][2] + piece.paths[i].path[0][4]) / 2;
168 | 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] ]);
169 | }
170 | }
171 | }
172 |
173 | break;
174 | }
175 | },
176 |
177 | _animationAvgXYArray : function(arr) {
178 | var res = [], avg = 0, i;
179 | var count = 0;
180 | for (i = 0; i < arr.length; i++) if (arr[i][1] != null) {
181 | avg += arr[i][1];
182 | count++;
183 | }
184 | avg = avg / count;
185 | for (i = 0; i < arr.length; i++)
186 | res.push([ arr[i][0], arr[i][1] == null ? null : avg ]);
187 | return res;
188 | },
189 |
190 | animationAvg : function(env, props, piece) {
191 | this._animationPiece(piece, props, piece.subSection);
192 |
193 | var avg = 0, i, l;
194 | switch (env.opt.type) {
195 | case 'line':
196 | switch (piece.subSection) {
197 | case 'Plot':
198 | if (!piece.paths) {
199 | // LINE
200 | piece.animation.startPath.push([ 'LINE', this._animationAvgXYArray(piece.path[0][1]), piece.path[0][2] ]);
201 |
202 | } else {
203 | // BAR
204 | l = 0;
205 | for (i = 0; i < piece.paths.length; i++)
206 | if (piece.paths[i].path) {
207 | l ++;
208 | avg += piece.paths[i].path[0][2];
209 | }
210 | avg = avg / l;
211 | for (i = 0; i < piece.paths.length; i++)
212 | if (piece.paths[i].path)
213 | 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] ]);
214 | }
215 | break;
216 |
217 | case 'Fill':
218 | piece.animation.startPath.push([ 'LINEAREA', this._animationAvgXYArray(piece.path[0][1]), this._animationAvgXYArray(piece.path[0][2]), piece.path[0][3] ]);
219 |
220 | break;
221 |
222 | case 'Dot':
223 | l = 0;
224 | for (i = 0; i < piece.paths.length; i++)
225 | if (piece.paths[i].path) {
226 | l ++;
227 | avg += piece.paths[i].path[0][2];
228 | }
229 | avg = avg / l;
230 | for (i = 0; i < piece.paths.length; i++)
231 | if (piece.paths[i].path)
232 | piece.paths[i].animation.startPath.push(['CIRCLE', piece.paths[i].path[0][1], avg, piece.paths[i].path[0][3]]);
233 | break;
234 | }
235 | break;
236 |
237 | case 'pie':
238 | var delta = 360 / piece.paths.length;
239 |
240 | if (piece.subSection == 'Plot')
241 | for (i = 0; i < piece.paths.length; i++)
242 | if (piece.paths[i].path && piece.paths[i].path[0][0] == 'SLICE')
243 | 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 ]);
244 |
245 | break;
246 |
247 | case 'funnel':
248 | alert('Unsupported animation AVG for funnel');
249 | break;
250 |
251 | case 'barline':
252 | alert('Unsupported animation AVG for barline');
253 | break;
254 | }
255 | },
256 |
257 | _animationRegXYArray : function(arr) {
258 | var res = [];
259 | var c = arr.length;
260 |
261 | var start = 0;
262 | var end = c - 1;
263 |
264 | while (arr[start][1] == null) start++;
265 | while (arr[end][1] == null) end--;
266 |
267 | var y1 = arr[0][1];
268 | var y2 = arr[c - 1][1];
269 |
270 | for (var i = 0; i < arr.length; i++) {
271 | if (arr[i][1] == null) res.push([ arr[i][0], null ]);
272 | else {
273 | res.push([ arr[i][0], arr[start][1] + (arr[end][1] - arr[start][1]) / (end - start) * ( i - start) ]);
274 | }
275 | }
276 |
277 | return res;
278 | },
279 |
280 | animationReg : function(env, props, piece) {
281 | this._animationPiece(piece, props, piece.subSection);
282 | var i, c, y1, y2;
283 |
284 | switch (env.opt.type) {
285 | case 'line':
286 | switch (piece.subSection) {
287 | case 'Plot':
288 | if (!piece.paths) {
289 | // LINE
290 | piece.animation.startPath.push([ 'LINE', this._animationRegXYArray(piece.path[0][1]), piece.path[0][2] ]);
291 |
292 | } else {
293 | // BAR
294 | c = piece.paths.length;
295 | if (c > 1) {
296 | for (i = 0; !piece.paths[i].path && i < piece.paths.length; i++) {}
297 | y1 = piece.paths[i].path ? common.getY(piece.paths[i].path[0]) : 0;
298 | for (i = piece.paths.length - 1; !piece.paths[i].path && i >= 0; i--) {}
299 | y2 = piece.paths[i].path ? common.getY(piece.paths[i].path[0]) : 0;
300 |
301 | for (i = 0; i < piece.paths.length; i++)
302 | if (piece.paths[i].path)
303 | 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] ]);
304 | }
305 | }
306 | break;
307 |
308 | case 'Fill':
309 | piece.animation.startPath.push([ 'LINEAREA', this._animationRegXYArray(piece.path[0][1]), this._animationRegXYArray(piece.path[0][2]), piece.path[0][3] ]);
310 | break;
311 |
312 | case 'Dot':
313 | c = piece.paths.length;
314 | if (c > 1) {
315 | for (i = 0; !piece.paths[i].path && i < piece.paths.length; i++) {}
316 | y1 = piece.paths[i].path ? common.getY(piece.paths[i].path[0]) : 0;
317 | for (i = piece.paths.length - 1; !piece.paths[i].path && i >= 0; i--) {}
318 | y2 = piece.paths[i].path ? common.getY(piece.paths[i].path[0]) : 0;
319 |
320 | for (i = 0; i < piece.paths.length; i++)
321 | if (piece.paths[i].path)
322 | 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]]);
323 | }
324 | break;
325 | }
326 | break;
327 |
328 | case 'pie':
329 | alert('Unsupported animation REG for pie');
330 | break;
331 |
332 | case 'funnel':
333 | alert('Unsupported animation REG for funnel');
334 | break;
335 |
336 | case 'barline':
337 | alert('Unsupported animation REG for barline');
338 | break;
339 | }
340 | }
341 | }
342 |
343 | $.elycharts.featuresmanager.register($.elycharts.animationmanager, 10);
344 |
345 | /***********************************************************************
346 | * FRAMEANIMATIONMANAGER
347 | **********************************************************************/
348 |
349 | $.elycharts.frameanimationmanager = {
350 |
351 | beforeShow : function(env, pieces) {
352 | if (env.opt.features.frameAnimation.active)
353 | $(env.container.get(0)).css(env.opt.features.frameAnimation.cssFrom);
354 | },
355 |
356 | afterShow : function(env, pieces) {
357 | if (env.opt.features.frameAnimation.active)
358 | env.container.animate(env.opt.features.frameAnimation.cssTo, env.opt.features.frameAnimation.speed, env.opt.features.frameAnimation.easing);
359 | }
360 | };
361 |
362 | $.elycharts.featuresmanager.register($.elycharts.frameanimationmanager, 90);
363 |
364 | })(jQuery);
365 |
--------------------------------------------------------------------------------
/src/elycharts_manager_balloon.js:
--------------------------------------------------------------------------------
1 | /**********************************************************************
2 | * ELYCHARTS
3 | * A Javascript library to generate interactive charts with vectorial graphics.
4 | *
5 | * Copyright (c) 2010-2014 Void Labs s.n.c. (http://void.it)
6 | * Licensed under the MIT (http://creativecommons.org/licenses/MIT/) license.
7 | **********************************************************************/
8 |
9 | (function($) {
10 |
11 | var common = $.elycharts.common;
12 |
13 | /***********************************************************************
14 | * FEATURE: BALLOON
15 | **********************************************************************/
16 |
17 | $.elycharts.balloonmanager = {
18 |
19 | afterShow : function(env, pieces) {
20 | // TODO transizioni
21 |
22 | if (env.opt.features.balloons.active && env.opt.balloons && env.opt.type == 'funnel') {
23 | var conf = env.opt.features.balloons;
24 | var lastSerie = false, lastIndex = false;
25 | for (var i = 0; i < pieces.length; i++) {
26 | if (pieces[i].section == 'Series' && pieces[i].subSection == 'Plot') {
27 | for (var index = 0; index < pieces[i].paths.length; index ++)
28 | if (env.opt.balloons[pieces[i].serie] && env.opt.balloons[pieces[i].serie][index]) {
29 | lastSerie = pieces[i].serie;
30 | lastIndex = index;
31 | this.drawBalloon(env, lastSerie, index, pieces[i].paths[index].rect);
32 | }
33 | } else if (lastSerie && pieces[i].section == 'Sector' && pieces[i].serie == 'bottom' && !pieces[i].subSection && lastIndex < env.opt.balloons[lastSerie].length - 1) {
34 | this.drawBalloon(env, lastSerie, env.opt.balloons[lastSerie].length - 1, pieces[i].rect);
35 | }
36 | }
37 | }
38 | },
39 |
40 | drawBalloon : function(env, serie, index, rect) {
41 | var conf = env.opt.features.balloons;
42 | var balloon = env.opt.balloons[serie][index];
43 |
44 | //var offset = $(env.container).offset();
45 | var style = {
46 | position : 'absolute', 'z-index' : 25,
47 | //top : offset.top + rect[1] , left: offset.left + conf.left,
48 | margin : rect[1] + "px 0 0 " + conf.left + "px",
49 | height : (conf.height ? conf.height : rect[3] - rect[1]) - conf.padding[0] * 2 ,
50 | width : conf.width ? conf.width : rect[0],
51 | padding : conf.padding[0] + 'px ' + conf.padding[1] + 'px'
52 | };
53 |
54 | if (typeof balloon == 'string')
55 | $("
").css(style).css(conf.style).html(balloon).prependTo(env.container);
56 | else
57 | $(balloon).css(style).css(conf.style).prependTo(env.container);
58 |
59 | // Disegna la linea
60 | if (conf.line) {
61 | var path = [];
62 | for (var j = 0; j < conf.line.length; j++) {
63 | if (j == 0)
64 | path.push([ 'M', rect[0] - conf.line[j][0], rect[1] + conf.line[j][1]]);
65 | else if (j == conf.line.length - 1)
66 | path.push([ 'L', conf.left + (conf.width ? conf.width : rect[0]) - conf.line[j][0], rect[1] + conf.line[j][1] ]);
67 | else
68 | path.push([ 'L', rect[0] - conf.line[j][0], rect[1] + conf.line[j][1]]);
69 | }
70 | common.showPath(env, path).attr(conf.lineProps);
71 | }
72 | }
73 | }
74 |
75 | $.elycharts.featuresmanager.register($.elycharts.balloonmanager, 30);
76 |
77 | })(jQuery);
78 |
--------------------------------------------------------------------------------
/src/elycharts_manager_highlight.js:
--------------------------------------------------------------------------------
1 | /**********************************************************************
2 | * ELYCHARTS
3 | * A Javascript library to generate interactive charts with vectorial graphics.
4 | *
5 | * Copyright (c) 2010-2014 Void Labs s.n.c. (http://void.it)
6 | * Licensed under the MIT (http://creativecommons.org/licenses/MIT/) license.
7 | **********************************************************************/
8 |
9 | (function($) {
10 |
11 | var common = $.elycharts.common;
12 |
13 | /***********************************************************************
14 | * FEATURE: HIGHLIGHT
15 | *
16 | * Permette di evidenziare in vari modi l'area in cui si passa con il
17 | * mouse.
18 | **********************************************************************/
19 |
20 | $.elycharts.highlightmanager = {
21 |
22 | removeHighlighted : function(env, full) {
23 | if (env.highlighted)
24 | while (env.highlighted.length > 0) {
25 | var o = env.highlighted.pop();
26 | if (o.piece) {
27 | if (full)
28 | common.animationStackPush(env, o.piece, o.piece.element, common.getPieceFullAttr(env, o.piece), o.cfg.restoreSpeed, o.cfg.restoreEasing, 0, true);
29 | } else
30 | o.element.remove();
31 | }
32 | },
33 |
34 | afterShow : function(env, pieces) {
35 | if (env.highlighted && env.highlighted.length > 0)
36 | this.removeHighlighted(env, false);
37 | env.highlighted = [];
38 | },
39 |
40 | onMouseOver : function(env, serie, index, mouseAreaData) {
41 | var path, element;
42 | // TODO Se non e' attivo l'overlay (per la serie o per tutto) e' inutile fare il resto
43 |
44 | // Cerco i piece da evidenziare (tutti quelli che sono costituiti da path multipli)
45 | for (var i = 0; i < mouseAreaData.pieces.length; i++)
46 |
47 | // Il loop sotto estrae solo i pieces con array di path (quindi non i line o i fill del linechart ... ma il resto si)
48 | if (mouseAreaData.pieces[i].section == 'Series' && mouseAreaData.pieces[i].paths
49 | && (!serie || mouseAreaData.pieces[i].serie == serie)
50 | && mouseAreaData.pieces[i].paths[index] && mouseAreaData.pieces[i].paths[index].element) {
51 | var piece = mouseAreaData.pieces[i].paths[index];
52 | element = piece.element;
53 | path = piece.path;
54 | var attr = common.getElementOriginalAttrs(element);
55 | var newattr = false; // In caso la geometria dell'oggetto è modificata mediante attr (es: per circle) qui memorizza i nuovi attributi
56 | var props = serie ? mouseAreaData.props : common.areaProps(env, mouseAreaData.pieces[i].section, mouseAreaData.pieces[i].serie);
57 | var pelement, ppiece, ppath;
58 | if (path && props.highlight) {
59 | if (props.highlight.scale) {
60 | var scale = props.highlight.scale;
61 | if (typeof scale == 'number')
62 | scale = [scale, scale];
63 |
64 | if (path[0][0] == 'RECT') {
65 | var w = path[0][3] - path[0][1];
66 | var h = path[0][4] - path[0][2];
67 | path = [ [ 'RECT', path[0][1], path[0][2] - h * (scale[1] - 1), path[0][3] + w * (scale[0] - 1), path[0][4] ] ];
68 | common.animationStackPush(env, piece, element, common.getSVGProps(env, path), props.highlight.scaleSpeed, props.highlight.scaleEasing);
69 | }
70 | else if (path[0][0] == 'CIRCLE') {
71 | // I pass directly new radius
72 | newattr = {r : path[0][3] * scale[0]};
73 | common.animationStackPush(env, piece, element, newattr, props.highlight.scaleSpeed, props.highlight.scaleEasing);
74 | }
75 | else if (path[0][0] == 'SLICE') {
76 | // Per lo slice x e' il raggio, y e' l'angolo
77 | var d = (path[0][6] - path[0][5]) * (scale[1] - 1) / 2;
78 | if (d > 90)
79 | d = 90;
80 | path = [ [ 'SLICE', path[0][1], path[0][2], path[0][3] * scale[0], path[0][4], path[0][5] - d, path[0][6] + d ] ];
81 | common.animationStackPush(env, piece, element, common.getSVGProps(env, path), props.highlight.scaleSpeed, props.highlight.scaleEasing);
82 |
83 | } else if (env.opt.type == 'funnel') {
84 | var dx = (piece.rect[2] - piece.rect[0]) * (scale[0] - 1) / 2;
85 | var dy = (piece.rect[3] - piece.rect[1]) * (scale[1] - 1) / 2;
86 |
87 | // Specifico di un settore del funnel
88 | // SHOULD ALREADY BE DONE BY core common.animationStackStart(env);
89 | path = [ common.movePath(env, [ path[0]], [-dx, -dy])[0],
90 | common.movePath(env, [ path[1]], [+dx, -dy])[0],
91 | common.movePath(env, [ path[2]], [+dx, +dy])[0],
92 | common.movePath(env, [ path[3]], [-dx, +dy])[0],
93 | path[4] ];
94 | common.animationStackPush(env, piece, element, common.getSVGProps(env, path), props.highlight.scaleSpeed, props.highlight.scaleEasing, 0, true);
95 |
96 | // Se c'e' un piece precedente lo usa, altrimenti cerca un topSector per la riduzione
97 | pelement = false;
98 | if (index > 0) {
99 | ppiece = mouseAreaData.pieces[i].paths[index - 1];
100 | pelement = ppiece.element;
101 | ppath = ppiece.path;
102 | } else {
103 | ppiece = common.findInPieces(mouseAreaData.pieces, 'Sector', 'top');
104 | if (ppiece) {
105 | pelement = ppiece.element;
106 | ppath = ppiece.path;
107 | }
108 | }
109 | if (pelement) {
110 | //pattr = common.getElementOriginalAttrs(pelement);
111 | ppath = [
112 | ppath[0], ppath[1],
113 | common.movePath(env, [ ppath[2]], [+dx, -dy])[0],
114 | common.movePath(env, [ ppath[3]], [-dx, -dy])[0],
115 | ppath[4] ];
116 | common.animationStackPush(env, ppiece, pelement, common.getSVGProps(env, ppath), props.highlight.scaleSpeed, props.highlight.scaleEasing, 0, true);
117 | env.highlighted.push({piece : ppiece, cfg : props.highlight});
118 | }
119 |
120 | // Se c'e' un piece successivo lo usa, altrimenti cerca un bottomSector per la riduzione
121 | pelement = false;
122 | if (index < mouseAreaData.pieces[i].paths.length - 1) {
123 | ppiece = mouseAreaData.pieces[i].paths[index + 1];
124 | pelement = ppiece.element;
125 | ppath = ppiece.path;
126 | } else {
127 | ppiece = common.findInPieces(mouseAreaData.pieces, 'Sector', 'bottom');
128 | if (ppiece) {
129 | pelement = ppiece.element;
130 | ppath = ppiece.path;
131 | }
132 | }
133 | if (pelement) {
134 | //var pattr = common.getElementOriginalAttrs(pelement);
135 | ppath = [
136 | common.movePath(env, [ ppath[0]], [-dx, +dy])[0],
137 | common.movePath(env, [ ppath[1]], [+dx, +dy])[0],
138 | ppath[2], ppath[3],
139 | ppath[4] ];
140 | common.animationStackPush(env, ppiece, pelement, common.getSVGProps(env, ppath), props.highlight.scaleSpeed, props.highlight.scaleEasing, 0, true);
141 | env.highlighted.push({piece : ppiece, cfg : props.highlight});
142 | }
143 | // SHOULD ALREADY BE DONE BY core: common.animationStackEnd(env);
144 | }
145 | /* Con scale non va bene
146 | if (!attr.scale)
147 | attr.scale = [1, 1];
148 | element.attr({scale : [scale[0], scale[1]]}); */
149 | }
150 | if (props.highlight.newProps) {
151 | for (var a in props.highlight.newProps)
152 | if (typeof attr[a] == 'undefined')
153 | attr[a] = false;
154 | common.animationStackPush(env, piece, element, props.highlight.newProps);
155 | }
156 | if (props.highlight.move) {
157 | var offset = $.isArray(props.highlight.move) ? props.highlight.move : [props.highlight.move, 0];
158 | path = common.movePath(env, path, offset);
159 | common.animationStackPush(env, piece, element, common.getSVGProps(env, path), props.highlight.moveSpeed, props.highlight.moveEasing);
160 | }
161 |
162 | //env.highlighted.push({element : element, attr : attr});
163 | env.highlighted.push({piece : piece, cfg : props.highlight});
164 |
165 | if (props.highlight.overlayProps) {
166 | // NOTA: path e' il path modificato dai precedenti (cosi' l'overlay tiene conto della cosa), deve guardare anche a newattr
167 | //BIND: mouseAreaData.listenerDisabled = true;
168 | element = common.showPath(env, path);
169 | if (newattr)
170 | element.attr(newattr);
171 | element.attr(props.highlight.overlayProps);
172 | //BIND: $(element.node).unbind().mouseover(mouseAreaData.mouseover).mouseout(mouseAreaData.mouseout);
173 | // Se metto immediatamente il mouseAreaData.listenerDisabled poi va comunque un mouseout dalla vecchia area e va
174 | // in loop. TODO Rivedere e sistemare anche per tooltip
175 | //BIND: setTimeout(function() { mouseAreaData.listenerDisabled = false; }, 10);
176 | attr = false;
177 | env.highlighted.push({element : element, attr : attr, cfg : props.highlight});
178 | }
179 | }
180 | }
181 |
182 | if (env.opt.features.highlight.indexHighlight && env.opt.type == 'line') {
183 | var t = env.opt.features.highlight.indexHighlight;
184 | if (t == 'auto')
185 | t = (env.indexCenter == 'bar' ? 'bar' : 'line');
186 |
187 | var delta1 = (env.width - env.opt.margins[3] - env.opt.margins[1]) / (env.opt.labels.length > 0 ? env.opt.labels.length : 1);
188 | var delta2 = (env.width - env.opt.margins[3] - env.opt.margins[1]) / (env.opt.labels.length > 1 ? env.opt.labels.length - 1 : 1);
189 | var lineCenter = true;
190 |
191 | switch (t) {
192 | case 'bar':
193 | path = [ ['RECT', env.opt.margins[3] + index * delta1, env.opt.margins[0] ,
194 | env.opt.margins[3] + (index + 1) * delta1, env.height - env.opt.margins[2] ] ];
195 | break;
196 |
197 | case 'line':
198 | lineCenter = false;
199 | case 'barline':
200 | var x = Math.round((lineCenter ? delta1 / 2 : 0) + env.opt.margins[3] + index * (lineCenter ? delta1 : delta2));
201 | path = [[ 'M', x, env.opt.margins[0]], ['L', x, env.height - env.opt.margins[2]]];
202 | }
203 | if (path) {
204 | //BIND: mouseAreaData.listenerDisabled = true;
205 | element = common.showPath(env, path).attr(env.opt.features.highlight.indexHighlightProps);
206 | //BIND: $(element.node).unbind().mouseover(mouseAreaData.mouseover).mouseout(mouseAreaData.mouseout);
207 | //BIND: setTimeout(function() { mouseAreaData.listenerDisabled = false; }, 10);
208 | env.highlighted.push({element : element, attr : false, cfg : env.opt.features.highlight});
209 | }
210 | }
211 | },
212 |
213 | onMouseOut : function(env, serie, index, mouseAreaData) {
214 | this.removeHighlighted(env, true);
215 | }
216 |
217 | };
218 |
219 | $.elycharts.featuresmanager.register($.elycharts.highlightmanager, 21);
220 |
221 | })(jQuery);
222 |
--------------------------------------------------------------------------------
/src/elycharts_manager_label.js:
--------------------------------------------------------------------------------
1 | /**********************************************************************
2 | * ELYCHARTS
3 | * A Javascript library to generate interactive charts with vectorial graphics.
4 | *
5 | * Copyright (c) 2010-2014 Void Labs s.n.c. (http://void.it)
6 | * Licensed under the MIT (http://creativecommons.org/licenses/MIT/) license.
7 | **********************************************************************/
8 |
9 | (function($) {
10 |
11 | var common = $.elycharts.common;
12 |
13 | /***********************************************************************
14 | * FEATURE: LABELS
15 | *
16 | * Permette di visualizzare in vari modi le label del grafico.
17 | * In particolare per pie e funnel permette la visualizzazione all'interno
18 | * delle fette.
19 | * Per i line chart le label sono visualizzate già nella gestione assi.
20 | *
21 | * TODO:
22 | * - Comunque per i line chart si potrebbe gestire la visualizzazione
23 | * all'interno delle barre, o sopra i punti.
24 | **********************************************************************/
25 |
26 | $.elycharts.labelmanager = {
27 |
28 | beforeShow : function(env, pieces) {
29 |
30 | if (!common.executeIfChanged(env, ['labels', 'values', 'series']))
31 | return;
32 |
33 | if (env.opt.labels && (env.opt.type == 'pie' || env.opt.type == 'funnel')) {
34 | var /*lastSerie = false, */lastIndex = false;
35 | var paths;
36 |
37 | for (var i = 0; i < pieces.length; i++) {
38 | if (pieces[i].section == 'Series' && pieces[i].subSection == 'Plot') {
39 | var props = common.areaProps(env, 'Series', pieces[i].serie);
40 | if (env.emptySeries && env.opt.series.empty)
41 | props.label = $.extend(true, props.label, env.opt.series.empty.label);
42 | if (props && props.label && props.label.active) {
43 | paths = [];
44 | for (var index = 0; index < pieces[i].paths.length; index++)
45 | if (pieces[i].paths[index].path) {
46 | //lastSerie = pieces[i].serie;
47 | lastIndex = index;
48 | paths.push(this.showLabel(env, pieces[i], pieces[i].paths[index], pieces[i].serie, index, pieces));
49 | } else
50 | paths.push({ path : false, attr : false });
51 | pieces.push({ section : pieces[i].section, serie : pieces[i].serie, subSection : 'Label', paths: paths });
52 | }
53 | }
54 | else if (pieces[i].section == 'Sector' && pieces[i].serie == 'bottom' && !pieces[i].subSection && lastIndex < env.opt.labels.length - 1) {
55 | paths = [];
56 | paths.push(this.showLabel(env, pieces[i], pieces[i], 'Series', env.opt.labels.length - 1, pieces));
57 | pieces.push({ section : pieces[i].section, serie : pieces[i].serie, subSection : 'Label', paths: paths });
58 | }
59 | }
60 |
61 | }
62 | },
63 |
64 | showLabel : function(env, piece, path, serie, index, pieces) {
65 | var pp = common.areaProps(env, 'Series', serie, index);
66 | if (env.opt.labels[index] || pp.label.label) {
67 | var p = path;
68 | var label = pp.label.label ? pp.label.label : env.opt.labels[index];
69 | var center = common.getCenter(p, pp.label.offset);
70 | if (!pp.label.html) {
71 | var attr = pp.label.props;
72 | if (pp.label.frameAnchor) {
73 | attr = common._clone(pp.label.props);
74 | attr['text-anchor'] = pp.label.frameAnchor[0];
75 | attr['alignment-baseline'] = pp.label.frameAnchor[1];
76 | }
77 | /*pieces.push({
78 | path : [ [ 'TEXT', label, center[0], center[1] ] ], attr : attr,
79 | section: 'Series', serie : serie, index : index, subSection : 'Label'
80 | });*/
81 | return { path : [ [ 'TEXT', label, center[0], center[1] ] ], attr : attr };
82 |
83 | } else {
84 | var opacity = 1;
85 | var style = common._clone(pp.label.style);
86 | var set_opacity = (typeof style.opacity != 'undefined')
87 | if (set_opacity) {
88 | opacity = style.opacity;
89 | style.opacity = 0;
90 | }
91 | style.position = 'absolute';
92 | style['z-index'] = 25;
93 |
94 | var el;
95 | if (typeof label == 'string')
96 | el = $('' + label + '
').css(style).prependTo(env.container);
97 | else
98 | el = $(label).css(style).prependTo(env.container);
99 |
100 | // Centramento corretto label
101 | if (env.opt.features.debug.active && el.height() == 0)
102 | 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.');
103 | var posX = center[0];
104 | var posY = center[1];
105 | if (!pp.label.frameAnchor || pp.label.frameAnchor[0] == 'middle')
106 | posX -= el.width() / 2;
107 | else if (pp.label.frameAnchor && pp.label.frameAnchor[0] == 'end')
108 | posX -= el.width();
109 | if (!pp.label.frameAnchor || pp.label.frameAnchor[1] == 'middle')
110 | posY -= el.height() / 2;
111 | else if (pp.label.frameAnchor && pp.label.frameAnchor[1] == 'top')
112 | posY -= el.height();
113 | if (set_opacity)
114 | el.css({ margin: posY + 'px 0 0 ' + posX + 'px', opacity : opacity});
115 | else
116 | el.css({ margin: posY + 'px 0 0 ' + posX + 'px'});
117 |
118 | /*pieces.push({
119 | path : [ [ 'DOMELEMENT', el ] ], attr : false,
120 | section: 'Series', serie : serie, index : index, subSection : 'Label'
121 | });*/
122 | return { path : [ [ 'DOMELEMENT', el ] ], attr : false };
123 |
124 | }
125 | }
126 | return false;
127 | }
128 | }
129 |
130 | $.elycharts.featuresmanager.register($.elycharts.labelmanager, 5);
131 |
132 | })(jQuery);
133 |
--------------------------------------------------------------------------------
/src/elycharts_manager_legend.js:
--------------------------------------------------------------------------------
1 | /**********************************************************************
2 | * ELYCHARTS
3 | * A Javascript library to generate interactive charts with vectorial graphics.
4 | *
5 | * Copyright (c) 2010-2014 Void Labs s.n.c. (http://void.it)
6 | * Licensed under the MIT (http://creativecommons.org/licenses/MIT/) license.
7 | **********************************************************************/
8 |
9 | (function($) {
10 |
11 | var common = $.elycharts.common;
12 |
13 | /***********************************************************************
14 | * FEATURE: LEGEND
15 | **********************************************************************/
16 |
17 | $.elycharts.legendmanager = {
18 |
19 | afterShow : function(env, pieces) {
20 | // TODO the whole thing should simply return "pieces" whose visibility is handled by core, so to enable animations and
21 | // make things more generic.
22 | if (env.legenditems) {
23 | for (item in env.legenditems) {
24 | env.legenditems[item].remove();
25 | }
26 | env.legenditems = false;
27 | }
28 | if (!env.opt.legend || env.opt.legend.length == 0)
29 | return;
30 |
31 | var props = env.opt.features.legend;
32 |
33 | if (props === false) return;
34 |
35 | var propsx = props.x;
36 | if (propsx == 'auto') {
37 | var autox = 1;
38 | propsx = 0;
39 | }
40 | var propswidth = props.width;
41 | if (propswidth == 'auto') {
42 | var autowidth = 1;
43 | propswidth = env.width;
44 | }
45 |
46 | var wauto = 0;
47 | var items = [];
48 | // env.opt.legend normalmente è { serie : 'Legend', ... }, per i pie invece { serie : ['Legend', ...], ... }
49 | var legendCount = 0;
50 | var serie, data, h, w, x, y, xd;
51 | for (serie in env.opt.legend) {
52 | if (env.opt.type != 'pie')
53 | legendCount ++;
54 | else
55 | legendCount += env.opt.legend[serie].length;
56 | }
57 | var i = 0;
58 | for (serie in env.opt.legend) {
59 | if (env.opt.type != 'pie')
60 | data = [ env.opt.legend[serie] ];
61 | else
62 | data = env.opt.legend[serie];
63 |
64 | for (var j = 0; j < data.length; j++) {
65 | var sprops = common.areaProps(env, 'Series', serie, env.opt.type == 'pie' ? j : false);
66 | var computedProps = $.extend(true, {}, props);
67 |
68 | if (sprops.legend)
69 | computedProps = $.extend(true, computedProps, sprops.legend);
70 |
71 | var color = common.getItemColor(env, serie, env.opt.type == 'pie' ? j : false);
72 | if (color) {
73 | common.colorize(env, computedProps, [['dotProps', 'fill']], color);
74 | }
75 |
76 | // legacy support for legend dot color inherited from pie "fill"
77 | // TODO maybe we should simply remove this and leave the "color" support only
78 | if (!computedProps.dotProps.fill && env.opt.type == 'pie') {
79 | if (sprops.plotProps && sprops.plotProps.fill)
80 | computedProps.dotProps.fill = sprops.plotProps.fill;
81 | }
82 |
83 | var hMargin = props.margins ? props.margins[0] + props.margins[2] : 0;
84 | var wMargin = props.margins ? props.margins[1] + props.margins[3] : 0;
85 | var tMargin = props.margins ? props.margins[0] : 0;
86 | var lMargin = props.margins ? props.margins[3] : 0;
87 |
88 | if (!props.horizontal) {
89 | // Posizione dell'angolo in alto a sinistra
90 | h = (props.height - hMargin) / legendCount;
91 | w = propswidth - wMargin;
92 | x = Math.floor(propsx + lMargin);
93 | y = Math.floor(props.y + tMargin + h * i);
94 | } else {
95 | h = props.height - hMargin;
96 | if (!props.itemWidth || props.itemWidth == 'fixed') {
97 | w = (propswidth - wMargin) / legendCount;
98 | x = Math.floor(propsx + lMargin + w * i);
99 | } else {
100 | w = (propswidth - wMargin) - wauto;
101 | x = Math.floor(propsx + lMargin + wauto);
102 | }
103 | y = Math.floor(props.y + tMargin);
104 | }
105 |
106 | if (computedProps.dotType == "rect") {
107 | items.push(common.showPath(env, [ [ 'RECT', props.dotMargins[0] + x, y + Math.floor((h - computedProps.dotHeight) / 2), props.dotMargins[0] + x + computedProps.dotWidth, y + Math.floor((h - computedProps.dotHeight) / 2) + computedProps.dotHeight, computedProps.dotR ] ]).attr(computedProps.dotProps));
108 | xd = props.dotMargins[0] + computedProps.dotWidth + props.dotMargins[1];
109 | } else if (computedProps.dotType == "circle") {
110 | items.push(common.showPath(env, [ [ 'CIRCLE', props.dotMargins[0] + x + computedProps.dotR, y + (h / 2), computedProps.dotR ] ]).attr(computedProps.dotProps));
111 | xd = props.dotMargins[0] + computedProps.dotR * 2 + props.dotMargins[1];
112 | }
113 |
114 | var text = data[j];
115 | var t = common.showPath(env, [ [ 'TEXT', text, x + xd, y + Math.ceil(h / 2) + (Raphael.VML ? 2 : 0) ] ]).attr({"text-anchor" : "start"}).attr(computedProps.textProps); //.hide();
116 | items.push(t);
117 | while (t.getBBox().width > (w - xd) && t.getBBox().width > 10) {
118 | text = text.substring(0, text.length - 1);
119 | t.attr({text : text});
120 | }
121 | t.show();
122 |
123 | if (props.horizontal && props.itemWidth == 'auto')
124 | wauto += xd + t.getBBox().width + 4;
125 | else if (!props.horizontal && autowidth)
126 | wauto = t.getBBox().width + xd > wauto ? t.getBBox().width + xd : wauto;
127 | else
128 | wauto += w;
129 |
130 | i++;
131 | }
132 | }
133 |
134 | if (autowidth)
135 | propswidth = wauto + props.margins[3] + props.margins[1] - 1;
136 | if (autox) {
137 | propsx = Math.floor((env.width - propswidth) / 2);
138 | for (i in items) {
139 | if (items[i].attrs.x)
140 | items[i].attr('x', items[i].attrs.x + propsx);
141 | else
142 | items[i].attr('path', common.movePath(env, items[i].attrs.path, [propsx, 0]));
143 | }
144 | }
145 | var borderPath = [ [ 'RECT', propsx, props.y, propsx + propswidth, props.y + props.height, props.r ] ];
146 | var border = common.showPath(env, borderPath).attr(props.borderProps);
147 |
148 | // The legend rectangle is written as the last one because it depends on the sizes of the contents but it should
149 | // be drawn behind the others, so at the end we bring to front all items but the border
150 | for(i in items) items[i].toFront();
151 |
152 | items.unshift(border);
153 |
154 | env.legenditems = items;
155 | }
156 | }
157 |
158 | $.elycharts.featuresmanager.register($.elycharts.legendmanager, 90);
159 |
160 | })(jQuery);
161 |
--------------------------------------------------------------------------------
/src/elycharts_manager_mouse.js:
--------------------------------------------------------------------------------
1 | /**********************************************************************
2 | * ELYCHARTS
3 | * A Javascript library to generate interactive charts with vectorial graphics.
4 | *
5 | * Copyright (c) 2010-2014 Void Labs s.n.c. (http://void.it)
6 | * Licensed under the MIT (http://creativecommons.org/licenses/MIT/) license.
7 | **********************************************************************/
8 |
9 | (function($) {
10 |
11 | var featuresmanager = $.elycharts.featuresmanager;
12 | var common = $.elycharts.common;
13 |
14 | /***********************************************************************
15 | * MOUSEMANAGER
16 | **********************************************************************/
17 |
18 | $.elycharts.mousemanager = {
19 |
20 | clear : function(env) {
21 | if (env.mouseLayer) {
22 | env.mouseLayer.remove();
23 | env.mouseLayer = null;
24 | env.mousePaper.clear();
25 | env.mousePaper.remove();
26 | env.mousePaper = null;
27 | env.mouseTimer = null;
28 | env.mouseAreas = null;
29 | // NOTE: do we also need to unbind mouseover/mouseout from areas or is this handled automatically by Raphael?
30 | }
31 | },
32 |
33 | afterShow : function(env, pieces) {
34 | if (!env.opt.interactive)
35 | return;
36 |
37 | this.clear(env);
38 |
39 | env.mouseLayer = $('
').css({position : 'absolute', 'z-index' : 20, opacity : 1}).prependTo(env.container);
40 | env.mousePaper = common._RaphaelInstance(env.mouseLayer.get(0), env.width, env.height);
41 | var paper = env.mousePaper;
42 |
43 | if (env.opt.features.debug.active && typeof DP_Debug != 'undefined') {
44 | env.paper.text(env.width, env.height - 5, 'DEBUG').attr({ 'text-anchor' : 'end', stroke: 'red', opacity: .1 });
45 | paper.text(env.width, env.height - 5, 'DEBUG').attr({ 'text-anchor' : 'end', stroke: 'red', opacity: .1 }).click(function() {
46 | DP_Debug.dump(env.opt, '', false, 4);
47 | });
48 | }
49 |
50 | var i, j;
51 |
52 | // Adding mouseover only in right area, based on pieces
53 | env.mouseAreas = [];
54 | if (env.opt.features.mousearea.type == 'single') {
55 | // SINGLE: Every serie's index is an area
56 | for (i = 0; i < pieces.length; i++) {
57 | if (pieces[i].mousearea) {
58 | // pathstep
59 | if (!pieces[i].paths) {
60 | // path standard, generating an area for each point
61 | if (pieces[i].path.length >= 1 && (pieces[i].path[0][0] == 'LINE' || pieces[i].path[0][0] == 'LINEAREA'))
62 | for (j = 0; j < pieces[i].path[0][1].length; j++) {
63 | var props = common.areaProps(env, pieces[i].section, pieces[i].serie);
64 | if (props.mouseareaShowOnNull || pieces[i].section != 'Series' || env.opt.values[pieces[i].serie][j] != null)
65 | env.mouseAreas.push({
66 | path : [ [ 'CIRCLE', pieces[i].path[0][1][j][0], pieces[i].path[0][1][j][1], 10 ] ],
67 | piece : pieces[i],
68 | pieces : pieces,
69 | index : j,
70 | props : props
71 | });
72 | }
73 |
74 | else // Code below is only for standard path - it should be useless now (now there are only LINE and LINEAREA)
75 | // TODO DELETE
76 | for (j = 0; j < pieces[i].path.length; j++) {
77 | env.mouseAreas.push({
78 | path : [ [ 'CIRCLE', common.getX(pieces[i].path[j]), common.getY(pieces[i].path[j]), 10 ] ],
79 | piece : pieces[i],
80 | pieces : pieces,
81 | index : j,
82 | props : common.areaProps(env, pieces[i].section, pieces[i].serie)
83 | });
84 | }
85 |
86 | // paths
87 | } else if (pieces[i].paths) {
88 | // Set of paths (bar graph?), generating overlapped areas
89 | for (j = 0; j < pieces[i].paths.length; j++)
90 | if (pieces[i].paths[j].path)
91 | env.mouseAreas.push({
92 | path : pieces[i].paths[j].path,
93 | piece : pieces[i],
94 | pieces : pieces,
95 | index : j,
96 | props : common.areaProps(env, pieces[i].section, pieces[i].serie)
97 | });
98 | }
99 | }
100 | }
101 | } else {
102 | // INDEX: Each index (in every serie) is an area
103 | var indexCenter = env.opt.features.mousearea.indexCenter;
104 | if (indexCenter == 'auto')
105 | indexCenter = env.indexCenter;
106 | var start, delta;
107 | if (indexCenter == 'bar') {
108 | delta = (env.width - env.opt.margins[3] - env.opt.margins[1]) / (env.opt.labels.length > 0 ? env.opt.labels.length : 1);
109 | start = env.opt.margins[3];
110 | } else {
111 | delta = (env.width - env.opt.margins[3] - env.opt.margins[1]) / (env.opt.labels.length > 1 ? env.opt.labels.length - 1 : 1);
112 | start = env.opt.margins[3] - delta / 2;
113 | }
114 |
115 | for (var idx in env.opt.labels) {
116 | // idx can be a string and concatenation results in bad sums.
117 | var index = parseInt(idx);
118 | env.mouseAreas.push({
119 | path : [ [ 'RECT', start + index * delta, env.height - env.opt.margins[2], start + (index + 1) * delta, env.opt.margins[0] ] ],
120 | piece : false,
121 | pieces : pieces,
122 | index : parseInt(index),
123 | props : env.opt.defaultSeries // TODO common.areaProps(env, 'Plot')
124 | });
125 | }
126 | }
127 |
128 | var syncenv = false;
129 | if (!env.opt.features.mousearea.syncTag) {
130 | env.mouseareaenv = { chartEnv : false, mouseObj : false, caller : false, inArea : -1, timer : false };
131 | syncenv = env.mouseareaenv;
132 | } else {
133 | if (!$.elycharts.mouseareaenv)
134 | $.elycharts.mouseareaenv = {};
135 | if (!$.elycharts.mouseareaenv[env.opt.features.mousearea.syncTag])
136 | $.elycharts.mouseareaenv[env.opt.features.mousearea.syncTag] = { chartEnv : false, mouseObj : false, caller : false, inArea : -1, timer : false };
137 | syncenv = $.elycharts.mouseareaenv[env.opt.features.mousearea.syncTag];
138 | }
139 | for (i = 0; i < env.mouseAreas.length; i++) {
140 | env.mouseAreas[i].area = common.showPath(env, env.mouseAreas[i].path, paper).attr({stroke: "#000", fill: "#fff", opacity: 0});
141 |
142 | (function(env, obj, objidx, caller, syncenv) {
143 | var piece = obj.piece;
144 | var index = obj.index;
145 |
146 | obj.mouseover = function(e) {
147 | //BIND: if (obj.listenerDisabled) return;
148 | obj.event = e;
149 | clearTimeout(syncenv.timer);
150 | caller.onMouseOverArea(env, piece, index, obj);
151 |
152 | if (syncenv.chartEnv && syncenv.chartEnv.id != env.id) {
153 | // Chart changed, removing old one
154 | syncenv.caller.onMouseExitArea(syncenv.chartEnv, syncenv.mouseObj.piece, syncenv.mouseObj.index, syncenv.mouseObj);
155 | caller.onMouseEnterArea(env, piece, index, obj);
156 | }
157 | else if (syncenv.inArea != objidx) {
158 | if (syncenv.inArea < 0)
159 | caller.onMouseEnterArea(env, piece, index, obj);
160 | else
161 | caller.onMouseChangedArea(env, piece, index, obj);
162 | }
163 | syncenv.chartEnv = env;
164 | syncenv.mouseObj = obj;
165 | syncenv.caller = caller;
166 | syncenv.inArea = objidx;
167 | };
168 | obj.mouseout = function(e) {
169 | //BIND: if (obj.listenerDisabled) return;
170 | obj.event = e;
171 | clearTimeout(syncenv.timer);
172 | caller.onMouseOutArea(env, piece, index, obj);
173 | syncenv.timer = setTimeout(function() {
174 | syncenv.timer = false;
175 | caller.onMouseExitArea(env, piece, index, obj);
176 | syncenv.chartEnv = false;
177 | syncenv.inArea = -1;
178 | }, env.opt.features.mousearea.areaMoveDelay);
179 | };
180 |
181 | $(obj.area.node).mouseover(obj.mouseover);
182 | $(obj.area.node).mouseout(obj.mouseout);
183 | })(env, env.mouseAreas[i], i, this, syncenv);
184 | }
185 | },
186 |
187 | // Called when mouse enter an area
188 | onMouseOverArea : function(env, piece, index, mouseAreaData) {
189 | //console.warn('over', piece.serie, index);
190 | if (env.opt.features.mousearea.onMouseOver)
191 | env.opt.features.mousearea.onMouseOver(env, mouseAreaData.piece ? mouseAreaData.piece.serie : false, mouseAreaData.index, mouseAreaData);
192 | featuresmanager.onMouseOver(env, mouseAreaData.piece ? mouseAreaData.piece.serie : false, mouseAreaData.index, mouseAreaData);
193 | },
194 |
195 | // Called when mouse exit from an area
196 | onMouseOutArea : function(env, piece, index, mouseAreaData) {
197 | //console.warn('out', piece.serie, index);
198 | if (env.opt.features.mousearea.onMouseOut)
199 | env.opt.features.mousearea.onMouseOut(env, mouseAreaData.piece ? mouseAreaData.piece.serie : false, mouseAreaData.index, mouseAreaData);
200 | featuresmanager.onMouseOut(env, mouseAreaData.piece ? mouseAreaData.piece.serie : false, mouseAreaData.index, mouseAreaData);
201 | },
202 |
203 | // Called when mouse enter an area from empty space (= it was in no area before)
204 | onMouseEnterArea : function(env, piece, index, mouseAreaData) {
205 | //console.warn('enter', piece.serie, index);
206 | if (env.opt.features.mousearea.onMouseEnter)
207 | env.opt.features.mousearea.onMouseEnter(env, mouseAreaData.piece ? mouseAreaData.piece.serie : false, mouseAreaData.index, mouseAreaData);
208 | featuresmanager.onMouseEnter(env, mouseAreaData.piece ? mouseAreaData.piece.serie : false, mouseAreaData.index, mouseAreaData);
209 | },
210 |
211 | // Called when mouse enter an area and it was on another area
212 | onMouseChangedArea : function(env, piece, index, mouseAreaData) {
213 | //console.warn('changed', piece.serie, index);
214 | if (env.opt.features.mousearea.onMouseChanged)
215 | env.opt.features.mousearea.onMouseChanged(env, mouseAreaData.piece ? mouseAreaData.piece.serie : false, mouseAreaData.index, mouseAreaData);
216 | featuresmanager.onMouseChanged(env, mouseAreaData.piece ? mouseAreaData.piece.serie : false, mouseAreaData.index, mouseAreaData);
217 | },
218 |
219 | // Called when mouse leaves an area and does not enter in another one (timeout check)
220 | onMouseExitArea : function(env, piece, index, mouseAreaData) {
221 | //console.warn('exit', piece.serie, index);
222 | if (env.opt.features.mousearea.onMouseExit)
223 | env.opt.features.mousearea.onMouseExit(env, mouseAreaData.piece ? mouseAreaData.piece.serie : false, mouseAreaData.index, mouseAreaData);
224 | featuresmanager.onMouseExit(env, mouseAreaData.piece ? mouseAreaData.piece.serie : false, mouseAreaData.index, mouseAreaData);
225 | }
226 |
227 | }
228 |
229 | $.elycharts.featuresmanager.register($.elycharts.mousemanager, 0);
230 |
231 | })(jQuery);
232 |
--------------------------------------------------------------------------------
/src/elycharts_manager_shadow.js:
--------------------------------------------------------------------------------
1 | /**********************************************************************
2 | * ELYCHARTS
3 | * A Javascript library to generate interactive charts with vectorial graphics.
4 | *
5 | * Copyright (c) 2010-2014 Void Labs s.n.c. (http://void.it)
6 | * Licensed under the MIT (http://creativecommons.org/licenses/MIT/) license.
7 | **********************************************************************/
8 |
9 | (function($) {
10 |
11 | /***********************************************************************
12 | * FEATURE: SHADOW
13 | **********************************************************************/
14 |
15 | $.elycharts.shadowmanager = {
16 |
17 | beforeShow : function(env, pieces) {
18 | if (!env.opt.features.shadows || !env.opt.features.shadows.active)
19 | return;
20 |
21 | // TODO if (!common.changed(env, ['labels', 'series']))
22 | // TODO FIX
23 | var shadowOffset = env.opt.features.shadows.offset;
24 |
25 | var shadows = [];
26 | for (var i = 0; i < pieces.length; i++) {
27 | var path = [];
28 | for (var j = 0; j < pieces[i].path.length; j++) {
29 | var o = pieces[i].path[j];
30 | switch (o[0]) {
31 | case 'M': case 'L':
32 | path.push([o[0], o[1] + shadowOffset[0], o[2] + shadowOffset[1]]);
33 | break;
34 | case 'A': case 'C':
35 | path.push([o[0], o[1], o[2], o[3], o[4], o[5], o[6] + shadowOffset[0], o[7] + shadowOffset[1]]);
36 | break;
37 | case 'z': case 'Z':
38 | path.push([o[0]]);
39 | break;
40 | }
41 | }
42 | shadows.push({path: path, attr: env.opt.features.shadows.props});
43 | }
44 | for (var i = shadows.length - 1; i >= 0; i--)
45 | pieces.unshift(shadows[i]);
46 | }
47 | }
48 |
49 | $.elycharts.featuresmanager.register($.elycharts.shadowmanager, 5);
50 |
51 | })(jQuery);
52 |
--------------------------------------------------------------------------------
/src/elycharts_manager_tooltip.js:
--------------------------------------------------------------------------------
1 | /**********************************************************************
2 | * ELYCHARTS
3 | * A Javascript library to generate interactive charts with vectorial graphics.
4 | *
5 | * Copyright (c) 2010-2014 Void Labs s.n.c. (http://void.it)
6 | * Licensed under the MIT (http://creativecommons.org/licenses/MIT/) license.
7 | **********************************************************************/
8 |
9 | (function($) {
10 |
11 | var common = $.elycharts.common;
12 |
13 | /***********************************************************************
14 | * FEATURE: TOOLTIP
15 | **********************************************************************/
16 |
17 | $.elycharts.tooltipmanager = {
18 |
19 | clear : function(env) {
20 | if (env.tooltipContainer) {
21 | env.tooltipFrame.clear();
22 | env.tooltipFrame.remove();
23 | env.tooltipFrame = null;
24 | env.tooltipFrameElement = null;
25 | env.tooltipContent.remove();
26 | env.tooltipContent = null;
27 | env.tooltipContainer.remove();
28 | env.tooltipContainer = null;
29 | }
30 | },
31 |
32 | afterShow : function(env, pieces) {
33 | this.clear(env);
34 |
35 | if (!$.elycharts.tooltipid)
36 | $.elycharts.tooltipid = 0;
37 | $.elycharts.tooltipid ++;
38 |
39 | // Preparo il tooltip
40 | env.tooltipContainer = $('').appendTo(document.body);
41 | env.tooltipFrame = common._RaphaelInstance('elycharts_tooltip_' + $.elycharts.tooltipid + '_frame', 500, 500);
42 | env.tooltipContent = $('#elycharts_tooltip_' + $.elycharts.tooltipid + '_content');
43 | },
44 |
45 | _prepareShow : function(env, props, mouseAreaData, tip) {
46 |
47 | // Il dimensionamento del tooltip e la view del frame SVG, lo fa solo se width ed height sono specificati
48 | if (props.width && props.width != 'auto' && props.height && props.height != 'auto') {
49 | var delta = props.frameProps && props.frameProps['stroke-width'] ? props.frameProps['stroke-width'] : 0;
50 | env.tooltipContainer.width(props.width + delta + 1).height(props.height + delta + 1);
51 | if (!env.tooltipFrameElement && props.frameProps) {
52 | var framePath = [ [ 'RECT', delta / 2, delta / 2, props.width, props.height, props.roundedCorners ] ];
53 | env.tooltipFrameElement = common.showPath(env, framePath, env.tooltipFrame).attr(props.frameProps);
54 | // env.tooltipFrameElement = env.tooltipFrame.rect(delta / 2, delta / 2, props.width, props.height, props.roundedCorners);
55 | }
56 | }
57 |
58 | if (env.tooltipFrameElement) {
59 | env.tooltipFrameElement.attr(props.frameProps);
60 | }
61 |
62 | if (props.padding)
63 | env.tooltipContent.css({ padding : props.padding[0] + 'px ' + props.padding[1] + 'px' });
64 | env.tooltipContent.css(props.contentStyle);
65 | env.tooltipContent.html(tip);
66 |
67 | //BIND: env.tooltipContainer.unbind().mouseover(mouseAreaData.mouseover).mouseout(mouseAreaData.mouseout);
68 |
69 | // WARN: Prendendo env.paper.canvas non va bene...
70 | //var offset = $(env.paper.canvas).offset();
71 | var offset = $(env.container).offset();
72 |
73 | if (env.opt.features.tooltip.fixedPos) {
74 | offset.top += env.opt.features.tooltip.fixedPos[1];
75 | offset.left += env.opt.features.tooltip.fixedPos[0];
76 |
77 | } else {
78 | var coord = this.getXY(env, props, mouseAreaData);
79 | if (!coord[2]) {
80 | offset.left += coord[0];
81 | while (offset.top + coord[1] < 0)
82 | coord[1] += 20;
83 | offset.top += coord[1];
84 | } else {
85 | offset.left = coord[0];
86 | offset.top = coord[1];
87 | }
88 | }
89 |
90 | return { top : offset.top, left : offset.left };
91 | },
92 |
93 | /**
94 | * Ritorna [x, y] oppure [x, y, true] se le coordinate sono relative alla pagina (e non al grafico)
95 | */
96 | getXY : function(env, props, mouseAreaData) {
97 | // NOTA Posizione mouse: mouseAreaData.event.pageX/pageY
98 | var x = 0, y = 0;
99 | if (mouseAreaData.path[0][0] == 'RECT') {
100 | // L'area e' su un rettangolo (un bar o un indice completo), il tooltip lo faccio subito sopra
101 | // Nota: per capire se e' sull'indice completo basta guardare mouseAreaData.piece == null
102 | x = common.getX(mouseAreaData.path[0]) - props.offset[1];
103 | y = common.getY(mouseAreaData.path[0]) - props.height - props.offset[0];
104 | }
105 | else if (mouseAreaData.path[0][0] == 'CIRCLE') {
106 | // L'area e' su un cerchio (punto di un line)
107 | x = common.getX(mouseAreaData.path[0]) - props.offset[1];
108 | y = common.getY(mouseAreaData.path[0]) - props.height - props.offset[0];
109 | }
110 | else if (mouseAreaData.path[0][0] == 'SLICE') {
111 | // L'area è su una fetta di torta (pie)
112 | var path = mouseAreaData.path[0];
113 |
114 | // Genera la posizione del tip considerando che deve stare all'interno di un cerchio che è sempre dalla parte opposta dell'area
115 | // e deve essere il piu' vicino possibile all'area
116 | var w = props.width && props.width != 'auto' ? props.width : 100;
117 | var h = props.height && props.height != 'auto' ? props.height : 100;
118 | // Raggio del cerchio che contiene il tip
119 | var cr = Math.sqrt(Math.pow(w,2) + Math.pow(h,2)) / 2;
120 | if (cr > env.opt.r)
121 | cr = env.opt.r;
122 |
123 | var tipangle = path[5] + (path[6] - path[5]) / 2 + 180;
124 | var rad = Math.PI / 180;
125 | x = path[1] + cr * Math.cos(- tipangle * rad) - w / 2;
126 | y = path[2] + cr * Math.sin(- tipangle * rad) - h / 2;
127 | }
128 | else if (mouseAreaData.piece && mouseAreaData.piece.paths && mouseAreaData.index >= 0 && mouseAreaData.piece.paths[mouseAreaData.index] && mouseAreaData.piece.paths[mouseAreaData.index].rect) {
129 | // L'area ha una forma complessa, ma abbiamo il rettangolo di contenimento (funnel)
130 | var rect = mouseAreaData.piece.paths[mouseAreaData.index].rect;
131 | x = rect[0] - props.offset[1];
132 | y = rect[1] - props.height - props.offset[0];
133 | }
134 |
135 | if (env.opt.features.tooltip.positionHandler)
136 | return env.opt.features.tooltip.positionHandler(env, props, mouseAreaData, x, y);
137 | else
138 | return [x, y];
139 | },
140 |
141 | getTip : function(env, serie, index) {
142 | var tip = false;
143 | if (env.opt.tooltips) {
144 | if (typeof env.opt.tooltips == 'function')
145 | 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);
146 | else {
147 | if (serie && env.opt.tooltips[serie] && env.opt.tooltips[serie][index])
148 | tip = env.opt.tooltips[serie][index];
149 | else if (!serie && env.opt.tooltips[index])
150 | tip = env.opt.tooltips[index];
151 | }
152 | }
153 | return tip;
154 | },
155 |
156 | _getProps : function(env, serie, index, mouseAreaData) {
157 | var props = mouseAreaData.props.tooltip;
158 | if (env.emptySeries && env.opt.series.empty)
159 | props = $.extend(true, props, env.opt.series.empty.tooltip);
160 | if (!props || !props.active)
161 | return false;
162 |
163 | if (props.frameProps) {
164 | var color = common.getItemColor(env, serie, index);
165 | if (color) {
166 | props = common._clone(props);
167 | common.colorize(env, props, [['frameProps', 'stroke']], color);
168 | }
169 | }
170 | return props;
171 | },
172 |
173 | _fadeOut : function(env) {
174 | env.tooltipContainer.fadeOut(env.opt.features.tooltip.fadeDelay);
175 | },
176 |
177 | onMouseEnter : function(env, serie, index, mouseAreaData) {
178 | var props = this._getProps(env, serie, index, mouseAreaData);
179 | if (!props) return false;
180 |
181 | var tip = this.getTip(env, serie, index);
182 | if (!tip) {
183 | this._fadeOut(env);
184 | return true;
185 | }
186 |
187 | //if (!env.opt.tooltips || (serie && (!env.opt.tooltips[serie] || !env.opt.tooltips[serie][index])) || (!serie && !env.opt.tooltips[index]))
188 | // return this.onMouseExit(env, serie, index, mouseAreaData);
189 | //var tip = serie ? env.opt.tooltips[serie][index] : env.opt.tooltips[index];
190 |
191 | env.tooltipContainer.css(this._prepareShow(env, props, mouseAreaData, tip)).fadeIn(env.opt.features.tooltip.fadeDelay);
192 |
193 | return true;
194 | },
195 |
196 | onMouseChanged : function(env, serie, index, mouseAreaData) {
197 | var props = this._getProps(env, serie, index, mouseAreaData);
198 | if (!props) return false;
199 |
200 | var tip = this.getTip(env, serie, index);
201 | if (!tip) {
202 | this._fadeOut(env);
203 | return true;
204 | }
205 |
206 | /*if (!env.opt.tooltips || (serie && (!env.opt.tooltips[serie] || !env.opt.tooltips[serie][index])) || (!serie && !env.opt.tooltips[index]))
207 | return this.onMouseExit(env, serie, index, mouseAreaData);
208 | var tip = serie ? env.opt.tooltips[serie][index] : env.opt.tooltips[index];*/
209 |
210 | env.tooltipContainer.clearQueue();
211 |
212 | // NOTE: this is needed because sometimes we "fadeOut" during mouseChanged so we also have to fadeIn in that cases.
213 | // For simplicity we always fadeIn every time.
214 | env.tooltipContainer.fadeIn(env.opt.features.tooltip.fadeDelay);
215 | // Nota: Non passo da animationStackPush, i tooltip non sono legati a piece
216 | env.tooltipContainer.animate(this._prepareShow(env, props, mouseAreaData, tip), env.opt.features.tooltip.moveDelay, 'linear' /*swing*/);
217 |
218 | return true;
219 | },
220 |
221 | onMouseExit : function(env, serie, index, mouseAreaData) {
222 | var props = this._getProps(env, serie, index, mouseAreaData);
223 | if (!props) return false;
224 |
225 | this._fadeOut(env);
226 |
227 | return true;
228 | }
229 | }
230 |
231 | $.elycharts.featuresmanager.register($.elycharts.tooltipmanager, 20);
232 |
233 | })(jQuery);
234 |
--------------------------------------------------------------------------------