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 by copy&paste (or any other chart library) and optionally adjust according to your needs!
Example and docs below are meant to support Chart.js v2, not Chart.js v3

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 matestack-ui-vuejs-ref=#{matestack_ui_vuejs_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 MatestackUiVueJs from 'matestack-ui-vuejs'
3
4
const chartJsComponent = {
5
mixins: [MatestackUiVueJs.componentMixin],
6
template: MatestackUiVueJs.componentHelpers.inlineTemplate,
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
}
227
228
export default chartJsComponent
Copied!
and then in your application.js file:
1
import chartJsComponent from '../../matestack/components/chart_js.js'// import component definition from source
2
3
const appInstance = createApp({})
4
5
appInstance.component('chart-js-component', chartJsComponent) // register at appInstance
6
7
MatestackUiBootstrap.registerComponents(appInstance)
8
9
document.addEventListener('DOMContentLoaded', () => {
10
MatestackUiVueJs.mount(appInstance)
11
})
Copied!

Usage

Example 1: Bar chart

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