├── .eslintignore
├── .eslintrc.json
├── .gitignore
├── LICENSE
├── README.md
├── index.js
├── package.json
├── rollup.config.js
└── src
├── components
└── VueChart.js
├── index.js
└── utils
├── equals.js
└── update.js
/.eslintignore:
--------------------------------------------------------------------------------
1 | /index.js
2 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {"extends": "seregpie"}
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017-2021 Sergej Sintschilin
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 | # VueChart
2 |
3 | A simple wrapper for Chart.js.
4 |
5 | Works for Vue 2 & 3.
6 |
7 | ## dependencies
8 |
9 | - [VueDemi](https://github.com/antfu/vue-demi)
10 |
11 | ## setup
12 |
13 | ### npm
14 |
15 | ```shell
16 | npm i @seregpie/vue-chart
17 | ```
18 |
19 | ---
20 |
21 | ```javascript
22 | import VueChart from '@seregpie/vue-chart';
23 | ```
24 |
25 | ### browser
26 |
27 | ```html
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | ```
39 |
40 | The module is globally available as `VueChart`.
41 |
42 | ## usage
43 |
44 | Register the component globally.
45 |
46 | ```javascript
47 | import {createApp} from 'vue';
48 | import VueChart from '@seregpie/vue-chart';
49 |
50 | let app = createApp({/*...*/});
51 | app.component(VueChart.name, VueChart);
52 | app.mount('body');
53 | ```
54 |
55 | *or*
56 |
57 | Register the component locally.
58 |
59 | ```javascript
60 | import VueChart from '@seregpie/vue-chart';
61 |
62 | export default {
63 | components: {
64 | VueChart,
65 | },
66 | // ...
67 | };
68 | ```
69 |
70 | ---
71 |
72 | ```html
73 |
79 | ```
80 |
81 | ## properties
82 |
83 | | name | type | description |
84 | | ---: | :--- | :--- |
85 | | `data` | `Object` | The data of the chart. |
86 | | `options` | `Object` | The configuration options of the chart of the current type. |
87 | | `type` | `String` | The type of the chart. Changing the value will recreate the chart. |
88 | | `updateMode` | `String` | The mode for the update process. |
89 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("chart.js"),require("vue-demi")):"function"==typeof define&&define.amd?define(["chart.js","vue-demi"],t):(e="undefined"!=typeof globalThis?globalThis:e||self).VueChart=t(e.Chart,e.VueDemi)}(this,(function(e,t){"use strict";var n=Object.is;let{isArray:i,isObject:o}=e.helpers;function r(e,t){if(n(e,t))return e;if(i(t)){if(i(e)){let n=e.length,i=t.length;for(let o=0,s=Math.min(n,i);oi?e.splice(i):n{n.has(o)?i.has(o)?e[o]=r(e[o],t[o]):delete e[o]:i.has(o)&&(e[o]=t[o])})),e}return t}let{clone:s}=e.helpers;var a,u,l=t.defineComponent({name:"VueChart",props:{data:Object,options:Object,type:{type:String,required:!0},updateMode:String},setup(n,{refs:i}){let o,a=t.ref(null);return t.onMounted((()=>{let u=t.isVue2?i.canvas:a.value;t.watchEffect((()=>{let{data:t,options:i,type:a,updateMode:l}=n;t=s(t),i=s(i),o=(()=>{if(o){if(o.config.type===a)return r(o.data,t),o.options=i,o.update(l),o;o.destroy()}return new e.Chart(u,{type:a,data:t,options:i})})()}))})),t.onUnmounted((()=>{o&&o.destroy()})),()=>t.h("div",{style:{height:"100%",position:"relative",width:"100%"}},[t.h("canvas",{style:{bottom:0,left:0,position:"absolute",right:0,top:0},ref:t.isVue2?"canvas":a})])}});t.isVue2&&(null===(a=globalThis.window)||void 0===a||null===(u=a.Vue)||void 0===u||u.component(l.name,l));return l}));
2 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@seregpie/vue-chart",
3 | "version": "1.1.0",
4 | "description": "A simple wrapper for Chart.js.",
5 | "keywords": [
6 | "area",
7 | "bar",
8 | "canvas",
9 | "chart",
10 | "component",
11 | "diagram",
12 | "doughnut",
13 | "line",
14 | "pie",
15 | "plugin",
16 | "polar",
17 | "radar",
18 | "scatter",
19 | "vue"
20 | ],
21 | "license": "MIT",
22 | "author": "Sergej Sintschilin ",
23 | "files": [],
24 | "main": "index.js",
25 | "repository": "github:SeregPie/VueChart",
26 | "scripts": {
27 | "build": "rollup -c",
28 | "prepublishOnly": "npm run build",
29 | "serve": "rollup -c -w"
30 | },
31 | "dependencies": {
32 | "vue-demi": "*"
33 | },
34 | "devDependencies": {
35 | "@babel/core": "^7.14.3",
36 | "@babel/preset-env": "^7.14.2",
37 | "@rollup/plugin-babel": "^5.3.0",
38 | "eslint": "^7.27.0",
39 | "eslint-config-seregpie": "^1.0.2",
40 | "rollup": "^2.49.0",
41 | "rollup-plugin-terser": "^7.0.2"
42 | },
43 | "peerDependencies": {
44 | "chart.js": "^3",
45 | "vue": "^2 || ^3"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import {babel} from '@rollup/plugin-babel';
2 | import {terser} from 'rollup-plugin-terser';
3 |
4 | import {main} from './package.json';
5 |
6 | let globals = {
7 | 'chart.js': 'Chart',
8 | 'vue-demi': 'VueDemi',
9 | };
10 |
11 | export default {
12 | external: Object.keys(globals),
13 | input: 'src/index.js',
14 | plugins: [
15 | babel({
16 | babelHelpers: 'bundled',
17 | presets: [['@babel/preset-env', {
18 | targets: 'defaults and not IE 11',
19 | }]],
20 | }),
21 | terser(),
22 | ],
23 | output: {
24 | file: main,
25 | format: 'umd',
26 | name: 'VueChart',
27 | globals,
28 | },
29 | };
30 |
--------------------------------------------------------------------------------
/src/components/VueChart.js:
--------------------------------------------------------------------------------
1 | import {
2 | Chart,
3 | helpers,
4 | } from 'chart.js';
5 | import {
6 | defineComponent,
7 | h,
8 | isVue2,
9 | onMounted,
10 | onUnmounted,
11 | ref,
12 | watchEffect,
13 | } from 'vue-demi';
14 |
15 | let {clone} = helpers;
16 |
17 | import update from '../utils/update';
18 |
19 | export default defineComponent({
20 | name: 'VueChart',
21 | props: {
22 | data: Object,
23 | options: Object,
24 | type: {
25 | type: String,
26 | required: true,
27 | },
28 | updateMode: String,
29 | },
30 | setup(props, {refs}) {
31 | let chart;
32 | let canvasRef = ref(null);
33 | onMounted(() => {
34 | let canvas = isVue2 ? refs.canvas : canvasRef.value;
35 | watchEffect(() => {
36 | let {
37 | data,
38 | options,
39 | type,
40 | updateMode,
41 | } = props;
42 | data = clone(data);
43 | options = clone(options);
44 | chart = (() => {
45 | if (chart) {
46 | if (chart.config.type === type) {
47 | // todo
48 | update(chart.data, data);
49 | chart.options = options;
50 | chart.update(updateMode);
51 | return chart;
52 | }
53 | chart.destroy();
54 | }
55 | return new Chart(canvas, {type, data, options});
56 | })();
57 | });
58 | });
59 | onUnmounted(() => {
60 | if (chart) {
61 | chart.destroy();
62 | }
63 | });
64 | return (() => {
65 | return h(
66 | 'div',
67 | {
68 | style: {
69 | height: '100%',
70 | position: 'relative',
71 | width: '100%',
72 | },
73 | },
74 | [h(
75 | 'canvas',
76 | {
77 | style: {
78 | bottom: 0,
79 | left: 0,
80 | position: 'absolute',
81 | right: 0,
82 | top: 0,
83 | },
84 | ref: isVue2 ? 'canvas' : canvasRef,
85 | },
86 | )],
87 | );
88 | });
89 | },
90 | });
91 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import component from './components/VueChart';
2 |
3 | export default component;
4 |
5 | import {isVue2} from 'vue-demi';
6 |
7 | if (isVue2) {
8 | globalThis.window?.Vue?.component(component.name, component);
9 | }
10 |
--------------------------------------------------------------------------------
/src/utils/equals.js:
--------------------------------------------------------------------------------
1 | export default Object.is;
2 |
--------------------------------------------------------------------------------
/src/utils/update.js:
--------------------------------------------------------------------------------
1 | import {helpers} from 'chart.js';
2 |
3 | let {
4 | isArray,
5 | isObject,
6 | } = helpers;
7 |
8 | import equals from './equals';
9 |
10 | function update(target, source) {
11 | if (equals(target, source)) {
12 | return target;
13 | }
14 | if (isArray(source)) {
15 | if (isArray(target)) {
16 | let targetLength = target.length;
17 | let sourceLength = source.length;
18 | for (let i = 0, ii = Math.min(targetLength, sourceLength); i < ii; i++) {
19 | target[i] = update(target[i], source[i]);
20 | }
21 | if (targetLength > sourceLength) {
22 | target.splice(sourceLength);
23 | } else
24 | if (targetLength < sourceLength) {
25 | target.push(...source.slice(targetLength));
26 | }
27 | return target;
28 | }
29 | } else
30 | if (isObject(source)) {
31 | if (isObject(target)) {
32 | let targetKeys = new Set(Object.keys(target));
33 | let sourceKeys = new Set(Object.keys(source));
34 | (new Set([...targetKeys, ...sourceKeys])).forEach(key => {
35 | if (targetKeys.has(key)) {
36 | if (sourceKeys.has(key)) {
37 | target[key] = update(target[key], source[key]);
38 | } else {
39 | delete target[key];
40 | }
41 | } else {
42 | if (sourceKeys.has(key)) {
43 | target[key] = source[key];
44 | }
45 | }
46 | });
47 | return target;
48 | }
49 | }
50 | return source;
51 | }
52 |
53 | export default update;
54 |
--------------------------------------------------------------------------------