Skip to content

Commit aa3a225

Browse files
committed
feat: chart examples
1 parent 48e9894 commit aa3a225

14 files changed

+302
-160
lines changed

app/helpers/admin_helper.rb

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
module AdminHelper
2-
def admin_widget_box(title, &block)
3-
render partial: 'admin/base/widget_box', locals: { body: capture(&block), title: title }
2+
def admin_widget_box(title, sizes: [], &block)
3+
sizes ||= []
4+
sizes[0] ||= 12
5+
sizes[1] ||= 12
6+
sizes[2] ||= 12
7+
render partial: 'admin/base/widget_box', locals: { body: capture(&block), title: title, sizes: sizes }
48
end
59

610
def append_page_button(body, link, options = {})

app/helpers/charts_helper.rb

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module ChartsHelper
2+
ChartsPresenter::CHART_TYPES.each do |chart_type|
3+
define_method "render_#{chart_type}_chart" do |data, options = {}|
4+
ChartsPresenter.new(chart_type, data, options).to_html
5+
end
6+
end
7+
end

app/presenters/charts_presenter.rb

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
class ChartsPresenter
2+
3+
CHART_TYPES = %w[ bar bubble doughnut horizontal_bar line pie polar_area radar scatter ]
4+
5+
class << self
6+
private
7+
8+
def element_id
9+
@element_id ||= -1
10+
@element_id += 1
11+
end
12+
end
13+
14+
# http://www.chartjs.org/docs/latest/general/
15+
def initialize(type, data, options)
16+
@type = type
17+
@data = data
18+
@options = options
19+
@element_id = @options.delete(:id) || "chart-#{self.class.send(:element_id)}"
20+
@css_class = @options.delete(:class) || 'chart'
21+
@width = @options.delete(:width) || '400'
22+
@height = @options.delete(:height) || '400'
23+
end
24+
25+
def to_html
26+
"#{canvas}<script>#{to_js}</script>".html_safe
27+
end
28+
29+
private
30+
31+
def to_js
32+
<<-END.squish.html_safe
33+
(function() {
34+
var initChart = function() {
35+
var ctx = document.getElementById(#{@element_id.to_json});
36+
var chart = new Chart(ctx, {
37+
type: "#{camel_case(@type)}",
38+
data: #{to_javascript_string @data},
39+
options: #{to_javascript_string @options}
40+
});
41+
};
42+
if (typeof Chart !== "undefined" && Chart !== null) {
43+
initChart();
44+
}
45+
else {
46+
/* W3C standard */
47+
if (window.addEventListener) {
48+
window.addEventListener("load", initChart, false);
49+
}
50+
/* IE */
51+
else if (window.attachEvent) {
52+
window.attachEvent("onload", initChart);
53+
}
54+
}
55+
})();
56+
END
57+
end
58+
59+
def canvas
60+
"<canvas id=\"#{@element_id}\" class=\"#{@css_class}\" width=\"#{@width}\" height=\"#{@height}\" style=\"width: #{@width}; height: #{@height}\"></canvas>"
61+
end
62+
63+
def camel_case(str)
64+
str = str.to_s.camelize
65+
str[0] = str[0].downcase
66+
str
67+
end
68+
69+
def to_javascript_string(element)
70+
case element
71+
when Hash
72+
hash_elements = []
73+
element.each do |key, value|
74+
hash_elements << camel_case(key).to_json + ':' + to_javascript_string(value)
75+
end
76+
'{' + hash_elements.join(',') + '}'
77+
when Array
78+
array_elements = []
79+
element.each do |value|
80+
array_elements << to_javascript_string(value)
81+
end
82+
'[' + array_elements.join(',') + ']'
83+
when String
84+
if element.match(/^\s*function.*}\s*$/m)
85+
# Raw-copy function definitions to the output without surrounding quotes.
86+
element
87+
else
88+
element.to_json
89+
end
90+
when BigDecimal
91+
element.to_s
92+
else
93+
element.to_json
94+
end
95+
end
96+
end
+25-26
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,25 @@
1-
.row
2-
.col-md-12.col-sm-12.col-xs-12
3-
.x_panel
4-
.x_title
5-
h2= title
6-
ul.nav.navbar-right.panel_toolbox
7-
li
8-
a.collapse-link
9-
i.fa.fa-chevron-up
10-
/ li.dropdown
11-
a.dropdown-toggle[href="#" data-toggle="dropdown" role="button" aria-expanded="false"]
12-
i.fa.fa-wrench
13-
ul.dropdown-menu[role="menu"]
14-
li
15-
a[href="#"]
16-
| Settings 1
17-
li
18-
a[href="#"]
19-
| Settings 2
20-
/ li
21-
a.close-link
22-
i.fa.fa-close
23-
.clearfix
24-
.x_content
25-
br
26-
= body
1+
div class="col-md-#{sizes[0]} col-sm-#{sizes[1]} col-xs-#{sizes[2]}"
2+
.x_panel
3+
.x_title
4+
h2= title
5+
ul.nav.navbar-right.panel_toolbox
6+
li
7+
a.collapse-link
8+
i.fa.fa-chevron-up
9+
/ li.dropdown
10+
a.dropdown-toggle[href="#" data-toggle="dropdown" role="button" aria-expanded="false"]
11+
i.fa.fa-wrench
12+
ul.dropdown-menu[role="menu"]
13+
li
14+
a[href="#"]
15+
| Settings 1
16+
li
17+
a[href="#"]
18+
| Settings 2
19+
/ li
20+
a.close-link
21+
i.fa.fa-close
22+
.clearfix
23+
.x_content
24+
br
25+
= body

