├── .eslintrc.js ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── babel.config.js ├── demo ├── components │ ├── Chart.jsx │ ├── Container.jsx │ ├── Map.jsx │ └── Stock.jsx ├── data │ └── mapData.js ├── demo.jsx └── index.html ├── dist ├── highcharts-react.d.ts ├── highcharts-react.js ├── highcharts-react.js.map ├── highcharts-react.min.d.ts ├── highcharts-react.min.js └── highcharts-react.min.js.map ├── index.js ├── package.json ├── src ├── HighchartsReact.d.ts └── HighchartsReact.js ├── tests ├── ParentComponent.jsx ├── __tests__ │ ├── component │ │ ├── addModule.test.js │ │ ├── chartReference.test.js │ │ ├── componentWithoutProps.test.js │ │ ├── dynamics.test.js │ │ ├── importComponent.test.js │ │ └── multipleCharts.test.js │ └── props │ │ ├── allowChartUpdate.test.js │ │ ├── callback.test.js │ │ ├── constructorType.test.js │ │ ├── containerProps.test.js │ │ ├── highcharts.test.js │ │ ├── immutable.test.js │ │ └── updateArgs.test.js └── setupTests.js └── webpack.config.js /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "env": { 3 | "browser": true, 4 | "jest": true, 5 | "node": true, 6 | "es6": true 7 | }, 8 | "globals": { 9 | "Atomics": "readonly", 10 | "SharedArrayBuffer": "readonly" 11 | }, 12 | "parserOptions": { 13 | "ecmaFeatures": { 14 | "jsx": true 15 | }, 16 | "ecmaVersion": 2018, 17 | "sourceType": "module" 18 | }, 19 | "plugins": [ 20 | "react" 21 | ], 22 | "extends": [ 23 | "eslint:recommended", 24 | "plugin:react/recommended" 25 | ], 26 | "rules": { 27 | "indent": ["error", 2], 28 | "camelcase": [2, {"properties": "always"}], 29 | "comma-dangle": [2, "never"], 30 | "dot-location": [2, "property"], 31 | "lines-around-comment": 0, 32 | "newline-after-var": 0, 33 | "no-alert": 2, 34 | "no-debugger": 2, 35 | "no-else-return": 2, 36 | "no-nested-ternary": 0, 37 | "no-param-reassign": 0, 38 | "no-restricted-properties": 0, 39 | "no-unmodified-loop-condition": 0, 40 | "no-useless-escape": 0, 41 | "no-var": 2, 42 | "object-curly-spacing": [2, "always"], 43 | "operator-assignment": 0, 44 | "operator-linebreak": [2, "after"], 45 | "padding-line-between-statements": 0, 46 | "prefer-arrow-callback": 0, 47 | "prefer-spread": 0, 48 | "react/jsx-curly-spacing": [2, "always"], 49 | "react/prop-types": 0, 50 | "semi": [2, "always"], 51 | "space-before-function-paren": [2, {"anonymous": "always", "named": "never"}], 52 | "strict": 0, 53 | "valid-jsdoc": ["error", { prefer: { "returns": "return"}}], 54 | "quotes": [2, "single"] 55 | } 56 | }; 57 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | demo/bundle.js 3 | package-lock.json 4 | yarn.lock 5 | .source.* 6 | .DS_Store 7 | -------------------------------------------------------------------------------- /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 | ### [3.2.1](https://github.com/highcharts/highcharts-react/compare/v3.0.0...v3.2.1) (2023-08-31) 6 | 7 | ### Features 8 | 9 | * adapted TS definitions for version 5.2.2 ([c24b667](https://github.com/highcharts/highcharts-react/commit/c24b667)) 10 | * exported HighchartsReactProps HighchartsReactRefObject types ([774c47b](https://github.com/highcharts/highcharts-react/commit/774c47b)) 11 | 12 | # [3.2.0](https://github.com/highcharts/highcharts-react/compare/v3.1.0...v3.2.0) (2023-03-01) 13 | 14 | ### Features 15 | 16 | * restricted chart update by adding props: `options`, `allowChartUpdate`, `updateArgs`, `containerProps`, `highcharts`, `constructorType` to useEffect dependency array ([30a9e1f](https://github.com/highcharts/highcharts-react/commit/30a9e1f)) 17 | * updated Highcharts with TypeScript section in README ([7c32a50](https://github.com/highcharts/highcharts-react/commit/7c32a50)) 18 | * added HighchartsReact named export ([ceadaf1](https://github.com/highcharts/highcharts-react/commit/ceadaf1)) 19 | * fixed build-demo script ([d9a82b7](https://github.com/highcharts/highcharts-react/commit/d9a82b7)) 20 | * fixed #366 - recreate a chart on constructorType or highcharts props change ([30a9e1f](https://github.com/highcharts/highcharts-react/commit/30a9e1f)) 21 | 22 | # [3.1.0](https://github.com/highcharts/highcharts-react/compare/v3.0.0...v3.1.0) (2021-10-14) 23 | 24 | ### Features 25 | 26 | * increase Highcharts dev dependency to >=9.0.0 ([f7f9efc](https://github.com/highcharts/highcharts-react/commit/f7f9efc)) 27 | * updated docs ([589c096](https://github.com/highcharts/highcharts-react/commit/589c096)) 28 | * removed Highcharts import in HighchartsReact component ([8344597](https://github.com/highcharts/highcharts-react/commit/8344597)) 29 | * improved component types([746ccb8](https://github.com/highcharts/highcharts-react/commit/746ccb8)) 30 | 31 | 32 | # [3.0.0](https://github.com/highcharts/highcharts-react/compare/v2.2.2...v3.0.0) (2020-02-17) 33 | 34 | 35 | ### Features 36 | 37 | * increase React peer dependency to v16.8.0 ([030ac4e](https://github.com/highcharts/highcharts-react/commit/030ac4e)) 38 | * refactor component with React Hooks ([c8b1e55](https://github.com/highcharts/highcharts-react/commit/c8b1e55)) 39 | * refactor tests ([634a7e7](https://github.com/highcharts/highcharts-react/commit/25f5ecb)) 40 | 41 | 42 | ### BREAKING CHANGES 43 | 44 | * To upgrade, run `yarn add react@^16.8.0 react-dom@^16.8.0` or `npm install --save react@^16.8.0 react-dom@^16.8.0`. 45 | If you're using `react-test-renderer`, you'll need to bump it to `^16.8.0` as well. 46 | 47 | 48 | 49 | 50 | ## [2.2.2](https://github.com/highcharts/highcharts-react/compare/v2.2.1...v2.2.2) (2019-06-07) 51 | 52 | 53 | ### Bug Fixes 54 | 55 | * Changed the way of importing Highcharts package. ([e7c314b](https://github.com/highcharts/highcharts-react/commit/e7c314b)) 56 | 57 | 58 | ### Features 59 | 60 | * **husky:** Husky added. ([1d8234a](https://github.com/highcharts/highcharts-react/commit/1d8234a)) 61 | 62 | 63 | 64 | 65 | ## [2.2.1](https://github.com/highcharts/highcharts-react/compare/v2.2.0...v2.2.1) (2019-06-07) 66 | 67 | 68 | ### Bug Fixes 69 | 70 | * **webpack:** Externals extended. Closes [#132](https://github.com/highcharts/highcharts-react/issues/132) ([193b3d2](https://github.com/highcharts/highcharts-react/commit/193b3d2)) 71 | 72 | 73 | 74 | 75 | # [2.2.0](https://github.com/highcharts/highcharts-react/compare/v2.1.3...v2.2.0) (2019-06-07) 76 | 77 | 78 | ### Bug Fixes 79 | 80 | * Fixed externals [#114](https://github.com/highcharts/highcharts-react/issues/114). ([ee27ed0](https://github.com/highcharts/highcharts-react/commit/ee27ed0)) 81 | 82 | 83 | ### Features 84 | 85 | * **debugger:** Added warning messages. ([3b3ff83](https://github.com/highcharts/highcharts-react/commit/3b3ff83)) 86 | * **immutable:** Support for immutable prop - rerendering entire chart on componentDidUpdate. ([6464894](https://github.com/highcharts/highcharts-react/commit/6464894)) 87 | 88 | 89 | 90 | 91 | ## [2.1.3](https://github.com/highcharts/highcharts-react/compare/v2.1.2...v2.1.3) (2019-03-27) 92 | 93 | 94 | ## Features 95 | 96 | * Fixed [#106](https://github.com/highcharts/highcharts-react/issues/106) - incorrect typescript typing ([4ffad38](https://github.com/highcharts/highcharts-react/commit/4ffad38)) 97 | 98 | 99 | 100 | 101 | ## [2.1.2](https://github.com/highcharts/highcharts-react/compare/v2.1.1...v2.1.2) (2019-03-20) 102 | 103 | 104 | ## Features 105 | 106 | * Fixed [#102](https://github.com/highcharts/highcharts-react/issues/102) - tsconfig incompatibility ([4e27d0d](https://github.com/highcharts/highcharts-react/commit/4e27d0d)) 107 | * Corrections in the documentation. 108 | 109 | 110 | 111 | 112 | ## [2.1.1](https://github.com/highcharts/highcharts-react/compare/v2.1.0...v2.1.1) (2019-03-07) 113 | 114 | 115 | ## Features 116 | 117 | * Fixed [#20](https://github.com/highcharts/highcharts-react/issues/20) - invalid indexer type ([1345d32](https://github.com/highcharts/highcharts-react/commit/1345d32)) 118 | 119 | 120 | 121 | 122 | # [2.1.0](https://github.com/highcharts/highcharts-react/compare/v2.0.0...v2.1.0) (2019-03-07) 123 | 124 | 125 | ### Features 126 | 127 | * Added `containerProps` option and corrections to the docs. ([f14a969](https://github.com/highcharts/highcharts-react/commit/f14a969)) 128 | * Added TypeScript declarations. ([b64eb01](https://github.com/highcharts/highcharts-react/commit/b64eb01)) 129 | 130 | 131 | 132 | 133 | # [2.0.0](https://github.com/highcharts/highcharts-react/compare/v1.5.1...v2.0.0) (2018-11-08) 134 | 135 | 136 | ### Features 137 | 138 | * **webpack-and-sourcemap-added:** Code compiled to ES5, added sourcemaps. ([cb5083a](https://github.com/highcharts/highcharts-react/commit/cb5083a)) 139 | * Updated for React v16 ([20c7ef9](https://github.com/highcharts/highcharts-react/commit/20c7ef9)) 140 | 141 | 142 | 143 | 144 | ## [1.4.1](https://github.com/highcharts/highcharts-react/compare/v1.4.0...v1.4.1) (2018-10-26) 145 | 146 | 147 | 148 | 149 | # [1.4.0](https://github.com/highcharts/highcharts-react/compare/v1.3.2...v1.4.0) (2018-08-24) 150 | 151 | 152 | ### Features 153 | 154 | * Added changelog. ([097ca9a](https://github.com/highcharts/highcharts-react/commit/097ca9a)) 155 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Highcharts React 2 | 3 | Copyright (c) 2016-2017, Highsoft 4 | 5 | The software in Highcharts React repository is free and open source, 6 | but as highcharts-react relies on Highcharts.js, it requires a valid 7 | Highcharts license for commercial use. 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining 10 | a copy of this software and associated documentation files (the 11 | "Software"), to deal in the Software without restriction, including 12 | without limitation the rights to use, copy, modify, merge, publish, 13 | distribute, sublicense, and/or sell copies of the Software, and to 14 | permit persons to whom the Software is furnished to do so, subject to 15 | the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be 18 | included in all copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 23 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 24 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 25 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 26 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Highcharts React 2 | Official minimal [Highcharts](https://www.highcharts.com/) integration for React. 3 | 4 | **Note: the beta of the upcoming v4 of the Highcharts React integration is 5 | now available at [`@highcharts/react@next`](https://www.npmjs.com/package/@highcharts/react/)** 6 | 7 | ## Table of Contents 8 | 1. [Getting started](#getting-started) 9 | 1. [General prerequisites](#general-prerequisites) 10 | 2. [Installing](#installing) 11 | 3. [Using](#using) 12 | 1. [Basic usage example](#basic-usage-example) 13 | 2. [Highcharts with NextJS](#highcharts-with-nextjs) 14 | 3. [Highcharts with TypeScript](#highcharts-with-typescript) 15 | 4. [Optimal way to update](#optimal-way-to-update) 16 | 2. [Options details](#options-details) 17 | 3. [Example with custom chart component](#example-with-custom-chart-component) 18 | 4. [Get repository](#get-repository) 19 | 5. [Examples](#examples) 20 | 6. [Tests](#tests) 21 | 7. [Changelog](#changelog) 22 | 8. [FAQ](#faq) 23 | 1. [Where to look for help?](#where-to-look-for-help) 24 | 2. [Why highcharts-react-official and not highcharts-react is used?](#why-highcharts-react-official-and-not-highcharts-react-is-used) 25 | 3. [How to get a chart instance?](#how-to-get-a-chart-instance) 26 | 4. [How to add a module?](#how-to-add-a-module) 27 | 5. [How to add React component to a chart's element?](#how-to-add-react-component-to-a-charts-element) 28 | 6. [Why Highcharts mutates my data?](#why-highcharts-mutates-my-data) 29 | 30 | ## Getting Started 31 | 32 | ### General prerequisites 33 | 34 | Make sure you have **node**, **NPM** and **React** up to date. 35 | Tested and required versions: 36 | 37 | * `node` 8.11.3+ 38 | * `npm` 6.4.1+ or similar package manager 39 | 40 | This integration also requires highcharts and react packages with the following versions installed in your project: 41 | 42 | For version **2.x.x** : 43 | 44 | * `react` 16.4+ 45 | * `highcharts` 5.0.0+ 46 | 47 | For version **3.x.x** : 48 | 49 | * `react` 16.8+ 50 | * `highcharts` 6.0.0+ 51 | 52 | ### Installing 53 | 54 | Get the package from NPM in your React app: 55 | 56 | ```bash 57 | npm install highcharts-react-official 58 | ``` 59 | 60 | If Highcharts is not already installed, get the package with Highcharts: 61 | 62 | ```bash 63 | npm install highcharts highcharts-react-official 64 | ``` 65 | 66 | ### Using 67 | 68 | #### Basic usage example 69 | 70 | Import into your React project and render a chart: 71 | 72 | ```jsx 73 | import React from 'react' 74 | import { render } from 'react-dom' 75 | import Highcharts from 'highcharts' 76 | import HighchartsReact from 'highcharts-react-official' 77 | 78 | const options = { 79 | title: { 80 | text: 'My chart' 81 | }, 82 | series: [{ 83 | data: [1, 2, 3] 84 | }] 85 | } 86 | 87 | const App = () =>
88 | 92 |
93 | 94 | render(, document.getElementById('root')) 95 | ``` 96 | 97 | ### Highcharts with TypeScript 98 | 99 | Live example: https://stackblitz.com/edit/react-starter-typescript-cfcznt 100 | 101 | ```tsx 102 | import React, { useRef } from 'react'; 103 | import * as Highcharts from 'highcharts'; 104 | import { HighchartsReact } from 'highcharts-react-official'; 105 | 106 | // The integration exports only a default component that at the same time is a 107 | // namespace for the related Props interface (HighchartsReact.Props) and 108 | // RefObject interface (HighchartsReact.RefObject). All other interfaces 109 | // like Options come from the Highcharts module itself. 110 | 111 | const options: Highcharts.Options = { 112 | title: { 113 | text: 'My chart' 114 | }, 115 | series: [{ 116 | type: 'line', 117 | data: [1, 2, 3] 118 | }] 119 | }; 120 | 121 | const App = (props: HighchartsReact.Props) => { 122 | const chartComponentRef = useRef(null); 123 | 124 | return ( 125 | 131 | ); 132 | }; 133 | // Render your App component into the #root element of the document. 134 | ReactDOM.render(, document.getElementById('root')); 135 | ``` 136 | 137 | Since version 3.2.1 it is also possible to import types for `props` and `ref` independently: 138 | 139 | ```tsx 140 | import HighchartsReact, { HighchartsReactRefObject, HighchartsReactProps } from 'highcharts-react-official'; 141 | ``` 142 | 143 | ### Highcharts with NextJS 144 | 145 | Next.js executes code twice - on server-side and then client-side. First run is done in an environment that lacks `window` and causes Highcharts to be loaded, but not initialized. Easy fix is to place all modules inits in a `if` checking if Highcharts is an object or a function. It should be an object for modules initialization to work without any errors, so code like below is an easy fix: 146 | 147 | ```jsx 148 | import React from 'react' 149 | import Highcharts from 'highcharts' 150 | import HighchartsExporting from 'highcharts/modules/exporting' 151 | import HighchartsReact from 'highcharts-react-official' 152 | 153 | if (typeof Highcharts === 'object') { 154 | HighchartsExporting(Highcharts) 155 | } 156 | 157 | ... 158 | ``` 159 | 160 | This is a know issue with NextJS and is covered here: https://github.com/vercel/next.js/issues/5354 161 | 162 | ### Optimal way to update 163 | 164 | A good practice is to keep all chart options in the state. When `setState` is called, the options are overwritten and only the new ones are passed to the `chart.update` method. 165 | 166 | **Live example:** https://stackblitz.com/edit/react-hketvd?file=index.js 167 | 168 | **Optimal way to update with React Hooks:** https://stackblitz.com/edit/react-nwseym?file=index.js 169 | 170 | ```jsx 171 | import React, { Component } from 'react'; 172 | import { render } from 'react-dom'; 173 | import HighchartsReact from 'highcharts-react-official'; 174 | import Highcharts from 'highcharts'; 175 | 176 | class LineChart extends Component { 177 | constructor(props) { 178 | super(props); 179 | 180 | this.state = { 181 | // To avoid unnecessary update keep all options in the state. 182 | chartOptions: { 183 | xAxis: { 184 | categories: ['A', 'B', 'C'], 185 | }, 186 | series: [ 187 | { data: [1, 2, 3] } 188 | ], 189 | plotOptions: { 190 | series: { 191 | point: { 192 | events: { 193 | mouseOver: this.setHoverData.bind(this) 194 | } 195 | } 196 | } 197 | } 198 | }, 199 | hoverData: null 200 | }; 201 | } 202 | 203 | setHoverData = (e) => { 204 | // The chart is not updated because `chartOptions` has not changed. 205 | this.setState({ hoverData: e.target.category }) 206 | } 207 | 208 | updateSeries = () => { 209 | // The chart is updated only with new options. 210 | this.setState({ 211 | chartOptions: { 212 | series: [ 213 | { data: [Math.random() * 5, 2, 1]} 214 | ] 215 | } 216 | }); 217 | } 218 | 219 | render() { 220 | const { chartOptions, hoverData } = this.state; 221 | 222 | return ( 223 |
224 | 228 |

