├── .clean-publish ├── .commitlintrc.json ├── .czrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.json ├── .github ├── 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 ├── .tool-versions ├── CHANGELOG.md ├── LICENSE ├── LICENSE.md ├── README.md ├── package.json ├── pnpm-lock.yaml ├── rollup.config.js ├── sandboxes ├── bar │ ├── grouped │ │ ├── App.tsx │ │ ├── index.html │ │ ├── index.tsx │ │ ├── package.json │ │ └── vite.config.js │ ├── horizontal │ │ ├── App.tsx │ │ ├── index.html │ │ ├── index.tsx │ │ ├── package.json │ │ └── vite.config.js │ ├── stacked │ │ ├── App.tsx │ │ ├── index.html │ │ ├── index.tsx │ │ ├── package.json │ │ └── vite.config.js │ └── vertical │ │ ├── App.tsx │ │ ├── index.html │ │ ├── index.tsx │ │ ├── package.json │ │ └── vite.config.js ├── bubble │ └── default │ │ ├── App.tsx │ │ ├── index.html │ │ ├── index.tsx │ │ ├── package.json │ │ └── vite.config.js ├── chart │ ├── canvas │ │ ├── App.tsx │ │ ├── index.html │ │ ├── index.tsx │ │ ├── package.json │ │ └── vite.config.js │ ├── events │ │ ├── App.tsx │ │ ├── index.html │ │ ├── index.tsx │ │ ├── package.json │ │ └── vite.config.js │ ├── multitype │ │ ├── App.tsx │ │ ├── index.html │ │ ├── index.tsx │ │ ├── package.json │ │ └── vite.config.js │ └── ref │ │ ├── App.tsx │ │ ├── index.html │ │ ├── index.tsx │ │ ├── package.json │ │ └── vite.config.js ├── doughnut │ └── default │ │ ├── App.tsx │ │ ├── index.html │ │ ├── index.tsx │ │ ├── package.json │ │ └── vite.config.js ├── line │ ├── area │ │ ├── App.tsx │ │ ├── index.html │ │ ├── index.tsx │ │ ├── package.json │ │ └── vite.config.js │ ├── default │ │ ├── App.tsx │ │ ├── index.html │ │ ├── index.tsx │ │ ├── package.json │ │ └── vite.config.js │ └── multiaxis │ │ ├── App.tsx │ │ ├── index.html │ │ ├── index.tsx │ │ ├── package.json │ │ └── vite.config.js ├── pie │ └── default │ │ ├── App.tsx │ │ ├── index.html │ │ ├── index.tsx │ │ ├── package.json │ │ └── vite.config.js ├── polarArea │ └── default │ │ ├── App.tsx │ │ ├── index.html │ │ ├── index.tsx │ │ ├── package.json │ │ └── vite.config.js ├── radar │ └── default │ │ ├── App.tsx │ │ ├── index.html │ │ ├── index.tsx │ │ ├── package.json │ │ └── vite.config.js ├── scatter │ └── default │ │ ├── App.tsx │ │ ├── index.html │ │ ├── index.tsx │ │ ├── package.json │ │ └── vite.config.js └── tsconfig.json ├── src ├── chart.tsx ├── index.ts ├── typedCharts.tsx ├── types.ts └── utils.ts ├── stories ├── Bar.stories.tsx ├── Bubble.stories.tsx ├── Chart.data.ts ├── Chart.stories.tsx ├── Doughnut.stories.tsx ├── Line.stories.tsx ├── Pie.stories.tsx ├── PolarArea.stories.tsx ├── Radar.stories.tsx ├── Scatter.stories.tsx └── data.ts ├── test ├── .eslintrc.json ├── chart.test-d.tsx ├── chart.test.tsx └── setup.ts ├── tsconfig.json ├── vite.config.js └── website ├── .gitignore ├── CNAME ├── README.md ├── babel.config.js ├── docs ├── chartjs-v2.mdx ├── chartjs-v3.mdx ├── components │ ├── bar.mdx │ ├── bubble.mdx │ ├── chart.mdx │ ├── docs.js │ ├── doughnut.mdx │ ├── index.mdx │ ├── line.mdx │ ├── pie.mdx │ ├── polar-area.mdx │ ├── radar.mdx │ └── scatter.mdx ├── docs.js ├── examples │ ├── area-chart.mdx │ ├── bubble-chart.mdx │ ├── chart-events.mdx │ ├── chart-ref.mdx │ ├── docs.js │ ├── doughnut-chart.mdx │ ├── gradient-chart.mdx │ ├── grouped-bar-chart.mdx │ ├── horizontal-bar-chart.mdx │ ├── index.mdx │ ├── line-chart.mdx │ ├── multiaxis-line-chart.mdx │ ├── multitype-chart.mdx │ ├── pie-chart.mdx │ ├── polar-area-chart.mdx │ ├── radar-chart.mdx │ ├── scatter-chart.mdx │ ├── stacked-bar-chart.mdx │ └── vertical-bar-chart.mdx ├── faq │ ├── canvas-context.md │ ├── chartjs-instance.md │ ├── docs.js │ ├── esm-only.md │ ├── fill-property.md │ ├── index.mdx │ ├── maintain-aspect-ratio.md │ ├── registered-element.md │ ├── registered-scale.md │ ├── typescript.md │ └── why-two.md ├── index.mdx ├── migration-to-v4.md ├── migration-to-v5.md ├── working-with-datasets.md └── working-with-events.md ├── docusaurus.config.js ├── package.json ├── pnpm-lock.yaml ├── sidebars.js ├── src ├── components │ ├── ContextProvider.tsx │ └── PropsTable.tsx └── css │ └── custom.css ├── static ├── .nojekyll └── img │ ├── favicon.ico │ └── logo.svg └── tsconfig.json /.clean-publish: -------------------------------------------------------------------------------- 1 | { 2 | "withoutPublish": true, 3 | "tempDir": "package", 4 | "fields": ["tsd"], 5 | "files": ["website"] 6 | } 7 | -------------------------------------------------------------------------------- /.commitlintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["@commitlint/config-conventional"], 3 | "rules": { 4 | "body-max-line-length": [0] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.czrc: -------------------------------------------------------------------------------- 1 | { 2 | "path": "@commitlint/cz-commitlint" 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 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | .publish/* 2 | dist/* 3 | lib/* 4 | node_modules/* 5 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "@typescript-eslint/parser", 3 | "plugins": ["@typescript-eslint", "prettier"], 4 | "extends": [ 5 | "standard", 6 | "standard-react", 7 | "plugin:@typescript-eslint/recommended", 8 | "plugin:prettier/recommended" 9 | ], 10 | "env": { 11 | "browser": true 12 | }, 13 | "parserOptions": { 14 | "ecmaVersion": "latest", 15 | "ecmaFeatures": { 16 | "jsx": true 17 | } 18 | }, 19 | "settings": { 20 | "react": { 21 | "version": "detect" 22 | } 23 | }, 24 | "rules": { 25 | "curly": [2, "multi-line"], 26 | "quotes": [2, "single", "avoid-escape"], 27 | "react/display-name": 0, 28 | "react/jsx-boolean-value": 1, 29 | "jsx-quotes": [1, "prefer-single"], 30 | "react/jsx-no-undef": 1, 31 | "react/jsx-sort-props": 0, 32 | "react/jsx-uses-react": 1, 33 | "react/jsx-uses-vars": 1, 34 | "react/no-did-mount-set-state": 1, 35 | "react/no-did-update-set-state": 1, 36 | "react/no-unknown-property": 1, 37 | "react/prop-types": 0, 38 | "react/react-in-jsx-scope": 1, 39 | "react/self-closing-comp": 1, 40 | "semi": [2, "always"], 41 | "strict": 0, 42 | "no-use-before-define": 0, 43 | "@typescript-eslint/no-use-before-define": 2, 44 | "@typescript-eslint/consistent-type-imports": "error", 45 | "@typescript-eslint/no-import-type-side-effects": "error" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /.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: ⚠️ react-chartjs-2 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://codesandbox.io/s/github/reactchartjs/react-chartjs-2/tree/master/sandboxes/chart/ref) 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: react-chartjs-2 version 48 | description: Which version of `react-chartjs-2` 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/react-chartjs-2 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: react-chartjs-2 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: ⚠️ react-chartjs-2 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 | - master 6 | jobs: 7 | size: 8 | runs-on: ubuntu-latest 9 | name: size-limit 10 | steps: 11 | - name: Checkout the repository 12 | uses: actions/checkout@v4 13 | - name: Install pnpm 14 | uses: pnpm/action-setup@v2 15 | with: 16 | version: 9 17 | - name: Install Node.js 18 | uses: actions/setup-node@v4 19 | with: 20 | node-version: 22 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@v4 32 | - name: Install pnpm 33 | uses: pnpm/action-setup@v2 34 | with: 35 | version: 9 36 | - name: Install Node.js 37 | uses: actions/setup-node@v4 38 | with: 39 | node-version: 22 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@v4 54 | - name: Install pnpm 55 | uses: pnpm/action-setup@v2 56 | with: 57 | version: 9 58 | - name: Install Node.js 59 | uses: actions/setup-node@v4 60 | with: 61 | node-version: 22 62 | cache: 'pnpm' 63 | - name: Install dependencies 64 | run: pnpm install 65 | - name: Check storybook 66 | run: pnpm build:storybook 67 | editorconfig: 68 | runs-on: ubuntu-latest 69 | name: editorconfig 70 | steps: 71 | - name: Checkout the repository 72 | uses: actions/checkout@v4 73 | - name: Check editorconfig 74 | uses: editorconfig-checker/action-editorconfig-checker@main 75 | website: 76 | runs-on: ubuntu-latest 77 | name: website 78 | steps: 79 | - name: Checkout the repository 80 | uses: actions/checkout@v4 81 | - name: Install pnpm 82 | uses: pnpm/action-setup@v2 83 | with: 84 | version: 9 85 | - name: Install Node.js 86 | uses: actions/setup-node@v4 87 | with: 88 | node-version: 22 89 | cache: 'pnpm' 90 | - name: Install dependencies 91 | run: pnpm install 92 | - name: Install website dependencies 93 | run: pnpm install 94 | working-directory: ./website 95 | - name: Check website 96 | run: pnpm build 97 | working-directory: ./website 98 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | pull_request: 4 | push: 5 | branches: 6 | - master 7 | jobs: 8 | test: 9 | runs-on: ubuntu-latest 10 | name: Tests 11 | steps: 12 | - name: Checkout the repository 13 | uses: actions/checkout@v4 14 | - name: Install pnpm 15 | uses: pnpm/action-setup@v2 16 | with: 17 | version: 9 18 | - name: Install Node.js 19 | uses: actions/setup-node@v4 20 | with: 21 | node-version: 22 22 | cache: 'pnpm' 23 | - name: Install dependencies 24 | run: pnpm install 25 | - name: Run tests 26 | run: pnpm test 27 | - name: Collect coverage 28 | uses: codecov/codecov-action@v5 29 | if: success() 30 | with: 31 | token: ${{ secrets.CODECOV_TOKEN }} 32 | files: ./coverage/lcov.info 33 | fail_ci_if_error: true 34 | -------------------------------------------------------------------------------- /.github/workflows/commit.yml: -------------------------------------------------------------------------------- 1 | name: Commit 2 | on: 3 | push: 4 | jobs: 5 | commitlint: 6 | runs-on: ubuntu-latest 7 | name: commitlint 8 | steps: 9 | - name: Checkout the repository 10 | uses: actions/checkout@v4 11 | with: 12 | fetch-depth: 0 13 | - name: Run commitlint 14 | uses: wagoid/commitlint-github-action@v6 15 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | release: 4 | types: [created] 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | name: Publish package 9 | steps: 10 | - name: Checkout the repository 11 | uses: actions/checkout@v4 12 | - name: Install pnpm 13 | uses: pnpm/action-setup@v2 14 | with: 15 | version: 9 16 | - name: Install Node.js 17 | uses: actions/setup-node@v4 18 | with: 19 | node-version: 22 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 | - master 6 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 7 | permissions: 8 | contents: read 9 | pages: write 10 | id-token: write 11 | # Allow one concurrent deployment 12 | concurrency: 13 | group: "pages" 14 | cancel-in-progress: true 15 | jobs: 16 | deploy: 17 | environment: 18 | name: github-pages 19 | url: ${{ steps.deployment.outputs.page_url }} 20 | runs-on: ubuntu-latest 21 | name: deploy website 22 | steps: 23 | - name: Checkout the repository 24 | uses: actions/checkout@v4 25 | - name: Install pnpm 26 | uses: pnpm/action-setup@v2 27 | with: 28 | version: 9 29 | - name: Install Node.js 30 | uses: actions/setup-node@v4 31 | with: 32 | node-version: 22 33 | cache: 'pnpm' 34 | - name: Install dependencies 35 | run: pnpm install 36 | - name: Install website dependencies 37 | run: pnpm install 38 | working-directory: ./website 39 | - name: Build website 40 | run: pnpm build 41 | working-directory: ./website 42 | - name: Setup Pages 43 | uses: actions/configure-pages@v5 44 | - name: Upload artifact 45 | uses: actions/upload-pages-artifact@v3 46 | with: 47 | path: './website/build' 48 | - name: Deploy to GitHub Pages 49 | id: deployment 50 | uses: actions/deploy-pages@v4 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | 6 | # builds 7 | package 8 | dist 9 | storybook-static 10 | 11 | # misc 12 | .DS_Store 13 | .env 14 | .env.* 15 | 16 | npm-debug.log* 17 | 18 | # testing 19 | coverage 20 | -------------------------------------------------------------------------------- /.nano-staged.json: -------------------------------------------------------------------------------- 1 | { 2 | "**/*.{js,ts,tsx}": ["prettier --write", "eslint"] 3 | } 4 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | strict-peer-dependencies=false 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "jsxSingleQuote": true, 4 | "semi": true, 5 | "tabWidth": 2, 6 | "bracketSpacing": true, 7 | "arrowParens": "avoid", 8 | "trailingComma": "es5" 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.4 KB", 5 | "webpack": false, 6 | "running": false 7 | }, 8 | { 9 | "path": "dist/index.js", 10 | "limit": "590 B", 11 | "import": "{ Chart }" 12 | } 13 | ] 14 | -------------------------------------------------------------------------------- /.storybook/main.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const { mergeConfig } = require('vite'); 3 | 4 | module.exports = { 5 | viteFinal(config) { 6 | return mergeConfig(config, { 7 | resolve: { 8 | alias: { 9 | 'react-chartjs-2': path.resolve(__dirname, '../src'), 10 | }, 11 | }, 12 | }); 13 | }, 14 | stories: ['../stories/*.tsx'], 15 | addons: [ 16 | '@storybook/addon-docs', 17 | '@storybook/addon-controls', 18 | '@storybook/addon-actions', 19 | ], 20 | framework: { 21 | name: '@storybook/react-vite', 22 | options: {}, 23 | }, 24 | docs: {}, 25 | }; 26 | -------------------------------------------------------------------------------- /.storybook/manager.js: -------------------------------------------------------------------------------- 1 | import { addons } from '@storybook/manager-api'; 2 | 3 | import { theme } from './theme'; 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: 'react-chartjs-2', 6 | brandUrl: 'https://github.com/reactchartjs/react-chartjs-2', 7 | }); 8 | -------------------------------------------------------------------------------- /.tool-versions: -------------------------------------------------------------------------------- 1 | nodejs 22.4.1 2 | pnpm 9.15.2 3 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | ## [5.3.0](https://github.com/reactchartjs/react-chartjs-2/compare/v5.2.0...v5.3.0) (2025-01-01) 6 | 7 | 8 | ### Features 9 | 10 | * support react 19 ([#1236](https://github.com/reactchartjs/react-chartjs-2/issues/1236)) ([055b601](https://github.com/reactchartjs/react-chartjs-2/commit/055b601f22da8aac8c04a37cba16d48d8e4914ee)) 11 | 12 | 13 | ### Bug Fixes 14 | 15 | * docs typo ([#1202](https://github.com/reactchartjs/react-chartjs-2/issues/1202)) ([65b68c6](https://github.com/reactchartjs/react-chartjs-2/commit/65b68c6cf177fb98636876af3b0b96ffcd0ce483)) 16 | 17 | ## [5.2.0](https://github.com/reactchartjs/react-chartjs-2/compare/v5.1.0...v5.2.0) (2023-01-09) 18 | 19 | 20 | ### Features 21 | 22 | * restore compatability with webpack 4 ([#1146](https://github.com/reactchartjs/react-chartjs-2/issues/1146)) ([082c26d](https://github.com/reactchartjs/react-chartjs-2/commit/082c26d559f210af7c55c31a826fe4821a429700)) 23 | 24 | ## [5.1.0](https://github.com/reactchartjs/react-chartjs-2/compare/v5.0.1...v5.1.0) (2022-12-19) 25 | 26 | 27 | ### Features 28 | 29 | * restore CommonJS bundle ([#1137](https://github.com/reactchartjs/react-chartjs-2/issues/1137)) ([7db2643](https://github.com/reactchartjs/react-chartjs-2/commit/7db264337200c999bc987e0e288df08ef7813ee3)) 30 | 31 | ### [5.0.1](https://github.com/reactchartjs/react-chartjs-2/compare/v5.0.0...v5.0.1) (2022-11-17) 32 | 33 | 34 | ### Bug Fixes 35 | 36 | * remove chart.js v3 from peer dependencies ([7ae5702](https://github.com/reactchartjs/react-chartjs-2/commit/7ae57023783f4c64210119f0447bd1c0e1ba92e9)) 37 | 38 | ## [5.0.0](https://github.com/reactchartjs/react-chartjs-2/compare/v4.3.1...v5.0.0) (2022-11-17) 39 | 40 | 41 | ### ⚠ BREAKING CHANGES 42 | 43 | * no commonjs support 44 | 45 | ### Features 46 | 47 | * chart.js v4 support ([#1109](https://github.com/reactchartjs/react-chartjs-2/issues/1109)) ([deb2110](https://github.com/reactchartjs/react-chartjs-2/commit/deb211084757225e3ddb2574b567e805ba7eeeb6)) 48 | * package type module ([#1108](https://github.com/reactchartjs/react-chartjs-2/issues/1108)) ([6eb8ce7](https://github.com/reactchartjs/react-chartjs-2/commit/6eb8ce7f23654e46d17aedc104375112b2f2a955)) 49 | 50 | 51 | ### Bug Fixes 52 | 53 | * **deps:** update dependency chart.js to v4 ([#1104](https://github.com/reactchartjs/react-chartjs-2/issues/1104)) ([6192408](https://github.com/reactchartjs/react-chartjs-2/commit/61924087de28a7ee0bba6f61c50a0bde362b662c)) 54 | * **deps:** update dependency react-scripts to v5.0.1 ([#1049](https://github.com/reactchartjs/react-chartjs-2/issues/1049)) ([38a9796](https://github.com/reactchartjs/react-chartjs-2/commit/38a9796f1cefa63390d4eaf3eec960c77fe78d34)) 55 | * **deps:** update react monorepo to v18 ([#1031](https://github.com/reactchartjs/react-chartjs-2/issues/1031)) ([ad73425](https://github.com/reactchartjs/react-chartjs-2/commit/ad734256e173353222995b4edfbf7a8ad0dc96f3)) 56 | * **deps:** update react monorepo to v18.2.0 ([#1082](https://github.com/reactchartjs/react-chartjs-2/issues/1082)) ([72e7352](https://github.com/reactchartjs/react-chartjs-2/commit/72e7352fcdff182465bfdcd6a7f6c4579d062d01)) 57 | * **site:** [#1076](https://github.com/reactchartjs/react-chartjs-2/issues/1076) expand the docusaurus container content to give the sandboxes more space ([#1077](https://github.com/reactchartjs/react-chartjs-2/issues/1077)) ([b512e8d](https://github.com/reactchartjs/react-chartjs-2/commit/b512e8dc130e28c1284be77d4ef6c3a788b9e262)) 58 | 59 | ### [4.3.1](https://github.com/reactchartjs/react-chartjs-2/compare/v4.3.0...v4.3.1) (2022-07-13) 60 | 61 | 62 | ### Bug Fixes 63 | 64 | * update options without resetting chart ([#1061](https://github.com/reactchartjs/react-chartjs-2/issues/1061)) ([fa0a4bb](https://github.com/reactchartjs/react-chartjs-2/commit/fa0a4bbdb3d85735db289494c4bdf1da083a51da)) 65 | 66 | ## [4.3.0](https://github.com/reactchartjs/react-chartjs-2/compare/v4.2.0...v4.3.0) (2022-07-12) 67 | 68 | 69 | ### Features 70 | 71 | * assure redraw occurs when type changes ([#1054](https://github.com/reactchartjs/react-chartjs-2/issues/1054)) ([#1055](https://github.com/reactchartjs/react-chartjs-2/issues/1055)) ([bf0538f](https://github.com/reactchartjs/react-chartjs-2/commit/bf0538fd953ee878659d0b5647676fbfda460c76)) 72 | 73 | ## [4.2.0](https://github.com/reactchartjs/react-chartjs-2/compare/v4.1.0...v4.2.0) (2022-06-07) 74 | 75 | 76 | ### Features 77 | 78 | * implement passing updateMode property to chart's update method ([#1043](https://github.com/reactchartjs/react-chartjs-2/issues/1043)) ([96d2714](https://github.com/reactchartjs/react-chartjs-2/commit/96d2714c3df88346152a1b66b8fe729d43151e40)) 79 | 80 | ## [4.1.0](https://github.com/reactchartjs/react-chartjs-2/compare/v4.0.1...v4.1.0) (2022-04-07) 81 | 82 | 83 | ### Features 84 | 85 | * react 18 support ([#1034](https://github.com/reactchartjs/react-chartjs-2/issues/1034)) ([058035a](https://github.com/reactchartjs/react-chartjs-2/commit/058035a3e2da17ad9ee0c9f50793da3aaefb3913)) 86 | 87 | ### [4.0.1](https://github.com/reactchartjs/react-chartjs-2/compare/v4.0.0...v4.0.1) (2022-01-19) 88 | 89 | 90 | ### Bug Fixes 91 | 92 | * compatability with react 16 typings ([#987](https://github.com/reactchartjs/react-chartjs-2/issues/987)) ([4a01054](https://github.com/reactchartjs/react-chartjs-2/commit/4a010540ac01b1e4b299705ddd93f412df4875d1)), closes [#870](https://github.com/reactchartjs/react-chartjs-2/issues/870) 93 | * **deps:** update dependency @svgr/webpack to v6 ([#999](https://github.com/reactchartjs/react-chartjs-2/issues/999)) ([7611ebd](https://github.com/reactchartjs/react-chartjs-2/commit/7611ebdbdbf4e91991b1a15d393fbadf2de01246)) 94 | * **deps:** update dependency react-scripts to v5 ([#1001](https://github.com/reactchartjs/react-chartjs-2/issues/1001)) ([3936227](https://github.com/reactchartjs/react-chartjs-2/commit/3936227b4e6865bbd20419af4a5b0b49561f608c)) 95 | * **deps:** update docusaurus monorepo to v2.0.0-beta.14 ([#994](https://github.com/reactchartjs/react-chartjs-2/issues/994)) ([2a24ee9](https://github.com/reactchartjs/react-chartjs-2/commit/2a24ee92203c703d16c3784eccb0011b5b870802)) 96 | 97 | ## [4.0.0](https://github.com/reactchartjs/react-chartjs-2/compare/v3.3.0...v4.0.0) (2021-11-22) 98 | 99 | 100 | ### ⚠ BREAKING CHANGES 101 | 102 | * getDatasetAtEvent, getElementAtEvent and getElementsAtEvent props are removed, 103 | utils with the same names can used instead 104 | * New target browsers: ie 11 dropped for regular bundle, modern bundle builds for 105 | browsers with es6 modules support. 106 | * Functional data prop is removed 107 | * Added support of tree-shaking of Chart.js. Now you should register Chart.js 108 | components by yourself. 109 | * default export is renamed to Chart 110 | * Chart.js re-exports are removed 111 | 112 | ### Features 113 | 114 | * datasetIdKey prop ([#848](https://github.com/reactchartjs/react-chartjs-2/issues/848)) ([f895766](https://github.com/reactchartjs/react-chartjs-2/commit/f895766f012c0d3781d75b5f83adc6dbc8de0b03)) 115 | 116 | 117 | * default export is renamed to Chart ([#836](https://github.com/reactchartjs/react-chartjs-2/issues/836)) ([131daa0](https://github.com/reactchartjs/react-chartjs-2/commit/131daa008d3a3c280ba9e751c67ca926708b60e4)) 118 | * functional data prop is removed ([#840](https://github.com/reactchartjs/react-chartjs-2/issues/840)) ([b64dfb0](https://github.com/reactchartjs/react-chartjs-2/commit/b64dfb0430bf5817a5f8b8708551934ad426921e)) 119 | * getDatasetAtEvent, getElementAtEvent and getElementsAtEvent props are removed ([#845](https://github.com/reactchartjs/react-chartjs-2/issues/845)) ([6a9b2a7](https://github.com/reactchartjs/react-chartjs-2/commit/6a9b2a7527d23e7409c9273ad32eb100122ffb51)) 120 | * new target browsers ([#841](https://github.com/reactchartjs/react-chartjs-2/issues/841)) ([b1e83db](https://github.com/reactchartjs/react-chartjs-2/commit/b1e83db599e7f9b832c2fe1942b5e5f296730dd9)) 121 | * removed chart.js re-exports ([#835](https://github.com/reactchartjs/react-chartjs-2/issues/835)) ([30d5c2d](https://github.com/reactchartjs/react-chartjs-2/commit/30d5c2d457eae0b1142ea4ffb6eff8f583b60817)) 122 | * tree-shaking ([#839](https://github.com/reactchartjs/react-chartjs-2/issues/839)) ([fcd2849](https://github.com/reactchartjs/react-chartjs-2/commit/fcd2849037bb01d2eeadbfbc90c90054eb620d4c)) 123 | 124 | ## [3.3.0](https://github.com/reactchartjs/react-chartjs-2/compare/v3.2.0...v3.3.0) (2021-10-26) 125 | 126 | 127 | ### Features 128 | 129 | * export chart props types ([#810](https://github.com/reactchartjs/react-chartjs-2/issues/810)) ([82ab334](https://github.com/reactchartjs/react-chartjs-2/commit/82ab334c62939fb4924ed6021502fccfea29a5a2)), closes [#720](https://github.com/reactchartjs/react-chartjs-2/issues/720) 130 | 131 | 132 | ### Bug Fixes 133 | 134 | * data updating fix ([#807](https://github.com/reactchartjs/react-chartjs-2/issues/807)) ([45a50cc](https://github.com/reactchartjs/react-chartjs-2/commit/45a50cc46196ce64088a463b6f3b384a6c98eb06)), closes [#806](https://github.com/reactchartjs/react-chartjs-2/issues/806) 135 | 136 | ## [3.2.0](https://github.com/reactchartjs/react-chartjs-2/compare/v3.1.1...v3.2.0) (2021-10-21) 137 | 138 | 139 | ### Features 140 | 141 | * remove lodash ([#784](https://github.com/reactchartjs/react-chartjs-2/issues/784)) ([5594170](https://github.com/reactchartjs/react-chartjs-2/commit/559417024ef2fb34005727ff16d8fae8615cb071)) 142 | 143 | 144 | ### Bug Fixes 145 | 146 | * improve and fix rerendering ([#790](https://github.com/reactchartjs/react-chartjs-2/issues/790)) ([330fb1c](https://github.com/reactchartjs/react-chartjs-2/commit/330fb1cf0913bdbacda5ef755fb58c79482e1ea2)) 147 | * multitype chart typings ([#792](https://github.com/reactchartjs/react-chartjs-2/issues/792)) ([2f19eb3](https://github.com/reactchartjs/react-chartjs-2/commit/2f19eb3eba9681f383ca23e7a3a1f1c581c89061)) 148 | 149 | ### [3.1.1](https://github.com/reactchartjs/react-chartjs-2/compare/v3.1.0...v3.1.1) (2021-10-19) 150 | 151 | 152 | ### Bug Fixes 153 | 154 | * components' props types ([#782](https://github.com/reactchartjs/react-chartjs-2/issues/782)) ([eba8a27](https://github.com/reactchartjs/react-chartjs-2/commit/eba8a2794bb802dacc395a450110af8765fea868)), closes [#734](https://github.com/reactchartjs/react-chartjs-2/issues/734) [#741](https://github.com/reactchartjs/react-chartjs-2/issues/741) 155 | 156 | ## [3.1.0](https://github.com/reactchartjs/react-chartjs-2/compare/v2.4.0...v3.1.0) (2021-10-17) 157 | 158 | 159 | ### Features 160 | 161 | * Reduced package size 162 | 163 | 164 | ### Bug Fixes 165 | 166 | * minor types fixes ([#759](https://github.com/reactchartjs/react-chartjs-2/issues/759)) ([fe6c00f](https://github.com/reactchartjs/react-chartjs-2/commit/fe6c00f05cdc3099a66a7ac0c05fb5e6f216209a)) 167 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2020 Jeremy Ayerst 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Jeremy Ayerst 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 | # react-chartjs-2 2 | 3 | Logo 4 | 5 | React components for Chart.js, the most popular charting library. 6 | 7 | Supports Chart.js v4 and v3. 8 | 9 | [![NPM version][npm]][npm-url] 10 | [![Downloads][downloads]][downloads-url] 11 | [![Build status][build]][build-url] 12 | [![Coverage status][coverage]][coverage-url] 13 | [![Bundle size][size]][size-url] 14 | 15 | [npm]: https://img.shields.io/npm/v/react-chartjs-2.svg 16 | [npm-url]: https://www.npmjs.com/package/react-chartjs-2 17 | 18 | [downloads]: https://img.shields.io/npm/dm/react-chartjs-2.svg 19 | [downloads-url]: https://www.npmjs.com/package/react-chartjs-2 20 | 21 | [build]: https://img.shields.io/github/actions/workflow/status/reactchartjs/react-chartjs-2/ci.yml?branch=master 22 | [build-url]: https://github.com/reactchartjs/react-chartjs-2/actions 23 | 24 | [coverage]: https://img.shields.io/codecov/c/github/reactchartjs/react-chartjs-2.svg 25 | [coverage-url]: https://app.codecov.io/gh/reactchartjs/react-chartjs-2 26 | 27 | [size]: https://img.shields.io/bundlephobia/minzip/react-chartjs-2 28 | [size-url]: https://bundlephobia.com/package/react-chartjs-2 29 | 30 |
31 | Quickstart 32 |   •   33 | Docs 34 |   •   35 | Stack Overflow 36 |
37 |
38 | 39 | ## Quickstart 40 | 41 | Install this library with peer dependencies: 42 | 43 | ```bash 44 | pnpm add react-chartjs-2 chart.js 45 | # or 46 | yarn add react-chartjs-2 chart.js 47 | # or 48 | npm i react-chartjs-2 chart.js 49 | ``` 50 | 51 | We recommend using `chart.js@^4.0.0`. 52 | 53 | Then, import and use individual components: 54 | 55 | ```jsx 56 | import { Doughnut } from 'react-chartjs-2'; 57 | 58 | 59 | ``` 60 | 61 | ## Docs 62 | 63 | - [Migration to v4](https://react-chartjs-2.js.org/docs/migration-to-v4) 64 | - [Working with datasets](https://react-chartjs-2.js.org/docs/working-with-datasets) 65 | - [Working with events](https://react-chartjs-2.js.org/docs/working-with-events) 66 | - [FAQ](https://react-chartjs-2.js.org/faq) 67 | - [Components](https://react-chartjs-2.js.org/components) 68 | - [Examples](https://react-chartjs-2.js.org/examples) 69 | 70 | ## License 71 | 72 | [MIT Licensed](LICENSE) 73 | Copyright (c) 2020 Jeremy Ayerst 74 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-chartjs-2", 3 | "type": "module", 4 | "version": "5.3.0", 5 | "description": "React components for Chart.js", 6 | "author": "Jeremy Ayerst", 7 | "homepage": "https://github.com/reactchartjs/react-chartjs-2", 8 | "license": "MIT", 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/reactchartjs/react-chartjs-2.git" 12 | }, 13 | "bugs": { 14 | "url": "https://github.com/reactchartjs/react-chartjs-2/issues" 15 | }, 16 | "keywords": [ 17 | "chart", 18 | "chart-js", 19 | "chart.js", 20 | "react-chartjs-2", 21 | "react chart.js", 22 | "react-chart.js" 23 | ], 24 | "sideEffects": false, 25 | "types": "./dist/index.d.ts", 26 | "exports": "./src/index.ts", 27 | "publishConfig": { 28 | "main": "./dist/index.cjs", 29 | "module": "./dist/index.js", 30 | "exports": { 31 | "types": "./dist/index.d.ts", 32 | "import": "./dist/index.js", 33 | "require": "./dist/index.cjs" 34 | }, 35 | "directory": "package" 36 | }, 37 | "files": [ 38 | "dist" 39 | ], 40 | "scripts": { 41 | "prepublishOnly": "pnpm test && pnpm build && del ./package && clean-publish", 42 | "postpublish": "del ./package", 43 | "emitDeclarations": "tsc --emitDeclarationOnly", 44 | "build": "rollup -c && pnpm emitDeclarations", 45 | "start:storybook": "storybook dev -p 6006 --ci", 46 | "build:storybook": "del ./storybook-static; NODE_ENV=production storybook build", 47 | "test:lint": "eslint \"src/**/*.{ts,tsx}\" \"stories/**/*.{ts,tsx}\" \"sandboxes/**/*.{ts,tsx}\" \"test/**/*.{ts,tsx}\"", 48 | "test:unit": "vitest run --coverage", 49 | "test:unit:watch": "vitest watch", 50 | "test:size": "size-limit", 51 | "test:typings": "tsd", 52 | "test": "pnpm test:lint && pnpm test:unit", 53 | "format": "prettier --write src", 54 | "commit": "cz", 55 | "bumpVersion": "standard-version", 56 | "createGithubRelease": "simple-github-release", 57 | "release": "pnpm bumpVersion && git push origin master --tags && pnpm createGithubRelease", 58 | "updateGitHooks": "simple-git-hooks" 59 | }, 60 | "peerDependencies": { 61 | "chart.js": "^4.1.1", 62 | "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" 63 | }, 64 | "devDependencies": { 65 | "@commitlint/cli": "^17.0.0", 66 | "@commitlint/config-conventional": "^17.0.0", 67 | "@commitlint/cz-commitlint": "^17.0.0", 68 | "@rollup/plugin-node-resolve": "^16.0.0", 69 | "@size-limit/preset-big-lib": "^11.1.6", 70 | "@storybook/addon-actions": "^8.4.7", 71 | "@storybook/addon-controls": "^8.4.7", 72 | "@storybook/addon-docs": "^8.4.7", 73 | "@storybook/client-logger": "^8.4.7", 74 | "@storybook/manager-api": "^8.4.7", 75 | "@storybook/preview-api": "^8.4.7", 76 | "@storybook/react": "^8.4.7", 77 | "@storybook/react-vite": "^8.4.7", 78 | "@storybook/theming": "^8.4.7", 79 | "@swc/core": "^1.10.1", 80 | "@swc/helpers": "^0.5.15", 81 | "@testing-library/dom": "^10.4.0", 82 | "@testing-library/jest-dom": "^6.6.3", 83 | "@testing-library/react": "^16.1.0", 84 | "@types/faker": "^5.5.8", 85 | "@types/node": "^18.0.0", 86 | "@types/react": "^19.0.2", 87 | "@types/react-dom": "^19.0.2", 88 | "@typescript-eslint/eslint-plugin": "^8.18.0", 89 | "@typescript-eslint/parser": "^8.18.0", 90 | "@vitejs/plugin-react": "^4.3.4", 91 | "@vitest/coverage-v8": "^2.1.8", 92 | "browserslist": "^4.24.2", 93 | "chart.js": "^4.4.7", 94 | "chartjs-adapter-date-fns": "^3.0.0", 95 | "chartjs-plugin-annotation": "^3.1.0", 96 | "chartjs-plugin-zoom": "^2.2.0", 97 | "clean-publish": "^5.0.0", 98 | "commitizen": "^4.2.4", 99 | "date-fns": "^2.25.0", 100 | "del-cli": "^6.0.0", 101 | "eslint": "^8.57.1", 102 | "eslint-config-prettier": "^9.1.0", 103 | "eslint-config-standard": "^17.1.0", 104 | "eslint-config-standard-react": "^13.0.0", 105 | "eslint-plugin-import": "^2.25.1", 106 | "eslint-plugin-n": "^17.0.0", 107 | "eslint-plugin-prettier": "^5.2.1", 108 | "eslint-plugin-promise": "^7.0.0", 109 | "eslint-plugin-react": "^7.17.0", 110 | "faker": "^5.5.3", 111 | "happy-dom": "^16.1.0", 112 | "nano-staged": "^0.8.0", 113 | "prettier": "^3.4.2", 114 | "react": "^19.0.0", 115 | "react-dom": "^19.0.0", 116 | "rollup": "^4.0.0", 117 | "rollup-plugin-swc3": "^0.12.0", 118 | "simple-git-hooks": "^2.6.1", 119 | "simple-github-release": "^1.0.0", 120 | "size-limit": "^11.1.6", 121 | "standard-version": "^9.3.1", 122 | "storybook": "^8.4.7", 123 | "tsd": "^0.31.0", 124 | "typescript": "^5.7.2", 125 | "vite": "^6.0.6", 126 | "vitest": "^2.1.8", 127 | "vitest-canvas-mock": "^0.3.3" 128 | }, 129 | "tsd": { 130 | "directory": "./test", 131 | "compilerOptions": { 132 | "paths": { 133 | "react-chartjs-2": [ 134 | "./src" 135 | ] 136 | } 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import { swc } from 'rollup-plugin-swc3'; 2 | import { nodeResolve } from '@rollup/plugin-node-resolve'; 3 | import pkg from './package.json' with { type: 'json' }; 4 | 5 | const extensions = ['.js', '.ts', '.tsx']; 6 | const external = _ => /node_modules/.test(_) && !/@swc\/helpers/.test(_); 7 | const plugins = targets => [ 8 | nodeResolve({ 9 | extensions, 10 | }), 11 | swc({ 12 | tsconfig: false, 13 | jsc: { 14 | parser: { 15 | syntax: 'typescript', 16 | tsx: true, 17 | }, 18 | transform: { 19 | react: { 20 | useBuiltins: true, 21 | }, 22 | }, 23 | externalHelpers: true, 24 | }, 25 | env: { 26 | targets, 27 | }, 28 | module: { 29 | type: 'es6', 30 | }, 31 | sourceMaps: true, 32 | }), 33 | ]; 34 | 35 | export default { 36 | input: pkg.exports, 37 | plugins: plugins('defaults and supports es6-module'), 38 | external, 39 | output: [ 40 | { 41 | file: pkg.publishConfig.exports.import, 42 | format: 'es', 43 | sourcemap: true, 44 | }, 45 | { 46 | file: pkg.publishConfig.exports.require, 47 | format: 'cjs', 48 | sourcemap: true, 49 | }, 50 | ], 51 | }; 52 | -------------------------------------------------------------------------------- /sandboxes/bar/grouped/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | Chart as ChartJS, 4 | CategoryScale, 5 | LinearScale, 6 | BarElement, 7 | Title, 8 | Tooltip, 9 | Legend, 10 | } from 'chart.js'; 11 | import { Bar } from 'react-chartjs-2'; 12 | import faker from 'faker'; 13 | 14 | ChartJS.register( 15 | CategoryScale, 16 | LinearScale, 17 | BarElement, 18 | Title, 19 | Tooltip, 20 | Legend 21 | ); 22 | 23 | export const options = { 24 | plugins: { 25 | title: { 26 | display: true, 27 | text: 'Chart.js Bar Chart - Stacked', 28 | }, 29 | }, 30 | responsive: true, 31 | interaction: { 32 | mode: 'index' as const, 33 | intersect: false, 34 | }, 35 | scales: { 36 | x: { 37 | stacked: true, 38 | }, 39 | y: { 40 | stacked: true, 41 | }, 42 | }, 43 | }; 44 | 45 | const labels = ['January', 'February', 'March', 'April', 'May', 'June', 'July']; 46 | 47 | export const data = { 48 | labels, 49 | datasets: [ 50 | { 51 | label: 'Dataset 1', 52 | data: labels.map(() => faker.datatype.number({ min: -1000, max: 1000 })), 53 | backgroundColor: 'rgb(255, 99, 132)', 54 | stack: 'Stack 0', 55 | }, 56 | { 57 | label: 'Dataset 2', 58 | data: labels.map(() => faker.datatype.number({ min: -1000, max: 1000 })), 59 | backgroundColor: 'rgb(75, 192, 192)', 60 | stack: 'Stack 0', 61 | }, 62 | { 63 | label: 'Dataset 3', 64 | data: labels.map(() => faker.datatype.number({ min: -1000, max: 1000 })), 65 | backgroundColor: 'rgb(53, 162, 235)', 66 | stack: 'Stack 1', 67 | }, 68 | ], 69 | }; 70 | 71 | export function App() { 72 | return ; 73 | } 74 | -------------------------------------------------------------------------------- /sandboxes/bar/grouped/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /sandboxes/bar/grouped/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import { App } from './App.js'; 5 | 6 | const rootElement = document.getElementById('root'); 7 | createRoot(rootElement!).render(); 8 | -------------------------------------------------------------------------------- /sandboxes/bar/grouped/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "scripts": { 4 | "start": "vite" 5 | }, 6 | "dependencies": { 7 | "chart.js": "^4.0.0", 8 | "faker": "5.5.3", 9 | "react": "18.2.0", 10 | "react-chartjs-2": "^5.0.0", 11 | "react-dom": "18.2.0" 12 | }, 13 | "devDependencies": { 14 | "@types/faker": "5.5.9", 15 | "@types/react": "18.0.26", 16 | "@types/react-dom": "18.0.10", 17 | "@vitejs/plugin-react": "^4.0.0", 18 | "typescript": "4.9.5", 19 | "vite": "^6.0.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /sandboxes/bar/grouped/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | export default defineConfig({ 5 | plugins: [react()], 6 | }); 7 | -------------------------------------------------------------------------------- /sandboxes/bar/horizontal/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | Chart as ChartJS, 4 | CategoryScale, 5 | LinearScale, 6 | BarElement, 7 | Title, 8 | Tooltip, 9 | Legend, 10 | } from 'chart.js'; 11 | import { Bar } from 'react-chartjs-2'; 12 | import faker from 'faker'; 13 | 14 | ChartJS.register( 15 | CategoryScale, 16 | LinearScale, 17 | BarElement, 18 | Title, 19 | Tooltip, 20 | Legend 21 | ); 22 | 23 | export const options = { 24 | indexAxis: 'y' as const, 25 | elements: { 26 | bar: { 27 | borderWidth: 2, 28 | }, 29 | }, 30 | responsive: true, 31 | plugins: { 32 | legend: { 33 | position: 'right' as const, 34 | }, 35 | title: { 36 | display: true, 37 | text: 'Chart.js Horizontal Bar Chart', 38 | }, 39 | }, 40 | }; 41 | 42 | const labels = ['January', 'February', 'March', 'April', 'May', 'June', 'July']; 43 | 44 | export const data = { 45 | labels, 46 | datasets: [ 47 | { 48 | label: 'Dataset 1', 49 | data: labels.map(() => faker.datatype.number({ min: -1000, max: 1000 })), 50 | borderColor: 'rgb(255, 99, 132)', 51 | backgroundColor: 'rgba(255, 99, 132, 0.5)', 52 | }, 53 | { 54 | label: 'Dataset 2', 55 | data: labels.map(() => faker.datatype.number({ min: -1000, max: 1000 })), 56 | borderColor: 'rgb(53, 162, 235)', 57 | backgroundColor: 'rgba(53, 162, 235, 0.5)', 58 | }, 59 | ], 60 | }; 61 | 62 | export function App() { 63 | return ; 64 | } 65 | -------------------------------------------------------------------------------- /sandboxes/bar/horizontal/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /sandboxes/bar/horizontal/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import { App } from './App.js'; 5 | 6 | const rootElement = document.getElementById('root'); 7 | createRoot(rootElement!).render(); 8 | -------------------------------------------------------------------------------- /sandboxes/bar/horizontal/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "scripts": { 4 | "start": "vite" 5 | }, 6 | "dependencies": { 7 | "chart.js": "^4.0.0", 8 | "faker": "5.5.3", 9 | "react": "18.2.0", 10 | "react-chartjs-2": "^5.0.0", 11 | "react-dom": "18.2.0" 12 | }, 13 | "devDependencies": { 14 | "@types/faker": "5.5.9", 15 | "@types/react": "18.0.26", 16 | "@types/react-dom": "18.0.10", 17 | "@vitejs/plugin-react": "^4.0.0", 18 | "typescript": "4.9.5", 19 | "vite": "^6.0.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /sandboxes/bar/horizontal/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | export default defineConfig({ 5 | plugins: [react()], 6 | }); 7 | -------------------------------------------------------------------------------- /sandboxes/bar/stacked/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | Chart as ChartJS, 4 | CategoryScale, 5 | LinearScale, 6 | BarElement, 7 | Title, 8 | Tooltip, 9 | Legend, 10 | } from 'chart.js'; 11 | import { Bar } from 'react-chartjs-2'; 12 | import faker from 'faker'; 13 | 14 | ChartJS.register( 15 | CategoryScale, 16 | LinearScale, 17 | BarElement, 18 | Title, 19 | Tooltip, 20 | Legend 21 | ); 22 | 23 | export const options = { 24 | plugins: { 25 | title: { 26 | display: true, 27 | text: 'Chart.js Bar Chart - Stacked', 28 | }, 29 | }, 30 | responsive: true, 31 | scales: { 32 | x: { 33 | stacked: true, 34 | }, 35 | y: { 36 | stacked: true, 37 | }, 38 | }, 39 | }; 40 | 41 | const labels = ['January', 'February', 'March', 'April', 'May', 'June', 'July']; 42 | 43 | export const data = { 44 | labels, 45 | datasets: [ 46 | { 47 | label: 'Dataset 1', 48 | data: labels.map(() => faker.datatype.number({ min: -1000, max: 1000 })), 49 | backgroundColor: 'rgb(255, 99, 132)', 50 | }, 51 | { 52 | label: 'Dataset 2', 53 | data: labels.map(() => faker.datatype.number({ min: -1000, max: 1000 })), 54 | backgroundColor: 'rgb(75, 192, 192)', 55 | }, 56 | { 57 | label: 'Dataset 3', 58 | data: labels.map(() => faker.datatype.number({ min: -1000, max: 1000 })), 59 | backgroundColor: 'rgb(53, 162, 235)', 60 | }, 61 | ], 62 | }; 63 | 64 | export function App() { 65 | return ; 66 | } 67 | -------------------------------------------------------------------------------- /sandboxes/bar/stacked/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /sandboxes/bar/stacked/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import { App } from './App.js'; 5 | 6 | const rootElement = document.getElementById('root'); 7 | createRoot(rootElement!).render(); 8 | -------------------------------------------------------------------------------- /sandboxes/bar/stacked/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "scripts": { 4 | "start": "vite" 5 | }, 6 | "dependencies": { 7 | "chart.js": "^4.0.0", 8 | "faker": "5.5.3", 9 | "react": "18.2.0", 10 | "react-chartjs-2": "^5.0.0", 11 | "react-dom": "18.2.0" 12 | }, 13 | "devDependencies": { 14 | "@types/faker": "5.5.9", 15 | "@types/react": "18.0.26", 16 | "@types/react-dom": "18.0.10", 17 | "@vitejs/plugin-react": "^4.0.0", 18 | "typescript": "4.9.5", 19 | "vite": "^6.0.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /sandboxes/bar/stacked/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | export default defineConfig({ 5 | plugins: [react()], 6 | }); 7 | -------------------------------------------------------------------------------- /sandboxes/bar/vertical/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | Chart as ChartJS, 4 | CategoryScale, 5 | LinearScale, 6 | BarElement, 7 | Title, 8 | Tooltip, 9 | Legend, 10 | } from 'chart.js'; 11 | import { Bar } from 'react-chartjs-2'; 12 | import faker from 'faker'; 13 | 14 | ChartJS.register( 15 | CategoryScale, 16 | LinearScale, 17 | BarElement, 18 | Title, 19 | Tooltip, 20 | Legend 21 | ); 22 | 23 | export const options = { 24 | responsive: true, 25 | plugins: { 26 | legend: { 27 | position: 'top' as const, 28 | }, 29 | title: { 30 | display: true, 31 | text: 'Chart.js Bar Chart', 32 | }, 33 | }, 34 | }; 35 | 36 | const labels = ['January', 'February', 'March', 'April', 'May', 'June', 'July']; 37 | 38 | export const data = { 39 | labels, 40 | datasets: [ 41 | { 42 | label: 'Dataset 1', 43 | data: labels.map(() => faker.datatype.number({ min: 0, max: 1000 })), 44 | backgroundColor: 'rgba(255, 99, 132, 0.5)', 45 | }, 46 | { 47 | label: 'Dataset 2', 48 | data: labels.map(() => faker.datatype.number({ min: 0, max: 1000 })), 49 | backgroundColor: 'rgba(53, 162, 235, 0.5)', 50 | }, 51 | ], 52 | }; 53 | 54 | export function App() { 55 | return ; 56 | } 57 | -------------------------------------------------------------------------------- /sandboxes/bar/vertical/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /sandboxes/bar/vertical/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import { App } from './App.js'; 5 | 6 | const rootElement = document.getElementById('root'); 7 | createRoot(rootElement!).render(); 8 | -------------------------------------------------------------------------------- /sandboxes/bar/vertical/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "scripts": { 4 | "start": "vite" 5 | }, 6 | "dependencies": { 7 | "chart.js": "^4.0.0", 8 | "faker": "5.5.3", 9 | "react": "18.2.0", 10 | "react-chartjs-2": "^5.0.0", 11 | "react-dom": "18.2.0" 12 | }, 13 | "devDependencies": { 14 | "@types/faker": "5.5.9", 15 | "@types/react": "18.0.26", 16 | "@types/react-dom": "18.0.10", 17 | "@vitejs/plugin-react": "^4.0.0", 18 | "typescript": "4.9.5", 19 | "vite": "^6.0.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /sandboxes/bar/vertical/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | export default defineConfig({ 5 | plugins: [react()], 6 | }); 7 | -------------------------------------------------------------------------------- /sandboxes/bubble/default/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | Chart as ChartJS, 4 | LinearScale, 5 | PointElement, 6 | Tooltip, 7 | Legend, 8 | } from 'chart.js'; 9 | import { Bubble } from 'react-chartjs-2'; 10 | import faker from 'faker'; 11 | 12 | ChartJS.register(LinearScale, PointElement, Tooltip, Legend); 13 | 14 | export const options = { 15 | scales: { 16 | y: { 17 | beginAtZero: true, 18 | }, 19 | }, 20 | }; 21 | 22 | export const data = { 23 | datasets: [ 24 | { 25 | label: 'Red dataset', 26 | data: Array.from({ length: 50 }, () => ({ 27 | x: faker.datatype.number({ min: -100, max: 100 }), 28 | y: faker.datatype.number({ min: -100, max: 100 }), 29 | r: faker.datatype.number({ min: 5, max: 20 }), 30 | })), 31 | backgroundColor: 'rgba(255, 99, 132, 0.5)', 32 | }, 33 | { 34 | label: 'Blue dataset', 35 | data: Array.from({ length: 50 }, () => ({ 36 | x: faker.datatype.number({ min: -100, max: 100 }), 37 | y: faker.datatype.number({ min: -100, max: 100 }), 38 | r: faker.datatype.number({ min: 5, max: 20 }), 39 | })), 40 | backgroundColor: 'rgba(53, 162, 235, 0.5)', 41 | }, 42 | ], 43 | }; 44 | 45 | export function App() { 46 | return ; 47 | } 48 | -------------------------------------------------------------------------------- /sandboxes/bubble/default/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /sandboxes/bubble/default/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import { App } from './App.js'; 5 | 6 | const rootElement = document.getElementById('root'); 7 | createRoot(rootElement!).render(); 8 | -------------------------------------------------------------------------------- /sandboxes/bubble/default/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "scripts": { 4 | "start": "vite" 5 | }, 6 | "dependencies": { 7 | "chart.js": "^4.0.0", 8 | "faker": "5.5.3", 9 | "react": "18.2.0", 10 | "react-chartjs-2": "^5.0.0", 11 | "react-dom": "18.2.0" 12 | }, 13 | "devDependencies": { 14 | "@types/faker": "5.5.9", 15 | "@types/react": "18.0.26", 16 | "@types/react-dom": "18.0.10", 17 | "@vitejs/plugin-react": "^4.0.0", 18 | "typescript": "4.9.5", 19 | "vite": "^6.0.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /sandboxes/bubble/default/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | export default defineConfig({ 5 | plugins: [react()], 6 | }); 7 | -------------------------------------------------------------------------------- /sandboxes/chart/canvas/App.tsx: -------------------------------------------------------------------------------- 1 | import React, { useRef, useEffect, useState } from 'react'; 2 | import type { ChartData, ChartArea } from 'chart.js'; 3 | import { 4 | Chart as ChartJS, 5 | CategoryScale, 6 | LinearScale, 7 | PointElement, 8 | LineElement, 9 | Tooltip, 10 | Legend, 11 | } from 'chart.js'; 12 | import { Chart } from 'react-chartjs-2'; 13 | import faker from 'faker'; 14 | 15 | ChartJS.register( 16 | CategoryScale, 17 | LinearScale, 18 | PointElement, 19 | LineElement, 20 | Tooltip, 21 | Legend 22 | ); 23 | 24 | const labels = ['January', 'February', 'March', 'April', 'May', 'June', 'July']; 25 | const colors = [ 26 | 'red', 27 | 'orange', 28 | 'yellow', 29 | 'lime', 30 | 'green', 31 | 'teal', 32 | 'blue', 33 | 'purple', 34 | ]; 35 | 36 | export const data = { 37 | labels, 38 | datasets: [ 39 | { 40 | label: 'Dataset 1', 41 | data: labels.map(() => faker.datatype.number({ min: -1000, max: 1000 })), 42 | }, 43 | { 44 | label: 'Dataset 2', 45 | data: labels.map(() => faker.datatype.number({ min: -1000, max: 1000 })), 46 | }, 47 | ], 48 | }; 49 | 50 | function createGradient(ctx: CanvasRenderingContext2D, area: ChartArea) { 51 | const colorStart = faker.random.arrayElement(colors); 52 | const colorMid = faker.random.arrayElement( 53 | colors.filter(color => color !== colorStart) 54 | ); 55 | const colorEnd = faker.random.arrayElement( 56 | colors.filter(color => color !== colorStart && color !== colorMid) 57 | ); 58 | 59 | const gradient = ctx.createLinearGradient(0, area.bottom, 0, area.top); 60 | 61 | gradient.addColorStop(0, colorStart); 62 | gradient.addColorStop(0.5, colorMid); 63 | gradient.addColorStop(1, colorEnd); 64 | 65 | return gradient; 66 | } 67 | 68 | export function App() { 69 | const chartRef = useRef(null); 70 | const [chartData, setChartData] = useState>({ 71 | datasets: [], 72 | }); 73 | 74 | useEffect(() => { 75 | const chart = chartRef.current; 76 | 77 | if (!chart) { 78 | return; 79 | } 80 | 81 | const chartData = { 82 | ...data, 83 | datasets: data.datasets.map(dataset => ({ 84 | ...dataset, 85 | borderColor: createGradient(chart.ctx, chart.chartArea), 86 | })), 87 | }; 88 | 89 | setChartData(chartData); 90 | }, []); 91 | 92 | return ; 93 | } 94 | -------------------------------------------------------------------------------- /sandboxes/chart/canvas/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /sandboxes/chart/canvas/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import { App } from './App.js'; 5 | 6 | const rootElement = document.getElementById('root'); 7 | createRoot(rootElement!).render(); 8 | -------------------------------------------------------------------------------- /sandboxes/chart/canvas/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "scripts": { 4 | "start": "vite" 5 | }, 6 | "dependencies": { 7 | "chart.js": "^4.0.0", 8 | "faker": "5.5.3", 9 | "react": "18.2.0", 10 | "react-chartjs-2": "^5.0.0", 11 | "react-dom": "18.2.0" 12 | }, 13 | "devDependencies": { 14 | "@types/faker": "5.5.9", 15 | "@types/react": "18.0.26", 16 | "@types/react-dom": "18.0.10", 17 | "@vitejs/plugin-react": "^4.0.0", 18 | "typescript": "4.9.5", 19 | "vite": "^6.0.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /sandboxes/chart/canvas/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | export default defineConfig({ 5 | plugins: [react()], 6 | }); 7 | -------------------------------------------------------------------------------- /sandboxes/chart/events/App.tsx: -------------------------------------------------------------------------------- 1 | import React, { type MouseEvent, useRef } from 'react'; 2 | import type { InteractionItem } from 'chart.js'; 3 | import { 4 | Chart as ChartJS, 5 | LinearScale, 6 | CategoryScale, 7 | BarElement, 8 | PointElement, 9 | LineElement, 10 | Legend, 11 | Tooltip, 12 | } from 'chart.js'; 13 | import { 14 | Chart, 15 | getDatasetAtEvent, 16 | getElementAtEvent, 17 | getElementsAtEvent, 18 | } from 'react-chartjs-2'; 19 | import faker from 'faker'; 20 | 21 | ChartJS.register( 22 | LinearScale, 23 | CategoryScale, 24 | BarElement, 25 | PointElement, 26 | LineElement, 27 | Legend, 28 | Tooltip 29 | ); 30 | 31 | export const options = { 32 | scales: { 33 | y: { 34 | beginAtZero: true, 35 | }, 36 | }, 37 | }; 38 | 39 | const labels = ['January', 'February', 'March', 'April', 'May', 'June', 'July']; 40 | 41 | export const data = { 42 | labels, 43 | datasets: [ 44 | { 45 | type: 'line' as const, 46 | label: 'Dataset 1', 47 | borderColor: 'rgb(255, 99, 132)', 48 | borderWidth: 2, 49 | fill: false, 50 | data: labels.map(() => faker.datatype.number({ min: -1000, max: 1000 })), 51 | }, 52 | { 53 | type: 'bar' as const, 54 | label: 'Dataset 2', 55 | backgroundColor: 'rgb(75, 192, 192)', 56 | data: labels.map(() => faker.datatype.number({ min: -1000, max: 1000 })), 57 | borderColor: 'white', 58 | borderWidth: 2, 59 | }, 60 | { 61 | type: 'bar' as const, 62 | label: 'Dataset 3', 63 | backgroundColor: 'rgb(53, 162, 235)', 64 | data: labels.map(() => faker.datatype.number({ min: -1000, max: 1000 })), 65 | }, 66 | ], 67 | }; 68 | 69 | export function App() { 70 | const printDatasetAtEvent = (dataset: InteractionItem[]) => { 71 | if (!dataset.length) return; 72 | 73 | const datasetIndex = dataset[0].datasetIndex; 74 | 75 | console.log(data.datasets[datasetIndex].label); 76 | }; 77 | 78 | const printElementAtEvent = (element: InteractionItem[]) => { 79 | if (!element.length) return; 80 | 81 | const { datasetIndex, index } = element[0]; 82 | 83 | console.log(data.labels[index], data.datasets[datasetIndex].data[index]); 84 | }; 85 | 86 | const printElementsAtEvent = (elements: InteractionItem[]) => { 87 | if (!elements.length) return; 88 | 89 | console.log(elements.length); 90 | }; 91 | 92 | const chartRef = useRef(null); 93 | 94 | const onClick = (event: MouseEvent) => { 95 | const { current: chart } = chartRef; 96 | 97 | if (!chart) { 98 | return; 99 | } 100 | 101 | printDatasetAtEvent(getDatasetAtEvent(chart, event)); 102 | printElementAtEvent(getElementAtEvent(chart, event)); 103 | printElementsAtEvent(getElementsAtEvent(chart, event)); 104 | }; 105 | 106 | return ( 107 | 114 | ); 115 | } 116 | -------------------------------------------------------------------------------- /sandboxes/chart/events/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /sandboxes/chart/events/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import { App } from './App.js'; 5 | 6 | const rootElement = document.getElementById('root'); 7 | createRoot(rootElement!).render(); 8 | -------------------------------------------------------------------------------- /sandboxes/chart/events/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "scripts": { 4 | "start": "vite" 5 | }, 6 | "dependencies": { 7 | "chart.js": "^4.0.0", 8 | "faker": "5.5.3", 9 | "react": "18.2.0", 10 | "react-chartjs-2": "^5.0.0", 11 | "react-dom": "18.2.0" 12 | }, 13 | "devDependencies": { 14 | "@types/faker": "5.5.9", 15 | "@types/react": "18.0.26", 16 | "@types/react-dom": "18.0.10", 17 | "@vitejs/plugin-react": "^4.0.0", 18 | "typescript": "4.9.5", 19 | "vite": "^6.0.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /sandboxes/chart/events/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | export default defineConfig({ 5 | plugins: [react()], 6 | }); 7 | -------------------------------------------------------------------------------- /sandboxes/chart/multitype/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | Chart as ChartJS, 4 | LinearScale, 5 | CategoryScale, 6 | BarElement, 7 | PointElement, 8 | LineElement, 9 | Legend, 10 | Tooltip, 11 | LineController, 12 | BarController, 13 | } from 'chart.js'; 14 | import { Chart } from 'react-chartjs-2'; 15 | import faker from 'faker'; 16 | 17 | ChartJS.register( 18 | LinearScale, 19 | CategoryScale, 20 | BarElement, 21 | PointElement, 22 | LineElement, 23 | Legend, 24 | Tooltip, 25 | LineController, 26 | BarController 27 | ); 28 | 29 | const labels = ['January', 'February', 'March', 'April', 'May', 'June', 'July']; 30 | 31 | export const data = { 32 | labels, 33 | datasets: [ 34 | { 35 | type: 'line' as const, 36 | label: 'Dataset 1', 37 | borderColor: 'rgb(255, 99, 132)', 38 | borderWidth: 2, 39 | fill: false, 40 | data: labels.map(() => faker.datatype.number({ min: -1000, max: 1000 })), 41 | }, 42 | { 43 | type: 'bar' as const, 44 | label: 'Dataset 2', 45 | backgroundColor: 'rgb(75, 192, 192)', 46 | data: labels.map(() => faker.datatype.number({ min: -1000, max: 1000 })), 47 | borderColor: 'white', 48 | borderWidth: 2, 49 | }, 50 | { 51 | type: 'bar' as const, 52 | label: 'Dataset 3', 53 | backgroundColor: 'rgb(53, 162, 235)', 54 | data: labels.map(() => faker.datatype.number({ min: -1000, max: 1000 })), 55 | }, 56 | ], 57 | }; 58 | 59 | export function App() { 60 | return ; 61 | } 62 | -------------------------------------------------------------------------------- /sandboxes/chart/multitype/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /sandboxes/chart/multitype/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import { App } from './App.js'; 5 | 6 | const rootElement = document.getElementById('root'); 7 | createRoot(rootElement!).render(); 8 | -------------------------------------------------------------------------------- /sandboxes/chart/multitype/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "scripts": { 4 | "start": "vite" 5 | }, 6 | "dependencies": { 7 | "chart.js": "^4.0.0", 8 | "faker": "5.5.3", 9 | "react": "18.2.0", 10 | "react-chartjs-2": "^5.0.0", 11 | "react-dom": "18.2.0" 12 | }, 13 | "devDependencies": { 14 | "@types/faker": "5.5.9", 15 | "@types/react": "18.0.26", 16 | "@types/react-dom": "18.0.10", 17 | "@vitejs/plugin-react": "^4.0.0", 18 | "typescript": "4.9.5", 19 | "vite": "^6.0.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /sandboxes/chart/multitype/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | export default defineConfig({ 5 | plugins: [react()], 6 | }); 7 | -------------------------------------------------------------------------------- /sandboxes/chart/ref/App.tsx: -------------------------------------------------------------------------------- 1 | import React, { useRef, useEffect } from 'react'; 2 | import { 3 | Chart as ChartJS, 4 | LinearScale, 5 | CategoryScale, 6 | BarElement, 7 | PointElement, 8 | LineElement, 9 | Legend, 10 | Tooltip, 11 | } from 'chart.js'; 12 | import { Chart } from 'react-chartjs-2'; 13 | import faker from 'faker'; 14 | 15 | ChartJS.register( 16 | LinearScale, 17 | CategoryScale, 18 | BarElement, 19 | PointElement, 20 | LineElement, 21 | Legend, 22 | Tooltip 23 | ); 24 | 25 | const labels = ['January', 'February', 'March', 'April', 'May', 'June', 'July']; 26 | 27 | export const data = { 28 | labels, 29 | datasets: [ 30 | { 31 | type: 'line' as const, 32 | label: 'Dataset 1', 33 | borderColor: 'rgb(255, 99, 132)', 34 | borderWidth: 2, 35 | fill: false, 36 | data: labels.map(() => faker.datatype.number({ min: -1000, max: 1000 })), 37 | }, 38 | { 39 | type: 'bar' as const, 40 | label: 'Dataset 2', 41 | backgroundColor: 'rgb(75, 192, 192)', 42 | data: labels.map(() => faker.datatype.number({ min: -1000, max: 1000 })), 43 | borderColor: 'white', 44 | borderWidth: 2, 45 | }, 46 | { 47 | type: 'bar' as const, 48 | label: 'Dataset 3', 49 | backgroundColor: 'rgb(53, 162, 235)', 50 | data: labels.map(() => faker.datatype.number({ min: -1000, max: 1000 })), 51 | }, 52 | ], 53 | }; 54 | 55 | function triggerTooltip(chart: ChartJS | null) { 56 | const tooltip = chart?.tooltip; 57 | 58 | if (!tooltip) { 59 | return; 60 | } 61 | 62 | if (tooltip.getActiveElements().length > 0) { 63 | tooltip.setActiveElements([], { x: 0, y: 0 }); 64 | } else { 65 | const { chartArea } = chart; 66 | 67 | tooltip.setActiveElements( 68 | [ 69 | { 70 | datasetIndex: 0, 71 | index: 2, 72 | }, 73 | { 74 | datasetIndex: 1, 75 | index: 2, 76 | }, 77 | ], 78 | { 79 | x: (chartArea.left + chartArea.right) / 2, 80 | y: (chartArea.top + chartArea.bottom) / 2, 81 | } 82 | ); 83 | } 84 | 85 | chart.update(); 86 | } 87 | 88 | export function App() { 89 | const chartRef = useRef(null); 90 | 91 | useEffect(() => { 92 | const chart = chartRef.current; 93 | 94 | triggerTooltip(chart); 95 | }, []); 96 | 97 | return ; 98 | } 99 | -------------------------------------------------------------------------------- /sandboxes/chart/ref/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /sandboxes/chart/ref/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import { App } from './App.js'; 5 | 6 | const rootElement = document.getElementById('root'); 7 | createRoot(rootElement!).render(); 8 | -------------------------------------------------------------------------------- /sandboxes/chart/ref/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "scripts": { 4 | "start": "vite" 5 | }, 6 | "dependencies": { 7 | "chart.js": "^4.0.0", 8 | "faker": "5.5.3", 9 | "react": "18.2.0", 10 | "react-chartjs-2": "^5.0.0", 11 | "react-dom": "18.2.0" 12 | }, 13 | "devDependencies": { 14 | "@types/faker": "5.5.9", 15 | "@types/react": "18.0.26", 16 | "@types/react-dom": "18.0.10", 17 | "@vitejs/plugin-react": "^4.0.0", 18 | "typescript": "4.9.5", 19 | "vite": "^6.0.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /sandboxes/chart/ref/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | export default defineConfig({ 5 | plugins: [react()], 6 | }); 7 | -------------------------------------------------------------------------------- /sandboxes/doughnut/default/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Chart as ChartJS, ArcElement, Tooltip, Legend } from 'chart.js'; 3 | import { Doughnut } from 'react-chartjs-2'; 4 | 5 | ChartJS.register(ArcElement, Tooltip, Legend); 6 | 7 | export const data = { 8 | labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'], 9 | datasets: [ 10 | { 11 | label: '# of Votes', 12 | data: [12, 19, 3, 5, 2, 3], 13 | backgroundColor: [ 14 | 'rgba(255, 99, 132, 0.2)', 15 | 'rgba(54, 162, 235, 0.2)', 16 | 'rgba(255, 206, 86, 0.2)', 17 | 'rgba(75, 192, 192, 0.2)', 18 | 'rgba(153, 102, 255, 0.2)', 19 | 'rgba(255, 159, 64, 0.2)', 20 | ], 21 | borderColor: [ 22 | 'rgba(255, 99, 132, 1)', 23 | 'rgba(54, 162, 235, 1)', 24 | 'rgba(255, 206, 86, 1)', 25 | 'rgba(75, 192, 192, 1)', 26 | 'rgba(153, 102, 255, 1)', 27 | 'rgba(255, 159, 64, 1)', 28 | ], 29 | borderWidth: 1, 30 | }, 31 | ], 32 | }; 33 | 34 | export function App() { 35 | return ; 36 | } 37 | -------------------------------------------------------------------------------- /sandboxes/doughnut/default/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /sandboxes/doughnut/default/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import { App } from './App.js'; 5 | 6 | const rootElement = document.getElementById('root'); 7 | createRoot(rootElement!).render(); 8 | -------------------------------------------------------------------------------- /sandboxes/doughnut/default/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "scripts": { 4 | "start": "vite" 5 | }, 6 | "dependencies": { 7 | "chart.js": "^4.0.0", 8 | "faker": "5.5.3", 9 | "react": "18.2.0", 10 | "react-chartjs-2": "^5.0.0", 11 | "react-dom": "18.2.0" 12 | }, 13 | "devDependencies": { 14 | "@types/faker": "5.5.9", 15 | "@types/react": "18.0.26", 16 | "@types/react-dom": "18.0.10", 17 | "@vitejs/plugin-react": "^4.0.0", 18 | "typescript": "4.9.5", 19 | "vite": "^6.0.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /sandboxes/doughnut/default/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | export default defineConfig({ 5 | plugins: [react()], 6 | }); 7 | -------------------------------------------------------------------------------- /sandboxes/line/area/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | Chart as ChartJS, 4 | CategoryScale, 5 | LinearScale, 6 | PointElement, 7 | LineElement, 8 | Title, 9 | Tooltip, 10 | Filler, 11 | Legend, 12 | } from 'chart.js'; 13 | import { Line } from 'react-chartjs-2'; 14 | import faker from 'faker'; 15 | 16 | ChartJS.register( 17 | CategoryScale, 18 | LinearScale, 19 | PointElement, 20 | LineElement, 21 | Title, 22 | Tooltip, 23 | Filler, 24 | Legend 25 | ); 26 | 27 | export const options = { 28 | responsive: true, 29 | plugins: { 30 | legend: { 31 | position: 'top' as const, 32 | }, 33 | title: { 34 | display: true, 35 | text: 'Chart.js Line Chart', 36 | }, 37 | }, 38 | }; 39 | 40 | const labels = ['January', 'February', 'March', 'April', 'May', 'June', 'July']; 41 | 42 | export const data = { 43 | labels, 44 | datasets: [ 45 | { 46 | fill: true, 47 | label: 'Dataset 2', 48 | data: labels.map(() => faker.datatype.number({ min: 0, max: 1000 })), 49 | borderColor: 'rgb(53, 162, 235)', 50 | backgroundColor: 'rgba(53, 162, 235, 0.5)', 51 | }, 52 | ], 53 | }; 54 | 55 | export function App() { 56 | return ; 57 | } 58 | -------------------------------------------------------------------------------- /sandboxes/line/area/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /sandboxes/line/area/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import { App } from './App.js'; 5 | 6 | const rootElement = document.getElementById('root'); 7 | createRoot(rootElement!).render(); 8 | -------------------------------------------------------------------------------- /sandboxes/line/area/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "scripts": { 4 | "start": "vite" 5 | }, 6 | "dependencies": { 7 | "chart.js": "^4.0.0", 8 | "faker": "5.5.3", 9 | "react": "18.2.0", 10 | "react-chartjs-2": "^5.0.0", 11 | "react-dom": "18.2.0" 12 | }, 13 | "devDependencies": { 14 | "@types/faker": "5.5.9", 15 | "@types/react": "18.0.26", 16 | "@types/react-dom": "18.0.10", 17 | "@vitejs/plugin-react": "^4.0.0", 18 | "typescript": "4.9.5", 19 | "vite": "^6.0.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /sandboxes/line/area/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | export default defineConfig({ 5 | plugins: [react()], 6 | }); 7 | -------------------------------------------------------------------------------- /sandboxes/line/default/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | Chart as ChartJS, 4 | CategoryScale, 5 | LinearScale, 6 | PointElement, 7 | LineElement, 8 | Title, 9 | Tooltip, 10 | Legend, 11 | } from 'chart.js'; 12 | import { Line } from 'react-chartjs-2'; 13 | import faker from 'faker'; 14 | 15 | ChartJS.register( 16 | CategoryScale, 17 | LinearScale, 18 | PointElement, 19 | LineElement, 20 | Title, 21 | Tooltip, 22 | Legend 23 | ); 24 | 25 | export const options = { 26 | responsive: true, 27 | plugins: { 28 | legend: { 29 | position: 'top' as const, 30 | }, 31 | title: { 32 | display: true, 33 | text: 'Chart.js Line Chart', 34 | }, 35 | }, 36 | }; 37 | 38 | const labels = ['January', 'February', 'March', 'April', 'May', 'June', 'July']; 39 | 40 | export const data = { 41 | labels, 42 | datasets: [ 43 | { 44 | label: 'Dataset 1', 45 | data: labels.map(() => faker.datatype.number({ min: -1000, max: 1000 })), 46 | borderColor: 'rgb(255, 99, 132)', 47 | backgroundColor: 'rgba(255, 99, 132, 0.5)', 48 | }, 49 | { 50 | label: 'Dataset 2', 51 | data: labels.map(() => faker.datatype.number({ min: -1000, max: 1000 })), 52 | borderColor: 'rgb(53, 162, 235)', 53 | backgroundColor: 'rgba(53, 162, 235, 0.5)', 54 | }, 55 | ], 56 | }; 57 | 58 | export function App() { 59 | return ; 60 | } 61 | -------------------------------------------------------------------------------- /sandboxes/line/default/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /sandboxes/line/default/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import { App } from './App.js'; 5 | 6 | const rootElement = document.getElementById('root'); 7 | createRoot(rootElement!).render(); 8 | -------------------------------------------------------------------------------- /sandboxes/line/default/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "scripts": { 4 | "start": "vite" 5 | }, 6 | "dependencies": { 7 | "chart.js": "^4.0.0", 8 | "faker": "5.5.3", 9 | "react": "18.2.0", 10 | "react-chartjs-2": "^5.0.0", 11 | "react-dom": "18.2.0" 12 | }, 13 | "devDependencies": { 14 | "@types/faker": "5.5.9", 15 | "@types/react": "18.0.26", 16 | "@types/react-dom": "18.0.10", 17 | "@vitejs/plugin-react": "^4.0.0", 18 | "typescript": "4.9.5", 19 | "vite": "^6.0.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /sandboxes/line/default/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | export default defineConfig({ 5 | plugins: [react()], 6 | }); 7 | -------------------------------------------------------------------------------- /sandboxes/line/multiaxis/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | Chart as ChartJS, 4 | CategoryScale, 5 | LinearScale, 6 | PointElement, 7 | LineElement, 8 | Title, 9 | Tooltip, 10 | Legend, 11 | } from 'chart.js'; 12 | import { Line } from 'react-chartjs-2'; 13 | import faker from 'faker'; 14 | 15 | ChartJS.register( 16 | CategoryScale, 17 | LinearScale, 18 | PointElement, 19 | LineElement, 20 | Title, 21 | Tooltip, 22 | Legend 23 | ); 24 | 25 | export const options = { 26 | responsive: true, 27 | interaction: { 28 | mode: 'index' as const, 29 | intersect: false, 30 | }, 31 | stacked: false, 32 | plugins: { 33 | title: { 34 | display: true, 35 | text: 'Chart.js Line Chart - Multi Axis', 36 | }, 37 | }, 38 | scales: { 39 | y: { 40 | type: 'linear' as const, 41 | display: true, 42 | position: 'left' as const, 43 | }, 44 | y1: { 45 | type: 'linear' as const, 46 | display: true, 47 | position: 'right' as const, 48 | grid: { 49 | drawOnChartArea: false, 50 | }, 51 | }, 52 | }, 53 | }; 54 | 55 | const labels = ['January', 'February', 'March', 'April', 'May', 'June', 'July']; 56 | 57 | export const data = { 58 | labels, 59 | datasets: [ 60 | { 61 | label: 'Dataset 1', 62 | data: labels.map(() => faker.datatype.number({ min: -1000, max: 1000 })), 63 | borderColor: 'rgb(255, 99, 132)', 64 | backgroundColor: 'rgba(255, 99, 132, 0.5)', 65 | yAxisID: 'y', 66 | }, 67 | { 68 | label: 'Dataset 2', 69 | data: labels.map(() => faker.datatype.number({ min: -1000, max: 1000 })), 70 | borderColor: 'rgb(53, 162, 235)', 71 | backgroundColor: 'rgba(53, 162, 235, 0.5)', 72 | yAxisID: 'y1', 73 | }, 74 | ], 75 | }; 76 | 77 | export function App() { 78 | return ; 79 | } 80 | -------------------------------------------------------------------------------- /sandboxes/line/multiaxis/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /sandboxes/line/multiaxis/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import { App } from './App.js'; 5 | 6 | const rootElement = document.getElementById('root'); 7 | createRoot(rootElement!).render(); 8 | -------------------------------------------------------------------------------- /sandboxes/line/multiaxis/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "scripts": { 4 | "start": "vite" 5 | }, 6 | "dependencies": { 7 | "chart.js": "^4.0.0", 8 | "faker": "5.5.3", 9 | "react": "18.2.0", 10 | "react-chartjs-2": "^5.0.0", 11 | "react-dom": "18.2.0" 12 | }, 13 | "devDependencies": { 14 | "@types/faker": "5.5.9", 15 | "@types/react": "18.0.26", 16 | "@types/react-dom": "18.0.10", 17 | "@vitejs/plugin-react": "^4.0.0", 18 | "typescript": "4.9.5", 19 | "vite": "^6.0.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /sandboxes/line/multiaxis/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | export default defineConfig({ 5 | plugins: [react()], 6 | }); 7 | -------------------------------------------------------------------------------- /sandboxes/pie/default/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Chart as ChartJS, ArcElement, Tooltip, Legend } from 'chart.js'; 3 | import { Pie } from 'react-chartjs-2'; 4 | 5 | ChartJS.register(ArcElement, Tooltip, Legend); 6 | 7 | export const data = { 8 | labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'], 9 | datasets: [ 10 | { 11 | label: '# of Votes', 12 | data: [12, 19, 3, 5, 2, 3], 13 | backgroundColor: [ 14 | 'rgba(255, 99, 132, 0.2)', 15 | 'rgba(54, 162, 235, 0.2)', 16 | 'rgba(255, 206, 86, 0.2)', 17 | 'rgba(75, 192, 192, 0.2)', 18 | 'rgba(153, 102, 255, 0.2)', 19 | 'rgba(255, 159, 64, 0.2)', 20 | ], 21 | borderColor: [ 22 | 'rgba(255, 99, 132, 1)', 23 | 'rgba(54, 162, 235, 1)', 24 | 'rgba(255, 206, 86, 1)', 25 | 'rgba(75, 192, 192, 1)', 26 | 'rgba(153, 102, 255, 1)', 27 | 'rgba(255, 159, 64, 1)', 28 | ], 29 | borderWidth: 1, 30 | }, 31 | ], 32 | }; 33 | 34 | export function App() { 35 | return ; 36 | } 37 | -------------------------------------------------------------------------------- /sandboxes/pie/default/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /sandboxes/pie/default/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import { App } from './App.js'; 5 | 6 | const rootElement = document.getElementById('root'); 7 | createRoot(rootElement!).render(); 8 | -------------------------------------------------------------------------------- /sandboxes/pie/default/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "scripts": { 4 | "start": "vite" 5 | }, 6 | "dependencies": { 7 | "chart.js": "^4.0.0", 8 | "faker": "5.5.3", 9 | "react": "18.2.0", 10 | "react-chartjs-2": "^5.0.0", 11 | "react-dom": "18.2.0" 12 | }, 13 | "devDependencies": { 14 | "@types/faker": "5.5.9", 15 | "@types/react": "18.0.26", 16 | "@types/react-dom": "18.0.10", 17 | "@vitejs/plugin-react": "^4.0.0", 18 | "typescript": "4.9.5", 19 | "vite": "^6.0.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /sandboxes/pie/default/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | export default defineConfig({ 5 | plugins: [react()], 6 | }); 7 | -------------------------------------------------------------------------------- /sandboxes/polarArea/default/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | Chart as ChartJS, 4 | RadialLinearScale, 5 | ArcElement, 6 | Tooltip, 7 | Legend, 8 | } from 'chart.js'; 9 | import { PolarArea } from 'react-chartjs-2'; 10 | 11 | ChartJS.register(RadialLinearScale, ArcElement, Tooltip, Legend); 12 | 13 | export const data = { 14 | labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'], 15 | datasets: [ 16 | { 17 | label: '# of Votes', 18 | data: [12, 19, 3, 5, 2, 3], 19 | backgroundColor: [ 20 | 'rgba(255, 99, 132, 0.5)', 21 | 'rgba(54, 162, 235, 0.5)', 22 | 'rgba(255, 206, 86, 0.5)', 23 | 'rgba(75, 192, 192, 0.5)', 24 | 'rgba(153, 102, 255, 0.5)', 25 | 'rgba(255, 159, 64, 0.5)', 26 | ], 27 | borderWidth: 1, 28 | }, 29 | ], 30 | }; 31 | 32 | export function App() { 33 | return ; 34 | } 35 | -------------------------------------------------------------------------------- /sandboxes/polarArea/default/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /sandboxes/polarArea/default/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import { App } from './App.js'; 5 | 6 | const rootElement = document.getElementById('root'); 7 | createRoot(rootElement!).render(); 8 | -------------------------------------------------------------------------------- /sandboxes/polarArea/default/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "scripts": { 4 | "start": "vite" 5 | }, 6 | "dependencies": { 7 | "chart.js": "^4.0.0", 8 | "faker": "5.5.3", 9 | "react": "18.2.0", 10 | "react-chartjs-2": "^5.0.0", 11 | "react-dom": "18.2.0" 12 | }, 13 | "devDependencies": { 14 | "@types/faker": "5.5.9", 15 | "@types/react": "18.0.26", 16 | "@types/react-dom": "18.0.10", 17 | "@vitejs/plugin-react": "^4.0.0", 18 | "typescript": "4.9.5", 19 | "vite": "^6.0.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /sandboxes/polarArea/default/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | export default defineConfig({ 5 | plugins: [react()], 6 | }); 7 | -------------------------------------------------------------------------------- /sandboxes/radar/default/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | Chart as ChartJS, 4 | RadialLinearScale, 5 | PointElement, 6 | LineElement, 7 | Filler, 8 | Tooltip, 9 | Legend, 10 | } from 'chart.js'; 11 | import { Radar } from 'react-chartjs-2'; 12 | 13 | ChartJS.register( 14 | RadialLinearScale, 15 | PointElement, 16 | LineElement, 17 | Filler, 18 | Tooltip, 19 | Legend 20 | ); 21 | 22 | export const data = { 23 | labels: ['Thing 1', 'Thing 2', 'Thing 3', 'Thing 4', 'Thing 5', 'Thing 6'], 24 | datasets: [ 25 | { 26 | label: '# of Votes', 27 | data: [2, 9, 3, 5, 2, 3], 28 | backgroundColor: 'rgba(255, 99, 132, 0.2)', 29 | borderColor: 'rgba(255, 99, 132, 1)', 30 | borderWidth: 1, 31 | }, 32 | ], 33 | }; 34 | 35 | export function App() { 36 | return ; 37 | } 38 | -------------------------------------------------------------------------------- /sandboxes/radar/default/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /sandboxes/radar/default/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import { App } from './App.js'; 5 | 6 | const rootElement = document.getElementById('root'); 7 | createRoot(rootElement!).render(); 8 | -------------------------------------------------------------------------------- /sandboxes/radar/default/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "scripts": { 4 | "start": "vite" 5 | }, 6 | "dependencies": { 7 | "chart.js": "^4.0.0", 8 | "faker": "5.5.3", 9 | "react": "18.2.0", 10 | "react-chartjs-2": "^5.0.0", 11 | "react-dom": "18.2.0" 12 | }, 13 | "devDependencies": { 14 | "@types/faker": "5.5.9", 15 | "@types/react": "18.0.26", 16 | "@types/react-dom": "18.0.10", 17 | "@vitejs/plugin-react": "^4.0.0", 18 | "typescript": "4.9.5", 19 | "vite": "^6.0.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /sandboxes/radar/default/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | export default defineConfig({ 5 | plugins: [react()], 6 | }); 7 | -------------------------------------------------------------------------------- /sandboxes/scatter/default/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | Chart as ChartJS, 4 | LinearScale, 5 | PointElement, 6 | LineElement, 7 | Tooltip, 8 | Legend, 9 | } from 'chart.js'; 10 | import { Scatter } from 'react-chartjs-2'; 11 | import faker from 'faker'; 12 | 13 | ChartJS.register(LinearScale, PointElement, LineElement, Tooltip, Legend); 14 | 15 | export const options = { 16 | scales: { 17 | y: { 18 | beginAtZero: true, 19 | }, 20 | }, 21 | }; 22 | 23 | export const data = { 24 | datasets: [ 25 | { 26 | label: 'A dataset', 27 | data: Array.from({ length: 100 }, () => ({ 28 | x: faker.datatype.number({ min: -100, max: 100 }), 29 | y: faker.datatype.number({ min: -100, max: 100 }), 30 | })), 31 | backgroundColor: 'rgba(255, 99, 132, 1)', 32 | }, 33 | ], 34 | }; 35 | 36 | export function App() { 37 | return ; 38 | } 39 | -------------------------------------------------------------------------------- /sandboxes/scatter/default/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /sandboxes/scatter/default/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import { App } from './App.js'; 5 | 6 | const rootElement = document.getElementById('root'); 7 | createRoot(rootElement!).render(); 8 | -------------------------------------------------------------------------------- /sandboxes/scatter/default/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "scripts": { 4 | "start": "vite" 5 | }, 6 | "dependencies": { 7 | "chart.js": "^4.0.0", 8 | "faker": "5.5.3", 9 | "react": "18.2.0", 10 | "react-chartjs-2": "^5.0.0", 11 | "react-dom": "18.2.0" 12 | }, 13 | "devDependencies": { 14 | "@types/faker": "5.5.9", 15 | "@types/react": "18.0.26", 16 | "@types/react-dom": "18.0.10", 17 | "@vitejs/plugin-react": "^4.0.0", 18 | "typescript": "4.9.5", 19 | "vite": "^6.0.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /sandboxes/scatter/default/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | export default defineConfig({ 5 | plugins: [react()], 6 | }); 7 | -------------------------------------------------------------------------------- /sandboxes/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "paths": { 6 | "react-chartjs-2": ["../src"] 7 | } 8 | }, 9 | "include": ["."] 10 | } 11 | -------------------------------------------------------------------------------- /src/chart.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useRef, forwardRef } from 'react'; 2 | import { Chart as ChartJS } from 'chart.js'; 3 | import type { ChartType, DefaultDataPoint } from 'chart.js'; 4 | 5 | import type { ForwardedRef, ChartProps, BaseChartComponent } from './types.js'; 6 | import { 7 | reforwardRef, 8 | cloneData, 9 | setOptions, 10 | setLabels, 11 | setDatasets, 12 | } from './utils.js'; 13 | 14 | function ChartComponent< 15 | TType extends ChartType = ChartType, 16 | TData = DefaultDataPoint, 17 | TLabel = unknown, 18 | >( 19 | props: ChartProps, 20 | ref: ForwardedRef> 21 | ) { 22 | const { 23 | height = 150, 24 | width = 300, 25 | redraw = false, 26 | datasetIdKey, 27 | type, 28 | data, 29 | options, 30 | plugins = [], 31 | fallbackContent, 32 | updateMode, 33 | ...canvasProps 34 | } = props; 35 | const canvasRef = useRef(null); 36 | const chartRef = useRef | null>(null); 37 | 38 | const renderChart = () => { 39 | if (!canvasRef.current) return; 40 | 41 | chartRef.current = new ChartJS(canvasRef.current, { 42 | type, 43 | data: cloneData(data, datasetIdKey), 44 | options: options && { ...options }, 45 | plugins, 46 | }); 47 | 48 | reforwardRef(ref, chartRef.current); 49 | }; 50 | 51 | const destroyChart = () => { 52 | reforwardRef(ref, null); 53 | 54 | if (chartRef.current) { 55 | chartRef.current.destroy(); 56 | chartRef.current = null; 57 | } 58 | }; 59 | 60 | useEffect(() => { 61 | if (!redraw && chartRef.current && options) { 62 | setOptions(chartRef.current, options); 63 | } 64 | }, [redraw, options]); 65 | 66 | useEffect(() => { 67 | if (!redraw && chartRef.current) { 68 | setLabels(chartRef.current.config.data, data.labels); 69 | } 70 | }, [redraw, data.labels]); 71 | 72 | useEffect(() => { 73 | if (!redraw && chartRef.current && data.datasets) { 74 | setDatasets(chartRef.current.config.data, data.datasets, datasetIdKey); 75 | } 76 | }, [redraw, data.datasets]); 77 | 78 | useEffect(() => { 79 | if (!chartRef.current) return; 80 | 81 | if (redraw) { 82 | destroyChart(); 83 | setTimeout(renderChart); 84 | } else { 85 | chartRef.current.update(updateMode); 86 | } 87 | }, [redraw, options, data.labels, data.datasets, updateMode]); 88 | 89 | useEffect(() => { 90 | if (!chartRef.current) return; 91 | 92 | destroyChart(); 93 | setTimeout(renderChart); 94 | }, [type]); 95 | 96 | useEffect(() => { 97 | renderChart(); 98 | 99 | return () => destroyChart(); 100 | }, []); 101 | 102 | return ( 103 | 110 | {fallbackContent} 111 | 112 | ); 113 | } 114 | 115 | export const Chart = forwardRef(ChartComponent) as BaseChartComponent; 116 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export type { ChartProps } from './types.js'; 2 | export * from './chart.js'; 3 | export * from './typedCharts.js'; 4 | export { 5 | getDatasetAtEvent, 6 | getElementAtEvent, 7 | getElementsAtEvent, 8 | } from './utils.js'; 9 | -------------------------------------------------------------------------------- /src/typedCharts.tsx: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from 'react'; 2 | import { 3 | Chart as ChartJS, 4 | LineController, 5 | BarController, 6 | RadarController, 7 | DoughnutController, 8 | PolarAreaController, 9 | BubbleController, 10 | PieController, 11 | ScatterController, 12 | } from 'chart.js'; 13 | import type { ChartType, ChartComponentLike } from 'chart.js'; 14 | 15 | import type { 16 | ChartProps, 17 | ChartJSOrUndefined, 18 | TypedChartComponent, 19 | } from './types.js'; 20 | import { Chart } from './chart.js'; 21 | 22 | function createTypedChart( 23 | type: T, 24 | registerables: ChartComponentLike 25 | ) { 26 | ChartJS.register(registerables); 27 | 28 | return forwardRef, Omit, 'type'>>( 29 | (props, ref) => 30 | ) as TypedChartComponent; 31 | } 32 | 33 | export const Line = /* #__PURE__ */ createTypedChart('line', LineController); 34 | 35 | export const Bar = /* #__PURE__ */ createTypedChart('bar', BarController); 36 | 37 | export const Radar = /* #__PURE__ */ createTypedChart('radar', RadarController); 38 | 39 | export const Doughnut = /* #__PURE__ */ createTypedChart( 40 | 'doughnut', 41 | DoughnutController 42 | ); 43 | 44 | export const PolarArea = /* #__PURE__ */ createTypedChart( 45 | 'polarArea', 46 | PolarAreaController 47 | ); 48 | 49 | export const Bubble = /* #__PURE__ */ createTypedChart( 50 | 'bubble', 51 | BubbleController 52 | ); 53 | 54 | export const Pie = /* #__PURE__ */ createTypedChart('pie', PieController); 55 | 56 | export const Scatter = /* #__PURE__ */ createTypedChart( 57 | 'scatter', 58 | ScatterController 59 | ); 60 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | CanvasHTMLAttributes, 3 | MutableRefObject, 4 | ReactNode, 5 | JSX, 6 | } from 'react'; 7 | import type { 8 | Chart, 9 | ChartType, 10 | ChartData, 11 | ChartOptions, 12 | DefaultDataPoint, 13 | Plugin, 14 | UpdateMode, 15 | } from 'chart.js'; 16 | 17 | export type ForwardedRef = 18 | | ((instance: T | null) => void) 19 | | MutableRefObject 20 | | null; 21 | 22 | export interface ChartProps< 23 | TType extends ChartType = ChartType, 24 | TData = DefaultDataPoint, 25 | TLabel = unknown, 26 | > extends CanvasHTMLAttributes { 27 | /** 28 | * Chart.js chart type 29 | */ 30 | type: TType; 31 | /** 32 | * The data object that is passed into the Chart.js chart 33 | * @see https://www.chartjs.org/docs/latest/getting-started/ 34 | */ 35 | data: ChartData; 36 | /** 37 | * The options object that is passed into the Chart.js chart 38 | * @see https://www.chartjs.org/docs/latest/general/options.html 39 | * @default {} 40 | */ 41 | options?: ChartOptions; 42 | /** 43 | * The plugins array that is passed into the Chart.js chart 44 | * @see https://www.chartjs.org/docs/latest/developers/plugins.html 45 | * @default [] 46 | */ 47 | plugins?: Plugin[]; 48 | /** 49 | * Teardown and redraw chart on every update 50 | * @default false 51 | */ 52 | redraw?: boolean; 53 | /** 54 | * Key name to identificate dataset 55 | * @default 'label' 56 | */ 57 | datasetIdKey?: string; 58 | /** 59 | * A fallback for when the canvas cannot be rendered. Can be used for accessible chart descriptions 60 | * @see https://www.chartjs.org/docs/latest/general/accessibility.html 61 | * @default null 62 | * @todo Replace with `children` prop. 63 | */ 64 | fallbackContent?: ReactNode; 65 | /** 66 | * A mode string to indicate transition configuration should be used. 67 | * @see https://www.chartjs.org/docs/latest/developers/api.html#update-mode 68 | */ 69 | updateMode?: UpdateMode; 70 | } 71 | 72 | /** 73 | * @todo Replace `undefined` with `null` 74 | */ 75 | export type ChartJSOrUndefined< 76 | TType extends ChartType = ChartType, 77 | TData = DefaultDataPoint, 78 | TLabel = unknown, 79 | > = Chart | undefined; 80 | 81 | export type BaseChartComponent = < 82 | TType extends ChartType = ChartType, 83 | TData = DefaultDataPoint, 84 | TLabel = unknown, 85 | >( 86 | props: ChartProps & { 87 | ref?: ForwardedRef>; 88 | } 89 | ) => JSX.Element; 90 | 91 | export type TypedChartComponent = < 92 | TData = DefaultDataPoint, 93 | TLabel = unknown, 94 | >( 95 | props: Omit, 'type'> & { 96 | ref?: ForwardedRef>; 97 | } 98 | ) => JSX.Element; 99 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | import type { MouseEvent } from 'react'; 2 | import type { 3 | ChartType, 4 | ChartData, 5 | DefaultDataPoint, 6 | ChartDataset, 7 | ChartOptions, 8 | Chart, 9 | } from 'chart.js'; 10 | 11 | import type { ForwardedRef } from './types.js'; 12 | 13 | const defaultDatasetIdKey = 'label'; 14 | 15 | export function reforwardRef(ref: ForwardedRef, value: T) { 16 | if (typeof ref === 'function') { 17 | ref(value); 18 | } else if (ref) { 19 | ref.current = value; 20 | } 21 | } 22 | 23 | export function setOptions< 24 | TType extends ChartType = ChartType, 25 | TData = DefaultDataPoint, 26 | TLabel = unknown, 27 | >(chart: Chart, nextOptions: ChartOptions) { 28 | const options = chart.options; 29 | 30 | if (options && nextOptions) { 31 | Object.assign(options, nextOptions); 32 | } 33 | } 34 | 35 | export function setLabels< 36 | TType extends ChartType = ChartType, 37 | TData = DefaultDataPoint, 38 | TLabel = unknown, 39 | >( 40 | currentData: ChartData, 41 | nextLabels: TLabel[] | undefined 42 | ) { 43 | currentData.labels = nextLabels; 44 | } 45 | 46 | export function setDatasets< 47 | TType extends ChartType = ChartType, 48 | TData = DefaultDataPoint, 49 | TLabel = unknown, 50 | >( 51 | currentData: ChartData, 52 | nextDatasets: ChartDataset[], 53 | datasetIdKey = defaultDatasetIdKey 54 | ) { 55 | const addedDatasets: ChartDataset[] = []; 56 | 57 | currentData.datasets = nextDatasets.map( 58 | (nextDataset: Record) => { 59 | // given the new set, find it's current match 60 | const currentDataset = currentData.datasets.find( 61 | (dataset: Record) => 62 | dataset[datasetIdKey] === nextDataset[datasetIdKey] 63 | ); 64 | 65 | // There is no original to update, so simply add new one 66 | if ( 67 | !currentDataset || 68 | !nextDataset.data || 69 | addedDatasets.includes(currentDataset) 70 | ) { 71 | return { ...nextDataset } as ChartDataset; 72 | } 73 | 74 | addedDatasets.push(currentDataset); 75 | 76 | Object.assign(currentDataset, nextDataset); 77 | 78 | return currentDataset; 79 | } 80 | ); 81 | } 82 | 83 | export function cloneData< 84 | TType extends ChartType = ChartType, 85 | TData = DefaultDataPoint, 86 | TLabel = unknown, 87 | >(data: ChartData, datasetIdKey = defaultDatasetIdKey) { 88 | const nextData: ChartData = { 89 | labels: [], 90 | datasets: [], 91 | }; 92 | 93 | setLabels(nextData, data.labels); 94 | setDatasets(nextData, data.datasets, datasetIdKey); 95 | 96 | return nextData; 97 | } 98 | 99 | /** 100 | * Get dataset from mouse click event 101 | * @param chart - Chart.js instance 102 | * @param event - Mouse click event 103 | * @returns Dataset 104 | */ 105 | export function getDatasetAtEvent( 106 | chart: Chart, 107 | event: MouseEvent 108 | ) { 109 | return chart.getElementsAtEventForMode( 110 | event.nativeEvent, 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( 124 | chart: Chart, 125 | event: MouseEvent 126 | ) { 127 | return chart.getElementsAtEventForMode( 128 | event.nativeEvent, 129 | 'nearest', 130 | { intersect: true }, 131 | false 132 | ); 133 | } 134 | 135 | /** 136 | * Get all dataset elements from mouse click event 137 | * @param chart - Chart.js instance 138 | * @param event - Mouse click event 139 | * @returns Dataset 140 | */ 141 | export function getElementsAtEvent( 142 | chart: Chart, 143 | event: MouseEvent 144 | ) { 145 | return chart.getElementsAtEventForMode( 146 | event.nativeEvent, 147 | 'index', 148 | { intersect: true }, 149 | false 150 | ); 151 | } 152 | -------------------------------------------------------------------------------- /stories/Bar.stories.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import 'chart.js/auto'; 3 | import { Bar } from '../src'; 4 | import * as verticalBar from '../sandboxes/bar/vertical/App'; 5 | import * as horizontalBar from '../sandboxes/bar/horizontal/App'; 6 | import * as stackedBar from '../sandboxes/bar/stacked/App'; 7 | import * as groupedBar from '../sandboxes/bar/grouped/App'; 8 | 9 | export default { 10 | title: 'Components/Bar', 11 | component: Bar, 12 | parameters: { 13 | layout: 'centered', 14 | }, 15 | args: { 16 | width: 500, 17 | height: 400, 18 | }, 19 | }; 20 | 21 | export const Vertical = args => ; 22 | 23 | Vertical.args = { 24 | data: verticalBar.data, 25 | options: verticalBar.options, 26 | }; 27 | 28 | export const Horizontal = args => ; 29 | 30 | Horizontal.args = { 31 | data: horizontalBar.data, 32 | options: horizontalBar.options, 33 | }; 34 | 35 | export const Stacked = args => ; 36 | 37 | Stacked.args = { 38 | data: stackedBar.data, 39 | options: stackedBar.options, 40 | }; 41 | 42 | export const Grouped = args => ; 43 | 44 | Grouped.args = { 45 | data: groupedBar.data, 46 | options: groupedBar.options, 47 | }; 48 | -------------------------------------------------------------------------------- /stories/Bubble.stories.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import 'chart.js/auto'; 3 | import { Bubble } from '../src'; 4 | import { data, options } from '../sandboxes/bubble/default/App'; 5 | 6 | export default { 7 | title: 'Components/Bubble', 8 | component: Bubble, 9 | parameters: { 10 | layout: 'centered', 11 | }, 12 | args: { 13 | width: 500, 14 | height: 400, 15 | }, 16 | }; 17 | 18 | export const Default = args => ; 19 | 20 | Default.args = { 21 | data, 22 | options, 23 | }; 24 | -------------------------------------------------------------------------------- /stories/Chart.data.ts: -------------------------------------------------------------------------------- 1 | import faker from 'faker'; 2 | import { colorRed } from './data'; 3 | 4 | export const dynamicOptions = { 5 | scales: { 6 | y: { 7 | beginAtZero: true, 8 | }, 9 | }, 10 | }; 11 | 12 | export const getDynamicData = () => ({ 13 | labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'], 14 | datasets: [ 15 | { 16 | type: 'bar', 17 | label: 'Scale', 18 | data: Array.from({ length: 6 }, () => 19 | faker.datatype.number({ min: -10, max: 10 }) 20 | ), 21 | backgroundColor: [ 22 | 'rgba(255, 99, 132, 0.2)', 23 | 'rgba(54, 162, 235, 0.2)', 24 | 'rgba(255, 206, 86, 0.2)', 25 | 'rgba(75, 192, 192, 0.2)', 26 | 'rgba(153, 102, 255, 0.2)', 27 | 'rgba(255, 159, 64, 0.2)', 28 | ], 29 | borderColor: [ 30 | 'rgba(255, 99, 132, 1)', 31 | 'rgba(54, 162, 235, 1)', 32 | 'rgba(255, 206, 86, 1)', 33 | 'rgba(75, 192, 192, 1)', 34 | 'rgba(153, 102, 255, 1)', 35 | 'rgba(255, 159, 64, 1)', 36 | ], 37 | borderWidth: 1, 38 | }, 39 | ], 40 | }); 41 | 42 | export const sameData1 = { 43 | labels: [ 44 | 'Jan', 45 | 'Feb', 46 | 'Mar', 47 | 'Apr', 48 | 'Mei', 49 | 'Jun', 50 | 'Jul', 51 | 'Aug', 52 | 'Sep', 53 | 'Oct', 54 | 'Nov', 55 | 'Dec', 56 | ], 57 | datasets: [ 58 | { 59 | label: 'My First dataset', 60 | backgroundColor: 'rgba(75,192,192,0.4)', 61 | data: [33, 53, 85, 41, 44, 65, 61, 47, 52, 53, 62, 82], 62 | }, 63 | { 64 | label: 'My Second dataset', 65 | backgroundColor: '#742774', 66 | data: [33, 25, 35, 51, 54, 76, 65, 40, 42, 39, 51, 55], 67 | }, 68 | ], 69 | }; 70 | 71 | export const sameData2 = { 72 | labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], 73 | datasets: [ 74 | { 75 | label: 'My First dataset', 76 | backgroundColor: 'rgba(75,192,192,0.4)', 77 | data: [42, 13, 45, 29, 44, 25, 27], 78 | }, 79 | { 80 | label: 'My Second dataset', 81 | backgroundColor: '#742774', 82 | data: [33, 25, 35, 44, 50, 40, 48], 83 | }, 84 | ], 85 | }; 86 | 87 | export const decimationOptions = { 88 | // Turn off animations and data parsing for performance 89 | animation: false, 90 | parsing: false, 91 | 92 | interaction: { 93 | mode: 'nearest', 94 | axis: 'x', 95 | intersect: false, 96 | }, 97 | plugins: { 98 | decimation: { 99 | enabled: true, 100 | algorithm: 'lttb', 101 | samples: 500, 102 | }, 103 | }, 104 | scales: { 105 | x: { 106 | type: 'time', 107 | ticks: { 108 | source: 'auto', 109 | // Disabled rotation for performance 110 | maxRotation: 0, 111 | autoSkip: true, 112 | }, 113 | }, 114 | }, 115 | }; 116 | 117 | export const getDecimationData = () => { 118 | const start = Date.now(); 119 | const data = Array.from({ length: 100000 }, (_, i) => ({ 120 | x: start + i * 30000, 121 | y: faker.datatype.number({ min: 0, max: Math.random() < 0.001 ? 100 : 20 }), 122 | })); 123 | 124 | return { 125 | datasets: [ 126 | { 127 | borderColor: colorRed, 128 | borderWidth: 1, 129 | data, 130 | label: 'Large Dataset', 131 | radius: 0, 132 | }, 133 | ], 134 | }; 135 | }; 136 | -------------------------------------------------------------------------------- /stories/Chart.stories.tsx: -------------------------------------------------------------------------------- 1 | import React, { 2 | type MouseEvent, 3 | useRef, 4 | useState, 5 | useEffect, 6 | useReducer, 7 | useMemo, 8 | } from 'react'; 9 | import 'chart.js/auto'; 10 | import type { InteractionItem } from 'chart.js'; 11 | import { Chart as ChartJS } from 'chart.js'; 12 | import 'chartjs-adapter-date-fns'; 13 | import annotationPlugin from 'chartjs-plugin-annotation'; 14 | import zoomPlugin from 'chartjs-plugin-zoom'; 15 | import { 16 | Chart, 17 | getDatasetAtEvent, 18 | getElementAtEvent, 19 | getElementsAtEvent, 20 | } from '../src'; 21 | import * as multitypeChart from '../sandboxes/chart/multitype/App'; 22 | import * as eventsChart from '../sandboxes/chart/events/App'; 23 | import * as data from './Chart.data'; 24 | 25 | ChartJS.register(annotationPlugin, zoomPlugin); 26 | 27 | export default { 28 | title: 'Components/Chart', 29 | component: Chart, 30 | parameters: { 31 | layout: 'centered', 32 | }, 33 | args: { 34 | width: 500, 35 | height: 400, 36 | }, 37 | }; 38 | 39 | export const MultiType = args => ; 40 | 41 | MultiType.args = { 42 | data: multitypeChart.data, 43 | }; 44 | 45 | export const Dynamic = args => { 46 | const [dynamicData, setDynamicData] = useState(data.getDynamicData); 47 | 48 | useEffect(() => { 49 | const interval = setInterval( 50 | () => setDynamicData(data.getDynamicData()), 51 | 3000 52 | ); 53 | 54 | return () => clearInterval(interval); 55 | }, []); 56 | 57 | return ; 58 | }; 59 | 60 | Dynamic.args = { 61 | options: data.dynamicOptions, 62 | }; 63 | 64 | export const ClickEvents = ({ 65 | onDatasetClick, 66 | onElementClick, 67 | onElementsClick, 68 | options, 69 | data, 70 | ...args 71 | }) => { 72 | const datasetAtEvent = (dataset: InteractionItem[]) => { 73 | if (!dataset.length) return; 74 | 75 | const datasetIndex = dataset[0].datasetIndex; 76 | 77 | onDatasetClick(data.datasets[datasetIndex].label); 78 | }; 79 | 80 | const elementAtEvent = (element: InteractionItem[]) => { 81 | if (!element.length) return; 82 | 83 | const { datasetIndex, index } = element[0]; 84 | 85 | onElementClick(data.labels[index], data.datasets[datasetIndex].data[index]); 86 | }; 87 | 88 | const elementsAtEvent = (elements: InteractionItem[]) => { 89 | if (!elements.length) return; 90 | 91 | onElementsClick(elements); 92 | }; 93 | 94 | const chartRef = useRef(null); 95 | 96 | const onClick = (event: MouseEvent) => { 97 | const { current: chart } = chartRef; 98 | 99 | if (!chart) { 100 | return; 101 | } 102 | 103 | datasetAtEvent(getDatasetAtEvent(chart, event)); 104 | elementAtEvent(getElementAtEvent(chart, event)); 105 | elementsAtEvent(getElementsAtEvent(chart, event)); 106 | }; 107 | 108 | return ( 109 | 117 | ); 118 | }; 119 | 120 | ClickEvents.args = { 121 | options: eventsChart.options, 122 | data: eventsChart.data, 123 | }; 124 | 125 | ClickEvents.argTypes = { 126 | onDatasetClick: { action: 'dataset clicked' }, 127 | onElementClick: { action: 'element clicked' }, 128 | onElementsClick: { action: 'elements clicked' }, 129 | }; 130 | 131 | export const Redraw = args => ; 132 | 133 | Redraw.args = { 134 | data: multitypeChart.data, 135 | redraw: true, 136 | }; 137 | 138 | export const SameDataToggle = args => { 139 | const [currentData, toggleData] = useReducer( 140 | prevState => 141 | prevState === data.sameData1 ? data.sameData2 : data.sameData1, 142 | data.sameData1 143 | ); 144 | 145 | return ; 146 | }; 147 | 148 | SameDataToggle.args = { 149 | type: 'bar', 150 | }; 151 | 152 | export const Decimation = args => { 153 | const [currentData, toggleData] = useReducer( 154 | data.getDecimationData, 155 | data.getDecimationData() 156 | ); 157 | 158 | return ; 159 | }; 160 | 161 | Decimation.args = { 162 | type: 'line', 163 | options: data.decimationOptions, 164 | }; 165 | 166 | export const DynamicOptions = args => { 167 | const [yMax, setYMax] = useState(100); 168 | const options = useMemo( 169 | () => ({ 170 | plugins: { 171 | annotation: { 172 | annotations: { 173 | box1: { 174 | type: 'box', 175 | xMin: 1, 176 | xMax: 2, 177 | yMin: 50, 178 | yMax: yMax, 179 | backgroundColor: 'rgba(255, 99, 132, 0.25)', 180 | }, 181 | }, 182 | }, 183 | zoom: { 184 | zoom: { 185 | wheel: { 186 | enabled: true, 187 | }, 188 | pinch: { 189 | enabled: true, 190 | }, 191 | mode: 'xy', 192 | }, 193 | }, 194 | }, 195 | }), 196 | [yMax] 197 | ); 198 | 199 | return ( 200 | <> 201 | 202 | 203 | 204 | ); 205 | }; 206 | 207 | DynamicOptions.args = { 208 | data: multitypeChart.data, 209 | }; 210 | -------------------------------------------------------------------------------- /stories/Doughnut.stories.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import 'chart.js/auto'; 3 | import { Doughnut } from '../src'; 4 | import { data } from '../sandboxes/doughnut/default/App'; 5 | 6 | export default { 7 | title: 'Components/Doughnut', 8 | component: Doughnut, 9 | parameters: { 10 | layout: 'centered', 11 | }, 12 | args: { 13 | width: 500, 14 | height: 400, 15 | }, 16 | }; 17 | 18 | export const Default = args => ; 19 | 20 | Default.args = { 21 | data, 22 | }; 23 | 24 | export const Rotation = args => { 25 | const [rotation, setRotation] = useState(0); 26 | 27 | useEffect(() => { 28 | const interval = setInterval(() => { 29 | setRotation(rotation => rotation + 90); 30 | }, 3000); 31 | 32 | return () => clearInterval(interval); 33 | }); 34 | 35 | return ; 36 | }; 37 | 38 | Rotation.args = { 39 | data, 40 | }; 41 | -------------------------------------------------------------------------------- /stories/Line.stories.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import 'chart.js/auto'; 3 | import { Line } from '../src'; 4 | import * as defaultLine from '../sandboxes/line/default/App'; 5 | import * as multiaxisLine from '../sandboxes/line/multiaxis/App'; 6 | 7 | export default { 8 | title: 'Components/Line', 9 | component: Line, 10 | parameters: { 11 | layout: 'centered', 12 | }, 13 | args: { 14 | width: 500, 15 | height: 400, 16 | }, 17 | }; 18 | 19 | export const Default = args => ; 20 | 21 | Default.args = { 22 | data: defaultLine.data, 23 | options: defaultLine.options, 24 | }; 25 | 26 | export const MultiAxis = args => ; 27 | 28 | MultiAxis.args = { 29 | data: multiaxisLine.data, 30 | options: multiaxisLine.options, 31 | }; 32 | -------------------------------------------------------------------------------- /stories/Pie.stories.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import faker from 'faker'; 3 | import 'chart.js/auto'; 4 | import { Pie } from '../src'; 5 | import { data } from '../sandboxes/pie/default/App'; 6 | 7 | export default { 8 | title: 'Components/Pie', 9 | component: Pie, 10 | parameters: { 11 | layout: 'centered', 12 | }, 13 | args: { 14 | width: 500, 15 | height: 400, 16 | }, 17 | }; 18 | 19 | export const Default = args => ; 20 | 21 | Default.args = { 22 | data, 23 | }; 24 | 25 | function randomDataset() { 26 | return { 27 | value: faker.datatype.number({ min: -100, max: 100 }), 28 | color: faker.internet.color(), 29 | }; 30 | } 31 | 32 | export const Dynamic = args => { 33 | const [datasets, setDatasets] = useState(() => [randomDataset()]); 34 | const onAdd = () => { 35 | setDatasets(datasets => [...datasets, randomDataset()]); 36 | }; 37 | const onRemove = () => { 38 | setDatasets(datasets => datasets.slice(0, -1)); 39 | }; 40 | const data = { 41 | labels: datasets.map((_, i) => `#${i}`), 42 | datasets: [ 43 | { 44 | data: datasets.map(({ value }) => value), 45 | backgroundColor: datasets.map(({ color }) => color), 46 | }, 47 | ], 48 | }; 49 | 50 | return ( 51 | <> 52 | 53 | 54 | 55 |
    56 | {datasets.map(({ value, color }, i) => ( 57 |
  • 58 | {value} 59 |
  • 60 | ))} 61 |
