blazer 1.2.1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of blazer might be problematic. Click here for more details.

@@ -8,6 +8,7 @@
8
8
  //= require ./moment
9
9
  //= require ./moment-timezone
10
10
  //= require ./daterangepicker
11
+ //= require ./Chart.js
11
12
  //= require ./chartkick
12
13
  //= require ./ace/ace
13
14
  //= require ./ace/ext-language_tools
@@ -1,8 +1,8 @@
1
1
  /*
2
2
  * Chartkick.js
3
- * Create beautiful Javascript charts with minimal code
3
+ * Create beautiful JavaScript charts with minimal code
4
4
  * https://github.com/ankane/chartkick.js
5
- * v1.4.1
5
+ * v1.5.1
6
6
  * MIT License
7
7
  */
8
8
 
@@ -12,8 +12,9 @@
12
12
  'use strict';
13
13
 
14
14
  var config = window.Chartkick || {};
15
- var Chartkick, DATE_PATTERN, ISO8601_PATTERN, DECIMAL_SEPARATOR, adapters = [];
16
- DATE_PATTERN = /^(\d\d\d\d)(\-)?(\d\d)(\-)?(\d\d)$/i;
15
+ var Chartkick, ISO8601_PATTERN, DECIMAL_SEPARATOR, adapters = [];
16
+ var DATE_PATTERN = /^(\d\d\d\d)(\-)?(\d\d)(\-)?(\d\d)$/i;
17
+ var adapters = [];
17
18
 
18
19
  // helpers
19
20
 
@@ -125,8 +126,8 @@
125
126
  setMax(options, opts.max);
126
127
  }
127
128
 
