Chart.js
Chart.js integration, Bootstrap theming aware. In order to limit the scope of the matestack-ui-bootstrap gem, Chart.js components are not part of this gem. The below shown example should enable you to easily integrate Chart.js (or any other chart library) according to your needs!

Ruby component

app/matestack/components/chart_js.rb
1
class Components::ChartJs < Matestack::Ui::VueJsComponent
2
vue_name "chart-js-component"
3
4
requires :type
5
requires :datasets
6
optional :labels
7
optional :height
8
optional :width
9
optional :display_legend
10
optional :display_x_axes
11
optional :display_y_axes
12
optional :cutout_percentage
13
optional class: { as: :bs_class }
14
15
# injected into vue.js components
16
def vue_props
17
{}.tap do |props|
18
props[:type] = context.type
19
props[:datasets] = context.datasets
20
props[:labels] = context.labels
21
props[:display_legend] = !display_legend.nil? ? context.display_legend : false
22
props[:display_x_axes] = !display_x_axes.nil? ? context.display_x_axes : true
23
props[:display_y_axes] = !display_y_axes.nil? ? context.display_y_axes : true
24
props[:display_y_axes] = !display_y_axes.nil? ? context.display_y_axes : true
25
props[:cutout_percentage] = !context.cutout_percentage.nil? ? context.cutout_percentage : 70
26
end
27
end
28
29
def response
30
div class: "chart-container #{context.bs_class}", style: "width: 100%; height: 100%;" do
31
plain "<canvas ref='chart'></canvas>".html_safe
32
end
33
end
34
35
end
Copied!

Vue.js component