app/views/admin/base/examples.html.slim

+27-2
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,13 @@ h3= 'admin_form_for'
1818
= f.submit_cancel 'Go', cancel: root_path
1919

2020
h3= 'admin_widget_box'
21-
= admin_widget_box 'Hi' do
22-
= 'Aloha'
21+
.row
22+
= admin_widget_box 'Hi', sizes: [4, 6, 12] do
23+
= 'Aloha'
24+
= admin_widget_box 'Hi 2', sizes: [4, 6, 12] do
25+
= 'Aloha2'
26+
= admin_widget_box 'Hi 3', sizes: [4, 6, 12] do
27+
= 'Aloha3'
2328

2429
h3= 'render_admin_data_table'
2530
= render_admin_data_table(data: [User.new, Category.new]) do |data|
@@ -32,3 +37,23 @@ h3= 'render_admin_data_table'
3237
tr
3338
td= obj.class
3439
td
40+
41+
h3= 'render_line_chart'
42+
- options = { width: '100%', height: '100px', responsive: true }
43+
- labels = (4.days.ago.to_date..(Time.now.to_date)).map(&:to_s)
44+
- datasets = 3.times.map { |i| { label: "data-#{i+1}", data: 5.times.map { (1..100).to_a.sample }, background_color: 'rgba(0,0,0,0)', border_color: "rgba(#{100*i},#{100*i},#{100*i}, 1)" } }
45+
= admin_widget_box 'Line', sizes: [6] do
46+
= render_line_chart({ labels: labels, datasets: datasets }, options)
47+
= admin_widget_box 'Radar', sizes: [6] do
48+
= render_radar_chart({ labels: labels, datasets: datasets }, options)
49+
= admin_widget_box 'Bar', sizes: [6] do
50+
- datasets = datasets.map { |d| d.merge(background_color: "##{d[:data][0]}#{d[:data][0]}#{d[:data][0]}") }
51+
= render_bar_chart({ labels: labels, datasets: datasets }, options)
52+
= admin_widget_box 'Pie', sizes: [6] do
53+
- datasets = [{ data: 5.times.map { |i| (1..100).to_a.sample }, background_color: 5.times.map { |i| "##{i*24}#{i*24}#{i*24}" } }]
54+
- labels = 5.times.map { |i| "pie-#{i+1}" }
55+
= render_pie_chart({ labels: labels, datasets: datasets }, options)
56+
= admin_widget_box 'Doughnut', sizes: [6] do
57+
= render_doughnut_chart({ labels: labels, datasets: datasets }, options)
58+
= admin_widget_box 'Polar Area', sizes: [6] do
59+
= render_polar_area_chart({ labels: labels, datasets: datasets }, options)
+4-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
= render partial: 'btns', object: @category, as: :category
22

3-
= admin_widget_box 'Edit Category' do
4-
= admin_form_for @category, as: :category do |f|
5-
= render partial: 'form', object: f, as: :f
3+
.row
4+
= admin_widget_box 'Edit Category' do
5+
= admin_form_for @category, as: :category do |f|
6+
= render partial: 'form', object: f, as: :f
+30-28
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,34 @@
11
- append_page_button 'New Category', new_admin_category_path, class: 'btn-primary'
22

3-
= admin_widget_box 'Filtering' do
4-
= render partial: 'filtering', as: :q, object: @q
3+
.row
4+
= admin_widget_box 'Filtering' do
5+
= render partial: 'filtering', as: :q, object: @q
56

