├── .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 └── config.ts ├── CNAME ├── api └── index.md ├── examples └── index.md ├── guide └── index.md ├── images └── vue-chartjs.png ├── index.md ├── ja ├── api │ └── index.md ├── guide │ └── index.md └── index.md ├── migration-guides └── index.md ├── package.json ├── pt-br ├── api │ └── index.md ├── guide │ └── index.md └── index.md ├── ru ├── api │ └── index.md ├── guide │ └── index.md └── index.md └── zh-cn ├── api └── index.md ├── guide └── index.md └── index.md /.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 | size: 8 | runs-on: ubuntu-latest 9 | name: Checking size 10 | steps: 11 | - name: Checkout the repository 12 | uses: actions/checkout@v3 13 | - name: Install pnpm 14 | uses: pnpm/action-setup@v2 15 | with: 16 | version: 7 17 | - name: Install Node.js 18 | uses: actions/setup-node@v3 19 | with: 20 | node-version: 16 21 | cache: 'pnpm' 22 | - name: Check size 23 | uses: andresz1/size-limit-action@master 24 | with: 25 | github_token: ${{ secrets.GITHUB_TOKEN }} 26 | typings: 27 | runs-on: ubuntu-latest 28 | name: typings 29 | steps: 30 | - name: Checkout the repository 31 | uses: actions/checkout@v3 32 | - name: Install pnpm 33 | uses: pnpm/action-setup@v2 34 | with: 35 | version: 7 36 | - name: Install Node.js 37 | uses: actions/setup-node@v3 38 | with: 39 | node-version: 16 40 | cache: 'pnpm' 41 | - name: Install dependencies 42 | run: pnpm install 43 | - name: Prebuild 44 | run: pnpm build 45 | - name: Check typings 46 | if: success() 47 | run: pnpm test:typings 48 | storybook: 49 | runs-on: ubuntu-latest 50 | name: storybook 51 | steps: 52 | - name: Checkout the repository 53 | uses: actions/checkout@v3 54 | - name: Install pnpm 55 | uses: pnpm/action-setup@v2 56 | with: 57 | version: 7 58 | - name: Install Node.js 59 | uses: actions/setup-node@v3 60 | with: 61 | node-version: 16 62 | cache: 'pnpm' 63 | - name: Install dependencies 64 | run: pnpm install 65 | - name: Check storybook 66 | run: pnpm build:storybook 67 | -------------------------------------------------------------------------------- /.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@v3 12 | - name: Install pnpm 13 | uses: pnpm/action-setup@v2 14 | with: 15 | version: 7 16 | - name: Install Node.js 17 | uses: actions/setup-node@v3 18 | with: 19 | node-version: 16 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@v3 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@v3 12 | - name: Install pnpm 13 | uses: pnpm/action-setup@v2 14 | with: 15 | version: 7 16 | - name: Install Node.js 17 | uses: actions/setup-node@v3 18 | with: 19 | node-version: 16 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@v3 13 | - name: Install pnpm 14 | uses: pnpm/action-setup@v2 15 | with: 16 | version: 7 17 | - name: Install Node.js 18 | uses: actions/setup-node@v3 19 | with: 20 | node-version: 16 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": "1.95 KB", 5 | "webpack": false, 6 | "running": false 7 | }, 8 | { 9 | "path": "dist/index.js", 10 | "limit": "1 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 | Install 23 |   •   24 | How to use 25 |   •   26 | Docs 27 |   •   28 | Slack 29 |   •   30 | Stack Overflow 31 |
32 |
33 | 34 | ## Quickstart 35 | 36 | Install this library with peer dependencies: 37 | 38 | ```bash 39 | pnpm add vue-chartjs chart.js 40 | # or 41 | yarn add vue-chartjs chart.js 42 | # or 43 | npm i vue-chartjs chart.js 44 | ``` 45 | 46 | Then, import and use individual components: 47 | 48 | ```vue 49 | 52 | 53 | 85 | ``` 86 | 87 |
88 | 89 | Need an API to fetch data? Consider [Cube](https://cube.dev/?ref=eco-vue-chartjs), an open-source API for data apps. 90 | 91 |
92 | 93 | [![supported by Cube](https://user-images.githubusercontent.com/986756/154330861-d79ab8ec-aacb-4af8-9e17-1b28f1eccb01.svg)](https://cube.dev/?ref=eco-vue-chartjs) 94 | 95 | ## Docs 96 | 97 | - [Reactivity](https://vue-chartjs.org/guide/#updating-charts) 98 | - [Access to Chart instance](https://vue-chartjs.org/guide/#access-to-chart-instance) 99 | - [Migration from v4 to v5](https://vue-chartjs.org/migration-guides/#migration-from-v4-to-v5/) 100 | - [Migration from vue-chart-3](https://vue-chartjs.org/migration-guides/#migration-from-vue-chart-3/) 101 | - [API](https://vue-chartjs.org/api/) 102 | - [Examples](https://vue-chartjs.org/examples/) 103 | 104 | ## Build Setup 105 | 106 | ``` bash 107 | # install dependencies 108 | pnpm install 109 | 110 | # build for production with minification 111 | pnpm build 112 | 113 | # run unit tests 114 | pnpm test:unit 115 | 116 | # run all tests 117 | pnpm test 118 | ``` 119 | 120 | ## Contributing 121 | 122 | 1. Fork it ( https://github.com/apertureless/vue-chartjs/fork ) 123 | 2. Create your feature branch (`git checkout -b my-new-feature`) 124 | 3. Commit your changes (`git commit -am 'Add some feature'`) 125 | 4. Push to the branch (`git push origin my-new-feature`) 126 | 5. Create a new Pull Request 127 | 128 | ## License 129 | 130 | This software is distributed under [MIT license](LICENSE.txt). 131 | 132 | Buy Me A Coffee 133 | -------------------------------------------------------------------------------- /assets/bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onlinehub0808/vueChartjs/31f511e4e5787c37a4d9ace4c69789022eb4f48c/assets/bar.png -------------------------------------------------------------------------------- /assets/bubble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onlinehub0808/vueChartjs/31f511e4e5787c37a4d9ace4c69789022eb4f48c/assets/bubble.png -------------------------------------------------------------------------------- /assets/donate.svg: -------------------------------------------------------------------------------- 1 | 2 | DonateDonate 3 | -------------------------------------------------------------------------------- /assets/doughnut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onlinehub0808/vueChartjs/31f511e4e5787c37a4d9ace4c69789022eb4f48c/assets/doughnut.png -------------------------------------------------------------------------------- /assets/line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onlinehub0808/vueChartjs/31f511e4e5787c37a4d9ace4c69789022eb4f48c/assets/line.png -------------------------------------------------------------------------------- /assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onlinehub0808/vueChartjs/31f511e4e5787c37a4d9ace4c69789022eb4f48c/assets/logo.png -------------------------------------------------------------------------------- /assets/pie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onlinehub0808/vueChartjs/31f511e4e5787c37a4d9ace4c69789022eb4f48c/assets/pie.png -------------------------------------------------------------------------------- /assets/polar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onlinehub0808/vueChartjs/31f511e4e5787c37a4d9ace4c69789022eb4f48c/assets/polar.png -------------------------------------------------------------------------------- /assets/radar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onlinehub0808/vueChartjs/31f511e4e5787c37a4d9ace4c69789022eb4f48c/assets/radar.png -------------------------------------------------------------------------------- /assets/scatter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onlinehub0808/vueChartjs/31f511e4e5787c37a4d9ace4c69789022eb4f48c/assets/scatter.png -------------------------------------------------------------------------------- /assets/vue-chartjs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onlinehub0808/vueChartjs/31f511e4e5787c37a4d9ace4c69789022eb4f48c/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.2.0", 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": "^17.0.0", 82 | "@commitlint/config-conventional": "^17.0.0", 83 | "@rollup/plugin-node-resolve": "^15.0.1", 84 | "@size-limit/preset-big-lib": "^8.0.0", 85 | "@storybook/addon-actions": "^6.5.13", 86 | "@storybook/addon-controls": "^6.5.13", 87 | "@storybook/addon-docs": "^6.5.13", 88 | "@storybook/addons": "^6.5.13", 89 | "@storybook/builder-vite": "^0.2.6", 90 | "@storybook/client-api": "^6.5.13", 91 | "@storybook/client-logger": "^6.5.13", 92 | "@storybook/vue3": "^6.5.14", 93 | "@swc/core": "^1.3.23", 94 | "@swc/helpers": "^0.4.0", 95 | "@vitejs/plugin-vue": "^4.0.0", 96 | "@vitest/coverage-c8": "^0.27.0", 97 | "@vue/eslint-config-typescript": "^11.0.0", 98 | "@vue/test-utils": "^2.0.0-rc.17", 99 | "browserslist": "^4.19.1", 100 | "chart.js": "^4.1.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.31.0", 107 | "eslint-config-prettier": "^8.3.0", 108 | "eslint-config-standard": "^17.0.0", 109 | "eslint-plugin-import": "^2.25.4", 110 | "eslint-plugin-n": "^15.2.4", 111 | "eslint-plugin-node": "^11.1.0", 112 | "eslint-plugin-prettier": "^4.2.1", 113 | "eslint-plugin-prettier-vue": "4.2.0", 114 | "eslint-plugin-promise": "^6.0.0", 115 | "eslint-plugin-vue": "^9.0.0", 116 | "jsdom": "^21.0.0", 117 | "nano-staged": "^0.8.0", 118 | "prettier": "2.8.2", 119 | "react": "^18.2.0", 120 | "react-dom": "^18.2.0", 121 | "rollup": "^3.7.5", 122 | "rollup-plugin-swc3": "^0.8.0", 123 | "simple-git-hooks": "^2.7.0", 124 | "simple-github-release": "^1.0.0", 125 | "size-limit": "^8.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.27.0", 131 | "vitest-canvas-mock": "^0.2.2", 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 { 2 | defineComponent, 3 | ref, 4 | shallowRef, 5 | h, 6 | onMounted, 7 | onBeforeUnmount, 8 | watch, 9 | toRaw 10 | } from 'vue' 11 | import { Chart as ChartJS } from 'chart.js' 12 | import type { ChartComponent } from './types.js' 13 | import { Props } from './props.js' 14 | import { 15 | cloneData, 16 | setLabels, 17 | setDatasets, 18 | setOptions, 19 | toRawIfProxy, 20 | cloneProxy 21 | } from './utils.js' 22 | 23 | export const Chart = defineComponent({ 24 | props: Props, 25 | setup(props, { expose }) { 26 | const canvasRef = ref(null) 27 | const chartRef = shallowRef(null) 28 | 29 | expose({ chart: chartRef }) 30 | 31 | const renderChart = () => { 32 | if (!canvasRef.value) return 33 | 34 | const { type, data, options, plugins, datasetIdKey } = props 35 | const clonedData = cloneData(data, datasetIdKey) 36 | const proxiedData = cloneProxy(clonedData, data) 37 | 38 | chartRef.value = new ChartJS(canvasRef.value, { 39 | type, 40 | data: proxiedData, 41 | options: { ...options }, 42 | plugins 43 | }) 44 | } 45 | 46 | const destroyChart = () => { 47 | const chart = toRaw(chartRef.value) 48 | 49 | if (chart) { 50 | chart.destroy() 51 | chartRef.value = null 52 | } 53 | } 54 | 55 | const update = (chart: ChartJS) => { 56 | chart.update(props.updateMode) 57 | } 58 | 59 | onMounted(renderChart) 60 | 61 | onBeforeUnmount(destroyChart) 62 | 63 | watch( 64 | [() => props.options, () => props.data], 65 | ( 66 | [nextOptionsProxy, nextDataProxy], 67 | [prevOptionsProxy, prevDataProxy] 68 | ) => { 69 | const chart = toRaw(chartRef.value) 70 | 71 | if (!chart) { 72 | return 73 | } 74 | 75 | let shouldUpdate = false 76 | 77 | if (nextOptionsProxy) { 78 | const nextOptions = toRawIfProxy(nextOptionsProxy) 79 | const prevOptions = toRawIfProxy(prevOptionsProxy) 80 | 81 | if (nextOptions && nextOptions !== prevOptions) { 82 | setOptions(chart, nextOptions) 83 | shouldUpdate = true 84 | } 85 | } 86 | 87 | if (nextDataProxy) { 88 | const nextLabels = toRawIfProxy(nextDataProxy.labels) 89 | const prevLabels = toRawIfProxy(prevDataProxy.labels) 90 | const nextDatasets = toRawIfProxy(nextDataProxy.datasets) 91 | const prevDatasets = toRawIfProxy(prevDataProxy.datasets) 92 | 93 | if (nextLabels !== prevLabels) { 94 | setLabels(chart.config.data, nextLabels) 95 | shouldUpdate = true 96 | } 97 | 98 | if (nextDatasets && nextDatasets !== prevDatasets) { 99 | setDatasets(chart.config.data, nextDatasets, props.datasetIdKey) 100 | shouldUpdate = true 101 | } 102 | } 103 | 104 | if (shouldUpdate) { 105 | update(chart) 106 | } 107 | }, 108 | { deep: true } 109 | ) 110 | 111 | return () => { 112 | return h('canvas', { 113 | ref: canvasRef 114 | }) 115 | } 116 | } 117 | }) as ChartComponent 118 | -------------------------------------------------------------------------------- /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 Props = { 34 | type: { 35 | type: String as PropType, 36 | required: true 37 | }, 38 | ...CommonProps 39 | } as const 40 | -------------------------------------------------------------------------------- /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 { TypedChartComponent, ChartComponentRef } from './types.js' 15 | import { CommonProps } from './props.js' 16 | import { Chart } from './chart.js' 17 | import { compatProps } from './utils.js' 18 | 19 | export function createTypedChart< 20 | TType extends ChartType = ChartType, 21 | TData = DefaultDataPoint, 22 | TLabel = unknown 23 | >( 24 | type: TType, 25 | registerables: ChartComponentLike 26 | ): TypedChartComponent { 27 | ChartJS.register(registerables) 28 | 29 | return defineComponent({ 30 | props: CommonProps, 31 | setup(props, { expose }) { 32 | const ref = shallowRef(null) 33 | const reforwardRef = (chartRef: ChartComponentRef) => { 34 | ref.value = chartRef?.chart 35 | } 36 | 37 | expose({ chart: ref }) 38 | 39 | return () => { 40 | return h( 41 | Chart, 42 | compatProps( 43 | { 44 | ref: reforwardRef as any 45 | }, 46 | { 47 | type, 48 | ...props 49 | } 50 | ) 51 | ) 52 | } 53 | } 54 | }) as any 55 | } 56 | 57 | export const Bar = /* #__PURE__ */ createTypedChart('bar', BarController) 58 | 59 | export const Doughnut = /* #__PURE__ */ createTypedChart( 60 | 'doughnut', 61 | DoughnutController 62 | ) 63 | 64 | export const Line = /* #__PURE__ */ createTypedChart('line', LineController) 65 | 66 | export const Pie = /* #__PURE__ */ createTypedChart('pie', PieController) 67 | 68 | export const PolarArea = /* #__PURE__ */ createTypedChart( 69 | 'polarArea', 70 | PolarAreaController 71 | ) 72 | 73 | export const Radar = /* #__PURE__ */ createTypedChart('radar', RadarController) 74 | 75 | export const Bubble = /* #__PURE__ */ createTypedChart( 76 | 'bubble', 77 | BubbleController 78 | ) 79 | 80 | export const Scatter = /* #__PURE__ */ createTypedChart( 81 | 'scatter', 82 | ScatterController 83 | ) 84 | -------------------------------------------------------------------------------- /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 | "scripts": { 6 | "dev": "vitepress dev src", 7 | "build": "vitepress build src" 8 | }, 9 | "devDependencies": { 10 | "vitepress": "^0.22.3" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /website/src/.vitepress/config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitepress' 2 | 3 | export default defineConfig({ 4 | lastUpdated: true, 5 | 6 | themeConfig: { 7 | repo: 'apertureless/vue-chartjs', 8 | docsDir: 'website/src', 9 | docsBranch: 'main', 10 | editLinks: true, 11 | editLinkText: 'Help us improve this page!', 12 | lastUpdated: 'Last Updated', 13 | 14 | algolia: { 15 | indexName: 'vue-chartjs', 16 | apiKey: 'a1bb4528e8ed1eb89e40d6e4c1000514', 17 | appId: '24VA3R3NCC' 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: 'Slack', 39 | link: 'https://slack.cube.dev/?ref=eco-vue-chartjs' 40 | }, 41 | { 42 | text: 'Stack Overflow', 43 | link: 'https://stackoverflow.com/questions/tagged/vue-chartjs/' 44 | } 45 | ], 46 | 47 | sidebar: 'auto', 48 | 49 | locales: { 50 | '/': { 51 | selectText: 'Languages', 52 | label: 'English', 53 | editLinkText: 'Edit this page on GitHub' 54 | } 55 | // '/ru/': { 56 | // selectText: 'Языки', 57 | // label: 'Русский', 58 | // editLinkText: 'Редактировать эту страницу на GitHub', 59 | // nav: [ 60 | // { 61 | // text: 'Руководство', 62 | // link: '/ru/guide/' 63 | // }, 64 | // { 65 | // text: 'API', 66 | // link: '/ru/api/' 67 | // } 68 | // ] 69 | // } 70 | // '/zh-cn/': { 71 | // selectText: '选择语言', 72 | // label: '中文(简体)', 73 | // sidebar: 'auto', 74 | // editLinkText: '在GitHub上编辑本页', 75 | // nav: [ 76 | // { 77 | // text: '指南', 78 | // link: '/zh-cn/guide/' 79 | // }, 80 | // { 81 | // text: 'API 参考', 82 | // link: '/zh-cn/api/' 83 | // } 84 | // ] 85 | // }, 86 | // '/ja/': { 87 | // selectText: 'Languages', 88 | // label: '日本語', 89 | // editLinkText: 'Edit this page on GitHub', 90 | // nav: [ 91 | // { 92 | // text: 'Guide', 93 | // link: '/ja/guide/' 94 | // }, 95 | // { 96 | // text: 'API', 97 | // link: '/ja/api/' 98 | // } 99 | // ] 100 | // }, 101 | // '/pt-br/': { 102 | // selectText: 'Linguas', 103 | // label: 'Português do Brasil', 104 | // editLinkText: 'Edite esta página no GitHub', 105 | // nav: [ 106 | // { text: 'Guia', link: '/pt-br/guide/' }, 107 | // { text: 'API', link: '/pt-br/api/' } 108 | // ] 109 | // } 110 | } 111 | }, 112 | locales: { 113 | '/': { 114 | lang: 'en-US', 115 | title: '📈 vue-chartjs', 116 | description: '⚡ Easy and beautiful charts with Chart.js and Vue.js' 117 | } 118 | // '/ru/': { 119 | // lang: 'ru', 120 | // title: '📈 vue-chartjs', 121 | // description: '⚡ Простые и красивые графики с Chart.js и Vue.js' 122 | // } 123 | // '/zh-cn/': { 124 | // lang: 'zh-CN', 125 | // title: '📈 vue-chartjs', 126 | // description: '⚡ 使用 Chart.js 和 Vue.js 搭建简单和漂亮的图表' 127 | // }, 128 | // '/ja/': { 129 | // lang: 'ja', 130 | // title: '📈 vue-chartjs', 131 | // description: '⚡ Easy and beautiful charts with Chart.js and Vue.js' 132 | // }, 133 | // '/pt-br/': { 134 | // lang: 'pt-br', 135 | // title: '📈 vue-chartjs', 136 | // description: '⚡ Gráficos bonitos e fácil com Chart.js e Vue.js' 137 | // } 138 | } 139 | }) 140 | -------------------------------------------------------------------------------- /website/src/CNAME: -------------------------------------------------------------------------------- 1 | vue-chartjs.org 2 | -------------------------------------------------------------------------------- /website/src/api/index.md: -------------------------------------------------------------------------------- 1 | # Coding Reference 2 | 3 | ## Props 4 | 5 | There are some basic props defined in the components provided by `vue-chartjs`. 6 | 7 | | Prop | Description | 8 | |---|---| 9 | | data | The data object that is passed into the Chart.js chart | 10 | | options | The options object that is passed into the Chart.js chart | 11 | | datasetIdKey | Key name to identificate dataset | 12 | | plugins | The plugins array that is passed into the Chart.js chart | 13 | | updateMode | A mode string to indicate transition configuration should be used. | 14 | 15 | Rest props will fall through to the canvas element. 16 | 17 | ## Global Methods 18 | 19 | Global Methods need to be imported. 20 | 21 | ### createTypedChart 22 | 23 | - **Type:** `Function` 24 | - **Arguments**:`chart-type`, `chart-controller` 25 | - **Usage:** 26 | 27 | ```js 28 | import { createTypedChart } from 'vue-chartjs' 29 | import { LineController } from 'chart.js' 30 | 31 | const CustomLine = createTypedChart('line', LineController) 32 | ``` 33 | -------------------------------------------------------------------------------- /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/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 | ## Access to Chart instance 129 | 130 | You can get access to chart instance via template refs. 131 | 132 | ```vue 133 | 136 | ``` 137 | 138 | In Vue3 projects: 139 | 140 | ```javascript 141 | const chartInstance = this.$refs.bar.chart 142 | ``` 143 | 144 | ## Examples 145 | 146 | ### Chart with props 147 | 148 | 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. 149 | 150 | ```vue 151 | 154 | 155 | 176 | ``` 177 | 178 | ### Chart with local data 179 | 180 | You can handle your chart data directly in your parent component. 181 | 182 | ```vue 183 | 186 | 187 | 212 | ``` 213 | 214 | ### Chart with API data 215 | 216 | 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. 217 | 218 | To prevent this, a simple `v-if` is the best solution. 219 | 220 | Create your chart component with a data prop and options prop, so we can pass in our data and options from a container component. 221 | 222 | ```vue 223 | 228 | 229 | 256 | ``` 257 | 258 | ### Chart with dynamic styles 259 | 260 | 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. 261 | 262 | ::: warning 263 | You need to set `position: relative` 264 | ::: 265 | 266 | ```vue 267 | 272 | 273 | 292 | ``` 293 | 294 | ### Custom / New Charts 295 | 296 | 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. 297 | 298 | In `vue-chartjs`, you can do this pretty much the same way: 299 | 300 | ```js 301 | // 1. Import Chart.js so you can use the global Chart object 302 | import { Chart } from 'chart.js' 303 | // 2. Import the `createTypedChart()` method to create the vue component. 304 | import { createTypedChart } from 'vue-chartjs' 305 | // 3. Import needed controller from Chart.js 306 | import { LineController } from 'chart.js' 307 | 308 | // 3. Extend one of the default charts 309 | // http://www.chartjs.org/docs/latest/developers/charts.html 310 | class LineWithLineController extends LineController { /* custom magic here */} 311 | 312 | // 4. Generate the vue-chartjs component 313 | // The first argument is the chart-id, the second the chart type, third is the custom controller 314 | const CustomLine = createTypedChart('line', LineWithLineController) 315 | 316 | // 5. Extend the CustomLine Component just like you do with the default vue-chartjs charts. 317 | 318 | export default { 319 | components: { CustomLine } 320 | } 321 | ``` 322 | 323 | ## Resources 324 | 325 | Here are some resources, such as tutorials, on how to use `vue-chartjs`: 326 | 327 | - [Using vue-chartjs with WordPress](https://medium.com/@apertureless/wordpress-vue-and-chart-js-6b61493e289f) 328 | - [Create stunning Charts with Vue and Chart.js](https://hackernoon.com/creating-stunning-charts-with-vue-js-and-chart-js-28af584adc0a) 329 | - [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) 330 | - [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) 331 | - [Build a realtime chart with VueJS and Pusher](https://blog.pusher.com/build-realtime-chart-with-vuejs-pusher/) 332 | -------------------------------------------------------------------------------- /website/src/images/vue-chartjs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onlinehub0808/vueChartjs/31f511e4e5787c37a4d9ace4c69789022eb4f48c/website/src/images/vue-chartjs.png -------------------------------------------------------------------------------- /website/src/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: true 3 | heroImage: https://raw.githubusercontent.com/apertureless/vue-chartjs/main/website/src/images/vue-chartjs.png 4 | actionText: Get Started → 5 | actionLink: /guide/ 6 | features: 7 | - title: Easy 8 | details: Easy for both beginners and pros 🙌 9 | - title: Extendable 10 | details: Simple to use, easy to extend 💪 11 | - title: Powerful 12 | details: With the full power of chart.js 💯 13 | footer: MIT Licensed | Copyright © 2018-present Jakub Juszczak 14 | --- 15 | -------------------------------------------------------------------------------- /website/src/ja/api/index.md: -------------------------------------------------------------------------------- 1 | # コーディング レファレンス 2 | 3 | ## Props 4 | 5 | `vue-chartjs`によって提供されるコンポーネントにはいくつかの基本的なプロパティが定義されています。 `拡張`しているので、それらは *見えない* ですが、それらの値は上書きすることができます: 6 | 7 | | Prop名 | 説明 | 8 | |---|---| 9 | | width | チャート幅 | 10 | | height | チャート高さ | 11 | | chart-id | canvas要素のid | 12 | | css-classes | 囲んでいる div の css クラス (文字列) | 13 | | styles | 囲んでいる div の css クラス (オブジェクト) | 14 | | plugins | chartjs プラグイン (配列) | 15 | 16 | ## Events 17 | 18 | `reactData`または` reactProp`ミックスインが使用されている場合、以下のイベントが発行されます。 19 | 20 | | Event名 | 説明| 21 | |---|---| 22 | | `chart:render` | ミックスインが完全にレンダリングしたとき | 23 | | `chart:destroy` | ミックスインがチャートオブジェクトインスタンスを削除したとき | 24 | | `chart:update` | ミックスインが再レンダリングの代わりに更新をしたとき | 25 | | `labels:update` | labelsがセットされたとき | 26 | | `xlabels:update` | xlabelsがセットされたとき | 27 | | `ylabels:update` | ylabelsがセットされたとき | 28 | 29 | ## Global Methods 30 | グローバルメソッドはインポートして使用します。 31 | 32 | ### generateChart 33 | 34 | - **Type:** `Function` 35 | - **Arguments**: `chart-id`, `chart-type` 36 | - **Usage:** 37 | 38 | ```js 39 | import { generateChart } from 'vue-chartjs' 40 | // First argument is the chart-id, second the chart type. 41 | const CustomLine = generateChart('custom-line', 'LineWithLine') 42 | ``` 43 | 44 | ## Instance Methods 45 | 46 | インスタンスメソッドは独自のチャートコンポーネント内で使用することができます。 47 | 48 | 49 | ### generateLegend() 50 | 51 | HTMLの凡例を作成するヘルパー関数 52 | 53 | - **Type:** `Function` 54 | - **Arguments**: `none` 55 | - **Usage:** 56 | 57 | ```js {11} 58 | import { Line } from 'vue-chartjs' 59 | 60 | export default { 61 | extends: Line, 62 | props: ['datasets', 'options'] 63 | data: () => ({ 64 | htmlLegend: null 65 | }) 66 | mounted () { 67 | this.renderChart(this.datasets, this.options) 68 | this.htmlLegend = this.generateLegend() 69 | } 70 | } 71 | 72 | ``` 73 | 74 | ### プラグインの追加 75 | 76 | Chart.jsでは、グローバルプラグインとインラインプラグインを定義できます。 グローバルプラグインは、[Chart.js docs](http://www.chartjs.org/docs/latest/developers/plugins.html)で説明されているように`vue-chartjs`でも問題なく動作します。 77 | 78 | 79 | インラインプラグインを追加したい場合に備えて、`vue-chartjs`は`addPlugin()`と呼ばれるヘルパーメソッドを公開します。 80 | 81 | `renderChart()`メソッドの前に `addPlugin()`を呼び出すべきです。 82 | 83 | - **Type:** `Function` 84 | - **Arguments**: `Array` of Plugins 85 | - **Usage:** 86 | 87 | ```js 88 | mounted () { 89 | this.addPlugin({ 90 | id: 'my-plugin', 91 | beforeInit: function (chart) { 92 | .... 93 | } 94 | }) 95 | } 96 | ``` 97 | 98 | ### renderChart() 99 | 100 | Chart.js のインスタンスを作成して描画します。 101 | 102 | - **Type:** `Function` 103 | - **Arguments**: `Chart Data`, `Chart Options` 104 | - **Usage:** 105 | 106 | ```js 107 | mounted () { 108 | this.renderChart({ 109 | labels: ['January', 'February'], 110 | datasets: [ 111 | { 112 | label: 'Data One', 113 | backgroundColor: '#f87979', 114 | data: [40, 20] 115 | } 116 | ]}, 117 | { 118 | responsive: true 119 | } 120 | ) 121 | } 122 | ``` 123 | 124 | ## Chart.js オブジェクト 125 | 126 | 独自のチャートコンポーネント内からChart.jsのオブジェクトには `this.$data._chart` でアクセスできます。 127 | 128 | ## Canvas 129 | 130 | Canvas要素には `this.$refs.canvas` でアクセスできます。 131 | -------------------------------------------------------------------------------- /website/src/ja/guide/index.md: -------------------------------------------------------------------------------- 1 | # 最初に 2 | 3 | **vue-chartjs** は [Chart.js](https://github.com/chartjs/Chart.js) をvueで使用するためのラッパーです。 再利用可能なチャートコンポーネントを簡単に作成できます。 4 | 5 | ## 初めに 6 | 7 | `vue-chartjs` あまり手間をかけずにvueの中でchart.jsを使うことができます。 シンプルなチャートをできるだけ早く起動して実行したいという人に最適です。 8 | 9 | chart.jsの基本ロジックを抽象化していますが、公開されたchart.jsのオブジェクトを使用して柔軟にカスタマイズできます。 10 | 11 | ## インストール 12 | 13 | ### NPM 14 | 15 | `npm`を使って` vue-chartjs`をインストールすることができます。 ただしプロジェクトへの依存関係として `chart.js`を追加する必要があります。 なぜなら `Chart.js`はpeerDependencyだからです。 このため、Chart.jsのバージョンを完全に制御できます。 16 | 17 | `yarn add vue-chartjs chart.js@2.9.4` or `npm install vue-chartjs chart.js@2.9.4 --save` 18 | 19 | ::: tip 20 | Vue.jsの Version 1.xを使用している場合は`legacy`タグを使用してください。しかし、vueのバージョン1はもうメンテナンスされません。 21 | 22 | `yarn add vue-chartjs@legacy` 23 | ::: 24 | 25 | ### ブラウザ 26 | 27 | ブラウザから直接 `vue-chartjs` を使用することができます。 28 | 先に`Chart.js`スクリプトを追加してから`vue-chartjs`スクリプトを追加してください 29 | 30 | ```html 31 | 32 | 33 | ``` 34 | 35 | ## 統合 36 | 37 | `Chart.js`で利用可能なすべてのチャートタイプは名前付きコンポーネントとしてエクスポートされ、そのままインポートすることができます。 これらのコンポーネントは通常のVueコンポーネントですが、それを`拡張`する必要があります。 38 | 39 | `vue-chartjs`の背後にある考え方は、最大限の柔軟性と拡張性を持ち、使いやすいコンポーネントを提供することです。 これを実現するには、独自の *Chart Component* を作成し、それを`vue-chartjs`コンポーネントして提供するように拡張する必要があります。 40 | 41 | 拡張することで、チャートコンポーネントのメソッドとロジックは、独自のチャートコンポーネントにマージされます。 42 | 43 | ## 最初のチャートの作成 44 | 45 | BaseChartをインポートしてextendします。この方法で異なるデータのチャートを表示するときに柔軟性が大幅に向上します。 46 | コンポーネントをカプセル化し、プロパティを使用してコンポーネント内のデータに渡したり、コンポーネント内に直接データを記述することができます。ただし直接コンポーネント内にデータを記述した場合は再利用ができません。 47 | 48 | パッケージ全体または各モジュールを個別にインポートできます。 インポートしたものを `extends:`か `mixins:[]`を使って指定します。 また `mounted()`フックで、 `this.renderChart()`を呼び出します。 これでチャートインスタンスが作成されます。 49 | 50 | ```js{1,4,6} 51 | import { Bar } from 'vue-chartjs' 52 | 53 | export default { 54 | extends: Bar, 55 | mounted () { 56 | this.renderChart(data, options) 57 | } 58 | } 59 | ``` 60 | 61 | :::tip 62 | `extends: Bar` または `mixins: [Bar]` どちらの記述方法でも使用できます。 63 | ::: 64 | 65 | メソッドthis.renderChart()は、Barコンポーネントによって提供され、2つのパラメータを受け付けています。 どちらも`Object`です。 最初のものは表示するデータで、二番目のものはオプションを格納するオブジェクトです。 66 | 67 | チャート毎に必要なオブジェクト構造は公式 [Chart.js docs](http://www.chartjs.org/docs/latest/#creating-a-chart)をチェックしてください。 68 | 69 | ### Vue シングルファイルコンポーネント 70 | 71 | 本ドキュメントのほとんどの例はjavascriptファイルを基に記述されていて、 `.vue`ファイルの例はありません。 これはあなたが、たいてい必要なのは ` 87 | 88 | 90 | ``` 91 | 92 | ::: danger Template タグはマージできません 93 | `.vue`ファイルに`