Skip to content

Commit 2df29e1

Browse files
authored
Merge pull request #11 from apertureless/feature/reactive_chart_data
WIP Feature/reactive chart data #11
2 parents ae93b96 + 6f77de8 commit 2df29e1

File tree

12 files changed

+224
-16
lines changed

12 files changed

+224
-16
lines changed

README.md

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ Just create your own component.
3636
// CommitChart.js
3737
import { Bar } from 'vue-chartjs'
3838

39-
export default BarChart.extend({
39+
export default Bar.extend({
4040
mounted () {
4141
// Overwriting base render method with actual data.
4242
this.renderChart({
@@ -67,7 +67,7 @@ You can overwrite the default chart options. Just pass the options object as a s
6767
// MonthlyIncome.js
6868
import { Line } from 'vue-chartjs'
6969

70-
export default LineChart.extend({
70+
export default Line.extend({
7171
props: [data, options],
7272
mounted () {
7373
this.renderChart(this.data, this.options)
@@ -92,6 +92,30 @@ export default {
9292
</script>
9393
```
9494

95+
## Reactivity
96+
97+
Chart.js does not update or re-render the chart if new data is passed.
98+
However you can simply implement this by your own or use one of the two mixins which are included.
99+
100+
- `reactiveProp`
101+
- `reactiveData`
102+
103+
The mixins automatically create `chartData` as a prop or data. And add a watcher. If data has changed, the chart will update.
104+
105+
```javascript
106+
// MonthlyIncome.js
107+
import { Line, reactiveProp } from 'vue-chartjs'
108+
109+
export default Line.extend({
110+
mixins: [reactiveProp]
111+
props: [chartData, options],
112+
mounted () {
113+
this.renderChart(this.chartData, this.options)
114+
}
115+
})
116+
117+
```
118+
95119
## Available Charts
96120

97121
### Bar Chart

codecov.yml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
codecov:
2+
branch: master
3+
4+
coverage:
5+
precision: 2
6+
round: down
7+
range: "70...100"
8+
9+
status:
10+
project:
11+
default:
12+
target: auto
13+
threshold: null
14+
branches: null
15+
16+
patch:
17+
default:
18+
target: auto
19+
branches: null
20+
21+
changes:
22+
default:
23+
branches: null
24+
25+
ignore:
26+
- "tests/*"
27+
- "src/examples/*"
28+
- "src/mixins/*"
29+
30+
31+
comment:
32+
layout: "header, diff, changes, sunburst, uncovered, tree"
33+
branches: null
34+
behavior: default

package.json

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@
3838
"chai": "^3.5.0",
3939
"chromedriver": "^2.21.2",
4040
"connect-history-api-fallback": "^1.1.0",
41-
"cross-spawn": "^2.1.5",
41+
"cross-spawn": "^4.0.2",
4242
"css-loader": "^0.25.0",
43-
"eslint": "^3.7.0",
43+
"eslint": "^3.7.1",
4444
"eslint-config-standard": "^6.2.0",
4545
"eslint-friendly-formatter": "^2.0.5",
4646
"eslint-loader": "^1.3.0",
@@ -56,23 +56,25 @@
5656
"http-proxy-middleware": "^0.17.2",
5757
"inject-loader": "^2.0.1",
5858
"isparta-loader": "^2.0.0",
59+
"jasmine-core": "^2.5.2",
5960
"json-loader": "^0.5.4",
60-
"karma": "^0.13.15",
61-
"karma-coverage": "^0.5.5",
62-
"karma-mocha": "^0.2.2",
61+
"karma": "^1.3.0",
62+
"karma-coverage": "^1.1.1",
63+
"karma-jasmine": "^1.0.2",
64+
"karma-mocha": "^1.2.0",
6365
"karma-phantomjs-launcher": "^1.0.0",
6466
"karma-sinon-chai": "^1.2.0",
6567
"karma-sourcemap-loader": "^0.3.7",
6668
"karma-spec-reporter": "0.0.26",
6769
"karma-webpack": "^1.7.0",
68-
"lodash": "^4.15.0",
70+
"lodash": "^4.16.3",
6971
"lolex": "^1.4.0",
7072
"mocha": "^3.1.0",
71-
"nightwatch": "^0.8.18",
72-
"ora": "^0.2.0",
73-
"phantomjs-prebuilt": "^2.1.3",
73+
"nightwatch": "^0.9.8",
74+
"ora": "^0.3.0",
75+
"phantomjs-prebuilt": "^2.1.13",
7476
"selenium-server": "^2.53.1",
75-
"shelljs": "^0.6.0",
77+
"shelljs": "^0.7.4",
7678
"sinon": "^1.17.3",
7779
"sinon-chai": "^2.8.0",
7880
"url-loader": "^0.5.7",
@@ -83,6 +85,6 @@
8385
"webpack": "^1.13.2",
8486
"webpack-dev-middleware": "^1.4.0",
8587
"webpack-hot-middleware": "^2.6.0",
86-
"webpack-merge": "^0.8.3"
88+
"webpack-merge": "^0.14.1"
8789
}
8890
}

src/examples/App.vue

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<template>
22
<div class="container">
33
<bar-example></bar-example>
4+
<reactive-example></reactive-example>
45
<line-example></line-example>
56
<doughnut-example></doughnut-example>
67
<pie-example></pie-example>
@@ -18,9 +19,21 @@
1819
import RadarExample from './RadarExample'
1920
import PolarAreaExample from './PolarAreaExample'
2021
import BubbleExample from './BubbleExample'
22+
import ReactiveExample from './ReactiveExample'
23+
import ReactivePropExample from './ReactivePropExample'
2124
2225
export default {
23-
components: { BarExample, LineExample, DoughnutExample, PieExample, RadarExample, PolarAreaExample, BubbleExample }
26+
components: {
27+
BarExample,
28+
LineExample,
29+
DoughnutExample,
30+
PieExample,
31+
RadarExample,
32+
PolarAreaExample,
33+
BubbleExample,
34+
ReactiveExample,
35+
ReactivePropExample
36+
}
2437
}
2538
</script>
2639

src/examples/ReactiveExample.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import BarChart from '../BaseCharts/Bar'
2+
import reactiveData from '../mixins/reactiveData'
3+
4+
export default BarChart.extend({
5+
mixins: [reactiveData],
6+
data () {
7+
return {
8+
chartData: ''
9+
}
10+
},
11+
created () {
12+
this.fillData()
13+
},
14+
15+
mounted () {
16+
this.renderChart(this.chartData)
17+
18+
setInterval(() => {
19+
this.fillData()
20+
}, 5000)
21+
},
22+
23+
methods: {
24+
fillData () {
25+
this.chartData = {
26+
labels: ['January' + this.getRandomInt(), 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
27+
datasets: [
28+
{
29+
label: 'Data One',
30+
backgroundColor: '#f87979',
31+
data: [this.getRandomInt(), this.getRandomInt(), this.getRandomInt(), this.getRandomInt(), this.getRandomInt(), this.getRandomInt(), this.getRandomInt(), this.getRandomInt(), this.getRandomInt(), this.getRandomInt(), this.getRandomInt(), this.getRandomInt()]
32+
}
33+
]
34+
}
35+
},
36+
37+
getRandomInt () {
38+
return Math.floor(Math.random() * (50 - 5 + 1)) + 5
39+
}
40+
}
41+
})
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import BarChart from '../BaseCharts/Bar'
2+
import reactiveData from '../mixins/reactiveProp'
3+
4+
export default BarChart.extend({
5+
mixins: [reactiveData],
6+
7+
mounted () {
8+
this.renderChart(this.chartData)
9+
}
10+
})

src/index.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import Pie from './BaseCharts/Pie'
55
import PolarArea from './BaseCharts/PolarArea'
66
import Radar from './BaseCharts/Radar'
77
import Bubble from './BaseCharts/Bubble'
8+
import reactiveProp from './mixins/reactiveProp'
9+
import reactiveData from './mixins/reactiveData'
810

911
const VueCharts = {
1012
Bar,
@@ -13,7 +15,9 @@ const VueCharts = {
1315
Pie,
1416
PolarArea,
1517
Radar,
16-
Bubble
18+
Bubble,
19+
reactiveProp,
20+
reactiveData
1721
}
1822

1923
module.exports = VueCharts

src/mixins/reactiveData.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
module.exports = {
2+
data () {
3+
return {
4+
chartData: null
5+
}
6+
},
7+
watch: {
8+
'chartData': {
9+
handler (newData, oldData) {
10+
if (oldData) {
11+
let chart = this._chart
12+
13+
let newDataLabels = newData.datasets.map((dataset) => {
14+
return dataset.label
15+
})
16+
17+
let oldDataLabels = oldData.datasets.map((dataset) => {
18+
return dataset.label
19+
})
20+
21+
if (JSON.stringify(newDataLabels) === JSON.stringify(oldDataLabels)) {
22+
this.forceUpdate(newData, chart)
23+
} else {
24+
this.forceRender()
25+
}
26+
}
27+
}
28+
}
29+
},
30+
methods: {
31+
forceUpdate (newData, chart) {
32+
newData.datasets.forEach((dataset, i) => {
33+
chart.data.datasets[i].data = dataset.data
34+
})
35+
36+
chart.data.labels = newData.labels
37+
chart.update()
38+
},
39+
40+
forceRender () {
41+
this.renderChart(this.chartData, this.options)
42+
}
43+
}
44+
}

src/mixins/reactiveProp.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
module.exports = {
2+
props: {
3+
chartData: {
4+
required: true
5+
}
6+
},
7+
8+
watch: {
9+
'chartData': {
10+
handler (newData, oldData) {
11+
if (oldData) {
12+
let chart = this._chart
13+
14+
let newDataLabels = newData.datasets.map((dataset) => {
15+
return dataset.label
16+
})
17+
18+
let oldDataLabels = oldData.datasets.map((dataset) => {
19+
return dataset.label
20+
})
21+
22+
if (JSON.stringify(newDataLabels) === JSON.stringify(oldDataLabels)) {
23+
newData.datasets.forEach((dataset, i) => {
24+
chart.data.datasets[i].data = dataset.data
25+
})
26+
chart.data.labels = newData.labels
27+
chart.update()
28+
} else {
29+
this.renderChart(this.chartData, this.options)
30+
}
31+
}
32+
}
33+
}
34+
}
35+
}

test/unit/.eslintrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
},
55
"globals": {
66
"expect": true,
7+
"jasmine": true,
78
"sinon": true
89
}
910
}

0 commit comments

Comments
 (0)