@bildvitta/quasar-ui-asteroid 3.11.0-beta.3 → 3.11.0-beta.4
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.
- package/package.json +1 -1
- package/src/components/chart-view/QasChartView.vue +383 -0
- package/src/components/chart-view/QasChartView.yml +87 -0
- package/src/components/chart-view/config/charts/bar.js +45 -0
- package/src/components/chart-view/config/charts/doughnut.js +43 -0
- package/src/components/chart-view/config/charts/index.js +9 -0
- package/src/components/chart-view/config/charts/line.js +57 -0
- package/src/components/chart-view/config/defaults/colors.js +19 -0
- package/src/components/chart-view/config/defaults/font.js +5 -0
- package/src/components/chart-view/config/defaults/index.js +2 -0
- package/src/components/chart-view/config/index.js +3 -0
- package/src/components/chart-view/config/plugins/index.js +3 -0
- package/src/components/chart-view/config/plugins/legend.js +9 -0
- package/src/components/chart-view/config/plugins/tooltip.js +15 -0
- package/src/components/chart-view/config/plugins/zoom.js +31 -0
- package/src/components/header-actions/QasHeaderActions.vue +17 -1
- package/src/components/header-actions/QasHeaderActions.yml +7 -1
- package/src/components/search-box/QasSearchBox.vue +48 -17
- package/src/components/search-box/QasSearchBox.yml +8 -0
- package/src/components/search-input/QasSearchInput.vue +1 -24
- package/src/components/select-list/QasSelectList.vue +76 -48
- package/src/components/select-list/QasSelectList.yml +8 -39
- package/src/components/select-list/private/PvSelectListCheckbox.vue +31 -0
- package/src/css/components/item.scss +4 -0
- package/src/helpers/rules.js +2 -2
- package/src/mixins/search-filter.js +1 -1
- package/src/vue-plugin/components/chart-view-component.js +16 -0
- package/src/vue-plugin/third-party-components-initializer.js +2 -0
package/package.json
CHANGED
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<qas-header-actions v-if="hasHeaderActions" align-columns="end">
|
|
3
|
+
<template #left>
|
|
4
|
+
<div v-if="title" class="text-grey-9 text-h3">
|
|
5
|
+
{{ title }}
|
|
6
|
+
</div>
|
|
7
|
+
|
|
8
|
+
<div v-if="subtitle" class="text-body1 text-grey-8">
|
|
9
|
+
{{ subtitle }}
|
|
10
|
+
</div>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<template #right>
|
|
14
|
+
<qas-filters v-bind="chartFiltersProps" v-model:currentFilters="filters" />
|
|
15
|
+
</template>
|
|
16
|
+
</qas-header-actions>
|
|
17
|
+
|
|
18
|
+
<div v-bind="parentComponentProps">
|
|
19
|
+
<component :is="chartComponent.is" v-if="showChart" v-bind="chartComponent.props" />
|
|
20
|
+
|
|
21
|
+
<div v-else-if="!isFetching">
|
|
22
|
+
<slot name="empty-results">
|
|
23
|
+
<qas-empty-result-text />
|
|
24
|
+
</slot>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<q-inner-loading :showing="isFetching">
|
|
28
|
+
<q-spinner color="grey" size="3em" />
|
|
29
|
+
</q-inner-loading>
|
|
30
|
+
</div>
|
|
31
|
+
</template>
|
|
32
|
+
|
|
33
|
+
<script>
|
|
34
|
+
// Importações do chart.js
|
|
35
|
+
import {
|
|
36
|
+
Chart as ChartJS,
|
|
37
|
+
Title,
|
|
38
|
+
Tooltip,
|
|
39
|
+
Legend,
|
|
40
|
+
CategoryScale,
|
|
41
|
+
LinearScale,
|
|
42
|
+
BarElement,
|
|
43
|
+
LineElement,
|
|
44
|
+
PointElement,
|
|
45
|
+
ArcElement
|
|
46
|
+
} from 'chart.js'
|
|
47
|
+
import { Bar as BarChart, Doughnut as DoughnutChart, Line as LineChart } from 'vue-chartjs'
|
|
48
|
+
|
|
49
|
+
// Configurações padrões
|
|
50
|
+
import { charts, colors, font } from './config'
|
|
51
|
+
|
|
52
|
+
// Plugins
|
|
53
|
+
import zoomPlugin from 'chartjs-plugin-zoom'
|
|
54
|
+
import chartDataLabels from 'chartjs-plugin-datalabels'
|
|
55
|
+
|
|
56
|
+
// Outras importações
|
|
57
|
+
import { extend } from 'quasar'
|
|
58
|
+
import { filterListByHandle } from '../../helpers'
|
|
59
|
+
import { getAction } from '@bildvitta/store-adapter'
|
|
60
|
+
|
|
61
|
+
const ChartTypes = {
|
|
62
|
+
Bar: 'bar',
|
|
63
|
+
Doughnut: 'doughnut',
|
|
64
|
+
Line: 'line'
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export default {
|
|
68
|
+
name: 'QasChartView',
|
|
69
|
+
|
|
70
|
+
components: {
|
|
71
|
+
BarChart,
|
|
72
|
+
DoughnutChart,
|
|
73
|
+
LineChart
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
props: {
|
|
77
|
+
entity: {
|
|
78
|
+
required: true,
|
|
79
|
+
type: String
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
fetching: {
|
|
83
|
+
type: Boolean
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
filtersProps: {
|
|
87
|
+
default: () => ({}),
|
|
88
|
+
type: Object
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
height: {
|
|
92
|
+
default: '380px',
|
|
93
|
+
type: String
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
maxDoughnutSlices: {
|
|
97
|
+
default: 15,
|
|
98
|
+
type: Number
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
options: {
|
|
102
|
+
default: () => ({}),
|
|
103
|
+
type: Object
|
|
104
|
+
},
|
|
105
|
+
|
|
106
|
+
subtitle: {
|
|
107
|
+
default: '',
|
|
108
|
+
type: String
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
title: {
|
|
112
|
+
default: '',
|
|
113
|
+
type: String
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
type: {
|
|
117
|
+
default: ChartTypes.Bar,
|
|
118
|
+
type: String,
|
|
119
|
+
validator: value => Object.values(ChartTypes).includes(value)
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
url: {
|
|
123
|
+
default: '',
|
|
124
|
+
type: String
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
useFilterButton: {
|
|
128
|
+
type: Boolean
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
emits: [
|
|
133
|
+
'fetch-error',
|
|
134
|
+
'fetch-success',
|
|
135
|
+
'update:fetching'
|
|
136
|
+
],
|
|
137
|
+
|
|
138
|
+
data () {
|
|
139
|
+
return {
|
|
140
|
+
data: [],
|
|
141
|
+
filters: {},
|
|
142
|
+
isFetched: false,
|
|
143
|
+
isFetching: false
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
computed: {
|
|
148
|
+
chartData () {
|
|
149
|
+
if (!this.data.length) {
|
|
150
|
+
return {
|
|
151
|
+
labels: [],
|
|
152
|
+
datasets: []
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const [dataset] = this.data
|
|
157
|
+
const labels = this.getXAxisData(dataset.data.map(item => item.x))
|
|
158
|
+
|
|
159
|
+
const datasets = this.data.map(({ label, data }, index) => {
|
|
160
|
+
const backgroundColor = this.isDoughnut ? colors : colors.at(index)
|
|
161
|
+
const borderColor = this.isDoughnut ? 'white' : colors.at(index)
|
|
162
|
+
const yAxisData = []
|
|
163
|
+
const xAxisData = []
|
|
164
|
+
|
|
165
|
+
for (const dataKey in data) {
|
|
166
|
+
const item = data[dataKey]
|
|
167
|
+
|
|
168
|
+
if (item) {
|
|
169
|
+
yAxisData.push(item.y)
|
|
170
|
+
xAxisData.push(item.tooltip)
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return {
|
|
175
|
+
backgroundColor,
|
|
176
|
+
borderColor,
|
|
177
|
+
data: this.getYAxisData(yAxisData),
|
|
178
|
+
label,
|
|
179
|
+
tooltips: this.getXAxisData(xAxisData)
|
|
180
|
+
}
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
datasets,
|
|
185
|
+
labels
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
|
|
189
|
+
chartFiltersProps () {
|
|
190
|
+
const { entity, useFilterButton, url } = this
|
|
191
|
+
|
|
192
|
+
return {
|
|
193
|
+
class: 'q-mb-xs',
|
|
194
|
+
entity,
|
|
195
|
+
url,
|
|
196
|
+
useChip: false,
|
|
197
|
+
useFilterButton,
|
|
198
|
+
useSearch: false,
|
|
199
|
+
useSpacing: false,
|
|
200
|
+
useUpdateRoute: false,
|
|
201
|
+
|
|
202
|
+
...this.filtersProps
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
|
|
206
|
+
chartOptions () {
|
|
207
|
+
const { options, type } = this
|
|
208
|
+
|
|
209
|
+
return extend(true, charts[type], options)
|
|
210
|
+
},
|
|
211
|
+
|
|
212
|
+
chartPlugins () {
|
|
213
|
+
return filterListByHandle([
|
|
214
|
+
{
|
|
215
|
+
handle: this.isDoughnut,
|
|
216
|
+
item: chartDataLabels
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
handle: this.isBar || this.isLine,
|
|
220
|
+
item: zoomPlugin
|
|
221
|
+
}
|
|
222
|
+
])
|
|
223
|
+
},
|
|
224
|
+
|
|
225
|
+
chartType () {
|
|
226
|
+
const components = {
|
|
227
|
+
bar: 'BarChart',
|
|
228
|
+
doughnut: 'DoughnutChart',
|
|
229
|
+
line: 'LineChart'
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return components[this.type]
|
|
233
|
+
},
|
|
234
|
+
|
|
235
|
+
chartComponent () {
|
|
236
|
+
return {
|
|
237
|
+
is: this.chartType,
|
|
238
|
+
props: {
|
|
239
|
+
data: this.chartData,
|
|
240
|
+
options: this.chartOptions,
|
|
241
|
+
plugins: this.chartPlugins
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
},
|
|
245
|
+
|
|
246
|
+
parentComponentProps () {
|
|
247
|
+
return {
|
|
248
|
+
class: 'relative-position',
|
|
249
|
+
style: `min-height: ${this.height}`
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
|
|
253
|
+
hasDataSets () {
|
|
254
|
+
return !!this.chartData?.datasets.filter(dataset => dataset.data.length)?.length
|
|
255
|
+
},
|
|
256
|
+
|
|
257
|
+
hasHeaderActions () {
|
|
258
|
+
return this.title || this.subtitle || this.useFilterButton
|
|
259
|
+
},
|
|
260
|
+
|
|
261
|
+
isBar () {
|
|
262
|
+
return this.type === 'bar'
|
|
263
|
+
},
|
|
264
|
+
|
|
265
|
+
isDoughnut () {
|
|
266
|
+
return this.type === 'doughnut'
|
|
267
|
+
},
|
|
268
|
+
|
|
269
|
+
isLine () {
|
|
270
|
+
return this.type === 'line'
|
|
271
|
+
},
|
|
272
|
+
|
|
273
|
+
showChart () {
|
|
274
|
+
return this.isFetched && this.hasDataSets
|
|
275
|
+
},
|
|
276
|
+
|
|
277
|
+
defaultChartItems () {
|
|
278
|
+
return [
|
|
279
|
+
CategoryScale,
|
|
280
|
+
LinearScale,
|
|
281
|
+
PointElement,
|
|
282
|
+
Title,
|
|
283
|
+
Tooltip,
|
|
284
|
+
Legend
|
|
285
|
+
]
|
|
286
|
+
},
|
|
287
|
+
|
|
288
|
+
elementsChartItems () {
|
|
289
|
+
return {
|
|
290
|
+
bar: [BarElement],
|
|
291
|
+
doughnut: [ArcElement],
|
|
292
|
+
line: [LineElement]
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
},
|
|
296
|
+
|
|
297
|
+
watch: {
|
|
298
|
+
filters () {
|
|
299
|
+
this.fetchData()
|
|
300
|
+
},
|
|
301
|
+
|
|
302
|
+
isFetching (value) {
|
|
303
|
+
this.$emit('update:fetching', value)
|
|
304
|
+
}
|
|
305
|
+
},
|
|
306
|
+
|
|
307
|
+
created () {
|
|
308
|
+
this.registerChartJS()
|
|
309
|
+
this.fetchData()
|
|
310
|
+
},
|
|
311
|
+
|
|
312
|
+
unmounted () {
|
|
313
|
+
this.unregisterChartJS()
|
|
314
|
+
},
|
|
315
|
+
|
|
316
|
+
methods: {
|
|
317
|
+
async fetchData () {
|
|
318
|
+
try {
|
|
319
|
+
this.isFetching = true
|
|
320
|
+
|
|
321
|
+
const response = await getAction.call(this, {
|
|
322
|
+
entity: this.entity,
|
|
323
|
+
key: 'fetchList',
|
|
324
|
+
payload: {
|
|
325
|
+
url: this.url,
|
|
326
|
+
filters: this.filters
|
|
327
|
+
}
|
|
328
|
+
})
|
|
329
|
+
|
|
330
|
+
const { results } = response.data
|
|
331
|
+
this.data = results
|
|
332
|
+
|
|
333
|
+
this.$emit('fetch-success', response)
|
|
334
|
+
} catch (error) {
|
|
335
|
+
this.$qas.error('Ops… Não conseguimos acessar as informações. Por favor, tente novamente em alguns minutos.')
|
|
336
|
+
|
|
337
|
+
this.$emit('fetch-error', error)
|
|
338
|
+
} finally {
|
|
339
|
+
this.isFetching = false
|
|
340
|
+
this.isFetched = true
|
|
341
|
+
}
|
|
342
|
+
},
|
|
343
|
+
|
|
344
|
+
getXAxisData (data = []) {
|
|
345
|
+
if (this.isDoughnut && data.length > this.maxDoughnutSlices) {
|
|
346
|
+
data = data.slice(0, this.maxDoughnutSlices - 1)
|
|
347
|
+
data.push('Outros')
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
return data
|
|
351
|
+
},
|
|
352
|
+
|
|
353
|
+
getYAxisData (data = []) {
|
|
354
|
+
if (this.isDoughnut && data.length > this.maxDoughnutSlices) {
|
|
355
|
+
const otherSlicesValues = data
|
|
356
|
+
.slice(this.maxDoughnutSlices - 1)
|
|
357
|
+
.reduce((accumulator, currentValue) => accumulator + currentValue, 0)
|
|
358
|
+
|
|
359
|
+
data = data.slice(0, this.maxDoughnutSlices - 1)
|
|
360
|
+
data.push(otherSlicesValues)
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
return data
|
|
364
|
+
},
|
|
365
|
+
|
|
366
|
+
registerChartJS () {
|
|
367
|
+
ChartJS.register(
|
|
368
|
+
...this.defaultChartItems,
|
|
369
|
+
...this.elementsChartItems[this.type]
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
ChartJS.defaults.font = font
|
|
373
|
+
},
|
|
374
|
+
|
|
375
|
+
unregisterChartJS () {
|
|
376
|
+
ChartJS.unregister(
|
|
377
|
+
...this.defaultChartItems,
|
|
378
|
+
...this.elementsChartItems[this.type]
|
|
379
|
+
)
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
</script>
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
type: component
|
|
2
|
+
|
|
3
|
+
meta:
|
|
4
|
+
desc: Componente responsável pela renderização de gráficos
|
|
5
|
+
|
|
6
|
+
props:
|
|
7
|
+
entity:
|
|
8
|
+
desc: Entidade da store, por exemplo se tiver que trabalhar com modulo de usuários, teremos o model "users" na store, que vai ser nossa "entity".
|
|
9
|
+
required: true
|
|
10
|
+
type: String
|
|
11
|
+
|
|
12
|
+
fetching:
|
|
13
|
+
model: true
|
|
14
|
+
desc: Model de fetching, utilizado para saber se o componente está fazendo fetching de dados.
|
|
15
|
+
type: Boolean
|
|
16
|
+
examples: [v-model:fetching="isFetching"]
|
|
17
|
+
|
|
18
|
+
filters-props:
|
|
19
|
+
desc: Repassa as props para o componente "QasFilters".
|
|
20
|
+
default: {}
|
|
21
|
+
type: Object
|
|
22
|
+
|
|
23
|
+
height:
|
|
24
|
+
desc: Define a altura do gráfico.
|
|
25
|
+
default: 380px
|
|
26
|
+
type: String
|
|
27
|
+
|
|
28
|
+
max-doughnut-slices:
|
|
29
|
+
desc: Define o máximo de fatias que o gráfico de Doughnut poderá ter. Passando o número máximo definido, o gráfico irá exibir uma fatia chamada "Outros".
|
|
30
|
+
default: 15
|
|
31
|
+
type: Number
|
|
32
|
+
|
|
33
|
+
options:
|
|
34
|
+
desc: Opções do chart.js que serão mescladas com as opções padrões pré definidas.
|
|
35
|
+
default: {}
|
|
36
|
+
type: Object
|
|
37
|
+
|
|
38
|
+
subtitle:
|
|
39
|
+
desc: Define um subtítulo para o gráfico.
|
|
40
|
+
type: String
|
|
41
|
+
|
|
42
|
+
title:
|
|
43
|
+
desc: Define um título para o gráfico.
|
|
44
|
+
type: String
|
|
45
|
+
|
|
46
|
+
type:
|
|
47
|
+
desc: Tipo de exibição do gráfico.
|
|
48
|
+
default: bar
|
|
49
|
+
type: String
|
|
50
|
+
examples: [bar, doughnut, line]
|
|
51
|
+
|
|
52
|
+
url:
|
|
53
|
+
desc: Envia como parâmetro para a action "fetchList" do modulo correspondente a "entity".
|
|
54
|
+
type: String
|
|
55
|
+
|
|
56
|
+
use-filter-button:
|
|
57
|
+
desc: Controla se o componente vai usar ou não o componente "QasFilters".
|
|
58
|
+
type: Boolean
|
|
59
|
+
|
|
60
|
+
slots:
|
|
61
|
+
default:
|
|
62
|
+
desc: 'Slot para ter o conteúdo principal (dentro do main).'
|
|
63
|
+
|
|
64
|
+
empty-results:
|
|
65
|
+
desc: 'Slot acessar quando a listagem está vazia.'
|
|
66
|
+
|
|
67
|
+
events:
|
|
68
|
+
'@fetch-error -> function(value)':
|
|
69
|
+
desc: Dispara quando a action "fetchList" cai em uma exceção.
|
|
70
|
+
params:
|
|
71
|
+
value:
|
|
72
|
+
desc: Retorna todos os dados "cru" respondido na exceção do fetch.
|
|
73
|
+
type: Object
|
|
74
|
+
|
|
75
|
+
'@fetch-success -> function(value)':
|
|
76
|
+
desc: Dispara quando a action "fetchList" é executada com sucesso.
|
|
77
|
+
params:
|
|
78
|
+
value:
|
|
79
|
+
desc: Retorna todos os dados "cru" respondido pelo fetch.
|
|
80
|
+
type: Object
|
|
81
|
+
|
|
82
|
+
'@update:fetching -> function(value)':
|
|
83
|
+
desc: Dispara logo antes da action "fetchList" e ao cair no bloco "finally", ou seja, quando começar o fetching e após terminar.
|
|
84
|
+
params:
|
|
85
|
+
value:
|
|
86
|
+
desc: Retorna se está ou não fazendo fetching de dados.
|
|
87
|
+
type: Boolean
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { textColor } from '../defaults'
|
|
2
|
+
import { legendPluginConfig, tooltipPluginConfig, zoomPluginConfig } from '../plugins'
|
|
3
|
+
|
|
4
|
+
export const bar = {
|
|
5
|
+
barPercentage: 0.7,
|
|
6
|
+
borderSkipped: true,
|
|
7
|
+
borderWidth: 2,
|
|
8
|
+
color: textColor,
|
|
9
|
+
maintainAspectRatio: false,
|
|
10
|
+
plugins: {
|
|
11
|
+
legend: legendPluginConfig,
|
|
12
|
+
tooltip: tooltipPluginConfig,
|
|
13
|
+
zoom: zoomPluginConfig
|
|
14
|
+
},
|
|
15
|
+
responsive: true,
|
|
16
|
+
scales: {
|
|
17
|
+
x: {
|
|
18
|
+
border: {
|
|
19
|
+
display: false
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
grid: {
|
|
23
|
+
display: false
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
ticks: {
|
|
27
|
+
padding: 8
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
y: {
|
|
32
|
+
border: {
|
|
33
|
+
display: false
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
grid: {
|
|
37
|
+
display: false
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
ticks: {
|
|
41
|
+
stepSize: 1
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { tooltipPluginConfig } from '../plugins'
|
|
2
|
+
import { percent } from '../../../../helpers'
|
|
3
|
+
|
|
4
|
+
function getPercentFormat (value, context) {
|
|
5
|
+
const total = context.dataset.data.reduce((accumulator, currentValue, index) => {
|
|
6
|
+
if (context.chart._hiddenIndices?.[index]) return accumulator
|
|
7
|
+
|
|
8
|
+
return accumulator + currentValue
|
|
9
|
+
}, 0)
|
|
10
|
+
|
|
11
|
+
const percentage = (value * 100) / total
|
|
12
|
+
const places = percentage % 1 ? 2 : 0
|
|
13
|
+
|
|
14
|
+
return percentage >= 5 ? percent(percentage, places) : ''
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const doughnut = {
|
|
18
|
+
borderSkipped: true,
|
|
19
|
+
borderWidth: 1,
|
|
20
|
+
maintainAspectRatio: false,
|
|
21
|
+
responsive: true,
|
|
22
|
+
plugins: {
|
|
23
|
+
datalabels: {
|
|
24
|
+
color: 'white',
|
|
25
|
+
font: {
|
|
26
|
+
weight: 600
|
|
27
|
+
},
|
|
28
|
+
formatter: getPercentFormat
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
legend: {
|
|
32
|
+
align: 'center',
|
|
33
|
+
labels: {
|
|
34
|
+
padding: 16,
|
|
35
|
+
pointStyle: 'circle',
|
|
36
|
+
usePointStyle: true
|
|
37
|
+
},
|
|
38
|
+
position: 'bottom'
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
tooltip: tooltipPluginConfig
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { textColor } from '../defaults'
|
|
2
|
+
import { legendPluginConfig, tooltipPluginConfig, zoomPluginConfig } from '../plugins'
|
|
3
|
+
|
|
4
|
+
export const line = {
|
|
5
|
+
borderSkipped: true,
|
|
6
|
+
borderWidth: 2,
|
|
7
|
+
color: textColor,
|
|
8
|
+
maintainAspectRatio: false,
|
|
9
|
+
pointStyle: false,
|
|
10
|
+
responsive: true,
|
|
11
|
+
|
|
12
|
+
layout: {
|
|
13
|
+
padding: {
|
|
14
|
+
left: -24
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
plugins: {
|
|
19
|
+
legend: legendPluginConfig,
|
|
20
|
+
tooltip: tooltipPluginConfig,
|
|
21
|
+
zoom: zoomPluginConfig
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
scales: {
|
|
25
|
+
x: {
|
|
26
|
+
border: {
|
|
27
|
+
display: false
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
grid: {
|
|
31
|
+
color: '#E0E0E0'
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
ticks: {
|
|
35
|
+
padding: 8
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
y: {
|
|
40
|
+
beginAtZero: true,
|
|
41
|
+
offset: true,
|
|
42
|
+
|
|
43
|
+
border: {
|
|
44
|
+
display: false
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
grid: {
|
|
48
|
+
color: '#E0E0E0'
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
ticks: {
|
|
52
|
+
padding: 24,
|
|
53
|
+
stepSize: 1
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export const colors = [
|
|
2
|
+
'#1976D2',
|
|
3
|
+
'#90CAF9',
|
|
4
|
+
'#2962FF',
|
|
5
|
+
'#004198',
|
|
6
|
+
'#00C853',
|
|
7
|
+
'#651FFF',
|
|
8
|
+
'#26C6DA',
|
|
9
|
+
'#1976D2',
|
|
10
|
+
'#2196F3',
|
|
11
|
+
'#536DFE',
|
|
12
|
+
'#26A69A',
|
|
13
|
+
'#3F51B5',
|
|
14
|
+
'#43A047',
|
|
15
|
+
'#7E57C2',
|
|
16
|
+
'#8BC34A'
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
export const textColor = '#616161'
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const tooltipPluginConfig = {
|
|
2
|
+
backgroundColor: '#212121',
|
|
3
|
+
boxPadding: 4,
|
|
4
|
+
callbacks: {
|
|
5
|
+
title: function (items) {
|
|
6
|
+
return items.map(item => item.dataset.tooltips[item.dataIndex] || item.label)
|
|
7
|
+
}
|
|
8
|
+
},
|
|
9
|
+
caretSize: 0,
|
|
10
|
+
cornerRadius: 4,
|
|
11
|
+
displayColors: false,
|
|
12
|
+
padding: 12,
|
|
13
|
+
titleColor: '#fff',
|
|
14
|
+
titleMarginBottom: 8
|
|
15
|
+
}
|