Hovering over {hoverData}

229 | 230 |
231 | ) 232 | } 233 | } 234 | 235 | render(, document.getElementById('root')); 236 | ``` 237 | 238 | ## Options details 239 | 240 | Available options with example values: 241 | 242 | ```jsx 243 | 253 | ``` 254 | 255 | | Parameter | Type | Required | Defaults | Description | 256 | | --------- | :----: | :--------: | :--------: | ----------- | 257 | | `options` | Object | yes | - | Highcharts chart configuration object. Please refer to the Highcharts [API documentation](https://api.highcharts.com/highcharts/). | 258 | | `highcharts` | Object | yes | - | Used to pass the Highcharts instance after modules are initialized. If not set the component will try to get the Highcharts from window. | 259 | | `constructorType` | String | no | `'chart'` | String for [constructor method](https://www.highcharts.com/docs/getting-started/your-first-chart). Official constructors:
- `'chart'` for Highcharts charts
- `'stockChart'` for Highstock charts
- `'mapChart'` for Highmaps charts
- `'ganttChart'` for Gantt charts| 260 | | `allowChartUpdate` | Boolean | no | `true` | This integration uses `chart.update()` method to apply new options to the chart when changing the parent component. This option allow to turn off the updating. | 261 | | `immutable` | Boolean | no | `false` | Reinitialises the chart on prop update (as oppose to `chart.update()`) - useful in some cases but slower than a regular update.| 262 | | `updateArgs` | Array | no | `[true, true, true]` | Array of `update()`'s function optional arguments. Parameters should be defined in the same order like in native Highcharts function: `[redraw, oneToOne, animation]`. [Here](https://api.highcharts.com/class-reference/Highcharts.Chart#update) is a more specific description of the parameters.| 263 | | `containerProps` | Object | no | - | The props object passed to the chart container in `React.createElement` method. Useful for adding styles or class.| 264 | | `callback` | Function | no | - | A callback function for the created chart. First argument for the function will hold the created `chart`. Default `this` in the function points to the `chart`. This option is optional. | 265 | 266 | 267 | ## Example with custom chart component 268 | 269 | Create custom component `./components/MyStockChart.jsx`: 270 | 271 | ```jsx 272 | import React from 'react' 273 | import Highcharts from 'highcharts/highstock' 274 | import HighchartsReact from 'highcharts-react-official' 275 | 276 | const options = { 277 | title: { 278 | text: 'My stock chart' 279 | }, 280 | series: [{ 281 | data: [1, 2, 3] 282 | }] 283 | } 284 | 285 | const MyStockChart = () => 290 | 291 | export default MyStockChart 292 | ``` 293 | 294 | Render your custom chart component like below: 295 | 296 | ```jsx 297 | import React from 'react' 298 | import { render } from 'react-dom' 299 | import MyStockChart from './components/MyStockChart.jsx' 300 | 301 | const App = () =>
302 | 303 |
304 | 305 | render(, document.getElementById('root')) 306 | ``` 307 | 308 | ## Get repository 309 | 310 | Clone github repository and install dependencies: 311 | 312 | ```bash 313 | git clone https://github.com/highcharts/highcharts-react 314 | cd highcharts-react 315 | npm install 316 | ``` 317 | 318 | Examples and tests require Highcharts library, don't forget to: 319 | 320 | ```bash 321 | npm install highcharts 322 | ``` 323 | 324 | ## Examples 325 | 326 | There are several interesting examples in the demo folder that use all available constructors and several modules. 327 | 328 | Bundle these with: 329 | 330 | ```bash 331 | npm run build-demo 332 | ``` 333 | 334 | Demo is located under demo/index.html 335 | 336 | Live example: https://stackblitz.com/edit/react-4ded5d?file=index.js 337 | 338 | ## Tests 339 | 340 | This integration contains tests for: testing environment, chart rendering and passing down container props. 341 | To run tests, type: 342 | 343 | ```bash 344 | npm run test 345 | ``` 346 | 347 | ## Changelog 348 | The changelog is available [here](https://github.com/highcharts/highcharts-react/blob/master/CHANGELOG.md). 349 | 350 | ## FAQ 351 | 352 | ### Where to look for help? 353 | 354 | [Technical support](https://www.highcharts.com/support) will help you with Highcharts and with the integration. 355 | 356 | If you have a bug to report or an enhancement suggestion please submit [Issues](https://github.com/highcharts/highcharts-react/issues) in this repository. 357 | 358 | ### Why highcharts-react-official and not highcharts-react is used? 359 | 360 | The NPM package is registered as `highcharts-react-official` because `highcharts-react` was already taken. 361 | 362 | ### How to get a chart instance? 363 | 364 | For class components and version prior to 3.0.0 use `React.createRef`: 365 | 366 | ```jsx 367 | constructor(props) { 368 | super(props) 369 | this.chartRef = React.createRef(); 370 | } 371 | 372 | render() { 373 | return ( 374 | 379 | ); 380 | } 381 | ``` 382 | 383 | For functional components and version 3.0.0 and later use `useRef` hook: 384 | 385 | ```jsx 386 | const chartComponent = useRef(null); 387 | const [options] = useState({...}); 388 | 389 | useEffect(() => { 390 | const chart = chartComponent.current.chart; 391 | ... 392 | }, []); 393 | 394 | return ; 395 | ``` 396 | 397 | Alternatively store a chart reference in a callback function: 398 | 399 | ```jsx 400 | afterChartCreated = (chart) => { 401 | // Highcharts creates a separate chart instance during export 402 | if (!chart.options.chart.forExport) { 403 | this.internalChart = chart; 404 | } 405 | } 406 | 407 | componentDidMount() { 408 | // example of use 409 | this.internalChart.addSeries({ data: [1, 2, 3] }) 410 | } 411 | 412 | render() { 413 | return ( 414 |
415 |

Highcharts