62 | 63 | ); 64 | }; 65 | -------------------------------------------------------------------------------- /stories/PolarArea.stories.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import 'chart.js/auto'; 3 | import { PolarArea } from '../src'; 4 | import { data } from '../sandboxes/polarArea/default/App'; 5 | 6 | export default { 7 | title: 'Components/PolarArea', 8 | component: PolarArea, 9 | parameters: { 10 | layout: 'centered', 11 | }, 12 | args: { 13 | width: 500, 14 | height: 400, 15 | }, 16 | }; 17 | 18 | export const Default = args => ; 19 | 20 | Default.args = { 21 | data, 22 | }; 23 | -------------------------------------------------------------------------------- /stories/Radar.stories.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import 'chart.js/auto'; 3 | import { Radar } from '../src'; 4 | import { data } from '../sandboxes/radar/default/App'; 5 | 6 | export default { 7 | title: 'Components/Radar', 8 | component: Radar, 9 | parameters: { 10 | layout: 'centered', 11 | }, 12 | args: { 13 | width: 500, 14 | height: 400, 15 | }, 16 | }; 17 | 18 | export const Default = args => ; 19 | 20 | Default.args = { 21 | data, 22 | }; 23 | -------------------------------------------------------------------------------- /stories/Scatter.stories.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import 'chart.js/auto'; 3 | import { Scatter } from '../src'; 4 | import { data, options } from '../sandboxes/scatter/default/App'; 5 | 6 | export default { 7 | title: 'Components/Scatter', 8 | component: Scatter, 9 | parameters: { 10 | layout: 'centered', 11 | }, 12 | args: { 13 | width: 500, 14 | height: 400, 15 | }, 16 | }; 17 | 18 | export const Default = args => ; 19 | 20 | Default.args = { 21 | data, 22 | options, 23 | }; 24 | -------------------------------------------------------------------------------- /stories/data.ts: -------------------------------------------------------------------------------- 1 | import faker from 'faker'; 2 | 3 | export const months = [ 4 | 'January', 5 | 'February', 6 | 'March', 7 | 'April', 8 | 'May', 9 | 'June', 10 | 'July', 11 | ]; 12 | export const colorRed = 'rgb(255, 99, 132)'; 13 | export const colorRed05 = 'rgba(255, 99, 132, 0.5)'; 14 | export const colorGreen = 'rgb(75, 192, 192)'; 15 | export const colorGreen05 = 'rgba(75, 192, 192, 0.5)'; 16 | export const colorBlue = 'rgb(53, 162, 235)'; 17 | export const colorBlue05 = 'rgba(53, 162, 235, 0.5)'; 18 | 19 | export function numbers(count = months.length) { 20 | return Array.from({ length: count }, () => 21 | faker.datatype.number({ min: -100, max: 100 }) 22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /test/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "@typescript-eslint/no-explicit-any": "off" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/chart.test-d.tsx: -------------------------------------------------------------------------------- 1 | import { expectError } from 'tsd'; 2 | import React from 'react'; 3 | import type { Plugin } from 'chart.js'; 4 | import { Chart, Scatter, Doughnut } from '../src/index.js'; 5 | 6 | const data = { 7 | datasets: [], 8 | }; 9 | const multiTypeData = { 10 | datasets: [ 11 | { 12 | type: 'line' as const, 13 | label: 'Dataset 1', 14 | data: [], 15 | }, 16 | { 17 | type: 'bar' as const, 18 | label: 'Dataset 2', 19 | data: [], 20 | }, 21 | ], 22 | }; 23 | 24 | /** 25 | * Should check type-specific props 26 | */ 27 | 28 | []} />; 29 | []} />; 30 | ; 31 | []} />; 32 | 33 | expectError([]} />); 34 | 35 | /** 36 | * Should check type-specific options 37 | */ 38 | 39 | ; 45 | 46 | expectError( 47 | 53 | ); 54 | -------------------------------------------------------------------------------- /test/chart.test.tsx: -------------------------------------------------------------------------------- 1 | import { vi, beforeEach, afterEach, describe, it, expect } from 'vitest'; 2 | import React from 'react'; 3 | import { render, cleanup, fireEvent } from '@testing-library/react'; 4 | import 'chart.js/auto'; 5 | import { Chart as ChartJS } from 'chart.js'; 6 | import { Chart } from '../src/index.js'; 7 | 8 | describe('', () => { 9 | const data = { 10 | labels: ['red', 'blue'], 11 | datasets: [{ label: 'colors', data: [1, 2] }], 12 | }; 13 | 14 | const options = { 15 | responsive: false, 16 | }; 17 | 18 | let chart: any, update: any, destroy: any; 19 | const ref = (el: ChartJS | undefined | null): void => { 20 | chart = el; 21 | 22 | if (chart) { 23 | update = vi.spyOn(chart, 'update'); 24 | destroy = vi.spyOn(chart, 'destroy'); 25 | } 26 | }; 27 | 28 | beforeEach(() => { 29 | chart = null; 30 | }); 31 | 32 | afterEach(() => { 33 | if (chart) chart.destroy(); 34 | 35 | cleanup(); 36 | 37 | if (update) update.mockClear(); 38 | if (destroy) destroy.mockClear(); 39 | }); 40 | 41 | it('should not pollute props', () => { 42 | render(); 43 | 44 | expect(data).toStrictEqual({ 45 | labels: ['red', 'blue'], 46 | datasets: [{ label: 'colors', data: [1, 2] }], 47 | }); 48 | 49 | // expect(options).toStrictEqual({ 50 | // responsive: false, 51 | // }); 52 | }); 53 | 54 | it('should set ref to chart instance', () => { 55 | render(); 56 | 57 | expect(chart).toBeTruthy(); 58 | expect(chart instanceof ChartJS).toBe(true); 59 | }); 60 | 61 | it('should pass props onto chart', () => { 62 | render(); 63 | 64 | expect(chart.config.data).toMatchObject(data); 65 | expect(chart.config.options).toMatchObject(options); 66 | expect(chart.config.type).toEqual('bar'); 67 | }); 68 | 69 | it('should pass new data on data change', () => { 70 | const newData = { 71 | labels: ['red', 'blue'], 72 | datasets: [{ label: 'colors', data: [2, 1] }], 73 | }; 74 | 75 | const { rerender } = render( 76 | 77 | ); 78 | 79 | // const meta = chart.config.data.datasets[0]._meta; 80 | const id = chart.id; 81 | 82 | rerender(); 83 | 84 | expect(chart.config.data).toMatchObject(newData); 85 | // make sure that other properties were maintained 86 | // expect(chart.config.data.datasets[0]._meta).toEqual(meta); 87 | expect(update).toHaveBeenCalled(); 88 | expect(chart.id).toEqual(id); 89 | }); 90 | 91 | it('should properly update with entirely new data', () => { 92 | const newData = { 93 | labels: ['purple', 'pink'], 94 | datasets: [{ label: 'new-colors', data: [1, 10] }], 95 | }; 96 | 97 | const { rerender } = render( 98 | 99 | ); 100 | 101 | const meta = chart.config.data.datasets[0]._meta; 102 | const id = chart.id; 103 | 104 | rerender(); 105 | 106 | expect(chart.config.data).toMatchObject(newData); 107 | expect(meta).not.toEqual(chart.config.data.datasets[0]); 108 | expect(update).toHaveBeenCalled(); 109 | expect(chart.id).toEqual(id); 110 | }); 111 | 112 | it('should properly update with a new chart type', () => { 113 | const newType = 'line'; 114 | 115 | const { rerender } = render( 116 | 117 | ); 118 | 119 | const originalChartDestroy = destroy; 120 | 121 | rerender(); 122 | 123 | expect(originalChartDestroy).toHaveBeenCalled(); 124 | }); 125 | 126 | it('should properly maintain order with new data', () => { 127 | const oldData = { 128 | labels: ['red', 'blue'], 129 | datasets: [ 130 | { label: 'new-colors', data: [1, 2] }, 131 | { label: 'colors', data: [3, 2] }, 132 | ], 133 | }; 134 | 135 | const newData = { 136 | labels: ['red', 'blue'], 137 | datasets: [ 138 | { label: 'colors', data: [4, 5] }, 139 | { label: 'new-colors', data: [1, 2] }, 140 | ], 141 | }; 142 | 143 | const { rerender } = render( 144 | 145 | ); 146 | 147 | const meta = Object.assign({}, chart._metasets); 148 | 149 | const id = chart.id; 150 | 151 | rerender(); 152 | 153 | expect(chart.config.data).toMatchObject(newData); 154 | expect(meta[0]).toBe(chart._metasets[1]); 155 | expect(meta[1]).toBe(chart._metasets[0]); 156 | expect(update).toHaveBeenCalled(); 157 | expect(chart.id).toEqual(id); 158 | }); 159 | 160 | it('should properly update when original data did not exist', () => { 161 | const oldData = { 162 | labels: ['red', 'blue'], 163 | datasets: [ 164 | { label: 'new-colors', data: [] }, 165 | { label: 'colors', data: [3, 2] }, 166 | ], 167 | }; 168 | 169 | const newData = { 170 | labels: ['red', 'blue'], 171 | datasets: [ 172 | { label: 'colors', data: [4, 5] }, 173 | { label: 'new-colors', data: [1, 2] }, 174 | ], 175 | }; 176 | 177 | const { rerender } = render( 178 | 179 | ); 180 | 181 | // even when we feed the data as undefined, the constructor will 182 | // force it to []. Here we force it back 183 | chart.config.data.datasets[0].data = undefined; 184 | const meta = Object.assign({}, chart._metasets); 185 | 186 | const id = chart.id; 187 | 188 | rerender(); 189 | 190 | expect(chart.config.data).toMatchObject(newData); 191 | expect(meta[0]).toBe(chart._metasets[1]); 192 | expect(update).toHaveBeenCalled(); 193 | expect(chart.id).toEqual(id); 194 | }); 195 | 196 | it('should properly update when incoming data does not exist', () => { 197 | const oldData = { 198 | labels: ['red', 'blue'], 199 | datasets: [ 200 | { label: 'new-colors', data: [1, 2] }, 201 | { label: 'colors', data: [3, 2] }, 202 | ], 203 | }; 204 | 205 | const newData = { 206 | labels: ['red', 'blue'], 207 | datasets: [ 208 | { label: 'colors', data: [4, 5] }, 209 | { label: 'new-colors', data: [] }, 210 | ], 211 | }; 212 | 213 | const { rerender } = render( 214 | 215 | ); 216 | 217 | const id = chart.id; 218 | 219 | rerender(); 220 | 221 | expect(chart.config.data).toMatchObject(newData); 222 | expect(update).toHaveBeenCalled(); 223 | expect(chart.id).toEqual(id); 224 | }); 225 | 226 | it('should pass new options on options change', () => { 227 | const newOptions = { 228 | responsive: true, 229 | }; 230 | 231 | const { rerender } = render( 232 | 233 | ); 234 | 235 | const id = chart.id; 236 | 237 | rerender(); 238 | 239 | expect(chart.options).toMatchObject(newOptions); 240 | expect(update).toHaveBeenCalled(); 241 | expect(chart.id).toEqual(id); 242 | }); 243 | 244 | it('should destroy and rerender when set to redraw', () => { 245 | const newData = { 246 | labels: ['red', 'blue'], 247 | datasets: [{ label: 'colors', data: [2, 1] }], 248 | }; 249 | 250 | const { rerender } = render( 251 | 252 | ); 253 | 254 | // const id = chart.id; 255 | const originalChartDestroy = destroy; 256 | 257 | rerender( 258 | 259 | ); 260 | 261 | expect(originalChartDestroy).toHaveBeenCalled(); 262 | }); 263 | 264 | it('should destroy when unmounted', () => { 265 | const { unmount } = render( 266 | 267 | ); 268 | 269 | expect(chart).toBeTruthy(); 270 | 271 | unmount(); 272 | 273 | expect(chart).toBe(null); 274 | }); 275 | 276 | it('should add className ', () => { 277 | render( 278 | 285 | ); 286 | 287 | expect(chart).toBeTruthy(); 288 | expect(chart.canvas).toHaveProperty('className'); 289 | expect(chart.canvas).toHaveClass('chart-example'); 290 | }); 291 | 292 | it('should call onClick', () => { 293 | const onClick = vi.fn(); 294 | 295 | const { getByTestId } = render( 296 | 304 | ); 305 | 306 | fireEvent.click(getByTestId('canvas')); 307 | 308 | expect(onClick).toHaveBeenCalled(); 309 | }); 310 | 311 | it('should show fallback content if given', () => { 312 | const fallback =

Fallback content

; 313 | const { getByTestId } = render( 314 | 322 | ); 323 | 324 | expect(chart).toBeTruthy(); 325 | expect(chart.canvas).toContainElement(getByTestId('fallbackContent')); 326 | }); 327 | 328 | it('should pass through aria labels to the canvas element', () => { 329 | const ariaLabel = 'ARIA LABEL'; 330 | render( 331 | 338 | ); 339 | 340 | expect(chart.canvas.getAttribute('aria-label')).toBe(ariaLabel); 341 | }); 342 | 343 | it('should rerender datasets with same labels', () => { 344 | const getData = () => ({ 345 | labels: [1, 2, 3], 346 | datasets: [ 347 | { 348 | label: '', 349 | data: [5, 6, 7], 350 | }, 351 | { 352 | label: '', 353 | data: [3, 2, 1], 354 | }, 355 | ], 356 | }); 357 | 358 | const { rerender } = render( 359 | 360 | ); 361 | 362 | const [prevDataset1, prevDataset2] = chart.config.data.datasets; 363 | 364 | rerender(); 365 | 366 | const [nextDataset1, nextDataset2] = chart.config.data.datasets; 367 | 368 | expect(prevDataset1).toBe(nextDataset1); 369 | expect(prevDataset2).not.toBe(nextDataset2); 370 | }); 371 | 372 | it('should rerender datasets with id', () => { 373 | const getData = () => ({ 374 | labels: [1, 2, 3], 375 | datasets: [ 376 | { 377 | id: 1, 378 | label: '', 379 | data: [5, 6, 7], 380 | }, 381 | { 382 | id: 2, 383 | label: '', 384 | data: [3, 2, 1], 385 | }, 386 | ], 387 | }); 388 | 389 | const { rerender } = render( 390 | 391 | ); 392 | 393 | const [prevDataset1, prevDataset2] = chart.config.data.datasets; 394 | 395 | rerender( 396 | 397 | ); 398 | 399 | const [nextDataset1, nextDataset2] = chart.config.data.datasets; 400 | 401 | expect(prevDataset1).toBe(nextDataset1); 402 | expect(prevDataset2).toBe(nextDataset2); 403 | }); 404 | 405 | it('should pass updateMode prop to update method', () => { 406 | const newData = { 407 | labels: ['purple', 'pink'], 408 | datasets: [{ label: 'new-colors', data: [1, 10] }], 409 | }; 410 | 411 | const { rerender } = render( 412 | 419 | ); 420 | 421 | rerender( 422 | 429 | ); 430 | 431 | expect(update).toHaveBeenCalledTimes(1); 432 | expect(update).toBeCalledWith('active'); 433 | }); 434 | }); 435 | -------------------------------------------------------------------------------- /test/setup.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom/vitest'; 2 | 3 | import 'vitest-canvas-mock'; 4 | -------------------------------------------------------------------------------- /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": "NodeNext", 14 | "moduleResolution": "NodeNext", 15 | "resolveJsonModule": true, 16 | /* Emit */ 17 | "declaration": true, 18 | "declarationMap": true, 19 | "inlineSourceMap": true, 20 | "outDir": "dist", 21 | /* Interop Constraints */ 22 | "allowSyntheticDefaultImports": true, 23 | "isolatedModules": true, 24 | /* Language and Environment */ 25 | "jsx": "react", 26 | "lib": [ 27 | "dom", 28 | "esnext" 29 | ], 30 | "target": "ESNext", 31 | /* Completeness */ 32 | "skipLibCheck": true 33 | }, 34 | "include": [ 35 | "src" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | export default defineConfig({ 5 | plugins: [react()], 6 | test: { 7 | environment: 'happy-dom', 8 | setupFiles: ['test/setup.ts'], 9 | server: { 10 | deps: { 11 | inline: ['vitest-canvas-mock'], 12 | }, 13 | }, 14 | coverage: { 15 | reporter: ['lcovonly', 'text'], 16 | }, 17 | }, 18 | }); 19 | -------------------------------------------------------------------------------- /website/.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.* 14 | 15 | npm-debug.log* 16 | -------------------------------------------------------------------------------- /website/CNAME: -------------------------------------------------------------------------------- 1 | react-chartjs-2.js.org 2 | -------------------------------------------------------------------------------- /website/README.md: -------------------------------------------------------------------------------- 1 | # Website 2 | 3 | This website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator. 4 | 5 | ### Installation 6 | 7 | ``` 8 | $ pnpm install 9 | ``` 10 | 11 | ### Local Development 12 | 13 | ``` 14 | $ pnpm start 15 | ``` 16 | 17 | This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. 18 | 19 | ### Build 20 | 21 | ``` 22 | $ pnpm build 23 | ``` 24 | 25 | This command generates static content into the `build` directory and can be served using any static contents hosting service. 26 | 27 | ### Deployment 28 | 29 | ``` 30 | $ GIT_USER= USE_SSH=true pnpm deploy 31 | ``` 32 | 33 | If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. 34 | -------------------------------------------------------------------------------- /website/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')], 3 | }; 4 | -------------------------------------------------------------------------------- /website/docs/chartjs-v2.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | slug: /docs/chartjs-v2 3 | description: Using react-chartjs-2 with Chart.js v2 4 | --- 5 | 6 | import Tabs from '@theme/Tabs'; 7 | import TabItem from '@theme/TabItem'; 8 | 9 | # Using with Chart.js v2 10 | 11 | If your app needs [Chart.js v2](https://www.chartjs.org/docs/2.9.4/), please use a [compatible version](https://www.npmjs.com/package/react-chartjs-2/v/2.11.2) of this library: 12 | 13 | 14 | 15 | 16 | ```bash 17 | yarn add chart.js@^2.9.4 react-chartjs-2@^2.11.2 18 | ``` 19 | 20 | 21 | 22 | 23 | ```bash 24 | pnpm add chart.js@^2.9.4 react-chartjs-2@^2.11.2 25 | ``` 26 | 27 | 28 | 29 | 30 | ```bash 31 | npm install --save chart.js@^2.9.4 react-chartjs-2@^2.11.2 32 | ``` 33 | 34 | 35 | 36 | 37 | Also, please consider upgrading your app to [Chart.js v3](#upgrading-to-chartjs-v3). 38 | 39 | ## Upgrading to Chart.js v3 40 | 41 | First, upgrade packages. You'll need to install Chart.js v3 and the latest version of this library: 42 | 43 | 44 | 45 | 46 | ```bash 47 | yarn add chart.js@^3.6.0 react-chartjs-2@^4.0.0 48 | ``` 49 | 50 | 51 | 52 | 53 | ```bash 54 | pnpm add chart.js@^3.6.0 react-chartjs-2@^4.0.0 55 | ``` 56 | 57 | 58 | 59 | 60 | ```bash 61 | npm install --save chart.js@^3.6.0 react-chartjs-2@^4.0.0 62 | ``` 63 | 64 | 65 | 66 | 67 | Then, please follow the [this guide](/docs/migration-to-v4). 68 | -------------------------------------------------------------------------------- /website/docs/chartjs-v3.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | slug: /docs/chartjs-v3 3 | description: Using react-chartjs-2 with Chart.js v3 4 | --- 5 | 6 | import Tabs from '@theme/Tabs'; 7 | import TabItem from '@theme/TabItem'; 8 | 9 | # Using with Chart.js v3 10 | 11 | If your app needs [Chart.js v3](https://www.chartjs.org/docs/3.9.1/), please use a [compatible version](https://www.npmjs.com/package/react-chartjs-2/v/4.3.1) of this library: 12 | 13 | 14 | 15 | 16 | ```bash 17 | yarn add chart.js@^3.9.1 react-chartjs-2@^4.3.1 18 | ``` 19 | 20 | 21 | 22 | 23 | ```bash 24 | pnpm add chart.js@^3.9.1 react-chartjs-2@^4.3.1 25 | ``` 26 | 27 | 28 | 29 | 30 | ```bash 31 | npm install --save chart.js@^3.9.1 react-chartjs-2@^4.3.1 32 | ``` 33 | 34 | 35 | 36 | 37 | Also, please consider upgrading your app to [Chart.js v4](#upgrading-to-chartjs-v4). 38 | 39 | ## Upgrading to Chart.js v4 40 | 41 | First, upgrade packages. You'll need to install Chart.js v3 and the latest version of this library: 42 | 43 | 44 | 45 | 46 | ```bash 47 | yarn add chart.js@^4.0.0 react-chartjs-2@^5.0.0 48 | ``` 49 | 50 | 51 | 52 | 53 | ```bash 54 | pnpm add chart.js@^4.0.0 react-chartjs-2@^5.0.0 55 | ``` 56 | 57 | 58 | 59 | 60 | ```bash 61 | npm install --save chart.js@^4.0.0 react-chartjs-2@^5.0.0 62 | ``` 63 | 64 | 65 | 66 | 67 | Then, please follow the [this guide](/docs/migration-to-v5). 68 | -------------------------------------------------------------------------------- /website/docs/components/bar.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: Description of Bar component from react-chartjs-2. 3 | --- 4 | 5 | import PropsTable from '../../src/components/PropsTable' 6 | 7 | # Bar 8 | 9 | ## Usage 10 | 11 | ```jsx 12 | import { Bar } from 'react-chartjs-2'; 13 | 14 | 19 | ``` 20 | 21 | [See full usage examples.](/tags/bar-chart) 22 | 23 | ## Props 24 | 25 | Also supports all standard `` props. 26 | 27 | 28 | -------------------------------------------------------------------------------- /website/docs/components/bubble.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: Description of Bubble component from react-chartjs-2. 3 | --- 4 | 5 | import PropsTable from '../../src/components/PropsTable' 6 | 7 | # Bubble 8 | 9 | ## Usage 10 | 11 | ```jsx 12 | import { Bubble } from 'react-chartjs-2'; 13 | 14 | 19 | ``` 20 | 21 | [See full usage examples.](/tags/bubble-chart) 22 | 23 | ## Props 24 | 25 | Also supports all standard `` props. 26 | 27 | 28 | -------------------------------------------------------------------------------- /website/docs/components/chart.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: Description of Chart component from react-chartjs-2. 3 | --- 4 | 5 | import PropsTable from '../../src/components/PropsTable' 6 | 7 | # Chart 8 | 9 | ## Usage 10 | 11 | ```jsx 12 | import { Chart } from 'react-chartjs-2'; 13 | 14 | 20 | ``` 21 | 22 | [See full usage examples.](/tags/chart) 23 | 24 | ## Props 25 | 26 | Also supports all standard `` props. 27 | 28 | 29 | -------------------------------------------------------------------------------- /website/docs/components/docs.js: -------------------------------------------------------------------------------- 1 | exports.docs = [ 2 | { title: 'Chart', slug: '/components/chart' }, 3 | { title: 'Bar', slug: '/components/bar' }, 4 | { title: 'Line', slug: '/components/line' }, 5 | { title: 'Pie', slug: '/components/pie' }, 6 | { title: 'Doughnut', slug: '/components/doughnut' }, 7 | { title: 'PolarArea', slug: '/components/polar-area' }, 8 | { title: 'Radar', slug: '/components/radar' }, 9 | { title: 'Scatter', slug: '/components/scatter' }, 10 | { title: 'Bubble', slug: '/components/bubble' }, 11 | ]; 12 | -------------------------------------------------------------------------------- /website/docs/components/doughnut.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: Description of Doughnut component from react-chartjs-2. 3 | --- 4 | 5 | import PropsTable from '../../src/components/PropsTable' 6 | 7 | # Doughnut 8 | 9 | ## Usage 10 | 11 | ```jsx 12 | import { Doughnut } from 'react-chartjs-2'; 13 | 14 | 19 | ``` 20 | 21 | [See full usage examples.](/tags/doughnut-chart) 22 | 23 | ## Props 24 | 25 | Also supports all standard `` props. 26 | 27 | 28 | -------------------------------------------------------------------------------- /website/docs/components/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | slug: /components 3 | description: List of react-chartjs-2 components. 4 | --- 5 | 6 | import Link from '@docusaurus/Link'; 7 | import { docs } from './docs'; 8 | 9 | # Components 10 | 11 |
    12 | {docs.map(({ title, slug }, i) => ( 13 |
  • 14 | {title} 15 |
  • 16 | ))} 17 |
