├── .gitignore ├── babel.config.js ├── .eslintrc.json ├── rollup.config.js ├── .github └── workflows │ └── ci.yml ├── dist ├── vue-highcharts.min.js └── vue-highcharts.js ├── LICENSE ├── index.js ├── package.json ├── test └── test.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | npm-debug.log* 2 | node_modules 3 | coverage 4 | package-lock.json 5 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | ['@babel/preset-env'], 4 | ], 5 | }; 6 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb-base", 3 | "env": { 4 | "browser": true 5 | }, 6 | "rules": { 7 | "object-curly-newline": 0, 8 | "import/extensions": [2, "ignorePackages"] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from '@rollup/plugin-babel'; 2 | import { terser } from 'rollup-plugin-terser'; 3 | 4 | const outputOption = { 5 | name: 'VueHighcharts', 6 | globals: { vue: 'Vue' }, 7 | exports: 'named', 8 | format: 'umd', 9 | }; 10 | 11 | export default { 12 | input: 'index.js', 13 | output: [ 14 | { 15 | ...outputOption, 16 | file: 'dist/vue-highcharts.js', 17 | }, 18 | { 19 | ...outputOption, 20 | file: 'dist/vue-highcharts.min.js', 21 | plugins: [terser()], 22 | }, 23 | ], 24 | external: ['vue'], 25 | plugins: [ 26 | babel({ babelHelpers: 'bundled' }), 27 | ], 28 | }; 29 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@master 12 | - name: Use Node.js 13 | uses: actions/setup-node@v1 14 | with: 15 | node-version: '14.x' 16 | - name: Install Dependencies 17 | run: npm i 18 | - name: Build 19 | run: npm run build 20 | - name: Test 21 | run: npm test 22 | - name: Upload coverage to Codecov 23 | uses: codecov/codecov-action@v1 24 | with: 25 | token: ${{ secrets.CODECOV_TOKEN }} 26 | file: ./coverage/lcov.info 27 | if: github.event_name == 'push' 28 | continue-on-error: true 29 | -------------------------------------------------------------------------------- /dist/vue-highcharts.min.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("vue")):"function"==typeof define&&define.amd?define(["exports","vue"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).VueHighcharts={},e.Vue)}(this,(function(e,t){"use strict";var n={Highcharts:"chart",Highstock:"stockChart",Highmaps:"mapChart",HighchartsGantt:"ganttChart"};function r(){return t.h("div",{ref:"highchartsRef"})}function o(e,o){var u=o[n[e]];return u?{name:e,props:["options"],render:r,setup:function(e){var n=t.ref(null),r=t.ref(null);return t.onMounted((function(){t.watchEffect((function(){r.value=u(n.value,e.options)}))})),t.onBeforeUnmount((function(){n.value&&r.value.destroy()})),{highchartsRef:n,chart:r}}}:o.win?null:{render:r}}e.createHighcharts=o,e.default=function(e,t){Object.keys(n).forEach((function(n){var r=o(n,t.Highcharts);r&&e.component(n,r)}))},Object.defineProperty(e,"__esModule",{value:!0})})); 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Zhenye Wei 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 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import { h, ref, watchEffect, onMounted, onBeforeUnmount } from 'vue'; 2 | 3 | const ctors = { 4 | Highcharts: 'chart', 5 | Highstock: 'stockChart', 6 | Highmaps: 'mapChart', 7 | HighchartsGantt: 'ganttChart', 8 | }; 9 | 10 | function render() { 11 | return h('div', { ref: 'highchartsRef' }); 12 | } 13 | 14 | function createHighcharts(name, Highcharts) { 15 | const ctor = Highcharts[ctors[name]]; 16 | if (!ctor) { 17 | return Highcharts.win 18 | ? null 19 | // When running in server, Highcharts will not be instanced, 20 | // so there're no constructors in Highcharts, 21 | // to avoid unmated content during SSR, it returns minimum component. 22 | : { render }; 23 | } 24 | return { 25 | name, 26 | props: ['options'], 27 | render, 28 | setup(props) { 29 | const highchartsRef = ref(null); 30 | const chart = ref(null); 31 | onMounted(() => { 32 | watchEffect(() => { 33 | chart.value = ctor(highchartsRef.value, props.options); 34 | }); 35 | }); 36 | onBeforeUnmount(() => { 37 | if (highchartsRef.value) { 38 | chart.value.destroy(); 39 | } 40 | }); 41 | return { highchartsRef, chart }; 42 | }, 43 | }; 44 | } 45 | 46 | export { createHighcharts }; 47 | 48 | export default function install(app, options) { 49 | Object.keys(ctors).forEach((name) => { 50 | const component = createHighcharts(name, options.Highcharts); 51 | if (component) { 52 | app.component(name, component); 53 | } 54 | }); 55 | } 56 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-highcharts", 3 | "version": "0.2.0", 4 | "description": "Highcharts component for Vue", 5 | "main": "dist/vue-highcharts.js", 6 | "module": "index.js", 7 | "sideEffects": false, 8 | "files": [ 9 | "dist", 10 | "index.js" 11 | ], 12 | "scripts": { 13 | "lint": "eslint index.js test", 14 | "unit": "jest --collect-coverage", 15 | "test": "npm run lint && npm run unit", 16 | "dev": "rollup -c -w", 17 | "build": "rollup -c", 18 | "preversion": "npm test", 19 | "version": "npm run build && git add -A dist", 20 | "postversion": "git push && git push --tags && npm publish" 21 | }, 22 | "repository": { 23 | "type": "git", 24 | "url": "git+https://github.com/weizhenye/vue-highcharts.git" 25 | }, 26 | "keywords": [ 27 | "vue", 28 | "highcharts", 29 | "chart", 30 | "plugin", 31 | "component" 32 | ], 33 | "author": "Zhenye Wei", 34 | "license": "MIT", 35 | "bugs": { 36 | "url": "https://github.com/weizhenye/vue-highcharts/issues" 37 | }, 38 | "homepage": "https://github.com/weizhenye/vue-highcharts", 39 | "peerDependencies": { 40 | "highcharts": ">=4.2.0", 41 | "vue": ">=3" 42 | }, 43 | "devDependencies": { 44 | "@babel/core": "^7.11.6", 45 | "@babel/preset-env": "^7.11.5", 46 | "@rollup/plugin-babel": "^5.2.1", 47 | "eslint": "^7.9.0", 48 | "eslint-config-airbnb-base": "^14.2.0", 49 | "eslint-plugin-import": "^2.22.0", 50 | "highcharts": "^8.2.0", 51 | "jest": "^26.4.2", 52 | "rollup": "^2.27.1", 53 | "rollup-plugin-terser": "^7.0.2", 54 | "vue": "^3.0.0" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /dist/vue-highcharts.js: -------------------------------------------------------------------------------- 1 | (function (global, factory) { 2 | typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('vue')) : 3 | typeof define === 'function' && define.amd ? define(['exports', 'vue'], factory) : 4 | (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.VueHighcharts = {}, global.Vue)); 5 | }(this, (function (exports, vue) { 'use strict'; 6 | 7 | var ctors = { 8 | Highcharts: 'chart', 9 | Highstock: 'stockChart', 10 | Highmaps: 'mapChart', 11 | HighchartsGantt: 'ganttChart' 12 | }; 13 | 14 | function render() { 15 | return vue.h('div', { 16 | ref: 'highchartsRef' 17 | }); 18 | } 19 | 20 | function createHighcharts(name, Highcharts) { 21 | var ctor = Highcharts[ctors[name]]; 22 | 23 | if (!ctor) { 24 | return Highcharts.win ? null // When running in server, Highcharts will not be instanced, 25 | // so there're no constructors in Highcharts, 26 | // to avoid unmated content during SSR, it returns minimum component. 27 | : { 28 | render: render 29 | }; 30 | } 31 | 32 | return { 33 | name: name, 34 | props: ['options'], 35 | render: render, 36 | setup: function setup(props) { 37 | var highchartsRef = vue.ref(null); 38 | var chart = vue.ref(null); 39 | vue.onMounted(function () { 40 | vue.watchEffect(function () { 41 | chart.value = ctor(highchartsRef.value, props.options); 42 | }); 43 | }); 44 | vue.onBeforeUnmount(function () { 45 | if (highchartsRef.value) { 46 | chart.value.destroy(); 47 | } 48 | }); 49 | return { 50 | highchartsRef: highchartsRef, 51 | chart: chart 52 | }; 53 | } 54 | }; 55 | } 56 | function install(app, options) { 57 | Object.keys(ctors).forEach(function (name) { 58 | var component = createHighcharts(name, options.Highcharts); 59 | 60 | if (component) { 61 | app.component(name, component); 62 | } 63 | }); 64 | } 65 | 66 | exports.createHighcharts = createHighcharts; 67 | exports.default = install; 68 | 69 | Object.defineProperty(exports, '__esModule', { value: true }); 70 | 71 | }))); 72 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | /* global describe, it, expect */ 2 | 3 | import { createApp, ref, nextTick, onUnmounted, onBeforeUnmount } from 'vue'; 4 | import Highcharts from 'highcharts'; 5 | import loadStock from 'highcharts/modules/stock.js'; 6 | import loadMap from 'highcharts/modules/map.js'; 7 | import loadGantt from 'highcharts/modules/gantt.js'; 8 | import VueHighcharts, { createHighcharts } from '../index.js'; 9 | 10 | loadStock(Highcharts); 11 | loadMap(Highcharts); 12 | loadGantt(Highcharts); 13 | 14 | describe('vue-highcharts', () => { 15 | function createComponent(Component) { 16 | const app = createApp(Component); 17 | app.use(VueHighcharts, { Highcharts }); 18 | return app.mount(document.createElement('div')); 19 | } 20 | function checkComponent(template) { 21 | const root = createComponent({ 22 | template, 23 | setup() { 24 | return { chartRef: ref(null) }; 25 | }, 26 | }); 27 | expect(root.chartRef.highchartsRef.querySelector('.highcharts-root')).toBeDefined(); 28 | } 29 | 30 | it('should support component', () => { 31 | checkComponent(''); 32 | }); 33 | 34 | it('should support component', () => { 35 | checkComponent(''); 36 | }); 37 | 38 | it('should support component', () => { 39 | checkComponent(''); 40 | }); 41 | 42 | it('should support component', () => { 43 | checkComponent(''); 44 | }); 45 | 46 | it('can access the `chart` instance via template refs', () => { 47 | const root = createComponent({ 48 | template: '', 49 | setup() { 50 | return { chartRef: ref(null) }; 51 | }, 52 | }); 53 | expect(root.chartRef.chart).toBeDefined(); 54 | }); 55 | 56 | it('should destroy the chart instance when vm destroyed', (done) => { 57 | let chart = null; 58 | let el = null; 59 | const app = createApp({ 60 | template: '
', 61 | setup() { 62 | const divRef = ref(null); 63 | const chartRef = ref(null); 64 | onBeforeUnmount(() => { 65 | el = divRef.value; 66 | chart = chartRef.value.chart; 67 | expect(el.querySelector('.highcharts-root')).toBeDefined(); 68 | expect(chart).toBeDefined(); 69 | }); 70 | onUnmounted(() => { 71 | nextTick(() => { 72 | expect(el.querySelector('.highcharts-root')).toBeFalsy(); 73 | expect(chart).toEqual({}); 74 | done(); 75 | }); 76 | }); 77 | return { divRef, chartRef }; 78 | }, 79 | }); 80 | app.use(VueHighcharts, { Highcharts }); 81 | app.mount(document.createElement('div')); 82 | app.unmount(); 83 | }); 84 | 85 | it('should watch `options`', () => { 86 | const root = createComponent({ 87 | template: '', 88 | setup() { 89 | return { 90 | chartRef: ref(null), 91 | options: ref({ title: { text: 'origin' } }), 92 | }; 93 | }, 94 | }); 95 | expect(root.chartRef.chart.title.textStr).toBe('origin'); 96 | root.options.title.text = 'changed'; 97 | nextTick().then(() => { 98 | expect(root.chartRef.chart.title.textStr).toBe('changed'); 99 | }); 100 | }); 101 | 102 | it('can create single Componet', () => { 103 | const names = ['Highcharts', 'Highstock', 'Highmaps', 'HighchartsGantt']; 104 | names.forEach((name) => { 105 | const Component = createHighcharts(name, Highcharts); 106 | expect(Component.name).toEqual(name); 107 | }); 108 | const Unknown = createHighcharts('Unknown', Highcharts); 109 | expect(Unknown).toBeFalsy(); 110 | }); 111 | }); 112 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-highcharts 2 | 3 | [![GitHub Action](https://github.com/weizhenye/vue-highcharts/workflows/CI/badge.svg)](https://github.com/weizhenye/vue-highcharts/actions) 4 | [![Coverage](https://badgen.net/codecov/c/github/weizhenye/vue-highcharts?icon=codecov)](https://codecov.io/gh/weizhenye/vue-highcharts) 5 | [![NPM version](https://badgen.net/npm/v/vue-highcharts?icon=npm)](https://www.npmjs.com/package/vue-highcharts) 6 | [![License](https://badgen.net/npm/license/vue-highcharts?icon=https://api.iconify.design/octicon:law.svg?color=white)](https://github.com/weizhenye/vue-highcharts/blob/master/LICENSE) 7 | [![File size](https://badgen.net/bundlephobia/minzip/vue-highcharts?icon=https://api.iconify.design/ant-design:file-zip-outline.svg?color=white)](https://bundlephobia.com/result?p=vue-highcharts) 8 | [![Download](https://badgen.net/npm/dm/vue-highcharts?icon=npm)](https://www.npmjs.com/package/vue-highcharts) 9 | [![jsDelivr](https://badgen.net/jsdelivr/hits/npm/vue-highcharts?icon=https://api.iconify.design/simple-icons:jsdelivr.svg?color=white)](https://www.jsdelivr.com/package/npm/vue-highcharts) 10 | 11 | Highcharts component for Vue. 12 | 13 | ## Requirements 14 | 15 | * Vue >= 3.0.0 16 | * Highcharts >= 4.2.0 17 | 18 | ## Installation 19 | 20 | ```bash 21 | npm i -S vue-highcharts 22 | ``` 23 | 24 | For **Vue 2**, please run `npm i -S vue-highcharts@0.1`, and checkout document [here](https://github.com/weizhenye/vue-highcharts/tree/v0.1.0). 25 | 26 | ## Usage 27 | 28 | ### Registering globally 29 | 30 | ```js 31 | import { createApp } from 'vue'; 32 | import Highcharts from 'highcharts'; 33 | import VueHighcharts from 'vue-highcharts'; 34 | 35 | import App from './App.vue'; 36 | 37 | const app = createApp(App); 38 | app.use(VueHighcharts, { Highcharts }); 39 | // now is available in components 40 | ``` 41 | 42 |
43 | Direct <script> include 44 | 45 | ```html 46 | 47 | 48 | 49 | 54 | ``` 55 |
56 | 57 | ### Highstock, Highmaps and any other add-ons 58 | 59 | ```js 60 | import { createApp } from 'vue'; 61 | import Highcharts from 'highcharts'; 62 | import VueHighcharts from 'vue-highcharts'; 63 | 64 | import App from './App.vue'; 65 | 66 | // load these modules as your need 67 | import loadStock from 'highcharts/modules/stock.js'; 68 | import loadMap from 'highcharts/modules/map.js'; 69 | import loadGantt from 'highcharts/modules/gantt.js'; 70 | import loadDrilldown from 'highcharts/modules/drilldown.js'; 71 | // some charts like solid gauge require `highcharts-more.js`, you can find it in official document. 72 | import loadHighchartsMore from 'highcharts/highcharts-more.js'; 73 | import loadSolidGauge from 'highcharts/modules/solid-gauge.js'; 74 | 75 | loadStock(Highcharts); 76 | loadMap(Highcharts); 77 | loadGantt(Highcharts); 78 | loadDrilldown(Highcharts); 79 | loadHighchartsMore(Highcharts); 80 | loadSolidGauge(Highcharts); 81 | 82 | const app = createApp(App); 83 | app.use(VueHighcharts, { Highcharts }); 84 | // now , , , is available in components 85 | // drilldown and solid gauge are work with 86 | ``` 87 | 88 | ### Registering in components 89 | 90 | ```vue 91 | 95 | 96 | 113 | ``` 114 | 115 | Typing: 116 | 117 | ```ts 118 | type ChartName = 'Highcharts' | 'Highstock' | 'Highmaps' | 'HighchartsGantt'; 119 | function createHighcharts(name: ChartName, Highcharts: Highcharts): VueComponent | null 120 | ``` 121 | 122 | ### Configuration options and the chart instance 123 | 124 | ```vue 125 | 131 | 132 | 152 | ``` 153 | 154 | The `options` object can be found in [Highcharts API Reference](https://api.highcharts.com/highcharts/). 155 | 156 | The `chart` instance can be accessed with template refs. 157 | 158 | ## Demo 159 | 160 | * [Access `chart` instance via template refs](https://codepen.io/weizhenye/pen/yLeobOP) 161 | * [Synchronized charts](https://codepen.io/weizhenye/pen/PoZKmjG) 162 | * [Use Highmaps](https://codepen.io/weizhenye/pen/QWyMxaq) 163 | --------------------------------------------------------------------------------