blazer 1.7.7 → 2.6.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (139) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +242 -33
  3. data/CONTRIBUTING.md +42 -0
  4. data/LICENSE.txt +1 -1
  5. data/README.md +621 -211
  6. data/app/assets/fonts/blazer/glyphicons-halflings-regular.eot +0 -0
  7. data/app/assets/fonts/blazer/glyphicons-halflings-regular.svg +0 -0
  8. data/app/assets/fonts/blazer/glyphicons-halflings-regular.ttf +0 -0
  9. data/app/assets/fonts/blazer/glyphicons-halflings-regular.woff +0 -0
  10. data/app/assets/fonts/blazer/glyphicons-halflings-regular.woff2 +0 -0
  11. data/app/assets/images/blazer/favicon.png +0 -0
  12. data/app/assets/javascripts/blazer/Chart.js +15658 -10011
  13. data/app/assets/javascripts/blazer/Sortable.js +3413 -848
  14. data/app/assets/javascripts/blazer/ace/ace.js +21294 -4
  15. data/app/assets/javascripts/blazer/ace/ext-language_tools.js +1991 -3
  16. data/app/assets/javascripts/blazer/ace/mode-sql.js +110 -1
  17. data/app/assets/javascripts/blazer/ace/snippets/sql.js +40 -1
  18. data/app/assets/javascripts/blazer/ace/snippets/text.js +14 -1
  19. data/app/assets/javascripts/blazer/ace/theme-twilight.js +116 -1
  20. data/app/assets/javascripts/blazer/application.js +5 -3
  21. data/app/assets/javascripts/blazer/bootstrap.js +842 -628
  22. data/app/assets/javascripts/blazer/chartkick.js +2015 -1244
  23. data/app/assets/javascripts/blazer/daterangepicker.js +372 -299
  24. data/app/assets/javascripts/blazer/highlight.min.js +3 -0
  25. data/app/assets/javascripts/blazer/{jquery_ujs.js → jquery-ujs.js} +161 -75
  26. data/app/assets/javascripts/blazer/jquery.js +10126 -9562
  27. data/app/assets/javascripts/blazer/jquery.stickytableheaders.js +321 -259
  28. data/app/assets/javascripts/blazer/moment-timezone-with-data.js +1546 -0
  29. data/app/assets/javascripts/blazer/moment.js +5085 -2460
  30. data/app/assets/javascripts/blazer/queries.js +18 -4
  31. data/app/assets/javascripts/blazer/routes.js +3 -0
  32. data/app/assets/javascripts/blazer/selectize.js +3828 -3604
  33. data/app/assets/javascripts/blazer/stupidtable-custom-settings.js +13 -0
  34. data/app/assets/javascripts/blazer/stupidtable.js +254 -87
  35. data/app/assets/javascripts/blazer/vue.js +11175 -6676
  36. data/app/assets/stylesheets/blazer/application.css +51 -6
  37. data/app/assets/stylesheets/blazer/bootstrap-propshaft.css +10 -0
  38. data/app/assets/stylesheets/blazer/bootstrap-sprockets.css.erb +10 -0
  39. data/app/assets/stylesheets/blazer/{bootstrap.css.erb → bootstrap.css} +1337 -711
  40. data/app/assets/stylesheets/blazer/{daterangepicker-bs3.css → daterangepicker.css} +207 -172
  41. data/app/assets/stylesheets/blazer/{selectize.default.css → selectize.css} +26 -10
  42. data/app/controllers/blazer/base_controller.rb +73 -46
  43. data/app/controllers/blazer/checks_controller.rb +1 -1
  44. data/app/controllers/blazer/dashboards_controller.rb +7 -13
  45. data/app/controllers/blazer/queries_controller.rb +171 -51
  46. data/app/controllers/blazer/uploads_controller.rb +147 -0
  47. data/app/helpers/blazer/base_helper.rb +6 -16
  48. data/app/models/blazer/audit.rb +3 -3
  49. data/app/models/blazer/check.rb +31 -5
  50. data/app/models/blazer/dashboard.rb +6 -2
  51. data/app/models/blazer/dashboard_query.rb +1 -1
  52. data/app/models/blazer/query.rb +30 -4
  53. data/app/models/blazer/record.rb +5 -0
  54. data/app/models/blazer/upload.rb +11 -0
  55. data/app/models/blazer/uploads_connection.rb +7 -0
  56. data/app/views/blazer/_nav.html.erb +3 -1
  57. data/app/views/blazer/_variables.html.erb +48 -23
  58. data/app/views/blazer/check_mailer/failing_checks.html.erb +1 -0
  59. data/app/views/blazer/check_mailer/state_change.html.erb +1 -0
  60. data/app/views/blazer/checks/_form.html.erb +17 -9
  61. data/app/views/blazer/checks/edit.html.erb +2 -0
  62. data/app/views/blazer/checks/index.html.erb +37 -5
  63. data/app/views/blazer/checks/new.html.erb +2 -0
  64. data/app/views/blazer/dashboards/_form.html.erb +5 -5
  65. data/app/views/blazer/dashboards/edit.html.erb +2 -0
  66. data/app/views/blazer/dashboards/new.html.erb +2 -0
  67. data/app/views/blazer/dashboards/show.html.erb +13 -7
  68. data/app/views/blazer/queries/_caching.html.erb +16 -0
  69. data/app/views/blazer/queries/_cohorts.html.erb +48 -0
  70. data/app/views/blazer/queries/_form.html.erb +23 -13
  71. data/app/views/blazer/queries/docs.html.erb +137 -0
  72. data/app/views/blazer/queries/home.html.erb +21 -7
  73. data/app/views/blazer/queries/run.html.erb +64 -29
  74. data/app/views/blazer/queries/schema.html.erb +44 -7
  75. data/app/views/blazer/queries/show.html.erb +15 -8
  76. data/app/views/blazer/uploads/_form.html.erb +27 -0
  77. data/app/views/blazer/uploads/edit.html.erb +3 -0
  78. data/app/views/blazer/uploads/index.html.erb +55 -0
  79. data/app/views/blazer/uploads/new.html.erb +3 -0
  80. data/app/views/layouts/blazer/application.html.erb +10 -5
  81. data/config/routes.rb +10 -1
  82. data/lib/blazer/adapters/athena_adapter.rb +182 -0
  83. data/lib/blazer/adapters/base_adapter.rb +24 -1
  84. data/lib/blazer/adapters/bigquery_adapter.rb +79 -0
  85. data/lib/blazer/adapters/cassandra_adapter.rb +70 -0
  86. data/lib/blazer/adapters/drill_adapter.rb +38 -0
  87. data/lib/blazer/adapters/druid_adapter.rb +102 -0
  88. data/lib/blazer/adapters/elasticsearch_adapter.rb +30 -18
  89. data/lib/blazer/adapters/hive_adapter.rb +55 -0
  90. data/lib/blazer/adapters/ignite_adapter.rb +64 -0
  91. data/lib/blazer/adapters/influxdb_adapter.rb +57 -0
  92. data/lib/blazer/adapters/mongodb_adapter.rb +5 -1
  93. data/lib/blazer/adapters/neo4j_adapter.rb +62 -0
  94. data/lib/blazer/adapters/opensearch_adapter.rb +52 -0
  95. data/lib/blazer/adapters/presto_adapter.rb +9 -0
  96. data/lib/blazer/adapters/salesforce_adapter.rb +50 -0
  97. data/lib/blazer/adapters/snowflake_adapter.rb +82 -0
  98. data/lib/blazer/adapters/soda_adapter.rb +105 -0
  99. data/lib/blazer/adapters/spark_adapter.rb +14 -0
  100. data/lib/blazer/adapters/sql_adapter.rb +187 -20
  101. data/{app/mailers → lib}/blazer/check_mailer.rb +0 -0
  102. data/lib/blazer/data_source.rb +107 -30
  103. data/lib/blazer/engine.rb +21 -23
  104. data/lib/blazer/result.rb +95 -29
  105. data/lib/blazer/run_statement.rb +8 -4
  106. data/lib/blazer/run_statement_job.rb +8 -9
  107. data/lib/blazer/slack_notifier.rb +94 -0
  108. data/lib/blazer/statement.rb +75 -0
  109. data/lib/blazer/version.rb +1 -1
  110. data/lib/blazer.rb +154 -26
  111. data/lib/generators/blazer/install_generator.rb +7 -18
  112. data/lib/generators/blazer/templates/{config.yml → config.yml.tt} +26 -3
  113. data/lib/generators/blazer/templates/{install.rb → install.rb.tt} +6 -4
  114. data/lib/generators/blazer/templates/uploads.rb.tt +10 -0
  115. data/lib/generators/blazer/uploads_generator.rb +18 -0
  116. data/lib/tasks/blazer.rake +11 -1
  117. data/licenses/LICENSE-ace.txt +24 -0
  118. data/licenses/LICENSE-bootstrap.txt +21 -0
  119. data/licenses/LICENSE-chart.js.txt +9 -0
  120. data/licenses/LICENSE-chartkick.js.txt +22 -0
  121. data/licenses/LICENSE-daterangepicker.txt +21 -0
  122. data/licenses/LICENSE-fuzzysearch.txt +20 -0
  123. data/licenses/LICENSE-highlight.js.txt +29 -0
  124. data/licenses/LICENSE-jquery-ujs.txt +20 -0
  125. data/licenses/LICENSE-jquery.txt +20 -0
  126. data/licenses/LICENSE-moment-timezone.txt +20 -0
  127. data/licenses/LICENSE-moment.txt +22 -0
  128. data/licenses/LICENSE-selectize.txt +202 -0
  129. data/licenses/LICENSE-sortable.txt +21 -0
  130. data/licenses/LICENSE-stickytableheaders.txt +20 -0
  131. data/licenses/LICENSE-stupidtable.txt +19 -0
  132. data/licenses/LICENSE-vue.txt +21 -0
  133. metadata +83 -53
  134. data/.gitignore +0 -14
  135. data/Gemfile +0 -4
  136. data/Rakefile +0 -1
  137. data/app/assets/javascripts/blazer/highlight.pack.js +0 -1
  138. data/app/assets/javascripts/blazer/moment-timezone.js +0 -1007
  139. data/blazer.gemspec +0 -26
@@ -2,22 +2,15 @@
2
2
  * Chartkick.js
3
3
  * Create beautiful charts with one line of JavaScript
4
4
  * https://github.com/ankane/chartkick.js
5
- * v2.2.1
5
+ * v3.2.1
6
6
  * MIT License
7
7
  */
8
8
 