128
- if (opts.stacked) {
129
- setStacked(options);
129
+ if ("stacked" in opts) {
130
+ setStacked(options, opts.stacked);
130
131
  }
131
132
 
132
133
  if (opts.colors) {
@@ -210,7 +211,7 @@
210
211
  if (typeof n !== "object") {
211
212
  if (typeof n === "number") {
212
213
  n = new Date(n * 1000); // ms
213
- } else if (matches = n.match(DATE_PATTERN)) {
214
+ } else if (config.smarterDates && (matches = n.match(DATE_PATTERN))) {
214
215
  year = parseInt(matches[1], 10);
215
216
  month = parseInt(matches[3], 10) - 1;
216
217
  day = parseInt(matches[5], 10);
@@ -242,527 +243,835 @@
242
243
  return a[0].getTime() - b[0].getTime();
243
244
  }
244
245
 
245
- if ("Highcharts" in window) {
246
- var HighchartsAdapter = new function () {
247
- var Highcharts = window.Highcharts;
248
-
249
- this.name = "highcharts";
246
+ function sortByNumber(a, b) {
247
+ return a - b;
248
+ }
250
249
 
251
- var defaultOptions = {
252
- chart: {},
253
- xAxis: {
254
- title: {
255
- text: null
250
+ function loadAdapters() {
251
+ if (!HighchartsAdapter && "Highcharts" in window) {
252
+ var HighchartsAdapter = new function () {
253
+ var Highcharts = window.Highcharts;
254
+
255
+ this.name = "highcharts";
256
+
257
+ var defaultOptions = {
258
+ chart: {},
259
+ xAxis: {
260
+ title: {
261
+ text: null
262
+ },
263
+ labels: {
264
+ style: {
265
+ fontSize: "12px"
266
+ }
267
+ }
256
268
  },
257
- labels: {
258
- style: {
259
- fontSize: "12px"
269
+ yAxis: {
270
+ title: {
271
+ text: null
272
+ },
273
+ labels: {
274
+ style: {
275
+ fontSize: "12px"
276
+ }
260
277
  }
261
- }
262
- },
263
- yAxis: {
278
+ },
264
279
  title: {
265
280
  text: null
266
281
  },
267
- labels: {
282
+ credits: {
283
+ enabled: false
284
+ },
285
+ legend: {
286
+ borderWidth: 0
287
+ },
288
+ tooltip: {
268
289
  style: {
269
290
  fontSize: "12px"
270
291
  }
292
+ },
293
+ plotOptions: {
294
+ areaspline: {},
295
+ series: {
296
+ marker: {}
297
+ }
271
298
  }
272
- },
273
- title: {
274
- text: null
275
- },
276
- credits: {
277
- enabled: false
278
- },
279
- legend: {
280
- borderWidth: 0
281
- },
282
- tooltip: {
283
- style: {
284
- fontSize: "12px"
285
- }
286
- },
287
- plotOptions: {
288
- areaspline: {},
289
- series: {
290
- marker: {}
291
- }
292
- }
293
- };
299
+ };
294
300
 
295
- var hideLegend = function (options) {
296
- options.legend.enabled = false;
297
- };
301
+ var hideLegend = function (options) {
302
+ options.legend.enabled = false;
303
+ };
298
304
 
299
- var setMin = function (options, min) {
300
- options.yAxis.min = min;
301
- };
305
+ var setMin = function (options, min) {
306
+ options.yAxis.min = min;
307
+ };
302
308
 
303
- var setMax = function (options, max) {
304
- options.yAxis.max = max;
305
- };
309
+ var setMax = function (options, max) {
310
+ options.yAxis.max = max;
311
+ };
306
312
 
307
- var setStacked = function (options) {
308
- options.plotOptions.series.stacking = "normal";
309
- };
313
+ var setStacked = function (options, stacked) {
314
+ options.plotOptions.series.stacking = stacked ? "normal" : null;
315
+ };
310
316
 
311
- var setXtitle = function (options, title) {
312
- options.xAxis.title.text = title;
313
- };
317
+ var setXtitle = function (options, title) {
318
+ options.xAxis.title.text = title;
319
+ };
314
320
 
315
- var setYtitle = function (options, title) {
316
- options.yAxis.title.text = title;
317
- };
321
+ var setYtitle = function (options, title) {
322
+ options.yAxis.title.text = title;
323
+ };
324
+
325
+ var jsOptions = jsOptionsFunc(defaultOptions, hideLegend, setMin, setMax, setStacked, setXtitle, setYtitle);
318
326
 
319
- var jsOptions = jsOptionsFunc(defaultOptions, hideLegend, setMin, setMax, setStacked, setXtitle, setYtitle);
320
-
321
- this.renderLineChart = function (chart, chartType) {
322
- chartType = chartType || "spline";
323
- var chartOptions = {};
324
- if (chartType === "areaspline") {
325
- chartOptions = {
326
- plotOptions: {
327
- areaspline: {
328
- stacking: "normal"
329
- },
330
- series: {
331
- marker: {
332
- enabled: false
327
+ this.renderLineChart = function (chart, chartType) {
328
+ chartType = chartType || "spline";
329
+ var chartOptions = {};
330
+ if (chartType === "areaspline") {
331
+ chartOptions = {
332
+ plotOptions: {
333
+ areaspline: {
334
+ stacking: "normal"
335
+ },
336
+ series: {
337
+ marker: {
338
+ enabled: false
339
+ }
333
340
  }
334
341
  }
342
+ };
343
+ }
344
+ var options = jsOptions(chart.data, chart.options, chartOptions), data, i, j;
345
+ options.xAxis.type = chart.options.discrete ? "category" : "datetime";
346
+ options.chart.type = chartType;
347
+ options.chart.renderTo = chart.element.id;
348
+
349
+ var series = chart.data;
350
+ for (i = 0; i < series.length; i++) {
351
+ data = series[i].data;
352
+ if (!chart.options.discrete) {
353
+ for (j = 0; j < data.length; j++) {
354
+ data[j][0] = data[j][0].getTime();
355
+ }
335
356
  }
336
- };
337
- }
338
- var options = jsOptions(chart.data, chart.options, chartOptions), data, i, j;
339
- options.xAxis.type = chart.options.discrete ? "category" : "datetime";
340
- options.chart.type = chartType;
341
- options.chart.renderTo = chart.element.id;
342
-
343
- var series = chart.data;
344
- for (i = 0; i < series.length; i++) {
345
- data = series[i].data;
346
- if (!chart.options.discrete) {
347
- for (j = 0; j < data.length; j++) {
348
- data[j][0] = data[j][0].getTime();
349
- }
357
+ series[i].marker = {symbol: "circle"};
350
358
  }
351
- series[i].marker = {symbol: "circle"};
352
- }
353
- options.series = series;
354
- new Highcharts.Chart(options);
355
- };
356
-
357
- this.renderScatterChart = function (chart) {
358
- var chartOptions = {};
359
- var options = jsOptions(chart.data, chart.options, chartOptions);
360
- options.chart.type = 'scatter';
361
- options.chart.renderTo = chart.element.id;
362
- options.series = chart.data;
363
- new Highcharts.Chart(options);
364
- };
359
+ options.series = series;
360
+ new Highcharts.Chart(options);
361
+ };
365
362
 
366
- this.renderPieChart = function (chart) {
367
- var chartOptions = {};
368
- if (chart.options.colors) {
369
- chartOptions.colors = chart.options.colors;
370
- }
371
- var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {});
372
- options.chart.renderTo = chart.element.id;
373
- options.series = [{
374
- type: "pie",
375
- name: "Value",
376
- data: chart.data
377
- }];
378
- new Highcharts.Chart(options);
379
- };
380
-
381
- this.renderColumnChart = function (chart, chartType) {
382
- var chartType = chartType || "column";
383
- var series = chart.data;
384
- var options = jsOptions(series, chart.options), i, j, s, d, rows = [];
385
- options.chart.type = chartType;
386
- options.chart.renderTo = chart.element.id;
387
-
388
- for (i = 0; i < series.length; i++) {
389
- s = series[i];
363
+ this.renderScatterChart = function (chart) {
364
+ var chartOptions = {};
365
+ var options = jsOptions(chart.data, chart.options, chartOptions);
366
+ options.chart.type = 'scatter';
367
+ options.chart.renderTo = chart.element.id;
368
+ options.series = chart.data;
369
+ new Highcharts.Chart(options);
370
+ };
390
371
 
391
- for (j = 0; j < s.data.length; j++) {
392
- d = s.data[j];
393
- if (!rows[d[0]]) {
394
- rows[d[0]] = new Array(series.length);
372
+ this.renderPieChart = function (chart) {
373
+ var chartOptions = {};
374
+ if (chart.options.colors) {
375
+ chartOptions.colors = chart.options.colors;
376
+ }
377
+ var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {});
378
+ options.chart.renderTo = chart.element.id;
379
+ options.series = [{
380
+ type: "pie",
381
+ name: chart.options.label || "Value",
382
+ data: chart.data
383
+ }];
384
+ new Highcharts.Chart(options);
385
+ };
386
+
387
+ this.renderColumnChart = function (chart, chartType) {
388
+ var chartType = chartType || "column";
389
+ var series = chart.data;
390
+ var options = jsOptions(series, chart.options), i, j, s, d, rows = [];
391
+ options.chart.type = chartType;
392
+ options.chart.renderTo = chart.element.id;
393
+
394
+ for (i = 0; i < series.length; i++) {
395
+ s = series[i];
396
+
397
+ for (j = 0; j < s.data.length; j++) {
398
+ d = s.data[j];
399
+ if (!rows[d[0]]) {
400
+ rows[d[0]] = new Array(series.length);
401
+ }
402
+ rows[d[0]][i] = d[1];
395
403
  }
396
- rows[d[0]][i] = d[1];
397
404
  }
398
- }
399
405
 
400
- var categories = [];
401
- for (i in rows) {
402
- if (rows.hasOwnProperty(i)) {
403
- categories.push(i);
406
+ var categories = [];
407
+ for (i in rows) {
408
+ if (rows.hasOwnProperty(i)) {
409
+ categories.push(i);
410
+ }
404
411
  }
405
- }
406
- options.xAxis.categories = categories;
412
+ options.xAxis.categories = categories;
407
413
 
408
- var newSeries = [];
409
- for (i = 0; i < series.length; i++) {
410
- d = [];
411
- for (j = 0; j < categories.length; j++) {
412
- d.push(rows[categories[j]][i] || 0);
413
- }
414
+ var newSeries = [];
415
+ for (i = 0; i < series.length; i++) {
416
+ d = [];
417
+ for (j = 0; j < categories.length; j++) {
418
+ d.push(rows[categories[j]][i] || 0);
419
+ }
414
420
 
415
- newSeries.push({
416
- name: series[i].name,
417
- data: d
418
- });
419
- }
420
- options.series = newSeries;
421
+ newSeries.push({
422
+ name: series[i].name,
423
+ data: d
424
+ });
425
+ }
426
+ options.series = newSeries;
421
427
 
422
- new Highcharts.Chart(options);
423
- };
428
+ new Highcharts.Chart(options);
429
+ };
424
430
 
425
- var self = this;
431
+ var self = this;
426
432
 
427
- this.renderBarChart = function (chart) {
428
- self.renderColumnChart(chart, "bar");
429
- };
433
+ this.renderBarChart = function (chart) {
434
+ self.renderColumnChart(chart, "bar");
435
+ };
430
436
 
431
- this.renderAreaChart = function (chart) {
432
- self.renderLineChart(chart, "areaspline");
437
+ this.renderAreaChart = function (chart) {
438
+ self.renderLineChart(chart, "areaspline");
439
+ };
433
440
  };
434
- };
435
- adapters.push(HighchartsAdapter);
436
- }
437
- if (window.google && window.google.setOnLoadCallback) {
438
- var GoogleChartsAdapter = new function () {
439
- var google = window.google;
440
-
441
- this.name = "google";
442
-
443
- var loaded = {};
444
- var callbacks = [];
445
-
446
- var runCallbacks = function () {
447
- var cb, call;
448
- for (var i = 0; i < callbacks.length; i++) {
449
- cb = callbacks[i];
450
- call = google.visualization && ((cb.pack === "corechart" && google.visualization.LineChart) || (cb.pack === "timeline" && google.visualization.Timeline))
451
- if (call) {
452
- cb.callback();
453
- callbacks.splice(i, 1);
454
- i--;
441
+ adapters.push(HighchartsAdapter);
442
+ }
443
+ if (!GoogleChartsAdapter && window.google && window.google.setOnLoadCallback) {
444
+ var GoogleChartsAdapter = new function () {
445
+ var google = window.google;
446
+
447
+ this.name = "google";
448
+
449
+ var loaded = {};
450
+ var callbacks = [];
451
+
452
+ var runCallbacks = function () {
453
+ var cb, call;
454
+ for (var i = 0; i < callbacks.length; i++) {
455
+ cb = callbacks[i];
456
+ call = google.visualization && ((cb.pack === "corechart" && google.visualization.LineChart) || (cb.pack === "timeline" && google.visualization.Timeline))
457
+ if (call) {
458
+ cb.callback();
459
+ callbacks.splice(i, 1);
460
+ i--;
461
+ }
455
462
  }
456
- }
457
- };
463
+ };
458
464
 
459
- var waitForLoaded = function (pack, callback) {
460
- if (!callback) {
461
- callback = pack;
462
- pack = "corechart";
463
- }
465
+ var waitForLoaded = function (pack, callback) {
466
+ if (!callback) {
467
+ callback = pack;
468
+ pack = "corechart";
469
+ }
464
470
 
465
- callbacks.push({pack: pack, callback: callback});
471
+ callbacks.push({pack: pack, callback: callback});
466
472
 
467
- if (loaded[pack]) {
468
- runCallbacks();
469
- } else {
470
- loaded[pack] = true;
473
+ if (loaded[pack]) {
474
+ runCallbacks();
475
+ } else {
476
+ loaded[pack] = true;
471
477
 
472
- // https://groups.google.com/forum/#!topic/google-visualization-api/fMKJcyA2yyI
473
- var loadOptions = {
474
- packages: [pack],
475
- callback: runCallbacks
476
- };
477
- if (config.language) {
478
- loadOptions.language = config.language;
478
+ // https://groups.google.com/forum/#!topic/google-visualization-api/fMKJcyA2yyI
479
+ var loadOptions = {
480
+ packages: [pack],
481
+ callback: runCallbacks
482
+ };
483
+ if (config.language) {
484
+ loadOptions.language = config.language;
485
+ }
486
+ google.load("visualization", "1", loadOptions);
479
487
  }
480
- google.load("visualization", "1", loadOptions);
481
- }
482
- };
483
-
484
- // Set chart options
485
- var defaultOptions = {
486
- chartArea: {},
487
- fontName: "'Lucida Grande', 'Lucida Sans Unicode', Verdana, Arial, Helvetica, sans-serif",
488
- pointSize: 6,
489
- legend: {
490
- textStyle: {
491
- fontSize: 12,
492
- color: "#444"
488
+ };
489
+
490
+ // Set chart options
491
+ var defaultOptions = {
492
+ chartArea: {},
493
+ fontName: "'Lucida Grande', 'Lucida Sans Unicode', Verdana, Arial, Helvetica, sans-serif",
494
+ pointSize: 6,
495
+ legend: {
496
+ textStyle: {
497
+ fontSize: 12,
498
+ color: "#444"
499
+ },
500
+ alignment: "center",
501
+ position: "right"
493
502
  },
494
- alignment: "center",
495
- position: "right"
496
- },
497
- curveType: "function",
498
- hAxis: {
499
- textStyle: {
500
- color: "#666",
501
- fontSize: 12
503
+ curveType: "function",
504
+ hAxis: {
505
+ textStyle: {
506
+ color: "#666",
507
+ fontSize: 12
508
+ },
509
+ titleTextStyle: {},
510
+ gridlines: {
511
+ color: "transparent"
512
+ },
513
+ baselineColor: "#ccc",
514
+ viewWindow: {}
502
515
  },
503
- titleTextStyle: {},
504
- gridlines: {
505
- color: "transparent"
516
+ vAxis: {
517
+ textStyle: {
518
+ color: "#666",
519
+ fontSize: 12
520
+ },
521
+ titleTextStyle: {},
522
+ baselineColor: "#ccc",
523
+ viewWindow: {}
506
524
  },
507
- baselineColor: "#ccc",
508
- viewWindow: {}
509
- },
510
- vAxis: {
511
- textStyle: {
512
- color: "#666",
513
- fontSize: 12
514
- },
515
- titleTextStyle: {},
516
- baselineColor: "#ccc",
517
- viewWindow: {}
518
- },
519
- tooltip: {
520
- textStyle: {
521
- color: "#666",
522
- fontSize: 12
525
+ tooltip: {
526
+ textStyle: {
527
+ color: "#666",
528
+ fontSize: 12
529
+ }
523
530
  }
524
- }
525
- };
531
+ };
526
532
 
527
- var hideLegend = function (options) {
528
- options.legend.position = "none";
529
- };
533
+ var hideLegend = function (options) {
534
+ options.legend.position = "none";
535
+ };
530
536
 
531
- var setMin = function (options, min) {
532
- options.vAxis.viewWindow.min = min;
533
- };
537
+ var setMin = function (options, min) {
538
+ options.vAxis.viewWindow.min = min;
539
+ };
534
540
 
535
- var setMax = function (options, max) {
536
- options.vAxis.viewWindow.max = max;
537
- };
541
+ var setMax = function (options, max) {
542
+ options.vAxis.viewWindow.max = max;
543
+ };
538
544
 
539
- var setBarMin = function (options, min) {
540
- options.hAxis.viewWindow.min = min;
541
- };
542
-
543
- var setBarMax = function (options, max) {
544
- options.hAxis.viewWindow.max = max;
545
- };
545
+ var setBarMin = function (options, min) {
546
+ options.hAxis.viewWindow.min = min;
547
+ };
546
548
 
547
- var setStacked = function (options) {
548
- options.isStacked = true;
549
- };
549
+ var setBarMax = function (options, max) {
550
+ options.hAxis.viewWindow.max = max;
551
+ };
550
552
 
551
- var setXtitle = function (options, title) {
552
- options.hAxis.title = title;
553
- options.hAxis.titleTextStyle.italic = false;
554
- }
553
+ var setStacked = function (options, stacked) {
554
+ options.isStacked = !!stacked;
555
+ };
555
556
 
556
- var setYtitle = function (options, title) {
557
- options.vAxis.title = title;
558
- options.vAxis.titleTextStyle.italic = false;
559
- };
557
+ var setXtitle = function (options, title) {
558
+ options.hAxis.title = title;
559
+ options.hAxis.titleTextStyle.italic = false;
560
+ }
560
561
 
561
- var jsOptions = jsOptionsFunc(defaultOptions, hideLegend, setMin, setMax, setStacked, setXtitle, setYtitle);
562
+ var setYtitle = function (options, title) {
563
+ options.vAxis.title = title;
564
+ options.vAxis.titleTextStyle.italic = false;
565
+ };
562
566
 
563
- // cant use object as key
564
- var createDataTable = function (series, columnType) {
565
- var data = new google.visualization.DataTable();
566
- data.addColumn(columnType, "");
567
+ var jsOptions = jsOptionsFunc(defaultOptions, hideLegend, setMin, setMax, setStacked, setXtitle, setYtitle);
567
568
 
568
- var i, j, s, d, key, rows = [];
569
- for (i = 0; i < series.length; i++) {
570
- s = series[i];
571
- data.addColumn("number", s.name);
569
+ // cant use object as key
570
+ var createDataTable = function (series, columnType) {
571
+ var i, j, s, d, key, rows = [];
572
+ for (i = 0; i < series.length; i++) {
573
+ s = series[i];
572
574
 
573
- for (j = 0; j < s.data.length; j++) {
574
- d = s.data[j];
575
- key = (columnType === "datetime") ? d[0].getTime() : d[0];
576
- if (!rows[key]) {
577
- rows[key] = new Array(series.length);
575
+ for (j = 0; j < s.data.length; j++) {
576
+ d = s.data[j];
577
+ key = (columnType === "datetime") ? d[0].getTime() : d[0];
578
+ if (!rows[key]) {
579
+ rows[key] = new Array(series.length);
580
+ }
581
+ rows[key][i] = toFloat(d[1]);
578
582
  }
579
- rows[key][i] = toFloat(d[1]);
580
583
  }
581
- }
582
584
 
583
- var rows2 = [];
584
- var day = true;
585
- var value;
586
- for (i in rows) {
587
- if (rows.hasOwnProperty(i)) {
588
- if (columnType === "datetime") {
589
- value = new Date(toFloat(i));
590
- day = day && isDay(value);
591
- } else if (columnType === "number") {
592
- value = toFloat(i);
593
- } else {
594
- value = i;
585
+ var rows2 = [];
586
+ var day = true;
587
+ var value;
588
+ for (i in rows) {
589
+ if (rows.hasOwnProperty(i)) {
590
+ if (columnType === "datetime") {
591
+ value = new Date(toFloat(i));
592
+ day = day && isDay(value);
593
+ } else if (columnType === "number") {
594
+ value = toFloat(i);
595
+ } else {
596
+ value = i;
597
+ }
598
+ rows2.push([value].concat(rows[i]));
595
599
  }
596
- rows2.push([value].concat(rows[i]));
597
600
  }
598
- }
599
- if (columnType === "datetime") {
600
- rows2.sort(sortByTime);
601
- }
602
- data.addRows(rows2);
601
+ if (columnType === "datetime") {
602
+ rows2.sort(sortByTime);
603
+ }
603
604
 
604
- if (columnType === "datetime" && day) {
605
- var formatter = new google.visualization.DateFormat({
606
- pattern: "MMM d, yyyy"
605
+ // create datatable
606
+ var data = new google.visualization.DataTable();
607
+ columnType = columnType === "datetime" && day ? "date" : columnType;
608
+ data.addColumn(columnType, "");
609
+ for (i = 0; i < series.length; i++) {
610
+ data.addColumn("number", series[i].name);
611
+ }
612
+ data.addRows(rows2);
613
+
614
+ return data;
615
+ };
616
+
617
+ var resize = function (callback) {
618
+ if (window.attachEvent) {
619
+ window.attachEvent("onresize", callback);
620
+ } else if (window.addEventListener) {
621
+ window.addEventListener("resize", callback, true);
622
+ }
623
+ callback();
624
+ };
625
+
626
+ this.renderLineChart = function (chart) {
627
+ waitForLoaded(function () {
628
+ var options = jsOptions(chart.data, chart.options);
629
+ var data = createDataTable(chart.data, chart.options.discrete ? "string" : "datetime");
630
+ chart.chart = new google.visualization.LineChart(chart.element);
631
+ resize(function () {
632
+ chart.chart.draw(data, options);
633
+ });
607
634
  });
608
- formatter.format(data, 0);
609
- }
635
+ };
636
+
637
+ this.renderPieChart = function (chart) {
638
+ waitForLoaded(function () {
639
+ var chartOptions = {
640
+ chartArea: {
641
+ top: "10%",
642
+ height: "80%"
643
+ }
644
+ };
645
+ if (chart.options.colors) {
646
+ chartOptions.colors = chart.options.colors;
647
+ }
648
+ var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {});
610
649
 
611
- return data;
612
- };
650
+ var data = new google.visualization.DataTable();
651
+ data.addColumn("string", "");
652
+ data.addColumn("number", "Value");
653
+ data.addRows(chart.data);
613
654
 
614
- var resize = function (callback) {
615
- if (window.attachEvent) {
616
- window.attachEvent("onresize", callback);
617
- } else if (window.addEventListener) {
618
- window.addEventListener("resize", callback, true);
619
- }
620
- callback();
621
- };
655
+ chart.chart = new google.visualization.PieChart(chart.element);
656
+ resize(function () {
657
+ chart.chart.draw(data, options);
658
+ });
659
+ });
660
+ };
661
+
662
+ this.renderColumnChart = function (chart) {
663
+ waitForLoaded(function () {
664
+ var options = jsOptions(chart.data, chart.options);
665
+ var data = createDataTable(chart.data, "string");
666
+ chart.chart = new google.visualization.ColumnChart(chart.element);
667
+ resize(function () {
668
+ chart.chart.draw(data, options);
669
+ });
670
+ });
671
+ };
672
+
673
+ this.renderBarChart = function (chart) {
674
+ waitForLoaded(function () {
675
+ var chartOptions = {
676
+ hAxis: {
677
+ gridlines: {
678
+ color: "#ccc"
679
+ }
680
+ }
681
+ };
682
+ var options = jsOptionsFunc(defaultOptions, hideLegend, setBarMin, setBarMax, setStacked)(chart.data, chart.options, chartOptions);
683
+ var data = createDataTable(chart.data, "string");
684
+ chart.chart = new google.visualization.BarChart(chart.element);
685
+ resize(function () {
686
+ chart.chart.draw(data, options);
687
+ });
688
+ });
689
+ };
690
+
691
+ this.renderAreaChart = function (chart) {
692
+ waitForLoaded(function () {
693
+ var chartOptions = {
694
+ isStacked: true,
695
+ pointSize: 0,
696
+ areaOpacity: 0.5
697
+ };
698
+ var options = jsOptions(chart.data, chart.options, chartOptions);
699
+ var data = createDataTable(chart.data, chart.options.discrete ? "string" : "datetime");
700
+ chart.chart = new google.visualization.AreaChart(chart.element);
701
+ resize(function () {
702
+ chart.chart.draw(data, options);
703
+ });
704
+ });
705
+ };
706
+
707
+ this.renderGeoChart = function (chart) {
708
+ waitForLoaded(function () {
709
+ var chartOptions = {
710
+ legend: "none",
711
+ colorAxis: {
712
+ colors: chart.options.colors || ["#f6c7b6", "#ce502d"]
713
+ }
714
+ };
715
+ var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {});
716
+
717
+ var data = new google.visualization.DataTable();
718
+ data.addColumn("string", "");
719
+ data.addColumn("number", chart.options.label || "Value");
720
+ data.addRows(chart.data);
721
+
722
+ chart.chart = new google.visualization.GeoChart(chart.element);
723
+ resize(function () {
724
+ chart.chart.draw(data, options);
725
+ });
726
+ });
727
+ };
728
+
729
+ this.renderScatterChart = function (chart) {
730
+ waitForLoaded(function () {
731
+ var chartOptions = {};
732
+ var options = jsOptions(chart.data, chart.options, chartOptions);
733
+ var data = createDataTable(chart.data, "number");
734
+
735
+ chart.chart = new google.visualization.ScatterChart(chart.element);
736
+ resize(function () {
737
+ chart.chart.draw(data, options);
738
+ });
739
+ });
740
+ };
622
741
 
623
- this.renderLineChart = function (chart) {
624
- waitForLoaded(function () {
625
- var options = jsOptions(chart.data, chart.options);
626
- var data = createDataTable(chart.data, chart.options.discrete ? "string" : "datetime");
627
- chart.chart = new google.visualization.LineChart(chart.element);
628
- resize(function () {
629
- chart.chart.draw(data, options);
742
+ this.renderTimeline = function (chart) {
743
+ waitForLoaded("timeline", function () {
744
+ var chartOptions = {
745
+ legend: "none"
746
+ };
747
+
748
+ if (chart.options.colors) {
749
+ chartOptions.colors = chart.options.colors;
750
+ }
751
+ var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {});
752
+
753
+ var data = new google.visualization.DataTable();
754
+ data.addColumn({type: "string", id: "Name"});
755
+ data.addColumn({type: "date", id: "Start"});
756
+ data.addColumn({type: "date", id: "End"});
757
+ data.addRows(chart.data);
758
+
759
+ chart.element.style.lineHeight = "normal";
760
+ chart.chart = new google.visualization.Timeline(chart.element);
761
+
762
+ resize(function () {
763
+ chart.chart.draw(data, options);
764
+ });
630
765
  });
631
- });
766
+ };
632
767
  };
633
768
 
634
- this.renderPieChart = function (chart) {
635
- waitForLoaded(function () {
636
- var chartOptions = {
637
- chartArea: {
638
- top: "10%",
639
- height: "80%"
769
+ adapters.push(GoogleChartsAdapter);
770
+ }
771
+ if (!ChartjsAdapter && "Chart" in window) {
772
+ var ChartjsAdapter = new function () {
773
+ var Chart = window.Chart;
774
+
775
+ this.name = "chartjs";
776
+
777
+ var baseOptions = {
778
+ maintainAspectRatio: false,
779
+ animation: false
780
+ };
781
+
782
+ var defaultOptions = {
783
+ scales: {
784
+ yAxes: [
785
+ {
786
+ ticks: {
787
+ maxTicksLimit: 4
788
+ },
789
+ scaleLabel: {
790
+ fontSize: 16,
791
+ // fontStyle: "bold",
792
+ fontColor: "#333"
793
+ }
794
+ }
795
+ ],
796
+ xAxes: [
797
+ {
798
+ gridLines: {
799
+ drawOnChartArea: false
800
+ },
801
+ scaleLabel: {
802
+ fontSize: 16,
803
+ // fontStyle: "bold",
804
+ fontColor: "#333"
805
+ },
806
+ time: {},
807
+ ticks: {}
808
+ }
809
+ ]
810
+ },
811
+ legend: {}
812
+ };
813
+
814
+ // http://there4.io/2012/05/02/google-chart-color-list/
815
+ var defaultColors = [
816
+ "#3366CC", "#DC3912", "#FF9900", "#109618", "#990099", "#3B3EAC", "#0099C6",
817
+ "#DD4477", "#66AA00", "#B82E2E", "#316395", "#994499", "#22AA99", "#AAAA11",
818
+ "#6633CC", "#E67300", "#8B0707", "#329262", "#5574A6", "#3B3EAC"
819
+ ];
820
+
821
+ var hideLegend = function (options) {
822
+ options.legend.display = false;
823
+ };
824
+
825
+ var setMin = function (options, min) {
826
+ if (min !== null) {
827
+ options.scales.yAxes[0].ticks.min = min;
828
+ }
829
+ };
830
+
831
+ var setMax = function (options, max) {
832
+ options.scales.yAxes[0].ticks.max = max;
833
+ };
834
+
835
+ var setStacked = function (options, stacked) {
836
+ options.scales.xAxes[0].stacked = !!stacked;
837
+ options.scales.yAxes[0].stacked = !!stacked;
838
+ };
839
+
840
+ var setXtitle = function (options, title) {
841
+ options.scales.xAxes[0].scaleLabel.display = true;
842
+ options.scales.xAxes[0].scaleLabel.labelString = title;
843
+ };
844
+
845
+ var setYtitle = function (options, title) {
846
+ options.scales.yAxes[0].scaleLabel.display = true;
847
+ options.scales.yAxes[0].scaleLabel.labelString = title;
848
+ };
849
+
850
+ var drawChart = function(chart, type, data, options) {
851
+ chart.element.innerHTML = "<canvas></canvas>";
852
+ var ctx = chart.element.getElementsByTagName("CANVAS")[0];
853
+
854
+ chart.chart = new Chart(ctx, {
855
+ type: type,
856
+ data: data,
857
+ options: options
858
+ });
859
+ };
860
+
861
+ // http://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb
862
+ var addOpacity = function(hex, opacity) {
863
+ var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
864
+ return result ? "rgba(" + parseInt(result[1], 16) + ", " + parseInt(result[2], 16) + ", " + parseInt(result[3], 16) + ", " + opacity + ")" : hex;
865
+ };
866
+
867
+ var setLabelSize = function (chart, data, options) {
868
+ var maxLabelSize = Math.ceil(chart.element.offsetWidth / 4.0 / data.labels.length);
869
+ options.scales.xAxes[0].ticks.callback = function (value) {
870
+ value = toStr(value);
871
+ if (value.length > maxLabelSize) {
872
+ return value.substring(0, maxLabelSize - 2) + "...";
873
+ } else {
874
+ return value;
640
875
  }
641
876
  };
642
- if (chart.options.colors) {
643
- chartOptions.colors = chart.options.colors;
877
+ };
878
+
879
+ var jsOptions = jsOptionsFunc(merge(baseOptions, defaultOptions), hideLegend, setMin, setMax, setStacked, setXtitle, setYtitle);
880
+
881
+ var createDataTable = function (chart, options, chartType) {
882
+ var datasets = [];
883
+ var labels = [];
884
+
885
+ var colors = chart.options.colors || defaultColors;
886
+
887
+ var day = true;
888
+ var week = true;
889
+ var dayOfWeek;
890
+ var month = true;
891
+ var year = true;
892
+ var detectType = (chartType === "line" || chartType === "area") && !chart.options.discrete;
893
+
894
+ var series = chart.data;
895
+
896
+ var sortedLabels = [];
897
+
898
+ var i, j, s, d, key, rows = [];
899
+ for (i = 0; i < series.length; i++) {
900
+ s = series[i];
901
+
902
+ for (j = 0; j < s.data.length; j++) {
903
+ d = s.data[j];
904
+ key = detectType ? d[0].getTime() : d[0];
905
+ if (!rows[key]) {
906
+ rows[key] = new Array(series.length);
907
+ }
908
+ rows[key][i] = toFloat(d[1]);
909
+ if (sortedLabels.indexOf(key) === -1) {
910
+ sortedLabels.push(key);
911
+ }
912
+ }
644
913
  }
645
- var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {});
646
914
 
647
- var data = new google.visualization.DataTable();
648
- data.addColumn("string", "");
649
- data.addColumn("number", "Value");
650
- data.addRows(chart.data);
915
+ if (detectType) {
916
+ sortedLabels.sort(sortByNumber);
917
+ }
651
918
 
652
- chart.chart = new google.visualization.PieChart(chart.element);
653
- resize(function () {
654
- chart.chart.draw(data, options);
655
- });
656
- });
657
- };
919
+ var rows2 = [];
920
+ for (var j = 0; j < series.length; j++) {
921
+ rows2.push([]);
922
+ }
658
923
 
659
- this.renderColumnChart = function (chart) {
660
- waitForLoaded(function () {
661
- var options = jsOptions(chart.data, chart.options);
662
- var data = createDataTable(chart.data, "string");
663
- chart.chart = new google.visualization.ColumnChart(chart.element);
664
- resize(function () {
665
- chart.chart.draw(data, options);
666
- });
667
- });
668
- };
924
+ var day = true;
925
+ var value;
926
+ var k;
927
+ for (k = 0; k < sortedLabels.length; k++) {
928
+ i = sortedLabels[k];
929
+ if (detectType) {
930
+ value = new Date(toFloat(i));
931
+ // TODO make this efficient
932
+ day = day && isDay(value);
933
+ if (!dayOfWeek) {
934
+ dayOfWeek = value.getDay();
935
+ }
936
+ week = week && isWeek(value, dayOfWeek);
937
+ month = month && isMonth(value);
938
+ year = year && isYear(value);
939
+ } else {
940
+ value = i;
941
+ }
942
+ labels.push(value);
943
+ for (var j = 0; j < series.length; j++) {
944
+ rows2[j].push(rows[i][j])
945
+ }
946
+ }
669
947
 
670
- this.renderBarChart = function (chart) {
671
- waitForLoaded(function () {
672
- var chartOptions = {
673
- hAxis: {
674
- gridlines: {
675
- color: "#ccc"
948
+ for (var i = 0; i < series.length; i++) {
949
+ var s = series[i];
950
+
951
+ var backgroundColor = chartType !== "line" ? addOpacity(colors[i], 0.5) : colors[i];
952
+
953
+ var dataset = {
954
+ label: s.name,
955
+ data: rows2[i],
956
+ fill: chartType === "area",
957
+ borderColor: colors[i],
958
+ backgroundColor: backgroundColor,
959
+ pointBackgroundColor: colors[i],
960
+ borderWidth: 2
961
+ };
962
+
963
+ datasets.push(merge(dataset, s.library || {}));
964
+ }
965
+
966
+ if (detectType && labels.length > 0) {
967
+ var minTime = labels[0].getTime();
968
+ var maxTime = labels[0].getTime();
969
+ for (i = 1; i < labels.length; i++) {
970
+ value = labels[i].getTime();
971
+ if (value < minTime) {
972
+ minTime = value;
973
+ }
974
+ if (value > maxTime) {
975
+ maxTime = value;
676
976
  }
677
977
  }
678
- };
679
- var options = jsOptionsFunc(defaultOptions, hideLegend, setBarMin, setBarMax, setStacked)(chart.data, chart.options, chartOptions);
680
- var data = createDataTable(chart.data, "string");
681
- chart.chart = new google.visualization.BarChart(chart.element);
682
- resize(function () {
683
- chart.chart.draw(data, options);
684
- });
685
- });
686
- };
687
978
 
688
- this.renderAreaChart = function (chart) {
689
- waitForLoaded(function () {
690
- var chartOptions = {
691
- isStacked: true,
692
- pointSize: 0,
693
- areaOpacity: 0.5
694
- };
695
- var options = jsOptions(chart.data, chart.options, chartOptions);
696
- var data = createDataTable(chart.data, chart.options.discrete ? "string" : "datetime");
697
- chart.chart = new google.visualization.AreaChart(chart.element);
698
- resize(function () {
699
- chart.chart.draw(data, options);
700
- });
701
- });
702
- };
979
+ var timeDiff = (maxTime - minTime) / (86400 * 1000.0);
980
+
981
+ if (!options.scales.xAxes[0].time.unit) {
982
+ var step;
983
+ if (year || timeDiff > 365 * 10) {
984
+ options.scales.xAxes[0].time.unit = "year";
985
+ step = 365;
986
+ } else if (month || timeDiff > 30 * 10) {
987
+ options.scales.xAxes[0].time.unit = "month";
988
+ step = 30;
989
+ } else if (day || timeDiff > 10) {
990
+ options.scales.xAxes[0].time.unit = "day";
991
+ step = 1;
992
+ }
703
993
 
704
- this.renderGeoChart = function (chart) {
705
- waitForLoaded(function () {
706
- var chartOptions = {
707
- legend: "none",
708
- colorAxis: {
709
- colors: chart.options.colors || ["#f6c7b6", "#ce502d"]
994
+ if (step && timeDiff > 0) {
995
+ var unitStepSize = Math.ceil(timeDiff / step / (chart.element.offsetWidth / 100.0));
996
+ if (week) {
997
+ unitStepSize = Math.ceil(unitStepSize / 7.0) * 7;
998
+ }
999
+ options.scales.xAxes[0].time.unitStepSize = unitStepSize;
1000
+ }
1001
+ }
1002
+
1003
+ if (!options.scales.xAxes[0].time.tooltipFormat && day) {
1004
+ options.scales.xAxes[0].time.tooltipFormat = "ll";
710
1005
  }
1006
+ }
1007
+
1008
+ var data = {
1009
+ labels: labels,
1010
+ datasets: datasets
711
1011
  };
712
- var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {});
713
1012
 
714
- var data = new google.visualization.DataTable();
715
- data.addColumn("string", "");
716
- data.addColumn("number", "Value");
717
- data.addRows(chart.data);
1013
+ return data;
1014
+ };
718
1015
 
719
- chart.chart = new google.visualization.GeoChart(chart.element);
720
- resize(function () {
721
- chart.chart.draw(data, options);
722
- });
723
- });
724
- };
1016
+ this.renderLineChart = function (chart, chartType) {
1017
+ var areaOptions = {};
1018
+ if (chartType === "area") {
1019
+ // TODO fix area stacked
1020
+ // areaOptions.stacked = true;
1021
+ }
1022
+ var options = jsOptions(chart.data, merge(areaOptions, chart.options));
725
1023
 
726
- this.renderScatterChart = function (chart) {
727
- waitForLoaded(function () {
728
- var chartOptions = {};
729
- var options = jsOptions(chart.data, chart.options, chartOptions);
730
- var data = createDataTable(chart.data, "number");
1024
+ var data = createDataTable(chart, options, chartType || "line");
731
1025
 
732
- chart.chart = new google.visualization.ScatterChart(chart.element);
733
- resize(function () {
734
- chart.chart.draw(data, options);
735
- });
736
- });
737
- };
1026
+ options.scales.xAxes[0].type = chart.options.discrete ? "category" : "time";
738
1027
 
739
- this.renderTimeline = function (chart) {
740
- waitForLoaded("timeline", function () {
741
- var chartOptions = {
742
- legend: "none"
743
- };
1028
+ drawChart(chart, "line", data, options);
1029
+ }
744
1030
 
745
- if (chart.options.colors) {
746
- chartOptions.colors = chart.options.colors;
1031
+ this.renderPieChart = function (chart) {
1032
+ var options = merge(baseOptions, chart.options.library || {});
1033
+
1034
+ var labels = [];
1035
+ var values = [];
1036
+ for (var i = 0; i < chart.data.length; i++) {
1037
+ var point = chart.data[i];
1038
+ labels.push(point[0]);
1039
+ values.push(point[1]);
747
1040
  }
748
- var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {});
749
1041
 
750
- var data = new google.visualization.DataTable();
751
- data.addColumn({type: "string", id: "Name"});
752
- data.addColumn({type: "date", id: "Start"});
753
- data.addColumn({type: "date", id: "End"});
754
- data.addRows(chart.data);
1042
+ var data = {
1043
+ labels: labels,
1044
+ datasets: [
1045
+ {
1046
+ data: values,
1047
+ backgroundColor: chart.options.colors || defaultColors
1048
+ }
1049
+ ]
1050
+ };
755
1051
 
756
- chart.chart = new google.visualization.Timeline(chart.element);
1052
+ drawChart(chart, "pie", data, options);
1053
+ }
757
1054
 
758
- resize(function () {
759
- chart.chart.draw(data, options);
760
- });
761
- });
762
- };
763
- };
1055
+ this.renderColumnChart = function (chart, chartType) {
1056
+ var options = jsOptions(chart.data, chart.options);
1057
+ var data = createDataTable(chart, options, "column");
1058
+ setLabelSize(chart, data, options);
1059
+ drawChart(chart, (chartType === "bar" ? "horizontalBar" : "bar"), data, options);
1060
+ }
1061
+
1062
+ var self = this;
764
1063
 
765
- adapters.push(GoogleChartsAdapter);
1064
+ this.renderAreaChart = function (chart) {
1065
+ self.renderLineChart(chart, "area");
1066
+ };
1067
+
1068
+ this.renderBarChart = function (chart) {
1069
+ self.renderColumnChart(chart, "bar")
1070
+ }
1071
+ }
1072
+
1073
+ adapters.push(ChartjsAdapter);
1074
+ }
766
1075
  }
767
1076
 
768
1077
  // TODO remove chartType if cross-browser way
@@ -772,6 +1081,10 @@
772
1081
  fnName = "render" + chartType;
773
1082
  adapterName = chart.options.adapter;
774
1083
 
1084
+ if (adapters.length == 0) {
1085
+ loadAdapters();
1086
+ }
1087
+
775
1088
  for (i = 0; i < adapters.length; i++) {
776
1089
  adapter = adapters[i];
777
1090
  if ((!adapterName || adapterName === adapter.name) && isFunction(adapter[fnName])) {
@@ -810,16 +1123,48 @@
810
1123
  return d.getMilliseconds() + d.getSeconds() + d.getMinutes() + d.getHours() === 0;
811
1124
  }
812
1125
 
1126
+ function isWeek(d, dayOfWeek) {
1127
+ return isDay(d) && d.getDay() === dayOfWeek;
1128
+ }
1129
+
1130
+ function isMonth(d) {
1131
+ return isDay(d) && d.getDate() === 1;
1132
+ }
1133
+
1134
+ function isYear(d) {
1135
+ return isMonth(d) && d.getMonth() === 0;
1136
+ }
1137
+
1138
+ function isDate(obj) {
1139
+ return !isNaN(toDate(obj)) && toStr(obj).length >= 6;
1140
+ }
1141
+
1142
+ function detectDiscrete(series) {
1143
+ var i, j, data;
1144
+ for (i = 0; i < series.length; i++) {
1145
+ data = toArr(series[i].data);
1146
+ for (j = 0; j < data.length; j++) {
1147
+ if (!isDate(data[j][0])) {
1148
+ return true;
1149
+ }
1150
+ }
1151
+ }
1152
+ return false;
1153
+ }
1154
+
813
1155
  function processSeries(series, opts, keyType) {
814
1156
  var i;
815
1157
 
816
1158
  // see if one series or multiple
817
1159
  if (!isArray(series) || typeof series[0] !== "object" || isArray(series[0])) {
818
- series = [{name: "Value", data: series}];
1160
+ series = [{name: opts.label || "Value", data: series}];
819
1161
  opts.hideLegend = true;
820
1162
  } else {
821
1163
  opts.hideLegend = false;
822
1164
  }
1165
+ if (config.smarterDiscrete && (opts.discrete === null || opts.discrete === undefined)) {
1166
+ opts.discrete = detectDiscrete(series);
1167
+ }
823
1168
  if (opts.discrete) {
824
1169
  keyType = "string";
825
1170
  }