18 | -------------------------------------------------------------------------------- /website/docs/components/line.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: Description of Line component from react-chartjs-2. 3 | --- 4 | 5 | import PropsTable from '../../src/components/PropsTable' 6 | 7 | # Line 8 | 9 | ## Usage 10 | 11 | ```jsx 12 | import { Line } from 'react-chartjs-2'; 13 | 14 | 19 | ``` 20 | 21 | [See full usage examples.](/tags/line-chart) 22 | 23 | ## Props 24 | 25 | Also supports all standard `` props. 26 | 27 | 28 | -------------------------------------------------------------------------------- /website/docs/components/pie.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: Description of Pie component from react-chartjs-2. 3 | --- 4 | 5 | import PropsTable from '../../src/components/PropsTable' 6 | 7 | # Pie 8 | 9 | ## Usage 10 | 11 | ```jsx 12 | import { Pie } from 'react-chartjs-2'; 13 | 14 | 19 | ``` 20 | 21 | [See full usage examples.](/tags/pie-chart) 22 | 23 | ## Props 24 | 25 | Also supports all standard `` props. 26 | 27 | 28 | -------------------------------------------------------------------------------- /website/docs/components/polar-area.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: Description of PolarArea component from react-chartjs-2. 3 | --- 4 | 5 | import PropsTable from '../../src/components/PropsTable' 6 | 7 | # PolarArea 8 | 9 | ## Usage 10 | 11 | ```jsx 12 | import { PolarArea } from 'react-chartjs-2'; 13 | 14 | 19 | ``` 20 | 21 | [See full usage examples.](/tags/polar-area-chart) 22 | 23 | ## Props 24 | 25 | Also supports all standard `` props. 26 | 27 | 28 | -------------------------------------------------------------------------------- /website/docs/components/radar.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: Description of Radar component from react-chartjs-2. 3 | --- 4 | 5 | import PropsTable from '../../src/components/PropsTable' 6 | 7 | # Radar 8 | 9 | ## Usage 10 | 11 | ```jsx 12 | import { Radar } from 'react-chartjs-2'; 13 | 14 | 19 | ``` 20 | 21 | [See full usage examples.](/tags/radar-chart) 22 | 23 | ## Props 24 | 25 | Also supports all standard `` props. 26 | 27 | 28 | -------------------------------------------------------------------------------- /website/docs/components/scatter.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: Description of Scatter component from react-chartjs-2. 3 | --- 4 | 5 | import PropsTable from '../../src/components/PropsTable' 6 | 7 | # Scatter 8 | 9 | ## Usage 10 | 11 | ```jsx 12 | import { Scatter } from 'react-chartjs-2'; 13 | 14 | 19 | ``` 20 | 21 | [See full usage examples.](/tags/scatter-chart) 22 | 23 | ## Props 24 | 25 | Also supports all standard `` props. 26 | 27 | 28 | -------------------------------------------------------------------------------- /website/docs/docs.js: -------------------------------------------------------------------------------- 1 | exports.docs = [ 2 | { title: 'Migration to v5', slug: '/docs/migration-to-v5' }, 3 | { title: 'Migration to v4', slug: '/docs/migration-to-v4' }, 4 | { title: 'Working with datasets', slug: '/docs/working-with-datasets' }, 5 | { title: 'Working with events', slug: '/docs/working-with-events' }, 6 | { title: 'Using with Chart.js v3', slug: '/docs/chartjs-v3' }, 7 | { title: 'Using with Chart.js v2', slug: '/docs/chartjs-v2' }, 8 | ]; 9 | -------------------------------------------------------------------------------- /website/docs/examples/area-chart.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: Example of area chart in react-chartjs-2. 3 | tags: 4 | - Area Chart 5 | --- 6 | 7 | import ContextProvider from '../../src/components/ContextProvider'; 8 | 9 | # Area Chart 10 | 11 | 12 | {({ branch, theme }) => ( 13 | 26 | )} 27 | 28 | -------------------------------------------------------------------------------- /website/docs/examples/bubble-chart.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: Example of bubble chart in react-chartjs-2. 3 | tags: 4 | - Bubble Chart 5 | --- 6 | 7 | import ContextProvider from '../../src/components/ContextProvider'; 8 | 9 | # Bubble Chart 10 | 11 | 12 | {({ branch, theme }) => ( 13 | 26 | )} 27 | 28 | -------------------------------------------------------------------------------- /website/docs/examples/chart-events.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: Example of events in react-chartjs-2. 3 | tags: 4 | - Chart 5 | --- 6 | 7 | import ContextProvider from '../../src/components/ContextProvider'; 8 | 9 | # Chart Events 10 | 11 | 12 | {({ branch, theme }) => ( 13 | 26 | )} 27 | 28 | -------------------------------------------------------------------------------- /website/docs/examples/chart-ref.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: Example of getting ref in react-chartjs-2. 3 | tags: 4 | - Chart 5 | --- 6 | 7 | import ContextProvider from '../../src/components/ContextProvider'; 8 | 9 | # Get Chart Ref 10 | 11 | 12 | {({ branch, theme }) => ( 13 | 26 | )} 27 | 28 | -------------------------------------------------------------------------------- /website/docs/examples/docs.js: -------------------------------------------------------------------------------- 1 | exports.docs = [ 2 | { title: 'Vertical Bar Chart', slug: '/examples/vertical-bar-chart' }, 3 | { title: 'Horizontal Bar Chart', slug: '/examples/horizontal-bar-chart' }, 4 | { title: 'Stacked Bar Chart', slug: '/examples/stacked-bar-chart' }, 5 | { title: 'Grouped Bar Chart', slug: '/examples/grouped-bar-chart' }, 6 | { title: 'Area Chart', slug: '/examples/area-chart' }, 7 | { title: 'Line Chart', slug: '/examples/line-chart' }, 8 | { title: 'Multiaxis Line Chart', slug: '/examples/multiaxis-line-chart' }, 9 | { title: 'Pie Chart', slug: '/examples/pie-chart' }, 10 | { title: 'Doughnut Chart', slug: '/examples/doughnut-chart' }, 11 | { title: 'Polar Area Chart', slug: '/examples/polar-area-chart' }, 12 | { title: 'Radar Chart', slug: '/examples/radar-chart' }, 13 | { title: 'Scatter Chart', slug: '/examples/scatter-chart' }, 14 | { title: 'Bubble Chart', slug: '/examples/bubble-chart' }, 15 | { title: 'Multitype Chart', slug: '/examples/multitype-chart' }, 16 | { title: 'Chart Events', slug: '/examples/chart-events' }, 17 | { title: 'Chart Ref', slug: '/examples/chart-ref' }, 18 | { title: 'Gradient Chart', slug: '/examples/gradient-chart' }, 19 | ]; 20 | -------------------------------------------------------------------------------- /website/docs/examples/doughnut-chart.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: Example of doughnut chart in react-chartjs-2. 3 | tags: 4 | - Doughnut Chart 5 | --- 6 | 7 | import ContextProvider from '../../src/components/ContextProvider'; 8 | 9 | # Doughnut Chart 10 | 11 | 12 | {({ branch, theme }) => ( 13 | 26 | )} 27 | 28 | -------------------------------------------------------------------------------- /website/docs/examples/gradient-chart.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: Example of creating gradient chart in react-chartjs-2. 3 | tags: 4 | - Chart 5 | --- 6 | 7 | import ContextProvider from '../../src/components/ContextProvider'; 8 | 9 | # Gradient Chart 10 | 11 | 12 | {({ branch, theme }) => ( 13 | 26 | )} 27 | 28 | -------------------------------------------------------------------------------- /website/docs/examples/grouped-bar-chart.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: Example of grouped bar chart in react-chartjs-2. 3 | tags: 4 | - Bar Chart 5 | --- 6 | 7 | import ContextProvider from '../../src/components/ContextProvider'; 8 | 9 | # Grouped Bar Chart 10 | 11 | 12 | {({ branch, theme }) => ( 13 | 26 | )} 27 | 28 | -------------------------------------------------------------------------------- /website/docs/examples/horizontal-bar-chart.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: Example of horizontal bar chart in react-chartjs-2. 3 | tags: 4 | - Bar Chart 5 | --- 6 | 7 | import ContextProvider from '../../src/components/ContextProvider'; 8 | 9 | # Horizontal Bar Chart 10 | 11 | 12 | {({ branch, theme }) => ( 13 | 26 | )} 27 | 28 | -------------------------------------------------------------------------------- /website/docs/examples/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | slug: /examples 3 | description: List of react-chartjs-2 usage examples. 4 | --- 5 | 6 | import Link from '@docusaurus/Link'; 7 | import { docs } from './docs'; 8 | 9 | # Examples 10 | 11 |
    12 | {docs.map(({ title, slug }, i) => ( 13 |
  • 14 | {title} 15 |
  • 16 | ))} 17 |