9
- /*jslint browser: true, indent: 2, plusplus: true, vars: true */
10
-
11
- (function (window) {
12
- 'use strict';
13
-
14
- var config = window.Chartkick || {};
15
- var Chartkick, ISO8601_PATTERN, DECIMAL_SEPARATOR, adapters = [];
16
- var DATE_PATTERN = /^(\d\d\d\d)(\-)?(\d\d)(\-)?(\d\d)$/i;
17
- var GoogleChartsAdapter, HighchartsAdapter, ChartjsAdapter;
18
- var pendingRequests = [], runningRequests = 0, maxRequests = 4;
19
-
20
- // helpers
9
+ (function (global, factory) {
10
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
11
+ typeof define === 'function' && define.amd ? define(factory) :
12
+ (global = global || self, global.Chartkick = factory());
13
+ }(this, (function () { 'use strict';
21
14
 
22
15
  function isArray(variable) {
23
16
  return Object.prototype.toString.call(variable) === "[object Array]";
@@ -28,13 +21,17 @@
28
21
  }
29
22
 
30
23
  function isPlainObject(variable) {
31
- return !isFunction(variable) && variable instanceof Object;
24
+ // protect against prototype pollution, defense 2
25
+ return Object.prototype.toString.call(variable) === "[object Object]" && !isFunction(variable) && variable instanceof Object;
32
26
  }
33
27
 
34
28
  // https://github.com/madrobby/zepto/blob/master/src/zepto.js
35
29
  function extend(target, source) {
36
30
  var key;
37
31
  for (key in source) {
32
+ // protect against prototype pollution, defense 1
33
+ if (key === "__proto__") { continue; }
34
+
38
35
  if (isPlainObject(source[key]) || isArray(source[key])) {
39
36
  if (isPlainObject(source[key]) && !isPlainObject(target[key])) {
40
37
  target[key] = {};
@@ -56,9 +53,11 @@
56
53
  return target;
57
54
  }
58
55
 
56
+ var DATE_PATTERN = /^(\d\d\d\d)(-)?(\d\d)(-)?(\d\d)$/i;
57
+
59
58
  // https://github.com/Do/iso8601.js
60
- ISO8601_PATTERN = /(\d\d\d\d)(\-)?(\d\d)(\-)?(\d\d)(T)?(\d\d)(:)?(\d\d)?(:)?(\d\d)?([\.,]\d+)?($|Z|([\+\-])(\d\d)(:)?(\d\d)?)/i;
61
- DECIMAL_SEPARATOR = String(1.5).charAt(1);
59
+ var ISO8601_PATTERN = /(\d\d\d\d)(-)?(\d\d)(-)?(\d\d)(T)?(\d\d)(:)?(\d\d)?(:)?(\d\d)?([.,]\d+)?($|Z|([+-])(\d\d)(:)?(\d\d)?)/i;
60
+ var DECIMAL_SEPARATOR = String(1.5).charAt(1);
62
61
 
63
62
  function parseISO8601(input) {
64
63
  var day, hour, matches, milliseconds, minutes, month, offset, result, seconds, type, year;
@@ -105,6 +104,50 @@
105
104
  return false;
106
105
  }
107
106
 
107
+ function toStr(n) {
108
+ return "" + n;
109
+ }
110
+
111
+ function toFloat(n) {
112
+ return parseFloat(n);
113
+ }
114
+
115
+ function toDate(n) {
116
+ var matches, year, month, day;
117
+ if (typeof n !== "object") {
118
+ if (typeof n === "number") {
119
+ n = new Date(n * 1000); // ms
120
+ } else {
121
+ n = toStr(n);
122
+ if ((matches = n.match(DATE_PATTERN))) {
123
+ year = parseInt(matches[1], 10);
124
+ month = parseInt(matches[3], 10) - 1;
125
+ day = parseInt(matches[5], 10);
126
+ return new Date(year, month, day);
127
+ } else { // str
128
+ // try our best to get the str into iso8601
129
+ // TODO be smarter about this
130
+ var str = n.replace(/ /, "T").replace(" ", "").replace("UTC", "Z");
131
+ n = parseISO8601(str) || new Date(n);
132
+ }
133
+ }
134
+ }
135
+ return n;
136
+ }
137
+
138
+ function toArr(n) {
139
+ if (!isArray(n)) {
140
+ var arr = [], i;
141
+ for (i in n) {
142
+ if (n.hasOwnProperty(i)) {
143
+ arr.push([i, n[i]]);
144
+ }
145
+ }
146
+ n = arr;
147
+ }
148
+ return n;
149
+ }
150
+
108
151
  function jsOptionsFunc(defaultOptions, hideLegend, setTitle, setMin, setMax, setStacked, setXtitle, setYtitle) {
109
152
  return function (chart, opts, chartOptions) {
110
153
  var series = chart.data;
@@ -154,1228 +197,1735 @@
154
197
  };
155
198
  }
156
199
 
157
- function setText(element, text) {
158
- if (document.body.innerText) {
159
- element.innerText = text;
160
- } else {
161
- element.textContent = text;
162
- }
200
+ function sortByTime(a, b) {
201
+ return a[0].getTime() - b[0].getTime();
163
202
  }
164
203
 
165
- function chartError(element, message) {
166
- setText(element, "Error Loading Chart: " + message);
167
- element.style.color = "#ff0000";
204
+ function sortByNumberSeries(a, b) {
205
+ return a[0] - b[0];
168
206
  }
169
207
 
170
- function pushRequest(element, url, success) {
171
- pendingRequests.push([element, url, success]);
172
- runNext();
208
+ function sortByNumber(a, b) {
209
+ return a - b;
173
210
  }
174
211
 
175
- function runNext() {
176
- if (runningRequests < maxRequests) {
177
- var request = pendingRequests.shift()
178
- if (request) {
179
- runningRequests++;
180
- getJSON(request[0], request[1], request[2]);
181
- runNext();
182
- }
183
- }
212
+ function isMinute(d) {
213
+ return d.getMilliseconds() === 0 && d.getSeconds() === 0;
184
214
  }
185
215
 
186
- function requestComplete() {
187
- runningRequests--;
188
- runNext();
216
+ function isHour(d) {
217
+ return isMinute(d) && d.getMinutes() === 0;
189
218
  }
190
219
 
191
- function getJSON(element, url, success) {
192
- ajaxCall(url, success, function (jqXHR, textStatus, errorThrown) {
193
- var message = (typeof errorThrown === "string") ? errorThrown : errorThrown.message;
194
- chartError(element, message);
195
- });
220
+ function isDay(d) {
221
+ return isHour(d) && d.getHours() === 0;
196
222
  }
197
223
 
198
- function ajaxCall(url, success, error) {
199
- var $ = window.jQuery || window.Zepto || window.$;
224
+ function isWeek(d, dayOfWeek) {
225
+ return isDay(d) && d.getDay() === dayOfWeek;
226
+ }
200
227
 
201
- if ($) {
202
- $.ajax({
203
- dataType: "json",
204
- url: url,
205
- success: success,
206
- error: error,
207
- complete: requestComplete
208
- });
209
- } else {
210
- var xhr = new XMLHttpRequest();
211
- xhr.open("GET", url, true);
212
- xhr.setRequestHeader("Content-Type", "application/json");
213
- xhr.onload = function () {
214
- requestComplete();
215
- if (xhr.status === 200) {
216
- success(JSON.parse(xhr.responseText), xhr.statusText, xhr);
217
- } else {
218
- error(xhr, "error", xhr.statusText);
219
- }
220
- };
221
- xhr.send();
222
- }
228
+ function isMonth(d) {
229
+ return isDay(d) && d.getDate() === 1;
223
230
  }
224
231
 
225
- function errorCatcher(chart, callback) {
226
- try {
227
- callback(chart);
228
- } catch (err) {
229
- chartError(chart.element, err.message);
230
- throw err;
231
- }
232
+ function isYear(d) {
233
+ return isMonth(d) && d.getMonth() === 0;
232
234
  }
233
235
 
234
- function fetchDataSource(chart, callback, dataSource) {
235
- if (typeof dataSource === "string") {
236
- pushRequest(chart.element, dataSource, function (data, textStatus, jqXHR) {
237
- chart.rawData = data;
238
- errorCatcher(chart, callback);
239
- });
240
- } else {
241
- chart.rawData = dataSource;
242
- errorCatcher(chart, callback);
243
- }
236
+ function isDate(obj) {
237
+ return !isNaN(toDate(obj)) && toStr(obj).length >= 6;
244
238
  }
245
239
 
246
- function addDownloadButton(chart) {
247
- var element = chart.element;
248
- var link = document.createElement("a");
249
- link.download = chart.options.download === true ? "chart.png" : chart.options.download; // http://caniuse.com/download
250
- link.style.position = "absolute";
251
- link.style.top = "20px";
252
- link.style.right = "20px";
253
- link.style.zIndex = 1000;
254
- link.style.lineHeight = "20px";
255
- link.target = "_blank"; // for safari
256
- var image = document.createElement("img");
257
- image.alt = "Download";
258
- image.style.border = "none";
259
- // icon from font-awesome
260
- // http://fa2png.io/
261
- image.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAMAAAC6V+0/AAABCFBMVEUAAADMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMywEsqxAAAAV3RSTlMAAQIDBggJCgsMDQ4PERQaHB0eISIjJCouLzE0OTo/QUJHSUpLTU5PUllhYmltcHh5foWLjI+SlaCio6atr7S1t7m6vsHHyM7R2tze5Obo7fHz9ff5+/1hlxK2AAAA30lEQVQYGUXBhVYCQQBA0TdYWAt2d3d3YWAHyur7/z9xgD16Lw0DW+XKx+1GgX+FRzM3HWQWrHl5N/oapW5RPe0PkBu+UYeICvozTWZVK23Ao04B79oJrOsJDOoxkZoQPWgX29pHpCZEk7rEvQYiNSFq1UMqvlCjJkRBS1R8hb00Vb/TajtBL7nTHE1X1vyMQF732dQhyF2o6SAwrzP06iUQzvwsArlnzcOdrgBhJyHa1QOgO9U1GsKuvjUTjavliZYQ8nNPapG6sap/3nrIdJ6bOWzmX/fy0XVpfzZP3S8OJT3g9EEiJwAAAABJRU5ErkJggg==";
262
- link.appendChild(image);
263
- element.style.position = "relative";
240
+ function isNumber(obj) {
241
+ return typeof obj === "number";
242
+ }
264
243
 
265
- chart.downloadAttached = true;
244
+ var byteSuffixes = ["bytes", "KB", "MB", "GB", "TB", "PB", "EB"];
266
245
 
267
- // mouseenter
268
- addEvent(element, "mouseover", function(e) {
269
- var related = e.relatedTarget;
270
- // check download option again to ensure it wasn't changed
271
- if (!related || (related !== this && !childOf(this, related)) && chart.options.download) {
272
- link.href = chart.toImage();
273
- element.appendChild(link);
246
+ function formatValue(pre, value, options, axis) {
247
+ pre = pre || "";
248
+ if (options.prefix) {
249
+ if (value < 0) {
250
+ value = value * -1;
251
+ pre += "-";
274
252
  }
275
- });
253
+ pre += options.prefix;
254
+ }
276
255
 
277
- // mouseleave
278
- addEvent(element, "mouseout", function(e) {
279
- var related = e.relatedTarget;
280
- if (!related || (related !== this && !childOf(this, related))) {
281
- if (link.parentNode) {
282
- link.parentNode.removeChild(link);
256
+ var suffix = options.suffix || "";
257
+ var precision = options.precision;
258
+ var round = options.round;
259
+
260
+ if (options.byteScale) {
261
+ var suffixIdx;
262
+ var baseValue = axis ? options.byteScale : value;
263
+
264
+ if (baseValue >= 1152921504606846976) {
265
+ value /= 1152921504606846976;
266
+ suffixIdx = 6;
267
+ } else if (baseValue >= 1125899906842624) {
268
+ value /= 1125899906842624;
269
+ suffixIdx = 5;
270
+ } else if (baseValue >= 1099511627776) {
271
+ value /= 1099511627776;
272
+ suffixIdx = 4;
273
+ } else if (baseValue >= 1073741824) {
274
+ value /= 1073741824;
275
+ suffixIdx = 3;
276
+ } else if (baseValue >= 1048576) {
277
+ value /= 1048576;
278
+ suffixIdx = 2;
279
+ } else if (baseValue >= 1024) {
280
+ value /= 1024;
281
+ suffixIdx = 1;
282
+ } else {
283
+ suffixIdx = 0;
284
+ }
285
+
286
+ // TODO handle manual precision case
287
+ if (precision === undefined && round === undefined) {
288
+ if (value >= 1023.5) {
289
+ if (suffixIdx < byteSuffixes.length - 1) {
290
+ value = 1.0;
291
+ suffixIdx += 1;
292
+ }
283
293
  }
294
+ precision = value >= 1000 ? 4 : 3;
284
295
  }
285
- });
286
- }
296
+ suffix = " " + byteSuffixes[suffixIdx];
297
+ }
287
298
 
288
- // http://stackoverflow.com/questions/10149963/adding-event-listener-cross-browser
289
- function addEvent(elem, event, fn) {
290
- if (elem.addEventListener) {
291
- elem.addEventListener(event, fn, false);
292
- } else {
293
- elem.attachEvent("on" + event, function() {
294
- // set the this pointer same as addEventListener when fn is called
295
- return(fn.call(elem, window.event));
296
- });
299
+ if (precision !== undefined && round !== undefined) {
300
+ throw Error("Use either round or precision, not both");
297
301
  }
298
- }
299
302
 
300
- // https://gist.github.com/shawnbot/4166283
301
- function childOf(p, c) {
302
- if (p === c) return false;
303
- while (c && c !== p) c = c.parentNode;
304
- return c === p;
305
- }
303
+ if (!axis) {
304
+ if (precision !== undefined) {
305
+ value = value.toPrecision(precision);
306
+ if (!options.zeros) {
307
+ value = parseFloat(value);
308
+ }
309
+ }
306
310
 
307
- // type conversions
311
+ if (round !== undefined) {
312
+ if (round < 0) {
313
+ var num = Math.pow(10, -1 * round);
314
+ value = parseInt((1.0 * value / num).toFixed(0)) * num;
315
+ } else {
316
+ value = value.toFixed(round);
317
+ if (!options.zeros) {
318
+ value = parseFloat(value);
319
+ }
320
+ }
321
+ }
322
+ }
308
323
 
309
- function toStr(n) {
310
- return "" + n;
311
- }
324
+ if (options.thousands || options.decimal) {
325
+ value = toStr(value);
326
+ var parts = value.split(".");
327
+ value = parts[0];
328
+ if (options.thousands) {
329
+ value = value.replace(/\B(?=(\d{3})+(?!\d))/g, options.thousands);
330
+ }
331
+ if (parts.length > 1) {
332
+ value += (options.decimal || ".") + parts[1];
333
+ }
334
+ }
312
335
 
313
- function toFloat(n) {
314
- return parseFloat(n);
336
+ return pre + value + suffix;
315
337
  }
316
338
 
317
- function toDate(n) {
318
- var matches, year, month, day;
319
- if (typeof n !== "object") {
320
- if (typeof n === "number") {
321
- n = new Date(n * 1000); // ms
322
- } else if ((matches = n.match(DATE_PATTERN))) {
323
- year = parseInt(matches[1], 10);
324
- month = parseInt(matches[3], 10) - 1;
325
- day = parseInt(matches[5], 10);
326
- return new Date(year, month, day);
327
- } else { // str
328
- // try our best to get the str into iso8601
329
- // TODO be smarter about this
330
- var str = n.replace(/ /, "T").replace(" ", "").replace("UTC", "Z");
331
- n = parseISO8601(str) || new Date(n);
332
- }
339
+ function seriesOption(chart, series, option) {
340
+ if (option in series) {
341
+ return series[option];
342
+ } else if (option in chart.options) {
343
+ return chart.options[option];
333
344
  }
334
- return n;
345
+ return null;
335
346
  }
336
347
 
337
- function toArr(n) {
338
- if (!isArray(n)) {
339
- var arr = [], i;
340
- for (i in n) {
341
- if (n.hasOwnProperty(i)) {
342
- arr.push([i, n[i]]);
348
+ function allZeros(data) {
349
+ var i, j, d;
350
+ for (i = 0; i < data.length; i++) {
351
+ d = data[i].data;
352
+ for (j = 0; j < d.length; j++) {
353
+ if (d[j][1] != 0) {
354
+ return false;
343
355
  }
344
356
  }
345
- n = arr;
346
357
  }
347
- return n;
348
- }
349
-
350
- function sortByTime(a, b) {
351
- return a[0].getTime() - b[0].getTime();
358
+ return true;
352
359
  }
353
360
 
354
- function sortByNumber(a, b) {
355
- return a - b;
356
- }
361
+ var baseOptions = {
362
+ maintainAspectRatio: false,
363
+ animation: false,
364
+ tooltips: {
365
+ displayColors: false,
366
+ callbacks: {}
367
+ },
368
+ legend: {},
369
+ title: {fontSize: 20, fontColor: "#333"}
370
+ };
357
371
 
358
- function loadAdapters() {
359
- if (!HighchartsAdapter && "Highcharts" in window) {
360
- HighchartsAdapter = new function () {
361
- var Highcharts = window.Highcharts;
362
-
363
- this.name = "highcharts";
364
-
365
- var defaultOptions = {
366
- chart: {},
367
- xAxis: {
368
- title: {
369
- text: null
370
- },
371
- labels: {
372
- style: {
373
- fontSize: "12px"
374
- }
375
- }
376
- },
377
- yAxis: {
378
- title: {
379
- text: null
380
- },
381
- labels: {
382
- style: {
383
- fontSize: "12px"
384
- }
385
- }
386
- },
387
- title: {
388
- text: null
389
- },
390
- credits: {
391
- enabled: false
372
+ var defaultOptions = {
373
+ scales: {
374
+ yAxes: [
375
+ {
376
+ ticks: {
377
+ maxTicksLimit: 4
392
378
  },
393
- legend: {
394
- borderWidth: 0
379
+ scaleLabel: {
380
+ fontSize: 16,
381
+ // fontStyle: "bold",
382
+ fontColor: "#333"
383
+ }
384
+ }
385
+ ],
386
+ xAxes: [
387
+ {
388
+ gridLines: {
389
+ drawOnChartArea: false
395
390
  },
396
- tooltip: {
397
- style: {
398
- fontSize: "12px"
399
- }
391
+ scaleLabel: {
392
+ fontSize: 16,
393
+ // fontStyle: "bold",
394
+ fontColor: "#333"
400
395
  },
401
- plotOptions: {
402
- areaspline: {},
403
- series: {
404
- marker: {}
405
- }
406
- }
407
- };
396
+ time: {},
397
+ ticks: {}
398
+ }
399
+ ]
400
+ }
401
+ };
408
402
 
409
- var hideLegend = function (options, legend, hideLegend) {
410
- if (legend !== undefined) {
411
- options.legend.enabled = !!legend;
412
- if (legend && legend !== true) {
413
- if (legend === "top" || legend === "bottom") {
414
- options.legend.verticalAlign = legend;
415
- } else {
416
- options.legend.layout = "vertical";
417
- options.legend.verticalAlign = "middle";
418
- options.legend.align = legend;
419
- }
420
- }
421
- } else if (hideLegend) {
422
- options.legend.enabled = false;
423
- }
424
- };
403
+ // http://there4.io/2012/05/02/google-chart-color-list/
404
+ var defaultColors = [
405
+ "#3366CC", "#DC3912", "#FF9900", "#109618", "#990099", "#3B3EAC", "#0099C6",
406
+ "#DD4477", "#66AA00", "#B82E2E", "#316395", "#994499", "#22AA99", "#AAAA11",
407
+ "#6633CC", "#E67300", "#8B0707", "#329262", "#5574A6", "#651067"
408
+ ];
409
+
410
+ var hideLegend = function (options, legend, hideLegend) {
411
+ if (legend !== undefined) {
412
+ options.legend.display = !!legend;
413
+ if (legend && legend !== true) {
414
+ options.legend.position = legend;
415
+ }
416
+ } else if (hideLegend) {
417
+ options.legend.display = false;
418
+ }
419
+ };
425
420
 
426
- var setTitle = function (options, title) {
427
- options.title.text = title;
428
- };
421
+ var setTitle = function (options, title) {
422
+ options.title.display = true;
423
+ options.title.text = title;
424
+ };
429
425
 
430
- var setMin = function (options, min) {
431
- options.yAxis.min = min;
432
- };
426
+ var setMin = function (options, min) {
427
+ if (min !== null) {
428
+ options.scales.yAxes[0].ticks.min = toFloat(min);
429
+ }
430
+ };
433
431
 
434
- var setMax = function (options, max) {
435
- options.yAxis.max = max;
436
- };
432
+ var setMax = function (options, max) {
433
+ options.scales.yAxes[0].ticks.max = toFloat(max);
434
+ };
437
435
 
438
- var setStacked = function (options, stacked) {
439
- options.plotOptions.series.stacking = stacked ? "normal" : null;
440
- };
436
+ var setBarMin = function (options, min) {
437
+ if (min !== null) {
438
+ options.scales.xAxes[0].ticks.min = toFloat(min);
439
+ }
440
+ };
441
441
 
442
- var setXtitle = function (options, title) {
443
- options.xAxis.title.text = title;
444
- };
442
+ var setBarMax = function (options, max) {
443
+ options.scales.xAxes[0].ticks.max = toFloat(max);
444
+ };
445
445
 
446
- var setYtitle = function (options, title) {
447
- options.yAxis.title.text = title;
448
- };
446
+ var setStacked = function (options, stacked) {
447
+ options.scales.xAxes[0].stacked = !!stacked;
448
+ options.scales.yAxes[0].stacked = !!stacked;
449
+ };
449
450
 
450
- var jsOptions = jsOptionsFunc(defaultOptions, hideLegend, setTitle, setMin, setMax, setStacked, setXtitle, setYtitle);
451
-
452
- this.renderLineChart = function (chart, chartType) {
453
- chartType = chartType || "spline";
454
- var chartOptions = {};
455
- if (chartType === "areaspline") {
456
- chartOptions = {
457
- plotOptions: {
458
- areaspline: {
459
- stacking: "normal"
460
- },
461
- area: {
462
- stacking: "normal"
463
- },
464
- series: {
465
- marker: {
466
- enabled: false
467
- }
468
- }
469
- }
470
- };
471
- }
451
+ var setXtitle = function (options, title) {
452
+ options.scales.xAxes[0].scaleLabel.display = true;
453
+ options.scales.xAxes[0].scaleLabel.labelString = title;
454
+ };
472
455
 
473
- if (chart.options.curve === false) {
474
- if (chartType === "areaspline") {
475
- chartType = "area";
476
- } else if (chartType === "spline") {
477
- chartType = "line";
478
- }
479
- }
480
-
481
- var options = jsOptions(chart, chart.options, chartOptions), data, i, j;
482
- options.xAxis.type = chart.discrete ? "category" : "datetime";
483
- if (!options.chart.type) {
484
- options.chart.type = chartType;
485
- }
486
- options.chart.renderTo = chart.element.id;
487
-
488
- var series = chart.data;
489
- for (i = 0; i < series.length; i++) {
490
- data = series[i].data;
491
- if (!chart.discrete) {
492
- for (j = 0; j < data.length; j++) {
493
- data[j][0] = data[j][0].getTime();
494
- }
495
- }
496
- series[i].marker = {symbol: "circle"};
497
- }
498
- options.series = series;
499
- chart.chart = new Highcharts.Chart(options);
500
- };
501
-
502
- this.renderScatterChart = function (chart) {
503
- var chartOptions = {};
504
- var options = jsOptions(chart, chart.options, chartOptions);
505
- options.chart.type = "scatter";
506
- options.chart.renderTo = chart.element.id;
507
- options.series = chart.data;
508
- chart.chart = new Highcharts.Chart(options);
509
- };
456
+ var setYtitle = function (options, title) {
457
+ options.scales.yAxes[0].scaleLabel.display = true;
458
+ options.scales.yAxes[0].scaleLabel.labelString = title;
459
+ };
510
460
 
511
- this.renderPieChart = function (chart) {
512
- var chartOptions = merge(defaultOptions, {});
461
+ // https://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb
462
+ var addOpacity = function(hex, opacity) {
463
+ var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
464
+ return result ? "rgba(" + parseInt(result[1], 16) + ", " + parseInt(result[2], 16) + ", " + parseInt(result[3], 16) + ", " + opacity + ")" : hex;
465
+ };
513
466
 
514
- if (chart.options.colors) {
515
- chartOptions.colors = chart.options.colors;
516
- }
517
- if (chart.options.donut) {
518
- chartOptions.plotOptions = {pie: {innerSize: "50%"}};
519
- }
467
+ // check if not null or undefined
468
+ // https://stackoverflow.com/a/27757708/1177228
469
+ var notnull = function(x) {
470
+ return x != null;
471
+ };
520
472
 
521
- if ("legend" in chart.options) {
522
- hideLegend(chartOptions, chart.options.legend);
523
- }
473
+ var setLabelSize = function (chart, data, options) {
474
+ var maxLabelSize = Math.ceil(chart.element.offsetWidth / 4.0 / data.labels.length);
475
+ if (maxLabelSize > 25) {
476
+ maxLabelSize = 25;
477
+ } else if (maxLabelSize < 10) {
478
+ maxLabelSize = 10;
479
+ }
480
+ if (!options.scales.xAxes[0].ticks.callback) {
481
+ options.scales.xAxes[0].ticks.callback = function (value) {
482
+ value = toStr(value);
483
+ if (value.length > maxLabelSize) {
484
+ return value.substring(0, maxLabelSize - 2) + "...";
485
+ } else {
486
+ return value;
487
+ }
488
+ };
489
+ }
490
+ };
524
491
 
525
- if (chart.options.title) {
526
- setTitle(chartOptions, chart.options.title);
527
- }
492
+ var setFormatOptions = function(chart, options, chartType) {
493
+ var formatOptions = {
494
+ prefix: chart.options.prefix,
495
+ suffix: chart.options.suffix,
496
+ thousands: chart.options.thousands,
497
+ decimal: chart.options.decimal,
498
+ precision: chart.options.precision,
499
+ round: chart.options.round,
500
+ zeros: chart.options.zeros
501
+ };
528
502
 
529
- var options = merge(chartOptions, chart.options.library || {});
530
- options.chart.renderTo = chart.element.id;
531
- options.series = [{
532
- type: "pie",
533
- name: chart.options.label || "Value",
534
- data: chart.data
535
- }];
536
- chart.chart = new Highcharts.Chart(options);
537
- };
503
+ if (chart.options.bytes) {
504
+ var series = chart.data;
505
+ if (chartType === "pie") {
506
+ series = [{data: series}];
507
+ }
538
508
 
539
- this.renderColumnChart = function (chart, chartType) {
540
- chartType = chartType || "column";
541
- var series = chart.data;
542
- var options = jsOptions(chart, chart.options), i, j, s, d, rows = [], categories = [];
543
- options.chart.type = chartType;
544
- options.chart.renderTo = chart.element.id;
545
-
546
- for (i = 0; i < series.length; i++) {
547
- s = series[i];
548
-
549
- for (j = 0; j < s.data.length; j++) {
550
- d = s.data[j];
551
- if (!rows[d[0]]) {
552
- rows[d[0]] = new Array(series.length);
553
- categories.push(d[0]);
554
- }
555
- rows[d[0]][i] = d[1];
556
- }
509
+ // calculate max
510
+ var max = 0;
511
+ for (var i = 0; i < series.length; i++) {
512
+ var s = series[i];
513
+ for (var j = 0; j < s.data.length; j++) {
514
+ if (s.data[j][1] > max) {
515
+ max = s.data[j][1];
557
516
  }
517
+ }
518
+ }
558
519
 
559
- options.xAxis.categories = categories;
560
-
561
- var newSeries = [];
562
- for (i = 0; i < series.length; i++) {
563
- d = [];
564
- for (j = 0; j < categories.length; j++) {
565
- d.push(rows[categories[j]][i] || 0);
566
- }
520
+ // calculate scale
521
+ var scale = 1;
522
+ while (max >= 1024) {
523
+ scale *= 1024;
524
+ max /= 1024;
525
+ }
567
526
 
568
- newSeries.push({
569
- name: series[i].name,
570
- data: d
571
- });
572
- }
573
- options.series = newSeries;
527
+ // set step size
528
+ formatOptions.byteScale = scale;
529
+ }
574
530
 
575
- chart.chart = new Highcharts.Chart(options);
576
- };
531
+ if (chartType !== "pie") {
532
+ var myAxes = options.scales.yAxes;
533
+ if (chartType === "bar") {
534
+ myAxes = options.scales.xAxes;
535
+ }
577
536
 
578
- var self = this;
537
+ if (formatOptions.byteScale) {
538
+ if (!myAxes[0].ticks.stepSize) {
539
+ myAxes[0].ticks.stepSize = formatOptions.byteScale / 2;
540
+ }
541
+ if (!myAxes[0].ticks.maxTicksLimit) {
542
+ myAxes[0].ticks.maxTicksLimit = 4;
543
+ }
544
+ }
579
545
 
580
- this.renderBarChart = function (chart) {
581
- self.renderColumnChart(chart, "bar");
546
+ if (!myAxes[0].ticks.callback) {
547
+ myAxes[0].ticks.callback = function (value) {
548
+ return formatValue("", value, formatOptions, true);
582
549
  };
550
+ }
551
+ }
583
552
 
584
- this.renderAreaChart = function (chart) {
585
- self.renderLineChart(chart, "areaspline");
586
- };
587
- };
588
- adapters.push(HighchartsAdapter);
589
- }
590
- if (!GoogleChartsAdapter && window.google && (window.google.setOnLoadCallback || window.google.charts)) {
591
- GoogleChartsAdapter = new function () {
592
- var google = window.google;
593
-
594
- this.name = "google";
595
-
596
- var loaded = {};
597
- var callbacks = [];
598
-
599
- var runCallbacks = function () {
600
- var cb, call;
601
- for (var i = 0; i < callbacks.length; i++) {
602
- cb = callbacks[i];
603
- call = google.visualization && ((cb.pack === "corechart" && google.visualization.LineChart) || (cb.pack === "timeline" && google.visualization.Timeline));
604
- if (call) {
605
- cb.callback();
606
- callbacks.splice(i, 1);
607
- i--;
608
- }
553
+ if (!options.tooltips.callbacks.label) {
554
+ if (chartType === "scatter") {
555
+ options.tooltips.callbacks.label = function (item, data) {
556
+ var label = data.datasets[item.datasetIndex].label || '';
557
+ if (label) {
558
+ label += ': ';
609
559
  }
560
+ return label + '(' + item.xLabel + ', ' + item.yLabel + ')';
610
561
  };
611
-
612
- var waitForLoaded = function (pack, callback) {
613
- if (!callback) {
614
- callback = pack;
615
- pack = "corechart";
562
+ } else if (chartType === "bubble") {
563
+ options.tooltips.callbacks.label = function (item, data) {
564
+ var label = data.datasets[item.datasetIndex].label || '';
565
+ if (label) {
566
+ label += ': ';
616
567
  }
617
-
618
- callbacks.push({pack: pack, callback: callback});
619
-
620
- if (loaded[pack]) {
621
- runCallbacks();
568
+ var dataPoint = data.datasets[item.datasetIndex].data[item.index];
569
+ return label + '(' + item.xLabel + ', ' + item.yLabel + ', ' + dataPoint.v + ')';
570
+ };
571
+ } else if (chartType === "pie") {
572
+ // need to use separate label for pie charts
573
+ options.tooltips.callbacks.label = function (tooltipItem, data) {
574
+ var dataLabel = data.labels[tooltipItem.index];
575
+ var value = ': ';
576
+
577
+ if (isArray(dataLabel)) {
578
+ // show value on first line of multiline label
579
+ // need to clone because we are changing the value
580
+ dataLabel = dataLabel.slice();
581
+ dataLabel[0] += value;
622
582
  } else {
623
- loaded[pack] = true;
624
-
625
- // https://groups.google.com/forum/#!topic/google-visualization-api/fMKJcyA2yyI
626
- var loadOptions = {
627
- packages: [pack],
628
- callback: runCallbacks
629
- };
630
- if (config.language) {
631
- loadOptions.language = config.language;
632
- }
633
-
634
- if (window.google.setOnLoadCallback) {
635
- google.load("visualization", "1", loadOptions);
636
- } else {
637
- google.charts.load("current", loadOptions);
638
- }
583
+ dataLabel += value;
639
584
  }
640
- };
641
585
 
642
- // Set chart options
643
- var defaultOptions = {
644
- chartArea: {},
645
- fontName: "'Lucida Grande', 'Lucida Sans Unicode', Verdana, Arial, Helvetica, sans-serif",
646
- pointSize: 6,
647
- legend: {
648
- textStyle: {
649
- fontSize: 12,
650
- color: "#444"
651
- },
652
- alignment: "center",
653
- position: "right"
654
- },
655
- curveType: "function",
656
- hAxis: {
657
- textStyle: {
658
- color: "#666",
659
- fontSize: 12
660
- },
661
- titleTextStyle: {},
662
- gridlines: {
663
- color: "transparent"
664
- },
665
- baselineColor: "#ccc",
666
- viewWindow: {}
667
- },
668
- vAxis: {
669
- textStyle: {
670
- color: "#666",
671
- fontSize: 12
672
- },
673
- titleTextStyle: {},
674
- baselineColor: "#ccc",
675
- viewWindow: {}
676
- },
677
- tooltip: {
678
- textStyle: {
679
- color: "#666",
680
- fontSize: 12
681
- }
682
- }
586
+ return formatValue(dataLabel, data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index], formatOptions);
683
587
  };
684
-
685
- var hideLegend = function (options, legend, hideLegend) {
686
- if (legend !== undefined) {
687
- var position;
688
- if (!legend) {
689
- position = "none";
690
- } else if (legend === true) {
691
- position = "right";
692
- } else {
693
- position = legend;
694
- }
695
- options.legend.position = position;
696
- } else if (hideLegend) {
697
- options.legend.position = "none";
588
+ } else {
589
+ var valueLabel = chartType === "bar" ? "xLabel" : "yLabel";
590
+ options.tooltips.callbacks.label = function (tooltipItem, data) {
591
+ var label = data.datasets[tooltipItem.datasetIndex].label || '';
592
+ if (label) {
593
+ label += ': ';
698
594
  }
595
+ return formatValue(label, tooltipItem[valueLabel], formatOptions);
699
596
  };
597
+ }
598
+ }
599
+ };
700
600
 
701
- var setTitle = function (options, title) {
702
- options.title = title;
703
- options.titleTextStyle = {color: "#333", fontSize: "20px"};
704
- };
601
+ var jsOptions = jsOptionsFunc(merge(baseOptions, defaultOptions), hideLegend, setTitle, setMin, setMax, setStacked, setXtitle, setYtitle);
705
602
 
706
- var setMin = function (options, min) {
707
- options.vAxis.viewWindow.min = min;
708
- };
603
+ var createDataTable = function (chart, options, chartType, library) {
604
+ var datasets = [];
605
+ var labels = [];
709
606
 
710
- var setMax = function (options, max) {
711
- options.vAxis.viewWindow.max = max;
712
- };
607
+ var colors = chart.options.colors || defaultColors;
713
608
 
714
- var setBarMin = function (options, min) {
715
- options.hAxis.viewWindow.min = min;
716
- };
609
+ var day = true;
610
+ var week = true;
611
+ var dayOfWeek;
612
+ var month = true;
613
+ var year = true;
614
+ var hour = true;
615
+ var minute = true;
717
616
 
718
- var setBarMax = function (options, max) {
719
- options.hAxis.viewWindow.max = max;
720
- };
617
+ var series = chart.data;
721
618
 
722
- var setStacked = function (options, stacked) {
723
- options.isStacked = !!stacked;
724
- };
619
+ var max = 0;
620
+ if (chartType === "bubble") {
621
+ for (var i$1 = 0; i$1 < series.length; i$1++) {
622
+ var s$1 = series[i$1];
623
+ for (var j$1 = 0; j$1 < s$1.data.length; j$1++) {
624
+ if (s$1.data[j$1][2] > max) {
625
+ max = s$1.data[j$1][2];
626
+ }
627
+ }
628
+ }
629
+ }
725
630
 
726
- var setXtitle = function (options, title) {
727
- options.hAxis.title = title;
728
- options.hAxis.titleTextStyle.italic = false;
729
- };
631
+ var i, j, s, d, key, rows = [], rows2 = [];
730
632
 
731
- var setYtitle = function (options, title) {
732
- options.vAxis.title = title;
733
- options.vAxis.titleTextStyle.italic = false;
734
- };
633
+ if (chartType === "bar" || chartType === "column" || (chart.xtype !== "number" && chart.xtype !== "bubble")) {
634
+ var sortedLabels = [];
735
635
 
736
- var jsOptions = jsOptionsFunc(defaultOptions, hideLegend, setTitle, setMin, setMax, setStacked, setXtitle, setYtitle);
737
-
738
- // cant use object as key
739
- var createDataTable = function (series, columnType) {
740
- var i, j, s, d, key, rows = [], sortedLabels = [];
741
- for (i = 0; i < series.length; i++) {
742
- s = series[i];
743
-
744
- for (j = 0; j < s.data.length; j++) {
745
- d = s.data[j];
746
- key = (columnType === "datetime") ? d[0].getTime() : d[0];
747
- if (!rows[key]) {
748
- rows[key] = new Array(series.length);
749
- sortedLabels.push(key);
750
- }
751
- rows[key][i] = toFloat(d[1]);
752
- }
753
- }
636
+ for (i = 0; i < series.length; i++) {
637
+ s = series[i];
754
638
 
755
- var rows2 = [];
756
- var day = true;
757
- var value;
758
- for (var j = 0; j < sortedLabels.length; j++) {
759
- var i = sortedLabels[j];
760
- if (columnType === "datetime") {
761
- value = new Date(toFloat(i));
762
- day = day && isDay(value);
763
- } else if (columnType === "number") {
764
- value = toFloat(i);
765
- } else {
766
- value = i;
767
- }
768
- rows2.push([value].concat(rows[i]));
639
+ for (j = 0; j < s.data.length; j++) {
640
+ d = s.data[j];
641
+ key = chart.xtype == "datetime" ? d[0].getTime() : d[0];
642
+ if (!rows[key]) {
643
+ rows[key] = new Array(series.length);
769
644
  }
770
- if (columnType === "datetime") {
771
- rows2.sort(sortByTime);
645
+ rows[key][i] = toFloat(d[1]);
646
+ if (sortedLabels.indexOf(key) === -1) {
647
+ sortedLabels.push(key);
772
648
  }
649
+ }
650
+ }
773
651
 
774
- // create datatable
775
- var data = new google.visualization.DataTable();
776
- columnType = columnType === "datetime" && day ? "date" : columnType;
777
- data.addColumn(columnType, "");
778
- for (i = 0; i < series.length; i++) {
779
- data.addColumn("number", series[i].name);
780
- }
781
- data.addRows(rows2);
652
+ if (chart.xtype === "datetime" || chart.xtype === "number") {
653
+ sortedLabels.sort(sortByNumber);
654
+ }
782
655
 
783
- return data;
784
- };
656
+ for (j = 0; j < series.length; j++) {
657
+ rows2.push([]);
658
+ }
785
659
 
786
- var resize = function (callback) {
787
- if (window.attachEvent) {
788
- window.attachEvent("onresize", callback);
789
- } else if (window.addEventListener) {
790
- window.addEventListener("resize", callback, true);
660
+ var value;
661
+ var k;
662
+ for (k = 0; k < sortedLabels.length; k++) {
663
+ i = sortedLabels[k];
664
+ if (chart.xtype === "datetime") {
665
+ value = new Date(toFloat(i));
666
+ // TODO make this efficient
667
+ day = day && isDay(value);
668
+ if (!dayOfWeek) {
669
+ dayOfWeek = value.getDay();
791
670
  }
792
- callback();
793
- };
671
+ week = week && isWeek(value, dayOfWeek);
672
+ month = month && isMonth(value);
673
+ year = year && isYear(value);
674
+ hour = hour && isHour(value);
675
+ minute = minute && isMinute(value);
676
+ } else {
677
+ value = i;
678
+ }
679
+ labels.push(value);
680
+ for (j = 0; j < series.length; j++) {
681
+ // Chart.js doesn't like undefined
682
+ rows2[j].push(rows[i][j] === undefined ? null : rows[i][j]);
683
+ }
684
+ }
685
+ } else {
686
+ for (var i$2 = 0; i$2 < series.length; i$2++) {
687
+ var s$2 = series[i$2];
688
+ var d$1 = [];
689
+ for (var j$2 = 0; j$2 < s$2.data.length; j$2++) {
690
+ var point = {
691
+ x: toFloat(s$2.data[j$2][0]),
692
+ y: toFloat(s$2.data[j$2][1])
693
+ };
694
+ if (chartType === "bubble") {
695
+ point.r = toFloat(s$2.data[j$2][2]) * 20 / max;
696
+ // custom attribute, for tooltip
697
+ point.v = s$2.data[j$2][2];
698
+ }
699
+ d$1.push(point);
700
+ }
701
+ rows2.push(d$1);
702
+ }
703
+ }
704
+
705
+ for (i = 0; i < series.length; i++) {
706
+ s = series[i];
707
+
708
+ var color = s.color || colors[i];
709
+ var backgroundColor = chartType !== "line" ? addOpacity(color, 0.5) : color;
710
+
711
+ var dataset = {
712
+ label: s.name || "",
713
+ data: rows2[i],
714
+ fill: chartType === "area",
715
+ borderColor: color,
716
+ backgroundColor: backgroundColor,
717
+ pointBackgroundColor: color,
718
+ borderWidth: 2,
719
+ pointHoverBackgroundColor: color
720
+ };
794
721
 
795
- this.renderLineChart = function (chart) {
796
- waitForLoaded(function () {
797
- var chartOptions = {};
722
+ if (s.stack) {
723
+ dataset.stack = s.stack;
724
+ }
798
725
 
799
- if (chart.options.curve === false) {
800
- chartOptions.curveType = "none";
801
- }
726
+ var curve = seriesOption(chart, s, "curve");
727
+ if (curve === false) {
728
+ dataset.lineTension = 0;
729
+ }
802
730
 
803
- var options = jsOptions(chart, chart.options, chartOptions);
804
- var data = createDataTable(chart.data, chart.discrete ? "string" : "datetime");
805
- chart.chart = new google.visualization.LineChart(chart.element);
806
- resize(function () {
807
- chart.chart.draw(data, options);
808
- });
809
- });
810
- };
731
+ var points = seriesOption(chart, s, "points");
732
+ if (points === false) {
733
+ dataset.pointRadius = 0;
734
+ dataset.pointHitRadius = 5;
735
+ }
811
736
 
812
- this.renderPieChart = function (chart) {
813
- waitForLoaded(function () {
814
- var chartOptions = {
815
- chartArea: {
816
- top: "10%",
817
- height: "80%"
818
- },
819
- legend: {}
820
- };
821
- if (chart.options.colors) {
822
- chartOptions.colors = chart.options.colors;
823
- }
824
- if (chart.options.donut) {
825
- chartOptions.pieHole = 0.5;
826
- }
827
- if ("legend" in chart.options) {
828
- hideLegend(chartOptions, chart.options.legend);
829
- }
830
- if (chart.options.title) {
831
- setTitle(chartOptions, chart.options.title);
832
- }
833
- var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {});
834
-
835
- var data = new google.visualization.DataTable();
836
- data.addColumn("string", "");
837
- data.addColumn("number", "Value");
838
- data.addRows(chart.data);
839
-
840
- chart.chart = new google.visualization.PieChart(chart.element);
841
- resize(function () {
842
- chart.chart.draw(data, options);
843
- });
844
- });
845
- };
737
+ dataset = merge(dataset, chart.options.dataset || {});
738
+ dataset = merge(dataset, s.library || {});
739
+ dataset = merge(dataset, s.dataset || {});
846
740
 
847
- this.renderColumnChart = function (chart) {
848
- waitForLoaded(function () {
849
- var options = jsOptions(chart, chart.options);
850
- var data = createDataTable(chart.data, "string");
851
- chart.chart = new google.visualization.ColumnChart(chart.element);
852
- resize(function () {
853
- chart.chart.draw(data, options);
854
- });
855
- });
856
- };
741
+ datasets.push(dataset);
742
+ }
857
743
 
858
- this.renderBarChart = function (chart) {
859
- waitForLoaded(function () {
860
- var chartOptions = {
861
- hAxis: {
862
- gridlines: {
863
- color: "#ccc"
864
- }
865
- }
866
- };
867
- var options = jsOptionsFunc(defaultOptions, hideLegend, setTitle, setBarMin, setBarMax, setStacked, setXtitle, setYtitle)(chart, chart.options, chartOptions);
868
- var data = createDataTable(chart.data, "string");
869
- chart.chart = new google.visualization.BarChart(chart.element);
870
- resize(function () {
871
- chart.chart.draw(data, options);
872
- });
873
- });
874
- };
744
+ var xmin = chart.options.xmin;
745
+ var xmax = chart.options.xmax;
875
746
 
876
- this.renderAreaChart = function (chart) {
877
- waitForLoaded(function () {
878
- var chartOptions = {
879
- isStacked: true,
880
- pointSize: 0,
881
- areaOpacity: 0.5
882
- };
883
- var options = jsOptions(chart, chart.options, chartOptions);
884
- var data = createDataTable(chart.data, chart.discrete ? "string" : "datetime");
885
- chart.chart = new google.visualization.AreaChart(chart.element);
886
- resize(function () {
887
- chart.chart.draw(data, options);
888
- });
889
- });
890
- };
747
+ if (chart.xtype === "datetime") {
748
+ // hacky check for Chart.js >= 2.9.0
749
+ // https://github.com/chartjs/Chart.js/compare/v2.8.0...v2.9.0
750
+ var gte29 = "math" in library.helpers;
751
+ var ticksKey = gte29 ? "ticks" : "time";
752
+ if (notnull(xmin)) {
753
+ options.scales.xAxes[0][ticksKey].min = toDate(xmin).getTime();
754
+ }
755
+ if (notnull(xmax)) {
756
+ options.scales.xAxes[0][ticksKey].max = toDate(xmax).getTime();
757
+ }
758
+ } else if (chart.xtype === "number") {
759
+ if (notnull(xmin)) {
760
+ options.scales.xAxes[0].ticks.min = xmin;
761
+ }
762
+ if (notnull(xmax)) {
763
+ options.scales.xAxes[0].ticks.max = xmax;
764
+ }
765
+ }
891
766
 
892
- this.renderGeoChart = function (chart) {
893
- waitForLoaded(function () {
894
- var chartOptions = {
895
- legend: "none",
896
- colorAxis: {
897
- colors: chart.options.colors || ["#f6c7b6", "#ce502d"]
898
- }
899
- };
900
- var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {});
901
-
902
- var data = new google.visualization.DataTable();
903
- data.addColumn("string", "");
904
- data.addColumn("number", chart.options.label || "Value");
905
- data.addRows(chart.data);
906
-
907
- chart.chart = new google.visualization.GeoChart(chart.element);
908
- resize(function () {
909
- chart.chart.draw(data, options);
910
- });
911
- });
912
- };
767
+ // for empty datetime chart
768
+ if (chart.xtype === "datetime" && labels.length === 0) {
769
+ if (notnull(xmin)) {
770
+ labels.push(toDate(xmin));
771
+ }
772
+ if (notnull(xmax)) {
773
+ labels.push(toDate(xmax));
774
+ }
775
+ day = false;
776
+ week = false;
777
+ month = false;
778
+ year = false;
779
+ hour = false;
780
+ minute = false;
781
+ }
913
782
 
914
- this.renderScatterChart = function (chart) {
915
- waitForLoaded(function () {
916
- var chartOptions = {};
917
- var options = jsOptions(chart, chart.options, chartOptions);
918
- var data = createDataTable(chart.data, "number");
919
-
920
- chart.chart = new google.visualization.ScatterChart(chart.element);
921
- resize(function () {
922
- chart.chart.draw(data, options);
923
- });
924
- });
925
- };
783
+ if (chart.xtype === "datetime" && labels.length > 0) {
784
+ var minTime = (notnull(xmin) ? toDate(xmin) : labels[0]).getTime();
785
+ var maxTime = (notnull(xmax) ? toDate(xmax) : labels[0]).getTime();
786
+
787
+ for (i = 1; i < labels.length; i++) {
788
+ var value$1 = labels[i].getTime();
789
+ if (value$1 < minTime) {
790
+ minTime = value$1;
791
+ }
792
+ if (value$1 > maxTime) {
793
+ maxTime = value$1;
794
+ }
795
+ }
926
796
 
927
- this.renderTimeline = function (chart) {
928
- waitForLoaded("timeline", function () {
929
- var chartOptions = {
930
- legend: "none"
931
- };
797
+ var timeDiff = (maxTime - minTime) / (86400 * 1000.0);
798
+
799
+ if (!options.scales.xAxes[0].time.unit) {
800
+ var step;
801
+ if (year || timeDiff > 365 * 10) {
802
+ options.scales.xAxes[0].time.unit = "year";
803
+ step = 365;
804
+ } else if (month || timeDiff > 30 * 10) {
805
+ options.scales.xAxes[0].time.unit = "month";
806
+ step = 30;
807
+ } else if (day || timeDiff > 10) {
808
+ options.scales.xAxes[0].time.unit = "day";
809
+ step = 1;
810
+ } else if (hour || timeDiff > 0.5) {
811
+ options.scales.xAxes[0].time.displayFormats = {hour: "MMM D, h a"};
812
+ options.scales.xAxes[0].time.unit = "hour";
813
+ step = 1 / 24.0;
814
+ } else if (minute) {
815
+ options.scales.xAxes[0].time.displayFormats = {minute: "h:mm a"};
816
+ options.scales.xAxes[0].time.unit = "minute";
817
+ step = 1 / 24.0 / 60.0;
818
+ }
932
819
 
933
- if (chart.options.colors) {
934
- chartOptions.colors = chart.options.colors;
935
- }
936
- var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {});
820
+ if (step && timeDiff > 0) {
821
+ var unitStepSize = Math.ceil(timeDiff / step / (chart.element.offsetWidth / 100.0));
822
+ if (week && step === 1) {
823
+ unitStepSize = Math.ceil(unitStepSize / 7.0) * 7;
824
+ }
825
+ options.scales.xAxes[0].time.unitStepSize = unitStepSize;
826
+ }
827
+ }
937
828
 
938
- var data = new google.visualization.DataTable();
939
- data.addColumn({type: "string", id: "Name"});
940
- data.addColumn({type: "date", id: "Start"});
941
- data.addColumn({type: "date", id: "End"});
942
- data.addRows(chart.data);
829
+ if (!options.scales.xAxes[0].time.tooltipFormat) {
830
+ if (day) {
831
+ options.scales.xAxes[0].time.tooltipFormat = "ll";
832
+ } else if (hour) {
833
+ options.scales.xAxes[0].time.tooltipFormat = "MMM D, h a";
834
+ } else if (minute) {
835
+ options.scales.xAxes[0].time.tooltipFormat = "h:mm a";
836
+ }
837
+ }
838
+ }
943
839
 
944
- chart.element.style.lineHeight = "normal";
945
- chart.chart = new google.visualization.Timeline(chart.element);
840
+ var data = {
841
+ labels: labels,
842
+ datasets: datasets
843
+ };
946
844
 
947
- resize(function () {
948
- chart.chart.draw(data, options);
949
- });
950
- });
951
- };
952
- };
845
+ return data;
846
+ };
847
+
848
+ var defaultExport = function defaultExport(library) {
849
+ this.name = "chartjs";
850
+ this.library = library;
851
+ };
953
852
 
954
- adapters.push(GoogleChartsAdapter);
853
+ defaultExport.prototype.renderLineChart = function renderLineChart (chart, chartType) {
854
+ var chartOptions = {};
855
+ // fix for https://github.com/chartjs/Chart.js/issues/2441
856
+ if (!chart.options.max && allZeros(chart.data)) {
857
+ chartOptions.max = 1;
955
858
  }
956
- if (!ChartjsAdapter && "Chart" in window) {
957
- ChartjsAdapter = new function () {
958
- var Chart = window.Chart;
959
859
 
960
- this.name = "chartjs";
860
+ var options = jsOptions(chart, merge(chartOptions, chart.options));
861
+ setFormatOptions(chart, options, chartType);
961
862
 
962
- var baseOptions = {
963
- maintainAspectRatio: false,
964
- animation: false,
965
- tooltips: {
966
- displayColors: false
967
- },
968
- legend: {},
969
- title: {fontSize: 20, fontColor: "#333"}
970
- };
863
+ var data = createDataTable(chart, options, chartType || "line", this.library);
971
864
 
972
- var defaultOptions = {
973
- scales: {
974
- yAxes: [
975
- {
976
- ticks: {
977
- maxTicksLimit: 4
978
- },
979
- scaleLabel: {
980
- fontSize: 16,
981
- // fontStyle: "bold",
982
- fontColor: "#333"
983
- }
984
- }
985
- ],
986
- xAxes: [
987
- {
988
- gridLines: {
989
- drawOnChartArea: false
990
- },
991
- scaleLabel: {
992
- fontSize: 16,
993
- // fontStyle: "bold",
994
- fontColor: "#333"
995
- },
996
- time: {},
997
- ticks: {}
998
- }
999
- ]
1000
- }
1001
- };
865
+ if (chart.xtype === "number") {
866
+ options.scales.xAxes[0].type = "linear";
867
+ options.scales.xAxes[0].position = "bottom";
868
+ } else {
869
+ options.scales.xAxes[0].type = chart.xtype === "string" ? "category" : "time";
870
+ }
1002
871
 
1003
- // http://there4.io/2012/05/02/google-chart-color-list/
1004
- var defaultColors = [
1005
- "#3366CC", "#DC3912", "#FF9900", "#109618", "#990099", "#3B3EAC", "#0099C6",
1006
- "#DD4477", "#66AA00", "#B82E2E", "#316395", "#994499", "#22AA99", "#AAAA11",
1007
- "#6633CC", "#E67300", "#8B0707", "#329262", "#5574A6", "#3B3EAC"
1008
- ];
1009
-
1010
- var hideLegend = function (options, legend, hideLegend) {
1011
- if (legend !== undefined) {
1012
- options.legend.display = !!legend;
1013
- if (legend && legend !== true) {
1014
- options.legend.position = legend;
1015
- }
1016
- } else if (hideLegend) {
1017
- options.legend.display = false;
1018
- }
1019
- };
872
+ this.drawChart(chart, "line", data, options);
873
+ };
1020
874
 
1021
- var setTitle = function (options, title) {
1022
- options.title.display = true;
1023
- options.title.text = title;
1024
- };
875
+ defaultExport.prototype.renderPieChart = function renderPieChart (chart) {
876
+ var options = merge({}, baseOptions);
877
+ if (chart.options.donut) {
878
+ options.cutoutPercentage = 50;
879
+ }
1025
880
 
1026
- var setMin = function (options, min) {
1027
- if (min !== null) {
1028
- options.scales.yAxes[0].ticks.min = toFloat(min);
1029
- }
1030
- };
881
+ if ("legend" in chart.options) {
882
+ hideLegend(options, chart.options.legend);
883
+ }
1031
884
 
1032
- var setMax = function (options, max) {
1033
- options.scales.yAxes[0].ticks.max = toFloat(max);
1034
- };
885
+ if (chart.options.title) {
886
+ setTitle(options, chart.options.title);
887
+ }
1035
888
 
1036
- var setBarMin = function (options, min) {
1037
- if (min !== null) {
1038
- options.scales.xAxes[0].ticks.min = toFloat(min);
1039
- }
1040
- };
889
+ options = merge(options, chart.options.library || {});
890
+ setFormatOptions(chart, options, "pie");
1041
891
 
1042
- var setBarMax = function (options, max) {
1043
- options.scales.xAxes[0].ticks.max = toFloat(max);
1044
- };
892
+ var labels = [];
893
+ var values = [];
894
+ for (var i = 0; i < chart.data.length; i++) {
895
+ var point = chart.data[i];
896
+ labels.push(point[0]);
897
+ values.push(point[1]);
898
+ }
1045
899
 
1046
- var setStacked = function (options, stacked) {
1047
- options.scales.xAxes[0].stacked = !!stacked;
1048
- options.scales.yAxes[0].stacked = !!stacked;
1049
- };
900
+ var dataset = {
901
+ data: values,
902
+ backgroundColor: chart.options.colors || defaultColors
903
+ };
904
+ dataset = merge(dataset, chart.options.dataset || {});
1050
905
 
1051
- var setXtitle = function (options, title) {
1052
- options.scales.xAxes[0].scaleLabel.display = true;
1053
- options.scales.xAxes[0].scaleLabel.labelString = title;
1054
- };
906
+ var data = {
907
+ labels: labels,
908
+ datasets: [dataset]
909
+ };
1055
910
 
1056
- var setYtitle = function (options, title) {
1057
- options.scales.yAxes[0].scaleLabel.display = true;
1058
- options.scales.yAxes[0].scaleLabel.labelString = title;
1059
- };
911
+ this.drawChart(chart, "pie", data, options);
912
+ };
1060
913
 
1061
- var drawChart = function(chart, type, data, options) {
1062
- if (chart.chart) {
1063
- chart.chart.destroy();
1064
- } else {
1065
- chart.element.innerHTML = "<canvas></canvas>";
1066
- }
914
+ defaultExport.prototype.renderColumnChart = function renderColumnChart (chart, chartType) {
915
+ var options;
916
+ if (chartType === "bar") {
917
+ var barOptions = merge(baseOptions, defaultOptions);
918
+ delete barOptions.scales.yAxes[0].ticks.maxTicksLimit;
919
+ options = jsOptionsFunc(barOptions, hideLegend, setTitle, setBarMin, setBarMax, setStacked, setXtitle, setYtitle)(chart, chart.options);
920
+ } else {
921
+ options = jsOptions(chart, chart.options);
922
+ }
923
+ setFormatOptions(chart, options, chartType);
924
+ var data = createDataTable(chart, options, "column", this.library);
925
+ if (chartType !== "bar") {
926
+ setLabelSize(chart, data, options);
927
+ }
928
+ this.drawChart(chart, (chartType === "bar" ? "horizontalBar" : "bar"), data, options);
929
+ };
1067
930
 
1068
- var ctx = chart.element.getElementsByTagName("CANVAS")[0];
1069
- chart.chart = new Chart(ctx, {
1070
- type: type,
1071
- data: data,
1072
- options: options
1073
- });
1074
- };
931
+ defaultExport.prototype.renderAreaChart = function renderAreaChart (chart) {
932
+ this.renderLineChart(chart, "area");
933
+ };
1075
934
 
1076
- // http://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb
1077
- var addOpacity = function(hex, opacity) {
1078
- var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
1079
- return result ? "rgba(" + parseInt(result[1], 16) + ", " + parseInt(result[2], 16) + ", " + parseInt(result[3], 16) + ", " + opacity + ")" : hex;
1080
- };
935
+ defaultExport.prototype.renderBarChart = function renderBarChart (chart) {
936
+ this.renderColumnChart(chart, "bar");
937
+ };
1081
938
 
1082
- var setLabelSize = function (chart, data, options) {
1083
- var maxLabelSize = Math.ceil(chart.element.offsetWidth / 4.0 / data.labels.length);
1084
- if (maxLabelSize > 25) {
1085
- maxLabelSize = 25;
1086
- }
1087
- options.scales.xAxes[0].ticks.callback = function (value) {
1088
- value = toStr(value);
1089
- if (value.length > maxLabelSize) {
1090
- return value.substring(0, maxLabelSize - 2) + "...";
1091
- } else {
1092
- return value;
1093
- }
1094
- };
1095
- };
939
+ defaultExport.prototype.renderScatterChart = function renderScatterChart (chart, chartType) {
940
+ chartType = chartType || "scatter";
1096
941
 
1097
- var jsOptions = jsOptionsFunc(merge(baseOptions, defaultOptions), hideLegend, setTitle, setMin, setMax, setStacked, setXtitle, setYtitle);
1098
-
1099
- var createDataTable = function (chart, options, chartType) {
1100
- var datasets = [];
1101
- var labels = [];
1102
-
1103
- var colors = chart.options.colors || defaultColors;
1104
-
1105
- var day = true;
1106
- var week = true;
1107
- var dayOfWeek;
1108
- var month = true;
1109
- var year = true;
1110
- var hour = true;
1111
- var minute = true;
1112
- var detectType = (chartType === "line" || chartType === "area") && !chart.discrete;
1113
-
1114
- var series = chart.data;
1115
-
1116
- var sortedLabels = [];
1117
-
1118
- var i, j, s, d, key, rows = [];
1119
- for (i = 0; i < series.length; i++) {
1120
- s = series[i];
1121
-
1122
- for (j = 0; j < s.data.length; j++) {
1123
- d = s.data[j];
1124
- key = detectType ? d[0].getTime() : d[0];
1125
- if (!rows[key]) {
1126
- rows[key] = new Array(series.length);
1127
- }
1128
- rows[key][i] = toFloat(d[1]);
1129
- if (sortedLabels.indexOf(key) === -1) {
1130
- sortedLabels.push(key);
1131
- }
1132
- }
1133
- }
942
+ var options = jsOptions(chart, chart.options);
943
+ setFormatOptions(chart, options, chartType);
1134
944
 
1135
- if (detectType) {
1136
- sortedLabels.sort(sortByNumber);
1137
- }
945
+ if (!("showLines" in options)) {
946
+ options.showLines = false;
947
+ }
1138
948
 
1139
- var rows2 = [];
1140
- for (j = 0; j < series.length; j++) {
1141
- rows2.push([]);
1142
- }
949
+ var data = createDataTable(chart, options, chartType, this.library);
1143
950
 
1144
- var value;
1145
- var k;
1146
- for (k = 0; k < sortedLabels.length; k++) {
1147
- i = sortedLabels[k];
1148
- if (detectType) {
1149
- value = new Date(toFloat(i));
1150
- // TODO make this efficient
1151
- day = day && isDay(value);
1152
- if (!dayOfWeek) {
1153
- dayOfWeek = value.getDay();
1154
- }
1155
- week = week && isWeek(value, dayOfWeek);
1156
- month = month && isMonth(value);
1157
- year = year && isYear(value);
1158
- hour = hour && isHour(value);
1159
- minute = minute && isMinute(value);
1160
- } else {
1161
- value = i;
1162
- }
1163
- labels.push(value);
1164
- for (j = 0; j < series.length; j++) {
1165
- // Chart.js doesn't like undefined
1166
- rows2[j].push(rows[i][j] === undefined ? null : rows[i][j]);
1167
- }
1168
- }
951
+ options.scales.xAxes[0].type = "linear";
952
+ options.scales.xAxes[0].position = "bottom";
953
+
954
+ this.drawChart(chart, chartType, data, options);
955
+ };
956
+
957
+ defaultExport.prototype.renderBubbleChart = function renderBubbleChart (chart) {
958
+ this.renderScatterChart(chart, "bubble");
959
+ };
1169
960
 
1170
- for (i = 0; i < series.length; i++) {
1171
- s = series[i];
961
+ defaultExport.prototype.destroy = function destroy (chart) {
962
+ if (chart.chart) {
963
+ chart.chart.destroy();
964
+ }
965
+ };
1172
966
 
1173
- var backgroundColor = chartType !== "line" ? addOpacity(colors[i], 0.5) : colors[i];
967
+ defaultExport.prototype.drawChart = function drawChart (chart, type, data, options) {
968
+ this.destroy(chart);
1174
969
 
1175
- var dataset = {
1176
- label: s.name,
1177
- data: rows2[i],
1178
- fill: chartType === "area",
1179
- borderColor: colors[i],
1180
- backgroundColor: backgroundColor,
1181
- pointBackgroundColor: colors[i],
1182
- borderWidth: 2
1183
- };
970
+ var chartOptions = {
971
+ type: type,
972
+ data: data,
973
+ options: options
974
+ };
1184
975
 
1185
- if (chart.options.curve === false) {
1186
- dataset.lineTension = 0;
1187
- }
976
+ if (chart.options.code) {
977
+ window.console.log("new Chart(ctx, " + JSON.stringify(chartOptions) + ");");
978
+ }
1188
979
 
1189
- datasets.push(merge(dataset, s.library || {}));
1190
- }
980
+ chart.element.innerHTML = "<canvas></canvas>";
981
+ var ctx = chart.element.getElementsByTagName("CANVAS")[0];
982
+ chart.chart = new this.library(ctx, chartOptions);
983
+ };
1191
984
 
1192
- if (detectType && labels.length > 0) {
1193
- var minTime = labels[0].getTime();
1194
- var maxTime = labels[0].getTime();
1195
- for (i = 1; i < labels.length; i++) {
1196
- value = labels[i].getTime();
1197
- if (value < minTime) {
1198
- minTime = value;
1199
- }
1200
- if (value > maxTime) {
1201
- maxTime = value;
1202
- }
1203
- }
985
+ var defaultOptions$1 = {
986
+ chart: {},
987
+ xAxis: {
988
+ title: {
989
+ text: null
990
+ },
991
+ labels: {
992
+ style: {
993
+ fontSize: "12px"
994
+ }
995
+ }
996
+ },
997
+ yAxis: {
998
+ title: {
999
+ text: null
1000
+ },
1001
+ labels: {
1002
+ style: {
1003
+ fontSize: "12px"
1004
+ }
1005
+ }
1006
+ },
1007
+ title: {
1008
+ text: null
1009
+ },
1010
+ credits: {
1011
+ enabled: false
1012
+ },
1013
+ legend: {
1014
+ borderWidth: 0
1015
+ },
1016
+ tooltip: {
1017
+ style: {
1018
+ fontSize: "12px"
1019
+ }
1020
+ },
1021
+ plotOptions: {
1022
+ areaspline: {},
1023
+ area: {},
1024
+ series: {
1025
+ marker: {}
1026
+ }
1027
+ }
1028
+ };
1204
1029
 
1205
- var timeDiff = (maxTime - minTime) / (86400 * 1000.0);
1206
-
1207
- if (!options.scales.xAxes[0].time.unit) {
1208
- var step;
1209
- if (year || timeDiff > 365 * 10) {
1210
- options.scales.xAxes[0].time.unit = "year";
1211
- step = 365;
1212
- } else if (month || timeDiff > 30 * 10) {
1213
- options.scales.xAxes[0].time.unit = "month";
1214
- step = 30;
1215
- } else if (day || timeDiff > 10) {
1216
- options.scales.xAxes[0].time.unit = "day";
1217
- step = 1;
1218
- } else if (hour || timeDiff > 0.5) {
1219
- options.scales.xAxes[0].time.displayFormats = {hour: "MMM D, h a"};
1220
- options.scales.xAxes[0].time.unit = "hour";
1221
- step = 1 / 24.0;
1222
- } else if (minute) {
1223
- options.scales.xAxes[0].time.displayFormats = {minute: "h:mm a"};
1224
- options.scales.xAxes[0].time.unit = "minute";
1225
- step = 1 / 24.0 / 60.0;
1226
- }
1227
-
1228
- if (step && timeDiff > 0) {
1229
- var unitStepSize = Math.ceil(timeDiff / step / (chart.element.offsetWidth / 100.0));
1230
- if (week && step === 1) {
1231
- unitStepSize = Math.ceil(unitStepSize / 7.0) * 7;
1232
- }
1233
- options.scales.xAxes[0].time.unitStepSize = unitStepSize;
1234
- }
1235
- }
1030
+ var hideLegend$1 = function (options, legend, hideLegend) {
1031
+ if (legend !== undefined) {
1032
+ options.legend.enabled = !!legend;
1033
+ if (legend && legend !== true) {
1034
+ if (legend === "top" || legend === "bottom") {
1035
+ options.legend.verticalAlign = legend;
1036
+ } else {
1037
+ options.legend.layout = "vertical";
1038
+ options.legend.verticalAlign = "middle";
1039
+ options.legend.align = legend;
1040
+ }
1041
+ }
1042
+ } else if (hideLegend) {
1043
+ options.legend.enabled = false;
1044
+ }
1045
+ };
1236
1046
 
1237
- if (!options.scales.xAxes[0].time.tooltipFormat) {
1238
- if (day) {
1239
- options.scales.xAxes[0].time.tooltipFormat = "ll";
1240
- } else if (hour) {
1241
- options.scales.xAxes[0].time.tooltipFormat = "MMM D, h a";
1242
- } else if (minute) {
1243
- options.scales.xAxes[0].time.tooltipFormat = "h:mm a";
1244
- }
1245
- }
1246
- }
1047
+ var setTitle$1 = function (options, title) {
1048
+ options.title.text = title;
1049
+ };
1247
1050
 
1248
- var data = {
1249
- labels: labels,
1250
- datasets: datasets
1251
- };
1051
+ var setMin$1 = function (options, min) {
1052
+ options.yAxis.min = min;
1053
+ };
1252
1054
 
1253
- return data;
1254
- };
1055
+ var setMax$1 = function (options, max) {
1056
+ options.yAxis.max = max;
1057
+ };
1255
1058
 
1256
- this.renderLineChart = function (chart, chartType) {
1257
- var chartOptions = {};
1258
- if (chartType === "area") {
1259
- // TODO fix area stacked
1260
- // chartOptions.stacked = true;
1261
- }
1262
- // fix for https://github.com/chartjs/Chart.js/issues/2441
1263
- if (!chart.options.max && allZeros(chart.data)) {
1264
- chartOptions.max = 1;
1265
- }
1059
+ var setStacked$1 = function (options, stacked) {
1060
+ var stackedValue = stacked ? (stacked === true ? "normal" : stacked) : null;
1061
+ options.plotOptions.series.stacking = stackedValue;
1062
+ options.plotOptions.area.stacking = stackedValue;
1063
+ options.plotOptions.areaspline.stacking = stackedValue;
1064
+ };
1266
1065
 
1267
- var options = jsOptions(chart, merge(chartOptions, chart.options));
1066
+ var setXtitle$1 = function (options, title) {
1067
+ options.xAxis.title.text = title;
1068
+ };
1268
1069
 
1269
- var data = createDataTable(chart, options, chartType || "line");
1070
+ var setYtitle$1 = function (options, title) {
1071
+ options.yAxis.title.text = title;
1072
+ };
1270
1073
 
1271
- options.scales.xAxes[0].type = chart.discrete ? "category" : "time";
1074
+ var jsOptions$1 = jsOptionsFunc(defaultOptions$1, hideLegend$1, setTitle$1, setMin$1, setMax$1, setStacked$1, setXtitle$1, setYtitle$1);
1075
+
1076
+ var setFormatOptions$1 = function(chart, options, chartType) {
1077
+ var formatOptions = {
1078
+ prefix: chart.options.prefix,
1079
+ suffix: chart.options.suffix,
1080
+ thousands: chart.options.thousands,
1081
+ decimal: chart.options.decimal,
1082
+ precision: chart.options.precision,
1083
+ round: chart.options.round,
1084
+ zeros: chart.options.zeros
1085
+ };
1272
1086
 
1273
- drawChart(chart, "line", data, options);
1274
- };
1087
+ if (chartType !== "pie" && !options.yAxis.labels.formatter) {
1088
+ options.yAxis.labels.formatter = function () {
1089
+ return formatValue("", this.value, formatOptions);
1090
+ };
1091
+ }
1275
1092
 
1276
- this.renderPieChart = function (chart) {
1277
- var options = merge({}, baseOptions);
1278
- if (chart.options.donut) {
1279
- options.cutoutPercentage = 50;
1280
- }
1093
+ if (!options.tooltip.pointFormatter) {
1094
+ options.tooltip.pointFormatter = function () {
1095
+ return '<span style="color:' + this.color + '">\u25CF</span> ' + formatValue(this.series.name + ': <b>', this.y, formatOptions) + '</b><br/>';
1096
+ };
1097
+ }
1098
+ };
1281
1099
 
1282
- if ("legend" in chart.options) {
1283
- hideLegend(options, chart.options.legend);
1284
- }
1100
+ var defaultExport$1 = function defaultExport(library) {
1101
+ this.name = "highcharts";
1102
+ this.library = library;
1103
+ };
1285
1104
 
1286
- if (chart.options.title) {
1287
- setTitle(options, chart.options.title);
1105
+ defaultExport$1.prototype.renderLineChart = function renderLineChart (chart, chartType) {
1106
+ chartType = chartType || "spline";
1107
+ var chartOptions = {};
1108
+ if (chartType === "areaspline") {
1109
+ chartOptions = {
1110
+ plotOptions: {
1111
+ areaspline: {
1112
+ stacking: "normal"
1113
+ },
1114
+ area: {
1115
+ stacking: "normal"
1116
+ },
1117
+ series: {
1118
+ marker: {
1119
+ enabled: false
1120
+ }
1288
1121
  }
1122
+ }
1123
+ };
1124
+ }
1125
+
1126
+ if (chart.options.curve === false) {
1127
+ if (chartType === "areaspline") {
1128
+ chartType = "area";
1129
+ } else if (chartType === "spline") {
1130
+ chartType = "line";
1131
+ }
1132
+ }
1289
1133
 
1290
- options = merge(options, chart.options.library || {});
1134
+ var options = jsOptions$1(chart, chart.options, chartOptions), data, i, j;
1135
+ options.xAxis.type = chart.xtype === "string" ? "category" : (chart.xtype === "number" ? "linear" : "datetime");
1136
+ if (!options.chart.type) {
1137
+ options.chart.type = chartType;
1138
+ }
1139
+ setFormatOptions$1(chart, options, chartType);
1140
+
1141
+ var series = chart.data;
1142
+ for (i = 0; i < series.length; i++) {
1143
+ series[i].name = series[i].name || "Value";
1144
+ data = series[i].data;
1145
+ if (chart.xtype === "datetime") {
1146
+ for (j = 0; j < data.length; j++) {
1147
+ data[j][0] = data[j][0].getTime();
1148
+ }
1149
+ }
1150
+ series[i].marker = {symbol: "circle"};
1151
+ if (chart.options.points === false) {
1152
+ series[i].marker.enabled = false;
1153
+ }
1154
+ }
1155
+
1156
+ this.drawChart(chart, series, options);
1157
+ };
1158
+
1159
+ defaultExport$1.prototype.renderScatterChart = function renderScatterChart (chart) {
1160
+ var options = jsOptions$1(chart, chart.options, {});
1161
+ options.chart.type = "scatter";
1162
+ this.drawChart(chart, chart.data, options);
1163
+ };
1164
+
1165
+ defaultExport$1.prototype.renderPieChart = function renderPieChart (chart) {
1166
+ var chartOptions = merge(defaultOptions$1, {});
1167
+
1168
+ if (chart.options.colors) {
1169
+ chartOptions.colors = chart.options.colors;
1170
+ }
1171
+ if (chart.options.donut) {
1172
+ chartOptions.plotOptions = {pie: {innerSize: "50%"}};
1173
+ }
1174
+
1175
+ if ("legend" in chart.options) {
1176
+ hideLegend$1(chartOptions, chart.options.legend);
1177
+ }
1178
+
1179
+ if (chart.options.title) {
1180
+ setTitle$1(chartOptions, chart.options.title);
1181
+ }
1182
+
1183
+ var options = merge(chartOptions, chart.options.library || {});
1184
+ setFormatOptions$1(chart, options, "pie");
1185
+ var series = [{
1186
+ type: "pie",
1187
+ name: chart.options.label || "Value",
1188
+ data: chart.data
1189
+ }];
1190
+
1191
+ this.drawChart(chart, series, options);
1192
+ };
1193
+
1194
+ defaultExport$1.prototype.renderColumnChart = function renderColumnChart (chart, chartType) {
1195
+ chartType = chartType || "column";
1196
+ var series = chart.data;
1197
+ var options = jsOptions$1(chart, chart.options), i, j, s, d, rows = [], categories = [];
1198
+ options.chart.type = chartType;
1199
+ setFormatOptions$1(chart, options, chartType);
1200
+
1201
+ for (i = 0; i < series.length; i++) {
1202
+ s = series[i];
1203
+
1204
+ for (j = 0; j < s.data.length; j++) {
1205
+ d = s.data[j];
1206
+ if (!rows[d[0]]) {
1207
+ rows[d[0]] = new Array(series.length);
1208
+ categories.push(d[0]);
1209
+ }
1210
+ rows[d[0]][i] = d[1];
1211
+ }
1212
+ }
1213
+
1214
+ if (chart.xtype === "number") {
1215
+ categories.sort(sortByNumber);
1216
+ }
1217
+
1218
+ options.xAxis.categories = categories;
1219
+
1220
+ var newSeries = [], d2;
1221
+ for (i = 0; i < series.length; i++) {
1222
+ d = [];
1223
+ for (j = 0; j < categories.length; j++) {
1224
+ d.push(rows[categories[j]][i] || 0);
1225
+ }
1226
+
1227
+ d2 = {
1228
+ name: series[i].name || "Value",
1229
+ data: d
1230
+ };
1231
+ if (series[i].stack) {
1232
+ d2.stack = series[i].stack;
1233
+ }
1234
+
1235
+ newSeries.push(d2);
1236
+ }
1237
+
1238
+ this.drawChart(chart, newSeries, options);
1239
+ };
1240
+
1241
+ defaultExport$1.prototype.renderBarChart = function renderBarChart (chart) {
1242
+ this.renderColumnChart(chart, "bar");
1243
+ };
1244
+
1245
+ defaultExport$1.prototype.renderAreaChart = function renderAreaChart (chart) {
1246
+ this.renderLineChart(chart, "areaspline");
1247
+ };
1248
+
1249
+ defaultExport$1.prototype.destroy = function destroy (chart) {
1250
+ if (chart.chart) {
1251
+ chart.chart.destroy();
1252
+ }
1253
+ };
1254
+
1255
+ defaultExport$1.prototype.drawChart = function drawChart (chart, data, options) {
1256
+ this.destroy(chart);
1257
+
1258
+ options.chart.renderTo = chart.element.id;
1259
+ options.series = data;
1260
+
1261
+ if (chart.options.code) {
1262
+ window.console.log("new Highcharts.Chart(" + JSON.stringify(options) + ");");
1263
+ }
1264
+
1265
+ chart.chart = new this.library.Chart(options);
1266
+ };
1267
+
1268
+ var loaded = {};
1269
+ var callbacks = [];
1270
+
1271
+ // Set chart options
1272
+ var defaultOptions$2 = {
1273
+ chartArea: {},
1274
+ fontName: "'Lucida Grande', 'Lucida Sans Unicode', Verdana, Arial, Helvetica, sans-serif",
1275
+ pointSize: 6,
1276
+ legend: {
1277
+ textStyle: {
1278
+ fontSize: 12,
1279
+ color: "#444"
1280
+ },
1281
+ alignment: "center",
1282
+ position: "right"
1283
+ },
1284
+ curveType: "function",
1285
+ hAxis: {
1286
+ textStyle: {
1287
+ color: "#666",
1288
+ fontSize: 12
1289
+ },
1290
+ titleTextStyle: {},
1291
+ gridlines: {
1292
+ color: "transparent"
1293
+ },
1294
+ baselineColor: "#ccc",
1295
+ viewWindow: {}
1296
+ },
1297
+ vAxis: {
1298
+ textStyle: {
1299
+ color: "#666",
1300
+ fontSize: 12
1301
+ },
1302
+ titleTextStyle: {},
1303
+ baselineColor: "#ccc",
1304
+ viewWindow: {}
1305
+ },
1306
+ tooltip: {
1307
+ textStyle: {
1308
+ color: "#666",
1309
+ fontSize: 12
1310
+ }
1311
+ }
1312
+ };
1313
+
1314
+ var hideLegend$2 = function (options, legend, hideLegend) {
1315
+ if (legend !== undefined) {
1316
+ var position;
1317
+ if (!legend) {
1318
+ position = "none";
1319
+ } else if (legend === true) {
1320
+ position = "right";
1321
+ } else {
1322
+ position = legend;
1323
+ }
1324
+ options.legend.position = position;
1325
+ } else if (hideLegend) {
1326
+ options.legend.position = "none";
1327
+ }
1328
+ };
1329
+
1330
+ var setTitle$2 = function (options, title) {
1331
+ options.title = title;
1332
+ options.titleTextStyle = {color: "#333", fontSize: "20px"};
1333
+ };
1334
+
1335
+ var setMin$2 = function (options, min) {
1336
+ options.vAxis.viewWindow.min = min;
1337
+ };
1338
+
1339
+ var setMax$2 = function (options, max) {
1340
+ options.vAxis.viewWindow.max = max;
1341
+ };
1342
+
1343
+ var setBarMin$1 = function (options, min) {
1344
+ options.hAxis.viewWindow.min = min;
1345
+ };
1346
+
1347
+ var setBarMax$1 = function (options, max) {
1348
+ options.hAxis.viewWindow.max = max;
1349
+ };
1350
+
1351
+ var setStacked$2 = function (options, stacked) {
1352
+ options.isStacked = stacked ? stacked : false;
1353
+ };
1354
+
1355
+ var setXtitle$2 = function (options, title) {
1356
+ options.hAxis.title = title;
1357
+ options.hAxis.titleTextStyle.italic = false;
1358
+ };
1359
+
1360
+ var setYtitle$2 = function (options, title) {
1361
+ options.vAxis.title = title;
1362
+ options.vAxis.titleTextStyle.italic = false;
1363
+ };
1364
+
1365
+ var jsOptions$2 = jsOptionsFunc(defaultOptions$2, hideLegend$2, setTitle$2, setMin$2, setMax$2, setStacked$2, setXtitle$2, setYtitle$2);
1366
+
1367
+ var resize = function (callback) {
1368
+ if (window.attachEvent) {
1369
+ window.attachEvent("onresize", callback);
1370
+ } else if (window.addEventListener) {
1371
+ window.addEventListener("resize", callback, true);
1372
+ }
1373
+ callback();
1374
+ };
1375
+
1376
+ var defaultExport$2 = function defaultExport(library) {
1377
+ this.name = "google";
1378
+ this.library = library;
1379
+ };
1380
+
1381
+ defaultExport$2.prototype.renderLineChart = function renderLineChart (chart) {
1382
+ var this$1 = this;
1383
+
1384
+ this.waitForLoaded(chart, function () {
1385
+ var chartOptions = {};
1386
+
1387
+ if (chart.options.curve === false) {
1388
+ chartOptions.curveType = "none";
1389
+ }
1390
+
1391
+ if (chart.options.points === false) {
1392
+ chartOptions.pointSize = 0;
1393
+ }
1394
+
1395
+ var options = jsOptions$2(chart, chart.options, chartOptions);
1396
+ var data = this$1.createDataTable(chart.data, chart.xtype);
1397
+
1398
+ this$1.drawChart(chart, "LineChart", data, options);
1399
+ });
1400
+ };
1401
+
1402
+ defaultExport$2.prototype.renderPieChart = function renderPieChart (chart) {
1403
+ var this$1 = this;
1404
+
1405
+ this.waitForLoaded(chart, function () {
1406
+ var chartOptions = {
1407
+ chartArea: {
1408
+ top: "10%",
1409
+ height: "80%"
1410
+ },
1411
+ legend: {}
1412
+ };
1413
+ if (chart.options.colors) {
1414
+ chartOptions.colors = chart.options.colors;
1415
+ }
1416
+ if (chart.options.donut) {
1417
+ chartOptions.pieHole = 0.5;
1418
+ }
1419
+ if ("legend" in chart.options) {
1420
+ hideLegend$2(chartOptions, chart.options.legend);
1421
+ }
1422
+ if (chart.options.title) {
1423
+ setTitle$2(chartOptions, chart.options.title);
1424
+ }
1425
+ var options = merge(merge(defaultOptions$2, chartOptions), chart.options.library || {});
1426
+
1427
+ var data = new this$1.library.visualization.DataTable();
1428
+ data.addColumn("string", "");
1429
+ data.addColumn("number", "Value");
1430
+ data.addRows(chart.data);
1431
+
1432
+ this$1.drawChart(chart, "PieChart", data, options);
1433
+ });
1434
+ };
1435
+
1436
+ defaultExport$2.prototype.renderColumnChart = function renderColumnChart (chart) {
1437
+ var this$1 = this;
1438
+
1439
+ this.waitForLoaded(chart, function () {
1440
+ var options = jsOptions$2(chart, chart.options);
1441
+ var data = this$1.createDataTable(chart.data, chart.xtype);
1442
+
1443
+ this$1.drawChart(chart, "ColumnChart", data, options);
1444
+ });
1445
+ };
1446
+
1447
+ defaultExport$2.prototype.renderBarChart = function renderBarChart (chart) {
1448
+ var this$1 = this;
1449
+
1450
+ this.waitForLoaded(chart, function () {
1451
+ var chartOptions = {
1452
+ hAxis: {
1453
+ gridlines: {
1454
+ color: "#ccc"
1455
+ }
1456
+ }
1457
+ };
1458
+ var options = jsOptionsFunc(defaultOptions$2, hideLegend$2, setTitle$2, setBarMin$1, setBarMax$1, setStacked$2, setXtitle$2, setYtitle$2)(chart, chart.options, chartOptions);
1459
+ var data = this$1.createDataTable(chart.data, chart.xtype);
1460
+
1461
+ this$1.drawChart(chart, "BarChart", data, options);
1462
+ });
1463
+ };
1464
+
1465
+ defaultExport$2.prototype.renderAreaChart = function renderAreaChart (chart) {
1466
+ var this$1 = this;
1467
+
1468
+ this.waitForLoaded(chart, function () {
1469
+ var chartOptions = {
1470
+ isStacked: true,
1471
+ pointSize: 0,
1472
+ areaOpacity: 0.5
1473
+ };
1474
+
1475
+ var options = jsOptions$2(chart, chart.options, chartOptions);
1476
+ var data = this$1.createDataTable(chart.data, chart.xtype);
1477
+
1478
+ this$1.drawChart(chart, "AreaChart", data, options);
1479
+ });
1480
+ };
1481
+
1482
+ defaultExport$2.prototype.renderGeoChart = function renderGeoChart (chart) {
1483
+ var this$1 = this;
1484
+
1485
+ this.waitForLoaded(chart, "geochart", function () {
1486
+ var chartOptions = {
1487
+ legend: "none",
1488
+ colorAxis: {
1489
+ colors: chart.options.colors || ["#f6c7b6", "#ce502d"]
1490
+ }
1491
+ };
1492
+ var options = merge(merge(defaultOptions$2, chartOptions), chart.options.library || {});
1493
+
1494
+ var data = new this$1.library.visualization.DataTable();
1495
+ data.addColumn("string", "");
1496
+ data.addColumn("number", chart.options.label || "Value");
1497
+ data.addRows(chart.data);
1498
+
1499
+ this$1.drawChart(chart, "GeoChart", data, options);
1500
+ });
1501
+ };
1502
+
1503
+ defaultExport$2.prototype.renderScatterChart = function renderScatterChart (chart) {
1504
+ var this$1 = this;
1505
+
1506
+ this.waitForLoaded(chart, function () {
1507
+ var chartOptions = {};
1508
+ var options = jsOptions$2(chart, chart.options, chartOptions);
1509
+
1510
+ var series = chart.data, rows2 = [], i, j, data, d;
1511
+ for (i = 0; i < series.length; i++) {
1512
+ series[i].name = series[i].name || "Value";
1513
+ d = series[i].data;
1514
+ for (j = 0; j < d.length; j++) {
1515
+ var row = new Array(series.length + 1);
1516
+ row[0] = d[j][0];
1517
+ row[i + 1] = d[j][1];
1518
+ rows2.push(row);
1519
+ }
1520
+ }
1521
+
1522
+ data = new this$1.library.visualization.DataTable();
1523
+ data.addColumn("number", "");
1524
+ for (i = 0; i < series.length; i++) {
1525
+ data.addColumn("number", series[i].name);
1526
+ }
1527
+ data.addRows(rows2);
1528
+
1529
+ this$1.drawChart(chart, "ScatterChart", data, options);
1530
+ });
1531
+ };
1532
+
1533
+ defaultExport$2.prototype.renderTimeline = function renderTimeline (chart) {
1534
+ var this$1 = this;
1535
+
1536
+ this.waitForLoaded(chart, "timeline", function () {
1537
+ var chartOptions = {
1538
+ legend: "none"
1539
+ };
1540
+
1541
+ if (chart.options.colors) {
1542
+ chartOptions.colors = chart.options.colors;
1543
+ }
1544
+ var options = merge(merge(defaultOptions$2, chartOptions), chart.options.library || {});
1545
+
1546
+ var data = new this$1.library.visualization.DataTable();
1547
+ data.addColumn({type: "string", id: "Name"});
1548
+ data.addColumn({type: "date", id: "Start"});
1549
+ data.addColumn({type: "date", id: "End"});
1550
+ data.addRows(chart.data);
1551
+
1552
+ chart.element.style.lineHeight = "normal";
1553
+
1554
+ this$1.drawChart(chart, "Timeline", data, options);
1555
+ });
1556
+ };
1557
+
1558
+ defaultExport$2.prototype.destroy = function destroy (chart) {
1559
+ if (chart.chart) {
1560
+ chart.chart.clearChart();
1561
+ }
1562
+ };
1563
+
1564
+ defaultExport$2.prototype.drawChart = function drawChart (chart, type, data, options) {
1565
+ this.destroy(chart);
1566
+
1567
+ if (chart.options.code) {
1568
+ window.console.log("var data = new google.visualization.DataTable(" + data.toJSON() + ");\nvar chart = new google.visualization." + type + "(element);\nchart.draw(data, " + JSON.stringify(options) + ");");
1569
+ }
1570
+
1571
+ chart.chart = new this.library.visualization[type](chart.element);
1572
+ resize(function () {
1573
+ chart.chart.draw(data, options);
1574
+ });
1575
+ };
1576
+
1577
+ defaultExport$2.prototype.waitForLoaded = function waitForLoaded (chart, pack, callback) {
1578
+ var this$1 = this;
1579
+
1580
+ if (!callback) {
1581
+ callback = pack;
1582
+ pack = "corechart";
1583
+ }
1584
+
1585
+ callbacks.push({pack: pack, callback: callback});
1586
+
1587
+ if (loaded[pack]) {
1588
+ this.runCallbacks();
1589
+ } else {
1590
+ loaded[pack] = true;
1591
+
1592
+ // https://groups.google.com/forum/#!topic/google-visualization-api/fMKJcyA2yyI
1593
+ var loadOptions = {
1594
+ packages: [pack],
1595
+ callback: function () { this$1.runCallbacks(); }
1596
+ };
1597
+ var config = chart.__config();
1598
+ if (config.language) {
1599
+ loadOptions.language = config.language;
1600
+ }
1601
+ if (pack === "geochart" && config.mapsApiKey) {
1602
+ loadOptions.mapsApiKey = config.mapsApiKey;
1603
+ }
1604
+
1605
+ this.library.charts.load("current", loadOptions);
1606
+ }
1607
+ };
1608
+
1609
+ defaultExport$2.prototype.runCallbacks = function runCallbacks () {
1610
+ var cb, call;
1611
+ for (var i = 0; i < callbacks.length; i++) {
1612
+ cb = callbacks[i];
1613
+ call = this.library.visualization && ((cb.pack === "corechart" && this.library.visualization.LineChart) || (cb.pack === "timeline" && this.library.visualization.Timeline) || (cb.pack === "geochart" && this.library.visualization.GeoChart));
1614
+ if (call) {
1615
+ cb.callback();
1616
+ callbacks.splice(i, 1);
1617
+ i--;
1618
+ }
1619
+ }
1620
+ };
1621
+
1622
+ // cant use object as key
1623
+ defaultExport$2.prototype.createDataTable = function createDataTable (series, columnType) {
1624
+ var i, j, s, d, key, rows = [], sortedLabels = [];
1625
+ for (i = 0; i < series.length; i++) {
1626
+ s = series[i];
1627
+ series[i].name = series[i].name || "Value";
1628
+
1629
+ for (j = 0; j < s.data.length; j++) {
1630
+ d = s.data[j];
1631
+ key = (columnType === "datetime") ? d[0].getTime() : d[0];
1632
+ if (!rows[key]) {
1633
+ rows[key] = new Array(series.length);
1634
+ sortedLabels.push(key);
1635
+ }
1636
+ rows[key][i] = toFloat(d[1]);
1637
+ }
1638
+ }
1639
+
1640
+ var rows2 = [];
1641
+ var day = true;
1642
+ var value;
1643
+ for (j = 0; j < sortedLabels.length; j++) {
1644
+ i = sortedLabels[j];
1645
+ if (columnType === "datetime") {
1646
+ value = new Date(toFloat(i));
1647
+ day = day && isDay(value);
1648
+ } else if (columnType === "number") {
1649
+ value = toFloat(i);
1650
+ } else {
1651
+ value = i;
1652
+ }
1653
+ rows2.push([value].concat(rows[i]));
1654
+ }
1655
+ if (columnType === "datetime") {
1656
+ rows2.sort(sortByTime);
1657
+ } else if (columnType === "number") {
1658
+ rows2.sort(sortByNumberSeries);
1659
+
1660
+ for (i = 0; i < rows2.length; i++) {
1661
+ rows2[i][0] = toStr(rows2[i][0]);
1662
+ }
1663
+
1664
+ columnType = "string";
1665
+ }
1666
+
1667
+ // create datatable
1668
+ var data = new this.library.visualization.DataTable();
1669
+ columnType = columnType === "datetime" && day ? "date" : columnType;
1670
+ data.addColumn(columnType, "");
1671
+ for (i = 0; i < series.length; i++) {
1672
+ data.addColumn("number", series[i].name);
1673
+ }
1674
+ data.addRows(rows2);
1675
+
1676
+ return data;
1677
+ };
1678
+
1679
+ var pendingRequests = [], runningRequests = 0, maxRequests = 4;
1680
+
1681
+ function pushRequest(url, success, error) {
1682
+ pendingRequests.push([url, success, error]);
1683
+ runNext();
1684
+ }
1685
+
1686
+ function runNext() {
1687
+ if (runningRequests < maxRequests) {
1688
+ var request = pendingRequests.shift();
1689
+ if (request) {
1690
+ runningRequests++;
1691
+ getJSON(request[0], request[1], request[2]);
1692
+ runNext();
1693
+ }
1694
+ }
1695
+ }
1696
+
1697
+ function requestComplete() {
1698
+ runningRequests--;
1699
+ runNext();
1700
+ }
1701
+
1702
+ function getJSON(url, success, error) {
1703
+ ajaxCall(url, success, function (jqXHR, textStatus, errorThrown) {
1704
+ var message = (typeof errorThrown === "string") ? errorThrown : errorThrown.message;
1705
+ error(message);
1706
+ });
1707
+ }
1708
+
1709
+ function ajaxCall(url, success, error) {
1710
+ var $ = window.jQuery || window.Zepto || window.$;
1711
+
1712
+ if ($ && $.ajax) {
1713
+ $.ajax({
1714
+ dataType: "json",
1715
+ url: url,
1716
+ success: success,
1717
+ error: error,
1718
+ complete: requestComplete
1719
+ });
1720
+ } else {
1721
+ var xhr = new XMLHttpRequest();
1722
+ xhr.open("GET", url, true);
1723
+ xhr.setRequestHeader("Content-Type", "application/json");
1724
+ xhr.onload = function () {
1725
+ requestComplete();
1726
+ if (xhr.status === 200) {
1727
+ success(JSON.parse(xhr.responseText), xhr.statusText, xhr);
1728
+ } else {
1729
+ error(xhr, "error", xhr.statusText);
1730
+ }
1731
+ };
1732
+ xhr.send();
1733
+ }
1734
+ }
1735
+
1736
+ var config = {};
1737
+ var adapters = [];
1738
+
1739
+ // helpers
1740
+
1741
+ function setText(element, text) {
1742
+ if (document.body.innerText) {
1743
+ element.innerText = text;
1744
+ } else {
1745
+ element.textContent = text;
1746
+ }
1747
+ }
1748
+
1749
+ // TODO remove prefix for all messages
1750
+ function chartError(element, message, noPrefix) {
1751
+ if (!noPrefix) {
1752
+ message = "Error Loading Chart: " + message;
1753
+ }
1754
+ setText(element, message);
1755
+ element.style.color = "#ff0000";
1756
+ }
1757
+
1758
+ function errorCatcher(chart) {
1759
+ try {
1760
+ chart.__render();
1761
+ } catch (err) {
1762
+ chartError(chart.element, err.message);
1763
+ throw err;
1764
+ }
1765
+ }
1766
+
1767
+ function fetchDataSource(chart, dataSource) {
1768
+ if (typeof dataSource === "string") {
1769
+ pushRequest(dataSource, function (data) {
1770
+ chart.rawData = data;
1771
+ errorCatcher(chart);
1772
+ }, function (message) {
1773
+ chartError(chart.element, message);
1774
+ });
1775
+ } else if (typeof dataSource === "function") {
1776
+ try {
1777
+ dataSource(function (data) {
1778
+ chart.rawData = data;
1779
+ errorCatcher(chart);
1780
+ }, function (message) {
1781
+ chartError(chart.element, message, true);
1782
+ });
1783
+ } catch (err) {
1784
+ chartError(chart.element, err, true);
1785
+ }
1786
+ } else {
1787
+ chart.rawData = dataSource;
1788
+ errorCatcher(chart);
1789
+ }
1790
+ }
1791
+
1792
+ function addDownloadButton(chart) {
1793
+ var element = chart.element;
1794
+ var link = document.createElement("a");
1795
+
1796
+ var download = chart.options.download;
1797
+ if (download === true) {
1798
+ download = {};
1799
+ } else if (typeof download === "string") {
1800
+ download = {filename: download};
1801
+ }
1802
+ link.download = download.filename || "chart.png"; // https://caniuse.com/download
1803
+
1804
+ link.style.position = "absolute";
1805
+ link.style.top = "20px";
1806
+ link.style.right = "20px";
1807
+ link.style.zIndex = 1000;
1808
+ link.style.lineHeight = "20px";
1809
+ link.target = "_blank"; // for safari
1810
+ var image = document.createElement("img");
1811
+ image.alt = "Download";
1812
+ image.style.border = "none";
1813
+ // icon from font-awesome
1814
+ // http://fa2png.io/
1815
+ image.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAMAAAC6V+0/AAABCFBMVEUAAADMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMywEsqxAAAAV3RSTlMAAQIDBggJCgsMDQ4PERQaHB0eISIjJCouLzE0OTo/QUJHSUpLTU5PUllhYmltcHh5foWLjI+SlaCio6atr7S1t7m6vsHHyM7R2tze5Obo7fHz9ff5+/1hlxK2AAAA30lEQVQYGUXBhVYCQQBA0TdYWAt2d3d3YWAHyur7/z9xgD16Lw0DW+XKx+1GgX+FRzM3HWQWrHl5N/oapW5RPe0PkBu+UYeICvozTWZVK23Ao04B79oJrOsJDOoxkZoQPWgX29pHpCZEk7rEvQYiNSFq1UMqvlCjJkRBS1R8hb00Vb/TajtBL7nTHE1X1vyMQF732dQhyF2o6SAwrzP06iUQzvwsArlnzcOdrgBhJyHa1QOgO9U1GsKuvjUTjavliZYQ8nNPapG6sap/3nrIdJ6bOWzmX/fy0XVpfzZP3S8OJT3g9EEiJwAAAABJRU5ErkJggg==";
1816
+ link.appendChild(image);
1817
+ element.style.position = "relative";
1291
1818
 
1292
- var labels = [];
1293
- var values = [];
1294
- for (var i = 0; i < chart.data.length; i++) {
1295
- var point = chart.data[i];
1296
- labels.push(point[0]);
1297
- values.push(point[1]);
1298
- }
1819
+ chart.__downloadAttached = true;
1299
1820
 
1300
- var data = {
1301
- labels: labels,
1302
- datasets: [
1303
- {
1304
- data: values,
1305
- backgroundColor: chart.options.colors || defaultColors
1306
- }
1307
- ]
1308
- };
1821
+ // mouseenter
1822
+ chart.__enterEvent = addEvent(element, "mouseover", function(e) {
1823
+ var related = e.relatedTarget;
1824
+ // check download option again to ensure it wasn't changed
1825
+ if ((!related || (related !== this && !childOf(this, related))) && chart.options.download) {
1826
+ link.href = chart.toImage(download);
1827
+ element.appendChild(link);
1828
+ }
1829
+ });
1309
1830
 
1310
- drawChart(chart, "pie", data, options);
1311
- };
1831
+ // mouseleave
1832
+ chart.__leaveEvent = addEvent(element, "mouseout", function(e) {
1833
+ var related = e.relatedTarget;
1834
+ if (!related || (related !== this && !childOf(this, related))) {
1835
+ if (link.parentNode) {
1836
+ link.parentNode.removeChild(link);
1837
+ }
1838
+ }
1839
+ });
1840
+ }
1312
1841
 
1313
- this.renderColumnChart = function (chart, chartType) {
1314
- var options;
1315
- if (chartType === "bar") {
1316
- options = jsOptionsFunc(merge(baseOptions, defaultOptions), hideLegend, setTitle, setBarMin, setBarMax, setStacked, setXtitle, setYtitle)(chart, chart.options);
1317
- } else {
1318
- options = jsOptions(chart, chart.options);
1319
- }
1320
- var data = createDataTable(chart, options, "column");
1321
- setLabelSize(chart, data, options);
1322
- drawChart(chart, (chartType === "bar" ? "horizontalBar" : "bar"), data, options);
1323
- };
1842
+ // https://stackoverflow.com/questions/10149963/adding-event-listener-cross-browser
1843
+ function addEvent(elem, event, fn) {
1844
+ if (elem.addEventListener) {
1845
+ elem.addEventListener(event, fn, false);
1846
+ return fn;
1847
+ } else {
1848
+ var fn2 = function() {
1849
+ // set the this pointer same as addEventListener when fn is called
1850
+ return(fn.call(elem, window.event));
1851
+ };
1852
+ elem.attachEvent("on" + event, fn2);
1853
+ return fn2;
1854
+ }
1855
+ }
1324
1856
 
1325
- var self = this;
1857
+ function removeEvent(elem, event, fn) {
1858
+ if (elem.removeEventListener) {
1859
+ elem.removeEventListener(event, fn, false);
1860
+ } else {
1861
+ elem.detachEvent("on" + event, fn);
1862
+ }
1863
+ }
1326
1864
 
1327
- this.renderAreaChart = function (chart) {
1328
- self.renderLineChart(chart, "area");
1329
- };
1865
+ // https://gist.github.com/shawnbot/4166283
1866
+ function childOf(p, c) {
1867
+ if (p === c) { return false; }
1868
+ while (c && c !== p) { c = c.parentNode; }
1869
+ return c === p;
1870
+ }
1330
1871
 
1331
- this.renderBarChart = function (chart) {
1332
- self.renderColumnChart(chart, "bar");
1333
- };
1872
+ function getAdapterType(library) {
1873
+ if (library) {
1874
+ if (library.product === "Highcharts") {
1875
+ return defaultExport$1;
1876
+ } else if (library.charts) {
1877
+ return defaultExport$2;
1878
+ } else if (isFunction(library)) {
1879
+ return defaultExport;
1880
+ }
1881
+ }
1882
+ throw new Error("Unknown adapter");
1883
+ }
1334
1884
 
1335
- this.renderScatterChart = function (chart) {
1336
- var options = jsOptions(chart, chart.options);
1337
-
1338
- var colors = chart.options.colors || defaultColors;
1339
-
1340
- var datasets = [];
1341
- var series = chart.data;
1342
- for (var i = 0; i < series.length; i++) {
1343
- var s = series[i];
1344
- var d = [];
1345
- for (var j = 0; j < s.data.length; j++) {
1346
- d.push({
1347
- x: toFloat(s.data[j][0]),
1348
- y: toFloat(s.data[j][1])
1349
- });
1350
- }
1885
+ function addAdapter(library) {
1886
+ var adapterType = getAdapterType(library);
1887
+ var adapter = new adapterType(library);
1351
1888
 
1352
- datasets.push({
1353
- label: s.name,
1354
- showLine: false,
1355
- data: d,
1356
- borderColor: colors[i],
1357
- backgroundColor: colors[i],
1358
- pointBackgroundColor: colors[i]
1359
- })
1360
- }
1889
+ if (adapters.indexOf(adapter) === -1) {
1890
+ adapters.push(adapter);
1891
+ }
1892
+ }
1361
1893
 
1362
- var data = {datasets: datasets};
1894
+ function loadAdapters() {
1895
+ if ("Chart" in window) {
1896
+ addAdapter(window.Chart);
1897
+ }
1363
1898
 
1364
- options.scales.xAxes[0].type = "linear";
1365
- options.scales.xAxes[0].position = "bottom";
1899
+ if ("Highcharts" in window) {
1900
+ addAdapter(window.Highcharts);
1901
+ }
1366
1902
 
1367
- drawChart(chart, "line", data, options);
1368
- };
1369
- };
1903
+ if (window.google && window.google.charts) {
1904
+ addAdapter(window.google);
1905
+ }
1906
+ }
1370
1907
 
1371
- adapters.unshift(ChartjsAdapter);
1908
+ function dataEmpty(data, chartType) {
1909
+ if (chartType === "PieChart" || chartType === "GeoChart" || chartType === "Timeline") {
1910
+ return data.length === 0;
1911
+ } else {
1912
+ for (var i = 0; i < data.length; i++) {
1913
+ if (data[i].data.length > 0) {
1914
+ return false;
1915
+ }
1916
+ }
1917
+ return true;
1372
1918
  }
1373
1919
  }
1374
1920
 
1375
1921
  function renderChart(chartType, chart) {
1376
- callAdapter(chartType, chart);
1377
- if (chart.options.download && !chart.downloadAttached && chart.adapter === "chartjs") {
1378
- addDownloadButton(chart);
1922
+ if (chart.options.messages && chart.options.messages.empty && dataEmpty(chart.data, chartType)) {
1923
+ setText(chart.element, chart.options.messages.empty);
1924
+ } else {
1925
+ callAdapter(chartType, chart);
1926
+ if (chart.options.download && !chart.__downloadAttached && chart.adapter === "chartjs") {
1927
+ addDownloadButton(chart);
1928
+ }
1379
1929
  }
1380
1930
  }
1381
1931
 
@@ -1392,10 +1942,16 @@
1392
1942
  adapter = adapters[i];
1393
1943
  if ((!adapterName || adapterName === adapter.name) && isFunction(adapter[fnName])) {
1394
1944
  chart.adapter = adapter.name;
1945
+ chart.__adapterObject = adapter;
1395
1946
  return adapter[fnName](chart);
1396
1947
  }
1397
1948
  }
1398
- throw new Error("No adapter found");
1949
+
1950
+ if (adapters.length > 0) {
1951
+ throw new Error("No charting library found for " + chartType);
1952
+ } else {
1953
+ throw new Error("No charting libraries found - be sure to include one before your charts");
1954
+ }
1399
1955
  }
1400
1956
 
1401
1957
  // process data
@@ -1414,49 +1970,43 @@
1414
1970
  var formatSeriesData = function (data, keyType) {
1415
1971
  var r = [], key, j;
1416
1972
  for (j = 0; j < data.length; j++) {
1417
- key = toFormattedKey(data[j][0], keyType);
1418
- r.push([key, toFloat(data[j][1])]);
1973
+ if (keyType === "bubble") {
1974
+ r.push([toFloat(data[j][0]), toFloat(data[j][1]), toFloat(data[j][2])]);
1975
+ } else {
1976
+ key = toFormattedKey(data[j][0], keyType);
1977
+ r.push([key, toFloat(data[j][1])]);
1978
+ }
1419
1979
  }
1420
1980
  if (keyType === "datetime") {
1421
1981
  r.sort(sortByTime);
1982
+ } else if (keyType === "number") {
1983
+ r.sort(sortByNumberSeries);
1422
1984
  }
1423
1985
  return r;
1424
1986
  };
1425
1987
 
1426
- function isMinute(d) {
1427
- return d.getMilliseconds() === 0 && d.getSeconds() === 0;
1428
- }
1429
-
1430
- function isHour(d) {
1431
- return isMinute(d) && d.getMinutes() === 0;
1432
- }
1433
-
1434
- function isDay(d) {
1435
- return isHour(d) && d.getHours() === 0;
1436
- }
1437
-
1438
- function isWeek(d, dayOfWeek) {
1439
- return isDay(d) && d.getDay() === dayOfWeek;
1440
- }
1441
-
1442
- function isMonth(d) {
1443
- return isDay(d) && d.getDate() === 1;
1444
- }
1445
-
1446
- function isYear(d) {
1447
- return isMonth(d) && d.getMonth() === 0;
1448
- }
1449
-
1450
- function isDate(obj) {
1451
- return !isNaN(toDate(obj)) && toStr(obj).length >= 6;
1988
+ function detectXType(series, noDatetime, options) {
1989
+ if (dataEmpty(series)) {
1990
+ if ((options.xmin || options.xmax) && (!options.xmin || isDate(options.xmin)) && (!options.xmax || isDate(options.xmax))) {
1991
+ return "datetime";
1992
+ } else {
1993
+ return "number";
1994
+ }
1995
+ } else if (detectXTypeWithFunction(series, isNumber)) {
1996
+ return "number";
1997
+ } else if (!noDatetime && detectXTypeWithFunction(series, isDate)) {
1998
+ return "datetime";
1999
+ } else {
2000
+ return "string";
2001
+ }
1452
2002
  }
1453
2003
 
1454
- function allZeros(data) {
1455
- var i, j, d;
1456
- for (i = 0; i < data.length; i++) {
1457
- d = data[i].data;
1458
- for (j = 0; j < d.length; j++) {
1459
- if (d[j][1] != 0) {
2004
+ function detectXTypeWithFunction(series, func) {
2005
+ var i, j, data;
2006
+ for (i = 0; i < series.length; i++) {
2007
+ data = toArr(series[i].data);
2008
+ for (j = 0; j < data.length; j++) {
2009
+ if (!func(data[j][0])) {
1460
2010
  return false;
1461
2011
  }
1462
2012
  }
@@ -1464,20 +2014,23 @@
1464
2014
  return true;
1465
2015
  }
1466
2016
 
1467
- function detectDiscrete(series) {
1468
- var i, j, data;
2017
+ // creates a shallow copy of each element of the array
2018
+ // elements are expected to be objects
2019
+ function copySeries(series) {
2020
+ var newSeries = [], i, j;
1469
2021
  for (i = 0; i < series.length; i++) {
1470
- data = toArr(series[i].data);
1471
- for (j = 0; j < data.length; j++) {
1472
- if (!isDate(data[j][0])) {
1473
- return true;
2022
+ var copy = {};
2023
+ for (j in series[i]) {
2024
+ if (series[i].hasOwnProperty(j)) {
2025
+ copy[j] = series[i][j];
1474
2026
  }
1475
2027
  }
2028
+ newSeries.push(copy);
1476
2029
  }
1477
- return false;
2030
+ return newSeries;
1478
2031
  }
1479
2032
 
1480
- function processSeries(chart, keyType) {
2033
+ function processSeries(chart, keyType, noDatetime) {
1481
2034
  var i;
1482
2035
 
1483
2036
  var opts = chart.options;
@@ -1485,23 +2038,24 @@
1485
2038
 
1486
2039
  // see if one series or multiple
1487
2040
  if (!isArray(series) || typeof series[0] !== "object" || isArray(series[0])) {
1488
- series = [{name: opts.label || "Value", data: series}];
2041
+ series = [{name: opts.label, data: series}];
1489
2042
  chart.hideLegend = true;
1490
2043
  } else {
1491
2044
  chart.hideLegend = false;
1492
2045
  }
1493
- if ((opts.discrete === null || opts.discrete === undefined)) {
1494
- chart.discrete = detectDiscrete(series);
1495
- } else {
1496
- chart.discrete = opts.discrete;
1497
- }
1498
- if (chart.discrete) {
1499
- keyType = "string";
2046
+
2047
+ // convert to array
2048
+ // must come before dataEmpty check
2049
+ series = copySeries(series);
2050
+ for (i = 0; i < series.length; i++) {
2051
+ series[i].data = toArr(series[i].data);
1500
2052
  }
1501
2053
 
2054
+ chart.xtype = keyType ? keyType : (opts.discrete ? "string" : detectXType(series, noDatetime, opts));
2055
+
1502
2056
  // right format
1503
2057
  for (i = 0; i < series.length; i++) {
1504
- series[i].data = formatSeriesData(toArr(series[i].data), keyType);
2058
+ series[i].data = formatSeriesData(series[i].data, chart.xtype);
1505
2059
  }
1506
2060
 
1507
2061
  return series;
@@ -1515,37 +2069,9 @@
1515
2069
  return perfectData;
1516
2070
  }
1517
2071
 
1518
- function processTime(chart)
1519
- {
1520
- var i, data = chart.rawData;
1521
- for (i = 0; i < data.length; i++) {
1522
- data[i][1] = toDate(data[i][1]);
1523
- data[i][2] = toDate(data[i][2]);
1524
- }
1525
- return data;
1526
- }
1527
-
1528
- function processLineData(chart) {
1529
- return processSeries(chart, "datetime");
1530
- }
1531
-
1532
- function processColumnData(chart) {
1533
- return processSeries(chart, "string");
1534
- }
1535
-
1536
- function processBarData(chart) {
1537
- return processSeries(chart, "string");
1538
- }
1539
-
1540
- function processAreaData(chart) {
1541
- return processSeries(chart, "datetime");
1542
- }
1543
-
1544
- function processScatterData(chart) {
1545
- return processSeries(chart, "number");
1546
- }
2072
+ // define classes
1547
2073
 
1548
- function createChart(chartType, chart, element, dataSource, opts, processData) {
2074
+ var Chart = function Chart(element, dataSource, options) {
1549
2075
  var elementId;
1550
2076
  if (typeof element === "string") {
1551
2077
  elementId = element;
@@ -1554,117 +2080,349 @@
1554
2080
  throw new Error("No element with id " + elementId);
1555
2081
  }
1556
2082
  }
2083
+ this.element = element;
2084
+ this.options = merge(Chartkick.options, options || {});
2085
+ this.dataSource = dataSource;
2086
+
2087
+ Chartkick.charts[element.id] = this;
2088
+
2089
+ fetchDataSource(this, dataSource);
2090
+
2091
+ if (this.options.refresh) {
2092
+ this.startRefresh();
2093
+ }
2094
+ };
2095
+
2096
+ Chart.prototype.getElement = function getElement () {
2097
+ return this.element;
2098
+ };
2099
+
2100
+ Chart.prototype.getDataSource = function getDataSource () {
2101
+ return this.dataSource;
2102
+ };
2103
+
2104
+ Chart.prototype.getData = function getData () {
2105
+ return this.data;
2106
+ };
2107
+
2108
+ Chart.prototype.getOptions = function getOptions () {
2109
+ return this.options;
2110
+ };
2111
+
2112
+ Chart.prototype.getChartObject = function getChartObject () {
2113
+ return this.chart;
2114
+ };
2115
+
2116
+ Chart.prototype.getAdapter = function getAdapter () {
2117
+ return this.adapter;
2118
+ };
2119
+
2120
+ Chart.prototype.updateData = function updateData (dataSource, options) {
2121
+ this.dataSource = dataSource;
2122
+ if (options) {
2123
+ this.__updateOptions(options);
2124
+ }
2125
+ fetchDataSource(this, dataSource);
2126
+ };
2127
+
2128
+ Chart.prototype.setOptions = function setOptions (options) {
2129
+ this.__updateOptions(options);
2130
+ this.redraw();
2131
+ };
2132
+
2133
+ Chart.prototype.redraw = function redraw () {
2134
+ fetchDataSource(this, this.rawData);
2135
+ };
2136
+
2137
+ Chart.prototype.refreshData = function refreshData () {
2138
+ if (typeof this.dataSource === "string") {
2139
+ // prevent browser from caching
2140
+ var sep = this.dataSource.indexOf("?") === -1 ? "?" : "&";
2141
+ var url = this.dataSource + sep + "_=" + (new Date()).getTime();
2142
+ fetchDataSource(this, url);
2143
+ } else if (typeof this.dataSource === "function") {
2144
+ fetchDataSource(this, this.dataSource);
2145
+ }
2146
+ };
2147
+
2148
+ Chart.prototype.startRefresh = function startRefresh () {
2149
+ var this$1 = this;
2150
+
2151
+ var refresh = this.options.refresh;
2152
+
2153
+ if (refresh && typeof this.dataSource !== "string" && typeof this.dataSource !== "function") {
2154
+ throw new Error("Data source must be a URL or callback for refresh");
2155
+ }
2156
+
2157
+ if (!this.intervalId) {
2158
+ if (refresh) {
2159
+ this.intervalId = setInterval( function () {
2160
+ this$1.refreshData();
2161
+ }, refresh * 1000);
2162
+ } else {
2163
+ throw new Error("No refresh interval");
2164
+ }
2165
+ }
2166
+ };
1557
2167
 
1558
- chart.element = element;
1559
- opts = merge(Chartkick.options, opts || {});
1560
- chart.options = opts;
1561
- chart.dataSource = dataSource;
2168
+ Chart.prototype.stopRefresh = function stopRefresh () {
2169
+ if (this.intervalId) {
2170
+ clearInterval(this.intervalId);
2171
+ this.intervalId = null;
2172
+ }
2173
+ };
1562
2174
 
1563
- if (!processData) {
1564
- processData = function (chart) {
1565
- return chart.rawData;
2175
+ Chart.prototype.toImage = function toImage (download) {
2176
+ if (this.adapter === "chartjs") {
2177
+ if (download && download.background && download.background !== "transparent") {
2178
+ // https://stackoverflow.com/questions/30464750/chartjs-line-chart-set-background-color
2179
+ var canvas = this.chart.chart.canvas;
2180
+ var ctx = this.chart.chart.ctx;
2181
+ var tmpCanvas = document.createElement("canvas");
2182
+ var tmpCtx = tmpCanvas.getContext("2d");
2183
+ tmpCanvas.width = ctx.canvas.width;
2184
+ tmpCanvas.height = ctx.canvas.height;
2185
+ tmpCtx.fillStyle = download.background;
2186
+ tmpCtx.fillRect(0, 0, tmpCanvas.width, tmpCanvas.height);
2187
+ tmpCtx.drawImage(canvas, 0, 0);
2188
+ return tmpCanvas.toDataURL("image/png");
2189
+ } else {
2190
+ return this.chart.toBase64Image();
1566
2191
  }
2192
+ } else {
2193
+ // TODO throw error in next major version
2194
+ // throw new Error("Feature only available for Chart.js");
2195
+ return null;
2196
+ }
2197
+ };
2198
+
2199
+ Chart.prototype.destroy = function destroy () {
2200
+ if (this.__adapterObject) {
2201
+ this.__adapterObject.destroy(this);
2202
+ }
2203
+
2204
+ if (this.__enterEvent) {
2205
+ removeEvent(this.element, "mouseover", this.__enterEvent);
2206
+ }
2207
+
2208
+ if (this.__leaveEvent) {
2209
+ removeEvent(this.element, "mouseout", this.__leaveEvent);
2210
+ }
2211
+ };
2212
+
2213
+ Chart.prototype.__updateOptions = function __updateOptions (options) {
2214
+ var updateRefresh = options.refresh && options.refresh !== this.options.refresh;
2215
+ this.options = merge(Chartkick.options, options);
2216
+ if (updateRefresh) {
2217
+ this.stopRefresh();
2218
+ this.startRefresh();
2219
+ }
2220
+ };
2221
+
2222
+ Chart.prototype.__render = function __render () {
2223
+ this.data = this.__processData();
2224
+ renderChart(this.__chartName(), this);
2225
+ };
2226
+
2227
+ Chart.prototype.__config = function __config () {
2228
+ return config;
2229
+ };
2230
+
2231
+ var LineChart = /*@__PURE__*/(function (Chart) {
2232
+ function LineChart () {
2233
+ Chart.apply(this, arguments);
2234
+ }
2235
+
2236
+ if ( Chart ) LineChart.__proto__ = Chart;
2237
+ LineChart.prototype = Object.create( Chart && Chart.prototype );
2238
+ LineChart.prototype.constructor = LineChart;
2239
+
2240
+ LineChart.prototype.__processData = function __processData () {
2241
+ return processSeries(this);
2242
+ };
2243
+
2244
+ LineChart.prototype.__chartName = function __chartName () {
2245
+ return "LineChart";
2246
+ };
2247
+
2248
+ return LineChart;
2249
+ }(Chart));
2250
+
2251
+ var PieChart = /*@__PURE__*/(function (Chart) {
2252
+ function PieChart () {
2253
+ Chart.apply(this, arguments);
1567
2254
  }
1568
2255
 
1569
- // getters
1570
- chart.getElement = function () {
1571
- return element;
2256
+ if ( Chart ) PieChart.__proto__ = Chart;
2257
+ PieChart.prototype = Object.create( Chart && Chart.prototype );
2258
+ PieChart.prototype.constructor = PieChart;
2259
+
2260
+ PieChart.prototype.__processData = function __processData () {
2261
+ return processSimple(this);
1572
2262
  };
1573
- chart.getDataSource = function () {
1574
- return chart.dataSource;
2263
+
2264
+ PieChart.prototype.__chartName = function __chartName () {
2265
+ return "PieChart";
1575
2266
  };
1576
- chart.getData = function () {
1577
- return chart.data;
2267
+
2268
+ return PieChart;
2269
+ }(Chart));
2270
+
2271
+ var ColumnChart = /*@__PURE__*/(function (Chart) {
2272
+ function ColumnChart () {
2273
+ Chart.apply(this, arguments);
2274
+ }
2275
+
2276
+ if ( Chart ) ColumnChart.__proto__ = Chart;
2277
+ ColumnChart.prototype = Object.create( Chart && Chart.prototype );
2278
+ ColumnChart.prototype.constructor = ColumnChart;
2279
+
2280
+ ColumnChart.prototype.__processData = function __processData () {
2281
+ return processSeries(this, null, true);
1578
2282
  };
1579
- chart.getOptions = function () {
1580
- return chart.options;
2283
+
2284
+ ColumnChart.prototype.__chartName = function __chartName () {
2285
+ return "ColumnChart";
1581
2286
  };
1582
- chart.getChartObject = function () {
1583
- return chart.chart;
2287
+
2288
+ return ColumnChart;
2289
+ }(Chart));
2290
+
2291
+ var BarChart = /*@__PURE__*/(function (Chart) {
2292
+ function BarChart () {
2293
+ Chart.apply(this, arguments);
2294
+ }
2295
+
2296
+ if ( Chart ) BarChart.__proto__ = Chart;
2297
+ BarChart.prototype = Object.create( Chart && Chart.prototype );
2298
+ BarChart.prototype.constructor = BarChart;
2299
+
2300
+ BarChart.prototype.__processData = function __processData () {
2301
+ return processSeries(this, null, true);
1584
2302
  };
1585
- chart.getAdapter = function () {
1586
- return chart.adapter;
2303
+
2304
+ BarChart.prototype.__chartName = function __chartName () {
2305
+ return "BarChart";
1587
2306
  };
1588
2307
 
1589
- var callback = function () {
1590
- chart.data = processData(chart);
1591
- renderChart(chartType, chart);
2308
+ return BarChart;
2309
+ }(Chart));
2310
+
2311
+ var AreaChart = /*@__PURE__*/(function (Chart) {
2312
+ function AreaChart () {
2313
+ Chart.apply(this, arguments);
2314
+ }
2315
+
2316
+ if ( Chart ) AreaChart.__proto__ = Chart;
2317
+ AreaChart.prototype = Object.create( Chart && Chart.prototype );
2318
+ AreaChart.prototype.constructor = AreaChart;
2319
+
2320
+ AreaChart.prototype.__processData = function __processData () {
2321
+ return processSeries(this);
1592
2322
  };
1593
2323
 
1594
- // functions
1595
- chart.updateData = function (dataSource, options) {
1596
- chart.dataSource = dataSource;
1597
- if (options) {
1598
- chart.options = merge(Chartkick.options, options);
1599
- }
1600
- fetchDataSource(chart, callback, dataSource);
2324
+ AreaChart.prototype.__chartName = function __chartName () {
2325
+ return "AreaChart";
1601
2326
  };
1602
- chart.setOptions = function (options) {
1603
- chart.options = merge(Chartkick.options, options);
1604
- chart.redraw();
2327
+
2328
+ return AreaChart;
2329
+ }(Chart));
2330
+
2331
+ var GeoChart = /*@__PURE__*/(function (Chart) {
2332
+ function GeoChart () {
2333
+ Chart.apply(this, arguments);
2334
+ }
2335
+
2336
+ if ( Chart ) GeoChart.__proto__ = Chart;
2337
+ GeoChart.prototype = Object.create( Chart && Chart.prototype );
2338
+ GeoChart.prototype.constructor = GeoChart;
2339
+
2340
+ GeoChart.prototype.__processData = function __processData () {
2341
+ return processSimple(this);
1605
2342
  };
1606
- chart.redraw = function() {
1607
- fetchDataSource(chart, callback, chart.rawData);
2343
+
2344
+ GeoChart.prototype.__chartName = function __chartName () {
2345
+ return "GeoChart";
1608
2346
  };
1609
- chart.refreshData = function () {
1610
- if (typeof dataSource === "string") {
1611
- // prevent browser from caching
1612
- var sep = dataSource.indexOf("?") === -1 ? "?" : "&";
1613
- var url = dataSource + sep + "_=" + (new Date()).getTime();
1614
- fetchDataSource(chart, callback, url);
1615
- }
2347
+
2348
+ return GeoChart;
2349
+ }(Chart));
2350
+
2351
+ var ScatterChart = /*@__PURE__*/(function (Chart) {
2352
+ function ScatterChart () {
2353
+ Chart.apply(this, arguments);
2354
+ }
2355
+
2356
+ if ( Chart ) ScatterChart.__proto__ = Chart;
2357
+ ScatterChart.prototype = Object.create( Chart && Chart.prototype );
2358
+ ScatterChart.prototype.constructor = ScatterChart;
2359
+
2360
+ ScatterChart.prototype.__processData = function __processData () {
2361
+ return processSeries(this, "number");
1616
2362
  };
1617
- chart.stopRefresh = function () {
1618
- if (chart.intervalId) {
1619
- clearInterval(chart.intervalId);
1620
- }
2363
+
2364
+ ScatterChart.prototype.__chartName = function __chartName () {
2365
+ return "ScatterChart";
1621
2366
  };
1622
- chart.toImage = function () {
1623
- if (chart.adapter === "chartjs") {
1624
- return chart.chart.toBase64Image();
1625
- } else {
1626
- return null;
1627
- }
2367
+
2368
+ return ScatterChart;
2369
+ }(Chart));
2370
+
2371
+ var BubbleChart = /*@__PURE__*/(function (Chart) {
2372
+ function BubbleChart () {
2373
+ Chart.apply(this, arguments);
1628
2374
  }
1629
2375
 
1630
- Chartkick.charts[element.id] = chart;
2376
+ if ( Chart ) BubbleChart.__proto__ = Chart;
2377
+ BubbleChart.prototype = Object.create( Chart && Chart.prototype );
2378
+ BubbleChart.prototype.constructor = BubbleChart;
1631
2379
 
1632
- fetchDataSource(chart, callback, dataSource);
2380
+ BubbleChart.prototype.__processData = function __processData () {
2381
+ return processSeries(this, "bubble");
2382
+ };
2383
+
2384
+ BubbleChart.prototype.__chartName = function __chartName () {
2385
+ return "BubbleChart";
2386
+ };
2387
+
2388
+ return BubbleChart;
2389
+ }(Chart));
1633
2390
 
1634
- if (opts.refresh) {
1635
- chart.intervalId = setInterval( function () {
1636
- chart.refreshData();
1637
- }, opts.refresh * 1000);
2391
+ var Timeline = /*@__PURE__*/(function (Chart) {
2392
+ function Timeline () {
2393
+ Chart.apply(this, arguments);
1638
2394
  }
1639
- }
1640
2395
 
1641
- // define classes
2396
+ if ( Chart ) Timeline.__proto__ = Chart;
2397
+ Timeline.prototype = Object.create( Chart && Chart.prototype );
2398
+ Timeline.prototype.constructor = Timeline;
1642
2399
 
1643
- Chartkick = {
1644
- LineChart: function (element, dataSource, options) {
1645
- createChart("LineChart", this, element, dataSource, options, processLineData);
1646
- },
1647
- PieChart: function (element, dataSource, options) {
1648
- createChart("PieChart", this, element, dataSource, options, processSimple);
1649
- },
1650
- ColumnChart: function (element, dataSource, options) {
1651
- createChart("ColumnChart", this, element, dataSource, options, processColumnData);
1652
- },
1653
- BarChart: function (element, dataSource, options) {
1654
- createChart("BarChart", this, element, dataSource, options, processBarData);
1655
- },
1656
- AreaChart: function (element, dataSource, options) {
1657
- createChart("AreaChart", this, element, dataSource, options, processAreaData);
1658
- },
1659
- GeoChart: function (element, dataSource, options) {
1660
- createChart("GeoChart", this, element, dataSource, options, processSimple);
1661
- },
1662
- ScatterChart: function (element, dataSource, options) {
1663
- createChart("ScatterChart", this, element, dataSource, options, processScatterData);
1664
- },
1665
- Timeline: function (element, dataSource, options) {
1666
- createChart("Timeline", this, element, dataSource, options, processTime);
1667
- },
2400
+ Timeline.prototype.__processData = function __processData () {
2401
+ var i, data = this.rawData;
2402
+ for (i = 0; i < data.length; i++) {
2403
+ data[i][1] = toDate(data[i][1]);
2404
+ data[i][2] = toDate(data[i][2]);
2405
+ }
2406
+ return data;
2407
+ };
2408
+
2409
+ Timeline.prototype.__chartName = function __chartName () {
2410
+ return "Timeline";
2411
+ };
2412
+
2413
+ return Timeline;
2414
+ }(Chart));
2415
+
2416
+ var Chartkick = {
2417
+ LineChart: LineChart,
2418
+ PieChart: PieChart,
2419
+ ColumnChart: ColumnChart,
2420
+ BarChart: BarChart,
2421
+ AreaChart: AreaChart,
2422
+ GeoChart: GeoChart,
2423
+ ScatterChart: ScatterChart,
2424
+ BubbleChart: BubbleChart,
2425
+ Timeline: Timeline,
1668
2426
  charts: {},
1669
2427
  configure: function (options) {
1670
2428
  for (var key in options) {
@@ -1673,6 +2431,9 @@
1673
2431
  }
1674
2432
  }
1675
2433
  },
2434
+ setDefaultOptions: function (opts) {
2435
+ Chartkick.options = opts;
2436
+ },
1676
2437
  eachChart: function (callback) {
1677
2438
  for (var chartId in Chartkick.charts) {
1678
2439
  if (Chartkick.charts.hasOwnProperty(chartId)) {
@@ -1680,14 +2441,24 @@
1680
2441
  }
1681
2442
  }
1682
2443
  },
2444
+ config: config,
1683
2445
  options: {},
1684
2446
  adapters: adapters,
1685
- createChart: createChart
2447
+ addAdapter: addAdapter,
2448
+ use: function(adapter) {
2449
+ addAdapter(adapter);
2450
+ return Chartkick;
2451
+ }
1686
2452
  };
1687
2453
 
1688
- if (typeof module === "object" && typeof module.exports === "object") {
1689
- module.exports = Chartkick;
1690
- } else {
2454
+ // not ideal, but allows for simpler integration
2455
+ if (typeof window !== "undefined" && !window.Chartkick) {
1691
2456
  window.Chartkick = Chartkick;
1692
2457
  }
1693
- }(window));
2458
+
2459
+ // backwards compatibility for esm require
2460
+ Chartkick.default = Chartkick;
2461
+
2462
+ return Chartkick;
2463
+
2464
+ })));