6-
= admin_widget_box 'Categories' do
7-
= render_admin_data_table(data: @categories) do
8-
thead
9-
tr
10-
th= '#'
11-
th= 'Name'
12-
th= 'Sort'
13-
th= 'Sorting'
14-
th= 'actions'
15-
tbody
16-
- @categories.each do |category|
7+
.row
8+
= admin_widget_box 'Categories' do
9+
= render_admin_data_table(data: @categories) do
10+
thead
1711
tr
18-
td= category.id
19-
td= category.name
20-
td= category.sort
21-
td
22-
- unless category.deleted?
23-
= render_admin_sorting_buttons(category)
24-
td
25-
- if category.deleted?
26-
= link_to 'Restore', restore_admin_category_path(category), method: :post, 'data-confirm' => 'Restore?'
27-
- else
28-
= link_to 'Show', admin_category_path(category)
29-
| &nbsp; | &nbsp;
30-
= link_to 'Edit', edit_admin_category_path(category)
31-
| &nbsp; | &nbsp;
32-
= link_to 'Delete', admin_category_path(category), method: :delete, 'data-confirm' => 'Delete?'
12+
th= '#'
13+
th= 'Name'
14+
th= 'Sort'
15+
th= 'Sorting'
16+
th= 'actions'
17+
tbody
18+
- @categories.each do |category|
19+
tr
20+
td= category.id
21+
td= category.name
22+
td= category.sort
23+
td
24+
- unless category.deleted?
25+
= render_admin_sorting_buttons(category)
26+
td
27+
- if category.deleted?
28+
= link_to 'Restore', restore_admin_category_path(category), method: :post, 'data-confirm' => 'Restore?'
29+
- else
30+
= link_to 'Show', admin_category_path(category)
31+
| &nbsp; | &nbsp;
32+
= link_to 'Edit', edit_admin_category_path(category)
33+
| &nbsp; | &nbsp;
34+
= link_to 'Delete', admin_category_path(category), method: :delete, 'data-confirm' => 'Delete?'
+4-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1-
= admin_widget_box 'New Category' do
2-
= admin_form_for @category, as: :category do |f|
3-
= render partial: 'form', object: f, as: :f
1+
.row
2+
= admin_widget_box 'New Category' do
3+
= admin_form_for @category, as: :category do |f|
4+
= render partial: 'form', object: f, as: :f
+17-16
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
= render partial: 'btns', object: @category, as: :category
22

3-
= admin_widget_box "Revisions (Total versions: #{@versions.size} )" do
4-
= render_admin_data_table(data: @versions) do
5-
thead
6-
tr
7-
th= 'Event'
8-
th= 'When'
9-
th= 'Who'
10-
th= 'What'
11-
tbody
12-
- @versions.reverse.each do |version|
3+
.row
4+
= admin_widget_box "Revisions (Total versions: #{@versions.size} )" do
5+
= render_admin_data_table(data: @versions) do
6+
thead
137
tr
14-
td= version.event
15-
td= version.created_at
16-
td= User&.find_by(id: version.whodunnit)&.name
17-
td
18-
- convert_changes_string(version.object_changes).each do |column, diffs|
19-
.diff= "#{column}: #{diffs[0].nil? ? "NULL" : diffs[0]} -> #{diffs[1].nil? ? "NULL" : diffs[1]}"
8+
th= 'Event'
9+
th= 'When'
10+
th= 'Who'
11+
th= 'What'
12+
tbody
13+
- @versions.reverse.each do |version|
14+
tr
15+
td= version.event
16+
td= version.created_at
17+
td= User&.find_by(id: version.whodunnit)&.name
18+
td
19+
- convert_changes_string(version.object_changes).each do |column, diffs|
20+
.diff= "#{column}: #{diffs[0].nil? ? "NULL" : diffs[0]} -> #{diffs[1].nil? ? "NULL" : diffs[1]}"
+27-26
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,28 @@
11
= render partial: 'btns', object: @category, as: :category
2-
= admin_widget_box "Category ##{@category.id}" do
3-
= render_admin_data_table(bordered: false) do
4-
tr
5-
th ID
6-
td= @category.id
7-
tr
8-
th Name
9-
td= @category.name
10-
tr
11-
th Tags
12-
td
13-
- @category.tag_list.each do |tag_name|
14-
- class_name = cycle('default', 'primary', 'success', 'info', 'warning', 'danger')
15-
= link_to admin_categories_path(q: { tagged: [tag_name] }) do
16-
span.label class="label-#{class_name}"
17-
= tag_name
18-
| &nbsp;
19-
tr
20-
th Sort
21-
td= @category.sort
22-
tr
23-
th Created at
24-
td= @category.created_at
25-
tr
26-
th Updated at
27-
td= @category.updated_at
2+
.row
3+
= admin_widget_box "Category ##{@category.id}" do
4+
= render_admin_data_table(bordered: false) do
5+
tr
6+
th ID
7+
td= @category.id
8+
tr
9+
th Name
10+
td= @category.name
11+
tr
12+
th Tags
13+
td
14+
- @category.tag_list.each do |tag_name|
15+
- class_name = cycle('default', 'primary', 'success', 'info', 'warning', 'danger')
16+
= link_to admin_categories_path(q: { tagged: [tag_name] }) do
17+
span.label class="label-#{class_name}"
18+
= tag_name
19+
| &nbsp;
20+
tr
21+
th Sort
22+
td= @category.sort
23+
tr
24+
th Created at
25+
td= @category.created_at
26+
tr
27+
th Updated at
28+
td= @category.updated_at

app/views/admin/users/edit.html.slim

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
= render partial: 'btns', object: @user, as: :user
22

3-
= admin_widget_box "Edit User" do
4-
= admin_form_for @user, as: :user, wrapper: :admin do |f|
5-
= render partial: "form", object: f, as: :f
3+
.row
4+
= admin_widget_box "Edit User" do
5+
= admin_form_for @user, as: :user, wrapper: :admin do |f|
6+
= render partial: "form", object: f, as: :f

0 commit comments

Comments
 (0)