If not already installed, do:
1
yarn add chart.[email protected]2.9.4
Copied!
Do not forget to import the following file into you application pack
app/matestack/components/chart_js.js
1
import Chart from 'chart.js';
2
import Vue from 'vue/dist/vue.esm'
3
import MatestackUiCore from 'matestack-ui-core';
4
5
Vue.component('chart-js-component', {
6
mixins: [MatestackUiCore.componentMixin],
7
8
data() {
9
return {
10
chartJsInstance: undefined,
11
defaultColor: undefined,
12
fontColor: undefined,
13
fontFamily: undefined
14
};
15
},
16
17
methods: {
18
getThemeColor: function(key){
19
const style = getComputedStyle(document.body);
20
return style.getPropertyValue('--bs-'+key);
21
},
22
getThemeColorArray: function(keysArray){
23
let result = []
24
const style = getComputedStyle(document.body);
25
keysArray.forEach(function(key){
26
result.push(style.getPropertyValue('--bs-'+key))
27
})
28
return result;
29
},
30
drawBarChart: function(chartElement){
31
const self = this;
32
this.props["datasets"].forEach(function(item){
33
if (item["backgroundColor"] === undefined){
34
item["backgroundColor"] = self.getThemeColor("primary")
35
}else{
36
if(Array.isArray(item["backgroundColor"])){
37
item["backgroundColor"] = self.getThemeColorArray(item["backgroundColor"])
38
}else{
39
item["backgroundColor"] = self.getThemeColor(item["backgroundColor"])
40
}
41
}
42
item["hoverBackgroundColor"] = "rgba(0, 0, 0, 0.1)"
43
if (item["barThickness"] === undefined){
44
item["barThickness"] = 10;
45
}
46
})
47
this.chartJsInstance = new Chart(chartElement, {
48
type: 'bar',
49
data: {
50
labels: this.props["labels"],
51
datasets: this.props["datasets"]
52
},
53
options: {
54
legend: {
55
display: this.props["display_legend"],
56
},
57
scales: {
58
yAxes: [{
59
display: this.props["display_y_axes"],
60
gridLines: {
61
display: false,
62
},
63
ticks: {
64
beginAtZero: true
65
}
66
}],
67
xAxes: [{
68
display: this.props["display_x_axes"],
69
gridLines: {
70
display: false,
71
},
72
ticks: {
73
beginAtZero: true
74
}
75
}]
76
}
77
}
78
});
79
},
80
drawLineChart: function(chartElement){
81
const self = this;
82
this.props["datasets"].forEach(function(item){
83
if (item["borderColor"] === undefined){
84
item["borderColor"] = self.getThemeColor("primary")
85
}else{
86
item["borderColor"] = self.getThemeColor(item["borderColor"])
87
}
88
item["hoverBackgroundColor"] = "rgba(0, 0, 0, 0.1)"
89
if (item["fill"] === undefined){
90
item["fill"] = false;
91
}
92
})
93
this.chartJsInstance = new Chart(chartElement, {
94
type: 'line',
95
data: {
96
labels: this.props["labels"],
97
datasets: this.props["datasets"]
98
},
99
options: {
100
legend: {
101
display: this.props["display_legend"],
102
},
103
scales: {
104
yAxes: [{
105
display: this.props["display_y_axes"],
106
gridLines: {
107
display: false,
108
},
109
ticks: {
110
beginAtZero: true
111
}
112
}],
113
xAxes: [{
114
display: this.props["display_x_axes"],
115
gridLines: {
116
display: false,
117
},
118
ticks: {
119
beginAtZero: true
120
}
121
}]
122
}
123
}
124
});
125
},
126
drawDoughnutChart: function(chartElement){
127
const self = this;
128
this.props["datasets"].forEach(function(item){
129
if (item["backgroundColor"] === undefined){
130
item["backgroundColor"] = self.getThemeColor("primary")
131
}else{
132
if(Array.isArray(item["backgroundColor"])){
133
item["backgroundColor"] = self.getThemeColorArray(item["backgroundColor"])
134
}else{
135
item["backgroundColor"] = self.getThemeColor(item["backgroundColor"])
136
}
137
}
138
item["hoverBackgroundColor"] = "rgba(0, 0, 0, 0.1)"
139
if (item["borderColor"] === undefined){
140
item["borderColor"] = self.getThemeColor("white")
141
}else{
142
item["borderColor"] = self.getThemeColor(item["borderColor"])
143
}
144
if (item["hoverBorderColor"] === undefined){
145
item["hoverBorderColor"] = self.getThemeColor("white")
146
}else{
147
item["hoverBorderColor"] = self.getThemeColor(item["hoverBorderColor"])
148
}
149
if (item["borderWidth"] === undefined){
150
item["borderWidth"] = 10
151
}
152
if (item["weight"] === undefined){
153
item["weight"] = 1
154
}
155
})
156
this.chartJsInstance = new Chart(chartElement, {
157
type: 'doughnut',
158
data: {
159
labels: this.props["labels"],
160
datasets: this.props["datasets"]
161
},
162
options: {
163
legend: {
164
display: this.props["display_legend"],
165
},
166
cutoutPercentage: this.props["cutout_percentage"]
167
}
168
});
169
},
170
drawPieChart: function(chartElement){
171
const self = this;
172
this.props["datasets"].forEach(function(item){
173
if (item["backgroundColor"] === undefined){
174
item["backgroundColor"] = self.getThemeColor("primary")
175
}else{
176
if(Array.isArray(item["backgroundColor"])){
177
item["backgroundColor"] = self.getThemeColorArray(item["backgroundColor"])
178
}else{
179
item["backgroundColor"] = self.getThemeColor(item["backgroundColor"])
180
}
181
}
182
item["hoverBackgroundColor"] = "rgba(0, 0, 0, 0.1)"
183
})
184
this.chartJsInstance = new Chart(chartElement, {
185
type: 'pie',
186
data: {
187
labels: this.props["labels"],
188
datasets: this.props["datasets"]
189
},
190
options: {
191
legend: {
192
display: this.props["display_legend"],
193
}
194
}
195
});
196
},
197
},
198
199
mounted: function() {
200
const style = getComputedStyle(document.body);
201
202
this.defaultColor = style.getPropertyValue('--bs-primary');
203
this.fontColor = style.getPropertyValue('--bs-secondary');
204
this.fontFamily = style.getPropertyValue('--bs-font-sans-serif');
205
206
Chart.defaults.global.defaultFontColor = this.fontColor
207
Chart.defaults.global.defaultFontFamily = this.fontFamily
208
Chart.defaults.global.defaultColor = this.fontFamily
209
210
const chartElement = this.$refs.chart
211
212
if(this.props["type"] == "bar"){
213
this.drawBarChart(chartElement);
214
}
215
if(this.props["type"] == "line"){
216
this.drawLineChart(chartElement);
217
}
218
if(this.props["type"] == "doughnut"){
219
this.drawDoughnutChart(chartElement);
220
}
221
if(this.props["type"] == "pie"){
222
this.drawPieChart(chartElement);
223
}
224
225
}
226
});
Copied!

Usage

Example 1: Bar chart

1
Components::ChartJs.(class: "w-50", type: :bar, datasets: [
2
{
3
label: "€",
4
data: [x, y, z],
5
backgroundColor: :primary
6
},
7
], labels: ["x", "y", "z"])
Copied!

Example 2: Doughnut chart

1
Components::ChartJs.(type: :doughnut, datasets: [
2
{
3
label: "€",
4
data: [x, y, z],
5
backgroundColor: [:orange, :secondary, :primary]
6
},
7
], labels: ["x", "y", "z"])
Copied!

Example 3: Line chart

1
Components::ChartJs.(type: :line, datasets: [
2
{
3
label: "€",
4
data: [x, y, z],
5
borderColor: :primary,
6
pointRadius: 0
7
},
8
{
9
label: "€",
10
data: [last_7_days, total, last_30_days],
11
borderColor: :danger,
12
fill: false
13
},
14
], labels: ["x", "y", "z"], display_x_axes: false, display_y_axes: false)
Copied!

Example 4: Pie chart

1
Components::ChartJs.(type: :pie, datasets: [
2
{
3
label: "€",
4
data: [x, y, z],
5
backgroundColor: [:orange, :secondary, :primary]
6
},
7
], labels: ["x", "y", "z"])
Copied!