Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Chart.js 3.0 support #754

Merged
merged 11 commits into from Feb 21, 2022
6 changes: 3 additions & 3 deletions package.json
Expand Up @@ -59,7 +59,7 @@
"start:storybook": "start-storybook -p 6006"
},
"peerDependencies": {
"chart.js": ">= 2.5"
"chart.js": "^3.7.0"
},
"dependencies": {
"@types/chart.js": "^2.7.55"
Expand All @@ -76,13 +76,13 @@
"@swc/core": "^1.2.120",
"@swc/helpers": "^0.3.2",
"@swc/jest": "^0.2.15",
"@types/chart.js": "^2.7.55",
"@types/chart.js": "^3.7.0",
dangreen marked this conversation as resolved.
Show resolved Hide resolved
"@vue/test-utils": "^1.3.0",
"@vue/vue2-jest": "^27.0.0-alpha.4",
"babel-jest": "^27.4.5",
"babel-loader": "8.2.3",
"browserslist": "^4.19.1",
"chart.js": "^2.8.0",
"chart.js": "^3.7.0",
"clean-publish": "^4.0.0",
"commitizen": "^4.2.4",
"cross-env": "^5.1.1",
Expand Down
25 changes: 5 additions & 20 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 18 additions & 7 deletions sandboxes/custom/src/components/customChart.vue
Expand Up @@ -4,13 +4,18 @@
#in an empty template and unexpected errors.

<script>
import Chart from 'chart.js'
import {
LineController,
LineElement,
PointElement,
CategoryScale,
LinearScale
} from 'chart.js'
import { generateChart } from 'vue-chartjs'

Chart.defaults.LineWithLine = Chart.defaults.line
Chart.controllers.LineWithLine = Chart.controllers.line.extend({
draw: function (ease) {
Chart.controllers.line.prototype.draw.call(this, ease)
class LineWithLineController extends LineController {
draw() {
super.draw(arguments)

if (this.chart.tooltip._active && this.chart.tooltip._active.length) {
let activePoint = this.chart.tooltip._active[0]
Expand All @@ -30,9 +35,15 @@ Chart.controllers.LineWithLine = Chart.controllers.line.extend({
ctx.restore()
}
}
})
}

const LineWithLine = generateChart('line-with-chart', 'LineWithLine')
const LineWithLine = generateChart(
'line-with-chart',
'line',
[LineElement, PointElement],
LineWithLineController,
[CategoryScale, LinearScale]
)

export default {
name: 'CustomChart',
Expand Down
161 changes: 135 additions & 26 deletions src/BaseCharts.js
@@ -1,6 +1,33 @@
import Chart from 'chart.js'
import {
Chart,
ArcElement,
BarElement,
LineElement,
BarController,
PointElement,
BubbleController,
DoughnutController,
LineController,
PieController,
PolarAreaController,
RadarController,
ScatterController,
LinearScale,
CategoryScale,
RadialLinearScale,
Title,
Tooltip,
Legend
} from 'chart.js'

export function generateChart(chartId, chartType) {
export function generateChart(
chartId,
chartType,
chartElements,
chartController,
chartScales,
dangreen marked this conversation as resolved.
Show resolved Hide resolved
defaultOptions
) {
return {
render: function (createElement) {
return createElement(
Expand Down Expand Up @@ -49,34 +76,56 @@ export function generateChart(chartId, chartType) {
}
}
},

data() {
return {
_chart: null,
_plugins: this.plugins
_chart: null
}
},

created() {
Chart.register(
...chartElements,
chartController,
...chartScales,
Title,
Tooltip,
Legend
)
},
methods: {
addPlugin(plugin) {
this.$data._plugins.push(plugin)
},
generateLegend() {
renderChart(data, options) {
if (this.$data._chart) {
return this.$data._chart.generateLegend()
this.$data._chart.destroy()
}
},
renderChart(data, options) {
if (this.$data._chart) this.$data._chart.destroy()
if (!this.$refs.canvas)

if (!this.$refs.canvas) {
throw new Error(
'Please remove the <template></template> tags from your chart component. See https://vue-chartjs.org/guide/#vue-single-file-components'
)
}

const chartOptions = options

if (
typeof defaultOptions !== 'undefined' &&
defaultOptions.length > 0
) {
for (const defaultOption of defaultOptions) {
for (const defaultOptionKey of Object.keys(defaultOption)) {
chartOptions[defaultOptionKey] = defaultOption[defaultOptionKey]
}
}
}

if (this.plugins.length > 0) {
for (const plugin of this.plugins) {
chartOptions['plugins'] = { ...chartOptions.plugins, ...plugin }
}
}

this.$data._chart = new Chart(this.$refs.canvas.getContext('2d'), {
type: chartType,
data: data,
options: options,
plugins: this.$data._plugins
options: chartOptions
})
}
},
Expand All @@ -88,18 +137,78 @@ export function generateChart(chartId, chartType) {
}
}

export const Bar = generateChart('bar-chart', 'bar')
export const Bar = generateChart(
dangreen marked this conversation as resolved.
Show resolved Hide resolved
'bar-chart',
'bar',
[BarElement],
BarController,
[LinearScale, CategoryScale]
dangreen marked this conversation as resolved.
Show resolved Hide resolved
)

export const HorizontalBar = generateChart(
'horizontalbar-chart',
'horizontalBar'
'bar',
[BarElement],
BarController,
[CategoryScale],
[{ indexAxis: 'y' }]
)

export const Doughnut = generateChart(
'doughnut-chart',
'doughnut',
[ArcElement],
DoughnutController,
[CategoryScale]
)

export const Line = generateChart(
'line-chart',
'line',
[LineElement],
LineController,
[LinearScale]
)

export const Pie = generateChart(
'pie-chart',
'pie',
[ArcElement],
PieController,
[CategoryScale]
)

export const PolarArea = generateChart(
'polar-chart',
'polarArea',
[ArcElement],
PolarAreaController,
[RadialLinearScale]
)

export const Radar = generateChart(
'radar-chart',
'radar',
[PointElement],
RadarController,
[RadialLinearScale]
)

export const Bubble = generateChart(
'bubble-chart',
'bubble',
[PointElement],
BubbleController,
[LinearScale]
)

export const Scatter = generateChart(
'scatter-chart',
'scatter',
[LineElement],
ScatterController,
[CategoryScale]
)
export const Doughnut = generateChart('doughnut-chart', 'doughnut')
export const Line = generateChart('line-chart', 'line')
export const Pie = generateChart('pie-chart', 'pie')
export const PolarArea = generateChart('polar-chart', 'polarArea')
export const Radar = generateChart('radar-chart', 'radar')
export const Bubble = generateChart('bubble-chart', 'bubble')
export const Scatter = generateChart('scatter-chart', 'scatter')

export default {
Bar,
Expand Down
25 changes: 6 additions & 19 deletions test/Bar.spec.js
Expand Up @@ -32,42 +32,29 @@ describe('BarChart', () => {
it('should destroy chart instance', done => {
const wrapper = mount(Component)
const { vm } = wrapper

expect(vm.$children[0].$data._chart.chart.ctx).not.toBe(null)
expect(vm.$children[0].$data._chart.ctx).not.toBe(null)

vm.$destroy()

vm.$nextTick(() => {
vm.$forceUpdate()
expect(vm.$children[0].$data._chart.chart.ctx).toBe(null)
expect(vm.$children[0].$data._chart.ctx).toBe(null)
done()
})
})

it('should add an inline plugin to the array', () => {
const testPlugin = {
id: 'test'
}

const wrapper = mount(Component)
const { vm } = wrapper

expect(vm.$children[0].$data._plugins).toEqual([])
vm.$children[0].addPlugin(testPlugin)

expect(vm.$children[0].$data._plugins.length).toEqual(1)
})

it('should add inline plugins based on prop', () => {
const testPlugin = {
id: 'test'
title: {
display: true
}
}

const wrapper = mount(Component, {
propsData: { plugins: [testPlugin] }
})
const { vm } = wrapper

expect(vm.$children[0].$data._plugins.length).toEqual(1)
expect(Object.keys(vm.$children[0].$data.options.plugins).length).toEqual(1)
})
})