sidekiq-benchmark 0.5.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.gitignore +3 -19
- data/README.md +2 -5
- data/lib/sidekiq-benchmark.rb +1 -0
- data/lib/sidekiq-benchmark/version.rb +1 -1
- data/lib/sidekiq-benchmark/web.rb +18 -5
- data/lib/sidekiq-benchmark/worker.rb +4 -2
- data/sidekiq-benchmark.gemspec +3 -3
- data/test/lib/testing.rb +2 -2
- data/test/lib/web_test.rb +20 -15
- data/test/lib/worker_test.rb +13 -13
- data/test/test_helper.rb +1 -1
- data/web/assets/javascripts/chartkick.js +2239 -322
- data/web/views/benchmarks.erb +26 -4
- metadata +8 -10
- data/.travis.yml +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e90aa6b3895541db3454bfac34902d919c5f9c5e8f6640085690af9530fe9995
|
4
|
+
data.tar.gz: 7a88366e826fc84954c47296294d4685cf5887bfa2bbea0fe4f966e917d28f95
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a7f05db5120b717567fc6f2c110ed5d1c4873ff35989f2c5a61c9c6317068c3e5a195ece0c504581c8d33a90f0aad5fc3e0e685265d10cffb9c61e037428e592
|
7
|
+
data.tar.gz: 690b2c9f0786eb23b0a6288d4f68008085e4917a205cccf016218cdb5a080cfbc94808403bb37d34f1d46c34107e1ec67c1103c190690272dc7f45b0eae4036d
|
data/.gitignore
CHANGED
@@ -1,20 +1,4 @@
|
|
1
|
-
|
2
|
-
*.swo
|
3
|
-
*.gem
|
4
|
-
*.rbc
|
5
|
-
.ruby-version
|
6
|
-
.bundle
|
7
|
-
.config
|
8
|
-
.yardoc
|
1
|
+
vendor/
|
9
2
|
Gemfile.lock
|
10
|
-
|
11
|
-
|
12
|
-
coverage
|
13
|
-
doc/
|
14
|
-
lib/bundler/man
|
15
|
-
pkg
|
16
|
-
rdoc
|
17
|
-
spec/reports
|
18
|
-
test/tmp
|
19
|
-
test/version_tmp
|
20
|
-
tmp
|
3
|
+
coverage/
|
4
|
+
*.gem
|
data/README.md
CHANGED
@@ -19,7 +19,7 @@ And then execute:
|
|
19
19
|
|
20
20
|
## Requirements
|
21
21
|
|
22
|
-
|
22
|
+
From version 0.5.0 works with Sidekiq 4.2 or newer
|
23
23
|
|
24
24
|
## Usage
|
25
25
|
|
@@ -73,7 +73,7 @@ end
|
|
73
73
|
|
74
74
|
### Sample Apps
|
75
75
|
|
76
|
-
[Heroku App](http://sidekiq-benchmark.herokuapp.com/benchmarks)
|
76
|
+
[Heroku App](http://sidekiq-benchmark.herokuapp.com/benchmarks/generate)
|
77
77
|
|
78
78
|
## Testing sidekiq workers
|
79
79
|
|
@@ -92,6 +92,3 @@ require 'sidekiq-benchmark/testing'
|
|
92
92
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
93
93
|
4. Push to the branch (`git push origin my-new-feature`)
|
94
94
|
5. Create new Pull Request
|
95
|
-
|
96
|
-
|
97
|
-
[](https://coderwall.com/kosmatov)
|
data/lib/sidekiq-benchmark.rb
CHANGED
@@ -23,11 +23,11 @@ module Sidekiq
|
|
23
23
|
@charts = {}
|
24
24
|
|
25
25
|
Sidekiq.redis do |conn|
|
26
|
-
@types = conn.smembers
|
26
|
+
@types = conn.smembers TYPES_KEY
|
27
27
|
@types.each do |type|
|
28
|
-
@charts[type] = {
|
28
|
+
@charts[type] = STAT_KEYS.reduce({}) { |a, e| a[e] = []; a }
|
29
29
|
|
30
|
-
total_key = "#{
|
30
|
+
total_key = "#{REDIS_NAMESPACE}:#{type}:total"
|
31
31
|
total_keys = conn.hkeys(total_key) - %w(start_time job_time finish_time)
|
32
32
|
|
33
33
|
total_time = conn.hget total_key, :job_time
|
@@ -37,7 +37,7 @@ module Sidekiq
|
|
37
37
|
@charts[type][:total] << [key, value.to_f.round(2)]
|
38
38
|
end
|
39
39
|
|
40
|
-
stats = conn.hgetall "#{
|
40
|
+
stats = conn.hgetall "#{REDIS_NAMESPACE}:#{type}:stats"
|
41
41
|
stats.each do |key, value|
|
42
42
|
@charts[type][:stats] << [key.to_f, value.to_i]
|
43
43
|
end
|
@@ -52,7 +52,20 @@ module Sidekiq
|
|
52
52
|
|
53
53
|
app.post "/benchmarks/remove" do
|
54
54
|
Sidekiq.redis do |conn|
|
55
|
-
keys =
|
55
|
+
keys = STAT_KEYS.map { |key| "#{REDIS_NAMESPACE}:#{params[:type]}:#{key}" }
|
56
|
+
conn.srem TYPES_KEY, params[:type]
|
57
|
+
conn.del keys
|
58
|
+
end
|
59
|
+
|
60
|
+
redirect "#{root_path}benchmarks"
|
61
|
+
end
|
62
|
+
app.post "/benchmarks/remove_all" do
|
63
|
+
Sidekiq.redis do |conn|
|
64
|
+
types = conn.smembers TYPES_KEY
|
65
|
+
keys = STAT_KEYS.map do |key|
|
66
|
+
types.map { |type| "#{REDIS_NAMESPACE}:#{type}:#{key}" }
|
67
|
+
end.flatten
|
68
|
+
keys << TYPES_KEY
|
56
69
|
conn.del keys
|
57
70
|
end
|
58
71
|
|
@@ -50,6 +50,8 @@ module Sidekiq
|
|
50
50
|
self[name] ||= 0.0
|
51
51
|
self[name] += t1 - t0
|
52
52
|
|
53
|
+
Sidekiq.logger.info "Benchmark #{name}: #{t1 - t0} sec." if @options[:log]
|
54
|
+
|
53
55
|
ret
|
54
56
|
end
|
55
57
|
alias_method :bm, :measure
|
@@ -68,8 +70,8 @@ module Sidekiq
|
|
68
70
|
|
69
71
|
def set_redis_key(key)
|
70
72
|
Sidekiq.redis do |conn|
|
71
|
-
conn.sadd
|
72
|
-
conn.expire
|
73
|
+
conn.sadd TYPES_KEY, key
|
74
|
+
conn.expire TYPES_KEY, REDIS_KEYS_TTL
|
73
75
|
end
|
74
76
|
end
|
75
77
|
|
data/sidekiq-benchmark.gemspec
CHANGED
@@ -13,14 +13,14 @@ Gem::Specification.new do |gem|
|
|
13
13
|
gem.homepage = "https://github.com/kosmatov/sidekiq-benchmark/"
|
14
14
|
gem.license = 'MIT'
|
15
15
|
|
16
|
-
gem.files = `git ls-files | grep -Ev '^(examples)'`.split("\n")
|
16
|
+
gem.files = `git ls-files | grep -Ev '^(examples|vendor|docker|.travis|Makefile)'`.split("\n")
|
17
17
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
18
18
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
19
19
|
gem.require_paths = ["lib"]
|
20
20
|
|
21
|
-
gem.add_dependency "chartkick",
|
21
|
+
gem.add_dependency "chartkick", ">= 1.1.1"
|
22
|
+
gem.add_dependency "sidekiq", "> 5"
|
22
23
|
|
23
|
-
gem.add_development_dependency "sidekiq"
|
24
24
|
gem.add_development_dependency "rake"
|
25
25
|
gem.add_development_dependency "rack-test"
|
26
26
|
gem.add_development_dependency "minitest", "~> 5"
|
data/test/lib/testing.rb
CHANGED
@@ -12,12 +12,12 @@ class Sidekiq::Benchmark::TestingTest < Minitest::Spec
|
|
12
12
|
it "save nothing to redis" do
|
13
13
|
Sidekiq.redis do |conn|
|
14
14
|
total_time = conn.hget(@worker.benchmark.redis_keys[:total], :job_time)
|
15
|
-
total_time.must_be_nil
|
15
|
+
_(total_time).must_be_nil
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
19
|
it "run code in bm blocks" do
|
20
|
-
@worker.counter.wont_equal 0
|
20
|
+
_(@worker.counter).wont_equal 0
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
data/test/lib/web_test.rb
CHANGED
@@ -14,33 +14,38 @@ module Sidekiq
|
|
14
14
|
Test.flush_db
|
15
15
|
end
|
16
16
|
|
17
|
-
it "
|
17
|
+
it "display index without stats" do
|
18
18
|
get '/benchmarks'
|
19
|
-
last_response.status.must_equal 200
|
19
|
+
_(last_response.status).must_equal 200
|
20
20
|
end
|
21
21
|
|
22
|
-
it "
|
22
|
+
it "display index with stats" do
|
23
23
|
WorkerMock.new
|
24
24
|
|
25
25
|
get '/benchmarks'
|
26
|
-
last_response.status.must_equal 200
|
26
|
+
_(last_response.status).must_equal 200
|
27
27
|
end
|
28
28
|
|
29
|
-
it "
|
29
|
+
it "remove all benchmarks data" do
|
30
30
|
WorkerMock.new
|
31
31
|
|
32
|
-
Sidekiq.redis
|
33
|
-
keys = conn.keys "benchmark:*"
|
34
|
-
keys.wont_be_empty
|
35
|
-
end
|
32
|
+
Sidekiq.redis { |conn| _(conn.keys("benchmark:*")).wont_be_empty }
|
36
33
|
|
37
|
-
post '/benchmarks/
|
38
|
-
last_response.status.must_equal 302
|
34
|
+
post '/benchmarks/remove_all'
|
35
|
+
_(last_response.status).must_equal 302
|
39
36
|
|
40
|
-
Sidekiq.redis
|
41
|
-
|
42
|
-
|
43
|
-
|
37
|
+
Sidekiq.redis { |conn| _(conn.keys("benchmark:*")).must_be_empty }
|
38
|
+
end
|
39
|
+
|
40
|
+
it "remove benchmark data" do
|
41
|
+
WorkerMock.new
|
42
|
+
|
43
|
+
Sidekiq.redis { |conn| _(conn.keys("benchmark:sidekiq_benchmark_test_workermock:*")).wont_be_empty }
|
44
|
+
|
45
|
+
post '/benchmarks/remove', type: :sidekiq_benchmark_test_workermock
|
46
|
+
_(last_response.status).must_equal 302
|
47
|
+
|
48
|
+
Sidekiq.redis { |conn| _(conn.keys("benchmark:sidekiq_benchmark_test_workermock:*")).must_be_empty }
|
44
49
|
end
|
45
50
|
end
|
46
51
|
end
|
data/test/lib/worker_test.rb
CHANGED
@@ -16,12 +16,12 @@ module Sidekiq
|
|
16
16
|
metrics = @worker.benchmark.metrics
|
17
17
|
|
18
18
|
@worker.metric_names.each do |metric_name|
|
19
|
-
metrics[metric_name].wont_be_nil
|
19
|
+
_(metrics[metric_name]).wont_be_nil
|
20
20
|
end
|
21
21
|
|
22
|
-
@worker.benchmark.start_time.wont_be_nil
|
23
|
-
@worker.benchmark.finish_time.wont_be_nil
|
24
|
-
metrics[:assigned_metric].must_equal @worker.assigned_metric
|
22
|
+
_(@worker.benchmark.start_time).wont_be_nil
|
23
|
+
_(@worker.benchmark.finish_time).wont_be_nil
|
24
|
+
_(metrics[:assigned_metric]).must_equal @worker.assigned_metric
|
25
25
|
end
|
26
26
|
|
27
27
|
it 'should add up metrics' do
|
@@ -34,10 +34,10 @@ module Sidekiq
|
|
34
34
|
it "should save metrics to redis" do
|
35
35
|
Sidekiq.redis do |conn|
|
36
36
|
total_time = conn.hget(@worker.benchmark.redis_keys[:total], :job_time)
|
37
|
-
total_time.wont_be_nil
|
37
|
+
_(total_time).wont_be_nil
|
38
38
|
|
39
39
|
metrics = conn.hkeys(@worker.benchmark.redis_keys[:stats])
|
40
|
-
metrics.wont_be_empty
|
40
|
+
_(metrics).wont_be_empty
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
@@ -47,20 +47,20 @@ module Sidekiq
|
|
47
47
|
|
48
48
|
Sidekiq.redis do |conn|
|
49
49
|
metric_set = conn.hkeys(worker.benchmark.redis_keys[:stats])
|
50
|
-
metric_set.must_be_empty
|
50
|
+
_(metric_set).must_be_empty
|
51
51
|
end
|
52
52
|
|
53
53
|
worker.metric_names.each do |metric_name|
|
54
|
-
metrics[metric_name].wont_be_nil
|
54
|
+
_(metrics[metric_name]).wont_be_nil
|
55
55
|
end
|
56
56
|
|
57
|
-
worker.benchmark.finish_time.must_be_nil
|
57
|
+
_(worker.benchmark.finish_time).must_be_nil
|
58
58
|
worker.finish
|
59
|
-
worker.benchmark.finish_time.wont_be_nil
|
59
|
+
_(worker.benchmark.finish_time).wont_be_nil
|
60
60
|
|
61
61
|
Sidekiq.redis do |conn|
|
62
62
|
metric_set = conn.hkeys(worker.benchmark.redis_keys[:stats])
|
63
|
-
metric_set.wont_be_empty
|
63
|
+
_(metric_set).wont_be_empty
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
@@ -68,8 +68,8 @@ module Sidekiq
|
|
68
68
|
worker = AlterWorkerMock.new
|
69
69
|
value = worker.benchmark.call(:multiply, 4, 4)
|
70
70
|
|
71
|
-
value.must_equal 16
|
72
|
-
worker.benchmark.metrics[:multiply].wont_be_nil
|
71
|
+
_(value).must_equal 16
|
72
|
+
_(worker.benchmark.metrics[:multiply]).wont_be_nil
|
73
73
|
end
|
74
74
|
|
75
75
|
end
|
data/test/test_helper.rb
CHANGED
@@ -18,7 +18,7 @@ require 'sidekiq-benchmark'
|
|
18
18
|
require 'delorean'
|
19
19
|
require 'pry'
|
20
20
|
|
21
|
-
REDIS = Sidekiq::RedisConnection.create url: "redis
|
21
|
+
REDIS = Sidekiq::RedisConnection.create url: "redis://#{ENV['REDIS_HOST'] || 'localhost'}/15"
|
22
22
|
Bundler.require
|
23
23
|
|
24
24
|
module Sidekiq
|
@@ -1,31 +1,37 @@
|
|
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
|
-
*
|
5
|
+
* v3.2.1
|
6
6
|
* MIT License
|
7
7
|
*/
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
(
|
13
|
-
|
14
|
-
|
15
|
-
// 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';
|
16
14
|
|
17
15
|
function isArray(variable) {
|
18
16
|
return Object.prototype.toString.call(variable) === "[object Array]";
|
19
17
|
}
|
20
18
|
|
19
|
+
function isFunction(variable) {
|
20
|
+
return variable instanceof Function;
|
21
|
+
}
|
22
|
+
|
21
23
|
function isPlainObject(variable) {
|
22
|
-
|
24
|
+
// protect against prototype pollution, defense 2
|
25
|
+
return Object.prototype.toString.call(variable) === "[object Object]" && !isFunction(variable) && variable instanceof Object;
|
23
26
|
}
|
24
27
|
|
25
28
|
// https://github.com/madrobby/zepto/blob/master/src/zepto.js
|
26
29
|
function extend(target, source) {
|
27
30
|
var key;
|
28
31
|
for (key in source) {
|
32
|
+
// protect against prototype pollution, defense 1
|
33
|
+
if (key === "__proto__") { continue; }
|
34
|
+
|
29
35
|
if (isPlainObject(source[key]) || isArray(source[key])) {
|
30
36
|
if (isPlainObject(source[key]) && !isPlainObject(target[key])) {
|
31
37
|
target[key] = {};
|
@@ -34,8 +40,7 @@
|
|
34
40
|
target[key] = [];
|
35
41
|
}
|
36
42
|
extend(target[key], source[key]);
|
37
|
-
}
|
38
|
-
else if (source[key] !== undefined) {
|
43
|
+
} else if (source[key] !== undefined) {
|
39
44
|
target[key] = source[key];
|
40
45
|
}
|
41
46
|
}
|
@@ -48,20 +53,23 @@
|
|
48
53
|
return target;
|
49
54
|
}
|
50
55
|
|
56
|
+
var DATE_PATTERN = /^(\d\d\d\d)(-)?(\d\d)(-)?(\d\d)$/i;
|
57
|
+
|
51
58
|
// https://github.com/Do/iso8601.js
|
52
|
-
var ISO8601_PATTERN = /(\d\d\d\d)(
|
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;
|
53
60
|
var DECIMAL_SEPARATOR = String(1.5).charAt(1);
|
54
61
|
|
55
62
|
function parseISO8601(input) {
|
56
63
|
var day, hour, matches, milliseconds, minutes, month, offset, result, seconds, type, year;
|
57
64
|
type = Object.prototype.toString.call(input);
|
58
|
-
if (type ===
|
65
|
+
if (type === "[object Date]") {
|
59
66
|
return input;
|
60
67
|
}
|
61
|
-
if (type !==
|
68
|
+
if (type !== "[object String]") {
|
62
69
|
return;
|
63
70
|
}
|
64
|
-
|
71
|
+
matches = input.match(ISO8601_PATTERN);
|
72
|
+
if (matches) {
|
65
73
|
year = parseInt(matches[1], 10);
|
66
74
|
month = parseInt(matches[3], 10) - 1;
|
67
75
|
day = parseInt(matches[5], 10);
|
@@ -75,7 +83,7 @@
|
|
75
83
|
if (matches[17]) {
|
76
84
|
offset += parseInt(matches[17], 10);
|
77
85
|
}
|
78
|
-
offset *= matches[14] ===
|
86
|
+
offset *= matches[14] === "-" ? -1 : 1;
|
79
87
|
result -= offset * 60 * 1000;
|
80
88
|
}
|
81
89
|
return new Date(result);
|
@@ -96,29 +104,92 @@
|
|
96
104
|
return false;
|
97
105
|
}
|
98
106
|
|
99
|
-
function
|
100
|
-
return
|
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
|
+
|
151
|
+
function jsOptionsFunc(defaultOptions, hideLegend, setTitle, setMin, setMax, setStacked, setXtitle, setYtitle) {
|
152
|
+
return function (chart, opts, chartOptions) {
|
153
|
+
var series = chart.data;
|
101
154
|
var options = merge({}, defaultOptions);
|
155
|
+
options = merge(options, chartOptions || {});
|
156
|
+
|
157
|
+
if (chart.hideLegend || "legend" in opts) {
|
158
|
+
hideLegend(options, opts.legend, chart.hideLegend);
|
159
|
+
}
|
102
160
|
|
103
|
-
|
104
|
-
|
105
|
-
if (opts.hideLegend) {
|
106
|
-
hideLegend(options);
|
161
|
+
if (opts.title) {
|
162
|
+
setTitle(options, opts.title);
|
107
163
|
}
|
108
164
|
|
109
165
|
// min
|
110
166
|
if ("min" in opts) {
|
111
167
|
setMin(options, opts.min);
|
112
|
-
}
|
113
|
-
else if (!negativeValues(series)) {
|
168
|
+
} else if (!negativeValues(series)) {
|
114
169
|
setMin(options, 0);
|
115
170
|
}
|
116
171
|
|
117
172
|
// max
|
118
|
-
if (
|
173
|
+
if (opts.max) {
|
119
174
|
setMax(options, opts.max);
|
120
175
|
}
|
121
176
|
|
177
|
+
if ("stacked" in opts) {
|
178
|
+
setStacked(options, opts.stacked);
|
179
|
+
}
|
180
|
+
|
181
|
+
if (opts.colors) {
|
182
|
+
options.colors = opts.colors;
|
183
|
+
}
|
184
|
+
|
185
|
+
if (opts.xtitle) {
|
186
|
+
setXtitle(options, opts.xtitle);
|
187
|
+
}
|
188
|
+
|
189
|
+
if (opts.ytitle) {
|
190
|
+
setYtitle(options, opts.ytitle);
|
191
|
+
}
|
192
|
+
|
122
193
|
// merge library last
|
123
194
|
options = merge(options, opts.library || {});
|
124
195
|
|
@@ -126,422 +197,2268 @@
|
|
126
197
|
};
|
127
198
|
}
|
128
199
|
|
129
|
-
|
130
|
-
|
200
|
+
function sortByTime(a, b) {
|
201
|
+
return a[0].getTime() - b[0].getTime();
|
202
|
+
}
|
203
|
+
|
204
|
+
function sortByNumberSeries(a, b) {
|
205
|
+
return a[0] - b[0];
|
206
|
+
}
|
207
|
+
|
208
|
+
function sortByNumber(a, b) {
|
209
|
+
return a - b;
|
210
|
+
}
|
211
|
+
|
212
|
+
function isMinute(d) {
|
213
|
+
return d.getMilliseconds() === 0 && d.getSeconds() === 0;
|
214
|
+
}
|
215
|
+
|
216
|
+
function isHour(d) {
|
217
|
+
return isMinute(d) && d.getMinutes() === 0;
|
218
|
+
}
|
219
|
+
|
220
|
+
function isDay(d) {
|
221
|
+
return isHour(d) && d.getHours() === 0;
|
222
|
+
}
|
223
|
+
|
224
|
+
function isWeek(d, dayOfWeek) {
|
225
|
+
return isDay(d) && d.getDay() === dayOfWeek;
|
226
|
+
}
|
227
|
+
|
228
|
+
function isMonth(d) {
|
229
|
+
return isDay(d) && d.getDate() === 1;
|
230
|
+
}
|
231
|
+
|
232
|
+
function isYear(d) {
|
233
|
+
return isMonth(d) && d.getMonth() === 0;
|
234
|
+
}
|
235
|
+
|
236
|
+
function isDate(obj) {
|
237
|
+
return !isNaN(toDate(obj)) && toStr(obj).length >= 6;
|
238
|
+
}
|
239
|
+
|
240
|
+
function isNumber(obj) {
|
241
|
+
return typeof obj === "number";
|
242
|
+
}
|
243
|
+
|
244
|
+
var byteSuffixes = ["bytes", "KB", "MB", "GB", "TB", "PB", "EB"];
|
245
|
+
|
246
|
+
function formatValue(pre, value, options, axis) {
|
247
|
+
pre = pre || "";
|
248
|
+
if (options.prefix) {
|
249
|
+
if (value < 0) {
|
250
|
+
value = value * -1;
|
251
|
+
pre += "-";
|
252
|
+
}
|
253
|
+
pre += options.prefix;
|
254
|
+
}
|
131
255
|
|
132
|
-
|
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
|
+
}
|
133
285
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
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;
|
139
292
|
}
|
140
293
|
}
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
294
|
+
precision = value >= 1000 ? 4 : 3;
|
295
|
+
}
|
296
|
+
suffix = " " + byteSuffixes[suffixIdx];
|
297
|
+
}
|
298
|
+
|
299
|
+
if (precision !== undefined && round !== undefined) {
|
300
|
+
throw Error("Use either round or precision, not both");
|
301
|
+
}
|
302
|
+
|
303
|
+
if (!axis) {
|
304
|
+
if (precision !== undefined) {
|
305
|
+
value = value.toPrecision(precision);
|
306
|
+
if (!options.zeros) {
|
307
|
+
value = parseFloat(value);
|
150
308
|
}
|
151
|
-
}
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
style: {
|
163
|
-
fontSize: "12px"
|
309
|
+
}
|
310
|
+
|
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
|
+
}
|
164
320
|
}
|
165
321
|
}
|
166
|
-
}
|
322
|
+
}
|
167
323
|
|
168
|
-
|
169
|
-
|
170
|
-
|
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
|
+
}
|
171
335
|
|
172
|
-
|
173
|
-
|
174
|
-
};
|
336
|
+
return pre + value + suffix;
|
337
|
+
}
|
175
338
|
|
176
|
-
|
177
|
-
|
178
|
-
|
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];
|
344
|
+
}
|
345
|
+
return null;
|
346
|
+
}
|
179
347
|
|
180
|
-
|
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;
|
355
|
+
}
|
356
|
+
}
|
357
|
+
}
|
358
|
+
return true;
|
359
|
+
}
|
181
360
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
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
|
+
};
|
186
371
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
372
|
+
var defaultOptions = {
|
373
|
+
scales: {
|
374
|
+
yAxes: [
|
375
|
+
{
|
376
|
+
ticks: {
|
377
|
+
maxTicksLimit: 4
|
378
|
+
},
|
379
|
+
scaleLabel: {
|
380
|
+
fontSize: 16,
|
381
|
+
// fontStyle: "bold",
|
382
|
+
fontColor: "#333"
|
383
|
+
}
|
384
|
+
}
|
385
|
+
],
|
386
|
+
xAxes: [
|
387
|
+
{
|
388
|
+
gridLines: {
|
389
|
+
drawOnChartArea: false
|
390
|
+
},
|
391
|
+
scaleLabel: {
|
392
|
+
fontSize: 16,
|
393
|
+
// fontStyle: "bold",
|
394
|
+
fontColor: "#333"
|
395
|
+
},
|
396
|
+
time: {},
|
397
|
+
ticks: {}
|
191
398
|
}
|
192
|
-
|
399
|
+
]
|
400
|
+
}
|
401
|
+
};
|
402
|
+
|
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;
|
193
415
|
}
|
194
|
-
|
195
|
-
|
196
|
-
}
|
416
|
+
} else if (hideLegend) {
|
417
|
+
options.legend.display = false;
|
418
|
+
}
|
419
|
+
};
|
197
420
|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
type: "pie",
|
203
|
-
name: "Value",
|
204
|
-
data: series
|
205
|
-
}];
|
206
|
-
new Highcharts.Chart(options);
|
207
|
-
};
|
421
|
+
var setTitle = function (options, title) {
|
422
|
+
options.title.display = true;
|
423
|
+
options.title.text = title;
|
424
|
+
};
|
208
425
|
|
209
|
-
|
210
|
-
|
211
|
-
options.
|
426
|
+
var setMin = function (options, min) {
|
427
|
+
if (min !== null) {
|
428
|
+
options.scales.yAxes[0].ticks.min = toFloat(min);
|
429
|
+
}
|
430
|
+
};
|
212
431
|
|
213
|
-
|
214
|
-
|
432
|
+
var setMax = function (options, max) {
|
433
|
+
options.scales.yAxes[0].ticks.max = toFloat(max);
|
434
|
+
};
|
215
435
|
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
436
|
+
var setBarMin = function (options, min) {
|
437
|
+
if (min !== null) {
|
438
|
+
options.scales.xAxes[0].ticks.min = toFloat(min);
|
439
|
+
}
|
440
|
+
};
|
441
|
+
|
442
|
+
var setBarMax = function (options, max) {
|
443
|
+
options.scales.xAxes[0].ticks.max = toFloat(max);
|
444
|
+
};
|
445
|
+
|
446
|
+
var setStacked = function (options, stacked) {
|
447
|
+
options.scales.xAxes[0].stacked = !!stacked;
|
448
|
+
options.scales.yAxes[0].stacked = !!stacked;
|
449
|
+
};
|
224
450
|
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
451
|
+
var setXtitle = function (options, title) {
|
452
|
+
options.scales.xAxes[0].scaleLabel.display = true;
|
453
|
+
options.scales.xAxes[0].scaleLabel.labelString = title;
|
454
|
+
};
|
455
|
+
|
456
|
+
var setYtitle = function (options, title) {
|
457
|
+
options.scales.yAxes[0].scaleLabel.display = true;
|
458
|
+
options.scales.yAxes[0].scaleLabel.labelString = title;
|
459
|
+
};
|
460
|
+
|
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
|
+
};
|
466
|
+
|
467
|
+
// check if not null or undefined
|
468
|
+
// https://stackoverflow.com/a/27757708/1177228
|
469
|
+
var notnull = function(x) {
|
470
|
+
return x != null;
|
471
|
+
};
|
472
|
+
|
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;
|
229
487
|
}
|
488
|
+
};
|
489
|
+
}
|
490
|
+
};
|
491
|
+
|
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
|
+
};
|
502
|
+
|
503
|
+
if (chart.options.bytes) {
|
504
|
+
var series = chart.data;
|
505
|
+
if (chartType === "pie") {
|
506
|
+
series = [{data: series}];
|
230
507
|
}
|
231
|
-
options.xAxis.categories = categories;
|
232
508
|
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
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];
|
516
|
+
}
|
238
517
|
}
|
518
|
+
}
|
239
519
|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
520
|
+
// calculate scale
|
521
|
+
var scale = 1;
|
522
|
+
while (max >= 1024) {
|
523
|
+
scale *= 1024;
|
524
|
+
max /= 1024;
|
244
525
|
}
|
245
|
-
options.series = newSeries;
|
246
526
|
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
// load from google
|
251
|
-
var loaded = false;
|
252
|
-
google.setOnLoadCallback(function() {
|
253
|
-
loaded = true;
|
254
|
-
});
|
255
|
-
google.load("visualization", "1.0", {"packages": ["corechart"]});
|
527
|
+
// set step size
|
528
|
+
formatOptions.byteScale = scale;
|
529
|
+
}
|
256
530
|
|
257
|
-
|
258
|
-
|
259
|
-
if (
|
260
|
-
|
531
|
+
if (chartType !== "pie") {
|
532
|
+
var myAxes = options.scales.yAxes;
|
533
|
+
if (chartType === "bar") {
|
534
|
+
myAxes = options.scales.xAxes;
|
261
535
|
}
|
262
|
-
};
|
263
536
|
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
fontSize: 12,
|
271
|
-
color: "#444"
|
272
|
-
},
|
273
|
-
alignment: "center",
|
274
|
-
position: "right"
|
275
|
-
},
|
276
|
-
curveType: "function",
|
277
|
-
hAxis: {
|
278
|
-
textStyle: {
|
279
|
-
color: "#666",
|
280
|
-
fontSize: 12
|
281
|
-
},
|
282
|
-
gridlines: {
|
283
|
-
color: "transparent"
|
284
|
-
},
|
285
|
-
baselineColor: "#ccc"
|
286
|
-
},
|
287
|
-
vAxis: {
|
288
|
-
textStyle: {
|
289
|
-
color: "#666",
|
290
|
-
fontSize: 12
|
291
|
-
},
|
292
|
-
baselineColor: "#ccc",
|
293
|
-
viewWindow: {}
|
294
|
-
},
|
295
|
-
tooltip: {
|
296
|
-
textStyle: {
|
297
|
-
color: "#666",
|
298
|
-
fontSize: 12
|
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;
|
299
543
|
}
|
300
544
|
}
|
301
|
-
};
|
302
545
|
|
303
|
-
|
304
|
-
|
305
|
-
|
546
|
+
if (!myAxes[0].ticks.callback) {
|
547
|
+
myAxes[0].ticks.callback = function (value) {
|
548
|
+
return formatValue("", value, formatOptions, true);
|
549
|
+
};
|
550
|
+
}
|
551
|
+
}
|
306
552
|
|
307
|
-
|
308
|
-
|
309
|
-
|
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 += ': ';
|
559
|
+
}
|
560
|
+
return label + '(' + item.xLabel + ', ' + item.yLabel + ')';
|
561
|
+
};
|
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 += ': ';
|
567
|
+
}
|
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;
|
582
|
+
} else {
|
583
|
+
dataLabel += value;
|
584
|
+
}
|
310
585
|
|
311
|
-
|
312
|
-
|
313
|
-
|
586
|
+
return formatValue(dataLabel, data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index], formatOptions);
|
587
|
+
};
|
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 += ': ';
|
594
|
+
}
|
595
|
+
return formatValue(label, tooltipItem[valueLabel], formatOptions);
|
596
|
+
};
|
597
|
+
}
|
598
|
+
}
|
599
|
+
};
|
600
|
+
|
601
|
+
var jsOptions = jsOptionsFunc(merge(baseOptions, defaultOptions), hideLegend, setTitle, setMin, setMax, setStacked, setXtitle, setYtitle);
|
602
|
+
|
603
|
+
var createDataTable = function (chart, options, chartType, library) {
|
604
|
+
var datasets = [];
|
605
|
+
var labels = [];
|
606
|
+
|
607
|
+
var colors = chart.options.colors || defaultColors;
|
608
|
+
|
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;
|
616
|
+
|
617
|
+
var series = chart.data;
|
618
|
+
|
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
|
+
}
|
314
630
|
|
315
|
-
var
|
631
|
+
var i, j, s, d, key, rows = [], rows2 = [];
|
316
632
|
|
317
|
-
|
318
|
-
|
319
|
-
var data = new google.visualization.DataTable();
|
320
|
-
data.addColumn(columnType, "");
|
633
|
+
if (chartType === "bar" || chartType === "column" || (chart.xtype !== "number" && chart.xtype !== "bubble")) {
|
634
|
+
var sortedLabels = [];
|
321
635
|
|
322
|
-
var i, j, s, d, key, rows = [];
|
323
636
|
for (i = 0; i < series.length; i++) {
|
324
637
|
s = series[i];
|
325
|
-
data.addColumn("number", s.name);
|
326
638
|
|
327
639
|
for (j = 0; j < s.data.length; j++) {
|
328
640
|
d = s.data[j];
|
329
|
-
key =
|
641
|
+
key = chart.xtype == "datetime" ? d[0].getTime() : d[0];
|
330
642
|
if (!rows[key]) {
|
331
643
|
rows[key] = new Array(series.length);
|
332
644
|
}
|
333
645
|
rows[key][i] = toFloat(d[1]);
|
646
|
+
if (sortedLabels.indexOf(key) === -1) {
|
647
|
+
sortedLabels.push(key);
|
648
|
+
}
|
334
649
|
}
|
335
650
|
}
|
336
651
|
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
652
|
+
if (chart.xtype === "datetime" || chart.xtype === "number") {
|
653
|
+
sortedLabels.sort(sortByNumber);
|
654
|
+
}
|
655
|
+
|
656
|
+
for (j = 0; j < series.length; j++) {
|
657
|
+
rows2.push([]);
|
658
|
+
}
|
659
|
+
|
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();
|
670
|
+
}
|
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]);
|
341
683
|
}
|
342
684
|
}
|
343
|
-
|
344
|
-
|
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);
|
345
702
|
}
|
703
|
+
}
|
346
704
|
|
347
|
-
|
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
|
+
};
|
721
|
+
|
722
|
+
if (s.stack) {
|
723
|
+
dataset.stack = s.stack;
|
724
|
+
}
|
348
725
|
|
349
|
-
|
350
|
-
|
726
|
+
var curve = seriesOption(chart, s, "curve");
|
727
|
+
if (curve === false) {
|
728
|
+
dataset.lineTension = 0;
|
729
|
+
}
|
351
730
|
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
chart.draw(data, options);
|
358
|
-
});
|
359
|
-
};
|
731
|
+
var points = seriesOption(chart, s, "points");
|
732
|
+
if (points === false) {
|
733
|
+
dataset.pointRadius = 0;
|
734
|
+
dataset.pointHitRadius = 5;
|
735
|
+
}
|
360
736
|
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
options.chartArea = {
|
365
|
-
top: "10%",
|
366
|
-
height: "80%"
|
367
|
-
};
|
737
|
+
dataset = merge(dataset, chart.options.dataset || {});
|
738
|
+
dataset = merge(dataset, s.library || {});
|
739
|
+
dataset = merge(dataset, s.dataset || {});
|
368
740
|
|
369
|
-
|
370
|
-
|
371
|
-
data.addColumn("number", "Value");
|
372
|
-
data.addRows(series);
|
741
|
+
datasets.push(dataset);
|
742
|
+
}
|
373
743
|
|
374
|
-
|
375
|
-
|
376
|
-
});
|
377
|
-
};
|
744
|
+
var xmin = chart.options.xmin;
|
745
|
+
var xmax = chart.options.xmax;
|
378
746
|
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
}
|
391
|
-
|
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
|
+
}
|
392
766
|
|
393
|
-
|
394
|
-
if (
|
395
|
-
|
396
|
-
|
397
|
-
|
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;
|
398
781
|
}
|
399
|
-
}
|
400
782
|
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
}
|
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();
|
405
786
|
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
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
|
+
}
|
414
795
|
}
|
415
|
-
});
|
416
|
-
}
|
417
796
|
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
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
|
+
}
|
819
|
+
|
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
|
+
}
|
828
|
+
|
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
|
+
}
|
839
|
+
|
840
|
+
var data = {
|
841
|
+
labels: labels,
|
842
|
+
datasets: datasets
|
843
|
+
};
|
844
|
+
|
845
|
+
return data;
|
846
|
+
};
|
847
|
+
|
848
|
+
var defaultExport = function defaultExport(library) {
|
849
|
+
this.name = "chartjs";
|
850
|
+
this.library = library;
|
851
|
+
};
|
852
|
+
|
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;
|
858
|
+
}
|
859
|
+
|
860
|
+
var options = jsOptions(chart, merge(chartOptions, chart.options));
|
861
|
+
setFormatOptions(chart, options, chartType);
|
862
|
+
|
863
|
+
var data = createDataTable(chart, options, chartType || "line", this.library);
|
864
|
+
|
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
|
+
}
|
871
|
+
|
872
|
+
this.drawChart(chart, "line", data, options);
|
873
|
+
};
|
874
|
+
|
875
|
+
defaultExport.prototype.renderPieChart = function renderPieChart (chart) {
|
876
|
+
var options = merge({}, baseOptions);
|
877
|
+
if (chart.options.donut) {
|
878
|
+
options.cutoutPercentage = 50;
|
879
|
+
}
|
880
|
+
|
881
|
+
if ("legend" in chart.options) {
|
882
|
+
hideLegend(options, chart.options.legend);
|
883
|
+
}
|
884
|
+
|
885
|
+
if (chart.options.title) {
|
886
|
+
setTitle(options, chart.options.title);
|
887
|
+
}
|
888
|
+
|
889
|
+
options = merge(options, chart.options.library || {});
|
890
|
+
setFormatOptions(chart, options, "pie");
|
891
|
+
|
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
|
+
}
|
899
|
+
|
900
|
+
var dataset = {
|
901
|
+
data: values,
|
902
|
+
backgroundColor: chart.options.colors || defaultColors
|
903
|
+
};
|
904
|
+
dataset = merge(dataset, chart.options.dataset || {});
|
905
|
+
|
906
|
+
var data = {
|
907
|
+
labels: labels,
|
908
|
+
datasets: [dataset]
|
909
|
+
};
|
910
|
+
|
911
|
+
this.drawChart(chart, "pie", data, options);
|
912
|
+
};
|
913
|
+
|
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
|
+
};
|
930
|
+
|
931
|
+
defaultExport.prototype.renderAreaChart = function renderAreaChart (chart) {
|
932
|
+
this.renderLineChart(chart, "area");
|
933
|
+
};
|
934
|
+
|
935
|
+
defaultExport.prototype.renderBarChart = function renderBarChart (chart) {
|
936
|
+
this.renderColumnChart(chart, "bar");
|
937
|
+
};
|
938
|
+
|
939
|
+
defaultExport.prototype.renderScatterChart = function renderScatterChart (chart, chartType) {
|
940
|
+
chartType = chartType || "scatter";
|
941
|
+
|
942
|
+
var options = jsOptions(chart, chart.options);
|
943
|
+
setFormatOptions(chart, options, chartType);
|
944
|
+
|
945
|
+
if (!("showLines" in options)) {
|
946
|
+
options.showLines = false;
|
947
|
+
}
|
948
|
+
|
949
|
+
var data = createDataTable(chart, options, chartType, this.library);
|
950
|
+
|
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
|
+
};
|
960
|
+
|
961
|
+
defaultExport.prototype.destroy = function destroy (chart) {
|
962
|
+
if (chart.chart) {
|
963
|
+
chart.chart.destroy();
|
964
|
+
}
|
965
|
+
};
|
966
|
+
|
967
|
+
defaultExport.prototype.drawChart = function drawChart (chart, type, data, options) {
|
968
|
+
this.destroy(chart);
|
969
|
+
|
970
|
+
var chartOptions = {
|
971
|
+
type: type,
|
972
|
+
data: data,
|
973
|
+
options: options
|
974
|
+
};
|
975
|
+
|
976
|
+
if (chart.options.code) {
|
977
|
+
window.console.log("new Chart(ctx, " + JSON.stringify(chartOptions) + ");");
|
978
|
+
}
|
979
|
+
|
980
|
+
chart.element.innerHTML = "<canvas></canvas>";
|
981
|
+
var ctx = chart.element.getElementsByTagName("CANVAS")[0];
|
982
|
+
chart.chart = new this.library(ctx, chartOptions);
|
983
|
+
};
|
984
|
+
|
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
|
+
};
|
1029
|
+
|
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
|
+
};
|
1046
|
+
|
1047
|
+
var setTitle$1 = function (options, title) {
|
1048
|
+
options.title.text = title;
|
1049
|
+
};
|
1050
|
+
|
1051
|
+
var setMin$1 = function (options, min) {
|
1052
|
+
options.yAxis.min = min;
|
1053
|
+
};
|
1054
|
+
|
1055
|
+
var setMax$1 = function (options, max) {
|
1056
|
+
options.yAxis.max = max;
|
1057
|
+
};
|
1058
|
+
|
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
|
+
};
|
1065
|
+
|
1066
|
+
var setXtitle$1 = function (options, title) {
|
1067
|
+
options.xAxis.title.text = title;
|
1068
|
+
};
|
1069
|
+
|
1070
|
+
var setYtitle$1 = function (options, title) {
|
1071
|
+
options.yAxis.title.text = title;
|
1072
|
+
};
|
1073
|
+
|
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
|
+
};
|
1086
|
+
|
1087
|
+
if (chartType !== "pie" && !options.yAxis.labels.formatter) {
|
1088
|
+
options.yAxis.labels.formatter = function () {
|
1089
|
+
return formatValue("", this.value, formatOptions);
|
1090
|
+
};
|
1091
|
+
}
|
1092
|
+
|
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
|
+
};
|
1099
|
+
|
1100
|
+
var defaultExport$1 = function defaultExport(library) {
|
1101
|
+
this.name = "highcharts";
|
1102
|
+
this.library = library;
|
1103
|
+
};
|
1104
|
+
|
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
|
+
}
|
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
|
+
}
|
1133
|
+
|
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;
|
424
1764
|
}
|
425
1765
|
}
|
426
1766
|
|
427
|
-
function fetchDataSource(
|
1767
|
+
function fetchDataSource(chart, dataSource) {
|
428
1768
|
if (typeof dataSource === "string") {
|
429
|
-
|
430
|
-
|
1769
|
+
pushRequest(dataSource, function (data) {
|
1770
|
+
chart.rawData = data;
|
1771
|
+
errorCatcher(chart);
|
1772
|
+
}, function (message) {
|
1773
|
+
chartError(chart.element, message);
|
431
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
|
+
}
|
432
1786
|
} else {
|
433
|
-
|
1787
|
+
chart.rawData = dataSource;
|
1788
|
+
errorCatcher(chart);
|
434
1789
|
}
|
435
1790
|
}
|
436
1791
|
|
437
|
-
|
1792
|
+
function addDownloadButton(chart) {
|
1793
|
+
var element = chart.element;
|
1794
|
+
var link = document.createElement("a");
|
438
1795
|
|
439
|
-
|
440
|
-
|
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";
|
1818
|
+
|
1819
|
+
chart.__downloadAttached = true;
|
1820
|
+
|
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
|
+
});
|
1830
|
+
|
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
|
+
});
|
441
1840
|
}
|
442
1841
|
|
443
|
-
|
444
|
-
|
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
|
+
}
|
445
1855
|
}
|
446
1856
|
|
447
|
-
function
|
448
|
-
if (
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
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
|
+
}
|
1864
|
+
|
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
|
+
}
|
1871
|
+
|
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;
|
456
1880
|
}
|
457
1881
|
}
|
458
|
-
|
1882
|
+
throw new Error("Unknown adapter");
|
459
1883
|
}
|
460
1884
|
|
461
|
-
function
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
1885
|
+
function addAdapter(library) {
|
1886
|
+
var adapterType = getAdapterType(library);
|
1887
|
+
var adapter = new adapterType(library);
|
1888
|
+
|
1889
|
+
if (adapters.indexOf(adapter) === -1) {
|
1890
|
+
adapters.push(adapter);
|
1891
|
+
}
|
1892
|
+
}
|
1893
|
+
|
1894
|
+
function loadAdapters() {
|
1895
|
+
if ("Chart" in window) {
|
1896
|
+
addAdapter(window.Chart);
|
1897
|
+
}
|
1898
|
+
|
1899
|
+
if ("Highcharts" in window) {
|
1900
|
+
addAdapter(window.Highcharts);
|
1901
|
+
}
|
1902
|
+
|
1903
|
+
if (window.google && window.google.charts) {
|
1904
|
+
addAdapter(window.google);
|
1905
|
+
}
|
1906
|
+
}
|
1907
|
+
|
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;
|
467
1915
|
}
|
468
1916
|
}
|
469
|
-
|
1917
|
+
return true;
|
470
1918
|
}
|
471
|
-
return n;
|
472
1919
|
}
|
473
1920
|
|
474
|
-
|
1921
|
+
function renderChart(chartType, 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
|
+
}
|
1929
|
+
}
|
1930
|
+
}
|
475
1931
|
|
476
|
-
|
477
|
-
|
1932
|
+
// TODO remove chartType if cross-browser way
|
1933
|
+
// to get the name of the chart class
|
1934
|
+
function callAdapter(chartType, chart) {
|
1935
|
+
var i, adapter, fnName, adapterName;
|
1936
|
+
fnName = "render" + chartType;
|
1937
|
+
adapterName = chart.options.adapter;
|
1938
|
+
|
1939
|
+
loadAdapters();
|
1940
|
+
|
1941
|
+
for (i = 0; i < adapters.length; i++) {
|
1942
|
+
adapter = adapters[i];
|
1943
|
+
if ((!adapterName || adapterName === adapter.name) && isFunction(adapter[fnName])) {
|
1944
|
+
chart.adapter = adapter.name;
|
1945
|
+
chart.__adapterObject = adapter;
|
1946
|
+
return adapter[fnName](chart);
|
1947
|
+
}
|
1948
|
+
}
|
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
|
+
}
|
478
1955
|
}
|
479
1956
|
|
480
|
-
|
481
|
-
var i, j, data, r, key;
|
1957
|
+
// process data
|
482
1958
|
|
483
|
-
|
484
|
-
if (
|
485
|
-
|
486
|
-
|
1959
|
+
var toFormattedKey = function (key, keyType) {
|
1960
|
+
if (keyType === "number") {
|
1961
|
+
key = toFloat(key);
|
1962
|
+
} else if (keyType === "datetime") {
|
1963
|
+
key = toDate(key);
|
487
1964
|
} else {
|
488
|
-
|
1965
|
+
key = toStr(key);
|
489
1966
|
}
|
1967
|
+
return key;
|
1968
|
+
};
|
490
1969
|
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
key =
|
1970
|
+
var formatSeriesData = function (data, keyType) {
|
1971
|
+
var r = [], key, j;
|
1972
|
+
for (j = 0; j < data.length; j++) {
|
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);
|
498
1977
|
r.push([key, toFloat(data[j][1])]);
|
499
1978
|
}
|
500
|
-
|
501
|
-
|
1979
|
+
}
|
1980
|
+
if (keyType === "datetime") {
|
1981
|
+
r.sort(sortByTime);
|
1982
|
+
} else if (keyType === "number") {
|
1983
|
+
r.sort(sortByNumberSeries);
|
1984
|
+
}
|
1985
|
+
return r;
|
1986
|
+
};
|
1987
|
+
|
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";
|
502
1994
|
}
|
503
|
-
|
1995
|
+
} else if (detectXTypeWithFunction(series, isNumber)) {
|
1996
|
+
return "number";
|
1997
|
+
} else if (!noDatetime && detectXTypeWithFunction(series, isDate)) {
|
1998
|
+
return "datetime";
|
1999
|
+
} else {
|
2000
|
+
return "string";
|
504
2001
|
}
|
2002
|
+
}
|
505
2003
|
|
506
|
-
|
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])) {
|
2010
|
+
return false;
|
2011
|
+
}
|
2012
|
+
}
|
2013
|
+
}
|
2014
|
+
return true;
|
507
2015
|
}
|
508
2016
|
|
509
|
-
|
510
|
-
|
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;
|
2021
|
+
for (i = 0; i < series.length; i++) {
|
2022
|
+
var copy = {};
|
2023
|
+
for (j in series[i]) {
|
2024
|
+
if (series[i].hasOwnProperty(j)) {
|
2025
|
+
copy[j] = series[i][j];
|
2026
|
+
}
|
2027
|
+
}
|
2028
|
+
newSeries.push(copy);
|
2029
|
+
}
|
2030
|
+
return newSeries;
|
511
2031
|
}
|
512
2032
|
|
513
|
-
function
|
514
|
-
|
2033
|
+
function processSeries(chart, keyType, noDatetime) {
|
2034
|
+
var i;
|
2035
|
+
|
2036
|
+
var opts = chart.options;
|
2037
|
+
var series = chart.rawData;
|
2038
|
+
|
2039
|
+
// see if one series or multiple
|
2040
|
+
if (!isArray(series) || typeof series[0] !== "object" || isArray(series[0])) {
|
2041
|
+
series = [{name: opts.label, data: series}];
|
2042
|
+
chart.hideLegend = true;
|
2043
|
+
} else {
|
2044
|
+
chart.hideLegend = false;
|
2045
|
+
}
|
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);
|
2052
|
+
}
|
2053
|
+
|
2054
|
+
chart.xtype = keyType ? keyType : (opts.discrete ? "string" : detectXType(series, noDatetime, opts));
|
2055
|
+
|
2056
|
+
// right format
|
2057
|
+
for (i = 0; i < series.length; i++) {
|
2058
|
+
series[i].data = formatSeriesData(series[i].data, chart.xtype);
|
2059
|
+
}
|
2060
|
+
|
2061
|
+
return series;
|
515
2062
|
}
|
516
2063
|
|
517
|
-
function
|
518
|
-
var perfectData = toArr(
|
2064
|
+
function processSimple(chart) {
|
2065
|
+
var perfectData = toArr(chart.rawData), i;
|
519
2066
|
for (i = 0; i < perfectData.length; i++) {
|
520
2067
|
perfectData[i] = [toStr(perfectData[i][0]), toFloat(perfectData[i][1])];
|
521
2068
|
}
|
522
|
-
|
2069
|
+
return perfectData;
|
523
2070
|
}
|
524
2071
|
|
525
|
-
|
2072
|
+
// define classes
|
2073
|
+
|
2074
|
+
var Chart = function Chart(element, dataSource, options) {
|
2075
|
+
var elementId;
|
526
2076
|
if (typeof element === "string") {
|
2077
|
+
elementId = element;
|
527
2078
|
element = document.getElementById(element);
|
2079
|
+
if (!element) {
|
2080
|
+
throw new Error("No element with id " + elementId);
|
2081
|
+
}
|
528
2082
|
}
|
529
|
-
|
530
|
-
|
2083
|
+
this.element = element;
|
2084
|
+
this.options = merge(Chartkick.options, options || {});
|
2085
|
+
this.dataSource = dataSource;
|
531
2086
|
|
532
|
-
|
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
|
+
};
|
2167
|
+
|
2168
|
+
Chart.prototype.stopRefresh = function stopRefresh () {
|
2169
|
+
if (this.intervalId) {
|
2170
|
+
clearInterval(this.intervalId);
|
2171
|
+
this.intervalId = null;
|
2172
|
+
}
|
2173
|
+
};
|
2174
|
+
|
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();
|
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);
|
2254
|
+
}
|
2255
|
+
|
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);
|
2262
|
+
};
|
2263
|
+
|
2264
|
+
PieChart.prototype.__chartName = function __chartName () {
|
2265
|
+
return "PieChart";
|
2266
|
+
};
|
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);
|
2282
|
+
};
|
2283
|
+
|
2284
|
+
ColumnChart.prototype.__chartName = function __chartName () {
|
2285
|
+
return "ColumnChart";
|
2286
|
+
};
|
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);
|
2302
|
+
};
|
2303
|
+
|
2304
|
+
BarChart.prototype.__chartName = function __chartName () {
|
2305
|
+
return "BarChart";
|
2306
|
+
};
|
2307
|
+
|
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);
|
2322
|
+
};
|
2323
|
+
|
2324
|
+
AreaChart.prototype.__chartName = function __chartName () {
|
2325
|
+
return "AreaChart";
|
2326
|
+
};
|
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);
|
2342
|
+
};
|
2343
|
+
|
2344
|
+
GeoChart.prototype.__chartName = function __chartName () {
|
2345
|
+
return "GeoChart";
|
2346
|
+
};
|
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");
|
2362
|
+
};
|
2363
|
+
|
2364
|
+
ScatterChart.prototype.__chartName = function __chartName () {
|
2365
|
+
return "ScatterChart";
|
2366
|
+
};
|
2367
|
+
|
2368
|
+
return ScatterChart;
|
2369
|
+
}(Chart));
|
2370
|
+
|
2371
|
+
var BubbleChart = /*@__PURE__*/(function (Chart) {
|
2372
|
+
function BubbleChart () {
|
2373
|
+
Chart.apply(this, arguments);
|
2374
|
+
}
|
2375
|
+
|
2376
|
+
if ( Chart ) BubbleChart.__proto__ = Chart;
|
2377
|
+
BubbleChart.prototype = Object.create( Chart && Chart.prototype );
|
2378
|
+
BubbleChart.prototype.constructor = BubbleChart;
|
2379
|
+
|
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));
|
2390
|
+
|
2391
|
+
var Timeline = /*@__PURE__*/(function (Chart) {
|
2392
|
+
function Timeline () {
|
2393
|
+
Chart.apply(this, arguments);
|
2394
|
+
}
|
2395
|
+
|
2396
|
+
if ( Chart ) Timeline.__proto__ = Chart;
|
2397
|
+
Timeline.prototype = Object.create( Chart && Chart.prototype );
|
2398
|
+
Timeline.prototype.constructor = Timeline;
|
2399
|
+
|
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));
|
533
2415
|
|
534
2416
|
var Chartkick = {
|
535
|
-
LineChart:
|
536
|
-
|
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,
|
2426
|
+
charts: {},
|
2427
|
+
configure: function (options) {
|
2428
|
+
for (var key in options) {
|
2429
|
+
if (options.hasOwnProperty(key)) {
|
2430
|
+
config[key] = options[key];
|
2431
|
+
}
|
2432
|
+
}
|
2433
|
+
},
|
2434
|
+
setDefaultOptions: function (opts) {
|
2435
|
+
Chartkick.options = opts;
|
537
2436
|
},
|
538
|
-
|
539
|
-
|
2437
|
+
eachChart: function (callback) {
|
2438
|
+
for (var chartId in Chartkick.charts) {
|
2439
|
+
if (Chartkick.charts.hasOwnProperty(chartId)) {
|
2440
|
+
callback(Chartkick.charts[chartId]);
|
2441
|
+
}
|
2442
|
+
}
|
540
2443
|
},
|
541
|
-
|
542
|
-
|
2444
|
+
config: config,
|
2445
|
+
options: {},
|
2446
|
+
adapters: adapters,
|
2447
|
+
addAdapter: addAdapter,
|
2448
|
+
use: function(adapter) {
|
2449
|
+
addAdapter(adapter);
|
2450
|
+
return Chartkick;
|
543
2451
|
}
|
544
2452
|
};
|
545
2453
|
|
546
|
-
|
547
|
-
|
2454
|
+
// not ideal, but allows for simpler integration
|
2455
|
+
if (typeof window !== "undefined" && !window.Chartkick) {
|
2456
|
+
window.Chartkick = Chartkick;
|
2457
|
+
}
|
2458
|
+
|
2459
|
+
// backwards compatibility for esm require
|
2460
|
+
Chartkick.default = Chartkick;
|
2461
|
+
|
2462
|
+
return Chartkick;
|
2463
|
+
|
2464
|
+
})));
|