416 | 421 |
422 | ); 423 | } 424 | ``` 425 | 426 | ### How to add a module? 427 | 428 | To add a module, import it like so: 429 | 430 | ```jsx 431 | import Highcharts from 'highcharts' 432 | import highchartsGantt from "highcharts/modules/gantt"; // The Gantt module 433 | import HighchartsReact from 'highcharts-react-official' 434 | 435 | // Init the module (only for Highcharts v < 12) 436 | if (typeof highchartsGantt === 'function') { 437 | highchartsGantt(Highcharts); 438 | } 439 | ``` 440 | 441 | 442 | ### How to add React component to a chart's element? 443 | 444 | By using [Portals](https://en.reactjs.org/docs/portals.html) it is possible to add a component to every HTML chart element. 445 | 446 | Live example: https://codesandbox.io/s/1o5y7r31k3 447 | 448 | ### Why Highcharts mutates my data? 449 | 450 | It can be confusing, since React props are read-only, but Highcharts for performance reasons mutates the original data array. This behaviour is NOT changed by our integration. You need to pass a copy of your data to the integration if you want to prevent mutations. 451 | 452 | Issue: https://github.com/highcharts/highcharts-react/issues/326
453 | More discussion here: https://github.com/highcharts/highcharts/issues/4259 454 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['@babel/preset-env', '@babel/preset-react'] 3 | }; 4 | -------------------------------------------------------------------------------- /demo/components/Chart.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import HighchartsReact from '../../' 3 | 4 | const Chart = ({ options, highcharts }) => 9 | 10 | export default Chart 11 | -------------------------------------------------------------------------------- /demo/components/Container.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import HighchartsReact from '../../' 3 | import Highcharts from 'highcharts' 4 | 5 | export default class Container extends React.Component { 6 | constructor () { 7 | super() 8 | this.state = { data: [] } 9 | setInterval(() => this.setState({ data: [...Array(3)].map(Math.random) }), 1500) 10 | } 11 | 12 | render () { 13 | const cb = function () {} 14 | return ( 15 |
16 | 21 |
22 | ) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /demo/components/Map.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import HighchartsReact from '../../' 3 | 4 | const MapChart = ({ options, highcharts }) => 9 | 10 | export default MapChart 11 | -------------------------------------------------------------------------------- /demo/components/Stock.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import HighchartsReact from '../../' 3 | 4 | const StockChart = ({ options, highcharts }) => 9 | 10 | export default StockChart 11 | -------------------------------------------------------------------------------- /demo/demo.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { render } from 'react-dom' 3 | // Import Highcharts 4 | import Highcharts from 'highcharts/highstock' 5 | 6 | // Import our demo components 7 | import Chart from './components/Chart.jsx' 8 | import StockChart from './components/Stock.jsx' 9 | import MapChart from './components/Map.jsx' 10 | import Container from './components/Container.jsx' 11 | import mapData from './data/mapData.js' 12 | 13 | // Load Highcharts modules 14 | require('highcharts/indicators/indicators')(Highcharts) 15 | require('highcharts/indicators/pivot-points')(Highcharts) 16 | require('highcharts/indicators/macd')(Highcharts) 17 | require('highcharts/modules/exporting')(Highcharts) 18 | require('highcharts/modules/map')(Highcharts) 19 | 20 | const chartOptions = { 21 | title: { 22 | text: '' 23 | }, 24 | series: [{ 25 | data: [1,2,3], 26 | 27 | }] 28 | } 29 | const stockOptions = { 30 | yAxis: [{ 31 | height: '75%', 32 | labels: { 33 | align: 'right', 34 | x: -3 35 | }, 36 | title: { 37 | text: 'AAPL' 38 | } 39 | }, { 40 | top: '75%', 41 | height: '25%', 42 | labels: { 43 | align: 'right', 44 | x: -3 45 | }, 46 | offset: 0, 47 | title: { 48 | text: 'MACD' 49 | } 50 | }], 51 | series: [{ 52 | data: [ 53 | /* Jan 2017 */ 54 | [1483401600000,115.80,116.33,114.76,116.15], 55 | [1483488000000,115.85,116.51,115.75,116.02], 56 | [1483574400000,115.92,116.86,115.81,116.61], 57 | [1483660800000,116.78,118.16,116.47,117.91], 58 | [1483920000000,117.95,119.43,117.94,118.99], 59 | [1484006400000,118.77,119.38,118.30,119.11], 60 | [1484092800000,118.74,119.93,118.60,119.75], 61 | [1484179200000,118.90,119.30,118.21,119.25], 62 | [1484265600000,119.11,119.62,118.81,119.04], 63 | [1484611200000,118.34,120.24,118.22,120.00], 64 | [1484697600000,120.00,120.50,119.71,119.99], 65 | [1484784000000,119.40,120.09,119.37,119.78], 66 | [1484870400000,120.45,120.45,119.73,120.00], 67 | [1485129600000,120.00,120.81,119.77,120.08], 68 | [1485216000000,119.55,120.10,119.50,119.97], 69 | [1485302400000,120.42,122.10,120.28,121.88], 70 | [1485388800000,121.67,122.44,121.60,121.94], 71 | [1485475200000,122.14,122.35,121.60,121.95], 72 | [1485734400000,120.93,121.63,120.66,121.63], 73 | [1485820800000,121.15,121.39,120.62,121.35], 74 | /* Feb 2017 */ 75 | [1485907200000,127.03,130.49,127.01,128.75], 76 | [1485993600000,127.98,129.39,127.78,128.53], 77 | [1486080000000,128.31,129.19,128.16,129.08], 78 | [1486339200000,129.13,130.50,128.90,130.29], 79 | [1486425600000,130.54,132.09,130.45,131.53], 80 | [1486512000000,131.35,132.22,131.22,132.04], 81 | [1486598400000,131.65,132.44,131.12,132.42], 82 | [1486684800000,132.46,132.94,132.05,132.12], 83 | [1486944000000,133.08,133.82,132.75,133.29], 84 | [1487030400000,133.47,135.09,133.25,135.02], 85 | [1487116800000,135.52,136.27,134.62,135.51], 86 | [1487203200000,135.67,135.90,134.84,135.34], 87 | [1487289600000,135.10,135.83,135.10,135.72], 88 | [1487635200000,136.23,136.75,135.98,136.70], 89 | [1487721600000,136.43,137.12,136.11,137.11], 90 | [1487808000000,137.38,137.48,136.30,136.53], 91 | [1487894400000,135.91,136.66,135.28,136.66], 92 | [1488153600000,137.14,137.44,136.28,136.93], 93 | [1488240000000,137.08,137.44,136.70,136.99], 94 | /* Mar 2017 */ 95 | [1488326400000,137.89,140.15,137.60,139.79], 96 | [1488412800000,140.00,140.28,138.76,138.96], 97 | [1488499200000,138.78,139.83,138.59,139.78], 98 | [1488758400000,139.36,139.77,138.60,139.34], 99 | [1488844800000,139.06,139.98,138.79,139.52], 100 | [1488931200000,138.95,139.80,138.82,139.00], 101 | [1489017600000,138.74,138.79,137.05,138.68], 102 | [1489104000000,139.25,139.36,138.64,139.14], 103 | [1489363200000,138.85,139.43,138.82,139.20], 104 | [1489449600000,139.30,139.65,138.84,138.99], 105 | [1489536000000,139.41,140.75,139.02,140.46], 106 | [1489622400000,140.72,141.02,140.26,140.69], 107 | [1489708800000,141.00,141.00,139.89,139.99], 108 | [1489968000000,140.40,141.50,140.23,141.46], 109 | [1490054400000,142.11,142.80,139.73,139.84], 110 | [1490140800000,139.84,141.60,139.76,141.42], 111 | [1490227200000,141.26,141.58,140.61,140.92], 112 | [1490313600000,141.50,141.74,140.35,140.64], 113 | [1490572800000,139.39,141.22,138.62,140.88], 114 | [1490659200000,140.91,144.04,140.62,143.80], 115 | [1490745600000,143.68,144.49,143.19,144.12], 116 | [1490832000000,144.19,144.50,143.50,143.93], 117 | [1490918400000,143.72,144.27,143.01,143.66], 118 | /* Apr 2017 */ 119 | [1491177600000,143.71,144.12,143.05,143.70], 120 | [1491264000000,143.25,144.89,143.17,144.77], 121 | [1491350400000,144.22,145.46,143.81,144.02], 122 | [1491436800000,144.29,144.52,143.45,143.66], 123 | [1491523200000,143.73,144.18,143.27,143.34], 124 | [1491782400000,143.60,143.88,142.90,143.17], 125 | [1491868800000,142.94,143.35,140.06,141.63], 126 | [1491955200000,141.60,142.15,141.01,141.80], 127 | [1492041600000,141.91,142.38,141.05,141.05], 128 | [1492387200000,141.48,141.88,140.87,141.83], 129 | [1492473600000,141.41,142.04,141.11,141.20], 130 | [1492560000000,141.88,142.00,140.45,140.68], 131 | [1492646400000,141.22,142.92,141.16,142.44], 132 | [1492732800000,142.44,142.68,141.85,142.27], 133 | [1492992000000,143.50,143.95,143.18,143.64], 134 | [1493078400000,143.91,144.90,143.87,144.53], 135 | [1493164800000,144.47,144.60,143.38,143.68], 136 | [1493251200000,143.92,144.16,143.31,143.79], 137 | [1493337600000,144.09,144.30,143.27,143.65], 138 | /* May 2017 */ 139 | [1493596800000,145.10,147.20,144.96,146.58], 140 | [1493683200000,147.54,148.09,146.84,147.51], 141 | [1493769600000,145.59,147.49,144.27,147.06], 142 | [1493856000000,146.52,147.14,145.81,146.53], 143 | [1493942400000,146.76,148.98,146.76,148.96], 144 | [1494201600000,149.03,153.70,149.03,153.01], 145 | [1494288000000,153.87,154.88,153.45,153.99], 146 | [1494374400000,153.63,153.94,152.11,153.26], 147 | [1494460800000,152.45,154.07,152.31,153.95], 148 | [1494547200000,154.70,156.42,154.67,156.10], 149 | [1494806400000,156.01,156.65,155.05,155.70], 150 | [1494892800000,155.94,156.06,154.72,155.47], 151 | [1494979200000,153.60,154.57,149.71,150.25], 152 | [1495065600000,151.27,153.34,151.13,152.54], 153 | [1495152000000,153.38,153.98,152.63,153.06], 154 | [1495411200000,154.00,154.58,152.91,153.99], 155 | [1495497600000,154.90,154.90,153.31,153.80], 156 | [1495584000000,153.84,154.17,152.67,153.34], 157 | [1495670400000,153.73,154.35,153.03,153.87], 158 | [1495756800000,154.00,154.24,153.31,153.61], 159 | [1496102400000,153.42,154.43,153.33,153.67], 160 | [1496188800000,153.97,154.17,152.38,152.76], 161 | /* Jun 2017 */ 162 | [1496275200000,153.17,153.33,152.22,153.18], 163 | [1496361600000,153.58,155.45,152.89,155.45], 164 | [1496620800000,154.34,154.45,153.46,153.93], 165 | [1496707200000,153.90,155.81,153.78,154.45], 166 | [1496793600000,155.02,155.98,154.48,155.37], 167 | [1496880000000,155.25,155.54,154.40,154.99], 168 | [1496966400000,155.19,155.19,146.02,148.98], 169 | [1497225600000,145.74,146.09,142.51,145.42], 170 | [1497312000000,147.16,147.45,145.15,146.59], 171 | [1497398400000,147.50,147.50,143.84,145.16], 172 | [1497484800000,143.32,144.48,142.21,144.29], 173 | [1497571200000,143.78,144.50,142.20,142.27], 174 | [1497830400000,143.66,146.74,143.66,146.34], 175 | [1497916800000,146.87,146.87,144.94,145.01], 176 | [1498003200000,145.52,146.07,144.61,145.87], 177 | [1498089600000,145.77,146.70,145.12,145.63], 178 | [1498176000000,145.13,147.16,145.11,146.28], 179 | [1498435200000,147.17,148.28,145.38,145.82], 180 | [1498521600000,145.01,146.16,143.62,143.73], 181 | [1498608000000,144.49,146.11,143.16,145.83], 182 | [1498694400000,144.71,145.13,142.28,143.68], 183 | [1498780800000,144.45,144.96,143.78,144.02], 184 | /* Jul 2017 */ 185 | [1499040000000,144.88,145.30,143.10,143.50], 186 | [1499212800000,143.69,144.79,142.72,144.09], 187 | [1499299200000,143.02,143.50,142.41,142.73], 188 | [1499385600000,142.90,144.75,142.90,144.18], 189 | [1499644800000,144.11,145.95,143.37,145.06], 190 | [1499731200000,144.73,145.85,144.38,145.53], 191 | [1499817600000,145.87,146.18,144.82,145.74], 192 | [1499904000000,145.50,148.49,145.44,147.77], 193 | [1499990400000,147.97,149.33,147.33,149.04], 194 | [1500249600000,148.82,150.90,148.57,149.56], 195 | [1500336000000,149.20,150.13,148.67,150.08], 196 | [1500422400000,150.48,151.42,149.95,151.02], 197 | [1500508800000,151.50,151.74,150.19,150.34], 198 | [1500595200000,149.99,150.44,148.88,150.27], 199 | [1500854400000,150.58,152.44,149.90,152.09], 200 | [1500940800000,151.80,153.84,151.80,152.74], 201 | [1501027200000,153.35,153.93,153.06,153.46], 202 | [1501113600000,153.75,153.99,147.30,150.56], 203 | [1501200000000,149.89,150.23,149.19,149.50], 204 | [1501459200000,149.90,150.33,148.13,148.73], 205 | /* Aug 2017 */ 206 | [1501545600000,149.10,150.22,148.41,150.05], 207 | [1501632000000,159.28,159.75,156.16,157.14], 208 | [1501718400000,157.05,157.21,155.02,155.57], 209 | [1501804800000,156.07,157.40,155.69,156.39], 210 | [1502064000000,157.06,158.92,156.67,158.81], 211 | [1502150400000,158.60,161.83,158.27,160.08], 212 | [1502236800000,159.26,161.27,159.11,161.06], 213 | [1502323200000,159.90,160.00,154.63,155.32], 214 | [1502409600000,156.60,158.57,156.07,157.48], 215 | [1502668800000,159.32,160.21,158.75,159.85], 216 | [1502755200000,160.66,162.20,160.14,161.60], 217 | [1502841600000,161.94,162.51,160.15,160.95], 218 | [1502928000000,160.52,160.71,157.84,157.86], 219 | [1503014400000,157.86,159.50,156.72,157.50], 220 | [1503273600000,157.50,157.89,155.11,157.21], 221 | [1503360000000,158.23,160.00,158.02,159.78], 222 | [1503446400000,159.07,160.47,158.88,159.98], 223 | [1503532800000,160.43,160.74,158.55,159.27], 224 | [1503619200000,159.65,160.56,159.27,159.86], 225 | [1503878400000,160.14,162.00,159.93,161.47], 226 | [1503964800000,160.10,163.12,160.00,162.91], 227 | [1504051200000,163.80,163.89,162.61,163.35], 228 | [1504137600000,163.64,164.52,163.48,164.00], 229 | /* Sep 2017 */ 230 | [1504224000000,164.80,164.94,163.63,164.05], 231 | [1504569600000,163.75,164.25,160.56,162.08], 232 | [1504656000000,162.71,162.99,160.52,161.91], 233 | [1504742400000,162.09,162.24,160.36,161.26], 234 | [1504828800000,160.86,161.15,158.53,158.63], 235 | [1505088000000,160.50,162.05,159.89,161.50], 236 | [1505174400000,162.61,163.96,158.77,160.86], 237 | [1505260800000,159.87,159.96,157.91,159.65], 238 | [1505347200000,158.99,159.40,158.09,158.28], 239 | [1505433600000,158.47,160.97,158.00,159.88], 240 | [1505692800000,160.11,160.50,158.00,158.67], 241 | [1505779200000,159.51,159.77,158.44,158.73], 242 | [1505865600000,157.90,158.26,153.83,156.07], 243 | [1505952000000,155.80,155.80,152.75,153.39], 244 | [1506038400000,151.54,152.27,150.56,151.89], 245 | [1506297600000,149.99,151.83,149.16,150.55], 246 | [1506384000000,151.78,153.92,151.69,153.14], 247 | [1506470400000,153.80,154.72,153.54,154.23], 248 | [1506556800000,153.89,154.28,152.70,153.28], 249 | [1506643200000,153.21,154.13,152.00,154.12], 250 | /* Oct 2017 */ 251 | [1506902400000,154.26,154.45,152.72,153.81], 252 | [1506988800000,154.01,155.09,153.91,154.48], 253 | [1507075200000,153.63,153.86,152.46,153.48], 254 | [1507161600000,154.18,155.44,154.05,155.39], 255 | [1507248000000,154.97,155.49,154.56,155.30], 256 | [1507507200000,155.81,156.73,155.48,155.84], 257 | [1507593600000,156.06,158.00,155.10,155.90], 258 | [1507680000000,155.97,156.98,155.75,156.55], 259 | [1507766400000,156.35,157.37,155.73,156.00], 260 | [1507852800000,156.73,157.28,156.41,156.99] 261 | ], 262 | type: 'ohlc', 263 | name: 'AAPL Stock Price', 264 | id: 'aapl' 265 | }, { 266 | type: 'pivotpoints', 267 | linkedTo: 'aapl', 268 | zIndex: 0, 269 | lineWidth: 1, 270 | dataLabels: { 271 | overflow: 'none', 272 | crop: false, 273 | y: 4, 274 | style: { 275 | fontSize: 9 276 | } 277 | } 278 | }, { 279 | type: 'macd', 280 | yAxis: 1, 281 | linkedTo: 'aapl' 282 | }] 283 | } 284 | 285 | const mapOptions = { 286 | title: { 287 | text: '' 288 | }, 289 | colorAxis: { 290 | min: 0, 291 | stops: [ 292 | [0, '#EFEFFF'], 293 | [0.67, '#4444FF'], 294 | [1, '#000022'] 295 | ] 296 | }, 297 | tooltip: { 298 | pointFormatter: function() { 299 | return this.properties['woe-label'].split(',')[0]; 300 | } 301 | }, 302 | series: [{ 303 | mapData: mapData, 304 | dataLabels: { 305 | formatter: function() { 306 | return this.point.properties['woe-label'].split(',')[0]; 307 | } 308 | }, 309 | name: 'Norway', 310 | data: [ 311 | ['no-mr', 0], 312 | ['no-st', 1], 313 | ['no-ho', 2], 314 | ['no-sf', 42], 315 | ['no-va', 4], 316 | ['no-of', 5], 317 | ['no-nt', 6], 318 | ['no-ro', 7], 319 | ['no-bu', 8], 320 | ['no-vf', 9], 321 | ['no-fi', 10], 322 | ['no-no', 11], 323 | ['no-tr', 12], 324 | ['no-ak', 13], 325 | ['no-op', 14], 326 | ['no-he', 15], 327 | ['no-os', 16], 328 | ['no-te', 17], 329 | ['no-aa', 18] 330 | ] 331 | }] 332 | } 333 | 334 | // Render app with demo chart 335 | class App extends React.Component { 336 | constructor(props) { 337 | super(props) 338 | 339 | this.state = { 340 | options: { 341 | series: chartOptions.series 342 | } 343 | } 344 | this.onClick = this.onClick.bind(this) 345 | } 346 | 347 | onClick() { 348 | this.setState({ 349 | options: { 350 | series: [{ 351 | data: [1, 2, 3] 352 | }, 353 | { 354 | data: [2, 3, 1] 355 | }, 356 | { 357 | data: [3, 2, 1] 358 | }] 359 | } 360 | }) 361 | } 362 | 363 | render() { 364 | return
365 |