18 | -------------------------------------------------------------------------------- /website/docs/examples/line-chart.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: Example of line chart in react-chartjs-2. 3 | tags: 4 | - Line Chart 5 | --- 6 | 7 | import ContextProvider from '../../src/components/ContextProvider'; 8 | 9 | # Line Chart 10 | 11 | 12 | {({ branch, theme }) => ( 13 | 26 | )} 27 | 28 | -------------------------------------------------------------------------------- /website/docs/examples/multiaxis-line-chart.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: Example of multiaxis line chart in react-chartjs-2. 3 | tags: 4 | - Line Chart 5 | --- 6 | 7 | import ContextProvider from '../../src/components/ContextProvider'; 8 | 9 | # Multiaxis Line Chart 10 | 11 | 12 | {({ branch, theme }) => ( 13 | 26 | )} 27 | 28 | -------------------------------------------------------------------------------- /website/docs/examples/multitype-chart.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: Example of multitype chart in react-chartjs-2. 3 | tags: 4 | - Chart 5 | --- 6 | 7 | import ContextProvider from '../../src/components/ContextProvider'; 8 | 9 | # Multitype Chart 10 | 11 | 12 | {({ branch, theme }) => ( 13 | 26 | )} 27 | 28 | -------------------------------------------------------------------------------- /website/docs/examples/pie-chart.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: Example of pie chart in react-chartjs-2. 3 | tags: 4 | - Pie Chart 5 | --- 6 | 7 | import ContextProvider from '../../src/components/ContextProvider'; 8 | 9 | # Pie Chart 10 | 11 | 12 | {({ branch, theme }) => ( 13 | 26 | )} 27 | 28 | -------------------------------------------------------------------------------- /website/docs/examples/polar-area-chart.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: Example of polar area chart in react-chartjs-2. 3 | tags: 4 | - Polar Area Chart 5 | --- 6 | 7 | import ContextProvider from '../../src/components/ContextProvider'; 8 | 9 | # Polar Area Chart 10 | 11 | 12 | {({ branch, theme }) => ( 13 | 26 | )} 27 | 28 | -------------------------------------------------------------------------------- /website/docs/examples/radar-chart.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: Example of radar chart in react-chartjs-2. 3 | tags: 4 | - Radar Chart 5 | --- 6 | 7 | import ContextProvider from '../../src/components/ContextProvider'; 8 | 9 | # Radar Chart 10 | 11 | 12 | {({ branch, theme }) => ( 13 | 26 | )} 27 | 28 | -------------------------------------------------------------------------------- /website/docs/examples/scatter-chart.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: Example of scatter chart in react-chartjs-2. 3 | tags: 4 | - Scatter Chart 5 | --- 6 | 7 | import ContextProvider from '../../src/components/ContextProvider'; 8 | 9 | # Scatter Chart 10 | 11 | 12 | {({ branch, theme }) => ( 13 | 26 | )} 27 | 28 | -------------------------------------------------------------------------------- /website/docs/examples/stacked-bar-chart.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: Example of stacked bar chart in react-chartjs-2. 3 | tags: 4 | - Bar Chart 5 | --- 6 | 7 | import ContextProvider from '../../src/components/ContextProvider'; 8 | 9 | # Stacked Bar Chart 10 | 11 | 12 | {({ branch, theme }) => ( 13 | 26 | )} 27 | 28 | -------------------------------------------------------------------------------- /website/docs/examples/vertical-bar-chart.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | description: Example of vertical bar chart in react-chartjs-2. 3 | tags: 4 | - Bar Chart 5 | --- 6 | 7 | import ContextProvider from '../../src/components/ContextProvider'; 8 | 9 | # Vertical Bar Chart 10 | 11 | 12 | {({ branch, theme }) => ( 13 | 26 | )} 27 | 28 | -------------------------------------------------------------------------------- /website/docs/faq/canvas-context.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: /faq/canvas-context 3 | --- 4 | 5 | # How to access the canvas context? 6 | 7 | The canvas node and hence context can be accessed by placing a ref to the element as: 8 | 9 | ```tsx 10 | function App() { 11 | const chartRef = useRef(null); 12 | 13 | useEffect(() => { 14 | const chart = chartRef.current; 15 | 16 | if (chart) { 17 | console.log('CanvasRenderingContext2D', chart.ctx); 18 | console.log('HTMLCanvasElement', chart.canvas); 19 | } 20 | }, []); 21 | 22 | return ; 23 | } 24 | ``` 25 | 26 | [See sandbox with working example](/examples/gradient-chart). 27 | -------------------------------------------------------------------------------- /website/docs/faq/chartjs-instance.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: /faq/chartjs-instance 3 | --- 4 | 5 | # How to access the Chart.js instance? 6 | 7 | The Chart.js instance can be accessed by placing a ref to the element as: 8 | 9 | ```tsx 10 | function App() { 11 | const chartRef = useRef(null); 12 | 13 | useEffect(() => { 14 | const chart = chartRef.current; 15 | 16 | if (chart) { 17 | console.log('ChartJS', chart); 18 | } 19 | }, []); 20 | 21 | return ; 22 | } 23 | ``` 24 | 25 | [See sandbox with working example](/examples/chart-ref). 26 | 27 | -------------------------------------------------------------------------------- /website/docs/faq/docs.js: -------------------------------------------------------------------------------- 1 | exports.docs = [ 2 | { 3 | title: "Why doesn't the chart maintain its width/height?", 4 | slug: '/faq/maintain-aspect-ratio', 5 | }, 6 | { 7 | title: 'How to access the Chart.js instance?', 8 | slug: '/faq/chartjs-instance', 9 | }, 10 | { title: 'How to access the canvas context?', slug: '/faq/canvas-context' }, 11 | { 12 | title: 'Why this library has "2" in its name?', 13 | slug: '/faq/why-two', 14 | }, 15 | { 16 | title: 'Why is a background fill not working?', 17 | slug: '/faq/fill-property', 18 | }, 19 | { 20 | title: 'How to fix "... is not a registered element" error?', 21 | slug: '/faq/registered-element', 22 | }, 23 | { 24 | title: 'How to fix "... is not a registered scale" error?', 25 | slug: '/faq/registered-scale', 26 | }, 27 | { 28 | title: 'How to use react-chartjs-2 with TypeScript?', 29 | slug: '/faq/typescript', 30 | }, 31 | { 32 | title: 'How to fix "Cannot find module \'react-chartjs-2\'" error?', 33 | slug: '/faq/esm-only', 34 | }, 35 | ]; 36 | -------------------------------------------------------------------------------- /website/docs/faq/esm-only.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: /faq/esm-only 3 | --- 4 | 5 | # How to fix "Cannot find module 'react-chartjs-2'" error? 6 | 7 | Upgrade to Chart.js v4.1 and react-chartjs-2 v5.1, where the CommonJS support was restored. 8 | -------------------------------------------------------------------------------- /website/docs/faq/fill-property.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: /faq/fill-property 3 | --- 4 | 5 | # Why is a background fill not working? 6 | 7 | As you can see in [migration to v4 guide](/docs/migration-to-v4#tree-shaking): 8 | 9 | > v4 of this library, [just like Chart.js v3](https://www.chartjs.org/docs/latest/getting-started/v3-migration.html#setup-and-installation), is tree-shakable. It means that you need to import and register the controllers, elements, scales, and plugins you want to use. 10 | > 11 | > For a list of all the available items to import, see [Chart.js docs](https://www.chartjs.org/docs/latest/getting-started/integration.html#bundlers-webpack-rollup-etc). 12 | 13 | So to enable background filling, you should register `Filler` component: 14 | 15 | ```js 16 | import { Filler } from "chart.js"; 17 | 18 | ChartJS.register(Filler); 19 | ``` 20 | -------------------------------------------------------------------------------- /website/docs/faq/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | slug: /faq 3 | description: Frequently asked questions about react-chartjs-2. 4 | --- 5 | 6 | import Link from '@docusaurus/Link'; 7 | import { docs } from './docs'; 8 | 9 | # FAQ 10 | 11 |
    12 | {docs.map(({ title, slug }, i) => ( 13 |
  • 14 | {title} 15 |
  • 16 | ))} 17 |
