my_chart 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +79 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/mychart.js +7 -0
- data/lib/my_chart.rb +65 -0
- data/lib/my_chart/charts/bar.rb +21 -0
- data/lib/my_chart/charts/doughnut.rb +7 -0
- data/lib/my_chart/charts/line.rb +17 -0
- data/lib/my_chart/charts/pie.rb +7 -0
- data/lib/my_chart/charts/plain_bar.rb +23 -0
- data/lib/my_chart/charts/polar_area.rb +9 -0
- data/lib/my_chart/charts/radar.rb +11 -0
- data/lib/my_chart/dsl/draw.rb +84 -0
- data/lib/my_chart/dsl/group.rb +15 -0
- data/lib/my_chart/dsl/material.rb +31 -0
- data/lib/my_chart/dsl/output.rb +27 -0
- data/lib/my_chart/helper/string.rb +13 -0
- data/lib/my_chart/proto.rb +127 -0
- data/lib/my_chart/rainbow.rb +39 -0
- data/lib/my_chart/tmpl.htm +12 -0
- data/lib/my_chart/type.rb +58 -0
- data/lib/my_chart/version.rb +3 -0
- data/lib/my_chart/x.rb +26 -0
- data/lib/my_chart/xy.rb +65 -0
- data/lib/my_chart/xyz.rb +38 -0
- data/my_chart.gemspec +26 -0
- metadata +119 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 206a10290af6ef9daf732af64ee651259864b6ba
|
4
|
+
data.tar.gz: 8c6c03cf3a2d5ae9dd4db5f25f25ca1b02fefa0f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 95d4d4d3be5597f5d40c8ad7367ab2c6c7a4609f1592bf8dcc0f7935bfd23432b3d15f9f1d618c1a8589bc7611c1a0d8a1810cc6fad5f421c0719f1b1f795c37
|
7
|
+
data.tar.gz: 7a1c500c480e6050c964d01c2c777b64058f1c9a494c21e1192435351f0c981c785e898391c974cb2ff1cac9d89c4384075690aa1bf6402e44a1c54d3e86c073
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
2
|
+
|
3
|
+
## Our Pledge
|
4
|
+
|
5
|
+
In the interest of fostering an open and welcoming environment, we as
|
6
|
+
contributors and maintainers pledge to making participation in our project and
|
7
|
+
our community a harassment-free experience for everyone, regardless of age, body
|
8
|
+
size, disability, ethnicity, gender identity and expression, level of experience,
|
9
|
+
nationality, personal appearance, race, religion, or sexual identity and
|
10
|
+
orientation.
|
11
|
+
|
12
|
+
## Our Standards
|
13
|
+
|
14
|
+
Examples of behavior that contributes to creating a positive environment
|
15
|
+
include:
|
16
|
+
|
17
|
+
* Using welcoming and inclusive language
|
18
|
+
* Being respectful of differing viewpoints and experiences
|
19
|
+
* Gracefully accepting constructive criticism
|
20
|
+
* Focusing on what is best for the community
|
21
|
+
* Showing empathy towards other community members
|
22
|
+
|
23
|
+
Examples of unacceptable behavior by participants include:
|
24
|
+
|
25
|
+
* The use of sexualized language or imagery and unwelcome sexual attention or
|
26
|
+
advances
|
27
|
+
* Trolling, insulting/derogatory comments, and personal or political attacks
|
28
|
+
* Public or private harassment
|
29
|
+
* Publishing others' private information, such as a physical or electronic
|
30
|
+
address, without explicit permission
|
31
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
32
|
+
professional setting
|
33
|
+
|
34
|
+
## Our Responsibilities
|
35
|
+
|
36
|
+
Project maintainers are responsible for clarifying the standards of acceptable
|
37
|
+
behavior and are expected to take appropriate and fair corrective action in
|
38
|
+
response to any instances of unacceptable behavior.
|
39
|
+
|
40
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
41
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
42
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
43
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
44
|
+
threatening, offensive, or harmful.
|
45
|
+
|
46
|
+
## Scope
|
47
|
+
|
48
|
+
This Code of Conduct applies both within project spaces and in public spaces
|
49
|
+
when an individual is representing the project or its community. Examples of
|
50
|
+
representing a project or community include using an official project e-mail
|
51
|
+
address, posting via an official social media account, or acting as an appointed
|
52
|
+
representative at an online or offline event. Representation of a project may be
|
53
|
+
further defined and clarified by project maintainers.
|
54
|
+
|
55
|
+
## Enforcement
|
56
|
+
|
57
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
58
|
+
reported by contacting the project team at block24block@gmail.com. All
|
59
|
+
complaints will be reviewed and investigated and will result in a response that
|
60
|
+
is deemed necessary and appropriate to the circumstances. The project team is
|
61
|
+
obligated to maintain confidentiality with regard to the reporter of an incident.
|
62
|
+
Further details of specific enforcement policies may be posted separately.
|
63
|
+
|
64
|
+
Project maintainers who do not follow or enforce the Code of Conduct in good
|
65
|
+
faith may face temporary or permanent repercussions as determined by other
|
66
|
+
members of the project's leadership.
|
67
|
+
|
68
|
+
## Attribution
|
69
|
+
|
70
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
71
|
+
available at [http://contributor-covenant.org/version/1/4][version]
|
72
|
+
|
73
|
+
[homepage]: http://contributor-covenant.org
|
74
|
+
[version]: http://contributor-covenant.org/version/1/4/
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2017 ken
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
# MyChart.js
|
2
|
+
|
3
|
+
generate chart.js html with ruby
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'my_chart'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install my_chart
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
suppose you want to have some statistic on mail files:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
MyChart.js do
|
27
|
+
|
28
|
+
material do
|
29
|
+
# load mail objects here
|
30
|
+
end
|
31
|
+
|
32
|
+
select :fail do |m|
|
33
|
+
m.fail?
|
34
|
+
end
|
35
|
+
|
36
|
+
line :day, :fail?, w: 1280, h: 500, asc: :key
|
37
|
+
|
38
|
+
bar :day, w: 1280, h: 500
|
39
|
+
|
40
|
+
bar :day, w: 1280, h: 500, from: :fail
|
41
|
+
|
42
|
+
output './mail_statistic.htm'
|
43
|
+
end
|
44
|
+
```
|
45
|
+
|
46
|
+
execute the script:
|
47
|
+
|
48
|
+
```sh
|
49
|
+
$ mychart.js mail_st.rb
|
50
|
+
```
|
51
|
+
|
52
|
+
## Supported charts
|
53
|
+
|
54
|
+
bar, doughnut, line, pie, polar_area, radar are built-in with basic style
|
55
|
+
|
56
|
+
if you would like to add custom style, this is for your reference:
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
class Bar < MyChartType::Proto
|
60
|
+
|
61
|
+
def concrete_type
|
62
|
+
:bar
|
63
|
+
end
|
64
|
+
|
65
|
+
def concrete_options
|
66
|
+
{
|
67
|
+
scales: {
|
68
|
+
yAxes: [{
|
69
|
+
ticks: {
|
70
|
+
beginAtZero:true
|
71
|
+
}
|
72
|
+
}]
|
73
|
+
}
|
74
|
+
}
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
```
|
79
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "my_chart"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/exe/mychart.js
ADDED
data/lib/my_chart.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'my_chart/dsl/material'
|
3
|
+
require 'my_chart/dsl/group'
|
4
|
+
require 'my_chart/dsl/draw'
|
5
|
+
require 'my_chart/dsl/output'
|
6
|
+
|
7
|
+
module MyChart
|
8
|
+
|
9
|
+
class << self
|
10
|
+
|
11
|
+
def js &blk
|
12
|
+
chart = Chart.new
|
13
|
+
chart.instance_exec &blk
|
14
|
+
chart.generate
|
15
|
+
chart
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
ALL_DATA = :__all_data__
|
21
|
+
DEFAULT_TMPL = File.join(File.dirname(__FILE__), 'my_chart', 'tmpl.htm')
|
22
|
+
|
23
|
+
class Chart
|
24
|
+
|
25
|
+
include MyChart::Dsl::Material
|
26
|
+
include MyChart::Dsl::Group
|
27
|
+
include MyChart::Dsl::Draw
|
28
|
+
include MyChart::Dsl::Output
|
29
|
+
|
30
|
+
attr_reader :chart_tags
|
31
|
+
|
32
|
+
def generate
|
33
|
+
generate_charts
|
34
|
+
generate_files
|
35
|
+
end
|
36
|
+
|
37
|
+
def plain_tags
|
38
|
+
chart_tags.map &:default_html
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def generate_charts
|
44
|
+
@chart_tags = charts.map do |id, chart|
|
45
|
+
chart
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def generate_files
|
50
|
+
output_files and output_files.each do |path, tmpl|
|
51
|
+
File.open path, 'w:utf-8' do |f|
|
52
|
+
f.puts filled_template tmpl
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def filled_template tmpl_file
|
58
|
+
@filled ||= {}
|
59
|
+
return @filled[tmpl_file] if @filled[tmpl_file]
|
60
|
+
@filled[tmpl_file] = ERB.new(File.read tmpl_file).result(binding)
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class Bar < MyChart::Proto
|
2
|
+
|
3
|
+
def concrete_type
|
4
|
+
:bar
|
5
|
+
end
|
6
|
+
|
7
|
+
def concrete_options
|
8
|
+
opt = {
|
9
|
+
scales: {
|
10
|
+
yAxes: [{
|
11
|
+
ticks: {
|
12
|
+
beginAtZero:true
|
13
|
+
}
|
14
|
+
}]
|
15
|
+
}
|
16
|
+
}
|
17
|
+
opt.merge!({legend: {display: false}}) unless has_z?
|
18
|
+
opt
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class PlainBar < MyChart::Proto
|
2
|
+
|
3
|
+
same_color_on_x
|
4
|
+
|
5
|
+
def concrete_type
|
6
|
+
:bar
|
7
|
+
end
|
8
|
+
|
9
|
+
def concrete_options
|
10
|
+
opt = {
|
11
|
+
scales: {
|
12
|
+
yAxes: [{
|
13
|
+
ticks: {
|
14
|
+
beginAtZero:true
|
15
|
+
}
|
16
|
+
}]
|
17
|
+
}
|
18
|
+
}
|
19
|
+
opt.merge!({legend: {display: false}}) unless has_z?
|
20
|
+
opt
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'my_chart/type'
|
2
|
+
|
3
|
+
module MyChart
|
4
|
+
module Dsl
|
5
|
+
module Draw
|
6
|
+
|
7
|
+
MyChart::Type.each_sym do |chart_cmd|
|
8
|
+
|
9
|
+
define_method chart_cmd do |*arg|
|
10
|
+
chart_config = ChartCmdARGV.new *arg
|
11
|
+
|
12
|
+
chart_id = "#{chart_cmd}__#{chart_config.data_id}".to_sym
|
13
|
+
klass = MyChart::Type.concrete chart_cmd
|
14
|
+
grp_data = grouped chart_config
|
15
|
+
|
16
|
+
charts[chart_id] = klass.new grp_data, id: chart_id, w: chart_config.w, h: chart_config.h, name: chart_config.name
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def charts
|
21
|
+
@charts ||= {}
|
22
|
+
end
|
23
|
+
|
24
|
+
def grouped cfg = nil
|
25
|
+
@grouped ||= {}
|
26
|
+
|
27
|
+
return @grouped unless cfg
|
28
|
+
|
29
|
+
x = get_x cfg.from
|
30
|
+
grp_m = check_overwrite_group_method cfg.x
|
31
|
+
xy = (@grouped[[cfg.x, cfg.from]] ||= (x.group_by &grp_m))
|
32
|
+
xy = (@grouped[[cfg.x, cfg.keys, cfg.from]] ||= (xy.complete_keys cfg.keys)) if cfg.keys
|
33
|
+
xy = xy.sort(cfg) if cfg.asc or cfg.desc
|
34
|
+
xy = xy.limit(cfg) if cfg.first or cfg.last
|
35
|
+
return xy unless cfg.y
|
36
|
+
|
37
|
+
grp_m = check_overwrite_group_method cfg.y
|
38
|
+
@grouped[[cfg.x, cfg.y, cfg.keys, cfg.from]] ||= xy.group_by(&grp_m)
|
39
|
+
end
|
40
|
+
|
41
|
+
def check_overwrite_group_method method_id
|
42
|
+
group_by_methods[method_id] || method_id
|
43
|
+
end
|
44
|
+
|
45
|
+
class ChartCmdARGV
|
46
|
+
|
47
|
+
attr_reader :opt, :x, :y
|
48
|
+
|
49
|
+
def initialize *arg
|
50
|
+
return if arg.empty?
|
51
|
+
@opt = (arg[-1].kind_of? Hash) ? arg[-1] : {}
|
52
|
+
@x = arg[0] if arg[0].kind_of? Symbol
|
53
|
+
@y = arg[1] if arg[1] and arg[1].kind_of? Symbol
|
54
|
+
end
|
55
|
+
|
56
|
+
def method_missing name, *arg
|
57
|
+
return opt[name] if [:w, :h, :name, :from, :keys, :asc, :desc, :first, :last].include? name
|
58
|
+
super
|
59
|
+
end
|
60
|
+
|
61
|
+
def sort
|
62
|
+
order = (asc and :asc) or (desc and :desc)
|
63
|
+
[order, 'by', (asc or desc)].join('_') if order
|
64
|
+
end
|
65
|
+
|
66
|
+
def limit
|
67
|
+
lm = (first and :first) or (last and :last)
|
68
|
+
[lm, (first or last)].join('_') if lm
|
69
|
+
end
|
70
|
+
|
71
|
+
def data_id
|
72
|
+
[x,
|
73
|
+
y ? y : "no_y",
|
74
|
+
keys ? "keys_#{keys.hash}" : "no_keys",
|
75
|
+
from ? "from_#{from}" : "from_all",
|
76
|
+
sort,
|
77
|
+
limit
|
78
|
+
].compact.join '__'
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'my_chart/x'
|
2
|
+
|
3
|
+
module MyChart
|
4
|
+
module Dsl
|
5
|
+
module Material
|
6
|
+
|
7
|
+
def material dat=nil, name: ALL_DATA, &blk
|
8
|
+
data = (dat ? dat : blk.call)
|
9
|
+
raw_data[name] = MyChart::X.new data
|
10
|
+
end
|
11
|
+
|
12
|
+
def select name, opt={}, &blk
|
13
|
+
from = opt[:from] || ALL_DATA
|
14
|
+
x = raw_data[from]
|
15
|
+
raise Exception, '#{from} is not defined' unless x
|
16
|
+
result = x.select &blk
|
17
|
+
name = opt[:from] ? "#{name}__from__#{opt[:from]}".to_sym : name
|
18
|
+
raw_data[name] = result
|
19
|
+
end
|
20
|
+
|
21
|
+
def raw_data
|
22
|
+
@raw_data ||= {}
|
23
|
+
end
|
24
|
+
|
25
|
+
def get_x id
|
26
|
+
raw_data[id || ALL_DATA]
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module MyChart
|
2
|
+
module Dsl
|
3
|
+
module Output
|
4
|
+
|
5
|
+
attr_reader :output_files
|
6
|
+
|
7
|
+
def output *files_and_tmpl
|
8
|
+
tmpl, files = extract_tmpl_file_address files_and_tmpl
|
9
|
+
@output_files ||= []
|
10
|
+
files.each do |f|
|
11
|
+
@output_files << [f, tmpl]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def extract_tmpl_file_address args
|
18
|
+
if args[-1].kind_of? Hash
|
19
|
+
[args.pop[:tmpl], args]
|
20
|
+
else
|
21
|
+
[DEFAULT_TMPL, args]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class String
|
2
|
+
def anticapitalize
|
3
|
+
self.empty? ? self.clone : (self[0].downcase + self[1..-1])
|
4
|
+
end
|
5
|
+
|
6
|
+
def underscore
|
7
|
+
self.gsub(/::/, '/').
|
8
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
9
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
10
|
+
tr("-", "_").
|
11
|
+
downcase
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'my_chart/rainbow'
|
2
|
+
require 'json'
|
3
|
+
require 'my_chart/xyz'
|
4
|
+
|
5
|
+
module MyChart
|
6
|
+
class Proto
|
7
|
+
|
8
|
+
attr_reader :id, :name
|
9
|
+
|
10
|
+
class << self
|
11
|
+
|
12
|
+
def no_z_axis
|
13
|
+
define_method :no_z_axis? do
|
14
|
+
true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def same_color_on_x
|
19
|
+
define_method :styled_datasets do
|
20
|
+
diff_color_on_z
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize grouped_data, opt={}
|
27
|
+
raise Exception, "#{type} has no z axis" if grouped_data.kind_of? MyChart::XYZ and no_z_axis?
|
28
|
+
@id = opt[:id]
|
29
|
+
@grouped_data = grouped_data
|
30
|
+
@width = opt[:w]
|
31
|
+
@height = opt[:h]
|
32
|
+
@name = opt[:name]
|
33
|
+
end
|
34
|
+
|
35
|
+
def labels
|
36
|
+
@grouped_data.labels
|
37
|
+
end
|
38
|
+
|
39
|
+
def datasets
|
40
|
+
@grouped_data.datasets
|
41
|
+
end
|
42
|
+
|
43
|
+
def json
|
44
|
+
{
|
45
|
+
type: type,
|
46
|
+
data: {
|
47
|
+
labels: labels,
|
48
|
+
datasets: styled_datasets
|
49
|
+
},
|
50
|
+
options: options
|
51
|
+
}.to_json
|
52
|
+
end
|
53
|
+
|
54
|
+
def iife
|
55
|
+
"(function(){
|
56
|
+
var ctx = document.getElementById('#{id}');
|
57
|
+
var myChart = new Chart(ctx, #{json});
|
58
|
+
})();"
|
59
|
+
end
|
60
|
+
|
61
|
+
def default_html
|
62
|
+
"<div class='my_chart'>#{title}<canvas id='#{id}' width='#{width}' height='#{height}'></canvas><script>#{iife}</script></div>"
|
63
|
+
end
|
64
|
+
|
65
|
+
def title
|
66
|
+
name ? "<h1>#{name}</h1>" : ""
|
67
|
+
end
|
68
|
+
|
69
|
+
def width
|
70
|
+
@width || 800
|
71
|
+
end
|
72
|
+
|
73
|
+
def height
|
74
|
+
@height || 300
|
75
|
+
end
|
76
|
+
|
77
|
+
def concrete_type
|
78
|
+
end
|
79
|
+
|
80
|
+
def type
|
81
|
+
concrete_type || :proto
|
82
|
+
end
|
83
|
+
|
84
|
+
def concrete_options
|
85
|
+
{}
|
86
|
+
end
|
87
|
+
|
88
|
+
def options
|
89
|
+
{responsive: false}.merge concrete_options
|
90
|
+
end
|
91
|
+
|
92
|
+
def concrete_style
|
93
|
+
{}
|
94
|
+
end
|
95
|
+
|
96
|
+
def styled_datasets
|
97
|
+
has_z? ? diff_color_on_z : diff_color_on_x
|
98
|
+
end
|
99
|
+
|
100
|
+
def has_z?
|
101
|
+
datasets.size > 1
|
102
|
+
end
|
103
|
+
|
104
|
+
def diff_color_on_z
|
105
|
+
colors = Rainbow[datasets.size].map do |color|
|
106
|
+
{borderColor: color.to_s,
|
107
|
+
backgroundColor: color.alpha(0.2).to_s,
|
108
|
+
borderWidth: 1}
|
109
|
+
end
|
110
|
+
datasets.zip(colors).map do |ds, col|
|
111
|
+
ds.merge(col).merge concrete_style
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def diff_color_on_x
|
116
|
+
[datasets[0].
|
117
|
+
merge({backgroundColor: Rainbow[labels.size].map(&:to_s)}).
|
118
|
+
merge(concrete_style)
|
119
|
+
]
|
120
|
+
end
|
121
|
+
|
122
|
+
def no_z_axis?
|
123
|
+
false
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module MyChart::Rainbow
|
2
|
+
|
3
|
+
SCALAR = (0..255)
|
4
|
+
SCALAR_DESC = SCALAR.to_a.reverse.slice 1,254
|
5
|
+
|
6
|
+
PALETTE = [SCALAR.map{|c| "rgba(255,#{c},0,1)"},
|
7
|
+
SCALAR_DESC.map{|c| "rgba(#{c},255,0,1)"},
|
8
|
+
SCALAR.map{|c| "rgba(0,255,#{c},1)"},
|
9
|
+
SCALAR_DESC.map{|c| "rgba(0,#{c},255,1)"},
|
10
|
+
SCALAR.map{|c| "rgba(#{c},0,255,1)"},
|
11
|
+
SCALAR_DESC.map{|c| "rgba(255,0,#{c},1)"},].flatten
|
12
|
+
|
13
|
+
def self.[] n
|
14
|
+
picked = rand PALETTE.size
|
15
|
+
steps = PALETTE.size / n
|
16
|
+
n.times.map do |t|
|
17
|
+
picked = picked + steps
|
18
|
+
picked = picked - PALETTE.size if picked >= PALETTE.size
|
19
|
+
picked
|
20
|
+
end.map do |picked|
|
21
|
+
RGBA.new PALETTE[picked]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class RGBA
|
26
|
+
def initialize rgba_str
|
27
|
+
@rgba = rgba_str
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s
|
31
|
+
@rgba
|
32
|
+
end
|
33
|
+
|
34
|
+
def alpha f
|
35
|
+
self.class.new @rgba.sub(/1\)/, [f, ')'].join)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<!DOCTYPE HTML>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8" />
|
5
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.3/Chart.min.js"></script>
|
6
|
+
</head>
|
7
|
+
<body>
|
8
|
+
<% chart_tags.each do |chart| %>
|
9
|
+
<%= chart.default_html %>
|
10
|
+
<% end %>
|
11
|
+
</body>
|
12
|
+
</html>
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'my_chart/helper/string'
|
2
|
+
require 'my_chart/proto'
|
3
|
+
|
4
|
+
module MyChart::Type
|
5
|
+
|
6
|
+
class << self
|
7
|
+
|
8
|
+
include Enumerable
|
9
|
+
|
10
|
+
def concrete type
|
11
|
+
chart_class = detect{|klass| class_to_sym(klass) == type }
|
12
|
+
raise Exception, "no such chart: #{type}" unless chart_class
|
13
|
+
chart_class
|
14
|
+
end
|
15
|
+
|
16
|
+
def each &blk
|
17
|
+
load_concrete_charts
|
18
|
+
custom_charts.each &blk
|
19
|
+
end
|
20
|
+
|
21
|
+
def each_sym &blk
|
22
|
+
map{ |klass| class_to_sym klass }.each &blk
|
23
|
+
end
|
24
|
+
|
25
|
+
def load_concrete_charts
|
26
|
+
return if @loaded
|
27
|
+
definitions.each do |c|
|
28
|
+
class_eval File.read(c)
|
29
|
+
end
|
30
|
+
@loaded = true
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def class_to_sym klass
|
36
|
+
basename(klass).anticapitalize.to_sym
|
37
|
+
end
|
38
|
+
|
39
|
+
def basename klass
|
40
|
+
klass.name.split(/::/)[-1]
|
41
|
+
end
|
42
|
+
|
43
|
+
def definitions
|
44
|
+
path = File.expand_path("../charts/*", __FILE__)
|
45
|
+
Dir[path]
|
46
|
+
end
|
47
|
+
|
48
|
+
def custom_charts
|
49
|
+
self.constants.map do |const|
|
50
|
+
const_get(const)
|
51
|
+
end.select do |klass|
|
52
|
+
klass != MyChart::Proto
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
data/lib/my_chart/x.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'my_chart/xy'
|
2
|
+
|
3
|
+
module MyChart
|
4
|
+
class X
|
5
|
+
def initialize objs
|
6
|
+
@objs = objs
|
7
|
+
end
|
8
|
+
|
9
|
+
def select &blk
|
10
|
+
X.new value.select(&blk)
|
11
|
+
end
|
12
|
+
|
13
|
+
def group_by &blk
|
14
|
+
XY.new value.group_by(&blk)
|
15
|
+
end
|
16
|
+
|
17
|
+
def value
|
18
|
+
@objs
|
19
|
+
end
|
20
|
+
|
21
|
+
def == obj
|
22
|
+
obj.kind_of? X and value == obj.value
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
data/lib/my_chart/xy.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'my_chart/xyz'
|
2
|
+
|
3
|
+
module MyChart
|
4
|
+
class XY
|
5
|
+
def initialize objs_hash
|
6
|
+
@objs_hash = objs_hash
|
7
|
+
end
|
8
|
+
|
9
|
+
def select &blk
|
10
|
+
XY.new value.select(&blk)
|
11
|
+
end
|
12
|
+
|
13
|
+
def group_by &blk
|
14
|
+
XYZ.new Hash[value.map{ |group_name, objs| [group_name, objs.group_by(&blk)] }]
|
15
|
+
end
|
16
|
+
|
17
|
+
def value
|
18
|
+
@objs_hash
|
19
|
+
end
|
20
|
+
|
21
|
+
def labels
|
22
|
+
value.keys
|
23
|
+
end
|
24
|
+
|
25
|
+
def datasets
|
26
|
+
[{label: 'xy', data: value.values.map{|objs| objs.count}}]
|
27
|
+
end
|
28
|
+
|
29
|
+
def == obj
|
30
|
+
obj.kind_of? XY and value == obj.value
|
31
|
+
end
|
32
|
+
|
33
|
+
def complete_keys range=nil
|
34
|
+
return self unless range
|
35
|
+
new_hash = value.dup
|
36
|
+
range.each do |key|
|
37
|
+
new_hash[key] = [] unless new_hash[key]
|
38
|
+
end
|
39
|
+
XY.new new_hash
|
40
|
+
end
|
41
|
+
|
42
|
+
def sort order
|
43
|
+
compare = if :key === order.asc
|
44
|
+
-> a, b { a[0] <=> b[0] }
|
45
|
+
elsif :key === order.desc
|
46
|
+
-> a, b { b[0] <=> a[0] }
|
47
|
+
elsif :count === order.asc
|
48
|
+
-> a, b { a[1].size <=> b[1].size }
|
49
|
+
else
|
50
|
+
-> a, b { b[1].size <=> a[1].size }
|
51
|
+
end
|
52
|
+
sorted = value.to_a.sort &compare
|
53
|
+
new_hash = Hash[sorted]
|
54
|
+
XY.new new_hash
|
55
|
+
end
|
56
|
+
|
57
|
+
def limit config
|
58
|
+
limit_method, num = config.first ? [:first, config.first] : [:last, config.last]
|
59
|
+
limited = value.to_a.send limit_method, num
|
60
|
+
new_hash = Hash[limited]
|
61
|
+
XY.new new_hash
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
data/lib/my_chart/xyz.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
module MyChart
|
2
|
+
class XYZ
|
3
|
+
def initialize objs_2d_hash
|
4
|
+
@objs_2d_hash = objs_2d_hash
|
5
|
+
end
|
6
|
+
|
7
|
+
def value
|
8
|
+
@objs_2d_hash
|
9
|
+
end
|
10
|
+
|
11
|
+
def labels
|
12
|
+
value.keys
|
13
|
+
end
|
14
|
+
|
15
|
+
def datasets
|
16
|
+
labels_in_datasets = keys_in_sub_hash value
|
17
|
+
labels_in_datasets.map do |lb|
|
18
|
+
{
|
19
|
+
label: lb,
|
20
|
+
data: value.map{ |k, sub_hash| sub_hash[lb] ? sub_hash[lb].count : 0}
|
21
|
+
}
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def == obj
|
26
|
+
obj.kind_of? XYZ and value == obj.value
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def keys_in_sub_hash hash_2d
|
32
|
+
hash_2d.values.reduce([]) do |labels, hash|
|
33
|
+
labels + hash.keys
|
34
|
+
end.uniq.sort_by(&:to_s)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
data/my_chart.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'my_chart/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "my_chart"
|
8
|
+
spec.version = MyChart::VERSION
|
9
|
+
spec.authors = ["ken"]
|
10
|
+
spec.email = ["block24block@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{chart.js wrapper}
|
13
|
+
spec.homepage = "https://github.com/turnon/my_chart"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
17
|
+
f.match(%r{^(test|spec|features)/})
|
18
|
+
end
|
19
|
+
spec.bindir = "exe"
|
20
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.14"
|
24
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
25
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: my_chart
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- ken
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-02-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.14'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.14'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '5.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '5.0'
|
55
|
+
description:
|
56
|
+
email:
|
57
|
+
- block24block@gmail.com
|
58
|
+
executables:
|
59
|
+
- mychart.js
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- ".gitignore"
|
64
|
+
- ".travis.yml"
|
65
|
+
- CODE_OF_CONDUCT.md
|
66
|
+
- Gemfile
|
67
|
+
- LICENSE.txt
|
68
|
+
- README.md
|
69
|
+
- Rakefile
|
70
|
+
- bin/console
|
71
|
+
- bin/setup
|
72
|
+
- exe/mychart.js
|
73
|
+
- lib/my_chart.rb
|
74
|
+
- lib/my_chart/charts/bar.rb
|
75
|
+
- lib/my_chart/charts/doughnut.rb
|
76
|
+
- lib/my_chart/charts/line.rb
|
77
|
+
- lib/my_chart/charts/pie.rb
|
78
|
+
- lib/my_chart/charts/plain_bar.rb
|
79
|
+
- lib/my_chart/charts/polar_area.rb
|
80
|
+
- lib/my_chart/charts/radar.rb
|
81
|
+
- lib/my_chart/dsl/draw.rb
|
82
|
+
- lib/my_chart/dsl/group.rb
|
83
|
+
- lib/my_chart/dsl/material.rb
|
84
|
+
- lib/my_chart/dsl/output.rb
|
85
|
+
- lib/my_chart/helper/string.rb
|
86
|
+
- lib/my_chart/proto.rb
|
87
|
+
- lib/my_chart/rainbow.rb
|
88
|
+
- lib/my_chart/tmpl.htm
|
89
|
+
- lib/my_chart/type.rb
|
90
|
+
- lib/my_chart/version.rb
|
91
|
+
- lib/my_chart/x.rb
|
92
|
+
- lib/my_chart/xy.rb
|
93
|
+
- lib/my_chart/xyz.rb
|
94
|
+
- my_chart.gemspec
|
95
|
+
homepage: https://github.com/turnon/my_chart
|
96
|
+
licenses:
|
97
|
+
- MIT
|
98
|
+
metadata: {}
|
99
|
+
post_install_message:
|
100
|
+
rdoc_options: []
|
101
|
+
require_paths:
|
102
|
+
- lib
|
103
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '0'
|
108
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - ">="
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
requirements: []
|
114
|
+
rubyforge_project:
|
115
|
+
rubygems_version: 2.6.8
|
116
|
+
signing_key:
|
117
|
+
specification_version: 4
|
118
|
+
summary: chart.js wrapper
|
119
|
+
test_files: []
|