Demos

366 | 367 |

Highcharts

368 | 369 | 370 | 371 |

Highstock

372 | 373 | 374 |

Highmaps

375 | 376 | 377 |

Live updating chart

378 | 379 |
380 | } 381 | } 382 | 383 | render(, document.getElementById('root')) 384 | -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 9 |
10 | 11 | -------------------------------------------------------------------------------- /dist/highcharts-react.d.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) Highsoft AS 3 | */ 4 | 5 | import * as React from 'react'; 6 | import * as Highcharts from 'highcharts'; 7 | 8 | /** 9 | * Highcharts component for React 10 | */ 11 | declare const HighchartsReact: React.ForwardRefExoticComponent< 12 | React.PropsWithoutRef & 13 | React.RefAttributes 14 | >; 15 | 16 | interface HighchartsReactRefObject { 17 | chart: Highcharts.Chart; 18 | 19 | /** 20 | * React reference 21 | */ 22 | container: React.RefObject; 23 | } 24 | 25 | interface HighchartsReactProps { 26 | /* * 27 | * 28 | * Properties 29 | * 30 | * */ 31 | 32 | /** 33 | * Indexer for custom properties 34 | */ 35 | [key: string]: any; 36 | 37 | /** 38 | * Flag for `Chart.update` call (Default: true) 39 | */ 40 | allowChartUpdate?: boolean; 41 | 42 | /** 43 | * Reference to the chart factory (Default: chart) 44 | */ 45 | constructorType?: keyof typeof Highcharts; 46 | 47 | /** 48 | * Properties of the chart container 49 | */ 50 | containerProps?: { [key: string]: any }; 51 | 52 | /** 53 | * Highcharts namespace 54 | */ 55 | highcharts?: typeof Highcharts; 56 | 57 | /** 58 | * Immutably recreates the chart on receiving new props 59 | */ 60 | immutable?: boolean; 61 | 62 | /** 63 | * Highcharts options 64 | */ 65 | options?: Highcharts.Options; 66 | 67 | /** 68 | * Flags for `Chart.update` call: redraw, oneToOne, and animation. (Default: 69 | * [true, true, true]) 70 | */ 71 | updateArgs?: [boolean] | [boolean, boolean] | [boolean, boolean, boolean]; 72 | 73 | /* * 74 | * 75 | * Functions 76 | * 77 | * */ 78 | 79 | /** 80 | * Callback for the chart factory 81 | */ 82 | callback?: Highcharts.ChartCallbackFunction; 83 | } 84 | 85 | declare namespace HighchartsReact { 86 | /** 87 | * Properties for a HighchartsReact component 88 | */ 89 | interface RefObject extends HighchartsReactRefObject {} 90 | interface Props extends HighchartsReactProps {} 91 | } 92 | 93 | export { HighchartsReact, HighchartsReactRefObject, HighchartsReactProps }; 94 | export default HighchartsReact; 95 | -------------------------------------------------------------------------------- /dist/highcharts-react.js: -------------------------------------------------------------------------------- 1 | (function webpackUniversalModuleDefinition(root, factory) { 2 | if(typeof exports === 'object' && typeof module === 'object') 3 | module.exports = factory(require("react")); 4 | else if(typeof define === 'function' && define.amd) 5 | define(["react"], factory); 6 | else if(typeof exports === 'object') 7 | exports["HighchartsReact"] = factory(require("react")); 8 | else 9 | root["HighchartsReact"] = factory(root["React"]); 10 | })(typeof self !== 'undefined' ? self : this, function(__WEBPACK_EXTERNAL_MODULE_1__) { 11 | return /******/ (function(modules) { // webpackBootstrap 12 | /******/ // The module cache 13 | /******/ var installedModules = {}; 14 | /******/ 15 | /******/ // The require function 16 | /******/ function __webpack_require__(moduleId) { 17 | /******/ 18 | /******/ // Check if module is in cache 19 | /******/ if(installedModules[moduleId]) { 20 | /******/ return installedModules[moduleId].exports; 21 | /******/ } 22 | /******/ // Create a new module (and put it into the cache) 23 | /******/ var module = installedModules[moduleId] = { 24 | /******/ i: moduleId, 25 | /******/ l: false, 26 | /******/ exports: {} 27 | /******/ }; 28 | /******/ 29 | /******/ // Execute the module function 30 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 31 | /******/ 32 | /******/ // Flag the module as loaded 33 | /******/ module.l = true; 34 | /******/ 35 | /******/ // Return the exports of the module 36 | /******/ return module.exports; 37 | /******/ } 38 | /******/ 39 | /******/ 40 | /******/ // expose the modules object (__webpack_modules__) 41 | /******/ __webpack_require__.m = modules; 42 | /******/ 43 | /******/ // expose the module cache 44 | /******/ __webpack_require__.c = installedModules; 45 | /******/ 46 | /******/ // define getter function for harmony exports 47 | /******/ __webpack_require__.d = function(exports, name, getter) { 48 | /******/ if(!__webpack_require__.o(exports, name)) { 49 | /******/ Object.defineProperty(exports, name, { 50 | /******/ configurable: false, 51 | /******/ enumerable: true, 52 | /******/ get: getter 53 | /******/ }); 54 | /******/ } 55 | /******/ }; 56 | /******/ 57 | /******/ // getDefaultExport function for compatibility with non-harmony modules 58 | /******/ __webpack_require__.n = function(module) { 59 | /******/ var getter = module && module.__esModule ? 60 | /******/ function getDefault() { return module['default']; } : 61 | /******/ function getModuleExports() { return module; }; 62 | /******/ __webpack_require__.d(getter, 'a', getter); 63 | /******/ return getter; 64 | /******/ }; 65 | /******/ 66 | /******/ // Object.prototype.hasOwnProperty.call 67 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 68 | /******/ 69 | /******/ // __webpack_public_path__ 70 | /******/ __webpack_require__.p = ""; 71 | /******/ 72 | /******/ // Load entry module and return exports 73 | /******/ return __webpack_require__(__webpack_require__.s = 0); 74 | /******/ }) 75 | /************************************************************************/ 76 | /******/ ([ 77 | /* 0 */ 78 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 79 | 80 | "use strict"; 81 | Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); 82 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "HighchartsReact", function() { return HighchartsReact; }); 83 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_react__ = __webpack_require__(1); 84 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_react___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_react__); 85 | function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } 86 | function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); } 87 | function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } 88 | function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } 89 | function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); } 90 | function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); } 91 | function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } 92 | function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } 93 | 94 | 95 | // React currently throws a warning when using `useLayoutEffect` on the server. 96 | // To get around it, we can conditionally `useEffect` on the server (no-op) and 97 | // `useLayoutEffect` in the browser. We need `useLayoutEffect` to ensure the 98 | // `Highcharts` ref is available in the layout phase. This makes it available 99 | // in a parent component's `componentDidMount`. 100 | var useIsomorphicLayoutEffect = typeof window !== 'undefined' ? __WEBPACK_IMPORTED_MODULE_0_react__["useLayoutEffect"] : __WEBPACK_IMPORTED_MODULE_0_react__["useEffect"]; 101 | var HighchartsReact = /*#__PURE__*/Object(__WEBPACK_IMPORTED_MODULE_0_react__["memo"])( /*#__PURE__*/Object(__WEBPACK_IMPORTED_MODULE_0_react__["forwardRef"])(function HighchartsReact(props, ref) { 102 | var containerRef = Object(__WEBPACK_IMPORTED_MODULE_0_react__["useRef"])(); 103 | var chartRef = Object(__WEBPACK_IMPORTED_MODULE_0_react__["useRef"])(); 104 | var constructorType = Object(__WEBPACK_IMPORTED_MODULE_0_react__["useRef"])(props.constructorType); 105 | var highcharts = Object(__WEBPACK_IMPORTED_MODULE_0_react__["useRef"])(props.highcharts); 106 | useIsomorphicLayoutEffect(function () { 107 | function createChart() { 108 | var H = props.highcharts || (typeof window === "undefined" ? "undefined" : _typeof(window)) === 'object' && window.Highcharts; 109 | var constructorType = props.constructorType || 'chart'; 110 | if (!H) { 111 | console.warn('The "highcharts" property was not passed.'); 112 | } else if (!H[constructorType]) { 113 | console.warn('The "constructorType" property is incorrect or some ' + 'required module is not imported.'); 114 | } else if (!props.options) { 115 | console.warn('The "options" property was not passed.'); 116 | } else { 117 | // Create a chart 118 | chartRef.current = H[constructorType](containerRef.current, props.options, props.callback); 119 | } 120 | } 121 | if (!chartRef.current) { 122 | createChart(); 123 | } else { 124 | if (props.allowChartUpdate !== false) { 125 | // Reacreate chart on Highcharts or constructor type change 126 | if (props.constructorType !== constructorType.current || props.highcharts !== highcharts.current) { 127 | constructorType.current = props.constructorType; 128 | highcharts.current = props.highcharts; 129 | createChart(); 130 | // Use `chart.update` to apply changes 131 | } else if (!props.immutable && chartRef.current) { 132 | var _chartRef$current; 133 | (_chartRef$current = chartRef.current).update.apply(_chartRef$current, [props.options].concat(_toConsumableArray(props.updateArgs || [true, true]))); 134 | } else { 135 | createChart(); 136 | } 137 | } 138 | } 139 | }, [props.options, props.allowChartUpdate, props.updateArgs, props.containerProps, props.highcharts, props.constructorType]); 140 | 141 | // Destroy the chart on unmount 142 | useIsomorphicLayoutEffect(function () { 143 | return function () { 144 | if (chartRef.current) { 145 | chartRef.current.destroy(); 146 | chartRef.current = null; 147 | } 148 | }; 149 | }, []); 150 | Object(__WEBPACK_IMPORTED_MODULE_0_react__["useImperativeHandle"])(ref, function () { 151 | return { 152 | get chart() { 153 | return chartRef.current; 154 | }, 155 | container: containerRef 156 | }; 157 | }, []); 158 | 159 | // Create container for the chart 160 | return /*#__PURE__*/__WEBPACK_IMPORTED_MODULE_0_react___default.a.createElement("div", _extends({}, props.containerProps, { 161 | ref: containerRef 162 | })); 163 | })); 164 | /* harmony default export */ __webpack_exports__["default"] = (HighchartsReact); 165 | 166 | /***/ }), 167 | /* 1 */ 168 | /***/ (function(module, exports) { 169 | 170 | module.exports = __WEBPACK_EXTERNAL_MODULE_1__; 171 | 172 | /***/ }) 173 | /******/ ]); 174 | }); 175 | //# sourceMappingURL=highcharts-react.js.map -------------------------------------------------------------------------------- /dist/highcharts-react.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack:///webpack/universalModuleDefinition","webpack:///webpack/bootstrap 06abc0fd1cd6e6cc78b4","webpack:///./src/HighchartsReact.js","webpack:///external {\"root\":\"React\",\"commonjs\":\"react\",\"commonjs2\":\"react\",\"amd\":\"react\"}"],"names":["useIsomorphicLayoutEffect","window","useLayoutEffect","useEffect","HighchartsReact","memo","forwardRef","props","ref","containerRef","useRef","chartRef","constructorType","highcharts","createChart","H","_typeof","Highcharts","console","warn","options","current","callback","allowChartUpdate","immutable","_chartRef$current","update","apply","concat","_toConsumableArray","updateArgs","containerProps","destroy","useImperativeHandle","chart","container","React","createElement","_extends"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD,O;QCVA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;;QAEA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;;;QAGA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;QACA;QACA;QACA;QACA;QACA,KAAK;QACL;QACA;;QAEA;QACA;QACA;QACA,2BAA2B,0BAA0B,EAAE;QACvD,iCAAiC,eAAe;QAChD;QACA;QACA;;QAEA;QACA,sDAAsD,+DAA+D;;QAErH;QACA;;QAEA;QACA;;;;;;;;;;;;;;;;;;;;ACtDe;;AAEf;AACA;AACA;AACA;AACA;AACA,IAAMA,yBAAyB,GAC7B,OAAOC,MAAM,KAAK,WAAW,GAAGC,sDAAe,GAAGC,gDAAS;AAEtD,IAAMC,eAAe,gBAAGC,mDAAI,eAACC,yDAAU,CAC5C,SAASF,eAAeA,CAACG,KAAK,EAAEC,GAAG,EAAE;EACnC,IAAMC,YAAY,GAAGC,qDAAM,EAAE;EAC7B,IAAMC,QAAQ,GAAGD,qDAAM,EAAE;EACzB,IAAME,eAAe,GAAGF,qDAAM,CAACH,KAAK,CAACK,eAAe,CAAC;EACrD,IAAMC,UAAU,GAAGH,qDAAM,CAACH,KAAK,CAACM,UAAU,CAAC;EAE3Cb,yBAAyB,CAAC,YAAM;IAC9B,SAASc,WAAWA,CAAA,EAAG;MACrB,IAAMC,CAAC,GAAGR,KAAK,CAACM,UAAU,IACxB,QAAOZ,MAAM,iCAAAe,OAAA,CAANf,MAAM,OAAK,QAAQ,IAAIA,MAAM,CAACgB,UACtC;MACD,IAAML,eAAe,GAAGL,KAAK,CAACK,eAAe,IAAI,OAAO;MAExD,IAAI,CAACG,CAAC,EAAE;QACNG,OAAO,CAACC,IAAI,CAAC,2CAA2C,CAAC;MAE3D,CAAC,MAAM,IAAI,CAACJ,CAAC,CAACH,eAAe,CAAC,EAAE;QAC9BM,OAAO,CAACC,IAAI,CACV,sDAAsD,GACpD,kCAAkC,CACrC;MACH,CAAC,MAAM,IAAI,CAACZ,KAAK,CAACa,OAAO,EAAE;QACzBF,OAAO,CAACC,IAAI,CAAC,wCAAwC,CAAC;MAExD,CAAC,MAAM;QACL;QACAR,QAAQ,CAACU,OAAO,GAAGN,CAAC,CAACH,eAAe,CAAC,CACnCH,YAAY,CAACY,OAAO,EACpBd,KAAK,CAACa,OAAO,EACbb,KAAK,CAACe,QAAQ,CACf;MACH;IACF;IAEA,IAAI,CAACX,QAAQ,CAACU,OAAO,EAAE;MACrBP,WAAW,EAAE;IACf,CAAC,MAAM;MACL,IAAIP,KAAK,CAACgB,gBAAgB,KAAK,KAAK,EAAE;QACpC;QACA,IACEhB,KAAK,CAACK,eAAe,KAAKA,eAAe,CAACS,OAAO,IACjDd,KAAK,CAACM,UAAU,KAAKA,UAAU,CAACQ,OAAO,EACvC;UACAT,eAAe,CAACS,OAAO,GAAGd,KAAK,CAACK,eAAe;UAC/CC,UAAU,CAACQ,OAAO,GAAGd,KAAK,CAACM,UAAU;UACrCC,WAAW,EAAE;UACf;QACA,CAAC,MAAM,IAAI,CAACP,KAAK,CAACiB,SAAS,IAAIb,QAAQ,CAACU,OAAO,EAAE;UAAA,IAAAI,iBAAA;UAC/C,CAAAA,iBAAA,GAAAd,QAAQ,CAACU,OAAO,EAACK,MAAM,CAAAC,KAAA,CAAAF,iBAAA,GACrBlB,KAAK,CAACa,OAAO,EAAAQ,MAAA,CAAAC,kBAAA,CACTtB,KAAK,CAACuB,UAAU,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,GACrC;QACH,CAAC,MAAM;UACLhB,WAAW,EAAE;QACf;MACF;IACF;EACF,CAAC,EAAE,CACDP,KAAK,CAACa,OAAO,EACbb,KAAK,CAACgB,gBAAgB,EACtBhB,KAAK,CAACuB,UAAU,EAChBvB,KAAK,CAACwB,cAAc,EACpBxB,KAAK,CAACM,UAAU,EAChBN,KAAK,CAACK,eAAe,CACtB,CAAC;;EAEF;EACAZ,yBAAyB,CAAC,YAAM;IAC9B,OAAO,YAAM;MACX,IAAIW,QAAQ,CAACU,OAAO,EAAE;QACpBV,QAAQ,CAACU,OAAO,CAACW,OAAO,EAAE;QAC1BrB,QAAQ,CAACU,OAAO,GAAG,IAAI;MACzB;IACF,CAAC;EACH,CAAC,EAAE,EAAE,CAAC;EAENY,kEAAmB,CACjBzB,GAAG,EACH;IAAA,OAAO;MACL,IAAI0B,KAAKA,CAAA,EAAG;QACV,OAAOvB,QAAQ,CAACU,OAAO;MACzB,CAAC;MACDc,SAAS,EAAE1B;IACb,CAAC;EAAA,CAAC,EACF,EAAE,CACH;;EAED;EACA,oBAAO2B,6CAAA,CAAAC,aAAA,QAAAC,QAAA,KAAU/B,KAAK,CAACwB,cAAc;IAAGvB,GAAG,EAAGC;EAAc,GAAG;AACjE,CAAC,CACF,CAAC;AAEaL,8EAAe,E;;;;;;AC9G9B,+C","file":"highcharts-react.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"react\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([\"react\"], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"HighchartsReact\"] = factory(require(\"react\"));\n\telse\n\t\troot[\"HighchartsReact\"] = factory(root[\"React\"]);\n})(typeof self !== 'undefined' ? self : this, function(__WEBPACK_EXTERNAL_MODULE_1__) {\nreturn \n\n\n// WEBPACK FOOTER //\n// webpack/universalModuleDefinition"," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 06abc0fd1cd6e6cc78b4","import React, {\n forwardRef,\n memo,\n useEffect,\n useImperativeHandle,\n useLayoutEffect,\n useRef\n} from 'react';\n\n// React currently throws a warning when using `useLayoutEffect` on the server.\n// To get around it, we can conditionally `useEffect` on the server (no-op) and\n// `useLayoutEffect` in the browser. We need `useLayoutEffect` to ensure the\n// `Highcharts` ref is available in the layout phase. This makes it available\n// in a parent component's `componentDidMount`.\nconst useIsomorphicLayoutEffect =\n typeof window !== 'undefined' ? useLayoutEffect : useEffect;\n\nexport const HighchartsReact = memo(forwardRef(\n function HighchartsReact(props, ref) {\n const containerRef = useRef();\n const chartRef = useRef();\n const constructorType = useRef(props.constructorType);\n const highcharts = useRef(props.highcharts);\n\n useIsomorphicLayoutEffect(() => {\n function createChart() {\n const H = props.highcharts || (\n typeof window === 'object' && window.Highcharts\n );\n const constructorType = props.constructorType || 'chart';\n \n if (!H) {\n console.warn('The \"highcharts\" property was not passed.');\n \n } else if (!H[constructorType]) {\n console.warn(\n 'The \"constructorType\" property is incorrect or some ' +\n 'required module is not imported.'\n );\n } else if (!props.options) {\n console.warn('The \"options\" property was not passed.');\n \n } else {\n // Create a chart\n chartRef.current = H[constructorType](\n containerRef.current,\n props.options,\n props.callback\n );\n }\n }\n\n if (!chartRef.current) {\n createChart();\n } else {\n if (props.allowChartUpdate !== false) {\n // Reacreate chart on Highcharts or constructor type change\n if (\n props.constructorType !== constructorType.current ||\n props.highcharts !== highcharts.current\n ) {\n constructorType.current = props.constructorType;\n highcharts.current = props.highcharts;\n createChart();\n // Use `chart.update` to apply changes\n } else if (!props.immutable && chartRef.current) {\n chartRef.current.update(\n props.options,\n ...(props.updateArgs || [true, true])\n );\n } else {\n createChart();\n }\n }\n }\n }, [\n props.options,\n props.allowChartUpdate,\n props.updateArgs,\n props.containerProps,\n props.highcharts,\n props.constructorType\n ]);\n\n // Destroy the chart on unmount\n useIsomorphicLayoutEffect(() => {\n return () => {\n if (chartRef.current) {\n chartRef.current.destroy();\n chartRef.current = null;\n }\n };\n }, []);\n\n useImperativeHandle(\n ref,\n () => ({\n get chart() {\n return chartRef.current;\n },\n container: containerRef\n }),\n []\n );\n\n // Create container for the chart\n return
;\n }\n));\n\nexport default HighchartsReact;\n\n\n\n// WEBPACK FOOTER //\n// ./src/HighchartsReact.js","module.exports = __WEBPACK_EXTERNAL_MODULE_1__;\n\n\n//////////////////\n// WEBPACK FOOTER\n// external {\"root\":\"React\",\"commonjs\":\"react\",\"commonjs2\":\"react\",\"amd\":\"react\"}\n// module id = 1\n// module chunks = 0 1"],"sourceRoot":""} -------------------------------------------------------------------------------- /dist/highcharts-react.min.d.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) Highsoft AS 3 | */ 4 | 5 | import * as React from 'react'; 6 | import * as Highcharts from 'highcharts'; 7 | 8 | /** 9 | * Highcharts component for React 10 | */ 11 | declare const HighchartsReact: React.ForwardRefExoticComponent< 12 | React.PropsWithoutRef & 13 | React.RefAttributes 14 | >; 15 | 16 | interface HighchartsReactRefObject { 17 | chart: Highcharts.Chart; 18 | 19 | /** 20 | * React reference 21 | */ 22 | container: React.RefObject; 23 | } 24 | 25 | interface HighchartsReactProps { 26 | /* * 27 | * 28 | * Properties 29 | * 30 | * */ 31 | 32 | /** 33 | * Indexer for custom properties 34 | */ 35 | [key: string]: any; 36 | 37 | /** 38 | * Flag for `Chart.update` call (Default: true) 39 | */ 40 | allowChartUpdate?: boolean; 41 | 42 | /** 43 | * Reference to the chart factory (Default: chart) 44 | */ 45 | constructorType?: keyof typeof Highcharts; 46 | 47 | /** 48 | * Properties of the chart container 49 | */ 50 | containerProps?: { [key: string]: any }; 51 | 52 | /** 53 | * Highcharts namespace 54 | */ 55 | highcharts?: typeof Highcharts; 56 | 57 | /** 58 | * Immutably recreates the chart on receiving new props 59 | */ 60 | immutable?: boolean; 61 | 62 | /** 63 | * Highcharts options 64 | */ 65 | options?: Highcharts.Options; 66 | 67 | /** 68 | * Flags for `Chart.update` call: redraw, oneToOne, and animation. (Default: 69 | * [true, true, true]) 70 | */ 71 | updateArgs?: [boolean] | [boolean, boolean] | [boolean, boolean, boolean]; 72 | 73 | /* * 74 | * 75 | * Functions 76 | * 77 | * */ 78 | 79 | /** 80 | * Callback for the chart factory 81 | */ 82 | callback?: Highcharts.ChartCallbackFunction; 83 | } 84 | 85 | declare namespace HighchartsReact { 86 | /** 87 | * Properties for a HighchartsReact component 88 | */ 89 | interface RefObject extends HighchartsReactRefObject {} 90 | interface Props extends HighchartsReactProps {} 91 | } 92 | 93 | export { HighchartsReact, HighchartsReactRefObject, HighchartsReactProps }; 94 | export default HighchartsReact; 95 | -------------------------------------------------------------------------------- /dist/highcharts-react.min.js: -------------------------------------------------------------------------------- 1 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(require("react")):"function"==typeof define&&define.amd?define(["react"],e):"object"==typeof exports?exports.HighchartsReact=e(require("react")):t.HighchartsReact=e(t.React)}("undefined"!=typeof self?self:this,function(t){return function(t){function e(n){if(r[n])return r[n].exports;var o=r[n]={i:n,l:!1,exports:{}};return t[n].call(o.exports,o,o.exports,e),o.l=!0,o.exports}var r={};return e.m=t,e.c=r,e.d=function(t,r,n){e.o(t,r)||Object.defineProperty(t,r,{configurable:!1,enumerable:!0,get:n})},e.n=function(t){var r=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(r,"a",r),r},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s=0)}([function(t,e,r){"use strict";function n(){return n=Object.assign?Object.assign.bind():function(t){for(var e=1;et.length)&&(e=t.length);for(var r=0,n=new Array(e);r arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; return _typeof = \"function\" == typeof Symbol && \"symbol\" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && \"function\" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }, _typeof(obj); }\n\n\n// React currently throws a warning when using `useLayoutEffect` on the server.\n// To get around it, we can conditionally `useEffect` on the server (no-op) and\n// `useLayoutEffect` in the browser. We need `useLayoutEffect` to ensure the\n// `Highcharts` ref is available in the layout phase. This makes it available\n// in a parent component's `componentDidMount`.\nvar useIsomorphicLayoutEffect = typeof window !== 'undefined' ? __WEBPACK_IMPORTED_MODULE_0_react__[\"useLayoutEffect\"] : __WEBPACK_IMPORTED_MODULE_0_react__[\"useEffect\"];\nvar HighchartsReact = /*#__PURE__*/Object(__WEBPACK_IMPORTED_MODULE_0_react__[\"memo\"])( /*#__PURE__*/Object(__WEBPACK_IMPORTED_MODULE_0_react__[\"forwardRef\"])(function HighchartsReact(props, ref) {\n var containerRef = Object(__WEBPACK_IMPORTED_MODULE_0_react__[\"useRef\"])();\n var chartRef = Object(__WEBPACK_IMPORTED_MODULE_0_react__[\"useRef\"])();\n var constructorType = Object(__WEBPACK_IMPORTED_MODULE_0_react__[\"useRef\"])(props.constructorType);\n var highcharts = Object(__WEBPACK_IMPORTED_MODULE_0_react__[\"useRef\"])(props.highcharts);\n useIsomorphicLayoutEffect(function () {\n function createChart() {\n var H = props.highcharts || (typeof window === \"undefined\" ? \"undefined\" : _typeof(window)) === 'object' && window.Highcharts;\n var constructorType = props.constructorType || 'chart';\n if (!H) {\n console.warn('The \"highcharts\" property was not passed.');\n } else if (!H[constructorType]) {\n console.warn('The \"constructorType\" property is incorrect or some ' + 'required module is not imported.');\n } else if (!props.options) {\n console.warn('The \"options\" property was not passed.');\n } else {\n // Create a chart\n chartRef.current = H[constructorType](containerRef.current, props.options, props.callback);\n }\n }\n if (!chartRef.current) {\n createChart();\n } else {\n if (props.allowChartUpdate !== false) {\n // Reacreate chart on Highcharts or constructor type change\n if (props.constructorType !== constructorType.current || props.highcharts !== highcharts.current) {\n constructorType.current = props.constructorType;\n highcharts.current = props.highcharts;\n createChart();\n // Use `chart.update` to apply changes\n } else if (!props.immutable && chartRef.current) {\n var _chartRef$current;\n (_chartRef$current = chartRef.current).update.apply(_chartRef$current, [props.options].concat(_toConsumableArray(props.updateArgs || [true, true])));\n } else {\n createChart();\n }\n }\n }\n }, [props.options, props.allowChartUpdate, props.updateArgs, props.containerProps, props.highcharts, props.constructorType]);\n\n // Destroy the chart on unmount\n useIsomorphicLayoutEffect(function () {\n return function () {\n if (chartRef.current) {\n chartRef.current.destroy();\n chartRef.current = null;\n }\n };\n }, []);\n Object(__WEBPACK_IMPORTED_MODULE_0_react__[\"useImperativeHandle\"])(ref, function () {\n return {\n get chart() {\n return chartRef.current;\n },\n container: containerRef\n };\n }, []);\n\n // Create container for the chart\n return /*#__PURE__*/__WEBPACK_IMPORTED_MODULE_0_react___default.a.createElement(\"div\", _extends({}, props.containerProps, {\n ref: containerRef\n }));\n}));\n/* harmony default export */ __webpack_exports__[\"default\"] = (HighchartsReact);\n\n/***/ }),\n/* 1 */\n/***/ (function(module, exports) {\n\nmodule.exports = __WEBPACK_EXTERNAL_MODULE_1__;\n\n/***/ })\n/******/ ]);\n});\n\n\n// WEBPACK FOOTER //\n// highcharts-react.min.js","import React, {\n forwardRef,\n memo,\n useEffect,\n useImperativeHandle,\n useLayoutEffect,\n useRef\n} from 'react';\n\n// React currently throws a warning when using `useLayoutEffect` on the server.\n// To get around it, we can conditionally `useEffect` on the server (no-op) and\n// `useLayoutEffect` in the browser. We need `useLayoutEffect` to ensure the\n// `Highcharts` ref is available in the layout phase. This makes it available\n// in a parent component's `componentDidMount`.\nconst useIsomorphicLayoutEffect =\n typeof window !== 'undefined' ? useLayoutEffect : useEffect;\n\nexport const HighchartsReact = memo(forwardRef(\n function HighchartsReact(props, ref) {\n const containerRef = useRef();\n const chartRef = useRef();\n const constructorType = useRef(props.constructorType);\n const highcharts = useRef(props.highcharts);\n\n useIsomorphicLayoutEffect(() => {\n function createChart() {\n const H = props.highcharts || (\n typeof window === 'object' && window.Highcharts\n );\n const constructorType = props.constructorType || 'chart';\n \n if (!H) {\n console.warn('The \"highcharts\" property was not passed.');\n \n } else if (!H[constructorType]) {\n console.warn(\n 'The \"constructorType\" property is incorrect or some ' +\n 'required module is not imported.'\n );\n } else if (!props.options) {\n console.warn('The \"options\" property was not passed.');\n \n } else {\n // Create a chart\n chartRef.current = H[constructorType](\n containerRef.current,\n props.options,\n props.callback\n );\n }\n }\n\n if (!chartRef.current) {\n createChart();\n } else {\n if (props.allowChartUpdate !== false) {\n // Reacreate chart on Highcharts or constructor type change\n if (\n props.constructorType !== constructorType.current ||\n props.highcharts !== highcharts.current\n ) {\n constructorType.current = props.constructorType;\n highcharts.current = props.highcharts;\n createChart();\n // Use `chart.update` to apply changes\n } else if (!props.immutable && chartRef.current) {\n chartRef.current.update(\n props.options,\n ...(props.updateArgs || [true, true])\n );\n } else {\n createChart();\n }\n }\n }\n }, [\n props.options,\n props.allowChartUpdate,\n props.updateArgs,\n props.containerProps,\n props.highcharts,\n props.constructorType\n ]);\n\n // Destroy the chart on unmount\n useIsomorphicLayoutEffect(() => {\n return () => {\n if (chartRef.current) {\n chartRef.current.destroy();\n chartRef.current = null;\n }\n };\n }, []);\n\n useImperativeHandle(\n ref,\n () => ({\n get chart() {\n return chartRef.current;\n },\n container: containerRef\n }),\n []\n );\n\n // Create container for the chart\n return
;\n }\n));\n\nexport default HighchartsReact;\n\n\n\n// WEBPACK FOOTER //\n// ./src/HighchartsReact.js","module.exports = __WEBPACK_EXTERNAL_MODULE_1__;\n\n\n//////////////////\n// WEBPACK FOOTER\n// external {\"root\":\"React\",\"commonjs\":\"react\",\"commonjs2\":\"react\",\"amd\":\"react\"}\n// module id = 1\n// module chunks = 0 1"],"sourceRoot":""} -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./src/HighchartsReact.js') 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "highcharts-react-official", 3 | "version": "3.2.2", 4 | "main": "./dist/highcharts-react.min.js", 5 | "types": "./dist/highcharts-react.min.d.ts", 6 | "license": "MIT", 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/highcharts/highcharts-react" 10 | }, 11 | "keywords": [ 12 | "highcharts", 13 | "highstock", 14 | "highmaps", 15 | "react" 16 | ], 17 | "scripts": { 18 | "test": "jest", 19 | "build-demo": "browserify ./demo/demo.jsx -o ./demo/bundle.js -t [ babelify --presets [ @babel/preset-env @babel/preset-react ] ]", 20 | "build": "webpack --config webpack.config.js", 21 | "release": "standard-version" 22 | }, 23 | "jest": { 24 | "setupFilesAfterEnv": [ 25 | "./tests/setupTests.js" 26 | ] 27 | }, 28 | "eslintConfig": { 29 | "extends": "react-app" 30 | }, 31 | "peerDependencies": { 32 | "highcharts": ">=6.0.0", 33 | "react": ">=16.8.0" 34 | }, 35 | "husky": { 36 | "hooks": { 37 | "pre-commit": "npm run test && npm run build" 38 | } 39 | }, 40 | "devDependencies": { 41 | "@babel/core": "^7.8.4", 42 | "@babel/preset-env": "^7.8.4", 43 | "@babel/preset-react": "^7.8.3", 44 | "babel-loader": "^8.0.6", 45 | "babelify": "^10.0.0", 46 | "browserify": "^14.3.0", 47 | "enzyme": "^3.11.0", 48 | "enzyme-adapter-react-16": "^1.15.2", 49 | "eslint": "^6.8.0", 50 | "eslint-plugin-react": "^7.18.3", 51 | "highcharts": ">=9.0.0", 52 | "husky": "^2.4.0", 53 | "jest": "^25.1.0", 54 | "react": "^16.9.0", 55 | "react-dom": "^16.9.0", 56 | "react-test-renderer": "^16.9.0", 57 | "standard": "^10.0.2", 58 | "standard-version": "^8.0.1", 59 | "webpack": "^3.12.0" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/HighchartsReact.d.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) Highsoft AS 3 | */ 4 | 5 | import * as React from 'react'; 6 | import * as Highcharts from 'highcharts'; 7 | 8 | /** 9 | * Highcharts component for React 10 | */ 11 | declare const HighchartsReact: React.ForwardRefExoticComponent< 12 | React.PropsWithoutRef & 13 | React.RefAttributes 14 | >; 15 | 16 | interface HighchartsReactRefObject { 17 | chart: Highcharts.Chart; 18 | 19 | /** 20 | * React reference 21 | */ 22 | container: React.RefObject; 23 | } 24 | 25 | interface HighchartsReactProps { 26 | /* * 27 | * 28 | * Properties 29 | * 30 | * */ 31 | 32 | /** 33 | * Indexer for custom properties 34 | */ 35 | [key: string]: any; 36 | 37 | /** 38 | * Flag for `Chart.update` call (Default: true) 39 | */ 40 | allowChartUpdate?: boolean; 41 | 42 | /** 43 | * Reference to the chart factory (Default: chart) 44 | */ 45 | constructorType?: keyof typeof Highcharts; 46 | 47 | /** 48 | * Properties of the chart container 49 | */ 50 | containerProps?: { [key: string]: any }; 51 | 52 | /** 53 | * Highcharts namespace 54 | */ 55 | highcharts?: typeof Highcharts; 56 | 57 | /** 58 | * Immutably recreates the chart on receiving new props 59 | */ 60 | immutable?: boolean; 61 | 62 | /** 63 | * Highcharts options 64 | */ 65 | options?: Highcharts.Options; 66 | 67 | /** 68 | * Flags for `Chart.update` call: redraw, oneToOne, and animation. (Default: 69 | * [true, true, true]) 70 | */ 71 | updateArgs?: [boolean] | [boolean, boolean] | [boolean, boolean, boolean]; 72 | 73 | /* * 74 | * 75 | * Functions 76 | * 77 | * */ 78 | 79 | /** 80 | * Callback for the chart factory 81 | */ 82 | callback?: Highcharts.ChartCallbackFunction; 83 | } 84 | 85 | declare namespace HighchartsReact { 86 | /** 87 | * Properties for a HighchartsReact component 88 | */ 89 | interface RefObject extends HighchartsReactRefObject {} 90 | interface Props extends HighchartsReactProps {} 91 | } 92 | 93 | export { HighchartsReact, HighchartsReactRefObject, HighchartsReactProps }; 94 | export default HighchartsReact; 95 | -------------------------------------------------------------------------------- /src/HighchartsReact.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | forwardRef, 3 | memo, 4 | useEffect, 5 | useImperativeHandle, 6 | useLayoutEffect, 7 | useRef 8 | } from 'react'; 9 | 10 | // React currently throws a warning when using `useLayoutEffect` on the server. 11 | // To get around it, we can conditionally `useEffect` on the server (no-op) and 12 | // `useLayoutEffect` in the browser. We need `useLayoutEffect` to ensure the 13 | // `Highcharts` ref is available in the layout phase. This makes it available 14 | // in a parent component's `componentDidMount`. 15 | const useIsomorphicLayoutEffect = 16 | typeof window !== 'undefined' && typeof window.document !== 'undefined' 17 | ? useLayoutEffect 18 | : useEffect; 19 | 20 | export const HighchartsReact = memo(forwardRef( 21 | function HighchartsReact(props, ref) { 22 | const containerRef = useRef(); 23 | const chartRef = useRef(); 24 | const constructorType = useRef(props.constructorType); 25 | const highcharts = useRef(props.highcharts); 26 | 27 | useIsomorphicLayoutEffect(() => { 28 | function createChart() { 29 | const H = props.highcharts || ( 30 | typeof window === 'object' && window.Highcharts 31 | ); 32 | const constructorType = props.constructorType || 'chart'; 33 | 34 | if (!H) { 35 | console.warn('The "highcharts" property was not passed.'); 36 | 37 | } else if (!H[constructorType]) { 38 | console.warn( 39 | 'The "constructorType" property is incorrect or some ' + 40 | 'required module is not imported.' 41 | ); 42 | } else if (!props.options) { 43 | console.warn('The "options" property was not passed.'); 44 | 45 | } else { 46 | // Create a chart 47 | chartRef.current = H[constructorType]( 48 | containerRef.current, 49 | props.options, 50 | props.callback 51 | ); 52 | } 53 | } 54 | 55 | if (!chartRef.current) { 56 | createChart(); 57 | } else { 58 | if (props.allowChartUpdate !== false) { 59 | // Reacreate chart on Highcharts or constructor type change 60 | if ( 61 | props.constructorType !== constructorType.current || 62 | props.highcharts !== highcharts.current 63 | ) { 64 | constructorType.current = props.constructorType; 65 | highcharts.current = props.highcharts; 66 | createChart(); 67 | // Use `chart.update` to apply changes 68 | } else if (!props.immutable && chartRef.current) { 69 | chartRef.current.update( 70 | props.options, 71 | ...(props.updateArgs || [true, true]) 72 | ); 73 | } else { 74 | createChart(); 75 | } 76 | } 77 | } 78 | }, [ 79 | props.options, 80 | props.allowChartUpdate, 81 | props.updateArgs, 82 | props.containerProps, 83 | props.highcharts, 84 | props.constructorType 85 | ]); 86 | 87 | // Destroy the chart on unmount 88 | useIsomorphicLayoutEffect(() => { 89 | return () => { 90 | if (chartRef.current) { 91 | chartRef.current.destroy(); 92 | chartRef.current = null; 93 | } 94 | }; 95 | }, []); 96 | 97 | useImperativeHandle( 98 | ref, 99 | () => ({ 100 | get chart() { 101 | return chartRef.current; 102 | }, 103 | container: containerRef 104 | }), 105 | [] 106 | ); 107 | 108 | // Create container for the chart 109 | return
; 110 | } 111 | )); 112 | 113 | export default HighchartsReact; 114 | -------------------------------------------------------------------------------- /tests/ParentComponent.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import HighchartsReact from '../src/HighchartsReact'; 3 | 4 | export default class ParentComponent extends React.Component { 5 | constructor(props) { 6 | super(props); 7 | this.chartComponent = React.createRef(); 8 | this.state = props.parentState; 9 | } 10 | 11 | render() { 12 | const { parentProps, options } = this.state; 13 | 14 | return ( 15 | 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/__tests__/component/addModule.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { mount } from 'enzyme'; 3 | import Highcharts from 'highcharts'; 4 | import HCmore from 'highcharts/highcharts-more'; 5 | import HighchartsReact from '../../../src/HighchartsReact'; 6 | 7 | const options = { 8 | accessibility: { 9 | enabled: false 10 | }, 11 | series: [{ 12 | type: 'bubble', 13 | data: [1, 2, 3] 14 | }] 15 | }; 16 | 17 | describe('Test - add module.', () => { 18 | beforeEach(() => { 19 | jest.spyOn(console, 'error'); 20 | console.error.mockImplementation(() => {}); 21 | }); 22 | 23 | it('There should be an error before module initialization.', () => { 24 | expect(() => { 25 | mount( 26 | 27 | ); 28 | }).toThrow(Error); 29 | }); 30 | 31 | it('Should be no errors in the console while module is attached properly.', () => { 32 | HCmore(Highcharts); 33 | 34 | expect(() => { 35 | mount( 36 | 37 | ); 38 | }).not.toThrow(Error); 39 | }); 40 | 41 | afterEach(() => { 42 | console.error.mockRestore(); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /tests/__tests__/component/chartReference.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { mount } from 'enzyme'; 3 | import Highcharts from 'highcharts'; 4 | import ParentComponent from '../../ParentComponent'; 5 | 6 | const parentState = { 7 | options: { 8 | accessibility: { 9 | enabled: false 10 | } 11 | }, 12 | parentProps: { 13 | highcharts: Highcharts 14 | } 15 | }; 16 | 17 | describe('Test - component refs.', () => { 18 | it('The component should have chart and container refs.', () => { 19 | const wrapper = mount( 20 | 21 | ); 22 | 23 | expect( 24 | wrapper.instance().chartComponent.current.chart 25 | ).toBe(Highcharts.charts[0]); 26 | 27 | expect( 28 | wrapper.instance().chartComponent.current.container 29 | ).toBeDefined(); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /tests/__tests__/component/componentWithoutProps.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { mount } from 'enzyme'; 3 | import HighchartsReact from '../../../src/HighchartsReact'; 4 | 5 | 6 | test('Check if console warn occurs when props are not set.', () => { 7 | global.console = { warn: jest.fn() }; 8 | 9 | mount(); 10 | 11 | expect(console.warn).toBeCalled(); 12 | }); 13 | -------------------------------------------------------------------------------- /tests/__tests__/component/dynamics.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { mount } from 'enzyme'; 3 | import Highcharts from 'highcharts'; 4 | import ParentComponent from '../../ParentComponent'; 5 | 6 | const test = jest.fn(); 7 | 8 | const parentState = { 9 | options: { 10 | accessibility: { 11 | enabled: false 12 | }, 13 | chart: { 14 | events: { 15 | redraw: test 16 | } 17 | }, 18 | series: [{ 19 | data: [1, 2, 3] 20 | }] 21 | }, 22 | 23 | parentProps: { 24 | highcharts: Highcharts 25 | } 26 | }; 27 | 28 | describe('Test - chart update and chart destroy.', () => { 29 | const wrapper = mount( 30 | 31 | ); 32 | it('Test function should not be triggered.', () => { 33 | wrapper.setState({ 34 | firstRender: false 35 | }); 36 | expect(test).not.toHaveBeenCalled(); 37 | }); 38 | 39 | it('Test function should be triggered - chart has been updated.', () => { 40 | wrapper.setState({ 41 | options: { 42 | series: [{ 43 | data: [1, 2, 3, 4] 44 | }] 45 | } 46 | }); 47 | expect(test).toHaveBeenCalledTimes(1); 48 | 49 | wrapper.setState({ 50 | options: { 51 | series: [{ 52 | data: [1, 2] 53 | }] 54 | } 55 | }); 56 | 57 | expect(test).toHaveBeenCalledTimes(2); 58 | }); 59 | 60 | it('Test the chart destroying after the component unmount.', () => { 61 | wrapper.unmount(); 62 | 63 | expect(Highcharts.charts).toStrictEqual([undefined]); 64 | }); 65 | 66 | }); 67 | -------------------------------------------------------------------------------- /tests/__tests__/component/importComponent.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Highcharts from 'highcharts'; 3 | import { mount } from 'enzyme'; 4 | import { default as HighchartsReactDefault, HighchartsReact } from '../../../src/HighchartsReact'; 5 | 6 | let charts = []; 7 | const componentProps = { 8 | options: { 9 | accessibility: { 10 | enabled: false 11 | }, 12 | chart: { 13 | events: { 14 | load() { 15 | charts.push(this); 16 | } 17 | } 18 | } 19 | }, 20 | highcharts: Highcharts 21 | }; 22 | 23 | describe('Test - import component.', () => { 24 | it('A chart should be created by HighchartsReact from default export', () => { 25 | mount(); 26 | expect(charts[0]).toBeDefined(); 27 | }); 28 | 29 | it('A chart should be created by HighchartsReact from named export', () => { 30 | mount(); 31 | expect(charts[1]).toBeDefined(); 32 | }); 33 | }); -------------------------------------------------------------------------------- /tests/__tests__/component/multipleCharts.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { mount } from 'enzyme'; 3 | import Highcharts from 'highcharts'; 4 | import HighchartsReact from '../../../src/HighchartsReact'; 5 | 6 | const options = { 7 | accessibility: { 8 | enabled: false 9 | } 10 | }; 11 | 12 | describe('Test - multiple charts.', () => { 13 | mount( 14 |
15 | 16 | 17 | 18 |
19 | ); 20 | 21 | it('There should be rendered three charts.', () => { 22 | expect(Highcharts.charts.length).toBe(3); 23 | expect(Highcharts.charts[1]).toHaveProperty('series'); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /tests/__tests__/props/allowChartUpdate.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { mount } from 'enzyme'; 3 | import Highcharts from 'highcharts'; 4 | import ParentComponent from '../../ParentComponent'; 5 | 6 | const redrawCallback = jest.fn(); 7 | 8 | const parentState = { 9 | options: { 10 | accessibility: { 11 | enabled: false 12 | }, 13 | chart: { 14 | events: { 15 | redraw: redrawCallback 16 | } 17 | }, 18 | series: [{ 19 | data: [1, 2, 3] 20 | }] 21 | }, 22 | 23 | parentProps: { 24 | highcharts: Highcharts, 25 | allowChartUpdate: false 26 | } 27 | }; 28 | 29 | describe('Props tests - allowChartUpdate.', () => { 30 | const wrapper = mount( 31 | 32 | ); 33 | 34 | it('Chart should be updated after component update.', () => { 35 | expect(redrawCallback).not.toHaveBeenCalled(); 36 | 37 | wrapper.setState({ 38 | options: { 39 | series: [{ 40 | data: [2, 2, 2] 41 | }] 42 | } 43 | }); 44 | 45 | expect(redrawCallback).not.toHaveBeenCalled(); 46 | }); 47 | 48 | it('Chart should not be updated after component update.', () => { 49 | wrapper.setState({ 50 | parentProps: { 51 | highcharts: Highcharts, 52 | allowChartUpdate: true 53 | }, 54 | options: { 55 | series: [{ 56 | data: [3, 2, 1] 57 | }] 58 | } 59 | }); 60 | 61 | expect(redrawCallback).toHaveBeenCalled(); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /tests/__tests__/props/callback.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { mount } from 'enzyme'; 3 | import Highcharts from 'highcharts'; 4 | import ParentComponent from '../../ParentComponent'; 5 | 6 | const callbackFn = jest.fn(); 7 | 8 | const parentState = { 9 | options: { 10 | accessibility: { 11 | enabled: false 12 | }, 13 | series: [{ 14 | data: [1, 2, 3] 15 | }] 16 | }, 17 | 18 | parentProps: { 19 | highcharts: Highcharts, 20 | callback: callbackFn 21 | } 22 | }; 23 | 24 | const parentProps = parentState.parentProps; 25 | 26 | describe('Props tests - callback.', () => { 27 | const wrapper = mount( 28 | 29 | ); 30 | 31 | it('Callback function should be called only once.', () => { 32 | expect(callbackFn).toHaveBeenCalledTimes(1); 33 | 34 | wrapper.setState({ 35 | options: { 36 | series: [{ 37 | data: [2, 2, 2] 38 | }] 39 | } 40 | }); 41 | 42 | expect(callbackFn).toHaveBeenCalledTimes(1); 43 | }); 44 | 45 | it('Callback function should be called multiple times.', () => { 46 | expect(callbackFn).toHaveBeenCalledTimes(1); 47 | 48 | wrapper.setState({ 49 | options: { 50 | accessibility: { 51 | enabled: false 52 | } 53 | }, 54 | parentProps: { 55 | ...parentProps, 56 | immutable: true 57 | } 58 | }); 59 | 60 | expect(callbackFn).toHaveBeenCalledTimes(2); 61 | 62 | wrapper.setState({ 63 | options: { 64 | accessibility: { 65 | enabled: false 66 | }, 67 | series: [{ 68 | data: [3, 3, 3] 69 | }] 70 | } 71 | }); 72 | 73 | expect(callbackFn).toHaveBeenCalledTimes(3); 74 | }); 75 | }); 76 | -------------------------------------------------------------------------------- /tests/__tests__/props/constructorType.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { mount } from 'enzyme'; 3 | import Highcharts from 'highcharts/highstock'; 4 | import ParentComponent from '../../ParentComponent'; 5 | 6 | import map from 'highcharts/modules/map'; 7 | map(Highcharts); 8 | 9 | let chart; 10 | const parentState = { 11 | options: { 12 | accessibility: { 13 | enabled: false 14 | }, 15 | chart: { 16 | events: { 17 | load() { 18 | chart = this; 19 | } 20 | } 21 | }, 22 | series: [{ 23 | data: [1, 2, 3] 24 | }] 25 | }, 26 | 27 | parentProps: { 28 | highcharts: Highcharts, 29 | constructorType: 'stockChart', 30 | immutable: true 31 | } 32 | }; 33 | 34 | const parentProps = parentState.parentProps; 35 | 36 | describe('Props tests - constructorType.', () => { 37 | const wrapper = mount( 38 | 39 | ); 40 | 41 | it('Chart should be a stock chart.', () => { 42 | expect(chart.navigator).toBeDefined(); 43 | }); 44 | 45 | it('Chart should not be a stock chart.', () => { 46 | wrapper.setState({ 47 | parentProps: { 48 | ...parentProps, constructorType: 'chart' 49 | } 50 | }); 51 | 52 | expect(chart.navigator).toBeUndefined(); 53 | }); 54 | 55 | it('Chart should be a map chart.', () => { 56 | wrapper.setState({ 57 | parentProps: { 58 | ...parentProps, constructorType: 'mapChart' 59 | } 60 | }); 61 | 62 | expect(chart).toBeDefined(); 63 | }); 64 | 65 | it('Chart should be recreated on constructorType change.', () => { 66 | wrapper.setState({ 67 | parentProps: { 68 | ...parentProps, immutable: false, constructorType: 'stockChart' 69 | } 70 | }); 71 | 72 | expect(chart.navigator).toBeDefined(); 73 | }); 74 | }); 75 | -------------------------------------------------------------------------------- /tests/__tests__/props/containerProps.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { mount } from 'enzyme'; 3 | import Highcharts from 'highcharts'; 4 | import ParentComponent from '../../ParentComponent'; 5 | 6 | const parentState = { 7 | options: { 8 | accessibility: { 9 | enabled: false 10 | } 11 | }, 12 | parentProps: { 13 | highcharts: Highcharts, 14 | containerProps: { style: { height: '300px' } } 15 | } 16 | }; 17 | 18 | describe('Props tests - containerProps.', () => { 19 | const wrapper = mount( 20 | 21 | ); 22 | 23 | it('Chart container should have style from containerProps.', () => { 24 | expect(wrapper.find('div').prop('style')).toHaveProperty('height', '300px'); 25 | }); 26 | 27 | it('Chart container should have class from containerProps.', () => { 28 | wrapper.setState({ 29 | parentProps: { 30 | highcharts: Highcharts, 31 | containerProps: { className: 'someCustomClassName' } 32 | } 33 | }); 34 | 35 | expect(wrapper.find('div').hasClass('someCustomClassName')).toBe(true); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /tests/__tests__/props/highcharts.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { mount } from 'enzyme'; 3 | import Highcharts from 'highcharts'; 4 | import Highstock from 'highcharts/highstock'; 5 | import ParentComponent from '../../ParentComponent'; 6 | 7 | let chart; 8 | const test = jest.fn(); 9 | const parentState = { 10 | options: { 11 | accessibility: { 12 | enabled: false 13 | }, 14 | chart: { 15 | events: { 16 | load() { 17 | chart = this; 18 | test(); 19 | } 20 | } 21 | }, 22 | series: [{ 23 | data: [1, 2, 3] 24 | }] 25 | }, 26 | 27 | parentProps: { 28 | highcharts: Highstock 29 | } 30 | }; 31 | 32 | describe('Props tests - highcharts.', () => { 33 | const wrapper = mount( 34 | 35 | ); 36 | 37 | it('A basic chart should be created.', () => { 38 | expect(chart.navigator).toBeUndefined(); 39 | }); 40 | 41 | it('A chart should be recreated once.', () => { 42 | wrapper.setState({ 43 | parentProps: { 44 | highcharts: Highcharts 45 | } 46 | }); 47 | 48 | wrapper.setState({ 49 | parentProps: { 50 | highcharts: Highcharts 51 | } 52 | }); 53 | 54 | expect(test).toHaveBeenCalledTimes(2); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /tests/__tests__/props/immutable.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { mount } from 'enzyme'; 3 | import Highcharts from 'highcharts/highstock'; 4 | import ParentComponent from '../../ParentComponent'; 5 | 6 | import map from 'highcharts/modules/map'; 7 | map(Highcharts); 8 | 9 | const loadCallback = jest.fn(); 10 | const redrawCallback = jest.fn(); 11 | 12 | const parentState = { 13 | options: { 14 | accessibility: { 15 | enabled: false 16 | }, 17 | chart: { 18 | events: { 19 | load: loadCallback, 20 | redraw: redrawCallback 21 | } 22 | }, 23 | series: [{ 24 | data: [1, 2, 3] 25 | }] 26 | }, 27 | 28 | parentProps: { 29 | highcharts: Highcharts, 30 | immutable: true 31 | } 32 | }; 33 | 34 | describe('Props tests - immutable.', () => { 35 | const wrapper = mount( 36 | 37 | ); 38 | 39 | it('Chart should be recreated after component update.', () => { 40 | wrapper.setState({ 41 | options: { 42 | accessibility: { 43 | enabled: false 44 | }, 45 | chart: { 46 | events: { 47 | load: loadCallback, 48 | redraw: redrawCallback 49 | } 50 | }, 51 | series: [{ 52 | data: [2, 2, 2] 53 | }] 54 | } 55 | }); 56 | 57 | expect(redrawCallback).not.toHaveBeenCalled(); 58 | expect(loadCallback).toHaveBeenCalledTimes(2); 59 | }); 60 | 61 | it('Chart should be updated after component update.', () => { 62 | wrapper.setState({ 63 | options: {}, 64 | parentProps: { 65 | highcharts: Highcharts, 66 | immutable: false 67 | } 68 | }); 69 | 70 | expect(redrawCallback).toHaveBeenCalledTimes(1); 71 | }); 72 | }); 73 | -------------------------------------------------------------------------------- /tests/__tests__/props/updateArgs.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { mount } from 'enzyme'; 3 | import Highcharts from 'highcharts/highstock'; 4 | import ParentComponent from '../../ParentComponent'; 5 | 6 | let chart; 7 | const redrawCallback = jest.fn(); 8 | 9 | const parentState = { 10 | options: { 11 | accessibility: { 12 | enabled: false 13 | }, 14 | chart: { 15 | events: { 16 | redraw: redrawCallback, 17 | load(){ 18 | chart = this; 19 | } 20 | } 21 | }, 22 | series: [{ 23 | data: [1, 2, 3] 24 | }, { 25 | data: [3, 2, 1] 26 | }] 27 | }, 28 | 29 | parentProps: { 30 | highcharts: Highcharts, 31 | updateArgs: [false, false] 32 | } 33 | }; 34 | 35 | describe('Props tests - updateArgs.', () => { 36 | const wrapper = mount( 37 | 38 | ); 39 | 40 | it('Redraw callback function should not be called.', () => { 41 | wrapper.setState({ 42 | options: { 43 | series: [] 44 | } 45 | }); 46 | 47 | expect(redrawCallback).not.toHaveBeenCalled(); 48 | }); 49 | 50 | it('Redraw callback function should be called, series should not be removed.', () => { 51 | wrapper.setState({ 52 | parentProps: { 53 | highcharts: Highcharts, 54 | updateArgs: [true, false] 55 | } 56 | }); 57 | 58 | expect(redrawCallback).toHaveBeenCalled(); 59 | expect(chart.series.length).toBe(2); 60 | }); 61 | 62 | it('Series should be removed.', () => { 63 | wrapper.setState({ 64 | parentProps: { 65 | highcharts: Highcharts, 66 | updateArgs: [true, true] 67 | } 68 | }); 69 | 70 | expect(chart.series.length).toBe(0); 71 | }); 72 | }); 73 | -------------------------------------------------------------------------------- /tests/setupTests.js: -------------------------------------------------------------------------------- 1 | import { configure } from 'enzyme'; 2 | import Adapter from 'enzyme-adapter-react-16'; 3 | 4 | configure({ adapter: new Adapter() }); 5 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const path = require('path'); 3 | const fs = require('fs'); 4 | 5 | (function () { 6 | const file = fs.readFileSync('src/HighchartsReact.d.ts'); 7 | 8 | fs.writeFileSync('dist/highcharts-react.d.ts', file); 9 | fs.writeFileSync('dist/highcharts-react.min.d.ts', file); 10 | }()); 11 | 12 | module.exports = { 13 | entry: { 14 | 'highcharts-react': './src/HighchartsReact.js', 15 | 'highcharts-react.min': './src/HighchartsReact.js' 16 | }, 17 | output: { 18 | filename: '[name].js', 19 | sourceMapFilename: '[name].js.map', 20 | library: 'HighchartsReact', 21 | libraryTarget: 'umd', 22 | path: path.resolve(__dirname, './dist') 23 | }, 24 | externals: { 25 | react: { 26 | root: 'React', 27 | commonjs: 'react', 28 | commonjs2: 'react', 29 | amd: 'react' 30 | }, 31 | highcharts: { 32 | root: 'Highcharts', 33 | commonjs: 'highcharts', 34 | commonjs2: 'highcharts', 35 | amd: 'highcharts' 36 | } 37 | }, 38 | devtool: 'source-map', 39 | module: { 40 | rules: [ 41 | { 42 | test: /\.js$/, 43 | exclude: /node_modules/, 44 | loader: 'babel-loader' 45 | } 46 | ] 47 | }, 48 | plugins: [ 49 | new webpack.optimize.UglifyJsPlugin({ 50 | include: /\.min\.js$/, 51 | minimize: true, 52 | sourceMap: true, 53 | debug: true 54 | }) 55 | ] 56 | }; 57 | --------------------------------------------------------------------------------