├── .travis.yml
├── LICENSE
├── README.md
├── artifacts
├── nextcharts-1.5.js
└── nextcharts-1.5.min.js
├── build.xml
├── lib
├── jackson-annotations-2.2.3.jar
├── jackson-core-2.2.3.jar
├── jackson-databind-2.2.3.jar
├── javax.servlet.jar
├── jetty-all-9.0.4.v20130625.jar
├── servlet-api-2.5.jar
└── yuicompressor-2.4.7.jar
└── src
├── html
├── main-jetty-test.html
├── main-test-dualAxis.html
├── main-test.html
└── main-widget-test.html
├── java
└── ro
│ └── nextreports
│ └── charts
│ └── JsonHandler.java
└── js
├── alarm.js
├── barchart.js
├── bubblechart.js
├── chart-util.js
├── color-util.js
├── display.js
├── html2canvas-0.5.0.js
├── indicator.js
├── jquery-1.10.2.min.js
├── jspdf.min-1.0.272.js
├── linechart.js
├── nextchart.js
├── nextwidget.js
├── pdf-capture.js
└── piechart.js
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 | jdk:
3 | - oraclejdk7
4 | script: ant minify-js
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction, and
10 | distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by the copyright
13 | owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all other entities
16 | that control, are controlled by, or are under common control with that entity.
17 | For the purposes of this definition, "control" means (i) the power, direct or
18 | indirect, to cause the direction or management of such entity, whether by
19 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
20 | outstanding shares, or (iii) beneficial ownership of such entity.
21 |
22 | "You" (or "Your") shall mean an individual or Legal Entity exercising
23 | permissions granted by this License.
24 |
25 | "Source" form shall mean the preferred form for making modifications, including
26 | but not limited to software source code, documentation source, and configuration
27 | files.
28 |
29 | "Object" form shall mean any form resulting from mechanical transformation or
30 | translation of a Source form, including but not limited to compiled object code,
31 | generated documentation, and conversions to other media types.
32 |
33 | "Work" shall mean the work of authorship, whether in Source or Object form, made
34 | available under the License, as indicated by a copyright notice that is included
35 | in or attached to the work (an example is provided in the Appendix below).
36 |
37 | "Derivative Works" shall mean any work, whether in Source or Object form, that
38 | is based on (or derived from) the Work and for which the editorial revisions,
39 | annotations, elaborations, or other modifications represent, as a whole, an
40 | original work of authorship. For the purposes of this License, Derivative Works
41 | shall not include works that remain separable from, or merely link (or bind by
42 | name) to the interfaces of, the Work and Derivative Works thereof.
43 |
44 | "Contribution" shall mean any work of authorship, including the original version
45 | of the Work and any modifications or additions to that Work or Derivative Works
46 | thereof, that is intentionally submitted to Licensor for inclusion in the Work
47 | by the copyright owner or by an individual or Legal Entity authorized to submit
48 | on behalf of the copyright owner. For the purposes of this definition,
49 | "submitted" means any form of electronic, verbal, or written communication sent
50 | to the Licensor or its representatives, including but not limited to
51 | communication on electronic mailing lists, source code control systems, and
52 | issue tracking systems that are managed by, or on behalf of, the Licensor for
53 | the purpose of discussing and improving the Work, but excluding communication
54 | that is conspicuously marked or otherwise designated in writing by the copyright
55 | owner as "Not a Contribution."
56 |
57 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf
58 | of whom a Contribution has been received by Licensor and subsequently
59 | incorporated within the Work.
60 |
61 | 2. Grant of Copyright License.
62 |
63 | Subject to the terms and conditions of this License, each Contributor hereby
64 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
65 | irrevocable copyright license to reproduce, prepare Derivative Works of,
66 | publicly display, publicly perform, sublicense, and distribute the Work and such
67 | Derivative Works in Source or Object form.
68 |
69 | 3. Grant of Patent License.
70 |
71 | Subject to the terms and conditions of this License, each Contributor hereby
72 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
73 | irrevocable (except as stated in this section) patent license to make, have
74 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where
75 | such license applies only to those patent claims licensable by such Contributor
76 | that are necessarily infringed by their Contribution(s) alone or by combination
77 | of their Contribution(s) with the Work to which such Contribution(s) was
78 | submitted. If You institute patent litigation against any entity (including a
79 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a
80 | Contribution incorporated within the Work constitutes direct or contributory
81 | patent infringement, then any patent licenses granted to You under this License
82 | for that Work shall terminate as of the date such litigation is filed.
83 |
84 | 4. Redistribution.
85 |
86 | You may reproduce and distribute copies of the Work or Derivative Works thereof
87 | in any medium, with or without modifications, and in Source or Object form,
88 | provided that You meet the following conditions:
89 |
90 | You must give any other recipients of the Work or Derivative Works a copy of
91 | this License; and
92 | You must cause any modified files to carry prominent notices stating that You
93 | changed the files; and
94 | You must retain, in the Source form of any Derivative Works that You distribute,
95 | all copyright, patent, trademark, and attribution notices from the Source form
96 | of the Work, excluding those notices that do not pertain to any part of the
97 | Derivative Works; and
98 | If the Work includes a "NOTICE" text file as part of its distribution, then any
99 | Derivative Works that You distribute must include a readable copy of the
100 | attribution notices contained within such NOTICE file, excluding those notices
101 | that do not pertain to any part of the Derivative Works, in at least one of the
102 | following places: within a NOTICE text file distributed as part of the
103 | Derivative Works; within the Source form or documentation, if provided along
104 | with the Derivative Works; or, within a display generated by the Derivative
105 | Works, if and wherever such third-party notices normally appear. The contents of
106 | the NOTICE file are for informational purposes only and do not modify the
107 | License. You may add Your own attribution notices within Derivative Works that
108 | You distribute, alongside or as an addendum to the NOTICE text from the Work,
109 | provided that such additional attribution notices cannot be construed as
110 | modifying the License.
111 | You may add Your own copyright statement to Your modifications and may provide
112 | additional or different license terms and conditions for use, reproduction, or
113 | distribution of Your modifications, or for any such Derivative Works as a whole,
114 | provided Your use, reproduction, and distribution of the Work otherwise complies
115 | with the conditions stated in this License.
116 |
117 | 5. Submission of Contributions.
118 |
119 | Unless You explicitly state otherwise, any Contribution intentionally submitted
120 | for inclusion in the Work by You to the Licensor shall be under the terms and
121 | conditions of this License, without any additional terms or conditions.
122 | Notwithstanding the above, nothing herein shall supersede or modify the terms of
123 | any separate license agreement you may have executed with Licensor regarding
124 | such Contributions.
125 |
126 | 6. Trademarks.
127 |
128 | This License does not grant permission to use the trade names, trademarks,
129 | service marks, or product names of the Licensor, except as required for
130 | reasonable and customary use in describing the origin of the Work and
131 | reproducing the content of the NOTICE file.
132 |
133 | 7. Disclaimer of Warranty.
134 |
135 | Unless required by applicable law or agreed to in writing, Licensor provides the
136 | Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
137 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
138 | including, without limitation, any warranties or conditions of TITLE,
139 | NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
140 | solely responsible for determining the appropriateness of using or
141 | redistributing the Work and assume any risks associated with Your exercise of
142 | permissions under this License.
143 |
144 | 8. Limitation of Liability.
145 |
146 | In no event and under no legal theory, whether in tort (including negligence),
147 | contract, or otherwise, unless required by applicable law (such as deliberate
148 | and grossly negligent acts) or agreed to in writing, shall any Contributor be
149 | liable to You for damages, including any direct, indirect, special, incidental,
150 | or consequential damages of any character arising as a result of this License or
151 | out of the use or inability to use the Work (including but not limited to
152 | damages for loss of goodwill, work stoppage, computer failure or malfunction, or
153 | any and all other commercial damages or losses), even if such Contributor has
154 | been advised of the possibility of such damages.
155 |
156 | 9. Accepting Warranty or Additional Liability.
157 |
158 | While redistributing the Work or Derivative Works thereof, You may choose to
159 | offer, and charge a fee for, acceptance of support, warranty, indemnity, or
160 | other liability obligations and/or rights consistent with this License. However,
161 | in accepting such obligations, You may act only on Your own behalf and on Your
162 | sole responsibility, not on behalf of any other Contributor, and only if You
163 | agree to indemnify, defend, and hold each Contributor harmless for any liability
164 | incurred by, or claims asserted against, such Contributor by reason of your
165 | accepting any such warranty or additional liability.
166 |
167 | END OF TERMS AND CONDITIONS
168 |
169 | APPENDIX: How to apply the Apache License to your work
170 |
171 | To apply the Apache License to your work, attach the following boilerplate
172 | notice, with the fields enclosed by brackets "[]" replaced with your own
173 | identifying information. (Don't include the brackets!) The text should be
174 | enclosed in the appropriate comment syntax for the file format. We also
175 | recommend that a file or class name and description of purpose be included on
176 | the same "printed page" as the copyright notice for easier identification within
177 | third-party archives.
178 |
179 | Copyright [yyyy] [name of copyright owner]
180 |
181 | Licensed under the Apache License, Version 2.0 (the "License");
182 | you may not use this file except in compliance with the License.
183 | You may obtain a copy of the License at
184 |
185 | http://www.apache.org/licenses/LICENSE-2.0
186 |
187 | Unless required by applicable law or agreed to in writing, software
188 | distributed under the License is distributed on an "AS IS" BASIS,
189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
190 | See the License for the specific language governing permissions and
191 | limitations under the License.
192 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #NextCharts
2 |
3 | NextCharts is an open source HTML5 charts library which uses the canvas tag for drawing. This library is used by [NextReports](https://github.com/nextreports/nextreports) from version 7.
4 |
5 | Following types of charts & styles can be defined (where h stands for horizontal and n for negative):
6 |
7 | * __bar__ : normal, glass, dome, cylinder, parallelepiped, combo with lines
8 | * __nbar__ : normal, glass
9 | * __stackedbar__ : normal, glass, dome, cylinder, parallelepiped
10 | * __hbar__ : normal, glass, dome, cylinder, parallelepiped
11 | * __hstackedbar__ : normal, glass, dome, cylinder, parallelepiped
12 | * __line__ : normal, soliddot, hollowdot, anchordot, bowdot, stardot
13 | * __area__ : normal, soliddot, hollowdot, anchordot, bowdot, stardot
14 | * __pie__
15 | * __bubble__
16 |
17 | 
18 |
19 | NextCharts supports dual axis definition and it allows to have a combo chart with bars and lines. Highlight selection is available on mouse move.
20 |
21 | As opposite to other charts libraries, tooltips are seen only on real selection of elements (and not on any position) and they are following the mouse cursor to allow for a smooth visualization. Other charts libraries have a fixed position for tooltips when entering the selection and user cannot move the mouse to a position which is under the tooltip, making the interaction more clumsy.
22 |
23 | A small number of widgets is also contained by this library. This set includes:
24 |
25 | * __Alarm__ (Status)
26 | * __Indicator__ (Gauge)
27 | * __Display__ (Value & Comparison)
28 |
29 | 
30 |
31 | ##Samples
32 |
33 | Some samples (to see how json properties must be specified) can be found in src/html:
34 |
35 | 1. main-test.html, main-test-dualAxis.html independent chart tests
36 | 2. main-jetty-test.html jetty chart test (must run ro.nextreports.charts.JsonHandler to start server)
37 | 3. main-widget-test.html independent widget test
38 |
39 | ##Articles
40 |
41 | * [Origins](http://blog.next-reports.com/2014/02/nextcharts-new-html5-library-for.html)
42 | * [How To Use](http://blog.next-reports.com/2014/02/nextcharts-developer-perspective.html)
43 | * [Styles](http://blog.next-reports.com/2014/02/nextcharts-styles.html)
44 | * [Tooltips](http://blog.next-reports.com/2014/03/nextcharts-tooltip-messages.html)
45 | * [Dual Y Axis](http://blog.next-reports.com/2014/10/nextcharts-dual-y-axis.html)
46 | * [Combo Bar & Lines](http://blog.next-reports.com/2014/02/nextcharts-combo-bar-line-charts.html)
47 | * [Bubble Chart](http://blog.next-reports.com/2014/03/nextreports-creating-bubble-chart.html)
48 | * [Indicator](http://blog.next-reports.com/2014/05/nextcharts-indicator.html)
49 | * [Display](http://blog.next-reports.com/2014/05/nextcharts-display-widget.html)
50 | * [Display-2](http://blog.next-reports.com/2014/08/display-revisited.html)
51 | * [Alarm](http://blog.next-reports.com/2014/06/nextcharts-alarm-widget.html)
52 | * [Highlights](http://blog.next-reports.com/2015/08/nextcharts-highlight-selection.html)
53 | * [Bar Chart with Negative Values](http://blog.next-reports.com/2015/08/nextcharts-bar-charts-with-negative.html)
54 |
55 | ##Read more
56 |
57 | You can find information about NextCharts on following links:
58 |
59 | 1. NextReports Blog: http://blog.next-reports.com/
60 | 2. NextReports Site: http://next-reports.com/
61 |
62 |
--------------------------------------------------------------------------------
/build.xml:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/lib/jackson-annotations-2.2.3.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nextreports/nextcharts/e4ab233cb426679facba834b3d2ecf1b7a342ffc/lib/jackson-annotations-2.2.3.jar
--------------------------------------------------------------------------------
/lib/jackson-core-2.2.3.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nextreports/nextcharts/e4ab233cb426679facba834b3d2ecf1b7a342ffc/lib/jackson-core-2.2.3.jar
--------------------------------------------------------------------------------
/lib/jackson-databind-2.2.3.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nextreports/nextcharts/e4ab233cb426679facba834b3d2ecf1b7a342ffc/lib/jackson-databind-2.2.3.jar
--------------------------------------------------------------------------------
/lib/javax.servlet.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nextreports/nextcharts/e4ab233cb426679facba834b3d2ecf1b7a342ffc/lib/javax.servlet.jar
--------------------------------------------------------------------------------
/lib/jetty-all-9.0.4.v20130625.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nextreports/nextcharts/e4ab233cb426679facba834b3d2ecf1b7a342ffc/lib/jetty-all-9.0.4.v20130625.jar
--------------------------------------------------------------------------------
/lib/servlet-api-2.5.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nextreports/nextcharts/e4ab233cb426679facba834b3d2ecf1b7a342ffc/lib/servlet-api-2.5.jar
--------------------------------------------------------------------------------
/lib/yuicompressor-2.4.7.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nextreports/nextcharts/e4ab233cb426679facba834b3d2ecf1b7a342ffc/lib/yuicompressor-2.4.7.jar
--------------------------------------------------------------------------------
/src/html/main-jetty-test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NextReports Charts
6 |
7 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
95 |
96 |
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/src/html/main-test-dualAxis.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NextReports Charts
6 |
7 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
144 |
145 |
146 |
147 |
--------------------------------------------------------------------------------
/src/html/main-test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NextReports Charts
6 |
7 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
304 |
305 |
306 |
307 |
308 |
309 |
--------------------------------------------------------------------------------
/src/html/main-widget-test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NextReports Widgets
6 |
7 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
135 |
136 |
137 |
138 |
--------------------------------------------------------------------------------
/src/java/ro/nextreports/charts/JsonHandler.java:
--------------------------------------------------------------------------------
1 | package ro.nextreports.charts;
2 |
3 | import javax.servlet.http.HttpServletRequest;
4 | import javax.servlet.http.HttpServletResponse;
5 | import javax.servlet.ServletException;
6 |
7 | import java.io.IOException;
8 |
9 | import org.eclipse.jetty.server.Server;
10 | import org.eclipse.jetty.server.Request;
11 | import org.eclipse.jetty.server.handler.AbstractHandler;
12 |
13 | public class JsonHandler extends AbstractHandler {
14 |
15 | private String jsonHBar =
16 | "{\"data\":[[16,66,24,30,80,52],[48,50,29,60,60,58],[30,40,28,52,34,50]]," +
17 | " \"labels\":[\"JAN\",\"FEB\",\"MAR\",\"APR\",\"MAY\",\"JUN\"]," +
18 | " \"color\":[\"#004CB3\",\"#A04CB3\",\"rgb(40,75,75)\"]," +
19 | " \"legend\":[\"2011 First year of work\",\"2012 Second year of work\",\"2013 Third year of work\"]," +
20 | " \"alpha\":0.6, \"showGridX\":true, \"showGridY\":true, \"colorGridX\":\"rgb(0,198,189)\", \"colorGridY\":\"rgb(0,198,189)\"," +
21 | // " \"message\":\"Value #val from #total\"," +
22 | // " \"showTicks\":false, " +
23 | " \"tickCount\":5, " +
24 | " \"title\":{\"text\":\"Financial Analysis\", \"font\":{\"weight\":\"bold\", \"size\":16, \"family\":\"sans-serif\"}, \"color\":\"blue\", \"alignment\":\"center\"}," +
25 | " \"labelOrientation\":\"vertical\"," +
26 | // //" \"background\":\"rgb(231,254,254)\"," +
27 | " \"type\":\"hstackedbar\"," +
28 | " \"style\":\"cylinder\"," +
29 | " \"yData\":{\"font\":{\"weight\":\"bold\",\"size\":14,\"family\":\"sans-serif\"}, \"color\":\"blue\"}," +
30 | " \"xData\":{\"font\":{\"weight\":\"bold\",\"size\":14,\"family\":\"sans-serif\"}, \"color\":\"blue\"}," +
31 | " \"yLegend\":{\"text\":\"Price\",\"font\":{\"weight\":\"bold\",\"size\":14,\"family\":\"sans-serif\"}, \"color\":\"#993366\"}," +
32 | " \"xLegend\":{\"text\":\"Month\",\"font\":{\"weight\":\"bold\",\"size\":14,\"family\":\"sans-serif\"}, \"color\":\"#993366\"}" +
33 | "}";
34 |
35 | // "{\"data\":[[16,66,24,42,49,8]], \"type\":\"hbar\" }";
36 |
37 | // "{\"data\":[[20.0,5.0,12.0]],\"type\":\"bar\",\"style\":\"glass\",\"background\":\"#ffffff\",\"labels\":[\"Dunn Brandon\",\"Frest Mark\",\"Winters John\"],\"labelOrientation\":\"horizontal\",\"color\":[\"#0000cc\"],\"legend\":[\"WRK\"],\"alpha\":0.5,\"colorXaxis\":\"#000000\",\"colorYaxis\":\"#000000\",\"showGridX\":true,\"showGridY\":true,\"tickCount\":5,\"showTicks\":true,\"title\":{\"text\":\"Next Reports Hours\",\"font\":{\"weight\":\"bold\",\"size\":16,\"family\":\"SansSerif\"},\"color\":\"#000000\",\"alignment\":\"center\"},\"xData\":{\"color\":\"#000000\",\"font\":{\"weight\":\"normal\",\"size\":12,\"family\":\"SansSerif\"}},\"yData\":{\"color\":\"#000000\",\"font\":{\"weight\":\"normal\",\"size\":12,\"family\":\"SansSerif\"}}}";
38 |
39 | private String jsonBar =
40 | "{\"data\":[[16,66,24,30,80,52],[48,50,29,60,70,58],[30,40,28,52,74,50]]," +
41 | " \"labels\":[\"JANUARY\",\"FEBRUARY\",\"MARCH\",\"APRIL\",\"MAY\",\"JUNE\"]," +
42 | " \"color\":[\"#004CB3\",\"#A04CB3\",\"#7aa37a\"]," +
43 | " \"legend\":[\"2011 First year of work\",\"2012 Second year of work\",\"2013 Third year of work\"]," +
44 | " \"alpha\":0.8, \"showGridX\":false, \"showGridY\":true," +
45 | " \"message\":\"Value #val\", \"tickCount\":5, " +
46 | " \"title\":{\"text\":\"Financial Analysis\", \"font\":{\"weight\":\"bold\", \"size\":16, \"family\":\"sans-serif\"}, \"color\":\"blue\"}," +
47 | " \"labelOrientation\":\"horizontal\"," +
48 | " \"type\":\"bar\"," +
49 | " \"style\":\"glass\"," +
50 | //" \"onclick\":\"function() console.log(\"Call from JS function\");\"" +
51 | " \"onClick\":\"function doClick(value){ console.log('Call from function : ' + value);}\""+
52 | "}";
53 |
54 | private String jsonStacked =
55 | "{\"data\":[[16,66,24,30,80,52],[48,50,29,60,60,58],[20,40,28,52,34,50]]," +
56 | " \"labels\":[\"JAN\",\"FEB\",\"MAR\",\"APR\",\"MAY\",\"JUN\"]," +
57 | " \"color\":[\"#004CB3\",\"#A04CB3\",\"rgb(40,75,75)\"]," +
58 | " \"legend\":[\"2011 First year of work\",\"2012 Second year of work\",\"2013 Third year of work\"]," +
59 | " \"alpha\":0.6, \"showGridX\":true, \"showGridY\":true, \"colorGridX\":\"rgb(0,198,189)\", \"colorGridY\":\"rgb(0,198,189)\"," +
60 | //" \"colorXaxis\":\"blue\", \"colorYaxis\":\"red\"," +
61 | " \"message\":\"Value #val from #total\", \"tickCount\":5, " +
62 | " \"title\":{\"text\":\"Financial Analysis\", \"font\":{\"weight\":\"bold\", \"size\":16, \"family\":\"sans-serif\"}, \"color\":\"blue\", \"alignment\":\"center\"}," +
63 | " \"labelOrientation\":\"horizontal\"," +
64 | " \"background\":\"rgb(231,254,254)\"," +
65 | " \"type\":\"stackedbar\"," +
66 | " \"style\":\"dome\"," +
67 | " \"yData\":{\"font\":{\"weight\":\"bold\",\"size\":14,\"family\":\"sans-serif\"}, \"color\":\"blue\"}," +
68 | " \"xData\":{\"font\":{\"weight\":\"bold\",\"size\":14,\"family\":\"sans-serif\"}, \"color\":\"blue\"}," +
69 | " \"yLegend\":{\"text\":\"Price\",\"font\":{\"weight\":\"bold\",\"size\":14,\"family\":\"sans-serif\"}, \"color\":\"#993366\"}," +
70 | " \"xLegend\":{\"text\":\"Month\",\"font\":{\"weight\":\"bold\",\"size\":14,\"family\":\"sans-serif\"}, \"color\":\"#993366\"}" +
71 | "}";
72 |
73 | private String jsonStackLine =
74 | "{\"data\":[[16,66,24,30,80,52],[48,50,29,60,60,58],[30,40,28,52,34,50]]," +
75 | " \"lineData\":[[31.33, 52, 27, 47.33, 74.66, 53.33],[100, 120, 53, 190, 40, 130]],"+
76 | " \"labels\":[\"JAN\",\"FEB\",\"MAR\",\"APR\",\"MAY\",\"JUN\"]," +
77 | " \"color\":[\"#004CB3\",\"#A04CB3\",\"rgb(40,75,75)\"]," +
78 | " \"lineColor\":[\"#270283\", \"#CC6633\"]," +
79 | " \"legend\":[\"2011\",\"2012\",\"2013\"]," +
80 | " \"lineLegend\":[\"Average\", \"Profit\"]," +
81 | " \"alpha\":0.6, \"showGridX\":true, \"showGridY\":true, \"colorGridX\":\"rgb(0,198,189)\", \"colorGridY\":\"rgb(0,198,189)\"," +
82 | " \"message\":\"Value #val from #total\", \"tickCount\":5, " +
83 | " \"title\":{\"text\":\"Financial Analysis\", \"font\":{\"weight\":\"bold\", \"size\":16, \"family\":\"sans-serif\"}, \"color\":\"blue\", \"alignment\":\"center\"}," +
84 | " \"labelOrientation\":\"horizontal\"," +
85 | //" \"background\":\"rgb(231,254,254)\"," +
86 | " \"type\":\"stackedbar\"," +
87 | " \"style\":\"glass\"," +
88 | " \"yData\":{\"font\":{\"weight\":\"bold\",\"size\":14,\"family\":\"sans-serif\"}, \"color\":\"blue\"}," +
89 | " \"xData\":{\"font\":{\"weight\":\"bold\",\"size\":14,\"family\":\"sans-serif\"}, \"color\":\"blue\"}," +
90 | " \"yLegend\":{\"text\":\"Price\",\"font\":{\"weight\":\"bold\",\"size\":14,\"family\":\"sans-serif\"}, \"color\":\"#993366\"}," +
91 | " \"xLegend\":{\"text\":\"Month\",\"font\":{\"weight\":\"bold\",\"size\":14,\"family\":\"sans-serif\"}, \"color\":\"#993366\"}" +
92 | "}";
93 |
94 | /** bar line */
95 | // "{\"data\":[[2,3,2,3,2,1],[1,2,1,2,3,1]]," +
96 | // " \"lineData\":[[2,1,3,2,3,2]],"+
97 | // " \"labels\":[\"4\",\"10\",\"6\",\"5\",\"4\",\"9\"]," +
98 | // " \"color\":[\"#7C7CD2\",\"#FB7C6C\"]," +
99 | // " \"lineColor\":[\"#8BE2A0\"]," +
100 | // " \"legend\":[\"One\",\"Two\"]," +
101 | // " \"lineLegend\":[\"Three\"]," +
102 | // " \"alpha\":1, \"showGridX\":true, \"showGridY\":true, \"colorGridX\":\"#F5E1AA\", \"colorGridY\":\"#F5E1AA\"," +
103 | // " \"message\":\"Value #val from #total\", \"tickCount\":5, " +
104 | // " \"background\":\"#F8F8D8\"," +
105 | // " \"type\":\"bar\"," +
106 | // " \"style\":\"normal\"" +
107 | // "}";
108 |
109 | /** bar line - bet index */
110 | // "{\"data\":[[6205, 6090, 6220, 6350, 6140, 6560, 6230, 6165, 6180, 6175, 6235, 6210]]," +
111 | // " \"lineData\":[[6490, 6455, 6485, 6500, 6550, 6600, 6575, 6510, 6530, 6540, 6560, 6555]],"+
112 | // " \"labels\":[\"3\",\"6\",\"7\",\"8\",\"9\",\"10\",\"13\",\"14\",\"15\",\"16\",\"17\",\"20\"]," +
113 | // " \"color\":[\"#004CB3\"]," +
114 | // " \"lineColor\":[\"#A04CB3\"]," +
115 | // " \"legend\":[\"Valoare tranzactii (mil RON)\"]," +
116 | // " \"lineLegend\":[\"Indice BET (puncte)\"]," +
117 | // " \"alpha\":1, \"showGridX\":false, \"showGridY\":true, \"colorGridX\":\"red\", \"colorGridY\":\"rgb(0,198,189)\"," +
118 | // " \"message\":\"#val\", \"tickCount\":5, " +
119 | // " \"type\":\"bar\"," +
120 | // " \"style\":\"glass\"" +
121 | // "}";
122 |
123 |
124 |
125 | private String jsonLine =
126 | "{\"data\":[[16,66,24,30,80,52],[48,50,29,60,60,58],[30,40,28,52,34,50]]," +
127 | " \"labels\":[\"JAN\",\"FEB\",\"MAR\",\"APR\",\"MAY\",\"JUN\"]," +
128 | " \"color\":[\"#004CB3\",\"#A04CB3\",\"rgb(40,75,75)\"]," +
129 | " \"legend\":[\"2011 First year of work\",\"2012 Second year of work\",\"2013 Third year of work\"]," +
130 | " \"alpha\":0.4, \"showGridX\":true, \"showGridY\":true, \"colorGridX\":\"rgb(0,198,189)\", \"colorGridY\":\"rgb(0,198,189)\"," +
131 | " \"message\":\"Value #val\", \"tickCount\":5, " +
132 | " \"title\":{\"text\":\"Financial Analysis\", \"font\":{\"weight\":\"bold\", \"size\":16, \"family\":\"sans-serif\"}, \"color\":\"blue\", \"alignment\":\"center\"}," +
133 | " \"labelOrientation\":\"horizontal\"," +
134 | //" \"background\":\"rgb(231,254,254)\"," +
135 | " \"type\":\"area\"," +
136 | " \"style\":\"soliddot\"," +
137 | " \"yData\":{\"font\":{\"weight\":\"bold\",\"size\":14,\"family\":\"sans-serif\"}, \"color\":\"blue\"}," +
138 | " \"xData\":{\"font\":{\"weight\":\"bold\",\"size\":14,\"family\":\"sans-serif\"}, \"color\":\"blue\"}," +
139 | " \"yLegend\":{\"text\":\"Price\",\"font\":{\"weight\":\"bold\",\"size\":14,\"family\":\"sans-serif\"}, \"color\":\"#993366\"}," +
140 | " \"xLegend\":{\"text\":\"Month\",\"font\":{\"weight\":\"bold\",\"size\":14,\"family\":\"sans-serif\"}, \"color\":\"#993366\"}" +
141 | "}";
142 |
143 | private String jsonPie =
144 | "{\"data\":[[16,66,24,30,80,52]]," +
145 | " \"labels\":[\"JANUARY\",\"FEBRUARY\",\"MARCH\",\"APRIL\",\"MAY\",\"JUNE\"]," +
146 | " \"color\": [\"#004CB3\",\"#A04CB3\", \"#7aa37a\", \"#f18e9f\", \"#90e269\", \"#bc987b\"]," +
147 | " \"alpha\":0.4," +
148 | " \"message\":\"Value #val from #total #percent% of 100%\"," +
149 | " \"title\":{\"text\":\"Financial Analysis\", \"font\":{\"weight\":\"bold\", \"size\":16, \"family\":\"sans-serif\"}, \"color\":\"blue\", \"alignment\":\"center\"}," +
150 | //" \"background\":\"rgb(231,254,254)\"," +
151 | " \"xData\":{\"font\":{\"weight\":\"bold\",\"size\":16,\"family\":\"sans-serif\"}, \"color\":\"blue\"}," +
152 | " \"type\":\"pie\"" +
153 | "}";
154 |
155 | private String jsonBubble =
156 | "{\"data\":[[80.66,79.84,78.6,72.73,80.05,72.49,68.09,81.55,68.6,78.09],[1.67,1.36,1.84,2.78,2,1.7,4.77,2.96,1.54,2.05],[33739900,81902307,5523095,79716203,61801570,73137148,31090763,7485600,141850000,307007000],[\"North America\",\"Europe\",\"Europe\",\"Middle East\",\"Europe\",\"Middle East\",\"Middle East\",\"Middle East\",\"Europe\",\"North America\"]]," +
157 | " \"labels\":[\"CAN\",\"DEU\",\"DNK\",\"EGY\",\"GBN\",\"IRN\",\"IRQ\",\"ISR\",\"RUS\",\"USA\"]," +
158 | " \"color\":[\"#004CB3\",\"#A04CB3\",\"#7aa37a\"]," +
159 | " \"categories\":[\"North America\",\"Europe\",\"Europe\",\"Middle East\",\"Europe\",\"Middle East\",\"Middle East\",\"Middle East\",\"Europe\",\"North America\"]," +
160 | " \"alpha\":0.6," +
161 | " \"showGridX\":true," +
162 | " \"showGridY\":true," +
163 | " \"colorGridX\":\"rgb(0,198,189)\"," +
164 | " \"colorGridY\":\"rgb(0,198,189)\"," +
165 | " \"message\":\"#label Life Expectancy: #x Fertility Rate: #val Region: #c Population: #z\"," +
166 | " \"tickCount\":4, " +
167 | " \"title\":{\"text\":\"Population Correlation\", \"font\":{\"weight\":\"bold\", \"size\":14, \"family\":\"sans-serif\"}, \"color\":\"blue\", \"alignment\":\"center\"}," +
168 | " \"labelOrientation\":\"horizontal\"," +
169 | " \"type\":\"bubble\"," +
170 | " \"style\":\"normal\"," +
171 | " \"yData\":{\"font\":{\"weight\":\"bold\",\"size\":14,\"family\":\"sans-serif\"}, \"color\":\"blue\"}," +
172 | " \"xData\":{\"font\":{\"weight\":\"bold\",\"size\":14,\"family\":\"sans-serif\"}, \"color\":\"blue\"}," +
173 | " \"yLegend\":{\"text\":\"Fertility Rate\",\"font\":{\"weight\":\"bold\",\"size\":14,\"family\":\"sans-serif\"}, \"color\":\"#993366\"}," +
174 | " \"xLegend\":{\"text\":\"Life Expectancy\",\"font\":{\"weight\":\"bold\",\"size\":14,\"family\":\"sans-serif\"}, \"color\":\"#993366\"}" +
175 | "}";
176 |
177 | public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
178 | throws IOException, ServletException {
179 |
180 | String type = request.getParameter("type");
181 | response.setContentType("application/json");
182 | response.setHeader("Access-Control-Allow-Origin", "*");
183 | response.setStatus(HttpServletResponse.SC_OK);
184 | baseRequest.setHandled(true);
185 | if (type.equals("hbar")) {
186 | response.getWriter().println(jsonHBar);
187 | } else if (type.equals("bar")) {
188 | response.getWriter().println(jsonBar);
189 | } else if (type.equals("stackedbar")) {
190 | response.getWriter().println(jsonStacked);
191 | } else if (type.equals("line")) {
192 | response.getWriter().println(jsonLine);
193 | } else if (type.equals("pie")) {
194 | response.getWriter().println(jsonPie);
195 | } else if (type.equals("bubble")) {
196 | response.getWriter().println(jsonBubble);
197 | } else {
198 | response.getWriter().println(jsonStackLine);
199 | }
200 | }
201 |
202 | public static void main(String[] args) throws Exception {
203 | Server server = new Server(8080);
204 | server.setHandler(new JsonHandler());
205 |
206 | server.start();
207 | server.join();
208 | }
209 | }
210 |
--------------------------------------------------------------------------------
/src/js/alarm.js:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * Alarm (status)
4 | *
5 | * {
6 | * "text" : "Project is on track.",
7 | * "color" : "green",
8 | * "background" : "white",
9 | * "shadow" : true
10 | * }
11 | *
12 | */
13 | function alarm(id, myjson, zoom, useParentWidth) {
14 |
15 | if (useParentWidth) {
16 | window.addEventListener('resize', resizeAlarmCanvas, false);
17 | }
18 |
19 | drawAlarm(true);
20 |
21 | function drawAlarm(animate) {
22 |
23 | var can = document.getElementById(id);
24 | if (can == null) {
25 | return;
26 | }
27 | var ctx = can.getContext('2d');
28 |
29 | if (zoom == true) {
30 | can.width = $(window).width();
31 | can.height = $(window).height();
32 | }
33 |
34 | if (useParentWidth) {
35 | can.width = can.parentNode.offsetWidth;
36 | }
37 |
38 | var canWidth = can.width;
39 | var canHeight = can.height;
40 | var textSize = canHeight/10;
41 |
42 | var text = myjson.text;
43 | if (typeof text === "undefined") {
44 | text = "";
45 | }
46 |
47 | var color = myjson.color;
48 | if (typeof color === "undefined") {
49 | color = "green";
50 | }
51 |
52 | var background = myjson.background;
53 | if (typeof background === "undefined") {
54 | background = "white";
55 | }
56 |
57 | var shadow = myjson.shadow;
58 | if (typeof shadow === "undefined") {
59 | shadow = false;
60 | }
61 |
62 | if (shadow) {
63 | ctx.shadowColor = "rgba(0,0,0,0.15)";
64 | ctx.shadowOffsetX = 3;
65 | ctx.shadowOffsetY = 3;
66 | ctx.shadowBlur = 2;
67 | }
68 |
69 | var size = canWidth;
70 | if (canHeight < canWidth) {
71 | size = canHeight;
72 | }
73 | var left = canWidth/20; // left padding
74 | var x = Math.pow(size,1.1)/8; // top-bottom padding
75 | var d = 2; // distance between circle and border
76 | var radius = (size - 2 * x) / 2;
77 | var fontSize = Math.log(size/20)*9;
78 |
79 | // clear canvas
80 | ctx.clearRect(0, 0, can.width, can.height);
81 | ctx.fillStyle = background;
82 | ctx.fillRect(0, 0, can.width, can.height);
83 |
84 | //text
85 | ctx.fillStyle = "black";
86 | ctx.font=fontSize + "px Arial";
87 |
88 | var xText = 3*left/2+ 2*radius;
89 | var yText = canHeight/2+ fontSize/4;
90 | var textWidth = ctx.measureText(text).width + left;
91 | var lines = new Array();
92 |
93 | if (xText + textWidth > canWidth) {
94 | // text fills multiple lines
95 | var res = text.split(" ");
96 | var words = res.length;
97 | var line = "";
98 | for (var k=0; k canWidth) {
102 | lines.push(line);
103 | line = res[k] + " ";
104 | } else {
105 | line = sline;
106 | }
107 | }
108 | lines.push(line);
109 | var linesNo = lines.length;
110 | var odd = ((linesNo % 2) != 0);
111 | var mid = Math.floor(linesNo/2);
112 |
113 | if (odd) {
114 | for (var line=0; line 2*d) {
193 | ctx.beginPath();
194 | ctx.arc(x,y,r-2*d,2* Math.PI , 0, false);
195 | ctx.closePath();
196 | ctx.stroke();
197 | ctx.fillStyle = grd;
198 | ctx.fill();
199 | }
200 | }
201 |
202 | function resizeAlarmCanvas() {
203 | var can = document.getElementById(id);
204 | if (can != null) {
205 | drawAlarm(false);
206 | }
207 | }
208 |
209 | }
210 |
211 |
--------------------------------------------------------------------------------
/src/js/bubblechart.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Json must contain as mandatory only "data" attribute
3 | *
4 | * type -> bubble
5 | * style -> normal, glass
6 | * labelOrientation -> horizontal, vertical, diagonal, halfdiagonal
7 | * showLabels -> true means X labels are shown on X axis; we can use false if we want to show them in message tooltip with #x
8 | * message -> can have markup #val for value, #x for x value, #z for size value, #c for category value, #label for id label
9 | * -> can contain to split text on more lines
10 | * title.alignment -> center, left, right
11 | * styleGridX, styleGridY -> line, dot, dash
12 | * onClick -> is a javascript function like 'function doClick(value){ ...}'
13 | *
14 | * data contains : x, y, z
15 | * labels contains ids array (as an exception of other charts, we will not draw them on X axis, but other labels obtained as X ticks from x data)
16 | * categories contains categories array
17 | * color contains colors only for distinct categories
18 | * legend must be computed from categories (unique categories)
19 | *
20 | * { "type": "bubble"
21 | * "style": "normal",
22 | * "background" : "white",
23 | * "data": [[80.66,79.84,78.6,72.73,80.05,72.49,68.09,81.55,68.6,78.09], [ 1.67, 1.36, 1.84, 2.78, 2, 1.7, 4.77, 2.96, 1.54, 2.05 ], [ 33739900, 81902307, 5523095, 79716203, 61801570, 73137148, 31090763, 7485600, 141850000, 307007000 ] ],
24 | * "labels": ["CAN", "DEU", "DNK", "EGY", "GBN", "IRN", "IRQ", "ISR", "RUS", "USA"],
25 | * "categories": [ "North America", "Europe", "Europe", "Middle East", "Europe", "Middle East", "Middle East", "Middle East", "Europe", "North America" ]
26 | * "labelOrientation": "horizontal",
27 | * "color": ["#004CB3","#A04CB3", "#7aa37a"],
28 | * "alpha" : 0.8,
29 | * "colorXaxis": "blue",
30 | * "colorYaxis": "blue",
31 | * "showGridX": true,
32 | * "showGridY": true,
33 | * "showLabels": true,
34 | * "colorGridX": "rgb(248, 248, 216)",
35 | * "colorGridY": "rgb(248, 248, 216)",
36 | * "styleGridX": "line",
37 | * "styleGridY": "line",
38 | * "message" : "Value \: #val",
39 | * "showTicks" : true,
40 | * "tickCount" : 5,
41 | * "startingFromZero" : false,
42 | * "title" : {
43 | * "text": "Correlation between life expectancy, fertility rate and population",
44 | * "font": {
45 | * "weight": "bold",
46 | * "size": "16",
47 | * "family": "sans-serif"
48 | * },
49 | * "color": "#000000",
50 | * "alignment":"left"
51 | * },
52 | * "xData" : {
53 | * "font": {
54 | * "weight": "bold",
55 | * "size": "16",
56 | * "family": "sans-serif"
57 | * },
58 | * "color": "blue"
59 | * },
60 | * "yData" : {
61 | * "font": {
62 | * "weight": "bold",
63 | * "size": "16",
64 | * "family": "sans-serif"
65 | * },
66 | * "color": "blue"
67 | * },
68 | * "xLegend" : {
69 | * "text": "Life Expectancy",
70 | * "font": {
71 | * "weight": "bold",
72 | * "size": "16",
73 | * "family": "sans-serif"
74 | * },
75 | * "color": "blue"
76 | * },
77 | * "yLegend" : {
78 | * "text": "Fertility Rate",
79 | * "font": {
80 | * "weight": "bold",
81 | * "size": "16",
82 | * "family": "sans-serif"
83 | * },
84 | * "color": "blue"
85 | * },
86 | * "tooltipPattern" : {
87 | * "decimals": 2,
88 | * "decimalSeparator" : ".",
89 | * "thousandSeparator" : ","
90 | * },
91 | * "onClick" : "function doClick(value){console.log("Call from function: " + value);}"
92 | * }
93 | *
94 | */
95 |
96 | var bubbleChart = function(myjson, idCan, idTipCan, canWidth, canHeight) {
97 |
98 | var obj;
99 | var data;
100 | var labels = new Array();
101 | var labelOrientation;
102 | var globalAlpha;
103 | var showGridX;
104 | var showGridY;
105 | var showLabels;
106 | var background;
107 | var message;
108 | var tickCount;
109 | var showTicks;
110 | var startingFromZero;
111 | var chartType;
112 | var chartStyle;
113 | var seriesColor;
114 | var xData, yData;
115 | var series;
116 | var uniqueCategories = new Array();
117 | var yStep;
118 | var dotsK = new Array();
119 | var max;
120 | var min;
121 | //space between 2 ticks
122 | var tickStep;
123 |
124 | var minValY;
125 | var maxValY;
126 | // bottom vertical space (to fit X labels and X legend)
127 | var step = 0;
128 | var gap = 40;
129 | // left horizontal space (to fit bigger Y labels and Y legend)
130 | var hStep = 60;
131 | var titleSpace = 0;
132 | var legendSpace = 0;
133 | var xLegendSpace = 0;
134 | var yLegendSpace = 0;
135 | var xaxisY = 0;
136 | var realWidth;
137 | var realHeight;
138 | var canvas;
139 | var c;
140 | var tipCanvas;
141 | var tempCanvas;
142 | var tempCtx;
143 | var H = new Array();
144 | var dotRadius = 3;
145 | // space between X axis and first tick
146 | var tickInit;
147 | var resizeWidth = false;
148 | var resizeHeight = false;
149 | //by default chart title, legends and axis values strings have a defined font size
150 | //if we want to have font size scaled accordingly with chart width then this property must be true
151 | //(such example may be when we want to show the chart on a big monitor)
152 | var adjustableTextFontSize = false;
153 | var highlighterIndex = -1;
154 |
155 | function drawBubble(myjson, idCan, idTipCan, canWidth, canHeight) {
156 |
157 | canvas = document.getElementById(idCan);
158 | if (canvas == null) {
159 | return;
160 | }
161 | tipCanvas = document.getElementById(idTipCan);
162 | c = canvas.getContext('2d');
163 |
164 | tempCanvas = document.createElement('canvas');
165 | tempCtx = tempCanvas.getContext('2d');
166 |
167 | obj = myjson;
168 | chartType = obj.type;
169 | if (typeof chartType === "undefined") {
170 | chartType = "bubble";
171 | }
172 |
173 | background = obj.background;
174 | if (typeof background === "undefined") {
175 | background = "white";
176 | }
177 |
178 | chartStyle = obj.style;
179 | // test for passing a wrong style
180 | if ((typeof chartStyle === "undefined") || (find(['normal', 'glass'],chartStyle) === false)) {
181 | chartStyle = "normal";
182 | }
183 |
184 | data = obj.data[0];
185 | for (var i=0;i 0)) {
254 | min = 0;
255 | }
256 |
257 | var objStep = calculateYStep(min, max, tickCount);
258 | yStep = objStep.yStep;
259 | minValY = objStep.minValY;
260 | maxValY = objStep.maxValY;
261 |
262 | // compute X labels
263 | var xmax = Math.max.apply( Math, obj.data[0]);
264 | var xmin = Math.min.apply( Math, obj.data[0]);
265 | var xobjStep = calculateYStep(xmin, xmax, tickCount);
266 | var x_yStep = xobjStep.yStep;
267 | var minValX = xobjStep.minValY;
268 | var maxValX = xobjStep.maxValY;
269 | for(var i=0; i= H[j]) {
432 | test = true;
433 | }
434 | }
435 | if (test) {
436 | stop = false;
437 | }
438 | } else {
439 | stop = false;
440 | }
441 |
442 | var sColor = getSeriesColor(i);
443 | c.strokeStyle = sColor;
444 |
445 | if (chartStyle == "glass") {
446 | var gradient = c.createLinearGradient( dataX-2*H[i], dataY-2*H[i], 4*H[i], 4*H[i] );
447 | gradient.addColorStop( 0, "#ddd" );
448 | gradient.addColorStop( 1, sColor );
449 | c.fillStyle = gradient;
450 | } else {
451 | c.fillStyle = sColor;
452 | }
453 |
454 | c.beginPath();
455 | c.arc(dataX, dataY, H[i], 0,Math.PI*2);
456 | var fs = c.fillStyle;
457 | if (i == highlighterIndex) {
458 | c.fillStyle = highlightColor(sColor,0.5);
459 | }
460 | if (withFill) {
461 | c.globalAlpha = globalAlpha;
462 | c.fill();
463 | c.globalAlpha = 1;
464 | var oldStroke = c.strokeStyle;
465 | c.strokeStyle = "#fff";
466 | c.stroke();
467 | c.strokeStyle = oldStroke;
468 | } else {
469 | // highlight selection
470 | if (c.isPointInPath(mousePos.x, mousePos.y)) {
471 | hit = true;
472 | }
473 | if (!hit) {
474 | highlighterIndex = -1;
475 | }
476 |
477 | var found;
478 | if (c.isPointInPath(mousePos.x, mousePos.y)) {
479 | if ((smallestRadius == undefined) || (smallestRadius > radius[i])) {
480 | smallestRadius = radius[i];
481 | smallestIndex = i;
482 | }
483 | if (i == smallestIndex) {
484 | highlighterIndex = i;
485 | }
486 | var tValue = obj.data[1][i];
487 | if (obj.tooltipPattern !== undefined) {
488 | tValue = formatNumber(tValue, obj.tooltipPattern.decimals, obj.tooltipPattern.decimalSeparator, obj.tooltipPattern.thousandSeparator);
489 | }
490 | var returnValue = obj.data[0][i]; // tValue
491 | if (withClick) {
492 | if (found === undefined) {
493 | found = returnValue;
494 | }
495 | } else {
496 | var mes = String(message).replace('#val', tValue);
497 | mes = mes.replace('#x', returnValue);
498 | mes = mes.replace('#z', obj.data[2][i]);
499 | mes = mes.replace('#c', obj.categories[i]);
500 | mes = mes.replace('#label', obj.labels[i]);
501 | if (obj.onClick !== undefined) {
502 | cursorStyle = 'pointer';
503 | canvas.style.cursor = cursorStyle;
504 | }
505 | if (found === undefined) {
506 | found = mes;
507 | }
508 | }
509 | } else {
510 | if (cursorStyle != 'pointer') {
511 | canvas.style.cursor = 'default';
512 | }
513 | }
514 | }
515 | }
516 |
517 | if (found !== undefined) {
518 | return found;
519 | }
520 |
521 | if (withFill) {
522 | unhighlight();
523 | return stop;
524 | } else {
525 | // empty tooltip message
526 | return "";
527 | }
528 | }
529 |
530 | function unhighlight(i) {
531 | c.drawImage(tempCanvas, 0, 0);
532 | }
533 |
534 | function getYValue(i, maxValY, yStep) {
535 | var label;
536 | if (obj.tooltipPattern !== undefined) {
537 | // y labels can have more than two decimals
538 | var decimals = obj.tooltipPattern.decimals;
539 | var exp = Math.pow(10, decimals);
540 | label = Math.round((maxValY-i*yStep)*exp)/exp;
541 | } else {
542 | label = Math.round((maxValY-i*yStep)*100)/100;
543 | }
544 | return label;
545 | }
546 |
547 | function getSeriesColor(i) {
548 | var cat = obj.categories[i];
549 | var ind = find(uniqueCategories,cat);
550 | if (ind === false) {
551 | return "white";
552 | }
553 | return seriesColor[ind];
554 | }
555 |
556 | function drawInit() {
557 |
558 | var font = c.font;
559 |
560 | //draw background (clear canvas)
561 | c.fillStyle = background;
562 | c.fillRect(0,0,realWidth,realHeight);
563 |
564 | // adjust step with X label space (x label can have different orientations) and X legend space
565 | var xLabelWidth = computeVStep();
566 |
567 | //draw title
568 | if (typeof obj.title !== "undefined") {
569 | var titleColor = obj.title.color;
570 | if (titleColor === undefined) {
571 | titleColor = '#000000';
572 | }
573 | c.fillStyle = titleColor;
574 | var b = " ";
575 | var f = obj.title.font;
576 | if (f === undefined) {
577 | f.weight = "bold";
578 | f.size = 12;
579 | f.family = "sans-serif";
580 | }
581 | if (adjustableTextFontSize) {
582 | f.size=getAdjustableTitleFontSize();
583 | }
584 | c.font = f.weight + b + f.size + "px" + b + f.family;
585 | var titlePadding = 20;
586 | if (adjustableTextFontSize) {
587 | titlePadding = getAdjustableTitleFontSize()/2;
588 | }
589 | titleSpace = +titlePadding + +f.size;
590 |
591 | var alignment = obj.title.alignment;
592 | if (alignment === undefined) {
593 | alignment = "center";
594 | }
595 | var xTitle;
596 | if (alignment == "left") {
597 | xTitle = hStep;
598 | } else if (alignment == "right") {
599 | xTitle = canvas.width - c.measureText(obj.title.text).width - 10;
600 | } else {
601 | // center
602 | xTitle = canvas.width/2- c.measureText(obj.title.text).width/2;
603 | }
604 |
605 | var titlePadding = 20;
606 | if (adjustableTextFontSize) {
607 | titlePadding = getAdjustableTitleFontSize()/2;
608 | }
609 | c.fillText(obj.title.text, xTitle , titlePadding+titleSpace/2 );
610 | c.font = font;
611 | } else {
612 | titleSpace = 10;
613 | }
614 |
615 |
616 | //draw X legend
617 | if (typeof obj.xLegend !== "undefined") {
618 |
619 | var xLegendColor = obj.xLegend.color;
620 | if (xLegendColor === undefined) {
621 | xLegendColor = '#000000';
622 | }
623 | c.fillStyle = xLegendColor;
624 | var b = " ";
625 | var f = obj.xLegend.font;
626 | if (f === undefined) {
627 | f.weight = "bold";
628 | f.size = 12;
629 | f.family = "sans-serif";
630 | }
631 | if (adjustableTextFontSize) {
632 | f.size = getAdjustableLabelFontSize();
633 | }
634 | c.font = f.weight + b + f.size + "px" + b + f.family;
635 | var legendPadding = 20;
636 | if (adjustableTextFontSize) {
637 | legendPadding = getAdjustableLabelFontSize()/2;
638 | }
639 | xLegendSpace = +legendPadding + +f.size;
640 |
641 | c.fillText(obj.xLegend.text, realWidth/2- c.measureText(obj.xLegend.text).width/2 , realHeight - f.size );
642 | c.font = font;
643 | } else {
644 | xLegendSpace = 0;
645 | }
646 |
647 | //draw Y legend
648 | if (typeof obj.yLegend !== "undefined") {
649 | var yLegendColor = obj.yLegend.color;
650 | if (yLegendColor === undefined) {
651 | yLegendColor = '#000000';
652 | }
653 | var b = " ";
654 | var f = obj.yLegend.font;
655 | if (f === undefined) {
656 | f.weight = "bold";
657 | f.size = 12;
658 | f.family = "sans-serif";
659 | }
660 | if (adjustableTextFontSize) {
661 | f.size = getAdjustableLabelFontSize();
662 | }
663 | c.font = f.weight + b + f.size + "px" + b + f.family;
664 | c.fillStyle = yLegendColor;
665 | c.save();
666 | c.translate(10 , realHeight/2);
667 | c.rotate(-Math.PI/2);
668 | c.textAlign = "center";
669 | c.fillText(obj.yLegend.text,0, f.size);
670 | c.restore();
671 | c.font = font;
672 | } else {
673 | yLegendSpace = 0;
674 | }
675 |
676 | // draw legend
677 | if (typeof obj.legend !== "undefined") {
678 | var x = hStep;
679 | c.font = "bold 10px sans-serif";
680 | if (adjustableTextFontSize) {
681 | c.font = "bold " + getAdjustableLabelFontSize() + "px sans-serif";
682 | }
683 | var legendPadding = 20;
684 | if (adjustableTextFontSize) {
685 | legendPadding = getAdjustableLabelFontSize();
686 | }
687 | legendSpace = legendPadding;
688 | var legendY = titleSpace+legendPadding;
689 | c.globalAlpha = globalAlpha;
690 | for (var k=0; k realWidth) {
695 | // draw legend on next line if does not fit on current one
696 | x = hStep;
697 | var lineSpace = 14;
698 | if (adjustableTextFontSize) {
699 | lineSpace = getAdjustableLabelFontSize();
700 | }
701 | legendY = legendY + lineSpace;
702 | var legendPadding = 20;
703 | if (adjustableTextFontSize) {
704 | legendPadding = getAdjustableLabelFontSize();
705 | }
706 | legendSpace += legendPadding;
707 | }
708 |
709 | c.fillText("---- " + obj.legend[k], x, legendY);
710 |
711 | x = x + legendWidth;
712 | }
713 | c.globalAlpha = 1;
714 | c.font = font;
715 | }
716 |
717 |
718 |
719 | c.font = font;
720 |
721 |
722 | // adjust tickStep depending if title or legend are present or not
723 | tickStep = (realHeight-step-titleSpace-legendSpace-tickInit)/tickCount;
724 |
725 | // compute Y value for xAxis
726 | xaxisY = tickCount*tickStep+tickInit+titleSpace+legendSpace;
727 |
728 | drawLabels(xLabelWidth);
729 | }
730 |
731 |
732 | function drawLabels(xLabelWidth) {
733 |
734 | var font = c.font;
735 |
736 | //draw Y labels and small lines
737 | if (showTicks) {
738 | c.fillStyle = "black";
739 | if (obj.yData !== undefined) {
740 | c.fillStyle = obj.yData.color;
741 | var b = " ";
742 | var yfont = obj.yData.font;
743 | if (adjustableTextFontSize) {
744 | yfont.size=getAdjustableLabelFontSize();
745 | }
746 | c.font = yfont.weight + b + yfont.size + "px" + b + yfont.family;
747 | }
748 | for(var i=0; i maxLabelWidth) {
963 | maxLabelWidth = labelWidth;
964 | }
965 | }
966 | result = maxLabelWidth + 20;
967 | } else {
968 | result = 20;
969 | }
970 | c.font = font;
971 | if (typeof obj.yLegend !== "undefined") {
972 | var b = " ";
973 | var f = obj.yLegend.font;
974 | if (f === undefined) {
975 | f.weight = "bold";
976 | f.size = 12;
977 | f.family = "sans-serif";
978 | }
979 | if (adjustableTextFontSize) {
980 | f.size = getAdjustableLabelFontSize();
981 | }
982 | c.font = f.weight + b + f.size + "px" + b + f.family;
983 | var legendPadding = 20;
984 | if (adjustableTextFontSize) {
985 | legendPadding = getAdjustableLabelFontSize();
986 | }
987 | yLegendSpace = +legendPadding + +f.size;
988 | c.font = font;
989 | result += yLegendSpace;
990 | }
991 |
992 | // take care for halfdiagonal, diagonal long labels
993 | // if they are too long hStep must be increased accordingly
994 | var cf = c.font;
995 | if (obj.xData !== undefined) {
996 | var b = " ";
997 | var xfont = obj.xData.font;
998 | if (adjustableTextFontSize) {
999 | xfont.size=getAdjustableLabelFontSize();
1000 | }
1001 | c.font = xfont.weight + b + xfont.size + "px" + b + xfont.family;
1002 | }
1003 | var minPos = new Array();
1004 | for(var i=0; i 0) {
1020 | if (len < 10) {
1021 | result += (10 - len);
1022 | }
1023 | }
1024 |
1025 | return result;
1026 | }
1027 |
1028 | // computes vertical step needed
1029 | // returns maximum width for x labels
1030 | function computeVStep() {
1031 | var xLabelWidth = 0;
1032 | if (typeof obj.xData !== "undefined") {
1033 | var xfont = obj.xData.font;
1034 | if (adjustableTextFontSize) {
1035 | xfont.size=getAdjustableLabelFontSize();
1036 | }
1037 | var b = " ";
1038 | c.font = xfont.weight + b + xfont.size + "px" + b + xfont.family;
1039 | }
1040 | if (showLabels) {
1041 | for(var i=0; i xLabelWidth) {
1044 | xLabelWidth = labelWidth;
1045 | }
1046 | }
1047 | }
1048 | var _xLegendSpace = 0;
1049 | if (typeof obj.xLegend !== "undefined") {
1050 | var f = obj.xLegend.font;
1051 | if (f === undefined) {
1052 | f.weight = "bold";
1053 | f.size = 12;
1054 | f.family = "sans-serif";
1055 | }
1056 | if (adjustableTextFontSize) {
1057 | f.size = getAdjustableLabelFontSize();
1058 | }
1059 | var legendPadding = 20;
1060 | if (adjustableTextFontSize) {
1061 | legendPadding = getAdjustableLabelFontSize();
1062 | }
1063 | _xLegendSpace = +legendPadding + +f.size;
1064 | }
1065 | if ((step < xLabelWidth+_xLegendSpace) || adjustableTextFontSize) {
1066 | step = xLabelWidth+_xLegendSpace;
1067 | }
1068 | return xLabelWidth;
1069 | }
1070 |
1071 | // depends on label orientation
1072 | function computeXLabelSpace(label) {
1073 | var _labelWidth = c.measureText(label).width + 10; // vertical
1074 |
1075 | if (labelOrientation === "horizontal") {
1076 | if (typeof obj.xData !== "undefined") {
1077 | _labelWidth = obj.xData.font.size + 20;
1078 | if (adjustableTextFontSize) {
1079 | _labelWidth=getAdjustableLabelFontSize() + 20;
1080 | }
1081 | } else {
1082 | _labelWidth = 12 + 20;
1083 | }
1084 | } else if (labelOrientation === "halfdiagonal") {
1085 | _labelWidth = c.measureText(label).width * Math.sin(Math.PI/8) + 20;
1086 | } else if (labelOrientation === "diagonal") {
1087 | _labelWidth = c.measureText(label).width * Math.sin(Math.PI/4) + 20;
1088 | }
1089 |
1090 | return _labelWidth;
1091 | }
1092 |
1093 | function getTitleSpace() {
1094 | var space = 10;
1095 | if (typeof obj.title !== "undefined") {
1096 | var f = obj.title.font;
1097 | if (f === undefined) {
1098 | f.size = 12;
1099 | }
1100 | if (adjustableTextFontSize) {
1101 | f.size=getAdjustableTitleFontSize();
1102 | }
1103 | var titlePadding = 20;
1104 | if (adjustableTextFontSize) {
1105 | titlePadding = getAdjustableTitleFontSize();
1106 | }
1107 | space = +titlePadding + +f.size;
1108 | }
1109 | return space;
1110 | }
1111 |
1112 | function getXLegendSpace() {
1113 | var _xLegendSpace = 0;
1114 | if (typeof obj.xLegend !== "undefined") {
1115 | var f = obj.xLegend.font;
1116 | if (f === undefined) {
1117 | f.size = 12;
1118 | }
1119 | var legendPadding = 20;
1120 | if (adjustableTextFontSize) {
1121 | f.size = getAdjustableLabelFontSize();
1122 | legendPadding = getAdjustableLabelFontSize();
1123 | }
1124 | _xLegendSpace = +legendPadding + +f.size;
1125 | }
1126 | return _xLegendSpace;
1127 | }
1128 |
1129 | function getLegendSpace() {
1130 | var font = c.font;
1131 | var _legendSpace = 20;
1132 | if (typeof obj.legend !== "undefined") {
1133 | var x = hStep;
1134 | c.font = "bold 10px sans-serif";
1135 | if (adjustableTextFontSize) {
1136 | c.font ="bold " + getAdjustableLabelFontSize() + "px sans-serif";
1137 | }
1138 | var legendPadding = 20;
1139 | if (adjustableTextFontSize) {
1140 | legendPadding = getAdjustableLabelFontSize()/2;
1141 | }
1142 | var legendY = getTitleSpace()+legendPadding;
1143 | for (var k=0; k realWidth) {
1147 | // draw legend on next line if does not fit on current one
1148 | x = hStep;
1149 | var lineSpace = 14;
1150 | if (adjustableTextFontSize) {
1151 | lineSpace = getAdjustableLabelFontSize();
1152 | }
1153 | legendY = legendY + lineSpace;
1154 | var pad = 20;
1155 | if (adjustableTextFontSize) {
1156 | pad = getAdjustableLabelFontSize();
1157 | }
1158 | _legendSpace += pad;
1159 | }
1160 |
1161 | x = x + legendWidth;
1162 | }
1163 | }
1164 | c.font = font;
1165 | return _legendSpace;
1166 | }
1167 |
1168 | function resizeCanvas() {
1169 | var can = document.getElementById(idCan);
1170 | if (can != null) {
1171 | var w = canWidth;
1172 | if (resizeWidth) {
1173 | if (!isPercent(w)) {
1174 | w = "100%";
1175 | }
1176 | }
1177 | var h = canHeight;
1178 | if (resizeHeight) {
1179 | if (!isPercent(h)) {
1180 | h = "100%";
1181 | }
1182 | }
1183 | updateSize(w, h);
1184 | drawChart();
1185 | }
1186 | }
1187 |
1188 | function getAdjustableTitleFontSize() {
1189 | return canvas.width/25;
1190 | }
1191 |
1192 | function getAdjustableLabelFontSize() {
1193 | return canvas.width/45;
1194 | }
1195 |
1196 | drawBubble(myjson, idCan, idTipCan, canWidth, canHeight);
1197 |
1198 | };
1199 |
1200 |
--------------------------------------------------------------------------------
/src/js/chart-util.js:
--------------------------------------------------------------------------------
1 | // This function starts by creating a dummy