pghero 1.6.2 → 1.6.3
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of pghero might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +5 -11
- data/app/assets/javascripts/pghero/chartkick.js +511 -152
- data/app/assets/stylesheets/pghero/application.css +11 -0
- data/app/controllers/pg_hero/home_controller.rb +3 -2
- data/app/views/pg_hero/home/_connections_table.html.erb +0 -7
- data/app/views/pg_hero/home/_live_queries_table.html.erb +1 -2
- data/app/views/pg_hero/home/connections.html.erb +29 -1
- data/app/views/pg_hero/home/explain.html.erb +2 -0
- data/app/views/pg_hero/home/index.html.erb +55 -1
- data/app/views/pg_hero/home/live_queries.html.erb +3 -1
- data/app/views/pg_hero/home/system.html.erb +16 -4
- data/guides/Rails.md +2 -3
- data/lib/generators/pghero/config_generator.rb +13 -0
- data/lib/generators/pghero/templates/config.yml +23 -0
- data/lib/pghero.rb +5 -3
- data/lib/pghero/database.rb +1 -1
- data/lib/pghero/methods/explain.rb +4 -1
- data/lib/pghero/methods/queries.rb +1 -5
- data/lib/pghero/methods/query_stats.rb +7 -0
- data/lib/pghero/version.rb +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1584095de5f97c95ab55a592deb44aa7eea06e35
|
4
|
+
data.tar.gz: 356b2efd8d8996b4e45378d9a840772413cb688e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2756d1a94611279615cd3362311cd7cf3aee45a610323137b902eca674a6ed7176ebcdfd8a96c7a92392fb48fceb0464f37c5cc21583343eb1aee75156300843
|
7
|
+
data.tar.gz: ea0b4eb73f5cb3ca170808e75021c808bd61d0ae5be36e99e89c86af8fd3f913236eaf87aabc8fc8afe61f10e7407599356ed9163b0e50d7b16d2d172d8561aa
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
## 1.6.3
|
2
|
+
|
3
|
+
- Added 10 second timeout for explain
|
4
|
+
- No longer show autovacuum in long running queries
|
5
|
+
- Added charts for connections
|
6
|
+
- Added new config format
|
7
|
+
- Removed Chartkick gem dependency for charts
|
8
|
+
- Fixed error when primary database is not PostgreSQL
|
9
|
+
|
1
10
|
## 1.6.2
|
2
11
|
|
3
12
|
- Suggest GiST over GIN for `LIKE` queries again (seeing better performance)
|
data/README.md
CHANGED
@@ -10,19 +10,13 @@ A performance dashboard for Postgres - health checks, suggested indexes, and mor
|
|
10
10
|
|
11
11
|
## Installation
|
12
12
|
|
13
|
-
PgHero
|
13
|
+
PgHero is available as a Rails engine, Linux package, and Docker image.
|
14
14
|
|
15
|
-
|
16
|
-
- [Docker](guides/Docker.md)
|
17
|
-
- [Heroku](guides/Heroku.md)
|
18
|
-
- [Rails](guides/Rails.md)
|
19
|
-
|
20
|
-
## Related Projects
|
15
|
+
Select your preferred method of installation to get started.
|
21
16
|
|
22
|
-
|
23
|
-
|
24
|
-
- [
|
25
|
-
- [pgslice](https://github.com/ankane/pgslice) - Postgres partitioning as easy as pie
|
17
|
+
- [Rails](guides/Rails.md)
|
18
|
+
- [Linux](guides/Linux.md)
|
19
|
+
- [Docker](guides/Docker.md)
|
26
20
|
|
27
21
|
## Credits
|
28
22
|
|
@@ -1,8 +1,8 @@
|
|
1
1
|
/*
|
2
2
|
* Chartkick.js
|
3
|
-
* Create beautiful
|
3
|
+
* Create beautiful charts with one line of JavaScript
|
4
4
|
* https://github.com/ankane/chartkick.js
|
5
|
-
* v2.
|
5
|
+
* v2.2.2
|
6
6
|
* MIT License
|
7
7
|
*/
|
8
8
|
|
@@ -15,6 +15,7 @@
|
|
15
15
|
var Chartkick, ISO8601_PATTERN, DECIMAL_SEPARATOR, adapters = [];
|
16
16
|
var DATE_PATTERN = /^(\d\d\d\d)(\-)?(\d\d)(\-)?(\d\d)$/i;
|
17
17
|
var GoogleChartsAdapter, HighchartsAdapter, ChartjsAdapter;
|
18
|
+
var pendingRequests = [], runningRequests = 0, maxRequests = 4;
|
18
19
|
|
19
20
|
// helpers
|
20
21
|
|
@@ -104,15 +105,18 @@
|
|
104
105
|
return false;
|
105
106
|
}
|
106
107
|
|
107
|
-
function jsOptionsFunc(defaultOptions, hideLegend, setMin, setMax, setStacked, setXtitle, setYtitle) {
|
108
|
-
return function (
|
108
|
+
function jsOptionsFunc(defaultOptions, hideLegend, setTitle, setMin, setMax, setStacked, setXtitle, setYtitle) {
|
109
|
+
return function (chart, opts, chartOptions) {
|
110
|
+
var series = chart.data;
|
109
111
|
var options = merge({}, defaultOptions);
|
110
112
|
options = merge(options, chartOptions || {});
|
111
113
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
114
|
+
if (chart.hideLegend || "legend" in opts) {
|
115
|
+
hideLegend(options, opts.legend, chart.hideLegend);
|
116
|
+
}
|
117
|
+
|
118
|
+
if (opts.title) {
|
119
|
+
setTitle(options, opts.title);
|
116
120
|
}
|
117
121
|
|
118
122
|
// min
|
@@ -163,6 +167,27 @@
|
|
163
167
|
element.style.color = "#ff0000";
|
164
168
|
}
|
165
169
|
|
170
|
+
function pushRequest(element, url, success) {
|
171
|
+
pendingRequests.push([element, url, success]);
|
172
|
+
runNext();
|
173
|
+
}
|
174
|
+
|
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
|
+
}
|
184
|
+
}
|
185
|
+
|
186
|
+
function requestComplete() {
|
187
|
+
runningRequests--;
|
188
|
+
runNext();
|
189
|
+
}
|
190
|
+
|
166
191
|
function getJSON(element, url, success) {
|
167
192
|
ajaxCall(url, success, function (jqXHR, textStatus, errorThrown) {
|
168
193
|
var message = (typeof errorThrown === "string") ? errorThrown : errorThrown.message;
|
@@ -178,13 +203,15 @@
|
|
178
203
|
dataType: "json",
|
179
204
|
url: url,
|
180
205
|
success: success,
|
181
|
-
error: error
|
206
|
+
error: error,
|
207
|
+
complete: requestComplete
|
182
208
|
});
|
183
209
|
} else {
|
184
210
|
var xhr = new XMLHttpRequest();
|
185
211
|
xhr.open("GET", url, true);
|
186
212
|
xhr.setRequestHeader("Content-Type", "application/json");
|
187
213
|
xhr.onload = function () {
|
214
|
+
requestComplete();
|
188
215
|
if (xhr.status === 200) {
|
189
216
|
success(JSON.parse(xhr.responseText), xhr.statusText, xhr);
|
190
217
|
} else {
|
@@ -204,18 +231,79 @@
|
|
204
231
|
}
|
205
232
|
}
|
206
233
|
|
207
|
-
function fetchDataSource(chart, callback) {
|
208
|
-
if (typeof
|
209
|
-
|
210
|
-
chart.
|
234
|
+
function fetchDataSource(chart, callback, dataSource) {
|
235
|
+
if (typeof dataSource === "string") {
|
236
|
+
pushRequest(chart.element, dataSource, function (data, textStatus, jqXHR) {
|
237
|
+
chart.rawData = data;
|
211
238
|
errorCatcher(chart, callback);
|
212
239
|
});
|
213
240
|
} else {
|
214
|
-
chart.
|
241
|
+
chart.rawData = dataSource;
|
215
242
|
errorCatcher(chart, callback);
|
216
243
|
}
|
217
244
|
}
|
218
245
|
|
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";
|
264
|
+
|
265
|
+
chart.downloadAttached = true;
|
266
|
+
|
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);
|
274
|
+
}
|
275
|
+
});
|
276
|
+
|
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);
|
283
|
+
}
|
284
|
+
}
|
285
|
+
});
|
286
|
+
}
|
287
|
+
|
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
|
+
});
|
297
|
+
}
|
298
|
+
}
|
299
|
+
|
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
|
+
}
|
306
|
+
|
219
307
|
// type conversions
|
220
308
|
|
221
309
|
function toStr(n) {
|
@@ -263,6 +351,10 @@
|
|
263
351
|
return a[0].getTime() - b[0].getTime();
|
264
352
|
}
|
265
353
|
|
354
|
+
function sortByNumberSeries(a, b) {
|
355
|
+
return a[0] - b[0];
|
356
|
+
}
|
357
|
+
|
266
358
|
function sortByNumber(a, b) {
|
267
359
|
return a - b;
|
268
360
|
}
|
@@ -318,8 +410,25 @@
|
|
318
410
|
}
|
319
411
|
};
|
320
412
|
|
321
|
-
var hideLegend = function (options) {
|
322
|
-
|
413
|
+
var hideLegend = function (options, legend, hideLegend) {
|
414
|
+
if (legend !== undefined) {
|
415
|
+
options.legend.enabled = !!legend;
|
416
|
+
if (legend && legend !== true) {
|
417
|
+
if (legend === "top" || legend === "bottom") {
|
418
|
+
options.legend.verticalAlign = legend;
|
419
|
+
} else {
|
420
|
+
options.legend.layout = "vertical";
|
421
|
+
options.legend.verticalAlign = "middle";
|
422
|
+
options.legend.align = legend;
|
423
|
+
}
|
424
|
+
}
|
425
|
+
} else if (hideLegend) {
|
426
|
+
options.legend.enabled = false;
|
427
|
+
}
|
428
|
+
};
|
429
|
+
|
430
|
+
var setTitle = function (options, title) {
|
431
|
+
options.title.text = title;
|
323
432
|
};
|
324
433
|
|
325
434
|
var setMin = function (options, min) {
|
@@ -342,7 +451,7 @@
|
|
342
451
|
options.yAxis.title.text = title;
|
343
452
|
};
|
344
453
|
|
345
|
-
var jsOptions = jsOptionsFunc(defaultOptions, hideLegend, setMin, setMax, setStacked, setXtitle, setYtitle);
|
454
|
+
var jsOptions = jsOptionsFunc(defaultOptions, hideLegend, setTitle, setMin, setMax, setStacked, setXtitle, setYtitle);
|
346
455
|
|
347
456
|
this.renderLineChart = function (chart, chartType) {
|
348
457
|
chartType = chartType || "spline";
|
@@ -353,6 +462,9 @@
|
|
353
462
|
areaspline: {
|
354
463
|
stacking: "normal"
|
355
464
|
},
|
465
|
+
area: {
|
466
|
+
stacking: "normal"
|
467
|
+
},
|
356
468
|
series: {
|
357
469
|
marker: {
|
358
470
|
enabled: false
|
@@ -361,8 +473,17 @@
|
|
361
473
|
}
|
362
474
|
};
|
363
475
|
}
|
364
|
-
|
365
|
-
|
476
|
+
|
477
|
+
if (chart.options.curve === false) {
|
478
|
+
if (chartType === "areaspline") {
|
479
|
+
chartType = "area";
|
480
|
+
} else if (chartType === "spline") {
|
481
|
+
chartType = "line";
|
482
|
+
}
|
483
|
+
}
|
484
|
+
|
485
|
+
var options = jsOptions(chart, chart.options, chartOptions), data, i, j;
|
486
|
+
options.xAxis.type = chart.discrete ? "category" : "datetime";
|
366
487
|
if (!options.chart.type) {
|
367
488
|
options.chart.type = chartType;
|
368
489
|
}
|
@@ -371,45 +492,61 @@
|
|
371
492
|
var series = chart.data;
|
372
493
|
for (i = 0; i < series.length; i++) {
|
373
494
|
data = series[i].data;
|
374
|
-
if (!chart.
|
495
|
+
if (!chart.discrete) {
|
375
496
|
for (j = 0; j < data.length; j++) {
|
376
497
|
data[j][0] = data[j][0].getTime();
|
377
498
|
}
|
378
499
|
}
|
379
500
|
series[i].marker = {symbol: "circle"};
|
501
|
+
if (chart.options.points === false) {
|
502
|
+
series[i].marker.enabled = false;
|
503
|
+
}
|
380
504
|
}
|
381
505
|
options.series = series;
|
382
|
-
new Highcharts.Chart(options);
|
506
|
+
chart.chart = new Highcharts.Chart(options);
|
383
507
|
};
|
384
508
|
|
385
509
|
this.renderScatterChart = function (chart) {
|
386
510
|
var chartOptions = {};
|
387
|
-
var options = jsOptions(chart
|
511
|
+
var options = jsOptions(chart, chart.options, chartOptions);
|
388
512
|
options.chart.type = "scatter";
|
389
513
|
options.chart.renderTo = chart.element.id;
|
390
514
|
options.series = chart.data;
|
391
|
-
new Highcharts.Chart(options);
|
515
|
+
chart.chart = new Highcharts.Chart(options);
|
392
516
|
};
|
393
517
|
|
394
518
|
this.renderPieChart = function (chart) {
|
395
|
-
var chartOptions = {};
|
519
|
+
var chartOptions = merge(defaultOptions, {});
|
520
|
+
|
396
521
|
if (chart.options.colors) {
|
397
522
|
chartOptions.colors = chart.options.colors;
|
398
523
|
}
|
399
|
-
|
524
|
+
if (chart.options.donut) {
|
525
|
+
chartOptions.plotOptions = {pie: {innerSize: "50%"}};
|
526
|
+
}
|
527
|
+
|
528
|
+
if ("legend" in chart.options) {
|
529
|
+
hideLegend(chartOptions, chart.options.legend);
|
530
|
+
}
|
531
|
+
|
532
|
+
if (chart.options.title) {
|
533
|
+
setTitle(chartOptions, chart.options.title);
|
534
|
+
}
|
535
|
+
|
536
|
+
var options = merge(chartOptions, chart.options.library || {});
|
400
537
|
options.chart.renderTo = chart.element.id;
|
401
538
|
options.series = [{
|
402
539
|
type: "pie",
|
403
540
|
name: chart.options.label || "Value",
|
404
541
|
data: chart.data
|
405
542
|
}];
|
406
|
-
new Highcharts.Chart(options);
|
543
|
+
chart.chart = new Highcharts.Chart(options);
|
407
544
|
};
|
408
545
|
|
409
546
|
this.renderColumnChart = function (chart, chartType) {
|
410
547
|
chartType = chartType || "column";
|
411
548
|
var series = chart.data;
|
412
|
-
var options = jsOptions(
|
549
|
+
var options = jsOptions(chart, chart.options), i, j, s, d, rows = [], categories = [];
|
413
550
|
options.chart.type = chartType;
|
414
551
|
options.chart.renderTo = chart.element.id;
|
415
552
|
|
@@ -420,17 +557,16 @@
|
|
420
557
|
d = s.data[j];
|
421
558
|
if (!rows[d[0]]) {
|
422
559
|
rows[d[0]] = new Array(series.length);
|
560
|
+
categories.push(d[0]);
|
423
561
|
}
|
424
562
|
rows[d[0]][i] = d[1];
|
425
563
|
}
|
426
564
|
}
|
427
565
|
|
428
|
-
|
429
|
-
|
430
|
-
if (rows.hasOwnProperty(i)) {
|
431
|
-
categories.push(i);
|
432
|
-
}
|
566
|
+
if (chart.options.xtype === "number") {
|
567
|
+
categories.sort(sortByNumber);
|
433
568
|
}
|
569
|
+
|
434
570
|
options.xAxis.categories = categories;
|
435
571
|
|
436
572
|
var newSeries = [];
|
@@ -447,7 +583,7 @@
|
|
447
583
|
}
|
448
584
|
options.series = newSeries;
|
449
585
|
|
450
|
-
new Highcharts.Chart(options);
|
586
|
+
chart.chart = new Highcharts.Chart(options);
|
451
587
|
};
|
452
588
|
|
453
589
|
var self = this;
|
@@ -557,8 +693,25 @@
|
|
557
693
|
}
|
558
694
|
};
|
559
695
|
|
560
|
-
var hideLegend = function (options) {
|
561
|
-
|
696
|
+
var hideLegend = function (options, legend, hideLegend) {
|
697
|
+
if (legend !== undefined) {
|
698
|
+
var position;
|
699
|
+
if (!legend) {
|
700
|
+
position = "none";
|
701
|
+
} else if (legend === true) {
|
702
|
+
position = "right";
|
703
|
+
} else {
|
704
|
+
position = legend;
|
705
|
+
}
|
706
|
+
options.legend.position = position;
|
707
|
+
} else if (hideLegend) {
|
708
|
+
options.legend.position = "none";
|
709
|
+
}
|
710
|
+
};
|
711
|
+
|
712
|
+
var setTitle = function (options, title) {
|
713
|
+
options.title = title;
|
714
|
+
options.titleTextStyle = {color: "#333", fontSize: "20px"};
|
562
715
|
};
|
563
716
|
|
564
717
|
var setMin = function (options, min) {
|
@@ -591,11 +744,11 @@
|
|
591
744
|
options.vAxis.titleTextStyle.italic = false;
|
592
745
|
};
|
593
746
|
|
594
|
-
var jsOptions = jsOptionsFunc(defaultOptions, hideLegend, setMin, setMax, setStacked, setXtitle, setYtitle);
|
747
|
+
var jsOptions = jsOptionsFunc(defaultOptions, hideLegend, setTitle, setMin, setMax, setStacked, setXtitle, setYtitle);
|
595
748
|
|
596
749
|
// cant use object as key
|
597
|
-
var createDataTable = function (series, columnType) {
|
598
|
-
var i, j, s, d, key, rows = [];
|
750
|
+
var createDataTable = function (series, columnType, xtype) {
|
751
|
+
var i, j, s, d, key, rows = [], sortedLabels = [];
|
599
752
|
for (i = 0; i < series.length; i++) {
|
600
753
|
s = series[i];
|
601
754
|
|
@@ -604,6 +757,7 @@
|
|
604
757
|
key = (columnType === "datetime") ? d[0].getTime() : d[0];
|
605
758
|
if (!rows[key]) {
|
606
759
|
rows[key] = new Array(series.length);
|
760
|
+
sortedLabels.push(key);
|
607
761
|
}
|
608
762
|
rows[key][i] = toFloat(d[1]);
|
609
763
|
}
|
@@ -612,21 +766,30 @@
|
|
612
766
|
var rows2 = [];
|
613
767
|
var day = true;
|
614
768
|
var value;
|
615
|
-
for (
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
}
|
625
|
-
rows2.push([value].concat(rows[i]));
|
769
|
+
for (var j = 0; j < sortedLabels.length; j++) {
|
770
|
+
var i = sortedLabels[j];
|
771
|
+
if (columnType === "datetime") {
|
772
|
+
value = new Date(toFloat(i));
|
773
|
+
day = day && isDay(value);
|
774
|
+
} else if (columnType === "number") {
|
775
|
+
value = toFloat(i);
|
776
|
+
} else {
|
777
|
+
value = i;
|
626
778
|
}
|
779
|
+
rows2.push([value].concat(rows[i]));
|
627
780
|
}
|
628
781
|
if (columnType === "datetime") {
|
629
782
|
rows2.sort(sortByTime);
|
783
|
+
} else if (columnType === "number") {
|
784
|
+
rows2.sort(sortByNumberSeries);
|
785
|
+
}
|
786
|
+
|
787
|
+
if (xtype === "number") {
|
788
|
+
rows2.sort(sortByNumberSeries);
|
789
|
+
|
790
|
+
for (var i = 0; i < rows2.length; i++) {
|
791
|
+
rows2[i][0] = toStr(rows2[i][0]);
|
792
|
+
}
|
630
793
|
}
|
631
794
|
|
632
795
|
// create datatable
|
@@ -652,8 +815,22 @@
|
|
652
815
|
|
653
816
|
this.renderLineChart = function (chart) {
|
654
817
|
waitForLoaded(function () {
|
655
|
-
var
|
656
|
-
|
818
|
+
var chartOptions = {};
|
819
|
+
|
820
|
+
if (chart.options.curve === false) {
|
821
|
+
chartOptions.curveType = "none";
|
822
|
+
}
|
823
|
+
|
824
|
+
if (chart.options.points === false) {
|
825
|
+
chartOptions.pointSize = 0;
|
826
|
+
}
|
827
|
+
|
828
|
+
var options = jsOptions(chart, chart.options, chartOptions);
|
829
|
+
var columnType = chart.discrete ? "string" : "datetime";
|
830
|
+
if (chart.options.xtype === "number") {
|
831
|
+
columnType = "number";
|
832
|
+
}
|
833
|
+
var data = createDataTable(chart.data, columnType);
|
657
834
|
chart.chart = new google.visualization.LineChart(chart.element);
|
658
835
|
resize(function () {
|
659
836
|
chart.chart.draw(data, options);
|
@@ -667,11 +844,21 @@
|
|
667
844
|
chartArea: {
|
668
845
|
top: "10%",
|
669
846
|
height: "80%"
|
670
|
-
}
|
847
|
+
},
|
848
|
+
legend: {}
|
671
849
|
};
|
672
850
|
if (chart.options.colors) {
|
673
851
|
chartOptions.colors = chart.options.colors;
|
674
852
|
}
|
853
|
+
if (chart.options.donut) {
|
854
|
+
chartOptions.pieHole = 0.5;
|
855
|
+
}
|
856
|
+
if ("legend" in chart.options) {
|
857
|
+
hideLegend(chartOptions, chart.options.legend);
|
858
|
+
}
|
859
|
+
if (chart.options.title) {
|
860
|
+
setTitle(chartOptions, chart.options.title);
|
861
|
+
}
|
675
862
|
var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {});
|
676
863
|
|
677
864
|
var data = new google.visualization.DataTable();
|
@@ -688,8 +875,8 @@
|
|
688
875
|
|
689
876
|
this.renderColumnChart = function (chart) {
|
690
877
|
waitForLoaded(function () {
|
691
|
-
var options = jsOptions(chart
|
692
|
-
var data = createDataTable(chart.data, "string");
|
878
|
+
var options = jsOptions(chart, chart.options);
|
879
|
+
var data = createDataTable(chart.data, "string", chart.options.xtype);
|
693
880
|
chart.chart = new google.visualization.ColumnChart(chart.element);
|
694
881
|
resize(function () {
|
695
882
|
chart.chart.draw(data, options);
|
@@ -706,8 +893,8 @@
|
|
706
893
|
}
|
707
894
|
}
|
708
895
|
};
|
709
|
-
var options = jsOptionsFunc(defaultOptions, hideLegend, setBarMin, setBarMax, setStacked, setXtitle, setYtitle)(chart
|
710
|
-
var data = createDataTable(chart.data, "string");
|
896
|
+
var options = jsOptionsFunc(defaultOptions, hideLegend, setTitle, setBarMin, setBarMax, setStacked, setXtitle, setYtitle)(chart, chart.options, chartOptions);
|
897
|
+
var data = createDataTable(chart.data, "string", chart.options.xtype);
|
711
898
|
chart.chart = new google.visualization.BarChart(chart.element);
|
712
899
|
resize(function () {
|
713
900
|
chart.chart.draw(data, options);
|
@@ -722,8 +909,13 @@
|
|
722
909
|
pointSize: 0,
|
723
910
|
areaOpacity: 0.5
|
724
911
|
};
|
725
|
-
|
726
|
-
var
|
912
|
+
|
913
|
+
var options = jsOptions(chart, chart.options, chartOptions);
|
914
|
+
var columnType = chart.discrete ? "string" : "datetime";
|
915
|
+
if (chart.options.xtype === "number") {
|
916
|
+
columnType = "number";
|
917
|
+
}
|
918
|
+
var data = createDataTable(chart.data, columnType);
|
727
919
|
chart.chart = new google.visualization.AreaChart(chart.element);
|
728
920
|
resize(function () {
|
729
921
|
chart.chart.draw(data, options);
|
@@ -756,8 +948,25 @@
|
|
756
948
|
this.renderScatterChart = function (chart) {
|
757
949
|
waitForLoaded(function () {
|
758
950
|
var chartOptions = {};
|
759
|
-
var options = jsOptions(chart
|
760
|
-
|
951
|
+
var options = jsOptions(chart, chart.options, chartOptions);
|
952
|
+
|
953
|
+
var series = chart.data, rows2 = [], i, j, data, d;
|
954
|
+
for (i = 0; i < series.length; i++) {
|
955
|
+
d = series[i].data;
|
956
|
+
for (j = 0; j < d.length; j++) {
|
957
|
+
var row = new Array(series.length + 1);
|
958
|
+
row[0] = d[j][0];
|
959
|
+
row[i + 1] = d[j][1];
|
960
|
+
rows2.push(row);
|
961
|
+
}
|
962
|
+
}
|
963
|
+
|
964
|
+
var data = new google.visualization.DataTable();
|
965
|
+
data.addColumn("number", "");
|
966
|
+
for (i = 0; i < series.length; i++) {
|
967
|
+
data.addColumn("number", series[i].name);
|
968
|
+
}
|
969
|
+
data.addRows(rows2);
|
761
970
|
|
762
971
|
chart.chart = new google.visualization.ScatterChart(chart.element);
|
763
972
|
resize(function () {
|
@@ -803,7 +1012,12 @@
|
|
803
1012
|
|
804
1013
|
var baseOptions = {
|
805
1014
|
maintainAspectRatio: false,
|
806
|
-
animation: false
|
1015
|
+
animation: false,
|
1016
|
+
tooltips: {
|
1017
|
+
displayColors: false
|
1018
|
+
},
|
1019
|
+
legend: {},
|
1020
|
+
title: {fontSize: 20, fontColor: "#333"}
|
807
1021
|
};
|
808
1022
|
|
809
1023
|
var defaultOptions = {
|
@@ -834,8 +1048,7 @@
|
|
834
1048
|
ticks: {}
|
835
1049
|
}
|
836
1050
|
]
|
837
|
-
}
|
838
|
-
legend: {}
|
1051
|
+
}
|
839
1052
|
};
|
840
1053
|
|
841
1054
|
// http://there4.io/2012/05/02/google-chart-color-list/
|
@@ -845,28 +1058,40 @@
|
|
845
1058
|
"#6633CC", "#E67300", "#8B0707", "#329262", "#5574A6", "#3B3EAC"
|
846
1059
|
];
|
847
1060
|
|
848
|
-
var hideLegend = function (options) {
|
849
|
-
|
1061
|
+
var hideLegend = function (options, legend, hideLegend) {
|
1062
|
+
if (legend !== undefined) {
|
1063
|
+
options.legend.display = !!legend;
|
1064
|
+
if (legend && legend !== true) {
|
1065
|
+
options.legend.position = legend;
|
1066
|
+
}
|
1067
|
+
} else if (hideLegend) {
|
1068
|
+
options.legend.display = false;
|
1069
|
+
}
|
1070
|
+
};
|
1071
|
+
|
1072
|
+
var setTitle = function (options, title) {
|
1073
|
+
options.title.display = true;
|
1074
|
+
options.title.text = title;
|
850
1075
|
};
|
851
1076
|
|
852
1077
|
var setMin = function (options, min) {
|
853
1078
|
if (min !== null) {
|
854
|
-
options.scales.yAxes[0].ticks.min = min;
|
1079
|
+
options.scales.yAxes[0].ticks.min = toFloat(min);
|
855
1080
|
}
|
856
1081
|
};
|
857
1082
|
|
858
1083
|
var setMax = function (options, max) {
|
859
|
-
options.scales.yAxes[0].ticks.max = max;
|
1084
|
+
options.scales.yAxes[0].ticks.max = toFloat(max);
|
860
1085
|
};
|
861
1086
|
|
862
1087
|
var setBarMin = function (options, min) {
|
863
1088
|
if (min !== null) {
|
864
|
-
options.scales.xAxes[0].ticks.min = min;
|
1089
|
+
options.scales.xAxes[0].ticks.min = toFloat(min);
|
865
1090
|
}
|
866
1091
|
};
|
867
1092
|
|
868
1093
|
var setBarMax = function (options, max) {
|
869
|
-
options.scales.xAxes[0].ticks.max = max;
|
1094
|
+
options.scales.xAxes[0].ticks.max = toFloat(max);
|
870
1095
|
};
|
871
1096
|
|
872
1097
|
var setStacked = function (options, stacked) {
|
@@ -885,9 +1110,13 @@
|
|
885
1110
|
};
|
886
1111
|
|
887
1112
|
var drawChart = function(chart, type, data, options) {
|
888
|
-
chart.
|
889
|
-
|
1113
|
+
if (chart.chart) {
|
1114
|
+
chart.chart.destroy();
|
1115
|
+
} else {
|
1116
|
+
chart.element.innerHTML = "<canvas></canvas>";
|
1117
|
+
}
|
890
1118
|
|
1119
|
+
var ctx = chart.element.getElementsByTagName("CANVAS")[0];
|
891
1120
|
chart.chart = new Chart(ctx, {
|
892
1121
|
type: type,
|
893
1122
|
data: data,
|
@@ -916,7 +1145,7 @@
|
|
916
1145
|
};
|
917
1146
|
};
|
918
1147
|
|
919
|
-
var jsOptions = jsOptionsFunc(merge(baseOptions, defaultOptions), hideLegend, setMin, setMax, setStacked, setXtitle, setYtitle);
|
1148
|
+
var jsOptions = jsOptionsFunc(merge(baseOptions, defaultOptions), hideLegend, setTitle, setMin, setMax, setStacked, setXtitle, setYtitle);
|
920
1149
|
|
921
1150
|
var createDataTable = function (chart, options, chartType) {
|
922
1151
|
var datasets = [];
|
@@ -931,7 +1160,7 @@
|
|
931
1160
|
var year = true;
|
932
1161
|
var hour = true;
|
933
1162
|
var minute = true;
|
934
|
-
var detectType = (chartType === "line" || chartType === "area") && !chart.
|
1163
|
+
var detectType = (chartType === "line" || chartType === "area") && !chart.discrete;
|
935
1164
|
|
936
1165
|
var series = chart.data;
|
937
1166
|
|
@@ -954,7 +1183,7 @@
|
|
954
1183
|
}
|
955
1184
|
}
|
956
1185
|
|
957
|
-
if (detectType) {
|
1186
|
+
if (detectType || chart.options.xtype === "number") {
|
958
1187
|
sortedLabels.sort(sortByNumber);
|
959
1188
|
}
|
960
1189
|
|
@@ -984,25 +1213,36 @@
|
|
984
1213
|
}
|
985
1214
|
labels.push(value);
|
986
1215
|
for (j = 0; j < series.length; j++) {
|
987
|
-
|
1216
|
+
// Chart.js doesn't like undefined
|
1217
|
+
rows2[j].push(rows[i][j] === undefined ? null : rows[i][j]);
|
988
1218
|
}
|
989
1219
|
}
|
990
1220
|
|
991
1221
|
for (i = 0; i < series.length; i++) {
|
992
1222
|
s = series[i];
|
993
1223
|
|
994
|
-
var
|
1224
|
+
var color = s.color || colors[i];
|
1225
|
+
var backgroundColor = chartType !== "line" ? addOpacity(color, 0.5) : color;
|
995
1226
|
|
996
1227
|
var dataset = {
|
997
1228
|
label: s.name,
|
998
1229
|
data: rows2[i],
|
999
1230
|
fill: chartType === "area",
|
1000
|
-
borderColor:
|
1231
|
+
borderColor: color,
|
1001
1232
|
backgroundColor: backgroundColor,
|
1002
|
-
pointBackgroundColor:
|
1233
|
+
pointBackgroundColor: color,
|
1003
1234
|
borderWidth: 2
|
1004
1235
|
};
|
1005
1236
|
|
1237
|
+
if (chart.options.curve === false) {
|
1238
|
+
dataset.lineTension = 0;
|
1239
|
+
}
|
1240
|
+
|
1241
|
+
if (chart.options.points === false) {
|
1242
|
+
dataset.pointRadius = 0;
|
1243
|
+
dataset.pointHitRadius = 5;
|
1244
|
+
}
|
1245
|
+
|
1006
1246
|
datasets.push(merge(dataset, s.library || {}));
|
1007
1247
|
}
|
1008
1248
|
|
@@ -1071,27 +1311,44 @@
|
|
1071
1311
|
};
|
1072
1312
|
|
1073
1313
|
this.renderLineChart = function (chart, chartType) {
|
1074
|
-
|
1314
|
+
if (chart.options.xtype === "number") {
|
1315
|
+
return self.renderScatterChart(chart, chartType, true);
|
1316
|
+
}
|
1317
|
+
|
1318
|
+
var chartOptions = {};
|
1075
1319
|
if (chartType === "area") {
|
1076
1320
|
// TODO fix area stacked
|
1077
|
-
//
|
1321
|
+
// chartOptions.stacked = true;
|
1078
1322
|
}
|
1079
1323
|
// fix for https://github.com/chartjs/Chart.js/issues/2441
|
1080
1324
|
if (!chart.options.max && allZeros(chart.data)) {
|
1081
|
-
|
1325
|
+
chartOptions.max = 1;
|
1082
1326
|
}
|
1083
1327
|
|
1084
|
-
var options = jsOptions(chart
|
1328
|
+
var options = jsOptions(chart, merge(chartOptions, chart.options));
|
1085
1329
|
|
1086
1330
|
var data = createDataTable(chart, options, chartType || "line");
|
1087
1331
|
|
1088
|
-
options.scales.xAxes[0].type = chart.
|
1332
|
+
options.scales.xAxes[0].type = chart.discrete ? "category" : "time";
|
1089
1333
|
|
1090
1334
|
drawChart(chart, "line", data, options);
|
1091
1335
|
};
|
1092
1336
|
|
1093
1337
|
this.renderPieChart = function (chart) {
|
1094
|
-
var options = merge(
|
1338
|
+
var options = merge({}, baseOptions);
|
1339
|
+
if (chart.options.donut) {
|
1340
|
+
options.cutoutPercentage = 50;
|
1341
|
+
}
|
1342
|
+
|
1343
|
+
if ("legend" in chart.options) {
|
1344
|
+
hideLegend(options, chart.options.legend);
|
1345
|
+
}
|
1346
|
+
|
1347
|
+
if (chart.options.title) {
|
1348
|
+
setTitle(options, chart.options.title);
|
1349
|
+
}
|
1350
|
+
|
1351
|
+
options = merge(options, chart.options.library || {});
|
1095
1352
|
|
1096
1353
|
var labels = [];
|
1097
1354
|
var values = [];
|
@@ -1117,9 +1374,9 @@
|
|
1117
1374
|
this.renderColumnChart = function (chart, chartType) {
|
1118
1375
|
var options;
|
1119
1376
|
if (chartType === "bar") {
|
1120
|
-
options = jsOptionsFunc(merge(baseOptions, defaultOptions), hideLegend, setBarMin, setBarMax, setStacked, setXtitle, setYtitle)(chart
|
1377
|
+
options = jsOptionsFunc(merge(baseOptions, defaultOptions), hideLegend, setTitle, setBarMin, setBarMax, setStacked, setXtitle, setYtitle)(chart, chart.options);
|
1121
1378
|
} else {
|
1122
|
-
options = jsOptions(chart
|
1379
|
+
options = jsOptions(chart, chart.options);
|
1123
1380
|
}
|
1124
1381
|
var data = createDataTable(chart, options, "column");
|
1125
1382
|
setLabelSize(chart, data, options);
|
@@ -1136,8 +1393,10 @@
|
|
1136
1393
|
self.renderColumnChart(chart, "bar");
|
1137
1394
|
};
|
1138
1395
|
|
1139
|
-
this.renderScatterChart = function (chart) {
|
1140
|
-
|
1396
|
+
this.renderScatterChart = function (chart, chartType, lineChart) {
|
1397
|
+
chartType = chartType || "line";
|
1398
|
+
|
1399
|
+
var options = jsOptions(chart, chart.options);
|
1141
1400
|
|
1142
1401
|
var colors = chart.options.colors || defaultColors;
|
1143
1402
|
|
@@ -1147,28 +1406,44 @@
|
|
1147
1406
|
var s = series[i];
|
1148
1407
|
var d = [];
|
1149
1408
|
for (var j = 0; j < s.data.length; j++) {
|
1150
|
-
|
1409
|
+
var point = {
|
1151
1410
|
x: toFloat(s.data[j][0]),
|
1152
1411
|
y: toFloat(s.data[j][1])
|
1153
|
-
}
|
1412
|
+
};
|
1413
|
+
if (chartType === "bubble") {
|
1414
|
+
point.r = toFloat(s.data[j][2]);
|
1415
|
+
}
|
1416
|
+
d.push(point);
|
1154
1417
|
}
|
1155
1418
|
|
1419
|
+
var color = s.color || colors[i];
|
1420
|
+
var backgroundColor = chartType === "area" ? addOpacity(color, 0.5) : color;
|
1421
|
+
|
1156
1422
|
datasets.push({
|
1157
1423
|
label: s.name,
|
1158
|
-
showLine: false,
|
1424
|
+
showLine: lineChart || false,
|
1159
1425
|
data: d,
|
1160
|
-
borderColor:
|
1161
|
-
backgroundColor:
|
1162
|
-
pointBackgroundColor:
|
1426
|
+
borderColor: color,
|
1427
|
+
backgroundColor: backgroundColor,
|
1428
|
+
pointBackgroundColor: color,
|
1429
|
+
fill: chartType === "area"
|
1163
1430
|
})
|
1164
1431
|
}
|
1165
1432
|
|
1433
|
+
if (chartType === "area") {
|
1434
|
+
chartType = "line";
|
1435
|
+
}
|
1436
|
+
|
1166
1437
|
var data = {datasets: datasets};
|
1167
1438
|
|
1168
1439
|
options.scales.xAxes[0].type = "linear";
|
1169
1440
|
options.scales.xAxes[0].position = "bottom";
|
1170
1441
|
|
1171
|
-
drawChart(chart,
|
1442
|
+
drawChart(chart, chartType, data, options);
|
1443
|
+
};
|
1444
|
+
|
1445
|
+
this.renderBubbleChart = function (chart) {
|
1446
|
+
this.renderScatterChart(chart, "bubble");
|
1172
1447
|
};
|
1173
1448
|
};
|
1174
1449
|
|
@@ -1176,9 +1451,16 @@
|
|
1176
1451
|
}
|
1177
1452
|
}
|
1178
1453
|
|
1454
|
+
function renderChart(chartType, chart) {
|
1455
|
+
callAdapter(chartType, chart);
|
1456
|
+
if (chart.options.download && !chart.downloadAttached && chart.adapter === "chartjs") {
|
1457
|
+
addDownloadButton(chart);
|
1458
|
+
}
|
1459
|
+
}
|
1460
|
+
|
1179
1461
|
// TODO remove chartType if cross-browser way
|
1180
1462
|
// to get the name of the chart class
|
1181
|
-
function
|
1463
|
+
function callAdapter(chartType, chart) {
|
1182
1464
|
var i, adapter, fnName, adapterName;
|
1183
1465
|
fnName = "render" + chartType;
|
1184
1466
|
adapterName = chart.options.adapter;
|
@@ -1188,6 +1470,7 @@
|
|
1188
1470
|
for (i = 0; i < adapters.length; i++) {
|
1189
1471
|
adapter = adapters[i];
|
1190
1472
|
if ((!adapterName || adapterName === adapter.name) && isFunction(adapter[fnName])) {
|
1473
|
+
chart.adapter = adapter.name;
|
1191
1474
|
return adapter[fnName](chart);
|
1192
1475
|
}
|
1193
1476
|
}
|
@@ -1210,11 +1493,17 @@
|
|
1210
1493
|
var formatSeriesData = function (data, keyType) {
|
1211
1494
|
var r = [], key, j;
|
1212
1495
|
for (j = 0; j < data.length; j++) {
|
1213
|
-
|
1214
|
-
|
1496
|
+
if (keyType === "bubble") {
|
1497
|
+
r.push([toFloat(data[j][0]), toFloat(data[j][1]), toFloat(data[j][2])]);
|
1498
|
+
} else {
|
1499
|
+
key = toFormattedKey(data[j][0], keyType);
|
1500
|
+
r.push([key, toFloat(data[j][1])]);
|
1501
|
+
}
|
1215
1502
|
}
|
1216
1503
|
if (keyType === "datetime") {
|
1217
1504
|
r.sort(sortByTime);
|
1505
|
+
} else if (keyType === "number") {
|
1506
|
+
r.sort(sortByNumberSeries);
|
1218
1507
|
}
|
1219
1508
|
return r;
|
1220
1509
|
};
|
@@ -1273,22 +1562,30 @@
|
|
1273
1562
|
return false;
|
1274
1563
|
}
|
1275
1564
|
|
1276
|
-
function processSeries(
|
1565
|
+
function processSeries(chart, keyType) {
|
1277
1566
|
var i;
|
1278
1567
|
|
1568
|
+
var opts = chart.options;
|
1569
|
+
var series = chart.rawData;
|
1570
|
+
|
1279
1571
|
// see if one series or multiple
|
1280
1572
|
if (!isArray(series) || typeof series[0] !== "object" || isArray(series[0])) {
|
1281
1573
|
series = [{name: opts.label || "Value", data: series}];
|
1282
|
-
|
1574
|
+
chart.hideLegend = true;
|
1283
1575
|
} else {
|
1284
|
-
|
1576
|
+
chart.hideLegend = false;
|
1285
1577
|
}
|
1286
|
-
if ((opts.discrete === null || opts.discrete === undefined)) {
|
1287
|
-
|
1578
|
+
if ((opts.discrete === null || opts.discrete === undefined) && keyType !== "bubble" && keyType !== "number") {
|
1579
|
+
chart.discrete = detectDiscrete(series);
|
1580
|
+
} else {
|
1581
|
+
chart.discrete = opts.discrete;
|
1288
1582
|
}
|
1289
|
-
if (
|
1583
|
+
if (chart.discrete) {
|
1290
1584
|
keyType = "string";
|
1291
1585
|
}
|
1586
|
+
if (chart.options.xtype) {
|
1587
|
+
keyType = chart.options.xtype;
|
1588
|
+
}
|
1292
1589
|
|
1293
1590
|
// right format
|
1294
1591
|
for (i = 0; i < series.length; i++) {
|
@@ -1298,17 +1595,17 @@
|
|
1298
1595
|
return series;
|
1299
1596
|
}
|
1300
1597
|
|
1301
|
-
function processSimple(
|
1302
|
-
var perfectData = toArr(
|
1598
|
+
function processSimple(chart) {
|
1599
|
+
var perfectData = toArr(chart.rawData), i;
|
1303
1600
|
for (i = 0; i < perfectData.length; i++) {
|
1304
1601
|
perfectData[i] = [toStr(perfectData[i][0]), toFloat(perfectData[i][1])];
|
1305
1602
|
}
|
1306
1603
|
return perfectData;
|
1307
1604
|
}
|
1308
1605
|
|
1309
|
-
function processTime(
|
1606
|
+
function processTime(chart)
|
1310
1607
|
{
|
1311
|
-
var i;
|
1608
|
+
var i, data = chart.rawData;
|
1312
1609
|
for (i = 0; i < data.length; i++) {
|
1313
1610
|
data[i][1] = toDate(data[i][1]);
|
1314
1611
|
data[i][2] = toDate(data[i][2]);
|
@@ -1317,46 +1614,30 @@
|
|
1317
1614
|
}
|
1318
1615
|
|
1319
1616
|
function processLineData(chart) {
|
1320
|
-
|
1321
|
-
renderChart("LineChart", chart);
|
1617
|
+
return processSeries(chart, "datetime");
|
1322
1618
|
}
|
1323
1619
|
|
1324
1620
|
function processColumnData(chart) {
|
1325
|
-
|
1326
|
-
renderChart("ColumnChart", chart);
|
1327
|
-
}
|
1328
|
-
|
1329
|
-
function processPieData(chart) {
|
1330
|
-
chart.data = processSimple(chart.data);
|
1331
|
-
renderChart("PieChart", chart);
|
1621
|
+
return processSeries(chart, "string");
|
1332
1622
|
}
|
1333
1623
|
|
1334
1624
|
function processBarData(chart) {
|
1335
|
-
|
1336
|
-
renderChart("BarChart", chart);
|
1625
|
+
return processSeries(chart, "string");
|
1337
1626
|
}
|
1338
1627
|
|
1339
1628
|
function processAreaData(chart) {
|
1340
|
-
|
1341
|
-
renderChart("AreaChart", chart);
|
1342
|
-
}
|
1343
|
-
|
1344
|
-
function processGeoData(chart) {
|
1345
|
-
chart.data = processSimple(chart.data);
|
1346
|
-
renderChart("GeoChart", chart);
|
1629
|
+
return processSeries(chart, "datetime");
|
1347
1630
|
}
|
1348
1631
|
|
1349
1632
|
function processScatterData(chart) {
|
1350
|
-
|
1351
|
-
renderChart("ScatterChart", chart);
|
1633
|
+
return processSeries(chart, "number");
|
1352
1634
|
}
|
1353
1635
|
|
1354
|
-
function
|
1355
|
-
|
1356
|
-
renderChart("Timeline", chart);
|
1636
|
+
function processBubbleData(chart) {
|
1637
|
+
return processSeries(chart, "bubble");
|
1357
1638
|
}
|
1358
1639
|
|
1359
|
-
function
|
1640
|
+
function createChart(chartType, chart, element, dataSource, opts, processData) {
|
1360
1641
|
var elementId;
|
1361
1642
|
if (typeof element === "string") {
|
1362
1643
|
elementId = element;
|
@@ -1365,51 +1646,119 @@
|
|
1365
1646
|
throw new Error("No element with id " + elementId);
|
1366
1647
|
}
|
1367
1648
|
}
|
1649
|
+
|
1368
1650
|
chart.element = element;
|
1369
|
-
|
1651
|
+
opts = merge(Chartkick.options, opts || {});
|
1652
|
+
chart.options = opts;
|
1370
1653
|
chart.dataSource = dataSource;
|
1654
|
+
|
1655
|
+
if (!processData) {
|
1656
|
+
processData = function (chart) {
|
1657
|
+
return chart.rawData;
|
1658
|
+
}
|
1659
|
+
}
|
1660
|
+
|
1661
|
+
// getters
|
1371
1662
|
chart.getElement = function () {
|
1372
1663
|
return element;
|
1373
1664
|
};
|
1665
|
+
chart.getDataSource = function () {
|
1666
|
+
return chart.dataSource;
|
1667
|
+
};
|
1374
1668
|
chart.getData = function () {
|
1375
1669
|
return chart.data;
|
1376
1670
|
};
|
1377
1671
|
chart.getOptions = function () {
|
1378
|
-
return
|
1672
|
+
return chart.options;
|
1379
1673
|
};
|
1380
1674
|
chart.getChartObject = function () {
|
1381
1675
|
return chart.chart;
|
1382
1676
|
};
|
1677
|
+
chart.getAdapter = function () {
|
1678
|
+
return chart.adapter;
|
1679
|
+
};
|
1680
|
+
|
1681
|
+
var callback = function () {
|
1682
|
+
chart.data = processData(chart);
|
1683
|
+
renderChart(chartType, chart);
|
1684
|
+
};
|
1685
|
+
|
1686
|
+
// functions
|
1687
|
+
chart.updateData = function (dataSource, options) {
|
1688
|
+
chart.dataSource = dataSource;
|
1689
|
+
if (options) {
|
1690
|
+
chart.options = merge(Chartkick.options, options);
|
1691
|
+
}
|
1692
|
+
fetchDataSource(chart, callback, dataSource);
|
1693
|
+
};
|
1694
|
+
chart.setOptions = function (options) {
|
1695
|
+
chart.options = merge(Chartkick.options, options);
|
1696
|
+
chart.redraw();
|
1697
|
+
};
|
1698
|
+
chart.redraw = function() {
|
1699
|
+
fetchDataSource(chart, callback, chart.rawData);
|
1700
|
+
};
|
1701
|
+
chart.refreshData = function () {
|
1702
|
+
if (typeof dataSource === "string") {
|
1703
|
+
// prevent browser from caching
|
1704
|
+
var sep = dataSource.indexOf("?") === -1 ? "?" : "&";
|
1705
|
+
var url = dataSource + sep + "_=" + (new Date()).getTime();
|
1706
|
+
fetchDataSource(chart, callback, url);
|
1707
|
+
}
|
1708
|
+
};
|
1709
|
+
chart.stopRefresh = function () {
|
1710
|
+
if (chart.intervalId) {
|
1711
|
+
clearInterval(chart.intervalId);
|
1712
|
+
}
|
1713
|
+
};
|
1714
|
+
chart.toImage = function () {
|
1715
|
+
if (chart.adapter === "chartjs") {
|
1716
|
+
return chart.chart.toBase64Image();
|
1717
|
+
} else {
|
1718
|
+
return null;
|
1719
|
+
}
|
1720
|
+
}
|
1721
|
+
|
1383
1722
|
Chartkick.charts[element.id] = chart;
|
1384
|
-
|
1723
|
+
|
1724
|
+
fetchDataSource(chart, callback, dataSource);
|
1725
|
+
|
1726
|
+
if (opts.refresh) {
|
1727
|
+
chart.intervalId = setInterval( function () {
|
1728
|
+
chart.refreshData();
|
1729
|
+
}, opts.refresh * 1000);
|
1730
|
+
}
|
1385
1731
|
}
|
1386
1732
|
|
1387
1733
|
// define classes
|
1388
1734
|
|
1389
1735
|
Chartkick = {
|
1390
|
-
LineChart: function (element, dataSource,
|
1391
|
-
|
1736
|
+
LineChart: function (element, dataSource, options) {
|
1737
|
+
createChart("LineChart", this, element, dataSource, options, processLineData);
|
1738
|
+
},
|
1739
|
+
PieChart: function (element, dataSource, options) {
|
1740
|
+
createChart("PieChart", this, element, dataSource, options, processSimple);
|
1392
1741
|
},
|
1393
|
-
|
1394
|
-
|
1742
|
+
ColumnChart: function (element, dataSource, options) {
|
1743
|
+
createChart("ColumnChart", this, element, dataSource, options, processColumnData);
|
1395
1744
|
},
|
1396
|
-
|
1397
|
-
|
1745
|
+
BarChart: function (element, dataSource, options) {
|
1746
|
+
createChart("BarChart", this, element, dataSource, options, processBarData);
|
1398
1747
|
},
|
1399
|
-
|
1400
|
-
|
1748
|
+
AreaChart: function (element, dataSource, options) {
|
1749
|
+
createChart("AreaChart", this, element, dataSource, options, processAreaData);
|
1401
1750
|
},
|
1402
|
-
|
1403
|
-
|
1751
|
+
GeoChart: function (element, dataSource, options) {
|
1752
|
+
createChart("GeoChart", this, element, dataSource, options, processSimple);
|
1404
1753
|
},
|
1405
|
-
|
1406
|
-
|
1754
|
+
ScatterChart: function (element, dataSource, options) {
|
1755
|
+
createChart("ScatterChart", this, element, dataSource, options, processScatterData);
|
1407
1756
|
},
|
1408
|
-
|
1409
|
-
|
1757
|
+
BubbleChart: function (element, dataSource, options) {
|
1758
|
+
createChart("BubbleChart", this, element, dataSource, options, processBubbleData);
|
1410
1759
|
},
|
1411
|
-
Timeline: function (element, dataSource,
|
1412
|
-
|
1760
|
+
Timeline: function (element, dataSource, options) {
|
1761
|
+
createChart("Timeline", this, element, dataSource, options, processTime);
|
1413
1762
|
},
|
1414
1763
|
charts: {},
|
1415
1764
|
configure: function (options) {
|
@@ -1418,7 +1767,17 @@
|
|
1418
1767
|
config[key] = options[key];
|
1419
1768
|
}
|
1420
1769
|
}
|
1421
|
-
}
|
1770
|
+
},
|
1771
|
+
eachChart: function (callback) {
|
1772
|
+
for (var chartId in Chartkick.charts) {
|
1773
|
+
if (Chartkick.charts.hasOwnProperty(chartId)) {
|
1774
|
+
callback(Chartkick.charts[chartId]);
|
1775
|
+
}
|
1776
|
+
}
|
1777
|
+
},
|
1778
|
+
options: {},
|
1779
|
+
adapters: adapters,
|
1780
|
+
createChart: createChart
|
1422
1781
|
};
|
1423
1782
|
|
1424
1783
|
if (typeof module === "object" && typeof module.exports === "object") {
|