├── .clean-publish ├── .codeclimate.yml ├── .commitlintrc.json ├── .czrc ├── .editorconfig ├── .eslintrc.cjs ├── .github ├── CONTRIBUTING.md ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug-report.yml │ ├── config.yml │ └── feature-request.yml ├── renovate.json └── workflows │ ├── checks.yml │ ├── ci.yml │ ├── commit.yml │ ├── release.yml │ └── website.yml ├── .gitignore ├── .nano-staged.json ├── .npmrc ├── .prettierrc ├── .simple-git-hooks.json ├── .size-limit.json ├── .storybook ├── main.js ├── manager.js ├── package.json ├── preview.js └── theme.js ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── assets ├── bar.png ├── bubble.png ├── donate.svg ├── doughnut.png ├── line.png ├── logo.png ├── pie.png ├── polar.png ├── radar.png ├── scatter.png ├── vue-chartjs.png └── vue-chartjs.svg ├── codecov.yml ├── package.json ├── pnpm-lock.yaml ├── rollup.config.js ├── sandboxes ├── bar │ ├── index.html │ ├── index.ts │ ├── package.json │ ├── src │ │ ├── App.vue │ │ └── chartConfig.ts │ └── vite.config.js ├── bubble │ ├── index.html │ ├── index.ts │ ├── package.json │ ├── src │ │ ├── App.vue │ │ └── chartConfig.ts │ └── vite.config.js ├── custom │ ├── index.html │ ├── index.ts │ ├── package.json │ ├── src │ │ ├── App.vue │ │ ├── chartConfig.ts │ │ └── components │ │ │ └── LineWithLineChart.ts │ └── vite.config.js ├── doughnut │ ├── index.html │ ├── index.ts │ ├── package.json │ ├── src │ │ ├── App.vue │ │ └── chartConfig.ts │ └── vite.config.js ├── events │ ├── index.html │ ├── index.ts │ ├── package.json │ ├── src │ │ ├── App.vue │ │ └── chartConfig.ts │ └── vite.config.js ├── line │ ├── index.html │ ├── index.ts │ ├── package.json │ ├── src │ │ ├── App.vue │ │ └── chartConfig.ts │ └── vite.config.js ├── pie │ ├── index.html │ ├── index.ts │ ├── package.json │ ├── src │ │ ├── App.vue │ │ └── chartConfig.ts │ └── vite.config.js ├── polar-area │ ├── index.html │ ├── index.ts │ ├── package.json │ ├── src │ │ ├── App.vue │ │ └── chartConfig.ts │ └── vite.config.js ├── radar │ ├── index.html │ ├── index.ts │ ├── package.json │ ├── src │ │ ├── App.vue │ │ └── chartConfig.ts │ └── vite.config.js ├── reactive │ ├── index.html │ ├── index.ts │ ├── package.json │ ├── src │ │ ├── App.vue │ │ └── chartConfig.ts │ └── vite.config.js ├── scatter │ ├── index.html │ ├── index.ts │ ├── package.json │ ├── src │ │ ├── App.vue │ │ └── chartConfig.ts │ └── vite.config.js └── tsconfig.json ├── src ├── chart.ts ├── index.ts ├── props.ts ├── typedCharts.ts ├── types.ts └── utils.ts ├── stories ├── bar.stories.ts ├── bubble.stories.ts ├── chart.stories.ts ├── custom.stories.ts ├── doughnut.stories.ts ├── line.stories.ts ├── pie.stories.ts ├── polarArea.stories.ts ├── radar.stories.ts ├── reactive.stories.ts └── scatter.stories.ts ├── test ├── Bar.spec.ts ├── Bubble.spec.ts ├── Doughnut.spec.ts ├── Line.spec.ts ├── Pie.spec.ts ├── PolarArea.spec.ts ├── Radar.spec.ts ├── Scatter.spec.ts ├── setup.js └── types.test-d.ts ├── tsconfig.json ├── vite.config.js └── website ├── package.json ├── pnpm-lock.yaml └── src ├── .vitepress ├── cache │ └── deps │ │ ├── @theme_index.js │ │ ├── @theme_index.js.map │ │ ├── _metadata.json │ │ ├── chunk-6J5AW4SK.js │ │ ├── chunk-6J5AW4SK.js.map │ │ ├── chunk-PWVUJGW4.js │ │ ├── chunk-PWVUJGW4.js.map │ │ ├── package.json │ │ ├── vitepress___@vue_devtools-api.js │ │ ├── vitepress___@vue_devtools-api.js.map │ │ ├── vitepress___@vueuse_core.js │ │ ├── vitepress___@vueuse_core.js.map │ │ ├── vue.js │ │ └── vue.js.map └── config.mts ├── CNAME ├── api └── index.md ├── de ├── api │ └── index.md ├── examples │ └── index.md ├── guide │ ├── examples.md │ └── index.md ├── index.md └── migration-guides │ ├── index.md │ ├── v4.md │ ├── v5.md │ └── vue-chart-3.md ├── examples └── index.md ├── guide ├── examples.md └── index.md ├── index.md ├── migration-guides ├── index.md ├── v4.md ├── v5.md └── vue-chart-3.md ├── package.json ├── pnpm-lock.yaml └── public └── vue-chartjs.png /.clean-publish: -------------------------------------------------------------------------------- 1 | { 2 | "withoutPublish": true, 3 | "tempDir": "package", 4 | "fields": ["tsd"], 5 | "files": ["website"] 6 | } 7 | -------------------------------------------------------------------------------- /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | engines: 2 | eslint: 3 | enabled: true 4 | duplication: 5 | enabled: true 6 | config: 7 | languages: 8 | - javascript: 9 | ratings: 10 | paths: 11 | - "**.js" 12 | exclude_paths: 13 | - "dist/" 14 | - "test/**/*" 15 | - "es/" 16 | - "build/" 17 | - "config/" 18 | -------------------------------------------------------------------------------- /.commitlintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["@commitlint/config-conventional"], 3 | "rules": { 4 | "body-max-line-length": [0] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.czrc: -------------------------------------------------------------------------------- 1 | { 2 | "path": "./node_modules/cz-conventional-changelog" 3 | } 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # This file is for unifying the coding style for different editors and IDEs 2 | # editorconfig.org 3 | root = true 4 | 5 | [*] 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | indent_style = space 11 | indent_size = 2 12 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parserOptions: { 4 | sourceType: 'module' 5 | }, 6 | // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style 7 | extends: [ 8 | 'standard', 9 | 'plugin:prettier/recommended', 10 | 'plugin:vue/recommended', 11 | 'plugin:prettier-vue/recommended', 12 | 'plugin:vue/vue3-essential', 13 | '@vue/eslint-config-typescript' 14 | ], 15 | // required to lint *.vue files 16 | plugins: ['prettier'], 17 | // add your custom rules here 18 | rules: { 19 | // allow paren-less arrow functions 20 | 'arrow-parens': 0, 21 | // allow debugger during development 22 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, 23 | 'prettier/prettier': 'error', 24 | quotes: [2, 'single', 'avoid-escape'] 25 | }, 26 | overrides: [ 27 | { 28 | files: ['sandboxes/**/*', 'test/**/*'], 29 | rules: { 30 | 'vue/no-reserved-component-names': 'off' 31 | } 32 | } 33 | ], 34 | ignorePatterns: ['dist/**/*', 'node_modules/**/*', 'rollup.config.js'] 35 | } 36 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Thank you for contributing vue-chartjs! 2 | ========================================= 3 | 4 | Please follow this steps: 5 | 6 | 1. Fork it ( https://github.com/apertureless/vue-chartjs/fork ) 7 | 2. Create your feature branch (`git checkout -b my-new-feature`) 8 | 3. Commit your changes (`git commit -am 'Add some feature'`) 9 | 4. Push to the branch (`git push origin my-new-feature`) 10 | 5. Create a new Pull Request 11 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: apertureless 2 | ko_fi: apertureless 3 | custom: ["paypal.me/apertureless"] 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.yml: -------------------------------------------------------------------------------- 1 | name: "🐛 Bug Report" 2 | description: "If something isn't working as expected." 3 | title: "[Bug]: " 4 | labels: ["bug"] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: Thanks for taking the time to file a bug report! Please fill out this form as completely as possible. 9 | 10 | - type: markdown 11 | attributes: 12 | value: ⚠️ vue-chartjs is just the wrapper around Chart.js, so if you are experiencing an issue with charts rendering, please create a related issue in [Chart.js repository](https://github.com/chartjs/Chart.js/issues). 13 | 14 | - type: checkboxes 15 | id: input1 16 | attributes: 17 | label: Would you like to work on a fix? 18 | options: 19 | - label: Check this if you would like to implement a PR, we are more than happy to help you go through the process. 20 | 21 | - type: textarea 22 | attributes: 23 | label: Current and expected behavior 24 | description: A clear and concise description of what the library is doing and what you would expect. 25 | validations: 26 | required: true 27 | 28 | - type: input 29 | attributes: 30 | label: Reproduction 31 | description: | 32 | Please provide issue reproduction. 33 | You can give a link to a repository with the reproduction or make a fork of [this sandbox](https://stackblitz.com/github/apertureless/vue-chartjs/tree/main/sandboxes/bar) and reproduce the issue there. 34 | validations: 35 | required: true 36 | 37 | - type: input 38 | attributes: 39 | label: chart.js version 40 | description: Which version of `chart.js` are you using? 41 | placeholder: v0.0.0 42 | validations: 43 | required: true 44 | 45 | - type: input 46 | attributes: 47 | label: vue-chartjs version 48 | description: Which version of `vue-chartjs` are you using? 49 | placeholder: v0.0.0 50 | validations: 51 | required: true 52 | 53 | - type: textarea 54 | attributes: 55 | label: Possible solution 56 | description: If you have suggestions on a fix for the bug. 57 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | 2 | blank_issues_enabled: false 3 | contact_links: 4 | - name: 🤔 Have a Question? 5 | url: https://stackoverflow.com/questions/tagged/vue-chartjs/ 6 | about: Feel free to ask questions on Stack Overflow. 7 | - name: 📊 Have a Problem With Chart.js? 8 | url: https://github.com/chartjs/Chart.js/issues 9 | about: vue-chartjs is just the wrapper around Chart.js, so if you are experiencing an issue with charts rendering, please create a related issue in Chart.js repository. 10 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.yml: -------------------------------------------------------------------------------- 1 | name: "🚀 Feature Request" 2 | description: "I have a specific suggestion!" 3 | labels: ["enhancement"] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: Thanks for taking the time to suggest a new feature! Please fill out this form as completely as possible. 8 | 9 | - type: markdown 10 | attributes: 11 | value: ⚠️ vue-chartjs is just the wrapper around Chart.js, so if you are experiencing an issue with charts rendering, please create a related issue in [Chart.js repository](https://github.com/chartjs/Chart.js/issues). 12 | 13 | - type: checkboxes 14 | id: input1 15 | attributes: 16 | label: Would you like to work on this feature? 17 | options: 18 | - label: Check this if you would like to implement a PR, we are more than happy to help you go through the process. 19 | 20 | - type: textarea 21 | attributes: 22 | label: What problem are you trying to solve? 23 | description: | 24 | A concise description of what the problem is. 25 | placeholder: | 26 | I have an issue when [...] 27 | validations: 28 | required: true 29 | 30 | - type: textarea 31 | attributes: 32 | label: Describe the solution you'd like 33 | validations: 34 | required: true 35 | 36 | - type: textarea 37 | attributes: 38 | label: Describe alternatives you've considered 39 | 40 | - type: textarea 41 | attributes: 42 | label: Documentation, Adoption, Migration Strategy 43 | description: | 44 | If you can, explain how users will be able to use this and how it might be documented. Maybe a mock-up? 45 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base", 4 | ":preserveSemverRanges" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.github/workflows/checks.yml: -------------------------------------------------------------------------------- 1 | name: Checks 2 | on: 3 | pull_request: 4 | branches: 5 | - main 6 | jobs: 7 | typings: 8 | runs-on: ubuntu-latest 9 | name: typings 10 | steps: 11 | - name: Checkout the repository 12 | uses: actions/checkout@v4 13 | - name: Install pnpm 14 | uses: pnpm/action-setup@v2 15 | with: 16 | version: 9 17 | - name: Install Node.js 18 | uses: actions/setup-node@v4 19 | with: 20 | node-version: 18 21 | cache: 'pnpm' 22 | - name: Install dependencies 23 | run: pnpm install 24 | - name: Prebuild 25 | run: pnpm build 26 | - name: Check typings 27 | if: success() 28 | run: pnpm test:typings 29 | storybook: 30 | runs-on: ubuntu-latest 31 | name: storybook 32 | steps: 33 | - name: Checkout the repository 34 | uses: actions/checkout@v4 35 | - name: Install pnpm 36 | uses: pnpm/action-setup@v2 37 | with: 38 | version: 9 39 | - name: Install Node.js 40 | uses: actions/setup-node@v4 41 | with: 42 | node-version: 18 43 | cache: 'pnpm' 44 | - name: Install dependencies 45 | run: pnpm install 46 | - name: Check storybook 47 | run: pnpm build:storybook 48 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | pull_request: 5 | jobs: 6 | test: 7 | runs-on: ubuntu-latest 8 | name: Running tests 9 | steps: 10 | - name: Checkout the repository 11 | uses: actions/checkout@v4 12 | - name: Install pnpm 13 | uses: pnpm/action-setup@v2 14 | with: 15 | version: 9 16 | - name: Install Node.js 17 | uses: actions/setup-node@v4 18 | with: 19 | node-version: 18 20 | cache: 'pnpm' 21 | - name: Install dependencies 22 | run: pnpm install 23 | - name: Run tests 24 | run: pnpm test 25 | -------------------------------------------------------------------------------- /.github/workflows/commit.yml: -------------------------------------------------------------------------------- 1 | name: Commit 2 | on: 3 | push: 4 | jobs: 5 | conventional-commit: 6 | runs-on: ubuntu-latest 7 | name: Checking commit name 8 | steps: 9 | - name: Checkout the repository 10 | uses: actions/checkout@v4 11 | with: 12 | fetch-depth: 0 13 | - name: Run commitlint 14 | uses: wagoid/commitlint-github-action@v5 15 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | release: 4 | types: [created] 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | name: Publish package 9 | steps: 10 | - name: Checkout the repository 11 | uses: actions/checkout@v4 12 | - name: Install pnpm 13 | uses: pnpm/action-setup@v2 14 | with: 15 | version: 9 16 | - name: Install Node.js 17 | uses: actions/setup-node@v4 18 | with: 19 | node-version: 18 20 | cache: 'pnpm' 21 | registry-url: 'https://registry.npmjs.org' 22 | - name: Install dependencies 23 | run: pnpm install 24 | - name: Publish 25 | run: pnpm publish --no-git-checks 26 | env: 27 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 28 | -------------------------------------------------------------------------------- /.github/workflows/website.yml: -------------------------------------------------------------------------------- 1 | name: Website 2 | on: 3 | push: 4 | branches: 5 | - main 6 | jobs: 7 | deploy: 8 | runs-on: ubuntu-latest 9 | name: deploy website 10 | steps: 11 | - name: Checkout the repository 12 | uses: actions/checkout@v4 13 | - name: Install pnpm 14 | uses: pnpm/action-setup@v2 15 | with: 16 | version: 9 17 | - name: Install Node.js 18 | uses: actions/setup-node@v4 19 | with: 20 | node-version: 18 21 | cache: 'pnpm' 22 | - name: Install dependencies 23 | run: pnpm install 24 | - name: Install website dependencies 25 | run: pnpm install 26 | working-directory: ./website 27 | - name: Build website 28 | run: pnpm build 29 | working-directory: ./website 30 | - name: Make CNAME file 31 | run: | 32 | cd ./website/src/.vitepress/dist 33 | echo "vue-chartjs.org" > CNAME 34 | - name: Prepare build 35 | run: | 36 | cd ./website/src/.vitepress/dist 37 | git init 38 | git add -A 39 | git config --local user.email "action@github.com" 40 | git config --local user.name "GitHub Action" 41 | git commit -m 'deploy' 42 | - name: Push build 43 | uses: ad-m/github-push-action@master 44 | with: 45 | github_token: ${{ secrets.GITHUB_TOKEN }} 46 | branch: gh-pages 47 | force: true 48 | directory: ./website/src/.vitepress/dist 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | 6 | # builds 7 | dist 8 | package 9 | storybook-static 10 | 11 | # misc 12 | .DS_Store 13 | 14 | npm-debug.log* 15 | 16 | # testing 17 | coverage 18 | -------------------------------------------------------------------------------- /.nano-staged.json: -------------------------------------------------------------------------------- 1 | { 2 | "**/*.{js,ts,vue}": ["prettier --write", "eslint"] 3 | } 4 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | strict-peer-dependencies=false 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "jsxSingleQuote": true, 4 | "semi": false, 5 | "tabWidth": 2, 6 | "bracketSpacing": true, 7 | "arrowParens": "avoid", 8 | "trailingComma": "none" 9 | } 10 | -------------------------------------------------------------------------------- /.simple-git-hooks.json: -------------------------------------------------------------------------------- 1 | { 2 | "commit-msg": "pnpm commitlint --edit \"$1\"", 3 | "pre-commit": "pnpm nano-staged", 4 | "pre-push": "pnpm test" 5 | } 6 | -------------------------------------------------------------------------------- /.size-limit.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "path": "dist/index.js", 4 | "limit": "2.95 KB", 5 | "webpack": false, 6 | "running": false 7 | }, 8 | { 9 | "path": "dist/index.js", 10 | "limit": "1.5 KB", 11 | "import": "{ Bar }" 12 | } 13 | ] 14 | -------------------------------------------------------------------------------- /.storybook/main.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const { mergeConfig } = require('vite') 3 | 4 | module.exports = { 5 | core: { 6 | builder: '@storybook/builder-vite' 7 | }, 8 | viteFinal(config) { 9 | return mergeConfig(config, { 10 | resolve: { 11 | dedupe: ['@storybook/client-api'], 12 | alias: { 13 | 'vue-chartjs': path.resolve(__dirname, '../src') 14 | } 15 | } 16 | }) 17 | }, 18 | framework: '@storybook/vue3', 19 | stories: ['../stories/*.stories.@(ts|js)'], 20 | addons: [ 21 | '@storybook/addon-docs', 22 | '@storybook/addon-controls', 23 | '@storybook/addon-actions' 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /.storybook/manager.js: -------------------------------------------------------------------------------- 1 | import { addons } from '@storybook/addons' 2 | 3 | import { theme } from './theme.js' 4 | 5 | addons.setConfig({ 6 | theme, 7 | panelPosition: 'right' 8 | }) 9 | -------------------------------------------------------------------------------- /.storybook/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "commonjs" 3 | } 4 | -------------------------------------------------------------------------------- /.storybook/preview.js: -------------------------------------------------------------------------------- 1 | import { configureActions } from '@storybook/addon-actions' 2 | 3 | configureActions({ 4 | depth: 5 5 | }) 6 | -------------------------------------------------------------------------------- /.storybook/theme.js: -------------------------------------------------------------------------------- 1 | import { create } from '@storybook/theming' 2 | 3 | export const theme = create({ 4 | base: 'light', 5 | brandTitle: 'vue-chartjs', 6 | brandUrl: 'https://github.com/apertureless/vue-chartjs' 7 | }) 8 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. 4 | 5 | We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion. 6 | 7 | Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct. 8 | 9 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team. 10 | 11 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. 12 | 13 | This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/) 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Jakub Juszczak 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-chartjs 2 | 3 | vue-chartjs logo 4 | 5 | **vue-chartjs** is a wrapper for [Chart.js](https://github.com/chartjs/Chart.js) in Vue. You can easily create reuseable chart components. 6 | 7 | Supports Chart.js v4. 8 | 9 | [![npm version](https://badge.fury.io/js/vue-chartjs.svg)](https://badge.fury.io/js/vue-chartjs) 10 | [![codecov](https://codecov.io/gh/apertureless/vue-chartjs/branch/master/graph/badge.svg)](https://codecov.io/gh/apertureless/vue-chartjs) 11 | [![Build Status](https://img.shields.io/github/actions/workflow/status/apertureless/vue-chartjs/ci.yml?branch=main)](https://github.com/apertureless/vue-chartjs/actions) 12 | [![Package Quality](http://npm.packagequality.com/shield/vue-chartjs.svg)](http://packagequality.com/#?package=vue-chartjs) 13 | [![npm](https://img.shields.io/npm/dm/vue-chartjs.svg)](https://www.npmjs.com/package/vue-chartjs) 14 | [![Gitter chat](https://img.shields.io/gitter/room/TechnologyAdvice/Stardust.svg)](https://gitter.im/vue-chartjs/Lobby) 15 | [![license](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/apertureless/vue-chartjs/blob/master/LICENSE.txt) 16 | [![CDNJS version](https://img.shields.io/cdnjs/v/vue-chartjs.svg)](https://cdnjs.com/libraries/vue-chartjs) 17 | [![Known Vulnerabilities](https://snyk.io/test/github/apertureless/vue-chartjs/badge.svg)](https://snyk.io/test/github/apertureless/vue-chartjs) 18 | [![Donate](https://raw.githubusercontent.com/apertureless/vue-chartjs/main/assets/donate.svg)](https://www.paypal.me/apertureless/50eur) 19 | [![ko-fi](https://www.ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/C0C1WP7C) 20 | 21 |
22 | QuickStart 23 |   •   24 | Docs 25 |   •   26 | Stack Overflow 27 |
28 |
29 | 30 | ## Quickstart 31 | 32 | Install this library with peer dependencies: 33 | 34 | ```bash 35 | pnpm add vue-chartjs chart.js 36 | # or 37 | yarn add vue-chartjs chart.js 38 | # or 39 | npm i vue-chartjs chart.js 40 | ``` 41 | 42 | Then, import and use individual components: 43 | 44 | ```vue 45 | 48 | 49 | 81 | ``` 82 | 83 |
84 | 85 | Need an API to fetch data? Consider [Cube](https://cube.dev/?ref=eco-vue-chartjs), an open-source API for data apps. 86 | 87 |
88 | 89 | [![supported by Cube](https://user-images.githubusercontent.com/986756/154330861-d79ab8ec-aacb-4af8-9e17-1b28f1eccb01.svg)](https://cube.dev/?ref=eco-vue-chartjs) 90 | 91 | ## Docs 92 | 93 | - [Reactivity](https://vue-chartjs.org/guide/#updating-charts) 94 | - [Access to Chart instance](https://vue-chartjs.org/guide/#access-to-chart-instance) 95 | - [Accessibility](https://vue-chartjs.org/guide/#accessibility) 96 | - [Migration from v4 to v5](https://vue-chartjs.org/migration-guides/#migration-from-v4-to-v5/) 97 | - [Migration from vue-chart-3](https://vue-chartjs.org/migration-guides/#migration-from-vue-chart-3/) 98 | - [API](https://vue-chartjs.org/api/) 99 | - [Examples](https://vue-chartjs.org/examples/) 100 | 101 | ## Build Setup 102 | 103 | ``` bash 104 | # install dependencies 105 | pnpm install 106 | 107 | # build for production with minification 108 | pnpm build 109 | 110 | # run unit tests 111 | pnpm test:unit 112 | 113 | # run all tests 114 | pnpm test 115 | ``` 116 | 117 | ## Contributing 118 | 119 | 1. Fork it ( https://github.com/apertureless/vue-chartjs/fork ) 120 | 2. Create your feature branch (`git checkout -b my-new-feature`) 121 | 3. Commit your changes (`git commit -am 'Add some feature'`) 122 | 4. Push to the branch (`git push origin my-new-feature`) 123 | 5. Create a new Pull Request 124 | 125 | ## License 126 | 127 | This software is distributed under [MIT license](LICENSE.txt). 128 | 129 | Buy Me A Coffee 130 | -------------------------------------------------------------------------------- /assets/bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apertureless/vue-chartjs/981b1f58141765513bd30b29112664b2a3d13ed8/assets/bar.png -------------------------------------------------------------------------------- /assets/bubble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apertureless/vue-chartjs/981b1f58141765513bd30b29112664b2a3d13ed8/assets/bubble.png -------------------------------------------------------------------------------- /assets/donate.svg: -------------------------------------------------------------------------------- 1 | 2 | DonateDonate 3 | -------------------------------------------------------------------------------- /assets/doughnut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apertureless/vue-chartjs/981b1f58141765513bd30b29112664b2a3d13ed8/assets/doughnut.png -------------------------------------------------------------------------------- /assets/line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apertureless/vue-chartjs/981b1f58141765513bd30b29112664b2a3d13ed8/assets/line.png -------------------------------------------------------------------------------- /assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apertureless/vue-chartjs/981b1f58141765513bd30b29112664b2a3d13ed8/assets/logo.png -------------------------------------------------------------------------------- /assets/pie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apertureless/vue-chartjs/981b1f58141765513bd30b29112664b2a3d13ed8/assets/pie.png -------------------------------------------------------------------------------- /assets/polar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apertureless/vue-chartjs/981b1f58141765513bd30b29112664b2a3d13ed8/assets/polar.png -------------------------------------------------------------------------------- /assets/radar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apertureless/vue-chartjs/981b1f58141765513bd30b29112664b2a3d13ed8/assets/radar.png -------------------------------------------------------------------------------- /assets/scatter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apertureless/vue-chartjs/981b1f58141765513bd30b29112664b2a3d13ed8/assets/scatter.png -------------------------------------------------------------------------------- /assets/vue-chartjs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apertureless/vue-chartjs/981b1f58141765513bd30b29112664b2a3d13ed8/assets/vue-chartjs.png -------------------------------------------------------------------------------- /assets/vue-chartjs.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 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 | - "sandboxes/*" 28 | - "stories/*" 29 | 30 | 31 | comment: 32 | layout: "header, diff, changes, sunburst, uncovered, tree" 33 | branches: null 34 | behavior: default 35 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-chartjs", 3 | "type": "module", 4 | "version": "5.3.2", 5 | "description": "Vue.js wrapper for chart.js for creating beautiful charts.", 6 | "author": "Jakub Juszczak ", 7 | "homepage": "http://vue-chartjs.org", 8 | "license": "MIT", 9 | "contributors": [ 10 | { 11 | "name": "Thorsten Lünborg", 12 | "web": "https://github.com/LinusBorg" 13 | }, 14 | { 15 | "name": "Juan Carlos Alonso", 16 | "web": "https://github.com/jcalonso" 17 | } 18 | ], 19 | "maintainers": [ 20 | { 21 | "name": "Jakub Juszczak", 22 | "email": "jakub@posteo.de", 23 | "web": "http://www.jakubjuszczak.de" 24 | } 25 | ], 26 | "repository": { 27 | "type": "git", 28 | "url": "git+ssh://git@github.com:apertureless/vue-chartjs.git" 29 | }, 30 | "bugs": { 31 | "url": "https://github.com/apertureless/vue-chartjs/issues" 32 | }, 33 | "keywords": [ 34 | "ChartJs", 35 | "Vue", 36 | "Visualisation", 37 | "Wrapper", 38 | "Charts" 39 | ], 40 | "sideEffects": false, 41 | "types": "./dist/index.d.ts", 42 | "exports": "./src/index.ts", 43 | "publishConfig": { 44 | "main": "./dist/index.cjs", 45 | "module": "./dist/index.js", 46 | "exports": { 47 | "types": "./dist/index.d.ts", 48 | "import": "./dist/index.js", 49 | "require": "./dist/index.cjs" 50 | }, 51 | "directory": "package" 52 | }, 53 | "files": [ 54 | "dist" 55 | ], 56 | "scripts": { 57 | "prepublishOnly": "pnpm test && pnpm build && del ./package && clean-publish", 58 | "postpublish": "del ./package", 59 | "emitDeclarations": "tsc --emitDeclarationOnly", 60 | "build": "rollup -c & pnpm emitDeclarations", 61 | "start:storybook": "start-storybook -p 6006 --ci", 62 | "build:storybook": "del ./storybook-static; NODE_ENV=production build-storybook", 63 | "lint": "eslint 'sandboxes/**/*.{js,ts,vue}' 'src/**/*.{js,ts,vue}' 'stories/**/*.{js,ts,vue}' 'test/**/*.{js,ts,vue}'", 64 | "test:unit": "vitest run --coverage", 65 | "test:unit:watch": "vitest watch", 66 | "test:typings": "tsd", 67 | "test:size": "size-limit", 68 | "test": "pnpm lint && pnpm test:unit", 69 | "format": "prettier --write src test sandboxes stories", 70 | "commit": "cz", 71 | "bumpVersion": "standard-version", 72 | "createGithubRelease": "simple-github-release", 73 | "release": "pnpm bumpVersion && git push origin main --tags && pnpm createGithubRelease", 74 | "updateGitHooks": "simple-git-hooks" 75 | }, 76 | "peerDependencies": { 77 | "chart.js": "^4.1.1", 78 | "vue": "^3.0.0-0 || ^2.7.0" 79 | }, 80 | "devDependencies": { 81 | "@commitlint/cli": "^18.0.0", 82 | "@commitlint/config-conventional": "^18.0.0", 83 | "@rollup/plugin-node-resolve": "^15.0.1", 84 | "@size-limit/preset-big-lib": "^11.0.0", 85 | "@storybook/addon-actions": "^6.5.16", 86 | "@storybook/addon-controls": "^6.5.16", 87 | "@storybook/addon-docs": "^6.5.16", 88 | "@storybook/addons": "^6.5.16", 89 | "@storybook/builder-vite": "^0.4.2", 90 | "@storybook/client-api": "^6.5.16", 91 | "@storybook/client-logger": "^6.5.16", 92 | "@storybook/vue3": "^6.5.16", 93 | "@swc/core": "^1.3.23", 94 | "@swc/helpers": "^0.5.0", 95 | "@vitejs/plugin-vue": "^4.0.0", 96 | "@vitest/coverage-c8": "^0.31.0", 97 | "@vue/eslint-config-typescript": "^12.0.0", 98 | "@vue/test-utils": "^2.0.0-rc.17", 99 | "browserslist": "^4.19.1", 100 | "chart.js": "^4.4.1", 101 | "clean-publish": "^4.0.0", 102 | "commitizen": "^4.2.4", 103 | "cross-env": "^7.0.0", 104 | "cz-conventional-changelog": "3.3.0", 105 | "del-cli": "^5.0.0", 106 | "eslint": "8.55.0", 107 | "eslint-config-prettier": "^9.0.0", 108 | "eslint-config-standard": "^17.0.0", 109 | "eslint-plugin-import": "^2.25.4", 110 | "eslint-plugin-n": "^16.0.0", 111 | "eslint-plugin-node": "^11.1.0", 112 | "eslint-plugin-prettier": "^4.2.1", 113 | "eslint-plugin-prettier-vue": "5.0.0", 114 | "eslint-plugin-promise": "^6.0.0", 115 | "eslint-plugin-vue": "^9.0.0", 116 | "jsdom": "^23.0.0", 117 | "nano-staged": "^0.8.0", 118 | "prettier": "2.8.8", 119 | "react": "^18.2.0", 120 | "react-dom": "^18.2.0", 121 | "rollup": "^3.7.5", 122 | "rollup-plugin-swc3": "^0.11.0", 123 | "simple-git-hooks": "^2.7.0", 124 | "simple-github-release": "^1.0.0", 125 | "size-limit": "^11.0.0", 126 | "standard-version": "^9.3.2", 127 | "tsd": "^0.25.0", 128 | "typescript": "^4.9.4", 129 | "vite": "^4.0.2", 130 | "vitest": "^0.31.0", 131 | "vitest-canvas-mock": "^0.3.0", 132 | "vue": "^3.2.31" 133 | }, 134 | "tsd": { 135 | "directory": "./test" 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import { swc } from 'rollup-plugin-swc3' 2 | import { nodeResolve } from '@rollup/plugin-node-resolve' 3 | import pkg from './package.json' assert { type: 'json' } 4 | 5 | const extensions = ['.js', '.ts'] 6 | const external = _ => /node_modules/.test(_) && !/@swc\/helpers/.test(_) 7 | const plugins = targets => [ 8 | nodeResolve({ 9 | extensions 10 | }), 11 | swc({ 12 | tsconfig: false, 13 | env: { 14 | targets 15 | }, 16 | module: { 17 | type: 'es6' 18 | }, 19 | sourceMaps: true 20 | }) 21 | ] 22 | 23 | export default { 24 | input: pkg.exports, 25 | plugins: plugins('defaults and supports es6-module'), 26 | external, 27 | output: [ 28 | { 29 | file: pkg.publishConfig.exports.import, 30 | format: 'es', 31 | sourcemap: true 32 | }, 33 | { 34 | file: pkg.publishConfig.exports.require, 35 | format: 'cjs', 36 | sourcemap: true 37 | } 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /sandboxes/bar/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /sandboxes/bar/index.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './src/App.vue' 3 | 4 | createApp(App).mount('#app') 5 | -------------------------------------------------------------------------------- /sandboxes/bar/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "scripts": { 4 | "start": "vite" 5 | }, 6 | "dependencies": { 7 | "chart.js": "^4.0.0", 8 | "vue": "^3.2.31", 9 | "vue-chartjs": "^5.0.0" 10 | }, 11 | "devDependencies": { 12 | "@vitejs/plugin-vue": "^4.0.0", 13 | "typescript": "^4.9.3", 14 | "vite": "^4.0.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /sandboxes/bar/src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 30 | -------------------------------------------------------------------------------- /sandboxes/bar/src/chartConfig.ts: -------------------------------------------------------------------------------- 1 | export const data = { 2 | labels: [ 3 | 'January', 4 | 'February', 5 | 'March', 6 | 'April', 7 | 'May', 8 | 'June', 9 | 'July', 10 | 'August', 11 | 'September', 12 | 'October', 13 | 'November', 14 | 'December' 15 | ], 16 | datasets: [ 17 | { 18 | label: 'Data One', 19 | backgroundColor: '#f87979', 20 | data: [40, 20, 12, 39, 10, 40, 39, 80, 40, 20, 12, 11] 21 | } 22 | ] 23 | } 24 | 25 | export const options = { 26 | responsive: true, 27 | maintainAspectRatio: false 28 | } 29 | -------------------------------------------------------------------------------- /sandboxes/bar/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | 4 | export default defineConfig({ 5 | plugins: [vue()] 6 | }) 7 | -------------------------------------------------------------------------------- /sandboxes/bubble/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /sandboxes/bubble/index.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './src/App.vue' 3 | 4 | createApp(App).mount('#app') 5 | -------------------------------------------------------------------------------- /sandboxes/bubble/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "scripts": { 4 | "start": "vite" 5 | }, 6 | "dependencies": { 7 | "chart.js": "^4.0.0", 8 | "vue": "^3.2.31", 9 | "vue-chartjs": "^5.0.0" 10 | }, 11 | "devDependencies": { 12 | "@vitejs/plugin-vue": "^4.0.0", 13 | "typescript": "^4.9.3", 14 | "vite": "^4.0.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /sandboxes/bubble/src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 28 | -------------------------------------------------------------------------------- /sandboxes/bubble/src/chartConfig.ts: -------------------------------------------------------------------------------- 1 | export const data = { 2 | datasets: [ 3 | { 4 | label: 'Data One', 5 | backgroundColor: '#f87979', 6 | data: [ 7 | { 8 | x: 20, 9 | y: 25, 10 | r: 5 11 | }, 12 | { 13 | x: 40, 14 | y: 10, 15 | r: 10 16 | }, 17 | { 18 | x: 30, 19 | y: 22, 20 | r: 30 21 | } 22 | ] 23 | }, 24 | { 25 | label: 'Data Two', 26 | backgroundColor: '#7C8CF8', 27 | data: [ 28 | { 29 | x: 10, 30 | y: 30, 31 | r: 15 32 | }, 33 | { 34 | x: 20, 35 | y: 20, 36 | r: 10 37 | }, 38 | { 39 | x: 15, 40 | y: 8, 41 | r: 30 42 | } 43 | ] 44 | } 45 | ] 46 | } 47 | 48 | export const options = { 49 | responsive: true, 50 | maintainAspectRatio: false 51 | } 52 | -------------------------------------------------------------------------------- /sandboxes/bubble/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | 4 | export default defineConfig({ 5 | plugins: [vue()] 6 | }) 7 | -------------------------------------------------------------------------------- /sandboxes/custom/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /sandboxes/custom/index.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './src/App.vue' 3 | 4 | createApp(App).mount('#app') 5 | -------------------------------------------------------------------------------- /sandboxes/custom/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "scripts": { 4 | "start": "vite" 5 | }, 6 | "dependencies": { 7 | "chart.js": "^4.0.0", 8 | "vue": "^3.2.31", 9 | "vue-chartjs": "^5.0.0" 10 | }, 11 | "devDependencies": { 12 | "@vitejs/plugin-vue": "^4.0.0", 13 | "typescript": "^4.9.3", 14 | "vite": "^4.0.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /sandboxes/custom/src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 39 | -------------------------------------------------------------------------------- /sandboxes/custom/src/chartConfig.ts: -------------------------------------------------------------------------------- 1 | export const data = { 2 | labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'], 3 | datasets: [ 4 | { 5 | label: 'Data One', 6 | backgroundColor: '#f87979', 7 | data: [40, 39, 10, 40, 39, 80, 40] 8 | } 9 | ] 10 | } 11 | 12 | export const options = { 13 | responsive: true, 14 | maintainAspectRatio: false, 15 | tooltips: { 16 | intersect: false 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /sandboxes/custom/src/components/LineWithLineChart.ts: -------------------------------------------------------------------------------- 1 | import { createTypedChart } from 'vue-chartjs' 2 | import { LineController } from 'chart.js' 3 | 4 | class LineWithLineController extends LineController { 5 | static override id = 'line-with-line' 6 | 7 | public override draw() { 8 | super.draw() 9 | 10 | if (this.chart?.tooltip && this.chart.tooltip.opacity > 0) { 11 | const ctx = this.chart.ctx 12 | const x = this.chart.tooltip.x 13 | const topY = this.chart.scales.y.top 14 | const bottomY = this.chart.scales.y.bottom 15 | 16 | // draw line 17 | ctx.save() 18 | ctx.beginPath() 19 | ctx.moveTo(x, topY) 20 | ctx.lineTo(x, bottomY) 21 | ctx.lineWidth = 2 22 | ctx.strokeStyle = '#07C' 23 | ctx.stroke() 24 | ctx.restore() 25 | } 26 | } 27 | } 28 | 29 | const LineWithLineChart = createTypedChart( 30 | 'line-with-line' as 'line', 31 | LineWithLineController 32 | ) 33 | 34 | export default LineWithLineChart 35 | -------------------------------------------------------------------------------- /sandboxes/custom/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | 4 | export default defineConfig({ 5 | plugins: [vue()] 6 | }) 7 | -------------------------------------------------------------------------------- /sandboxes/doughnut/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /sandboxes/doughnut/index.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './src/App.vue' 3 | 4 | createApp(App).mount('#app') 5 | -------------------------------------------------------------------------------- /sandboxes/doughnut/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "scripts": { 4 | "start": "vite" 5 | }, 6 | "dependencies": { 7 | "chart.js": "^4.0.0", 8 | "vue": "^3.2.31", 9 | "vue-chartjs": "^5.0.0" 10 | }, 11 | "devDependencies": { 12 | "@vitejs/plugin-vue": "^4.0.0", 13 | "typescript": "^4.9.3", 14 | "vite": "^4.0.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /sandboxes/doughnut/src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 22 | -------------------------------------------------------------------------------- /sandboxes/doughnut/src/chartConfig.ts: -------------------------------------------------------------------------------- 1 | export const data = { 2 | labels: ['VueJs', 'EmberJs', 'ReactJs', 'AngularJs'], 3 | datasets: [ 4 | { 5 | backgroundColor: ['#41B883', '#E46651', '#00D8FF', '#DD1B16'], 6 | data: [40, 20, 80, 10] 7 | } 8 | ] 9 | } 10 | 11 | export const options = { 12 | responsive: true, 13 | maintainAspectRatio: false 14 | } 15 | -------------------------------------------------------------------------------- /sandboxes/doughnut/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | 4 | export default defineConfig({ 5 | plugins: [vue()] 6 | }) 7 | -------------------------------------------------------------------------------- /sandboxes/events/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /sandboxes/events/index.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './src/App.vue' 3 | 4 | createApp(App).mount('#app') 5 | -------------------------------------------------------------------------------- /sandboxes/events/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "scripts": { 4 | "start": "vite" 5 | }, 6 | "dependencies": { 7 | "chart.js": "^4.0.0", 8 | "vue": "^3.2.31", 9 | "vue-chartjs": "^5.0.0" 10 | }, 11 | "devDependencies": { 12 | "@vitejs/plugin-vue": "^4.0.0", 13 | "typescript": "^4.9.3", 14 | "vite": "^4.0.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /sandboxes/events/src/App.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 90 | -------------------------------------------------------------------------------- /sandboxes/events/src/chartConfig.ts: -------------------------------------------------------------------------------- 1 | export const data = { 2 | labels: [ 3 | 'January', 4 | 'February', 5 | 'March', 6 | 'April', 7 | 'May', 8 | 'June', 9 | 'July', 10 | 'August', 11 | 'September', 12 | 'October', 13 | 'November', 14 | 'December' 15 | ], 16 | datasets: [ 17 | { 18 | label: 'Data One', 19 | backgroundColor: '#f87979', 20 | data: [40, 20, 12, 39, 10, 40, 39, 80, 40, 20, 12, 11] 21 | } 22 | ] 23 | } 24 | 25 | export const options = { 26 | responsive: true, 27 | maintainAspectRatio: false 28 | } 29 | -------------------------------------------------------------------------------- /sandboxes/events/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | 4 | export default defineConfig({ 5 | plugins: [vue()] 6 | }) 7 | -------------------------------------------------------------------------------- /sandboxes/line/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /sandboxes/line/index.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './src/App.vue' 3 | 4 | createApp(App).mount('#app') 5 | -------------------------------------------------------------------------------- /sandboxes/line/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "scripts": { 4 | "start": "vite" 5 | }, 6 | "dependencies": { 7 | "chart.js": "^4.0.0", 8 | "vue": "^3.2.31", 9 | "vue-chartjs": "^5.0.0" 10 | }, 11 | "devDependencies": { 12 | "@vitejs/plugin-vue": "^4.0.0", 13 | "typescript": "^4.9.3", 14 | "vite": "^4.0.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /sandboxes/line/src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 39 | -------------------------------------------------------------------------------- /sandboxes/line/src/chartConfig.ts: -------------------------------------------------------------------------------- 1 | export const data = { 2 | labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'], 3 | datasets: [ 4 | { 5 | label: 'Data One', 6 | backgroundColor: '#f87979', 7 | data: [40, 39, 10, 40, 39, 80, 40] 8 | } 9 | ] 10 | } 11 | 12 | export const options = { 13 | responsive: true, 14 | maintainAspectRatio: false 15 | } 16 | -------------------------------------------------------------------------------- /sandboxes/line/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | 4 | export default defineConfig({ 5 | plugins: [vue()] 6 | }) 7 | -------------------------------------------------------------------------------- /sandboxes/pie/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /sandboxes/pie/index.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './src/App.vue' 3 | 4 | createApp(App).mount('#app') 5 | -------------------------------------------------------------------------------- /sandboxes/pie/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "scripts": { 4 | "start": "vite" 5 | }, 6 | "dependencies": { 7 | "chart.js": "^4.0.0", 8 | "vue": "^3.2.31", 9 | "vue-chartjs": "^5.0.0" 10 | }, 11 | "devDependencies": { 12 | "@vitejs/plugin-vue": "^4.0.0", 13 | "typescript": "^4.9.3", 14 | "vite": "^4.0.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /sandboxes/pie/src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 22 | -------------------------------------------------------------------------------- /sandboxes/pie/src/chartConfig.ts: -------------------------------------------------------------------------------- 1 | export const data = { 2 | labels: ['VueJs', 'EmberJs', 'ReactJs', 'AngularJs'], 3 | datasets: [ 4 | { 5 | backgroundColor: ['#41B883', '#E46651', '#00D8FF', '#DD1B16'], 6 | data: [40, 20, 80, 10] 7 | } 8 | ] 9 | } 10 | 11 | export const options = { 12 | responsive: true, 13 | maintainAspectRatio: false 14 | } 15 | -------------------------------------------------------------------------------- /sandboxes/pie/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | 4 | export default defineConfig({ 5 | plugins: [vue()] 6 | }) 7 | -------------------------------------------------------------------------------- /sandboxes/polar-area/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /sandboxes/polar-area/index.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './src/App.vue' 3 | 4 | createApp(App).mount('#app') 5 | -------------------------------------------------------------------------------- /sandboxes/polar-area/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "scripts": { 4 | "start": "vite" 5 | }, 6 | "dependencies": { 7 | "chart.js": "^4.0.0", 8 | "vue": "^3.2.31", 9 | "vue-chartjs": "^5.0.0" 10 | }, 11 | "devDependencies": { 12 | "@vitejs/plugin-vue": "^4.0.0", 13 | "typescript": "^4.9.3", 14 | "vite": "^4.0.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /sandboxes/polar-area/src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 28 | -------------------------------------------------------------------------------- /sandboxes/polar-area/src/chartConfig.ts: -------------------------------------------------------------------------------- 1 | export const data = { 2 | labels: [ 3 | 'Eating', 4 | 'Drinking', 5 | 'Sleeping', 6 | 'Designing', 7 | 'Coding', 8 | 'Cycling', 9 | 'Running' 10 | ], 11 | datasets: [ 12 | { 13 | label: 'My First dataset', 14 | backgroundColor: 'rgba(179,181,198,0.2)', 15 | pointBackgroundColor: 'rgba(179,181,198,1)', 16 | pointBorderColor: '#fff', 17 | pointHoverBackgroundColor: '#fff', 18 | pointHoverBorderColor: 'rgba(179,181,198,1)', 19 | data: [65, 59, 90, 81, 56, 55, 40] 20 | }, 21 | { 22 | label: 'My Second dataset', 23 | backgroundColor: 'rgba(255,99,132,0.2)', 24 | pointBackgroundColor: 'rgba(255,99,132,1)', 25 | pointBorderColor: '#fff', 26 | pointHoverBackgroundColor: '#fff', 27 | pointHoverBorderColor: 'rgba(255,99,132,1)', 28 | data: [28, 48, 40, 19, 96, 27, 100] 29 | } 30 | ] 31 | } 32 | 33 | export const options = { 34 | responsive: true, 35 | maintainAspectRatio: false 36 | } 37 | -------------------------------------------------------------------------------- /sandboxes/polar-area/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | 4 | export default defineConfig({ 5 | plugins: [vue()] 6 | }) 7 | -------------------------------------------------------------------------------- /sandboxes/radar/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /sandboxes/radar/index.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './src/App.vue' 3 | 4 | createApp(App).mount('#app') 5 | -------------------------------------------------------------------------------- /sandboxes/radar/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "scripts": { 4 | "start": "vite" 5 | }, 6 | "dependencies": { 7 | "chart.js": "^4.0.0", 8 | "vue": "^3.2.31", 9 | "vue-chartjs": "^5.0.0" 10 | }, 11 | "devDependencies": { 12 | "@vitejs/plugin-vue": "^4.0.0", 13 | "typescript": "^4.9.3", 14 | "vite": "^4.0.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /sandboxes/radar/src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 37 | -------------------------------------------------------------------------------- /sandboxes/radar/src/chartConfig.ts: -------------------------------------------------------------------------------- 1 | export const data = { 2 | labels: [ 3 | 'Eating', 4 | 'Drinking', 5 | 'Sleeping', 6 | 'Designing', 7 | 'Coding', 8 | 'Cycling', 9 | 'Running' 10 | ], 11 | datasets: [ 12 | { 13 | label: 'My First dataset', 14 | backgroundColor: 'rgba(179,181,198,0.2)', 15 | borderColor: 'rgba(179,181,198,1)', 16 | pointBackgroundColor: 'rgba(179,181,198,1)', 17 | pointBorderColor: '#fff', 18 | pointHoverBackgroundColor: '#fff', 19 | pointHoverBorderColor: 'rgba(179,181,198,1)', 20 | data: [65, 59, 90, 81, 56, 55, 40] 21 | }, 22 | { 23 | label: 'My Second dataset', 24 | backgroundColor: 'rgba(255,99,132,0.2)', 25 | borderColor: 'rgba(255,99,132,1)', 26 | pointBackgroundColor: 'rgba(255,99,132,1)', 27 | pointBorderColor: '#fff', 28 | pointHoverBackgroundColor: '#fff', 29 | pointHoverBorderColor: 'rgba(255,99,132,1)', 30 | data: [28, 48, 40, 19, 96, 27, 100] 31 | } 32 | ] 33 | } 34 | 35 | export const options = { 36 | responsive: true, 37 | maintainAspectRatio: false 38 | } 39 | -------------------------------------------------------------------------------- /sandboxes/radar/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | 4 | export default defineConfig({ 5 | plugins: [vue()] 6 | }) 7 | -------------------------------------------------------------------------------- /sandboxes/reactive/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /sandboxes/reactive/index.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './src/App.vue' 3 | 4 | createApp(App).mount('#app') 5 | -------------------------------------------------------------------------------- /sandboxes/reactive/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "scripts": { 4 | "start": "vite" 5 | }, 6 | "dependencies": { 7 | "chart.js": "^4.0.0", 8 | "vue": "^3.2.31", 9 | "vue-chartjs": "^5.0.0" 10 | }, 11 | "devDependencies": { 12 | "@vitejs/plugin-vue": "^4.0.0", 13 | "typescript": "^4.9.3", 14 | "vite": "^4.0.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /sandboxes/reactive/src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 33 | -------------------------------------------------------------------------------- /sandboxes/reactive/src/chartConfig.ts: -------------------------------------------------------------------------------- 1 | function getRandomInt() { 2 | return Math.floor(Math.random() * (50 - 5 + 1)) + 5 3 | } 4 | 5 | export const randomData = () => ({ 6 | labels: [ 7 | 'January' + getRandomInt(), 8 | 'February', 9 | 'March', 10 | 'April', 11 | 'May', 12 | 'June', 13 | 'July', 14 | 'August', 15 | 'September', 16 | 'October', 17 | 'November', 18 | 'December' 19 | ], 20 | datasets: [ 21 | { 22 | label: 'Data One', 23 | backgroundColor: '#f87979', 24 | data: [ 25 | getRandomInt(), 26 | getRandomInt(), 27 | getRandomInt(), 28 | getRandomInt(), 29 | getRandomInt(), 30 | getRandomInt(), 31 | getRandomInt(), 32 | getRandomInt(), 33 | getRandomInt(), 34 | getRandomInt(), 35 | getRandomInt(), 36 | getRandomInt() 37 | ] 38 | } 39 | ] 40 | }) 41 | 42 | export const options = { 43 | responsive: true, 44 | maintainAspectRatio: false 45 | } 46 | -------------------------------------------------------------------------------- /sandboxes/reactive/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | 4 | export default defineConfig({ 5 | plugins: [vue()] 6 | }) 7 | -------------------------------------------------------------------------------- /sandboxes/scatter/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /sandboxes/scatter/index.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './src/App.vue' 3 | 4 | createApp(App).mount('#app') 5 | -------------------------------------------------------------------------------- /sandboxes/scatter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "scripts": { 4 | "start": "vite" 5 | }, 6 | "dependencies": { 7 | "chart.js": "^4.0.0", 8 | "vue": "^3.2.31", 9 | "vue-chartjs": "^5.0.0" 10 | }, 11 | "devDependencies": { 12 | "@vitejs/plugin-vue": "^4.0.0", 13 | "typescript": "^4.9.3", 14 | "vite": "^4.0.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /sandboxes/scatter/src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 29 | -------------------------------------------------------------------------------- /sandboxes/scatter/src/chartConfig.ts: -------------------------------------------------------------------------------- 1 | export const data = { 2 | datasets: [ 3 | { 4 | label: 'Scatter Dataset 1', 5 | fill: false, 6 | borderColor: '#f87979', 7 | backgroundColor: '#f87979', 8 | data: [ 9 | { 10 | x: -2, 11 | y: 4 12 | }, 13 | { 14 | x: -1, 15 | y: 1 16 | }, 17 | { 18 | x: 0, 19 | y: 0 20 | }, 21 | { 22 | x: 1, 23 | y: 1 24 | }, 25 | { 26 | x: 2, 27 | y: 4 28 | } 29 | ] 30 | }, 31 | { 32 | label: 'Scatter Dataset 2', 33 | fill: false, 34 | borderColor: '#7acbf9', 35 | backgroundColor: '#7acbf9', 36 | data: [ 37 | { 38 | x: -2, 39 | y: -4 40 | }, 41 | { 42 | x: -1, 43 | y: -1 44 | }, 45 | { 46 | x: 0, 47 | y: 1 48 | }, 49 | { 50 | x: 1, 51 | y: -1 52 | }, 53 | { 54 | x: 2, 55 | y: -4 56 | } 57 | ] 58 | } 59 | ] 60 | } 61 | 62 | export const options = { 63 | responsive: true, 64 | maintainAspectRatio: false 65 | } 66 | -------------------------------------------------------------------------------- /sandboxes/scatter/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | 4 | export default defineConfig({ 5 | plugins: [vue()] 6 | }) 7 | -------------------------------------------------------------------------------- /sandboxes/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "paths": { 6 | "vue-chartjs": ["../src"] 7 | } 8 | }, 9 | "include": ["."] 10 | } 11 | -------------------------------------------------------------------------------- /src/chart.ts: -------------------------------------------------------------------------------- 1 | import { Chart as ChartJS } from 'chart.js' 2 | import { 3 | defineComponent, 4 | h, 5 | nextTick, 6 | onUnmounted, 7 | onMounted, 8 | ref, 9 | shallowRef, 10 | toRaw, 11 | watch 12 | } from 'vue' 13 | 14 | import type { ChartComponent } from './types.js' 15 | import { Props } from './props.js' 16 | import { 17 | cloneData, 18 | setLabels, 19 | setDatasets, 20 | setOptions, 21 | toRawIfProxy, 22 | cloneProxy 23 | } from './utils.js' 24 | 25 | export const Chart = defineComponent({ 26 | props: Props, 27 | setup(props, { expose, slots }) { 28 | const canvasRef = ref(null) 29 | const chartRef = shallowRef(null) 30 | 31 | expose({ chart: chartRef }) 32 | 33 | const renderChart = () => { 34 | if (!canvasRef.value) return 35 | 36 | const { type, data, options, plugins, datasetIdKey } = props 37 | const clonedData = cloneData(data, datasetIdKey) 38 | const proxiedData = cloneProxy(clonedData, data) 39 | 40 | chartRef.value = new ChartJS(canvasRef.value, { 41 | type, 42 | data: proxiedData, 43 | options: { ...options }, 44 | plugins 45 | }) 46 | } 47 | 48 | const destroyChart = () => { 49 | const chart = toRaw(chartRef.value) 50 | 51 | if (chart) { 52 | if (props.destroyDelay > 0) { 53 | setTimeout(() => { 54 | chart.destroy() 55 | chartRef.value = null 56 | }, props.destroyDelay) 57 | } else { 58 | chart.destroy() 59 | chartRef.value = null 60 | } 61 | } 62 | } 63 | 64 | const update = (chart: ChartJS) => { 65 | chart.update(props.updateMode) 66 | } 67 | 68 | onMounted(renderChart) 69 | 70 | onUnmounted(destroyChart) 71 | 72 | watch( 73 | [() => props.options, () => props.data], 74 | ( 75 | [nextOptionsProxy, nextDataProxy], 76 | [prevOptionsProxy, prevDataProxy] 77 | ) => { 78 | const chart = toRaw(chartRef.value) 79 | 80 | if (!chart) { 81 | return 82 | } 83 | 84 | let shouldUpdate = false 85 | 86 | if (nextOptionsProxy) { 87 | const nextOptions = toRawIfProxy(nextOptionsProxy) 88 | const prevOptions = toRawIfProxy(prevOptionsProxy) 89 | 90 | if (nextOptions && nextOptions !== prevOptions) { 91 | setOptions(chart, nextOptions) 92 | shouldUpdate = true 93 | } 94 | } 95 | 96 | if (nextDataProxy) { 97 | const nextLabels = toRawIfProxy(nextDataProxy.labels) 98 | const prevLabels = toRawIfProxy(prevDataProxy.labels) 99 | const nextDatasets = toRawIfProxy(nextDataProxy.datasets) 100 | const prevDatasets = toRawIfProxy(prevDataProxy.datasets) 101 | 102 | if (nextLabels !== prevLabels) { 103 | setLabels(chart.config.data, nextLabels) 104 | shouldUpdate = true 105 | } 106 | 107 | if (nextDatasets && nextDatasets !== prevDatasets) { 108 | setDatasets(chart.config.data, nextDatasets, props.datasetIdKey) 109 | shouldUpdate = true 110 | } 111 | } 112 | 113 | if (shouldUpdate) { 114 | nextTick(() => { 115 | update(chart) 116 | }) 117 | } 118 | }, 119 | { deep: true } 120 | ) 121 | 122 | return () => { 123 | return h( 124 | 'canvas', 125 | { 126 | role: 'img', 127 | ariaLabel: props.ariaLabel, 128 | ariaDescribedby: props.ariaDescribedby, 129 | ref: canvasRef 130 | }, 131 | [h('p', {}, [slots.default ? slots.default() : ''])] 132 | ) 133 | } 134 | } 135 | }) as ChartComponent 136 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { Chart } from './chart.js' 2 | import { 3 | createTypedChart, 4 | Bar, 5 | Doughnut, 6 | Line, 7 | Pie, 8 | PolarArea, 9 | Radar, 10 | Bubble, 11 | Scatter 12 | } from './typedCharts.js' 13 | 14 | export type { ChartProps, ChartComponentRef } from './types.js' 15 | export { 16 | getDatasetAtEvent, 17 | getElementAtEvent, 18 | getElementsAtEvent 19 | } from './utils.js' 20 | export { 21 | Chart, 22 | createTypedChart, 23 | Bar, 24 | Doughnut, 25 | Line, 26 | Pie, 27 | PolarArea, 28 | Radar, 29 | Bubble, 30 | Scatter 31 | } 32 | -------------------------------------------------------------------------------- /src/props.ts: -------------------------------------------------------------------------------- 1 | import type { PropType } from 'vue' 2 | import type { 3 | ChartType, 4 | ChartData, 5 | ChartOptions, 6 | Plugin, 7 | UpdateMode 8 | } from 'chart.js' 9 | 10 | export const CommonProps = { 11 | data: { 12 | type: Object as PropType, 13 | required: true 14 | }, 15 | options: { 16 | type: Object as PropType, 17 | default: () => ({}) 18 | }, 19 | plugins: { 20 | type: Array as PropType, 21 | default: () => [] 22 | }, 23 | datasetIdKey: { 24 | type: String, 25 | default: 'label' 26 | }, 27 | updateMode: { 28 | type: String as PropType, 29 | default: undefined 30 | } 31 | } as const 32 | 33 | export const A11yProps = { 34 | ariaLabel: { 35 | type: String 36 | }, 37 | ariaDescribedby: { 38 | type: String 39 | } 40 | } as const 41 | 42 | export const Props = { 43 | type: { 44 | type: String as PropType, 45 | required: true 46 | }, 47 | destroyDelay: { 48 | type: Number, 49 | default: 0 // No delay by default 50 | }, 51 | ...CommonProps, 52 | ...A11yProps 53 | } as const 54 | -------------------------------------------------------------------------------- /src/typedCharts.ts: -------------------------------------------------------------------------------- 1 | import { defineComponent, shallowRef, h } from 'vue' 2 | import type { ChartType, ChartComponentLike, DefaultDataPoint } from 'chart.js' 3 | import { 4 | Chart as ChartJS, 5 | BarController, 6 | BubbleController, 7 | DoughnutController, 8 | LineController, 9 | PieController, 10 | PolarAreaController, 11 | RadarController, 12 | ScatterController 13 | } from 'chart.js' 14 | import type { DistributiveArray } from 'chart.js/dist/types/utils' 15 | import type { TypedChartComponent, ChartComponentRef } from './types.js' 16 | import { CommonProps } from './props.js' 17 | import { Chart } from './chart.js' 18 | import { compatProps } from './utils.js' 19 | 20 | export function createTypedChart< 21 | TType extends ChartType = ChartType, 22 | TData = DefaultDataPoint, 23 | TLabel = unknown 24 | >( 25 | type: TType, 26 | registerables: ChartComponentLike 27 | ): TypedChartComponent { 28 | ChartJS.register(registerables) 29 | 30 | return defineComponent({ 31 | props: CommonProps, 32 | setup(props, { expose }) { 33 | const ref = shallowRef(null) 34 | const reforwardRef = (chartRef: ChartComponentRef) => { 35 | ref.value = chartRef?.chart 36 | } 37 | 38 | expose({ chart: ref }) 39 | 40 | return () => { 41 | return h( 42 | Chart, 43 | compatProps( 44 | { 45 | ref: reforwardRef as any 46 | }, 47 | { 48 | type, 49 | ...props 50 | } 51 | ) 52 | ) 53 | } 54 | } 55 | }) as any 56 | } 57 | 58 | export interface ExtendedDataPoint { 59 | [key: string]: string | number | null | ExtendedDataPoint 60 | } 61 | 62 | export const Bar = /* #__PURE__ */ createTypedChart< 63 | 'bar', 64 | DefaultDataPoint<'bar'> | DistributiveArray 65 | >('bar', BarController) 66 | 67 | export const Doughnut = /* #__PURE__ */ createTypedChart( 68 | 'doughnut', 69 | DoughnutController 70 | ) 71 | 72 | export const Line = /* #__PURE__ */ createTypedChart('line', LineController) 73 | 74 | export const Pie = /* #__PURE__ */ createTypedChart('pie', PieController) 75 | 76 | export const PolarArea = /* #__PURE__ */ createTypedChart( 77 | 'polarArea', 78 | PolarAreaController 79 | ) 80 | 81 | export const Radar = /* #__PURE__ */ createTypedChart('radar', RadarController) 82 | 83 | export const Bubble = /* #__PURE__ */ createTypedChart( 84 | 'bubble', 85 | BubbleController 86 | ) 87 | 88 | export const Scatter = /* #__PURE__ */ createTypedChart( 89 | 'scatter', 90 | ScatterController 91 | ) 92 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import type { DefineComponent } from 'vue' 2 | import type { 3 | Chart as ChartJS, 4 | ChartType, 5 | ChartData, 6 | ChartOptions, 7 | DefaultDataPoint, 8 | Plugin, 9 | UpdateMode 10 | } from 'chart.js' 11 | 12 | export interface ChartProps< 13 | TType extends ChartType = ChartType, 14 | TData = DefaultDataPoint, 15 | TLabel = unknown 16 | > { 17 | /** 18 | * Chart.js chart type 19 | */ 20 | type: TType 21 | /** 22 | * The data object that is passed into the Chart.js chart 23 | * @see https://www.chartjs.org/docs/latest/getting-started/ 24 | */ 25 | data: ChartData 26 | /** 27 | * The options object that is passed into the Chart.js chart 28 | * @see https://www.chartjs.org/docs/latest/general/options.html 29 | * @default {} 30 | */ 31 | options?: ChartOptions 32 | /** 33 | * The plugins array that is passed into the Chart.js chart 34 | * @see https://www.chartjs.org/docs/latest/developers/plugins.html 35 | * @default [] 36 | */ 37 | plugins?: Plugin[] 38 | /** 39 | * Key name to identificate dataset 40 | * @default 'label' 41 | */ 42 | datasetIdKey?: string 43 | /** 44 | * A mode string to indicate transition configuration should be used. 45 | * @see https://www.chartjs.org/docs/latest/developers/api.html#update-mode 46 | */ 47 | updateMode?: UpdateMode 48 | } 49 | 50 | export interface ChartComponentRef< 51 | TType extends ChartType = ChartType, 52 | TData = DefaultDataPoint, 53 | TLabel = unknown 54 | > { 55 | chart: ChartJS | null 56 | } 57 | 58 | export type ChartComponent = DefineComponent 59 | 60 | export type TypedChartComponent< 61 | TType extends ChartType, 62 | TData = DefaultDataPoint, 63 | TLabel = unknown 64 | > = DefineComponent, 'type'>> 65 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | import { isProxy, toRaw, version } from 'vue' 2 | import type { 3 | Chart, 4 | ChartType, 5 | ChartData, 6 | ChartDataset, 7 | ChartOptions, 8 | DefaultDataPoint 9 | } from 'chart.js' 10 | 11 | export const compatProps = 12 | version[0] === '2' 13 | ? (internals: I, props: T) => 14 | Object.assign(internals, { attrs: props }) as unknown as I & T 15 | : (internals: I, props: T) => 16 | Object.assign(internals, props) 17 | 18 | export function toRawIfProxy(obj: T) { 19 | return isProxy(obj) ? toRaw(obj) : obj 20 | } 21 | 22 | export function cloneProxy(obj: T, src = obj) { 23 | return isProxy(src) ? new Proxy(obj, {}) : obj 24 | } 25 | 26 | export function setOptions< 27 | TType extends ChartType = ChartType, 28 | TData = DefaultDataPoint, 29 | TLabel = unknown 30 | >(chart: Chart, nextOptions: ChartOptions) { 31 | const options = chart.options 32 | 33 | if (options && nextOptions) { 34 | Object.assign(options, nextOptions) 35 | } 36 | } 37 | 38 | export function setLabels< 39 | TType extends ChartType = ChartType, 40 | TData = DefaultDataPoint, 41 | TLabel = unknown 42 | >( 43 | currentData: ChartData, 44 | nextLabels: TLabel[] | undefined 45 | ) { 46 | currentData.labels = nextLabels 47 | } 48 | 49 | export function setDatasets< 50 | TType extends ChartType = ChartType, 51 | TData = DefaultDataPoint, 52 | TLabel = unknown 53 | >( 54 | currentData: ChartData, 55 | nextDatasets: ChartDataset[], 56 | datasetIdKey: string 57 | ) { 58 | const addedDatasets: ChartDataset[] = [] 59 | 60 | currentData.datasets = nextDatasets.map( 61 | (nextDataset: Record) => { 62 | // given the new set, find it's current match 63 | const currentDataset = currentData.datasets.find( 64 | (dataset: Record) => 65 | dataset[datasetIdKey] === nextDataset[datasetIdKey] 66 | ) 67 | 68 | // There is no original to update, so simply add new one 69 | if ( 70 | !currentDataset || 71 | !nextDataset.data || 72 | addedDatasets.includes(currentDataset) 73 | ) { 74 | return { ...nextDataset } as ChartDataset 75 | } 76 | 77 | addedDatasets.push(currentDataset) 78 | 79 | Object.assign(currentDataset, nextDataset) 80 | 81 | return currentDataset 82 | } 83 | ) 84 | } 85 | 86 | export function cloneData< 87 | TType extends ChartType = ChartType, 88 | TData = DefaultDataPoint, 89 | TLabel = unknown 90 | >(data: ChartData, datasetIdKey: string) { 91 | const nextData: ChartData = { 92 | labels: [], 93 | datasets: [] 94 | } 95 | 96 | setLabels(nextData, data.labels) 97 | setDatasets(nextData, data.datasets, datasetIdKey) 98 | 99 | return nextData 100 | } 101 | 102 | /** 103 | * Get dataset from mouse click event 104 | * @param chart - Chart.js instance 105 | * @param event - Mouse click event 106 | * @returns Dataset 107 | */ 108 | export function getDatasetAtEvent(chart: Chart, event: MouseEvent) { 109 | return chart.getElementsAtEventForMode( 110 | event, 111 | 'dataset', 112 | { intersect: true }, 113 | false 114 | ) 115 | } 116 | 117 | /** 118 | * Get single dataset element from mouse click event 119 | * @param chart - Chart.js instance 120 | * @param event - Mouse click event 121 | * @returns Dataset 122 | */ 123 | export function getElementAtEvent(chart: Chart, event: MouseEvent) { 124 | return chart.getElementsAtEventForMode( 125 | event, 126 | 'nearest', 127 | { intersect: true }, 128 | false 129 | ) 130 | } 131 | 132 | /** 133 | * Get all dataset elements from mouse click event 134 | * @param chart - Chart.js instance 135 | * @param event - Mouse click event 136 | * @returns Dataset 137 | */ 138 | export function getElementsAtEvent(chart: Chart, event: MouseEvent) { 139 | return chart.getElementsAtEventForMode( 140 | event, 141 | 'index', 142 | { intersect: true }, 143 | false 144 | ) 145 | } 146 | -------------------------------------------------------------------------------- /stories/bar.stories.ts: -------------------------------------------------------------------------------- 1 | import 'chart.js/auto' 2 | import { Bar } from '../src/index.js' 3 | import * as barChartConfig from '../sandboxes/bar/src/chartConfig.js' 4 | 5 | export default { 6 | title: 'BarChart', 7 | component: Bar, 8 | parameters: { 9 | layout: 'centered' 10 | } 11 | } 12 | 13 | export function Default(args) { 14 | return { 15 | components: { Bar }, 16 | template: '', 17 | setup() { 18 | return { args } 19 | } 20 | } 21 | } 22 | 23 | Default.args = { 24 | id: 'bar-chart', 25 | width: 400, 26 | height: 400, 27 | ...barChartConfig 28 | } 29 | -------------------------------------------------------------------------------- /stories/bubble.stories.ts: -------------------------------------------------------------------------------- 1 | import 'chart.js/auto' 2 | import { Bubble } from '../src/index.js' 3 | import * as bubbleChartConfig from '../sandboxes/bubble/src/chartConfig.js' 4 | 5 | export default { 6 | title: 'BubbleChart', 7 | component: Bubble, 8 | parameters: { 9 | layout: 'centered' 10 | } 11 | } 12 | 13 | export function Default(args) { 14 | return { 15 | components: { Bubble }, 16 | template: '', 17 | setup() { 18 | return { args } 19 | } 20 | } 21 | } 22 | 23 | Default.args = { 24 | id: 'bar-chart', 25 | width: 400, 26 | height: 400, 27 | ...bubbleChartConfig 28 | } 29 | -------------------------------------------------------------------------------- /stories/chart.stories.ts: -------------------------------------------------------------------------------- 1 | import 'chart.js/auto' 2 | import type { InteractionItem } from 'chart.js' 3 | import { ref } from 'vue' 4 | import { 5 | ChartComponentRef, 6 | Chart, 7 | getDatasetAtEvent, 8 | getElementAtEvent, 9 | getElementsAtEvent 10 | } from '../src/index.js' 11 | import * as barChartConfig from '../sandboxes/bar/src/chartConfig.js' 12 | 13 | export default { 14 | title: 'Chart', 15 | component: Chart, 16 | parameters: { 17 | layout: 'centered' 18 | } 19 | } 20 | 21 | export function Default(args) { 22 | return { 23 | components: { Chart }, 24 | template: '', 25 | setup() { 26 | return { args } 27 | } 28 | } 29 | } 30 | 31 | Default.args = { 32 | id: 'bar-chart', 33 | type: 'bar', 34 | width: 400, 35 | height: 400, 36 | ...barChartConfig 37 | } 38 | 39 | export function Events(args) { 40 | return { 41 | components: { Chart }, 42 | template: '', 43 | setup() { 44 | const datasetAtEvent = (dataset: InteractionItem[]) => { 45 | if (!dataset.length) return 46 | 47 | const datasetIndex = dataset[0].datasetIndex 48 | 49 | console.log('dataset', barChartConfig.data.datasets[datasetIndex].label) 50 | } 51 | 52 | const elementAtEvent = (element: InteractionItem[]) => { 53 | if (!element.length) return 54 | 55 | const { datasetIndex, index } = element[0] 56 | 57 | console.log( 58 | 'element', 59 | barChartConfig.data.labels[index], 60 | barChartConfig.data.datasets[datasetIndex].data[index] 61 | ) 62 | } 63 | 64 | const elementsAtEvent = (elements: InteractionItem[]) => { 65 | if (!elements.length) return 66 | 67 | console.log('elements', elements) 68 | } 69 | 70 | const chartRef = ref(null) 71 | 72 | const onClick = (event: MouseEvent) => { 73 | const { 74 | value: { chart } 75 | } = chartRef 76 | 77 | if (!chart) { 78 | return 79 | } 80 | 81 | datasetAtEvent(getDatasetAtEvent(chart, event)) 82 | elementAtEvent(getElementAtEvent(chart, event)) 83 | elementsAtEvent(getElementsAtEvent(chart, event)) 84 | } 85 | 86 | return { 87 | chartRef, 88 | args, 89 | onClick 90 | } 91 | } 92 | } 93 | } 94 | 95 | Events.args = { 96 | id: 'bar-chart', 97 | type: 'bar', 98 | width: 400, 99 | height: 400, 100 | ...barChartConfig 101 | } 102 | -------------------------------------------------------------------------------- /stories/custom.stories.ts: -------------------------------------------------------------------------------- 1 | import 'chart.js/auto' 2 | import LineWithLineChart from '../sandboxes/custom/src/components/LineWithLineChart.js' 3 | import * as customChartConfig from '../sandboxes/custom/src/chartConfig.js' 4 | 5 | export default { 6 | title: 'CustomChart', 7 | component: LineWithLineChart, 8 | parameters: { 9 | layout: 'centered' 10 | } 11 | } 12 | 13 | export function Default(args) { 14 | return { 15 | components: { LineWithLineChart }, 16 | template: '', 17 | setup() { 18 | return { args } 19 | } 20 | } 21 | } 22 | 23 | Default.args = { 24 | id: 'custom-chart', 25 | width: 400, 26 | height: 400, 27 | ...customChartConfig 28 | } 29 | -------------------------------------------------------------------------------- /stories/doughnut.stories.ts: -------------------------------------------------------------------------------- 1 | import 'chart.js/auto' 2 | import { Doughnut } from '../src/index.js' 3 | import * as doughnutChartConfig from '../sandboxes/doughnut/src/chartConfig.js' 4 | 5 | export default { 6 | title: 'DoughnutChart', 7 | component: Doughnut, 8 | parameters: { 9 | layout: 'centered' 10 | } 11 | } 12 | 13 | export function Default(args) { 14 | return { 15 | components: { Doughnut }, 16 | template: '', 17 | setup() { 18 | return { args } 19 | } 20 | } 21 | } 22 | 23 | Default.args = { 24 | id: 'doughnut-chart', 25 | width: 400, 26 | height: 400, 27 | ...doughnutChartConfig 28 | } 29 | -------------------------------------------------------------------------------- /stories/line.stories.ts: -------------------------------------------------------------------------------- 1 | import 'chart.js/auto' 2 | import { Line } from '../src/index.js' 3 | import * as lineChartConfig from '../sandboxes/line/src/chartConfig.js' 4 | 5 | export default { 6 | title: 'LineChart', 7 | component: Line, 8 | parameters: { 9 | layout: 'centered' 10 | } 11 | } 12 | 13 | export function Default(args) { 14 | return { 15 | components: { Line }, 16 | template: '', 17 | setup() { 18 | return { args } 19 | } 20 | } 21 | } 22 | 23 | Default.args = { 24 | id: 'line-chart', 25 | width: 400, 26 | height: 400, 27 | ...lineChartConfig 28 | } 29 | -------------------------------------------------------------------------------- /stories/pie.stories.ts: -------------------------------------------------------------------------------- 1 | import 'chart.js/auto' 2 | import { Pie } from '../src/index.js' 3 | import * as pieChartConfig from '../sandboxes/pie/src/chartConfig.js' 4 | 5 | export default { 6 | title: 'PieChart', 7 | component: Pie, 8 | parameters: { 9 | layout: 'centered' 10 | } 11 | } 12 | 13 | export function Default(args) { 14 | return { 15 | components: { Pie }, 16 | template: '', 17 | setup() { 18 | return { args } 19 | } 20 | } 21 | } 22 | 23 | Default.args = { 24 | id: 'pie-chart', 25 | width: 400, 26 | height: 400, 27 | ...pieChartConfig 28 | } 29 | -------------------------------------------------------------------------------- /stories/polarArea.stories.ts: -------------------------------------------------------------------------------- 1 | import 'chart.js/auto' 2 | import { PolarArea } from '../src/index.js' 3 | import * as polarAreaChartConfig from '../sandboxes/polar-area/src/chartConfig.js' 4 | 5 | export default { 6 | title: 'PolarAreaChart', 7 | component: PolarArea, 8 | parameters: { 9 | layout: 'centered' 10 | } 11 | } 12 | 13 | export function Default(args) { 14 | return { 15 | components: { PolarArea }, 16 | template: '', 17 | setup() { 18 | return { args } 19 | } 20 | } 21 | } 22 | 23 | Default.args = { 24 | id: 'polar-area-chart', 25 | width: 400, 26 | height: 400, 27 | ...polarAreaChartConfig 28 | } 29 | -------------------------------------------------------------------------------- /stories/radar.stories.ts: -------------------------------------------------------------------------------- 1 | import 'chart.js/auto' 2 | import { Radar } from '../src/index.js' 3 | import * as radarChartConfig from '../sandboxes/radar/src/chartConfig.js' 4 | 5 | export default { 6 | title: 'RadarChart', 7 | component: Radar, 8 | parameters: { 9 | layout: 'centered' 10 | } 11 | } 12 | 13 | export function Default(args) { 14 | return { 15 | components: { Radar }, 16 | template: '', 17 | setup() { 18 | return { args } 19 | } 20 | } 21 | } 22 | 23 | Default.args = { 24 | id: 'radar-chart', 25 | width: 400, 26 | height: 400, 27 | ...radarChartConfig 28 | } 29 | -------------------------------------------------------------------------------- /stories/reactive.stories.ts: -------------------------------------------------------------------------------- 1 | import 'chart.js/auto' 2 | import { ref, onMounted } from 'vue' 3 | import { Bar } from '../src/index.js' 4 | import * as reactiveChartConfig from '../sandboxes/reactive/src/chartConfig.js' 5 | 6 | export default { 7 | title: 'Reactive', 8 | component: Bar, 9 | parameters: { 10 | layout: 'centered' 11 | } 12 | } 13 | 14 | export function Default(args) { 15 | return { 16 | components: { Bar }, 17 | template: '', 18 | setup() { 19 | const options = reactiveChartConfig.options 20 | const data = ref({ 21 | datasets: [] 22 | }) 23 | 24 | onMounted(() => { 25 | setInterval(() => { 26 | data.value = reactiveChartConfig.randomData() 27 | }, 3000) 28 | }) 29 | 30 | return { 31 | args, 32 | options, 33 | data 34 | } 35 | } 36 | } 37 | } 38 | 39 | Default.args = { 40 | id: 'reactive-chart', 41 | width: 400, 42 | height: 400 43 | } 44 | -------------------------------------------------------------------------------- /stories/scatter.stories.ts: -------------------------------------------------------------------------------- 1 | import 'chart.js/auto' 2 | import { Scatter } from '../src/index.js' 3 | import * as scatterChartConfig from '../sandboxes/scatter/src/chartConfig.js' 4 | 5 | export default { 6 | title: 'ScatterChart', 7 | component: Scatter, 8 | parameters: { 9 | layout: 'centered' 10 | } 11 | } 12 | 13 | export function Default(args) { 14 | return { 15 | components: { Scatter }, 16 | template: '', 17 | setup() { 18 | return { args } 19 | } 20 | } 21 | } 22 | 23 | Default.args = { 24 | id: 'scatter-chart', 25 | width: 400, 26 | height: 400, 27 | ...scatterChartConfig 28 | } 29 | -------------------------------------------------------------------------------- /test/Bar.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest' 2 | import { mount } from '@vue/test-utils' 3 | import { Bar } from '../src/index.js' 4 | import * as barChartConfig from '../sandboxes/bar/src/chartConfig.js' 5 | 6 | describe('BarChart', () => { 7 | it('should render a canvas', () => { 8 | const wrapper = mount(Bar, { 9 | props: barChartConfig as any 10 | }) 11 | 12 | const canvas = wrapper.find('canvas') 13 | 14 | expect(canvas.exists()).toBe(true) 15 | expect(canvas.element.id).toBe('') 16 | }) 17 | 18 | it('should change id based on prop', () => { 19 | const wrapper = mount(Bar, { 20 | props: { 21 | id: 'bar-chart-id', 22 | ...barChartConfig 23 | } as any 24 | }) 25 | 26 | const canvas = wrapper.find('canvas') 27 | 28 | expect(canvas.exists()).toBe(true) 29 | expect(canvas.element.id).toBe('bar-chart-id') 30 | }) 31 | 32 | it('should add inline plugins based on prop', () => { 33 | const testPlugin = { 34 | id: 'test' 35 | } 36 | 37 | const wrapper = mount(Bar, { 38 | props: { 39 | plugins: [testPlugin], 40 | ...barChartConfig 41 | } as any 42 | }) 43 | 44 | expect(wrapper.props().plugins.length).toEqual(1) 45 | }) 46 | }) 47 | -------------------------------------------------------------------------------- /test/Bubble.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest' 2 | import { mount } from '@vue/test-utils' 3 | import { Bubble } from '../src/index.js' 4 | import * as bubbleChartConfig from '../sandboxes/bubble/src/chartConfig.js' 5 | 6 | describe('BubbleChart', () => { 7 | it('should render a canvas', () => { 8 | const wrapper = mount(Bubble, { 9 | props: bubbleChartConfig as any 10 | }) 11 | 12 | const canvas = wrapper.find('canvas') 13 | 14 | expect(canvas.exists()).toBe(true) 15 | expect(canvas.element.id).toBe('') 16 | }) 17 | 18 | it('should change id based on prop', () => { 19 | const wrapper = mount(Bubble, { 20 | props: { 21 | id: 'bubble-chart-id', 22 | ...bubbleChartConfig 23 | } as any 24 | }) 25 | 26 | const canvas = wrapper.find('canvas') 27 | 28 | expect(canvas.exists()).toBe(true) 29 | expect(canvas.element.id).toBe('bubble-chart-id') 30 | }) 31 | 32 | it('should add inline plugins based on prop', () => { 33 | const testPlugin = { 34 | id: 'test' 35 | } 36 | 37 | const wrapper = mount(Bubble, { 38 | props: { 39 | plugins: [testPlugin], 40 | ...bubbleChartConfig 41 | } as any 42 | }) 43 | 44 | expect(wrapper.props().plugins.length).toEqual(1) 45 | }) 46 | }) 47 | -------------------------------------------------------------------------------- /test/Doughnut.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest' 2 | import { mount } from '@vue/test-utils' 3 | import { Doughnut } from '../src/index.js' 4 | import * as doughnutChartConfig from '../sandboxes/doughnut/src/chartConfig.js' 5 | 6 | describe('DoughnutChart', () => { 7 | it('should render a canvas', () => { 8 | const wrapper = mount(Doughnut, { 9 | props: doughnutChartConfig as any 10 | }) 11 | 12 | const canvas = wrapper.find('canvas') 13 | 14 | expect(canvas.exists()).toBe(true) 15 | expect(canvas.element.id).toBe('') 16 | }) 17 | 18 | it('should change id based on prop', () => { 19 | const wrapper = mount(Doughnut, { 20 | props: { 21 | id: 'doughnut-chart-id', 22 | ...doughnutChartConfig 23 | } as any 24 | }) 25 | 26 | const canvas = wrapper.find('canvas') 27 | 28 | expect(canvas.exists()).toBe(true) 29 | expect(canvas.element.id).toBe('doughnut-chart-id') 30 | }) 31 | 32 | it('should add inline plugins based on prop', () => { 33 | const testPlugin = { 34 | id: 'test' 35 | } 36 | 37 | const wrapper = mount(Doughnut, { 38 | props: { 39 | plugins: [testPlugin], 40 | ...doughnutChartConfig 41 | } as any 42 | }) 43 | 44 | expect(wrapper.props().plugins.length).toEqual(1) 45 | }) 46 | }) 47 | -------------------------------------------------------------------------------- /test/Line.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest' 2 | import { mount } from '@vue/test-utils' 3 | import { Line } from '../src/index.js' 4 | import * as lineChartConfig from '../sandboxes/line/src/chartConfig.js' 5 | 6 | describe('LineChart', () => { 7 | it('should render a canvas', () => { 8 | const wrapper = mount(Line, { 9 | props: lineChartConfig as any 10 | }) 11 | 12 | const canvas = wrapper.find('canvas') 13 | 14 | expect(canvas.exists()).toBe(true) 15 | expect(canvas.element.id).toBe('') 16 | }) 17 | 18 | it('should change id based on prop', () => { 19 | const wrapper = mount(Line, { 20 | props: { 21 | id: 'line-chart-id', 22 | ...lineChartConfig 23 | } as any 24 | }) 25 | 26 | const canvas = wrapper.find('canvas') 27 | 28 | expect(canvas.exists()).toBe(true) 29 | expect(canvas.element.id).toBe('line-chart-id') 30 | }) 31 | 32 | it('should add inline plugins based on prop', () => { 33 | const testPlugin = { 34 | id: 'test' 35 | } 36 | 37 | const wrapper = mount(Line, { 38 | props: { 39 | plugins: [testPlugin], 40 | ...lineChartConfig 41 | } as any 42 | }) 43 | 44 | expect(wrapper.props().plugins.length).toEqual(1) 45 | }) 46 | }) 47 | -------------------------------------------------------------------------------- /test/Pie.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest' 2 | import { mount } from '@vue/test-utils' 3 | import { Pie } from '../src/index.js' 4 | import * as pieChartConfig from '../sandboxes/pie/src/chartConfig.js' 5 | 6 | describe('PieChart', () => { 7 | it('should render a canvas', () => { 8 | const wrapper = mount(Pie, { 9 | props: pieChartConfig as any 10 | }) 11 | 12 | const canvas = wrapper.find('canvas') 13 | 14 | expect(canvas.exists()).toBe(true) 15 | expect(canvas.element.id).toBe('') 16 | }) 17 | 18 | it('should change id based on prop', () => { 19 | const wrapper = mount(Pie, { 20 | props: { 21 | id: 'pie-chart-id', 22 | ...pieChartConfig 23 | } as any 24 | }) 25 | 26 | const canvas = wrapper.find('canvas') 27 | 28 | expect(canvas.exists()).toBe(true) 29 | expect(canvas.element.id).toBe('pie-chart-id') 30 | }) 31 | 32 | it('should add inline plugins based on prop', () => { 33 | const testPlugin = { 34 | id: 'test' 35 | } 36 | 37 | const wrapper = mount(Pie, { 38 | props: { 39 | plugins: [testPlugin], 40 | ...pieChartConfig 41 | } as any 42 | }) 43 | 44 | expect(wrapper.props().plugins.length).toEqual(1) 45 | }) 46 | }) 47 | -------------------------------------------------------------------------------- /test/PolarArea.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest' 2 | import { mount } from '@vue/test-utils' 3 | import { PolarArea } from '../src/index.js' 4 | import * as polarAreaChartConfig from '../sandboxes/polar-area/src/chartConfig.js' 5 | 6 | describe('PolarAreaChart', () => { 7 | it('should render a canvas', () => { 8 | const wrapper = mount(PolarArea, { 9 | props: polarAreaChartConfig as any 10 | }) 11 | 12 | const canvas = wrapper.find('canvas') 13 | 14 | expect(canvas.exists()).toBe(true) 15 | expect(canvas.element.id).toBe('') 16 | }) 17 | 18 | it('should change id based on prop', () => { 19 | const wrapper = mount(PolarArea, { 20 | props: { 21 | id: 'polar-area-chart-id', 22 | ...polarAreaChartConfig 23 | } as any 24 | }) 25 | 26 | const canvas = wrapper.find('canvas') 27 | 28 | expect(canvas.exists()).toBe(true) 29 | expect(canvas.element.id).toBe('polar-area-chart-id') 30 | }) 31 | 32 | it('should add inline plugins based on prop', () => { 33 | const testPlugin = { 34 | id: 'test' 35 | } 36 | 37 | const wrapper = mount(PolarArea, { 38 | props: { 39 | plugins: [testPlugin], 40 | ...polarAreaChartConfig 41 | } as any 42 | }) 43 | 44 | expect(wrapper.props().plugins.length).toEqual(1) 45 | }) 46 | }) 47 | -------------------------------------------------------------------------------- /test/Radar.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest' 2 | import { mount } from '@vue/test-utils' 3 | import { Radar } from '../src/index.js' 4 | import * as radarChartConfig from '../sandboxes/radar/src/chartConfig.js' 5 | 6 | describe('RadarChart', () => { 7 | it('should render a canvas', () => { 8 | const wrapper = mount(Radar, { 9 | props: radarChartConfig as any 10 | }) 11 | 12 | const canvas = wrapper.find('canvas') 13 | 14 | expect(canvas.exists()).toBe(true) 15 | expect(canvas.element.id).toBe('') 16 | }) 17 | 18 | it('should change id based on prop', () => { 19 | const wrapper = mount(Radar, { 20 | props: { 21 | id: 'radar-chart-id', 22 | ...radarChartConfig 23 | } as any 24 | }) 25 | 26 | const canvas = wrapper.find('canvas') 27 | 28 | expect(canvas.exists()).toBe(true) 29 | expect(canvas.element.id).toBe('radar-chart-id') 30 | }) 31 | 32 | it('should add inline plugins based on prop', () => { 33 | const testPlugin = { 34 | id: 'test' 35 | } 36 | 37 | const wrapper = mount(Radar, { 38 | props: { 39 | plugins: [testPlugin], 40 | ...radarChartConfig 41 | } as any 42 | }) 43 | 44 | expect(wrapper.props().plugins.length).toEqual(1) 45 | }) 46 | }) 47 | -------------------------------------------------------------------------------- /test/Scatter.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest' 2 | import { mount } from '@vue/test-utils' 3 | import { Scatter } from '../src/index.js' 4 | import * as scatterChartConfig from '../sandboxes/scatter/src/chartConfig.js' 5 | 6 | describe('ScatterChart', () => { 7 | it('should render a canvas', () => { 8 | const wrapper = mount(Scatter, { 9 | props: scatterChartConfig as any 10 | }) 11 | 12 | const canvas = wrapper.find('canvas') 13 | 14 | expect(canvas.exists()).toBe(true) 15 | expect(canvas.element.id).toBe('') 16 | }) 17 | 18 | it('should change id based on prop', () => { 19 | const wrapper = mount(Scatter, { 20 | props: { 21 | id: 'scatter-chart-id', 22 | ...scatterChartConfig 23 | } as any 24 | }) 25 | 26 | const canvas = wrapper.find('canvas') 27 | 28 | expect(canvas.exists()).toBe(true) 29 | expect(canvas.element.id).toBe('scatter-chart-id') 30 | }) 31 | 32 | it('should add inline plugins based on prop', () => { 33 | const testPlugin = { 34 | id: 'test' 35 | } 36 | 37 | const wrapper = mount(Scatter, { 38 | props: { 39 | plugins: [testPlugin], 40 | ...scatterChartConfig 41 | } as any 42 | }) 43 | 44 | expect(wrapper.props().plugins.length).toEqual(1) 45 | }) 46 | }) 47 | -------------------------------------------------------------------------------- /test/setup.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import 'vitest-canvas-mock' 3 | 4 | class ResizeObserver { 5 | observe() {} 6 | unobserve() {} 7 | disconnect() {} 8 | } 9 | 10 | window.ResizeObserver = ResizeObserver 11 | 12 | class MutationObserver { 13 | disconnect() {} 14 | unobserve() {} 15 | observe() {} 16 | } 17 | 18 | window.MutationObserver = MutationObserver 19 | -------------------------------------------------------------------------------- /test/types.test-d.ts: -------------------------------------------------------------------------------- 1 | import { h } from 'vue' 2 | import { expectError } from 'tsd' 3 | import type { Plugin } from 'chart.js' 4 | 5 | import { Bar, Radar, Scatter, Doughnut } from '../src/index.js' 6 | 7 | const data = { 8 | datasets: [] 9 | } 10 | 11 | const testPlugin = { 12 | id: 'test' 13 | } 14 | 15 | /** 16 | * Should check type-specific props 17 | */ 18 | 19 | h(Radar, { 20 | data, 21 | plugins: [] 22 | }) 23 | 24 | h(Scatter, { 25 | data, 26 | plugins: [] 27 | }) 28 | 29 | h(Bar, { 30 | data, 31 | options: {} 32 | }) 33 | 34 | expectError( 35 | h(Scatter, { 36 | data, 37 | plugins: [testPlugin] as Plugin<'bubble'>[] 38 | }) 39 | ) 40 | 41 | /** 42 | * Should check type-specific options 43 | */ 44 | 45 | h(Doughnut, { 46 | data, 47 | options: { 48 | cutout: '75%' 49 | } 50 | }) 51 | 52 | expectError( 53 | h(Scatter, { 54 | data, 55 | options: { 56 | cutout: '75%' 57 | } 58 | }) 59 | ) 60 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Type Checking */ 4 | "strict": true, 5 | "strictBindCallApply": true, 6 | "noFallthroughCasesInSwitch": true, 7 | "noImplicitOverride": true, 8 | "noImplicitReturns": true, 9 | "noUnusedLocals": true, 10 | "noUnusedParameters": true, 11 | /* Modules */ 12 | "baseUrl": ".", 13 | "module": "ESNext", 14 | "moduleResolution": "Node", // restore to "NodeNext" after Chart.js update 15 | "resolveJsonModule": true, 16 | /* Emit */ 17 | "declaration": true, 18 | "declarationMap": true, 19 | "importsNotUsedAsValues": "error", 20 | "inlineSourceMap": true, 21 | "outDir": "dist", 22 | /* Interop Constraints */ 23 | "allowSyntheticDefaultImports": true, 24 | "isolatedModules": true, 25 | /* Language and Environment */ 26 | "lib": [ 27 | "dom", 28 | "esnext" 29 | ], 30 | "target": "ESNext", 31 | /* Completeness */ 32 | "skipLibCheck": true 33 | }, 34 | "include": [ 35 | "src" 36 | ], 37 | "exclude": [ 38 | "dist" 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | 4 | export default defineConfig({ 5 | plugins: [vue()], 6 | test: { 7 | environment: 'jsdom', 8 | setupFiles: ['test/setup.js'], 9 | deps: { 10 | inline: ['vitest-canvas-mock'] 11 | }, 12 | coverage: { 13 | reporter: ['lcovonly', 'text'] 14 | } 15 | } 16 | }) 17 | -------------------------------------------------------------------------------- /website/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "website", 3 | "version": "0.0.0", 4 | "private": true, 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vitepress dev src", 8 | "build": "vitepress build src" 9 | }, 10 | "devDependencies": { 11 | "vitepress": "^1.4.3" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /website/src/.vitepress/cache/deps/@theme_index.js: -------------------------------------------------------------------------------- 1 | import { useMediaQuery } from './chunk-PWVUJGW4.js' 2 | import { computed, ref, shallowRef, watch } from './chunk-6J5AW4SK.js' 3 | 4 | // node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/index.js 5 | import '/Users/jakubjuszczak/Projekte/Privat/vue-chartjs/website/node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/styles/fonts.css' 6 | 7 | // node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/without-fonts.js 8 | import '/Users/jakubjuszczak/Projekte/Privat/vue-chartjs/website/node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/styles/vars.css' 9 | import '/Users/jakubjuszczak/Projekte/Privat/vue-chartjs/website/node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/styles/base.css' 10 | import '/Users/jakubjuszczak/Projekte/Privat/vue-chartjs/website/node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/styles/icons.css' 11 | import '/Users/jakubjuszczak/Projekte/Privat/vue-chartjs/website/node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/styles/utils.css' 12 | import '/Users/jakubjuszczak/Projekte/Privat/vue-chartjs/website/node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/styles/components/custom-block.css' 13 | import '/Users/jakubjuszczak/Projekte/Privat/vue-chartjs/website/node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/styles/components/vp-code.css' 14 | import '/Users/jakubjuszczak/Projekte/Privat/vue-chartjs/website/node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/styles/components/vp-code-group.css' 15 | import '/Users/jakubjuszczak/Projekte/Privat/vue-chartjs/website/node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/styles/components/vp-doc.css' 16 | import '/Users/jakubjuszczak/Projekte/Privat/vue-chartjs/website/node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/styles/components/vp-sponsor.css' 17 | import VPBadge from '/Users/jakubjuszczak/Projekte/Privat/vue-chartjs/website/node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/components/VPBadge.vue' 18 | import Layout from '/Users/jakubjuszczak/Projekte/Privat/vue-chartjs/website/node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/Layout.vue' 19 | import { default as default2 } from '/Users/jakubjuszczak/Projekte/Privat/vue-chartjs/website/node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/components/VPBadge.vue' 20 | import { default as default3 } from '/Users/jakubjuszczak/Projekte/Privat/vue-chartjs/website/node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/components/VPImage.vue' 21 | import { default as default4 } from '/Users/jakubjuszczak/Projekte/Privat/vue-chartjs/website/node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/components/VPButton.vue' 22 | import { default as default5 } from '/Users/jakubjuszczak/Projekte/Privat/vue-chartjs/website/node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/components/VPHomeContent.vue' 23 | import { default as default6 } from '/Users/jakubjuszczak/Projekte/Privat/vue-chartjs/website/node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/components/VPHomeHero.vue' 24 | import { default as default7 } from '/Users/jakubjuszczak/Projekte/Privat/vue-chartjs/website/node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/components/VPHomeFeatures.vue' 25 | import { default as default8 } from '/Users/jakubjuszczak/Projekte/Privat/vue-chartjs/website/node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/components/VPHomeSponsors.vue' 26 | import { default as default9 } from '/Users/jakubjuszczak/Projekte/Privat/vue-chartjs/website/node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/components/VPLink.vue' 27 | import { default as default10 } from '/Users/jakubjuszczak/Projekte/Privat/vue-chartjs/website/node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/components/VPDocAsideSponsors.vue' 28 | import { default as default11 } from '/Users/jakubjuszczak/Projekte/Privat/vue-chartjs/website/node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/components/VPSocialLink.vue' 29 | import { default as default12 } from '/Users/jakubjuszczak/Projekte/Privat/vue-chartjs/website/node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/components/VPSocialLinks.vue' 30 | import { default as default13 } from '/Users/jakubjuszczak/Projekte/Privat/vue-chartjs/website/node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/components/VPSponsors.vue' 31 | import { default as default14 } from '/Users/jakubjuszczak/Projekte/Privat/vue-chartjs/website/node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/components/VPTeamPage.vue' 32 | import { default as default15 } from '/Users/jakubjuszczak/Projekte/Privat/vue-chartjs/website/node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/components/VPTeamPageTitle.vue' 33 | import { default as default16 } from '/Users/jakubjuszczak/Projekte/Privat/vue-chartjs/website/node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/components/VPTeamPageSection.vue' 34 | import { default as default17 } from '/Users/jakubjuszczak/Projekte/Privat/vue-chartjs/website/node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/components/VPTeamMembers.vue' 35 | 36 | // node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/support/utils.js 37 | import { withBase } from 'vitepress' 38 | 39 | // node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/composables/data.js 40 | import { useData as useData$ } from 'vitepress' 41 | var useData = useData$ 42 | 43 | // node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/support/utils.js 44 | function ensureStartingSlash(path) { 45 | return /^\//.test(path) ? path : `/${path}` 46 | } 47 | 48 | // node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/support/sidebar.js 49 | function getSidebar(_sidebar, path) { 50 | if (Array.isArray(_sidebar)) return addBase(_sidebar) 51 | if (_sidebar == null) return [] 52 | path = ensureStartingSlash(path) 53 | const dir = Object.keys(_sidebar) 54 | .sort((a, b) => { 55 | return b.split('/').length - a.split('/').length 56 | }) 57 | .find(dir2 => { 58 | return path.startsWith(ensureStartingSlash(dir2)) 59 | }) 60 | const sidebar = dir ? _sidebar[dir] : [] 61 | return Array.isArray(sidebar) 62 | ? addBase(sidebar) 63 | : addBase(sidebar.items, sidebar.base) 64 | } 65 | function getSidebarGroups(sidebar) { 66 | const groups = [] 67 | let lastGroupIndex = 0 68 | for (const index in sidebar) { 69 | const item = sidebar[index] 70 | if (item.items) { 71 | lastGroupIndex = groups.push(item) 72 | continue 73 | } 74 | if (!groups[lastGroupIndex]) { 75 | groups.push({ items: [] }) 76 | } 77 | groups[lastGroupIndex].items.push(item) 78 | } 79 | return groups 80 | } 81 | function addBase(items, _base) { 82 | return [...items].map(_item => { 83 | const item = { ..._item } 84 | const base = item.base || _base 85 | if (base && item.link) item.link = base + item.link 86 | if (item.items) item.items = addBase(item.items, base) 87 | return item 88 | }) 89 | } 90 | 91 | // node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/composables/sidebar.js 92 | function useSidebar() { 93 | const { frontmatter, page, theme: theme2 } = useData() 94 | const is960 = useMediaQuery('(min-width: 960px)') 95 | const isOpen = ref(false) 96 | const _sidebar = computed(() => { 97 | const sidebarConfig = theme2.value.sidebar 98 | const relativePath = page.value.relativePath 99 | return sidebarConfig ? getSidebar(sidebarConfig, relativePath) : [] 100 | }) 101 | const sidebar = ref(_sidebar.value) 102 | watch(_sidebar, (next, prev) => { 103 | if (JSON.stringify(next) !== JSON.stringify(prev)) 104 | sidebar.value = _sidebar.value 105 | }) 106 | const hasSidebar = computed(() => { 107 | return ( 108 | frontmatter.value.sidebar !== false && 109 | sidebar.value.length > 0 && 110 | frontmatter.value.layout !== 'home' 111 | ) 112 | }) 113 | const leftAside = computed(() => { 114 | if (hasAside) 115 | return frontmatter.value.aside == null 116 | ? theme2.value.aside === 'left' 117 | : frontmatter.value.aside === 'left' 118 | return false 119 | }) 120 | const hasAside = computed(() => { 121 | if (frontmatter.value.layout === 'home') return false 122 | if (frontmatter.value.aside != null) return !!frontmatter.value.aside 123 | return theme2.value.aside !== false 124 | }) 125 | const isSidebarEnabled = computed(() => hasSidebar.value && is960.value) 126 | const sidebarGroups = computed(() => { 127 | return hasSidebar.value ? getSidebarGroups(sidebar.value) : [] 128 | }) 129 | function open() { 130 | isOpen.value = true 131 | } 132 | function close() { 133 | isOpen.value = false 134 | } 135 | function toggle() { 136 | isOpen.value ? close() : open() 137 | } 138 | return { 139 | isOpen, 140 | sidebar, 141 | sidebarGroups, 142 | hasSidebar, 143 | hasAside, 144 | leftAside, 145 | isSidebarEnabled, 146 | open, 147 | close, 148 | toggle 149 | } 150 | } 151 | 152 | // node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/composables/local-nav.js 153 | import { onContentUpdated } from 'vitepress' 154 | 155 | // node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/composables/outline.js 156 | import { getScrollOffset } from 'vitepress' 157 | var resolvedHeaders = [] 158 | function getHeaders(range) { 159 | const headers = [ 160 | ...document.querySelectorAll('.VPDoc :where(h1,h2,h3,h4,h5,h6)') 161 | ] 162 | .filter(el => el.id && el.hasChildNodes()) 163 | .map(el => { 164 | const level = Number(el.tagName[1]) 165 | return { 166 | element: el, 167 | title: serializeHeader(el), 168 | link: '#' + el.id, 169 | level 170 | } 171 | }) 172 | return resolveHeaders(headers, range) 173 | } 174 | function serializeHeader(h) { 175 | let ret = '' 176 | for (const node of h.childNodes) { 177 | if (node.nodeType === 1) { 178 | if ( 179 | node.classList.contains('VPBadge') || 180 | node.classList.contains('header-anchor') || 181 | node.classList.contains('ignore-header') 182 | ) { 183 | continue 184 | } 185 | ret += node.textContent 186 | } else if (node.nodeType === 3) { 187 | ret += node.textContent 188 | } 189 | } 190 | return ret.trim() 191 | } 192 | function resolveHeaders(headers, range) { 193 | if (range === false) { 194 | return [] 195 | } 196 | const levelsRange = 197 | (typeof range === 'object' && !Array.isArray(range) 198 | ? range.level 199 | : range) || 2 200 | const [high, low] = 201 | typeof levelsRange === 'number' 202 | ? [levelsRange, levelsRange] 203 | : levelsRange === 'deep' 204 | ? [2, 6] 205 | : levelsRange 206 | return buildTree(headers, high, low) 207 | } 208 | function buildTree(data, min, max) { 209 | resolvedHeaders.length = 0 210 | const result = [] 211 | const stack = [] 212 | data.forEach(item => { 213 | const node = { ...item, children: [] } 214 | let parent = stack[stack.length - 1] 215 | while (parent && parent.level >= node.level) { 216 | stack.pop() 217 | parent = stack[stack.length - 1] 218 | } 219 | if ( 220 | node.element.classList.contains('ignore-header') || 221 | (parent && 'shouldIgnore' in parent) 222 | ) { 223 | stack.push({ level: node.level, shouldIgnore: true }) 224 | return 225 | } 226 | if (node.level > max || node.level < min) return 227 | resolvedHeaders.push({ element: node.element, link: node.link }) 228 | if (parent) parent.children.push(node) 229 | else result.push(node) 230 | stack.push(node) 231 | }) 232 | return result 233 | } 234 | 235 | // node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/composables/local-nav.js 236 | function useLocalNav() { 237 | const { theme: theme2, frontmatter } = useData() 238 | const headers = shallowRef([]) 239 | const hasLocalNav = computed(() => { 240 | return headers.value.length > 0 241 | }) 242 | onContentUpdated(() => { 243 | headers.value = getHeaders( 244 | frontmatter.value.outline ?? theme2.value.outline 245 | ) 246 | }) 247 | return { 248 | headers, 249 | hasLocalNav 250 | } 251 | } 252 | 253 | // node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/without-fonts.js 254 | var theme = { 255 | Layout, 256 | enhanceApp: ({ app }) => { 257 | app.component('Badge', VPBadge) 258 | } 259 | } 260 | var without_fonts_default = theme 261 | export { 262 | default2 as VPBadge, 263 | default4 as VPButton, 264 | default10 as VPDocAsideSponsors, 265 | default5 as VPHomeContent, 266 | default7 as VPHomeFeatures, 267 | default6 as VPHomeHero, 268 | default8 as VPHomeSponsors, 269 | default3 as VPImage, 270 | default9 as VPLink, 271 | default11 as VPSocialLink, 272 | default12 as VPSocialLinks, 273 | default13 as VPSponsors, 274 | default17 as VPTeamMembers, 275 | default14 as VPTeamPage, 276 | default16 as VPTeamPageSection, 277 | default15 as VPTeamPageTitle, 278 | without_fonts_default as default, 279 | useLocalNav, 280 | useSidebar 281 | } 282 | //# sourceMappingURL=@theme_index.js.map 283 | -------------------------------------------------------------------------------- /website/src/.vitepress/cache/deps/_metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "hash": "0c87bf3b", 3 | "configHash": "537ebdcd", 4 | "lockfileHash": "17c814b1", 5 | "browserHash": "7f9e4657", 6 | "optimized": { 7 | "vue": { 8 | "src": "../../../../../node_modules/.pnpm/vue@3.2.45/node_modules/vue/dist/vue.runtime.esm-bundler.js", 9 | "file": "vue.js", 10 | "fileHash": "81e7f501", 11 | "needsInterop": false 12 | }, 13 | "vitepress > @vue/devtools-api": { 14 | "src": "../../../../node_modules/.pnpm/@vue+devtools-api@7.6.1/node_modules/@vue/devtools-api/dist/index.js", 15 | "file": "vitepress___@vue_devtools-api.js", 16 | "fileHash": "f18838d4", 17 | "needsInterop": false 18 | }, 19 | "vitepress > @vueuse/core": { 20 | "src": "../../../../node_modules/.pnpm/@vueuse+core@11.2.0_vue@3.5.12_typescript@5.6.3_/node_modules/@vueuse/core/index.mjs", 21 | "file": "vitepress___@vueuse_core.js", 22 | "fileHash": "005e74d6", 23 | "needsInterop": false 24 | }, 25 | "@theme/index": { 26 | "src": "../../../../node_modules/.pnpm/vitepress@1.4.3_@algolia+client-search@4.24.0_postcss@8.4.47_search-insights@2.17.2_typescript@5.6.3/node_modules/vitepress/dist/client/theme-default/index.js", 27 | "file": "@theme_index.js", 28 | "fileHash": "a7aaf44d", 29 | "needsInterop": false 30 | } 31 | }, 32 | "chunks": { 33 | "chunk-PWVUJGW4": { 34 | "file": "chunk-PWVUJGW4.js" 35 | }, 36 | "chunk-6J5AW4SK": { 37 | "file": "chunk-6J5AW4SK.js" 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /website/src/.vitepress/cache/deps/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module" 3 | } 4 | -------------------------------------------------------------------------------- /website/src/.vitepress/cache/deps/vitepress___@vueuse_core.js: -------------------------------------------------------------------------------- 1 | import { 2 | DefaultMagicKeysAliasMap, 3 | StorageSerializers, 4 | TransitionPresets, 5 | assert, 6 | breakpointsAntDesign, 7 | breakpointsBootstrapV5, 8 | breakpointsElement, 9 | breakpointsMasterCss, 10 | breakpointsPrimeFlex, 11 | breakpointsQuasar, 12 | breakpointsSematic, 13 | breakpointsTailwind, 14 | breakpointsVuetify, 15 | breakpointsVuetifyV2, 16 | breakpointsVuetifyV3, 17 | bypassFilter, 18 | camelize, 19 | clamp, 20 | cloneFnJSON, 21 | computedAsync, 22 | computedEager, 23 | computedInject, 24 | computedWithControl, 25 | containsProp, 26 | controlledRef, 27 | createEventHook, 28 | createFetch, 29 | createFilterWrapper, 30 | createGlobalState, 31 | createInjectionState, 32 | createReusableTemplate, 33 | createSharedComposable, 34 | createSingletonPromise, 35 | createTemplatePromise, 36 | createUnrefFn, 37 | customStorageEventName, 38 | debounceFilter, 39 | defaultDocument, 40 | defaultLocation, 41 | defaultNavigator, 42 | defaultWindow, 43 | directiveHooks, 44 | executeTransition, 45 | extendRef, 46 | formatDate, 47 | formatTimeAgo, 48 | get, 49 | getLifeCycleTarget, 50 | getSSRHandler, 51 | hasOwn, 52 | hyphenate, 53 | identity, 54 | increaseWithUnit, 55 | injectLocal, 56 | invoke, 57 | isClient, 58 | isDef, 59 | isDefined, 60 | isIOS, 61 | isObject, 62 | isWorker, 63 | makeDestructurable, 64 | mapGamepadToXbox360Controller, 65 | noop, 66 | normalizeDate, 67 | notNullish, 68 | now, 69 | objectEntries, 70 | objectOmit, 71 | objectPick, 72 | onClickOutside, 73 | onKeyDown, 74 | onKeyPressed, 75 | onKeyStroke, 76 | onKeyUp, 77 | onLongPress, 78 | onStartTyping, 79 | pausableFilter, 80 | promiseTimeout, 81 | provideLocal, 82 | rand, 83 | reactify, 84 | reactifyObject, 85 | reactiveComputed, 86 | reactiveOmit, 87 | reactivePick, 88 | refAutoReset, 89 | refDebounced, 90 | refDefault, 91 | refThrottled, 92 | refWithControl, 93 | resolveRef, 94 | resolveUnref, 95 | set, 96 | setSSRHandler, 97 | syncRef, 98 | syncRefs, 99 | templateRef, 100 | throttleFilter, 101 | timestamp, 102 | toReactive, 103 | toRef, 104 | toRefs, 105 | toValue, 106 | tryOnBeforeMount, 107 | tryOnBeforeUnmount, 108 | tryOnMounted, 109 | tryOnScopeDispose, 110 | tryOnUnmounted, 111 | unrefElement, 112 | until, 113 | useActiveElement, 114 | useAnimate, 115 | useArrayDifference, 116 | useArrayEvery, 117 | useArrayFilter, 118 | useArrayFind, 119 | useArrayFindIndex, 120 | useArrayFindLast, 121 | useArrayIncludes, 122 | useArrayJoin, 123 | useArrayMap, 124 | useArrayReduce, 125 | useArraySome, 126 | useArrayUnique, 127 | useAsyncQueue, 128 | useAsyncState, 129 | useBase64, 130 | useBattery, 131 | useBluetooth, 132 | useBreakpoints, 133 | useBroadcastChannel, 134 | useBrowserLocation, 135 | useCached, 136 | useClipboard, 137 | useClipboardItems, 138 | useCloned, 139 | useColorMode, 140 | useConfirmDialog, 141 | useCounter, 142 | useCssVar, 143 | useCurrentElement, 144 | useCycleList, 145 | useDark, 146 | useDateFormat, 147 | useDebounceFn, 148 | useDebouncedRefHistory, 149 | useDeviceMotion, 150 | useDeviceOrientation, 151 | useDevicePixelRatio, 152 | useDevicesList, 153 | useDisplayMedia, 154 | useDocumentVisibility, 155 | useDraggable, 156 | useDropZone, 157 | useElementBounding, 158 | useElementByPoint, 159 | useElementHover, 160 | useElementSize, 161 | useElementVisibility, 162 | useEventBus, 163 | useEventListener, 164 | useEventSource, 165 | useEyeDropper, 166 | useFavicon, 167 | useFetch, 168 | useFileDialog, 169 | useFileSystemAccess, 170 | useFocus, 171 | useFocusWithin, 172 | useFps, 173 | useFullscreen, 174 | useGamepad, 175 | useGeolocation, 176 | useIdle, 177 | useImage, 178 | useInfiniteScroll, 179 | useIntersectionObserver, 180 | useInterval, 181 | useIntervalFn, 182 | useKeyModifier, 183 | useLastChanged, 184 | useLocalStorage, 185 | useMagicKeys, 186 | useManualRefHistory, 187 | useMediaControls, 188 | useMediaQuery, 189 | useMemoize, 190 | useMemory, 191 | useMounted, 192 | useMouse, 193 | useMouseInElement, 194 | useMousePressed, 195 | useMutationObserver, 196 | useNavigatorLanguage, 197 | useNetwork, 198 | useNow, 199 | useObjectUrl, 200 | useOffsetPagination, 201 | useOnline, 202 | usePageLeave, 203 | useParallax, 204 | useParentElement, 205 | usePerformanceObserver, 206 | usePermission, 207 | usePointer, 208 | usePointerLock, 209 | usePointerSwipe, 210 | usePreferredColorScheme, 211 | usePreferredContrast, 212 | usePreferredDark, 213 | usePreferredLanguages, 214 | usePreferredReducedMotion, 215 | usePrevious, 216 | useRafFn, 217 | useRefHistory, 218 | useResizeObserver, 219 | useScreenOrientation, 220 | useScreenSafeArea, 221 | useScriptTag, 222 | useScroll, 223 | useScrollLock, 224 | useSessionStorage, 225 | useShare, 226 | useSorted, 227 | useSpeechRecognition, 228 | useSpeechSynthesis, 229 | useStepper, 230 | useStorage, 231 | useStorageAsync, 232 | useStyleTag, 233 | useSupported, 234 | useSwipe, 235 | useTemplateRefsList, 236 | useTextDirection, 237 | useTextSelection, 238 | useTextareaAutosize, 239 | useThrottleFn, 240 | useThrottledRefHistory, 241 | useTimeAgo, 242 | useTimeout, 243 | useTimeoutFn, 244 | useTimeoutPoll, 245 | useTimestamp, 246 | useTitle, 247 | useToNumber, 248 | useToString, 249 | useToggle, 250 | useTransition, 251 | useUrlSearchParams, 252 | useUserMedia, 253 | useVModel, 254 | useVModels, 255 | useVibrate, 256 | useVirtualList, 257 | useWakeLock, 258 | useWebNotification, 259 | useWebSocket, 260 | useWebWorker, 261 | useWebWorkerFn, 262 | useWindowFocus, 263 | useWindowScroll, 264 | useWindowSize, 265 | watchArray, 266 | watchAtMost, 267 | watchDebounced, 268 | watchDeep, 269 | watchIgnorable, 270 | watchImmediate, 271 | watchOnce, 272 | watchPausable, 273 | watchThrottled, 274 | watchTriggerable, 275 | watchWithFilter, 276 | whenever 277 | } from './chunk-PWVUJGW4.js' 278 | import './chunk-6J5AW4SK.js' 279 | export { 280 | DefaultMagicKeysAliasMap, 281 | StorageSerializers, 282 | TransitionPresets, 283 | assert, 284 | computedAsync as asyncComputed, 285 | refAutoReset as autoResetRef, 286 | breakpointsAntDesign, 287 | breakpointsBootstrapV5, 288 | breakpointsElement, 289 | breakpointsMasterCss, 290 | breakpointsPrimeFlex, 291 | breakpointsQuasar, 292 | breakpointsSematic, 293 | breakpointsTailwind, 294 | breakpointsVuetify, 295 | breakpointsVuetifyV2, 296 | breakpointsVuetifyV3, 297 | bypassFilter, 298 | camelize, 299 | clamp, 300 | cloneFnJSON, 301 | computedAsync, 302 | computedEager, 303 | computedInject, 304 | computedWithControl, 305 | containsProp, 306 | computedWithControl as controlledComputed, 307 | controlledRef, 308 | createEventHook, 309 | createFetch, 310 | createFilterWrapper, 311 | createGlobalState, 312 | createInjectionState, 313 | reactify as createReactiveFn, 314 | createReusableTemplate, 315 | createSharedComposable, 316 | createSingletonPromise, 317 | createTemplatePromise, 318 | createUnrefFn, 319 | customStorageEventName, 320 | debounceFilter, 321 | refDebounced as debouncedRef, 322 | watchDebounced as debouncedWatch, 323 | defaultDocument, 324 | defaultLocation, 325 | defaultNavigator, 326 | defaultWindow, 327 | directiveHooks, 328 | computedEager as eagerComputed, 329 | executeTransition, 330 | extendRef, 331 | formatDate, 332 | formatTimeAgo, 333 | get, 334 | getLifeCycleTarget, 335 | getSSRHandler, 336 | hasOwn, 337 | hyphenate, 338 | identity, 339 | watchIgnorable as ignorableWatch, 340 | increaseWithUnit, 341 | injectLocal, 342 | invoke, 343 | isClient, 344 | isDef, 345 | isDefined, 346 | isIOS, 347 | isObject, 348 | isWorker, 349 | makeDestructurable, 350 | mapGamepadToXbox360Controller, 351 | noop, 352 | normalizeDate, 353 | notNullish, 354 | now, 355 | objectEntries, 356 | objectOmit, 357 | objectPick, 358 | onClickOutside, 359 | onKeyDown, 360 | onKeyPressed, 361 | onKeyStroke, 362 | onKeyUp, 363 | onLongPress, 364 | onStartTyping, 365 | pausableFilter, 366 | watchPausable as pausableWatch, 367 | promiseTimeout, 368 | provideLocal, 369 | rand, 370 | reactify, 371 | reactifyObject, 372 | reactiveComputed, 373 | reactiveOmit, 374 | reactivePick, 375 | refAutoReset, 376 | refDebounced, 377 | refDefault, 378 | refThrottled, 379 | refWithControl, 380 | resolveRef, 381 | resolveUnref, 382 | set, 383 | setSSRHandler, 384 | syncRef, 385 | syncRefs, 386 | templateRef, 387 | throttleFilter, 388 | refThrottled as throttledRef, 389 | watchThrottled as throttledWatch, 390 | timestamp, 391 | toReactive, 392 | toRef, 393 | toRefs, 394 | toValue, 395 | tryOnBeforeMount, 396 | tryOnBeforeUnmount, 397 | tryOnMounted, 398 | tryOnScopeDispose, 399 | tryOnUnmounted, 400 | unrefElement, 401 | until, 402 | useActiveElement, 403 | useAnimate, 404 | useArrayDifference, 405 | useArrayEvery, 406 | useArrayFilter, 407 | useArrayFind, 408 | useArrayFindIndex, 409 | useArrayFindLast, 410 | useArrayIncludes, 411 | useArrayJoin, 412 | useArrayMap, 413 | useArrayReduce, 414 | useArraySome, 415 | useArrayUnique, 416 | useAsyncQueue, 417 | useAsyncState, 418 | useBase64, 419 | useBattery, 420 | useBluetooth, 421 | useBreakpoints, 422 | useBroadcastChannel, 423 | useBrowserLocation, 424 | useCached, 425 | useClipboard, 426 | useClipboardItems, 427 | useCloned, 428 | useColorMode, 429 | useConfirmDialog, 430 | useCounter, 431 | useCssVar, 432 | useCurrentElement, 433 | useCycleList, 434 | useDark, 435 | useDateFormat, 436 | refDebounced as useDebounce, 437 | useDebounceFn, 438 | useDebouncedRefHistory, 439 | useDeviceMotion, 440 | useDeviceOrientation, 441 | useDevicePixelRatio, 442 | useDevicesList, 443 | useDisplayMedia, 444 | useDocumentVisibility, 445 | useDraggable, 446 | useDropZone, 447 | useElementBounding, 448 | useElementByPoint, 449 | useElementHover, 450 | useElementSize, 451 | useElementVisibility, 452 | useEventBus, 453 | useEventListener, 454 | useEventSource, 455 | useEyeDropper, 456 | useFavicon, 457 | useFetch, 458 | useFileDialog, 459 | useFileSystemAccess, 460 | useFocus, 461 | useFocusWithin, 462 | useFps, 463 | useFullscreen, 464 | useGamepad, 465 | useGeolocation, 466 | useIdle, 467 | useImage, 468 | useInfiniteScroll, 469 | useIntersectionObserver, 470 | useInterval, 471 | useIntervalFn, 472 | useKeyModifier, 473 | useLastChanged, 474 | useLocalStorage, 475 | useMagicKeys, 476 | useManualRefHistory, 477 | useMediaControls, 478 | useMediaQuery, 479 | useMemoize, 480 | useMemory, 481 | useMounted, 482 | useMouse, 483 | useMouseInElement, 484 | useMousePressed, 485 | useMutationObserver, 486 | useNavigatorLanguage, 487 | useNetwork, 488 | useNow, 489 | useObjectUrl, 490 | useOffsetPagination, 491 | useOnline, 492 | usePageLeave, 493 | useParallax, 494 | useParentElement, 495 | usePerformanceObserver, 496 | usePermission, 497 | usePointer, 498 | usePointerLock, 499 | usePointerSwipe, 500 | usePreferredColorScheme, 501 | usePreferredContrast, 502 | usePreferredDark, 503 | usePreferredLanguages, 504 | usePreferredReducedMotion, 505 | usePrevious, 506 | useRafFn, 507 | useRefHistory, 508 | useResizeObserver, 509 | useScreenOrientation, 510 | useScreenSafeArea, 511 | useScriptTag, 512 | useScroll, 513 | useScrollLock, 514 | useSessionStorage, 515 | useShare, 516 | useSorted, 517 | useSpeechRecognition, 518 | useSpeechSynthesis, 519 | useStepper, 520 | useStorage, 521 | useStorageAsync, 522 | useStyleTag, 523 | useSupported, 524 | useSwipe, 525 | useTemplateRefsList, 526 | useTextDirection, 527 | useTextSelection, 528 | useTextareaAutosize, 529 | refThrottled as useThrottle, 530 | useThrottleFn, 531 | useThrottledRefHistory, 532 | useTimeAgo, 533 | useTimeout, 534 | useTimeoutFn, 535 | useTimeoutPoll, 536 | useTimestamp, 537 | useTitle, 538 | useToNumber, 539 | useToString, 540 | useToggle, 541 | useTransition, 542 | useUrlSearchParams, 543 | useUserMedia, 544 | useVModel, 545 | useVModels, 546 | useVibrate, 547 | useVirtualList, 548 | useWakeLock, 549 | useWebNotification, 550 | useWebSocket, 551 | useWebWorker, 552 | useWebWorkerFn, 553 | useWindowFocus, 554 | useWindowScroll, 555 | useWindowSize, 556 | watchArray, 557 | watchAtMost, 558 | watchDebounced, 559 | watchDeep, 560 | watchIgnorable, 561 | watchImmediate, 562 | watchOnce, 563 | watchPausable, 564 | watchThrottled, 565 | watchTriggerable, 566 | watchWithFilter, 567 | whenever 568 | } 569 | //# sourceMappingURL=vitepress___@vueuse_core.js.map 570 | -------------------------------------------------------------------------------- /website/src/.vitepress/cache/deps/vitepress___@vueuse_core.js.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "sources": [], 4 | "sourcesContent": [], 5 | "mappings": "", 6 | "names": [] 7 | } 8 | -------------------------------------------------------------------------------- /website/src/.vitepress/cache/deps/vue.js: -------------------------------------------------------------------------------- 1 | import { 2 | BaseTransition, 3 | Comment, 4 | EffectScope, 5 | Fragment, 6 | KeepAlive, 7 | ReactiveEffect, 8 | Static, 9 | Suspense, 10 | Teleport, 11 | Text, 12 | Transition, 13 | TransitionGroup, 14 | VueElement, 15 | callWithAsyncErrorHandling, 16 | callWithErrorHandling, 17 | camelize, 18 | capitalize, 19 | cloneVNode, 20 | compatUtils, 21 | compile, 22 | computed, 23 | createApp, 24 | createBaseVNode, 25 | createBlock, 26 | createCommentVNode, 27 | createElementBlock, 28 | createHydrationRenderer, 29 | createPropsRestProxy, 30 | createRenderer, 31 | createSSRApp, 32 | createSlots, 33 | createStaticVNode, 34 | createTextVNode, 35 | createVNode, 36 | customRef, 37 | defineAsyncComponent, 38 | defineComponent, 39 | defineCustomElement, 40 | defineEmits, 41 | defineExpose, 42 | defineProps, 43 | defineSSRCustomElement, 44 | devtools, 45 | effect, 46 | effectScope, 47 | getCurrentInstance, 48 | getCurrentScope, 49 | getTransitionRawChildren, 50 | guardReactiveProps, 51 | h, 52 | handleError, 53 | hydrate, 54 | initCustomFormatter, 55 | initDirectivesForSSR, 56 | inject, 57 | isMemoSame, 58 | isProxy, 59 | isReactive, 60 | isReadonly, 61 | isRef, 62 | isRuntimeOnly, 63 | isShallow, 64 | isVNode, 65 | markRaw, 66 | mergeDefaults, 67 | mergeProps, 68 | nextTick, 69 | normalizeClass, 70 | normalizeProps, 71 | normalizeStyle, 72 | onActivated, 73 | onBeforeMount, 74 | onBeforeUnmount, 75 | onBeforeUpdate, 76 | onDeactivated, 77 | onErrorCaptured, 78 | onMounted, 79 | onRenderTracked, 80 | onRenderTriggered, 81 | onScopeDispose, 82 | onServerPrefetch, 83 | onUnmounted, 84 | onUpdated, 85 | openBlock, 86 | popScopeId, 87 | provide, 88 | proxyRefs, 89 | pushScopeId, 90 | queuePostFlushCb, 91 | reactive, 92 | readonly, 93 | ref, 94 | registerRuntimeCompiler, 95 | render, 96 | renderList, 97 | renderSlot, 98 | resolveComponent, 99 | resolveDirective, 100 | resolveDynamicComponent, 101 | resolveFilter, 102 | resolveTransitionHooks, 103 | setBlockTracking, 104 | setDevtoolsHook, 105 | setTransitionHooks, 106 | shallowReactive, 107 | shallowReadonly, 108 | shallowRef, 109 | ssrContextKey, 110 | ssrUtils, 111 | stop, 112 | toDisplayString, 113 | toHandlerKey, 114 | toHandlers, 115 | toRaw, 116 | toRef, 117 | toRefs, 118 | transformVNodeArgs, 119 | triggerRef, 120 | unref, 121 | useAttrs, 122 | useCssModule, 123 | useCssVars, 124 | useSSRContext, 125 | useSlots, 126 | useTransitionState, 127 | vModelCheckbox, 128 | vModelDynamic, 129 | vModelRadio, 130 | vModelSelect, 131 | vModelText, 132 | vShow, 133 | version, 134 | warn, 135 | watch, 136 | watchEffect, 137 | watchPostEffect, 138 | watchSyncEffect, 139 | withAsyncContext, 140 | withCtx, 141 | withDefaults, 142 | withDirectives, 143 | withKeys, 144 | withMemo, 145 | withModifiers, 146 | withScopeId 147 | } from './chunk-6J5AW4SK.js' 148 | export { 149 | BaseTransition, 150 | Comment, 151 | EffectScope, 152 | Fragment, 153 | KeepAlive, 154 | ReactiveEffect, 155 | Static, 156 | Suspense, 157 | Teleport, 158 | Text, 159 | Transition, 160 | TransitionGroup, 161 | VueElement, 162 | callWithAsyncErrorHandling, 163 | callWithErrorHandling, 164 | camelize, 165 | capitalize, 166 | cloneVNode, 167 | compatUtils, 168 | compile, 169 | computed, 170 | createApp, 171 | createBlock, 172 | createCommentVNode, 173 | createElementBlock, 174 | createBaseVNode as createElementVNode, 175 | createHydrationRenderer, 176 | createPropsRestProxy, 177 | createRenderer, 178 | createSSRApp, 179 | createSlots, 180 | createStaticVNode, 181 | createTextVNode, 182 | createVNode, 183 | customRef, 184 | defineAsyncComponent, 185 | defineComponent, 186 | defineCustomElement, 187 | defineEmits, 188 | defineExpose, 189 | defineProps, 190 | defineSSRCustomElement, 191 | devtools, 192 | effect, 193 | effectScope, 194 | getCurrentInstance, 195 | getCurrentScope, 196 | getTransitionRawChildren, 197 | guardReactiveProps, 198 | h, 199 | handleError, 200 | hydrate, 201 | initCustomFormatter, 202 | initDirectivesForSSR, 203 | inject, 204 | isMemoSame, 205 | isProxy, 206 | isReactive, 207 | isReadonly, 208 | isRef, 209 | isRuntimeOnly, 210 | isShallow, 211 | isVNode, 212 | markRaw, 213 | mergeDefaults, 214 | mergeProps, 215 | nextTick, 216 | normalizeClass, 217 | normalizeProps, 218 | normalizeStyle, 219 | onActivated, 220 | onBeforeMount, 221 | onBeforeUnmount, 222 | onBeforeUpdate, 223 | onDeactivated, 224 | onErrorCaptured, 225 | onMounted, 226 | onRenderTracked, 227 | onRenderTriggered, 228 | onScopeDispose, 229 | onServerPrefetch, 230 | onUnmounted, 231 | onUpdated, 232 | openBlock, 233 | popScopeId, 234 | provide, 235 | proxyRefs, 236 | pushScopeId, 237 | queuePostFlushCb, 238 | reactive, 239 | readonly, 240 | ref, 241 | registerRuntimeCompiler, 242 | render, 243 | renderList, 244 | renderSlot, 245 | resolveComponent, 246 | resolveDirective, 247 | resolveDynamicComponent, 248 | resolveFilter, 249 | resolveTransitionHooks, 250 | setBlockTracking, 251 | setDevtoolsHook, 252 | setTransitionHooks, 253 | shallowReactive, 254 | shallowReadonly, 255 | shallowRef, 256 | ssrContextKey, 257 | ssrUtils, 258 | stop, 259 | toDisplayString, 260 | toHandlerKey, 261 | toHandlers, 262 | toRaw, 263 | toRef, 264 | toRefs, 265 | transformVNodeArgs, 266 | triggerRef, 267 | unref, 268 | useAttrs, 269 | useCssModule, 270 | useCssVars, 271 | useSSRContext, 272 | useSlots, 273 | useTransitionState, 274 | vModelCheckbox, 275 | vModelDynamic, 276 | vModelRadio, 277 | vModelSelect, 278 | vModelText, 279 | vShow, 280 | version, 281 | warn, 282 | watch, 283 | watchEffect, 284 | watchPostEffect, 285 | watchSyncEffect, 286 | withAsyncContext, 287 | withCtx, 288 | withDefaults, 289 | withDirectives, 290 | withKeys, 291 | withMemo, 292 | withModifiers, 293 | withScopeId 294 | } 295 | //# sourceMappingURL=vue.js.map 296 | -------------------------------------------------------------------------------- /website/src/.vitepress/cache/deps/vue.js.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "sources": [], 4 | "sourcesContent": [], 5 | "mappings": "", 6 | "names": [] 7 | } 8 | -------------------------------------------------------------------------------- /website/src/.vitepress/config.mts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitepress' 2 | 3 | export default defineConfig({ 4 | lastUpdated: true, 5 | 6 | themeConfig: { 7 | editLink: { 8 | pattern: 9 | 'https://github.com/apertureless/vue-chartjs/edit/main/website/src/:path' 10 | }, 11 | search: { 12 | provider: 'algolia', 13 | options: { 14 | indexName: 'vue-chartjs', 15 | apiKey: 'a1bb4528e8ed1eb89e40d6e4c1000514', 16 | appId: '24VA3R3NCC' 17 | } 18 | }, 19 | 20 | nav: [ 21 | { text: 'Guide', link: '/guide/', activeMatch: '^/guide/' }, 22 | { 23 | text: 'Migration guides', 24 | link: '/migration-guides/', 25 | activeMatch: '^/migration-guides/' 26 | }, 27 | { 28 | text: 'API', 29 | link: '/api/', 30 | activeMatch: '^/api/' 31 | }, 32 | { 33 | text: 'Examples', 34 | link: '/examples/', 35 | activeMatch: '^/examples/' 36 | }, 37 | { 38 | text: 'Stack Overflow', 39 | link: 'https://stackoverflow.com/questions/tagged/vue-chartjs/' 40 | }, 41 | { 42 | text: 'Github', 43 | link: 'https://github.com/apertureless/vue-chartjs' 44 | } 45 | ], 46 | 47 | sidebar: [ 48 | { 49 | text: 'Introduction', 50 | items: [ 51 | { text: 'Getting started', link: '/guide' }, 52 | { text: 'Examples', link: '/guide/examples' } 53 | ] 54 | }, 55 | { 56 | text: 'Migration', 57 | items: [ 58 | { text: 'Introduction', link: '/migration-guides/' }, 59 | { text: 'Migrate to v5', link: '/migration-guides/v5' }, 60 | { text: 'Migrate to v4', link: '/migration-guides/v4' }, 61 | { 62 | text: 'Migrate from vue-chart-3', 63 | link: '/migration-guides/vue-chart-3' 64 | } 65 | ] 66 | } 67 | ], 68 | footer: { 69 | message: 'Released under the MIT License.', 70 | copyright: 'Copyright © 2019-present Jakub Juszczak' 71 | } 72 | }, 73 | 74 | locales: { 75 | root: { 76 | label: 'English', 77 | lang: 'en-US', 78 | title: '📈 vue-chartjs', 79 | description: '⚡ Easy and beautiful charts with Chart.js and Vue.js' 80 | }, 81 | de: { 82 | label: 'Deutsch', 83 | lang: 'de', 84 | link: '/de/', 85 | title: '📈 vue-chartjs', 86 | description: '⚡Einfache und schöne Diagramme mit Chart.js und Vue.js' 87 | } 88 | } 89 | }) 90 | -------------------------------------------------------------------------------- /website/src/CNAME: -------------------------------------------------------------------------------- 1 | vue-chartjs.org 2 | -------------------------------------------------------------------------------- /website/src/api/index.md: -------------------------------------------------------------------------------- 1 | # Coding Reference 2 | 3 | ## Props 4 | 5 | Some basic props are defined in the components provided by `vue-chartjs`. 6 | 7 | | Prop | Description | 8 | |---|---| 9 | | data | Data object that is passed into the Chart.js chart | 10 | | options | Options object that is passed into the Chart.js chart | 11 | | datasetIdKey | Key name to identify the dataset | 12 | | plugins | Plugins array that is passed into the Chart.js chart | 13 | | updateMode | Mode string to indicate the transition configuration to be used. | 14 | | ariaLabel | An [ARIA label](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-label) that describes the chart to make it accessible. | 15 | | ariaDescribedby | A reference to the [describing element](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-describedby). E. g. a table representation of the data. | 16 | 17 | The rest of the props will fall through to the canvas element. 18 | 19 | ## Global Methods 20 | 21 | Global Methods need to be imported. 22 | 23 | ### createTypedChart 24 | 25 | - **Type:** `Function` 26 | - **Arguments**:`chart-type`, `chart-controller` 27 | - **Usage:** 28 | 29 | ```js 30 | import { createTypedChart } from 'vue-chartjs' 31 | import { LineController } from 'chart.js' 32 | 33 | const CustomLine = createTypedChart('line', LineController) 34 | ``` 35 | -------------------------------------------------------------------------------- /website/src/de/api/index.md: -------------------------------------------------------------------------------- 1 | # Coding Reference 2 | 3 | ## Props 4 | 5 | Some basic props are defined in the components provided by `vue-chartjs`. 6 | 7 | | Prop | Description | 8 | |---|---| 9 | | data | Data object that is passed into the Chart.js chart | 10 | | options | Options object that is passed into the Chart.js chart | 11 | | datasetIdKey | Key name to identify the dataset | 12 | | plugins | Plugins array that is passed into the Chart.js chart | 13 | | updateMode | Mode string to indicate the transition configuration to be used. | 14 | | ariaLabel | An [ARIA label](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-label) that describes the chart to make it accessible. | 15 | | ariaDescribedby | A reference to the [describing element](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-describedby). E. g. a table representation of the data. | 16 | 17 | The rest of the props will fall through to the canvas element. 18 | 19 | ## Global Methods 20 | 21 | Global Methods need to be imported. 22 | 23 | ### createTypedChart 24 | 25 | - **Type:** `Function` 26 | - **Arguments**:`chart-type`, `chart-controller` 27 | - **Usage:** 28 | 29 | ```js 30 | import { createTypedChart } from 'vue-chartjs' 31 | import { LineController } from 'chart.js' 32 | 33 | const CustomLine = createTypedChart('line', LineController) 34 | ``` 35 | -------------------------------------------------------------------------------- /website/src/de/examples/index.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | ## Vue 3 charts 4 | 5 | - [Bar](https://stackblitz.com/github/apertureless/vue-chartjs/tree/main/sandboxes/bar) 6 | - [Bubble](https://stackblitz.com/github/apertureless/vue-chartjs/tree/main/sandboxes/bubble) 7 | - [Doughnut](https://stackblitz.com/github/apertureless/vue-chartjs/tree/main/sandboxes/doughnut) 8 | - [Line](https://stackblitz.com/github/apertureless/vue-chartjs/tree/main/sandboxes/line) 9 | - [Pie](https://stackblitz.com/github/apertureless/vue-chartjs/tree/main/sandboxes/pie) 10 | - [PolarArea](https://stackblitz.com/github/apertureless/vue-chartjs/tree/main/sandboxes/polar-area) 11 | - [Radar](https://stackblitz.com/github/apertureless/vue-chartjs/tree/main/sandboxes/radar) 12 | - [Scatter](https://stackblitz.com/github/apertureless/vue-chartjs/tree/main/sandboxes/scatter) 13 | - [Bar with reactive data](https://stackblitz.com/github/apertureless/vue-chartjs/tree/main/sandboxes/reactive) 14 | - [Custom chart](https://stackblitz.com/github/apertureless/vue-chartjs/tree/main/sandboxes/custom) 15 | - [Events](https://stackblitz.com/github/apertureless/vue-chartjs/tree/main/sandboxes/events) 16 | 17 | ## Vue 2 charts (vue-chartjs v4) 18 | 19 | - [Bar](https://codesandbox.io/s/github/apertureless/vue-chartjs/tree/v4/legacy/sandboxes/bar) 20 | - [Bubble](https://codesandbox.io/s/github/apertureless/vue-chartjs/tree/v4/legacy/sandboxes/bubble) 21 | - [Doughnut](https://codesandbox.io/s/github/apertureless/vue-chartjs/tree/v4/legacy/sandboxes/doughnut) 22 | - [Line](https://codesandbox.io/s/github/apertureless/vue-chartjs/tree/v4/legacy/sandboxes/line) 23 | - [Pie](https://codesandbox.io/s/github/apertureless/vue-chartjs/tree/v4/legacy/sandboxes/pie) 24 | - [PolarArea](https://codesandbox.io/s/github/apertureless/vue-chartjs/tree/v4/legacy/sandboxes/polar-area) 25 | - [Radar](https://codesandbox.io/s/github/apertureless/vue-chartjs/tree/v4/legacy/sandboxes/radar) 26 | - [Scatter](https://codesandbox.io/s/github/apertureless/vue-chartjs/tree/v4/legacy/sandboxes/scatter) 27 | -------------------------------------------------------------------------------- /website/src/de/guide/examples.md: -------------------------------------------------------------------------------- 1 | 2 | # Examples 3 | 4 | ## Chart with props 5 | 6 | Your goal should be to create reusable chart components. For this purpose, you should utilize Vue.js props to pass in chart options and chart data. This way, the parent component itself does not hold an opinion about fetching data and is only for presentation. 7 | 8 | ```vue 9 | 12 | 13 | 34 | ``` 35 | 36 | ## Chart with local data 37 | 38 | You can handle your chart data directly in your parent component. 39 | 40 | ```vue 41 | 44 | 45 | 70 | ``` 71 | 72 | ## Chart with API data 73 | 74 | A common pattern is to use an API to retrieve your data. However, there are some things to keep in mind. The most common problem is that you mount your chart component directly and pass in data from an asynchronous API call. The problem with this approach is that Chart.js tries to render your chart and access the chart data synchronously, so your chart mounts before the API data arrives. 75 | 76 | To prevent this, a simple `v-if` is the best solution. 77 | 78 | Create your chart component with a data prop and options prop, so we can pass in our data and options from a container component. 79 | 80 | ```vue 81 | 86 | 87 | 114 | ``` 115 | 116 | ## Chart with dynamic styles 117 | 118 | You can set `responsive: true` and pass in a styles object which gets applied as inline styles to the outer `
`. This way, you can change the height and width of the outer container dynamically, which is not the default behaviour of Chart.js. It is best to use computed properties for this. 119 | 120 | ::: warning 121 | You need to set `position: relative` 122 | ::: 123 | 124 | ```vue 125 | 130 | 131 | 150 | ``` 151 | 152 | ## Custom / New Charts 153 | 154 | Sometimes you need to extend the default Chart.js charts. There are a lot of [examples](http://www.chartjs.org/docs/latest/developers/charts.html) on how to extend and modify the default charts. Or, you can create your own chart type. 155 | 156 | In `vue-chartjs`, you can do this pretty much the same way: 157 | 158 | ```js 159 | // 1. Import Chart.js so you can use the global Chart object 160 | import { Chart } from 'chart.js' 161 | // 2. Import the `createTypedChart()` method to create the vue component. 162 | import { createTypedChart } from 'vue-chartjs' 163 | // 3. Import needed controller from Chart.js 164 | import { LineController } from 'chart.js' 165 | 166 | // 3. Extend one of the default charts 167 | // http://www.chartjs.org/docs/latest/developers/charts.html 168 | class LineWithLineController extends LineController { /* custom magic here */} 169 | 170 | // 4. Generate the vue-chartjs component 171 | // The first argument is the chart-id, the second the chart type, third is the custom controller 172 | const CustomLine = createTypedChart('line', LineWithLineController) 173 | 174 | // 5. Extend the CustomLine Component just like you do with the default vue-chartjs charts. 175 | 176 | export default { 177 | components: { CustomLine } 178 | } 179 | ``` 180 | 181 | ## Resources 182 | 183 | Here are some resources, such as tutorials, on how to use `vue-chartjs`: 184 | 185 | - [Using vue-chartjs with WordPress](https://medium.com/@apertureless/wordpress-vue-and-chart-js-6b61493e289f) 186 | - [Create stunning Charts with Vue and Chart.js](https://hackernoon.com/creating-stunning-charts-with-vue-js-and-chart-js-28af584adc0a) 187 | - [Let’s Build a Web App with Vue, Chart.js and an API Part I](https://hackernoon.com/lets-build-a-web-app-with-vue-chart-js-and-an-api-544eb81c4b44) 188 | - [Let’s Build a Web App with Vue, Chart.js and an API Part II](https://hackernoon.com/lets-build-a-web-app-with-vue-chart-js-and-an-api-part-ii-39781b1d5acf) 189 | - [Build a realtime chart with VueJS and Pusher](https://blog.pusher.com/build-realtime-chart-with-vuejs-pusher/) 190 | -------------------------------------------------------------------------------- /website/src/de/guide/index.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | **vue-chartjs** is a wrapper for [Chart.js](https://github.com/chartjs/Chart.js) in Vue. You can easily create reuseable chart components. 4 | 5 | Supports Chart.js v4. 6 | 7 | ## Introduction 8 | 9 | `vue-chartjs` lets you use Chart.js without much hassle inside Vue. It's perfect for people who need simple charts up and running as fast as possible. 10 | 11 | It abstracts the basic logic but exposes the Chart.js object to give you maximal flexibility. 12 | 13 | :::tip Need an API to fetch data? 14 | Please consider [Cube](https://cube.dev/?ref=eco-vue-chartjs), an open-source API for data apps. 15 | ::: 16 | 17 | ## Installation 18 | 19 | You can install `vue-chartjs` over `yarn` or `npm` or `pnpm`. However, you also need to add `chart.js` as a dependency to your project because `Chart.js` is a peerDependency. This way you can have full control over the versioning of `Chart.js`. 20 | 21 | ```bash 22 | pnpm add vue-chartjs chart.js 23 | # or 24 | yarn add vue-chartjs chart.js 25 | # or 26 | npm i vue-chartjs chart.js 27 | ``` 28 | 29 | ## Integration 30 | 31 | Every chart type that is available in Chart.js is exported as a named component and can be imported as such. These components are normal Vue components. 32 | 33 | The idea behind vue-chartjs is to provide easy-to-use components, with maximal flexibility and extensibility. 34 | 35 | ## Creating your first Chart 36 | 37 | First, you need to import the base chart. 38 | 39 | ```javascript 40 | import { Bar } from 'vue-chartjs' 41 | ``` 42 | 43 | Check out the official [Chart.js docs](http://www.chartjs.org/docs/latest/#creating-a-chart) to see the object structure you need to provide. 44 | 45 | Just create your own component. 46 | 47 | **BarChart.vue** 48 | 49 | ```vue 50 | 57 | 58 | 80 | ``` 81 | 82 | Use it in your vue app: 83 | 84 | **App.vue** 85 | 86 | ```vue 87 | 90 | 91 | 99 | ``` 100 | 101 | ## Updating Charts 102 | 103 | Since v4 charts have data change watcher and options change watcher by default. Wrapper will update or re-render the chart if new data or new options is passed. Mixins have been removed. 104 | 105 | ```vue 106 | 109 | 110 | 126 | ``` 127 | 128 | You may get Vue's `Target is readonly` warnings when you are updating your `chartData`. 129 | 130 | If your `chartData` is a `read-only` reactive value, you can override this warning by using a clone: 131 | 132 | ```vue 133 | 136 | ``` 137 | 138 | Unless you have a writable computed `chartData`, you won't be able to use the newer `structuredClone`, as you'll likely hit the `Write operation failed: computed value is readonly` error. 139 | 140 | You don't need to use a clone if your `chartData` is a [writable computed value](https://vuejs.org/guide/essentials/computed#writable-computed). 141 | 142 | 143 | 144 | ## Access to Chart instance 145 | 146 | You can get access to chart instance via template refs. 147 | 148 | ```vue 149 | 152 | ``` 153 | 154 | In Vue3 projects: 155 | 156 | ```javascript 157 | const chartInstance = this.$refs.bar.chart 158 | ``` 159 | 160 | ## Accessibility 161 | 162 | To make your charts accessible to all users, you should label your charts. 163 | Please refer also to the official [Chart.js Accessibility notes](https://www.chartjs.org/docs/latest/general/accessibility.html). 164 | 165 | ### `aria-label` 166 | 167 | You can directly label a chart by passing an `aria-label` prop. 168 | 169 | ```vue 170 | 173 | ``` 174 | 175 | ### `aria-describedby` 176 | 177 | You can reference to a describing element such as a table which describes the data by using the `aria-describedby` property. 178 | 179 | ```vue 180 | 200 | ``` 201 | 202 | ### Fallback-Content 203 | 204 | In case the Browser is not able to render the `canvas` element, you should consider providing fallback content by using the Slot of each component. 205 | 206 | ```vue 207 | 210 | ``` 211 | -------------------------------------------------------------------------------- /website/src/de/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: home 3 | hero: 4 | name: 📈 vue-chartjs 5 | tagline: ⚡ Einfache und schöne Diagramme mit Chart.js und Vue.js 6 | actions: 7 | - theme: brand 8 | text: Get Started → 9 | link: /guide/ 10 | features: 11 | - icon: 🙌 12 | title: Einfach 13 | details: Einfach für beginner sowie fortgeschrittene 14 | - icon: 💪 15 | title: Erweiterbar 16 | details: Simple to use, easy to extend 17 | - icon: 💯 18 | title: Mächtig 19 | details: With the full power of chart.js 💯 20 | --- 21 | -------------------------------------------------------------------------------- /website/src/de/migration-guides/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: doc 3 | --- 4 | 5 | # Migration 6 | 7 | Over the time `vue-chartjs` has changed a lot. As the web and frontend technology has changed. 8 | To keep up with the speed of evolution we have iterated and changed a lot. For a smooth transition between version please check the migration guides. 9 | 10 | 11 | - [v4 -> v5](/migration-guides/v5) 12 | - [v3 -> v4](/migration-guides/v4) 13 | - [vue-chart-3](/migration-guides/vue-chart-3) 14 | -------------------------------------------------------------------------------- /website/src/de/migration-guides/v4.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: doc 3 | --- 4 | # Migration from v3 to v4 5 | 6 | With v4, this library introduces a number of breaking changes. In order to improve performance, offer new features, and improve maintainability, it was necessary to break backwards compatibility, but we aimed to do so only when worth the benefit. 7 | 8 | v4 is fully compatible with Chart.js v3. 9 | 10 | ## Tree-shaking 11 | 12 | v4 of this library, [just like Chart.js v3](https://www.chartjs.org/docs/latest/getting-started/v3-migration.html#setup-and-installation), is tree-shakable. It means that you need to import and register the controllers, elements, scales, and plugins you want to use. 13 | 14 | For a list of all the available items to import, see [Chart.js docs](https://www.chartjs.org/docs/latest/getting-started/integration.html#bundlers-webpack-rollup-etc). 15 | 16 | v3: 17 | 18 | ```javascript 19 | import { Bar } from 'vue-chartjs' 20 | ``` 21 | 22 | v4 — lazy way: 23 | 24 | ```javascript 25 | import 'chart.js/auto'; 26 | import { Bar } from 'vue-chartjs' 27 | ``` 28 | 29 | v4 — tree-shakable way: 30 | 31 | ```javascript 32 | import { Bar } from 'vue-chartjs' 33 | import { Chart as ChartJS, Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale } from 'chart.js' 34 | 35 | ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale) 36 | ``` 37 | 38 | Using the "lazy way" is okay to simplify the migration, but please consider using the tree-shakable way to decrease the bundle size. 39 | 40 | Please note that typed chart components register their controllers by default, so you don't need to register them by yourself. For example, when using the Pie component, you don't need to register PieController explicitly. 41 | 42 | ```javascript 43 | import { Pie } from 'vue-chartjs' 44 | import { Chart as ChartJS, Title, Tooltip, Legend, ArcElement, CategoryScale } from 'chart.js' 45 | 46 | ChartJS.register(Title, Tooltip, Legend, ArcElement, CategoryScale) 47 | ``` 48 | 49 | ## Changing the creation of Charts 50 | 51 | In v3, you needed to import the component, and then either use extends or mixins and add it. 52 | 53 | v3: 54 | 55 | ```javascript 56 | // BarChart.js 57 | import { Bar } from 'vue-chartjs' 58 | 59 | export default { 60 | extends: Bar, 61 | mounted () { 62 | // Overwriting base render method with actual data. 63 | this.renderChart({ 64 | labels: ['January', 'February', 'March'], 65 | datasets: [ 66 | { 67 | label: 'GitHub Commits', 68 | backgroundColor: '#f87979', 69 | data: [40, 20, 12] 70 | } 71 | ] 72 | }) 73 | } 74 | } 75 | ``` 76 | 77 | ```vue 78 | 81 | 82 | 90 | ``` 91 | 92 | In v4, you need to import the component, pass props to it, and use Chart component as a standard Vue component. 93 | 94 | ```vue 95 | 98 | 99 | 125 | ``` 126 | 127 | ## New reactivity system 128 | 129 | v3 does not update or re-render the chart if new data is passed. You needed to use `reactiveProp` and `reactiveData` mixins for that. 130 | 131 | v3: 132 | 133 | ```javascript 134 | import { Line, mixins } from 'vue-chartjs' 135 | 136 | export default { 137 | extends: Line, 138 | mixins: [mixins.reactiveProp], 139 | props: ['chartData', 'options'], 140 | mounted () { 141 | this.renderChart(this.chartData, this.options) 142 | } 143 | } 144 | ``` 145 | 146 | v4 charts have data change watcher by default. v4 will update or re-render the chart if new data is passed. Mixins have been removed. 147 | 148 | v4: 149 | 150 | ```vue 151 | 154 | 155 | 170 | ``` 171 | -------------------------------------------------------------------------------- /website/src/de/migration-guides/v5.md: -------------------------------------------------------------------------------- 1 | # Migration from v4 to v5 2 | 3 | With v5, this library introduces a number of breaking changes 4 | 5 | ## ESM 6 | 7 | ### v5.0 8 | 9 | Chart.js v4 and vue-chartjs v5 are [ESM-only packages](https://nodejs.org/api/esm.html). To use them in your project, it also should be ESM: 10 | 11 | ```json 12 | // package.json 13 | { 14 | "type": "module" 15 | } 16 | ``` 17 | 18 | If you are experiencing this problem with Jest, you should follow [this doc](https://jestjs.io/docs/ecmascript-modules) to enable ESM support. Or, we can recommend you migrate to [Vitest](https://vitest.dev/). Vitest has ESM support out of the box and [has almost the same API as Jest](https://vitest.dev/guide/migration.html#migrating-from-jest). [Here is our example of migration](https://github.com/reactchartjs/react-chartjs-2/commit/7f3ec96101d21e43cae8cbfe5e09a46a17cff1ef). 19 | 20 | 21 | ### v5.1 22 | 23 | Chart.js v4.1 and vue-chartjs v5.1 have restored the CommonJS support. 24 | 25 | ## API changes 26 | 27 | - `chartData` props were renamed to `data` 28 | - `chartOptions` props were renamed to `options` 29 | - unknown props will fall through to the canvas element. 30 | - `generateChart` were refactored and renamed to `createTypedChart` 31 | - Vue.js < 2.7 is no longer supported. If you want to use vue-chartjs with Vue < 2.7 you have to lock your version to 4.x. 32 | -------------------------------------------------------------------------------- /website/src/de/migration-guides/vue-chart-3.md: -------------------------------------------------------------------------------- 1 | 2 | # Migration from vue-chart-3 3 | 4 | ## Uninstall vue-chart-3 5 | 6 | ```bash 7 | pnpm rm vue-chart-3 8 | # or 9 | yarn remove vue-chart-3 10 | # or 11 | npm uninstall vue-chart-3 12 | ``` 13 | 14 | ## Install vue-chartjs 15 | 16 | ```bash 17 | pnpm add vue-chartjs 18 | # or 19 | yarn add vue-chartjs 20 | # or 21 | npm i vue-chartjs 22 | ``` 23 | 24 | ## Change component import path 25 | 26 | For Vue 2.7 and Vue 3 projects: 27 | 28 | ```javascript 29 | import { /* component */ } from 'vue-chartjs' 30 | ``` 31 | 32 | For Vue 2 (<2.7) projects: 33 | 34 | ```javascript 35 | import { /* component */ } from 'vue-chartjs/legacy' 36 | ``` 37 | 38 | ## Rename components 39 | 40 | - BarChart to Bar 41 | - DoughnutChart to Doughnut 42 | - LineChart to Line 43 | - PieChart to Pie 44 | - PolarAreaChart to PolarArea 45 | - RadarChart to Radar 46 | - BubbleChart to Bubble 47 | - ScatterChart to Scatter 48 | 49 | ## Rename props 50 | 51 | - options to chartOptions 52 | -------------------------------------------------------------------------------- /website/src/examples/index.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | ## Vue 3 charts 4 | 5 | - [Bar](https://stackblitz.com/github/apertureless/vue-chartjs/tree/main/sandboxes/bar) 6 | - [Bubble](https://stackblitz.com/github/apertureless/vue-chartjs/tree/main/sandboxes/bubble) 7 | - [Doughnut](https://stackblitz.com/github/apertureless/vue-chartjs/tree/main/sandboxes/doughnut) 8 | - [Line](https://stackblitz.com/github/apertureless/vue-chartjs/tree/main/sandboxes/line) 9 | - [Pie](https://stackblitz.com/github/apertureless/vue-chartjs/tree/main/sandboxes/pie) 10 | - [PolarArea](https://stackblitz.com/github/apertureless/vue-chartjs/tree/main/sandboxes/polar-area) 11 | - [Radar](https://stackblitz.com/github/apertureless/vue-chartjs/tree/main/sandboxes/radar) 12 | - [Scatter](https://stackblitz.com/github/apertureless/vue-chartjs/tree/main/sandboxes/scatter) 13 | - [Bar with reactive data](https://stackblitz.com/github/apertureless/vue-chartjs/tree/main/sandboxes/reactive) 14 | - [Custom chart](https://stackblitz.com/github/apertureless/vue-chartjs/tree/main/sandboxes/custom) 15 | - [Events](https://stackblitz.com/github/apertureless/vue-chartjs/tree/main/sandboxes/events) 16 | 17 | ## Vue 2 charts (vue-chartjs v4) 18 | 19 | - [Bar](https://codesandbox.io/s/github/apertureless/vue-chartjs/tree/v4/legacy/sandboxes/bar) 20 | - [Bubble](https://codesandbox.io/s/github/apertureless/vue-chartjs/tree/v4/legacy/sandboxes/bubble) 21 | - [Doughnut](https://codesandbox.io/s/github/apertureless/vue-chartjs/tree/v4/legacy/sandboxes/doughnut) 22 | - [Line](https://codesandbox.io/s/github/apertureless/vue-chartjs/tree/v4/legacy/sandboxes/line) 23 | - [Pie](https://codesandbox.io/s/github/apertureless/vue-chartjs/tree/v4/legacy/sandboxes/pie) 24 | - [PolarArea](https://codesandbox.io/s/github/apertureless/vue-chartjs/tree/v4/legacy/sandboxes/polar-area) 25 | - [Radar](https://codesandbox.io/s/github/apertureless/vue-chartjs/tree/v4/legacy/sandboxes/radar) 26 | - [Scatter](https://codesandbox.io/s/github/apertureless/vue-chartjs/tree/v4/legacy/sandboxes/scatter) 27 | -------------------------------------------------------------------------------- /website/src/guide/examples.md: -------------------------------------------------------------------------------- 1 | 2 | # Examples 3 | 4 | ## Chart with props 5 | 6 | Your goal should be to create reusable chart components. For this purpose, you should utilize Vue.js props to pass in chart options and chart data. This way, the parent component itself does not hold an opinion about fetching data and is only for presentation. 7 | 8 | ```vue 9 | 12 | 13 | 34 | ``` 35 | 36 | ## Chart with local data 37 | 38 | You can handle your chart data directly in your parent component. 39 | 40 | ```vue 41 | 44 | 45 | 70 | ``` 71 | 72 | ## Chart with API data 73 | 74 | A common pattern is to use an API to retrieve your data. However, there are some things to keep in mind. The most common problem is that you mount your chart component directly and pass in data from an asynchronous API call. The problem with this approach is that Chart.js tries to render your chart and access the chart data synchronously, so your chart mounts before the API data arrives. 75 | 76 | To prevent this, a simple `v-if` is the best solution. 77 | 78 | Create your chart component with a data prop and options prop, so we can pass in our data and options from a container component. 79 | 80 | ```vue 81 | 86 | 87 | 114 | ``` 115 | 116 | ## Chart with dynamic styles 117 | 118 | You can set `responsive: true` and pass in a styles object which gets applied as inline styles to the outer `
`. This way, you can change the height and width of the outer container dynamically, which is not the default behaviour of Chart.js. It is best to use computed properties for this. 119 | 120 | ::: warning 121 | You need to set `position: relative` 122 | ::: 123 | 124 | ```vue 125 | 130 | 131 | 150 | ``` 151 | 152 | ## Custom / New Charts 153 | 154 | Sometimes you need to extend the default Chart.js charts. There are a lot of [examples](http://www.chartjs.org/docs/latest/developers/charts.html) on how to extend and modify the default charts. Or, you can create your own chart type. 155 | 156 | In `vue-chartjs`, you can do this pretty much the same way: 157 | 158 | ```js 159 | // 1. Import Chart.js so you can use the global Chart object 160 | import { Chart } from 'chart.js' 161 | // 2. Import the `createTypedChart()` method to create the vue component. 162 | import { createTypedChart } from 'vue-chartjs' 163 | // 3. Import needed controller from Chart.js 164 | import { LineController } from 'chart.js' 165 | 166 | // 3. Extend one of the default charts 167 | // http://www.chartjs.org/docs/latest/developers/charts.html 168 | class LineWithLineController extends LineController { /* custom magic here */} 169 | 170 | // 4. Generate the vue-chartjs component 171 | // The first argument is the chart-id, the second the chart type, third is the custom controller 172 | const CustomLine = createTypedChart('line', LineWithLineController) 173 | 174 | // 5. Extend the CustomLine Component just like you do with the default vue-chartjs charts. 175 | 176 | export default { 177 | components: { CustomLine } 178 | } 179 | ``` 180 | 181 | ## Resources 182 | 183 | Here are some resources, such as tutorials, on how to use `vue-chartjs`: 184 | 185 | - [Using vue-chartjs with WordPress](https://medium.com/@apertureless/wordpress-vue-and-chart-js-6b61493e289f) 186 | - [Create stunning Charts with Vue and Chart.js](https://hackernoon.com/creating-stunning-charts-with-vue-js-and-chart-js-28af584adc0a) 187 | - [Let’s Build a Web App with Vue, Chart.js and an API Part I](https://hackernoon.com/lets-build-a-web-app-with-vue-chart-js-and-an-api-544eb81c4b44) 188 | - [Let’s Build a Web App with Vue, Chart.js and an API Part II](https://hackernoon.com/lets-build-a-web-app-with-vue-chart-js-and-an-api-part-ii-39781b1d5acf) 189 | - [Build a realtime chart with VueJS and Pusher](https://blog.pusher.com/build-realtime-chart-with-vuejs-pusher/) 190 | -------------------------------------------------------------------------------- /website/src/guide/index.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | **vue-chartjs** is a wrapper for [Chart.js](https://github.com/chartjs/Chart.js) in Vue. You can easily create reuseable chart components. 4 | 5 | Supports Chart.js v4. 6 | 7 | ## Introduction 8 | 9 | `vue-chartjs` lets you use Chart.js without much hassle inside Vue. It's perfect for people who need simple charts up and running as fast as possible. 10 | 11 | It abstracts the basic logic but exposes the Chart.js object to give you maximal flexibility. 12 | 13 | :::tip Need an API to fetch data? 14 | Please consider [Cube](https://cube.dev/?ref=eco-vue-chartjs), an open-source API for data apps. 15 | ::: 16 | 17 | ## Installation 18 | 19 | You can install `vue-chartjs` over `yarn` or `npm` or `pnpm`. However, you also need to add `chart.js` as a dependency to your project because `Chart.js` is a peerDependency. This way you can have full control over the versioning of `Chart.js`. 20 | 21 | ```bash 22 | pnpm add vue-chartjs chart.js 23 | # or 24 | yarn add vue-chartjs chart.js 25 | # or 26 | npm i vue-chartjs chart.js 27 | ``` 28 | 29 | ## Integration 30 | 31 | Every chart type that is available in Chart.js is exported as a named component and can be imported as such. These components are normal Vue components. 32 | 33 | The idea behind vue-chartjs is to provide easy-to-use components, with maximal flexibility and extensibility. 34 | 35 | ## Creating your first Chart 36 | 37 | First, you need to import the base chart. 38 | 39 | ```javascript 40 | import { Bar } from 'vue-chartjs' 41 | ``` 42 | 43 | Check out the official [Chart.js docs](http://www.chartjs.org/docs/latest/#creating-a-chart) to see the object structure you need to provide. 44 | 45 | Just create your own component. 46 | 47 | **BarChart.vue** 48 | 49 | ```vue 50 | 57 | 58 | 80 | ``` 81 | 82 | Use it in your vue app: 83 | 84 | **App.vue** 85 | 86 | ```vue 87 | 90 | 91 | 99 | ``` 100 | 101 | ## Updating Charts 102 | 103 | Since v4 charts have data change watcher and options change watcher by default. Wrapper will update or re-render the chart if new data or new options is passed. Mixins have been removed. 104 | 105 | ```vue 106 | 109 | 110 | 126 | ``` 127 | 128 | You may get Vue's `Target is readonly` warnings when you are updating your `chartData`. 129 | 130 | If your `chartData` is a `read-only` reactive value, you can override this warning by using a clone: 131 | 132 | ```vue 133 | 136 | ``` 137 | 138 | Unless you have a writable computed `chartData`, you won't be able to use the newer `structuredClone`, as you'll likely hit the `Write operation failed: computed value is readonly` error. 139 | 140 | You don't need to use a clone if your `chartData` is a [writable computed value](https://vuejs.org/guide/essentials/computed#writable-computed). 141 | 142 | 143 | 144 | ## Access to Chart instance 145 | 146 | You can get access to chart instance via template refs. 147 | 148 | ```vue 149 | 152 | ``` 153 | 154 | In Vue3 projects: 155 | 156 | ```javascript 157 | const chartInstance = this.$refs.bar.chart 158 | ``` 159 | 160 | ## Accessibility 161 | 162 | To make your charts accessible to all users, you should label your charts. 163 | Please refer also to the official [Chart.js Accessibility notes](https://www.chartjs.org/docs/latest/general/accessibility.html). 164 | 165 | ### `aria-label` 166 | 167 | You can directly label a chart by passing an `aria-label` prop. 168 | 169 | ```vue 170 | 173 | ``` 174 | 175 | ### `aria-describedby` 176 | 177 | You can reference to a describing element such as a table which describes the data by using the `aria-describedby` property. 178 | 179 | ```vue 180 | 200 | ``` 201 | 202 | ### Fallback-Content 203 | 204 | In case the Browser is not able to render the `canvas` element, you should consider providing fallback content by using the Slot of each component. 205 | 206 | ```vue 207 | 210 | ``` 211 | -------------------------------------------------------------------------------- /website/src/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: home 3 | hero: 4 | name: 📈 vue-chartjs 5 | tagline: ⚡ Easy and beautiful charts with Chart.js and Vue.js 6 | actions: 7 | - theme: brand 8 | text: Get Started → 9 | link: /guide/ 10 | features: 11 | - icon: 🙌 12 | title: Easy 13 | details: Easy for both beginners and pros 14 | - icon: 💪 15 | title: Extendable 16 | details: Simple to use, easy to extend 17 | - icon: 💯 18 | title: Powerful 19 | details: With the full power of chart.js 💯 20 | --- 21 | -------------------------------------------------------------------------------- /website/src/migration-guides/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: doc 3 | --- 4 | 5 | # Migration 6 | 7 | Over the time `vue-chartjs` has changed a lot. As the web and frontend technology has changed. 8 | To keep up with the speed of evolution we have iterated and changed a lot. For a smooth transition between version please check the migration guides. 9 | 10 | 11 | - [v4 -> v5](/migration-guides/v5) 12 | - [v3 -> v4](/migration-guides/v4) 13 | - [vue-chart-3](/migration-guides/vue-chart-3) 14 | -------------------------------------------------------------------------------- /website/src/migration-guides/v4.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: doc 3 | --- 4 | # Migration from v3 to v4 5 | 6 | With v4, this library introduces a number of breaking changes. In order to improve performance, offer new features, and improve maintainability, it was necessary to break backwards compatibility, but we aimed to do so only when worth the benefit. 7 | 8 | v4 is fully compatible with Chart.js v3. 9 | 10 | ## Tree-shaking 11 | 12 | v4 of this library, [just like Chart.js v3](https://www.chartjs.org/docs/latest/getting-started/v3-migration.html#setup-and-installation), is tree-shakable. It means that you need to import and register the controllers, elements, scales, and plugins you want to use. 13 | 14 | For a list of all the available items to import, see [Chart.js docs](https://www.chartjs.org/docs/latest/getting-started/integration.html#bundlers-webpack-rollup-etc). 15 | 16 | v3: 17 | 18 | ```javascript 19 | import { Bar } from 'vue-chartjs' 20 | ``` 21 | 22 | v4 — lazy way: 23 | 24 | ```javascript 25 | import 'chart.js/auto'; 26 | import { Bar } from 'vue-chartjs' 27 | ``` 28 | 29 | v4 — tree-shakable way: 30 | 31 | ```javascript 32 | import { Bar } from 'vue-chartjs' 33 | import { Chart as ChartJS, Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale } from 'chart.js' 34 | 35 | ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale) 36 | ``` 37 | 38 | Using the "lazy way" is okay to simplify the migration, but please consider using the tree-shakable way to decrease the bundle size. 39 | 40 | Please note that typed chart components register their controllers by default, so you don't need to register them by yourself. For example, when using the Pie component, you don't need to register PieController explicitly. 41 | 42 | ```javascript 43 | import { Pie } from 'vue-chartjs' 44 | import { Chart as ChartJS, Title, Tooltip, Legend, ArcElement, CategoryScale } from 'chart.js' 45 | 46 | ChartJS.register(Title, Tooltip, Legend, ArcElement, CategoryScale) 47 | ``` 48 | 49 | ## Changing the creation of Charts 50 | 51 | In v3, you needed to import the component, and then either use extends or mixins and add it. 52 | 53 | v3: 54 | 55 | ```javascript 56 | // BarChart.js 57 | import { Bar } from 'vue-chartjs' 58 | 59 | export default { 60 | extends: Bar, 61 | mounted () { 62 | // Overwriting base render method with actual data. 63 | this.renderChart({ 64 | labels: ['January', 'February', 'March'], 65 | datasets: [ 66 | { 67 | label: 'GitHub Commits', 68 | backgroundColor: '#f87979', 69 | data: [40, 20, 12] 70 | } 71 | ] 72 | }) 73 | } 74 | } 75 | ``` 76 | 77 | ```vue 78 | 81 | 82 | 90 | ``` 91 | 92 | In v4, you need to import the component, pass props to it, and use Chart component as a standard Vue component. 93 | 94 | ```vue 95 | 98 | 99 | 125 | ``` 126 | 127 | ## New reactivity system 128 | 129 | v3 does not update or re-render the chart if new data is passed. You needed to use `reactiveProp` and `reactiveData` mixins for that. 130 | 131 | v3: 132 | 133 | ```javascript 134 | import { Line, mixins } from 'vue-chartjs' 135 | 136 | export default { 137 | extends: Line, 138 | mixins: [mixins.reactiveProp], 139 | props: ['chartData', 'options'], 140 | mounted () { 141 | this.renderChart(this.chartData, this.options) 142 | } 143 | } 144 | ``` 145 | 146 | v4 charts have data change watcher by default. v4 will update or re-render the chart if new data is passed. Mixins have been removed. 147 | 148 | v4: 149 | 150 | ```vue 151 | 154 | 155 | 170 | ``` 171 | -------------------------------------------------------------------------------- /website/src/migration-guides/v5.md: -------------------------------------------------------------------------------- 1 | # Migration from v4 to v5 2 | 3 | With v5, this library introduces a number of breaking changes 4 | 5 | ## ESM 6 | 7 | ### v5.0 8 | 9 | Chart.js v4 and vue-chartjs v5 are [ESM-only packages](https://nodejs.org/api/esm.html). To use them in your project, it also should be ESM: 10 | 11 | ```json 12 | // package.json 13 | { 14 | "type": "module" 15 | } 16 | ``` 17 | 18 | If you are experiencing this problem with Jest, you should follow [this doc](https://jestjs.io/docs/ecmascript-modules) to enable ESM support. Or, we can recommend you migrate to [Vitest](https://vitest.dev/). Vitest has ESM support out of the box and [has almost the same API as Jest](https://vitest.dev/guide/migration.html#migrating-from-jest). [Here is our example of migration](https://github.com/reactchartjs/react-chartjs-2/commit/7f3ec96101d21e43cae8cbfe5e09a46a17cff1ef). 19 | 20 | 21 | ### v5.1 22 | 23 | Chart.js v4.1 and vue-chartjs v5.1 have restored the CommonJS support. 24 | 25 | ## API changes 26 | 27 | - `chartData` props were renamed to `data` 28 | - `chartOptions` props were renamed to `options` 29 | - unknown props will fall through to the canvas element. 30 | - `generateChart` were refactored and renamed to `createTypedChart` 31 | - Vue.js < 2.7 is no longer supported. If you want to use vue-chartjs with Vue < 2.7 you have to lock your version to 4.x. 32 | -------------------------------------------------------------------------------- /website/src/migration-guides/vue-chart-3.md: -------------------------------------------------------------------------------- 1 | 2 | # Migration from vue-chart-3 3 | 4 | ## Uninstall vue-chart-3 5 | 6 | ```bash 7 | pnpm rm vue-chart-3 8 | # or 9 | yarn remove vue-chart-3 10 | # or 11 | npm uninstall vue-chart-3 12 | ``` 13 | 14 | ## Install vue-chartjs 15 | 16 | ```bash 17 | pnpm add vue-chartjs 18 | # or 19 | yarn add vue-chartjs 20 | # or 21 | npm i vue-chartjs 22 | ``` 23 | 24 | ## Change component import path 25 | 26 | For Vue 2.7 and Vue 3 projects: 27 | 28 | ```javascript 29 | import { /* component */ } from 'vue-chartjs' 30 | ``` 31 | 32 | For Vue 2 (<2.7) projects: 33 | 34 | ```javascript 35 | import { /* component */ } from 'vue-chartjs/legacy' 36 | ``` 37 | 38 | ## Rename components 39 | 40 | - BarChart to Bar 41 | - DoughnutChart to Doughnut 42 | - LineChart to Line 43 | - PieChart to Pie 44 | - PolarAreaChart to PolarArea 45 | - RadarChart to Radar 46 | - BubbleChart to Bubble 47 | - ScatterChart to Scatter 48 | 49 | ## Rename props 50 | 51 | - options to chartOptions 52 | -------------------------------------------------------------------------------- /website/src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-chartjs-docs", 3 | "private": true 4 | } 5 | -------------------------------------------------------------------------------- /website/src/pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: {} 10 | -------------------------------------------------------------------------------- /website/src/public/vue-chartjs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apertureless/vue-chartjs/981b1f58141765513bd30b29112664b2a3d13ed8/website/src/public/vue-chartjs.png --------------------------------------------------------------------------------