18 | -------------------------------------------------------------------------------- /website/docs/faq/maintain-aspect-ratio.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: /faq/maintain-aspect-ratio 3 | --- 4 | 5 | # Why doesn't the chart maintain its width/height? 6 | 7 | In order for Chart.js to obey the custom size you need to set `maintainAspectRatio` to `false`: 8 | 9 | ```tsx 10 | 16 | ``` 17 | -------------------------------------------------------------------------------- /website/docs/faq/registered-element.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: /faq/registered-element 3 | --- 4 | 5 | # How to fix "... is not a registered element" error? 6 | 7 | As you can see in [migration to v4 guide](/docs/migration-to-v4#tree-shaking): 8 | 9 | > v4 of this library, [just like Chart.js v3](https://www.chartjs.org/docs/latest/getting-started/v3-migration.html#setup-and-installation), is tree-shakable. It means that you need to import and register the controllers, elements, scales, and plugins you want to use. 10 | > 11 | > For a list of all the available items to import, see [Chart.js docs](https://www.chartjs.org/docs/latest/getting-started/integration.html#bundlers-webpack-rollup-etc). 12 | 13 | So you should register missed components. For example, if you have `Uncaught Error: "arc" is not a registered element.` error, you should register `ArcElement`: 14 | 15 | ```js 16 | import { ArcElement } from "chart.js"; 17 | 18 | ChartJS.register(ArcElement); 19 | ``` 20 | -------------------------------------------------------------------------------- /website/docs/faq/registered-scale.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: /faq/registered-scale 3 | --- 4 | 5 | # How to fix "... is not a registered scale" error? 6 | 7 | As you can see in [migration to v4 guide](/docs/migration-to-v4#tree-shaking): 8 | 9 | > v4 of this library, [just like Chart.js v3](https://www.chartjs.org/docs/latest/getting-started/v3-migration.html#setup-and-installation), is tree-shakable. It means that you need to import and register the controllers, elements, scales, and plugins you want to use. 10 | > 11 | > For a list of all the available items to import, see [Chart.js docs](https://www.chartjs.org/docs/latest/getting-started/integration.html#bundlers-webpack-rollup-etc). 12 | 13 | So you should register missed components. For example, if you have `Uncaught Error: "category" is not a registered scale.` error, you should register `CategoryScale`: 14 | 15 | ```js 16 | import { CategoryScale, Chart } from "chart.js"; 17 | 18 | Chart.register(CategoryScale); 19 | ``` 20 | -------------------------------------------------------------------------------- /website/docs/faq/typescript.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: /faq/typescript 3 | --- 4 | 5 | # How to use react-chartjs-2 with TypeScript? 6 | 7 | TypeScript has extremely robust type inference capabilities and most of the time 8 | we can enjoy type safety and autocompletion without having to do any extra work. 9 | 10 | But occasionally types need to be set explicitly. They can be imported from `Chart.js`: 11 | 12 | ```typescript 13 | import type { ChartData, ChartOptions } from 'chart.js'; 14 | ``` 15 | 16 | ...and then used with `options` and `data` props: 17 | 18 | ```typescript 19 | interface LineProps { 20 | options: ChartOptions<'line'>; 21 | data: ChartData<'line'>; 22 | } 23 | ``` 24 | 25 | The generic type being passed is a `ChartType` that can be one of the following values: 26 | `'bar'`, `'line'`, `'scatter'`, `'bubble'`, `'pie'`, `'doughnut'`, `'polarArea'` or `'radar'`. 27 | -------------------------------------------------------------------------------- /website/docs/faq/why-two.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: /faq/why-two 3 | --- 4 | 5 | # Why does `react-chartjs-2` have "2" in its name? 6 | 7 | Initially, this library was [created in 2016](https://github.com/reactchartjs/react-chartjs-2/commit/d8cbcb7dc050d749771c6bb1347e22ec63bdddf9#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5R3) as a wrapper for Chart.js v2. 8 | 9 | Later, it was updated to support [Chart.js v3](https://www.chartjs.org/docs/latest/getting-started/v3-migration.html) — a huge yet backwards-incompatible release with new features and performance improvements. However, the name persisted. 10 | -------------------------------------------------------------------------------- /website/docs/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | slug: / 3 | description: React components for Chart.js 4 | --- 5 | 6 | import Tabs from '@theme/Tabs'; 7 | import TabItem from '@theme/TabItem'; 8 | import Logo from '@site/static/img/logo.svg'; 9 | 10 | # react-chartjs-2 11 | 12 | 13 | 14 | React components for [Chart.js](https://www.chartjs.org), the most popular charting library. 15 | 16 | Supports Chart.js v4 (read below) and Chart.js v3 (see [this guide](/docs/chartjs-v3)). 17 | 18 | [![NPM version][npm]][npm-url] 19 | [![Downloads][downloads]][downloads-url] 20 | [![Build status][build]][build-url] 21 | [![Coverage status][coverage]][coverage-url] 22 | [![Bundle size][size]][size-url] 23 | 24 | [npm]: https://img.shields.io/npm/v/react-chartjs-2.svg 25 | [npm-url]: https://www.npmjs.com/package/react-chartjs-2 26 | 27 | [downloads]: https://img.shields.io/npm/dm/react-chartjs-2.svg 28 | [downloads-url]: https://www.npmjs.com/package/react-chartjs-2 29 | 30 | [build]: https://img.shields.io/github/actions/workflow/status/reactchartjs/react-chartjs-2/ci.yml?branch=master 31 | [build-url]: https://github.com/reactchartjs/react-chartjs-2/actions 32 | 33 | [coverage]: https://img.shields.io/codecov/c/github/reactchartjs/react-chartjs-2.svg 34 | [coverage-url]: https://app.codecov.io/gh/reactchartjs/react-chartjs-2 35 | 36 | [size]: https://img.shields.io/bundlephobia/minzip/react-chartjs-2 37 | [size-url]: https://bundlephobia.com/package/react-chartjs-2 38 | 39 | ## Quickstart 40 | 41 | Install this library with peer dependencies: 42 | 43 | 44 | 45 | 46 | ```bash 47 | yarn add chart.js react-chartjs-2 48 | ``` 49 | 50 | 51 | 52 | 53 | ```bash 54 | pnpm add chart.js react-chartjs-2 55 | ``` 56 | 57 | 58 | 59 | 60 | ```bash 61 | npm install --save chart.js react-chartjs-2 62 | ``` 63 | 64 | 65 | 66 | 67 | Then, import and use individual components: 68 | 69 | ```jsx 70 | import { Chart as ChartJS, ArcElement, Tooltip, Legend } from "chart.js"; 71 | import { Doughnut } from "react-chartjs-2"; 72 | 73 | ChartJS.register(ArcElement, Tooltip, Legend); 74 | 75 | 76 | ``` 77 | 78 | To learn more about importing and registering elements see [tree-shaking](https://react-chartjs-2.js.org/docs/migration-to-v4/#tree-shaking). 79 | 80 | ## Examples 81 | 82 | Please see [live examples](/examples). 83 | 84 | :::tip Need a guide? 85 | Please check "[Chart.js Example with Dynamic Dataset](https://cube.dev/blog/chart-js-example-with-dynamic-dataset/?ref=eco-react-chartjs)". 86 | ::: 87 | 88 | ## Getting Help 89 | 90 | Need help? Ask your question on [Stack Overflow](https://stackoverflow.com/questions/tagged/react-chartjs-2). 91 | 92 | If you've encountered an issue, please [file it on GitHub](https://github.com/reactchartjs/react-chartjs-2/issues). 93 | -------------------------------------------------------------------------------- /website/docs/migration-to-v4.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: /docs/migration-to-v4 3 | description: react-chartjs-2 migration guide to v4 4 | --- 5 | 6 | # Migration to v4 7 | 8 | With v4, this library introduces a number of breaking changes. In order to improve performance, offer new features, and improve maintainability, it was necessary to break backwards compatibility, but we aimed to do so only when worth the benefit. 9 | 10 | v4 is fully compatible with Chart.js v3. 11 | 12 | ## New exports 13 | 14 | - All re-exports from `chart.js` were removed 15 | - Default export was renamed to `Chart` 16 | 17 | ```jsx title="v3" 18 | import Chart, { 19 | Chart as ChartJS, 20 | defaults 21 | } from 'react-chartjs-2'; 22 | ``` 23 | 24 | ```jsx title="v4" 25 | import { 26 | Chart as ChartJS, 27 | defaults 28 | } from 'chart.js'; 29 | import { 30 | Chart 31 | } from 'react-chartjs-2'; 32 | ``` 33 | 34 | ## Tree-shaking 35 | 36 | v4 of this library, [just like Chart.js v3](https://www.chartjs.org/docs/latest/getting-started/v3-migration.html#setup-and-installation), is tree-shakable. It means that you need to import and register the controllers, elements, scales, and plugins you want to use. 37 | 38 | For a list of all the available items to import, see [Chart.js docs](https://www.chartjs.org/docs/latest/getting-started/integration.html#bundlers-webpack-rollup-etc). 39 | 40 | ```jsx title="v3" 41 | import Chart from 'react-chartjs-2'; 42 | 43 | 44 | ``` 45 | 46 | ```jsx title="v4 — lazy way" 47 | import 'chart.js/auto'; 48 | import { Chart } from 'react-chartjs-2'; 49 | 50 | 51 | ``` 52 | 53 | ```jsx title="v4 — tree-shakable way" 54 | import { Chart } from 'react-chartjs-2'; 55 | import { Chart as ChartJS, LineController, LineElement, PointElement, LinearScale, Title } from 'chart.js'; 56 | 57 | ChartJS.register(LineController, LineElement, PointElement, LinearScale, Title); 58 | 59 | 60 | ``` 61 | 62 | Using the "lazy way" is okay to simplify the migration, but please consider using the tree-shakable way to decrease the bundle size. 63 | 64 | Please note that typed chart components register their controllers by default, so you don't need to register them by yourself. For example, when using the [`Line` component](/components/line), you don't need to register `LineController` explicitly. 65 | 66 | ```jsx title="v4 — Line component" 67 | import { Line } from 'react-chartjs-2'; 68 | import { Chart as ChartJS, LineElement, PointElement, LinearScale, Title } from 'chart.js'; 69 | 70 | ChartJS.register(LineElement, PointElement, LinearScale, Title); 71 | 72 | 73 | ``` 74 | 75 | ## Drawing charts with gradients 76 | 77 | The option to pass a function to the `data` prop was removed. 78 | 79 | ```jsx title="v3" 80 | const chartData = canvas => { 81 | const ctx = canvas.getContext('2d'); 82 | 83 | return { 84 | datasets: [{ 85 | backgroundColor: createBackgroundGradient(ctx), 86 | // ... 87 | }], 88 | }; 89 | }; 90 | 91 | 92 | ``` 93 | 94 | ```jsx title="v4" 95 | const chartRef = useRef(null); 96 | const [chartData, setChartData] = useState({ 97 | datasets: [], 98 | }); 99 | 100 | useEffect(() => { 101 | const chart = chartRef.current; 102 | 103 | if (chart) { 104 | setChartData({ 105 | datasets: [{ 106 | backgroundColor: createBackgroundGradient(chart.ctx), 107 | // ... 108 | }] 109 | }); 110 | } 111 | }, []); 112 | 113 | 114 | ``` 115 | 116 | See the [full working example](/examples/gradient-chart). 117 | 118 | ## Getting data from click events 119 | 120 | `getDatasetAtEvent`, `getElementAtEvent` and `getElementsAtEvent` props were removed in favor of tree-shakable methods with the same names. 121 | 122 | ```jsx title="v3" 123 | { /* ... */ }} 127 | getElementAtEvent={(element, event) => { /* ... */ }} 128 | getElementsAtEvent={(elements, event) => { /* ... */ }} 129 | /> 130 | ``` 131 | 132 | ```jsx title="v4" 133 | const chartRef = useRef(null); 134 | 135 | { 140 | const dataset = getDatasetAtEvent(chartRef.current, event); 141 | const element = getElementAtEvent(chartRef.current, event); 142 | const elements = getElementsAtEvent(chartRef.current, event); 143 | }} 144 | /> 145 | ``` 146 | 147 | See the [full working example](/examples/chart-events). 148 | -------------------------------------------------------------------------------- /website/docs/migration-to-v5.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: /docs/migration-to-v5 3 | description: react-chartjs-2 migration guide to v5 4 | --- 5 | 6 | # Migration to v5 7 | 8 | ## v5.0 9 | 10 | Chart.js v4 and react-chartjs-2 v5 are [ESM-only packages](https://nodejs.org/api/esm.html). To use them in your project, it also should be ESM: 11 | 12 | ```json title="package.json" 13 | { 14 | "type": "module" 15 | } 16 | ``` 17 | 18 | ## v5.1 19 | 20 | Chart.js v4.1 and react-chartjs-2 v5.1 have restored the CommonJS support. 21 | -------------------------------------------------------------------------------- /website/docs/working-with-datasets.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: /docs/working-with-datasets 3 | description: Working with datasets in react-chartjs-2 4 | --- 5 | 6 | # Working with datasets 7 | 8 | You will find that any event which causes the chart to re-render, such as hover tooltips, etc., will cause the first dataset to be copied over to other datasets, causing your lines and bars to merge together. 9 | 10 | This is because to track changes in the dataset series, the library needs a `key` to be specified. If none is found, it can't tell the difference between the datasets while updating. To get around this issue, you can take these two approaches: 11 | 12 | 1. Add a `label` property to each dataset. By default, this library uses the `label` property as the key to distinguish datasets. 13 | 2. Specify a different property to be used as a key by passing a `datasetIdKey` prop to your chart component. 14 | 15 | See this example: 16 | 17 | ```tsx 18 | import { Line } from 'react-chartjs-2'; 19 | 20 | 38 | ``` 39 | -------------------------------------------------------------------------------- /website/docs/working-with-events.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: /docs/working-with-events 3 | description: Working with events in react-chartjs-2 4 | --- 5 | 6 | # Working with events 7 | 8 | There are three helper methods to get data from click event. 9 | 10 | ## getDatasetAtEvent 11 | 12 | Gets dataset from mouse click event. 13 | 14 | ```jsx 15 | import { useRef } from 'react'; 16 | import { Bar, getDatasetAtEvent } from 'react-chartjs-2'; 17 | 18 | function App() { 19 | const chartRef = useRef(); 20 | const onClick = (event) => { 21 | console.log(getDatasetAtEvent(chartRef.current, event)); 22 | } 23 | 24 | return ( 25 | 30 | ); 31 | } 32 | ``` 33 | 34 | ## getElementAtEvent 35 | 36 | Gets single dataset element from mouse click event. 37 | 38 | ```jsx 39 | import { useRef } from 'react'; 40 | import { Bar, getElementAtEvent } from 'react-chartjs-2'; 41 | 42 | function App() { 43 | const chartRef = useRef(); 44 | const onClick = (event) => { 45 | console.log(getElementAtEvent(chartRef.current, event)); 46 | } 47 | 48 | return ( 49 | 54 | ); 55 | } 56 | ``` 57 | 58 | ## getElementsAtEvent 59 | 60 | Gets all dataset elements from mouse click event. 61 | 62 | ```jsx 63 | import { useRef } from 'react'; 64 | import { Bar, getElementsAtEvent } from 'react-chartjs-2'; 65 | 66 | function App() { 67 | const chartRef = useRef(); 68 | const onClick = (event) => { 69 | console.log(getElementsAtEvent(chartRef.current, event)); 70 | } 71 | 72 | return ( 73 | 78 | ); 79 | } 80 | ``` 81 | 82 | See the [full working example](/examples/chart-events). 83 | -------------------------------------------------------------------------------- /website/docusaurus.config.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | const branch = require('git-branch'); 4 | const lightCodeTheme = require('prism-react-renderer/themes/github'); 5 | const darkCodeTheme = require('prism-react-renderer/themes/dracula'); 6 | 7 | const currentBranch = process.env.BRANCH || branch.sync(); 8 | 9 | /** @type {import('@docusaurus/types').Config} */ 10 | const config = { 11 | title: 'react-chartjs-2', 12 | tagline: 'React wrapper for Chart.js', 13 | url: 'https://react-chartjs-2.js.org', 14 | baseUrl: '/', 15 | onBrokenLinks: 'throw', 16 | onBrokenMarkdownLinks: 'warn', 17 | favicon: 'img/favicon.ico', 18 | organizationName: 'reactchartjs', 19 | projectName: 'react-chartjs-2', 20 | noIndex: currentBranch !== 'master', 21 | 22 | customFields: { 23 | branch: currentBranch, 24 | }, 25 | 26 | presets: [ 27 | [ 28 | '@docusaurus/preset-classic', 29 | /** @type {import('@docusaurus/preset-classic').Options} */ 30 | ({ 31 | docs: { 32 | routeBasePath: '/', 33 | sidebarPath: require.resolve('./sidebars.js'), 34 | editUrl: 35 | 'https://github.com/reactchartjs/react-chartjs-2/edit/master/website/', 36 | }, 37 | theme: { 38 | customCss: require.resolve('./src/css/custom.css'), 39 | }, 40 | }), 41 | ], 42 | ], 43 | 44 | themeConfig: 45 | /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ 46 | ({ 47 | navbar: { 48 | title: 'react-chartjs-2', 49 | logo: { 50 | alt: 'react-chartjs-2 logo', 51 | src: 'img/logo.svg', 52 | }, 53 | items: [ 54 | { 55 | type: 'doc', 56 | docId: 'faq/index', 57 | position: 'left', 58 | label: 'FAQ', 59 | }, 60 | { 61 | type: 'doc', 62 | docId: 'components/index', 63 | position: 'left', 64 | label: 'Components', 65 | }, 66 | { 67 | type: 'doc', 68 | docId: 'examples/index', 69 | position: 'left', 70 | label: 'Examples', 71 | }, 72 | { 73 | href: 'https://stackoverflow.com/questions/tagged/react-chartjs-2', 74 | label: 'Stack Overflow', 75 | position: 'right', 76 | }, 77 | { 78 | href: 'https://github.com/reactchartjs/react-chartjs-2', 79 | label: 'GitHub', 80 | position: 'right', 81 | }, 82 | ], 83 | }, 84 | prism: { 85 | theme: lightCodeTheme, 86 | darkTheme: darkCodeTheme, 87 | }, 88 | algolia: { 89 | appId: 'BH4D9OD16A', 90 | apiKey: 'd59187de89e7935f588bbb2fc9273f03', 91 | indexName: 'react-chartjs-2', 92 | }, 93 | }), 94 | 95 | plugins: [ 96 | [ 97 | 'docusaurus-plugin-react-docgen-typescript', 98 | { 99 | src: '../src/**/*.tsx', 100 | parserOptions: { 101 | propFilter: prop => { 102 | if (prop.parent) { 103 | return !prop.parent.fileName.includes('@types/react'); 104 | } 105 | 106 | return true; 107 | }, 108 | }, 109 | }, 110 | ], 111 | ], 112 | }; 113 | 114 | module.exports = config; 115 | -------------------------------------------------------------------------------- /website/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "website", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "docusaurus": "docusaurus", 7 | "start": "docusaurus start", 8 | "build": "docusaurus build", 9 | "swizzle": "docusaurus swizzle", 10 | "deploy": "docusaurus deploy", 11 | "clear": "docusaurus clear", 12 | "serve": "docusaurus serve", 13 | "write-translations": "docusaurus write-translations", 14 | "write-heading-ids": "docusaurus write-heading-ids", 15 | "typecheck": "tsc" 16 | }, 17 | "dependencies": { 18 | "@algolia/client-search": "^4.11.0", 19 | "@docusaurus/core": "2.0.0-beta.14", 20 | "@docusaurus/preset-classic": "2.0.0-beta.14", 21 | "@docusaurus/theme-search-algolia": "^2.0.0-beta.9", 22 | "@mdx-js/react": "^1.6.21", 23 | "@svgr/webpack": "^6.0.0", 24 | "clsx": "^1.1.1", 25 | "docusaurus-plugin-react-docgen-typescript": "^0.1.0", 26 | "file-loader": "^6.2.0", 27 | "git-branch": "^2.0.1", 28 | "prism-react-renderer": "^1.2.1", 29 | "react": "^18.0.0", 30 | "react-docgen-typescript": "^2.1.1", 31 | "react-dom": "^18.0.0", 32 | "url-loader": "^4.1.1" 33 | }, 34 | "devDependencies": { 35 | "@docusaurus/module-type-aliases": "2.0.0-beta.14", 36 | "@tsconfig/docusaurus": "^1.0.4", 37 | "@types/react": "^18.0.0", 38 | "typescript": "^4.3.5", 39 | "webpack": "^5.64.2" 40 | }, 41 | "browserslist": { 42 | "production": [ 43 | ">0.5%", 44 | "not dead", 45 | "not op_mini all" 46 | ], 47 | "development": [ 48 | "last 1 chrome version", 49 | "last 1 firefox version", 50 | "last 1 safari version" 51 | ] 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /website/sidebars.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | const { docs } = require('./docs/docs'); 4 | const { docs: faq } = require('./docs/faq/docs'); 5 | const { docs: components } = require('./docs/components/docs'); 6 | const { docs: examples } = require('./docs/examples/docs'); 7 | 8 | /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ 9 | const sidebars = { 10 | docsSidebar: [ 11 | { 12 | type: 'doc', 13 | id: 'index', 14 | label: 'Quickstart', 15 | }, 16 | ...docs.map(({ slug, title }) => ({ 17 | /** @type {'doc'} */ 18 | type: 'doc', 19 | id: slug.replace('/docs/', ''), 20 | label: title, 21 | })), 22 | ], 23 | faqSidebar: [ 24 | { 25 | type: 'doc', 26 | id: 'faq/index', 27 | label: 'Table of Contents', 28 | }, 29 | ...faq.map(({ slug, title }) => ({ 30 | /** @type {'doc'} */ 31 | type: 'doc', 32 | id: slug.replace('/', ''), 33 | label: title, 34 | })), 35 | ], 36 | componentsSidebar: [ 37 | { 38 | type: 'doc', 39 | id: 'components/index', 40 | label: 'Table of Contents', 41 | }, 42 | ...components.map(({ slug, title }) => ({ 43 | /** @type {'doc'} */ 44 | type: 'doc', 45 | id: slug.replace('/', ''), 46 | label: title, 47 | })), 48 | ], 49 | examplesSidebar: [ 50 | { 51 | type: 'doc', 52 | id: 'examples/index', 53 | label: 'Table of Contents', 54 | }, 55 | ...examples.map(({ slug, title }) => ({ 56 | /** @type {'doc'} */ 57 | type: 'doc', 58 | id: slug.replace('/', ''), 59 | label: title, 60 | })), 61 | ], 62 | }; 63 | 64 | module.exports = sidebars; 65 | -------------------------------------------------------------------------------- /website/src/components/ContextProvider.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react'; 2 | import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; 3 | import useThemeContext from '@theme/hooks/useThemeContext'; 4 | 5 | interface IContext { 6 | branch: string; 7 | theme: 'light' | 'dark'; 8 | } 9 | 10 | export default function ContextProvider({ 11 | children, 12 | }: { 13 | children(context: IContext): ReactNode; 14 | }) { 15 | const ctx = useDocusaurusContext(); 16 | const { isDarkTheme } = useThemeContext(); 17 | const context = { 18 | branch: ctx.siteConfig.customFields.branch as string, 19 | theme: isDarkTheme ? ('dark' as const) : ('light' as const), 20 | }; 21 | 22 | return children(context); 23 | } 24 | -------------------------------------------------------------------------------- /website/src/components/PropsTable.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Link from '@docusaurus/Link'; 3 | import { useDynamicImport } from 'docusaurus-plugin-react-docgen-typescript/pkg/dist-src/hooks/useDynamicImport'; 4 | 5 | function clean(description: string) { 6 | return description.replace(/\n@.*/g, ''); 7 | } 8 | 9 | function see(description: string) { 10 | const results = description.match(/@see (.*)/); 11 | 12 | if (!results) { 13 | return null; 14 | } 15 | 16 | const [, link] = results; 17 | 18 | return ( 19 | <> 20 |
21 | See more 22 | 23 | ); 24 | } 25 | 26 | export default function PropsTable({ component }: { component: string }) { 27 | const props = useDynamicImport(component); 28 | 29 | if (!props) { 30 | return null; 31 | } 32 | 33 | return ( 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | {Object.keys(props).map(key => { 46 | return ( 47 | 48 | 51 | 54 | 59 | 60 | 64 | 65 | ); 66 | })} 67 | 68 |
NameTypeDefault ValueRequiredDescription
49 | {key} 50 | 52 | {props[key].type?.name} 53 | 55 | {props[key].defaultValue && ( 56 | {props[key].defaultValue.value} 57 | )} 58 | {props[key].required ? 'Yes' : 'No'} 61 | {clean(props[key].description)} 62 | {see(props[key].description)} 63 |
69 | ); 70 | } 71 | -------------------------------------------------------------------------------- /website/src/css/custom.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Any CSS included here will be global. The classic template 3 | * bundles Infima by default. Infima is a CSS framework designed to 4 | * work well for content-centric websites. 5 | */ 6 | 7 | /* You can override the default Infima variables here. */ 8 | :root { 9 | --ifm-color-primary: #7a77ff; 10 | --ifm-color-primary-dark: #5552ff; 11 | --ifm-color-primary-darker: #433fff; 12 | --ifm-color-primary-darkest: #0c07ff; 13 | --ifm-color-primary-light: #9f9cff; 14 | --ifm-color-primary-lighter: #b1afff; 15 | --ifm-color-primary-lightest: #e8e7ff; 16 | --ifm-code-font-size: 95%; 17 | } 18 | 19 | .docusaurus-highlight-code-line { 20 | background-color: rgba(0, 0, 0, 0.1); 21 | display: block; 22 | margin: 0 calc(-1 * var(--ifm-pre-padding)); 23 | padding: 0 var(--ifm-pre-padding); 24 | } 25 | 26 | html[data-theme='dark'] .docusaurus-highlight-code-line { 27 | background-color: rgba(0, 0, 0, 0.3); 28 | } 29 | 30 | .logo { 31 | float: right; 32 | } 33 | 34 | @media (max-width: 768px) { 35 | .logo { 36 | float: none; 37 | display: block; 38 | margin: 0 auto; 39 | } 40 | } 41 | 42 | @media (min-width: 3160px) { 43 | .container { 44 | max-width: 2440px; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /website/static/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reactchartjs/react-chartjs-2/d95f0401a9a5994899de73f4fafa5d97751f36d1/website/static/.nojekyll -------------------------------------------------------------------------------- /website/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reactchartjs/react-chartjs-2/d95f0401a9a5994899de73f4fafa5d97751f36d1/website/static/img/favicon.ico -------------------------------------------------------------------------------- /website/static/img/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 12 | 13 | 14 | 17 | 18 | 19 | 22 | 25 | 28 | 31 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /website/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // This file is not used in compilation. It is here just for a nice editor experience. 3 | "extends": "@tsconfig/docusaurus/tsconfig.json", 4 | "compilerOptions": { 5 | "baseUrl": "." 6 | } 7 | } 8 | --------------------------------------------------------------------------------