├── .editorconfig ├── .gitignore ├── .jshintrc ├── .npmignore ├── .travis.yml ├── CONTRIBUTING.md ├── Gruntfile.js ├── ISSUE_TEMPLATE.md ├── LICENSE ├── README.md ├── bower.json ├── dist ├── highcharts-ng.css ├── highcharts-ng.js └── highcharts-ng.min.js ├── example ├── charts │ ├── app.js │ ├── general-example.html │ ├── highstocks-app.js │ └── highstocks-example.html ├── lazyload │ ├── app.js │ └── example.html └── maps │ ├── app.js │ └── example.html ├── jsfiddles ├── basic │ ├── demo.details │ ├── demo.html │ └── demo.js ├── disabled_change_detection │ ├── demo.details │ ├── demo.html │ └── demo.js ├── dynamic_axis │ ├── demo.details │ ├── demo.html │ └── demo.js ├── multi_axis │ ├── demo.details │ ├── demo.html │ └── demo.js ├── polar │ ├── demo.css │ ├── demo.details │ ├── demo.html │ └── demo.js ├── recreating │ ├── demo.details │ ├── demo.html │ └── demo.js └── resizing │ ├── demo.details │ ├── demo.html │ └── demo.js ├── karma.conf.js ├── package.json ├── src ├── highcharts-ng.css └── highcharts-ng.js └── test ├── .jshintrc ├── highcharts-mock.js └── spec └── highcharts-ng.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bower_components/ 2 | /node_modules/ 3 | npm-debug.log 4 | 5 | /.idea/ 6 | .DS_Store 7 | coverage 8 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "browser": true, 4 | "esnext": true, 5 | "bitwise": true, 6 | "camelcase": true, 7 | "curly": false, 8 | "eqeqeq": true, 9 | "immed": true, 10 | "indent": 2, 11 | "latedef": "nofunc", 12 | "newcap": true, 13 | "noarg": true, 14 | "quotmark": "single", 15 | "regexp": true, 16 | "undef": true, 17 | "unused": false, 18 | "strict": true, 19 | "globalstrict": false, 20 | "trailing": true, 21 | "smarttabs": true, 22 | "predef": [ 23 | "angular", 24 | "Highcharts" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /bower_components/ 2 | /node_modules/ 3 | npm-debug.log 4 | 5 | /.idea/ 6 | .DS_Store 7 | 8 | /test/ 9 | /src/ 10 | /example/ 11 | .editorconfig 12 | bower.json 13 | CONTRIBUTING.md 14 | Gruntfile.js 15 | karma.conf.js 16 | README.md 17 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '6.3' 4 | sudo: false 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ### New Issues/Bugs/Feature Requests etc. 4 | Please submit any problems you find - that's how things get better! To make life easier though it's best to fork one of the example jsfiddles and edit it so that it shows your problem. It's fine if it doesn't work (that's often the point!) 5 | 6 | ### Editing files 7 | Please don't edit files in the `dist` subdirectory as they are generated via Grunt. You'll find source code in the `src` subdirectory! 8 | 9 | ### Code style 10 | Regarding code style like indentation and whitespace, **follow the conventions you see used in the source already.** 11 | 12 | ### PhantomJS 13 | While Grunt can run the included unit tests via [PhantomJS](http://phantomjs.org/), this shouldn't be considered a substitute for the real thing. Please be sure to test the `test/*.html` unit test file(s) in _actual_ browsers. 14 | 15 | ## Modifying the code 16 | First, ensure that you have the latest [Node.js](http://nodejs.org/) and [npm](http://npmjs.org/) installed. 17 | 18 | Test that Grunt's CLI and Bower are installed by running `grunt --version` and `bower --version`. If the commands aren't found, run `npm install -g grunt-cli bower`. For more information about installing the tools, see the [getting started with Grunt guide](http://gruntjs.com/getting-started) or [bower.io](http://bower.io/) respectively. 19 | 20 | 1. Fork and clone the repo. 21 | 1. Run `npm install` to install all build dependencies (including Grunt). 22 | 1. Run `bower install` to install the front-end dependencies. 23 | 1. Run `grunt` to grunt this project. 24 | 25 | Assuming that you don't see any red, you're ready to go. Just be sure to run `grunt` after making any changes, to ensure that nothing is broken. 26 | 27 | ## Submitting pull requests 28 | 29 | 1. Create a new branch, please don't work in your `master` branch directly. 30 | 1. Add failing tests for the change you want to make. Run `grunt` to see the tests fail. 31 | 1. Fix stuff. 32 | 1. Run `grunt` to see if the tests pass. Repeat steps 2-4 until done. 33 | 1. Open `test/*.html` unit test file(s) in actual browser to ensure tests pass everywhere. 34 | 1. Update the documentation to reflect any changes. 35 | 1. Push to your fork and submit a pull request. 36 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | // Generated on 2013-11-30 using generator-angular-component 0.2.3 2 | 'use strict'; 3 | 4 | module.exports = function(grunt) { 5 | 6 | // Configurable paths 7 | var yoConfig = { 8 | livereload: 35729, 9 | src: 'src', 10 | dist: 'dist' 11 | }; 12 | 13 | // Livereload setup 14 | var lrSnippet = require('connect-livereload')({port: yoConfig.livereload}); 15 | var mountFolder = function (connect, dir) { 16 | return connect.static(require('path').resolve(dir)); 17 | }; 18 | 19 | require('load-grunt-tasks')(grunt); 20 | 21 | // Project configuration 22 | grunt.initConfig({ 23 | pkg: grunt.file.readJSON('package.json'), 24 | yo: yoConfig, 25 | meta: { 26 | banner: '/**\n' + 27 | ' * <%= pkg.name %>\n' + 28 | ' * @version v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %>\n' + 29 | ' * @link <%= pkg.homepage %>\n' + 30 | ' * @author <%= pkg.author.name %> <<%= pkg.author.email %>>\n' + 31 | ' * @license MIT License, http://www.opensource.org/licenses/MIT\n' + 32 | ' */\n' 33 | }, 34 | open: { 35 | server: { 36 | path: 'http://localhost:<%= connect.options.port %>' 37 | } 38 | }, 39 | clean: { 40 | dist: { 41 | files: [{ 42 | dot: true, 43 | src: [ 44 | '.tmp', 45 | '<%= yo.dist %>/*', 46 | '!<%= yo.dist %>/.git*' 47 | ] 48 | }] 49 | }, 50 | server: '.tmp' 51 | }, 52 | watch: { 53 | gruntfile: { 54 | files: '<%= jshint.gruntfile.src %>', 55 | tasks: ['jshint:gruntfile'] 56 | }, 57 | app: { 58 | files: [ 59 | '{.tmp,<%= yo.src %>}/{,*/}*.js' 60 | ], 61 | options: { 62 | livereload: yoConfig.livereload 63 | } 64 | }, 65 | test: { 66 | files: '<%= jshint.test.src %>', 67 | tasks: ['jshint:test', 'qunit'] 68 | } 69 | }, 70 | connect: { 71 | options: { 72 | port: 9000, 73 | hostname: '0.0.0.0' // Change this to '0.0.0.0' to access the server from outside. 74 | }, 75 | livereload: { 76 | options: { 77 | middleware: function (connect) { 78 | return [ 79 | lrSnippet, 80 | mountFolder(connect, '.tmp'), 81 | mountFolder(connect, yoConfig.src) 82 | ]; 83 | } 84 | } 85 | } 86 | }, 87 | jshint: { 88 | gruntfile: { 89 | options: { 90 | jshintrc: '.jshintrc' 91 | }, 92 | src: 'Gruntfile.js' 93 | }, 94 | src: { 95 | options: { 96 | jshintrc: '.jshintrc' 97 | }, 98 | src: ['<%= yo.src %>/{,*/}*.js'] 99 | }, 100 | test: { 101 | options: { 102 | jshintrc: 'test/.jshintrc' 103 | }, 104 | src: ['test/**/*.js'] 105 | } 106 | }, 107 | karma: { 108 | options: { 109 | configFile: 'karma.conf.js', 110 | browsers: ['PhantomJS'] 111 | }, 112 | unit: { 113 | singleRun: true 114 | }, 115 | server: { 116 | autoWatch: true 117 | } 118 | }, 119 | copy: { 120 | dist: { 121 | expand: true, 122 | cwd: '<%= yo.src %>', 123 | src: '**', 124 | dest: '<%= yo.dist %>' 125 | } 126 | }, 127 | usebanner: { 128 | dist: { 129 | options: { 130 | position: 'top', 131 | banner: '<%= meta.banner %>' 132 | }, 133 | files: { 134 | src: [ '<%= yo.dist %>/*.js' ] 135 | } 136 | } 137 | }, 138 | uglify: { 139 | options: { 140 | banner: '<%= meta.banner %>' 141 | }, 142 | dist: { 143 | files: { 144 | '<%= copy.dist.dest %>/<%= pkg.name %>.min.js': '<%= copy.dist.dest %>/<%= pkg.name %>.js', 145 | } 146 | } 147 | } 148 | }); 149 | 150 | grunt.registerTask('test', [ 151 | 'jshint', 152 | 'karma:unit' 153 | ]); 154 | 155 | grunt.registerTask('build', [ 156 | 'clean:dist', 157 | 'copy:dist', 158 | 'usebanner:dist', 159 | 'uglify:dist' 160 | ]); 161 | 162 | grunt.registerTask('release', [ 163 | 'test', 164 | 'bump-only', 165 | 'build', 166 | 'bump-commit' 167 | ]); 168 | 169 | grunt.registerTask('default', ['build']); 170 | 171 | }; 172 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | ## Link to jsfiddle showing the issue. 3 | 4 | 5 | 6 | ## Expected Behaviour 7 | 8 | 9 | 10 | 11 | ## Current Behaviour 12 | 13 | 14 | 15 | ## Your Environment 16 | 17 | * Version of highcharts-ng used: 18 | * Browser Name and version: 19 | * Operating System and version (desktop or mobile): 20 | * Link to your project: 21 | 22 | 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2013 Barry Fitzgerald http://pablojim.mit-license.org/ 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | highcharts-ng 2 | ============= 3 | 4 | AngularJS directive for Highcharts 5 | 6 | A simple Angularjs directive for Highcharts. 7 | 8 | 9 | Examples 10 | -------- 11 | 12 | See example in ./example/charts/general-example.html (https://rawgit.com/pablojim/highcharts-ng/master/example/charts/general-example.html) 13 | 14 | Also: 15 | 16 | - Basic: http://jsfiddle.net/gh/get/jquery/3.1.1/pablojim/highcharts-ng/tree/master/jsfiddles/basic/ 17 | - Polar Chart: http://jsfiddle.net/gh/get/jquery/3.1.1/pablojim/highcharts-ng/tree/master/jsfiddles/polar/ 18 | - Multi Axis: http://jsfiddle.net/gh/get/jquery/3.1.1/pablojim/highcharts-ng/tree/master/jsfiddles/multi_axis/ 19 | - Resizing to screen size: http://jsfiddle.net/gh/get/jquery/3.1.1/pablojim/highcharts-ng/tree/master/jsfiddles/resizing/ 20 | - Disabled change detection http://jsfiddle.net/gh/get/jquery/3.1.1/pablojim/highcharts-ng/tree/master/jsfiddles/disabled_change_detection/ 21 | - Recreating chart http://jsfiddle.net/gh/get/jquery/3.1.1/pablojim/highcharts-ng/tree/master/jsfiddles/recreating/ 22 | 23 | License 24 | ------- 25 | This library is available under the MIT license. However it and is a wrapper for Highcharts. Highcharts itself has an own license. So make sure to follow their license as well (https://github.com/highcharts/highcharts/blob/master/license.txt) 26 | 27 | Note: You need to include the Highcharts library your self. It is not included in this repository. 28 | 29 | Current Version 30 | --------------- 31 | **Needs Highcharts/Highstock >= 5.0.0** 32 | 33 | **Only supports AngularJS >= 1.5.8** 34 | 35 | **Configuration Format is not compatible with highcharts-ng 0.x.0** 36 | 37 | 38 | **Setup:** 39 | 40 | Install with npm: 41 | 42 | ```bash 43 | npm install highcharts-ng 44 | ``` 45 | 46 | or with bower: 47 | 48 | ```bash 49 | bower install highcharts-ng --save 50 | ``` 51 | 52 | Add highcharts as project dependency with npm 53 | ```bash 54 | npm install highcharts 55 | ``` 56 | 57 | or with bower: 58 | 59 | ```bash 60 | bower install highcharts --save 61 | ``` 62 | 63 | Add references to Highcharts/Highstocks: 64 | 65 | ```html 66 | 67 | ``` 68 | 69 | or 70 | 71 | ```html 72 | 73 | ``` 74 | 75 | Add Highcharts to your Angular app config: 76 | 77 | ```javascript 78 | var myapp = angular.module('myapp', ["highcharts-ng"]); 79 | ``` 80 | 81 | (optional) if you have some problems with resizing the chart to screen size, include the highcharts-ng css file 82 | 83 | ```html 84 | 85 | ``` 86 | 87 | Make a chart! 88 | 89 | ```html 90 | 91 | ``` 92 | 93 | The `chartConfig` object should be the same as a normal highcharts configuration. Any options that work in highcharts should work here also. To use highstock charts, you just need to add `chartType: 'stock'` to your `chartConfig`. 94 | 95 | It is **Highly Recommended** to give all Series and Axes a distinct ID. 96 | 97 | All properties on the chart configuration are optional. If you don't need a feature best to leave it out completely - Highcharts will usually default to something sensible. Each property is watched for changes by angularjs. 98 | 99 | After construction the Highcharts Chart object can be accessed with ```chartConfig.getChartObj()```. This is a simple way to access all the Highcharts API that is not currently managed by this directive. See the JSFiddle basic example to see how this is used to call the print function of Highcharts. 100 | 101 | Sometimes it could make sense to create an entire new Highcharts Chart instead of updating the previous one. For this to happen, you need to pass an entire new chart configuration object to the component instead of updating the previous configuration object. (See example section above) 102 | 103 | If you know the chart data is not going to change, you can disabled the changeDetection to improve performance. This can be done with the attribute ```disable-change-detection="true"```. However this really only affects charts with huge data sets. (See example section above) 104 | 105 | Features: 106 | --------- 107 | 108 | - Adding and removing series 109 | - Setting/Updating Chart options 110 | - Updating the chart title 111 | - Resizes with screen size changes. 112 | - Providing a custom changeDetection function or expression - for speed a custom changeDetection function can be provided to save dirty checking the full chart config. 113 | 114 | Features Not Supported that were previously supported: 115 | ------------------------------------------------------ 116 | - 2 way binding to chart xAxis. (use chartConfig.getChartObj() to get axis values) 117 | - Control of Loading status though the config (use chartConfig.getChartObj() to get axis values) 118 | Both of these should be possible to add with the right PR 119 | - Use of add and remove points on dynamically updated series 120 | 121 | 122 | Caveats: 123 | -------- 124 | 125 | - Due to many equality checks the directive maybe slow with large datasets - try using changeDetection instead 126 | - Whole Chart/Series is often redrawn where a simple update of data would suffice 127 | - If you don't assign ids to your series - incremental ids will be added. This may mean extra redraws. 128 | - Needs more tests! 129 | 130 | FAQ: 131 | -------- 132 | 133 | 134 | - Whats different to previous 0.0.X versions? 135 | 136 | This version is much much simpler and should be more stable. Some features however are still to be implemented 137 | e.g. 2-way binding to axes and loading functionality 138 | 139 | - How do I get access to the chart object? 140 | 141 | You can use `config.getChartObj`. 95% of the time you should not need this and should instead change the chartConfig instead. 142 | 143 | Be careful - if you manually change something with the chart object that is also in the chartConfig the chart and the config may end up out of sync. 144 | 145 | - Why don't you just use the standard Highcharts format? 146 | 147 | Since 1.0.0, vanilla Highcharts objects are supported! 148 | 149 | 150 | 151 | Versions 152 | -------- 153 | 154 | Version 1.2.1 155 | ------------- 156 | Fixes https://github.com/pablojim/highcharts-ng/issues/592 157 | 158 | 159 | Version 1.2.0 160 | ------------- 161 | Remove explicit dependency on Highcharts due to licensing concerns and also allows user to choose between Highcharts and Highstocks. 162 | 163 | - added support for $onChanges, added new binding to disable change detection https://github.com/pablojim/highcharts-ng/pull/622 164 | 165 | Thanks to @ngehlert and others for their contributions. 166 | 167 | Version 1.1.0 168 | ------------- 169 | Now has explicit dependency on highcharts.js. 170 | 171 | - Fix for resizing https://github.com/pablojim/highcharts-ng/issues/550 172 | - Added module loader support https://github.com/pablojim/highcharts-ng/commit/508df111886c4be8b26e82cb6d3e2303f17efed8 173 | Thanks to @houssemba and others for the contributions. 174 | 175 | Version 1.0.1 176 | ------------- 177 | - Fix for for multiple yAxes https://github.com/pablojim/highcharts-ng/issues/201 178 | 179 | Version 1.0.0 180 | ------------- 181 | - only support Highchart/Highstock >= 5.0.0 182 | - only support AngularJS >= 1.5.8 (see https://github.com/toddmotto/angular-component for lower versions) 183 | - Move to AngularJS Component 184 | - Now supports vanilla Highcharts config 185 | - Supports custom change detection functions 186 | - Should be much more stable and less bugs 187 | - 2 way axes binding no longer supported 188 | - loading property no longer supported 189 | 190 | Version 0.0.13 191 | -------------- 192 | - Minor bugfix 193 | 194 | Version 0.0.12 195 | -------------- 196 | - use addPoint where possible 197 | - seperate lazyloader - thanks @graingert 198 | - Lots of updates and fixes - thanks @graingert 199 | 200 | Version 0.0.11 201 | ---------------- 202 | - Bug fix for console error with missing yAxis 203 | 204 | Version 0.0.10 205 | ---------------- 206 | - Bug fix for 0.0.9 - problems with deep extend 207 | 208 | Version 0.0.9 209 | ---------------- 210 | - Lazy loading - thanks @FDIM 211 | - Better navigator support - thanks @ASethi77 212 | - Lots of bug fixes - thanks to all contributors 213 | 214 | Version 0.0.8 215 | ---------------- 216 | - added config.getHighcharts - thanks @ValentinH 217 | - Lots of bug fixes - thanks to all contributors 218 | - Now with support for Highmaps - see: http://rawgit.com/pablojim/highcharts-ng/master/example/maps/example.html 219 | 220 | Version 0.0.7 221 | ---------------- 222 | - Better support for large data series - thanks @f1ghtingfalcons 223 | - Lots of bug fixes - thanks to all contributors 224 | 225 | Version 0.0.6 226 | ---------------- 227 | - Added no data logic - thanks @eranbetzalel 228 | - Added reflow event thanks @pajooh 229 | - Added example for size setting 230 | - Minor bug fixes 231 | 232 | Version 0.0.5 233 | ---------------- 234 | - Now watches size property 235 | - More robust checks around axes 236 | 237 | Version 0.0.4 238 | ---------------- 239 | - Fix to minimised file 240 | 241 | Version 0.0.3 242 | ---------------- 243 | - Migrated to grunt, bower and npm 244 | - Bug fixes 245 | - Some speedups 246 | 247 | Version 0.0.2 248 | ---------------- 249 | - Removed JQuery dependency 250 | - Allowed for null config option 251 | 252 | Version 0.0.1 (not compatible with current version) 253 | ---------------- 254 | 255 | ```html 256 | 257 | ``` 258 | 259 | See an example here: [http://jsfiddle.net/pablojim/46rhz/](http://jsfiddle.net/pablojim/46rhz/) 260 | 261 | 262 | [![Build Status](https://travis-ci.org/pablojim/highcharts-ng.png)](https://travis-ci.org/pablojim/highcharts-ng) 263 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "highcharts-ng", 3 | "description": "An AngularJS directive for Highcharts, Highstocks or Highmaps", 4 | "keywords": [ 5 | "angularjs", 6 | "angular", 7 | "charts", 8 | "highcharts", 9 | "highstocks", 10 | "highmaps" 11 | ], 12 | "ignore": [ 13 | "test", 14 | "src", 15 | "example", 16 | ".travis.yml" 17 | ], 18 | "version": "1.2.2-dev", 19 | "main": "dist/highcharts-ng.js", 20 | "license": "MIT", 21 | "authors": [ 22 | { "name": "Barry Fitzgerald" } 23 | ], 24 | "dependencies": {}, 25 | "devDependencies": {} 26 | } 27 | -------------------------------------------------------------------------------- /dist/highcharts-ng.css: -------------------------------------------------------------------------------- 1 | highchart { 2 | display: block; 3 | width: 100%; 4 | max-width: 100%; 5 | } 6 | -------------------------------------------------------------------------------- /dist/highcharts-ng.js: -------------------------------------------------------------------------------- 1 | /** 2 | * highcharts-ng 3 | * @version v1.2.2-dev - 2018-05-14 4 | * @link https://github.com/pablojim/highcharts-ng 5 | * @author Barry Fitzgerald <> 6 | * @license MIT License, http://www.opensource.org/licenses/MIT 7 | */ 8 | 9 | if (typeof module !== 'undefined' && typeof exports !== 'undefined' && module.exports === exports){ 10 | module.exports = 'highcharts-ng'; 11 | } 12 | 13 | (function () { 14 | 'use strict'; 15 | /*global angular: false*/ 16 | var Highcharts = null; 17 | 18 | if (window && window.Highcharts) { 19 | Highcharts = window.Highcharts; 20 | } else if (typeof module !== 'undefined' && typeof exports !== 'undefined' && 21 | module.exports === 'highcharts-ng' 22 | ) { 23 | Highcharts = require('highcharts'); 24 | } 25 | 26 | 27 | angular.module('highcharts-ng', []) 28 | .component('highchart', { 29 | bindings: { 30 | config: '<', 31 | changeDetection: '<', 32 | disableChangeDetection: '<' 33 | }, 34 | controller: HighChartNGController 35 | }); 36 | 37 | HighChartNGController.$inject = ['$element', '$timeout']; 38 | 39 | function HighChartNGController($element, $timeout) { 40 | var initialized = false; 41 | var seriesId = 0; 42 | var yAxisId = 0; 43 | var xAxisId = 0; 44 | var ctrl = this; 45 | var prevConfig = {}; 46 | var mergedConfig = {}; 47 | var detector = ctrl.changeDetection || angular.equals; 48 | 49 | this.$onInit = function () { 50 | initChart(); 51 | initialized = true; 52 | }; 53 | 54 | this.$onChanges = function(changesObject) { 55 | if (changesObject.config && changesObject.config.currentValue !== undefined) { 56 | if (!initialized) { 57 | return; 58 | } 59 | initChart(); 60 | } 61 | }; 62 | 63 | this.removeItems = function (newItems, chartItems, id, toIgnore) { 64 | if (newItems && Array.isArray(newItems)) { 65 | var ids = ensureIds(newItems, id); 66 | for (var i = chartItems.length - 1; i >= 0; i -= 1) { 67 | var a = chartItems[i]; 68 | if ((toIgnore.indexOf(a.options.id) < 0) && (ids.indexOf(a.options.id) < 0)) { 69 | //if we don't set redraw to true, it can create 70 | //glitches in the chart's rendering where the series 71 | //doesn't completely re-render 72 | a.remove(true); 73 | } 74 | } 75 | } 76 | 77 | }; 78 | 79 | this.removeUnlinkedObjects = function (mergedConfig) { 80 | /* 81 | Removes unlinked objects, items that have been removed in the config, 82 | but not yet removed from the HighChart object 83 | */ 84 | //First check to see if there are any axes that need to be removed 85 | //If a series is linked to the axis, it will be removed by HighCharts 86 | this.removeItems(mergedConfig.yAxis, ctrl.chart.yAxis, yAxisId, 'navigator-y-axis'); 87 | this.removeItems(mergedConfig.xAxis, ctrl.chart.xAxis, xAxisId, 'navigator-x-axis'); 88 | this.removeItems(mergedConfig.series, ctrl.chart.series, seriesId, 'highcharts-navigator-series'); 89 | //TODO do we need to handle removing series from the config that highcharts has removed as part 90 | //of removing axes? 91 | }; 92 | 93 | this.addAnyNewAxes = function (configAxes, chart, isX) { 94 | if (configAxes && Array.isArray(configAxes)) { 95 | angular.forEach(configAxes, function (s) { 96 | if (!chart.get(s.id)) { 97 | chart.addAxis(s, isX); 98 | } 99 | }); 100 | } 101 | }; 102 | 103 | this.$doCheck = function () { 104 | if (ctrl.disableChangeDetection === true) { 105 | return; 106 | } 107 | if (!detector(ctrl.config, prevConfig)) { 108 | prevConfig = angular.merge({}, ctrl.config); 109 | mergedConfig = getMergedOptions($element, ctrl.config, seriesId); 110 | 111 | //Remove any unlinked objects before adding 112 | this.removeUnlinkedObjects(mergedConfig); 113 | 114 | //Allows dynamic adding Axes 115 | this.addAnyNewAxes(mergedConfig.yAxis, ctrl.chart, false); 116 | this.addAnyNewAxes(mergedConfig.xAxis, ctrl.chart, true); 117 | 118 | //Allows dynamic adding of series 119 | if (mergedConfig.series) { 120 | // Add any new series 121 | angular.forEach(ctrl.config.series, function (s) { 122 | if (!ctrl.chart.get(s.id)) { 123 | ctrl.chart.addSeries(s); 124 | } 125 | }); 126 | } 127 | 128 | ctrl.chart.update(mergedConfig, true); 129 | } 130 | }; 131 | 132 | this.$onDestroy = function () { 133 | if (ctrl.chart) { 134 | try { 135 | ctrl.chart.destroy(); 136 | } catch (ex) { 137 | // fail silently as highcharts will throw exception if element doesn't exist 138 | } 139 | 140 | $timeout(function () { 141 | $element.remove(); 142 | }, 0); 143 | } 144 | }; 145 | 146 | function initChart() { 147 | prevConfig = angular.merge({}, ctrl.config); 148 | mergedConfig = getMergedOptions($element, ctrl.config, seriesId); 149 | ctrl.chart = new Highcharts[getChartType(mergedConfig)](mergedConfig); 150 | ctrl.config.getChartObj = function () { 151 | return ctrl.chart; 152 | }; 153 | 154 | // Fix resizing bug 155 | // https://github.com/pablojim/highcharts-ng/issues/550 156 | var originalWidth = $element[0].clientWidth; 157 | var originalHeight = $element[0].clientHeight; 158 | $timeout(function () { 159 | if ($element[0].clientWidth !== 0 && $element[0].clientHeight !== 0 && ($element[0].clientWidth !== originalWidth || $element[0].clientHeight !== originalHeight)) { 160 | ctrl.chart.reflow(); 161 | } 162 | }, 0, false); 163 | } 164 | } 165 | 166 | 167 | function getMergedOptions(element, config, seriesId) { 168 | var mergedOptions = {}; 169 | 170 | var defaultOptions = { 171 | chart: { 172 | events: {} 173 | }, 174 | title: {}, 175 | subtitle: {}, 176 | series: [], 177 | credits: {}, 178 | plotOptions: {}, 179 | navigator: {}, 180 | }; 181 | 182 | if (config) { 183 | //check all series and axis ids are set 184 | if (config.series) { 185 | ensureIds(config.series, seriesId); 186 | } 187 | 188 | mergedOptions = angular.merge(defaultOptions, config); 189 | } else { 190 | mergedOptions = defaultOptions; 191 | } 192 | mergedOptions.chart.renderTo = element[0]; 193 | 194 | //check chart type is set 195 | return mergedOptions; 196 | } 197 | 198 | var chartTypeMap = { 199 | 'stock': 'StockChart', 200 | 'map': 'Map', 201 | 'chart': 'Chart' 202 | }; 203 | 204 | function getChartType(config) { 205 | if (config === undefined || config.chartType === undefined) return 'Chart'; 206 | return chartTypeMap[('' + config.chartType).toLowerCase()]; 207 | } 208 | 209 | function ensureIds(chartCollection, collectionId) { 210 | /* 211 | Ensures each item in the iteratble chartCollection has an id, 212 | and if not auto-generates one incrementing collectionId 213 | */ 214 | var ids = []; 215 | angular.forEach(chartCollection, function (s) { 216 | if (!angular.isDefined(s.id)) { 217 | collectionId += 1; 218 | s.id = 'cc-' + collectionId; 219 | } 220 | ids.push(s.id); 221 | }); 222 | 223 | return ids; 224 | } 225 | 226 | 227 | }()); 228 | -------------------------------------------------------------------------------- /dist/highcharts-ng.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * highcharts-ng 3 | * @version v1.2.2-dev - 2018-05-14 4 | * @link https://github.com/pablojim/highcharts-ng 5 | * @author Barry Fitzgerald <> 6 | * @license MIT License, http://www.opensource.org/licenses/MIT 7 | */ 8 | "undefined"!=typeof module&&"undefined"!=typeof exports&&module.exports===exports&&(module.exports="highcharts-ng"),function(){"use strict";function a(a,f){function g(){m=angular.merge({},l.config),n=b(a,l.config,i),l.chart=new(e[c(n)])(n),l.config.getChartObj=function(){return l.chart};var d=a[0].clientWidth,g=a[0].clientHeight;f(function(){0===a[0].clientWidth||0===a[0].clientHeight||a[0].clientWidth===d&&a[0].clientHeight===g||l.chart.reflow()},0,!1)}var h=!1,i=0,j=0,k=0,l=this,m={},n={},o=l.changeDetection||angular.equals;this.$onInit=function(){g(),h=!0},this.$onChanges=function(a){if(a.config&&void 0!==a.config.currentValue){if(!h)return;g()}},this.removeItems=function(a,b,c,e){if(a&&Array.isArray(a))for(var f=d(a,c),g=b.length-1;g>=0;g-=1){var h=b[g];e.indexOf(h.options.id)<0&&f.indexOf(h.options.id)<0&&h.remove(!0)}},this.removeUnlinkedObjects=function(a){this.removeItems(a.yAxis,l.chart.yAxis,j,"navigator-y-axis"),this.removeItems(a.xAxis,l.chart.xAxis,k,"navigator-x-axis"),this.removeItems(a.series,l.chart.series,i,"highcharts-navigator-series")},this.addAnyNewAxes=function(a,b,c){a&&Array.isArray(a)&&angular.forEach(a,function(a){b.get(a.id)||b.addAxis(a,c)})},this.$doCheck=function(){l.disableChangeDetection!==!0&&(o(l.config,m)||(m=angular.merge({},l.config),n=b(a,l.config,i),this.removeUnlinkedObjects(n),this.addAnyNewAxes(n.yAxis,l.chart,!1),this.addAnyNewAxes(n.xAxis,l.chart,!0),n.series&&angular.forEach(l.config.series,function(a){l.chart.get(a.id)||l.chart.addSeries(a)}),l.chart.update(n,!0)))},this.$onDestroy=function(){if(l.chart){try{l.chart.destroy()}catch(b){}f(function(){a.remove()},0)}}}function b(a,b,c){var e={},f={chart:{events:{}},title:{},subtitle:{},series:[],credits:{},plotOptions:{},navigator:{}};return b?(b.series&&d(b.series,c),e=angular.merge(f,b)):e=f,e.chart.renderTo=a[0],e}function c(a){return void 0===a||void 0===a.chartType?"Chart":f[(""+a.chartType).toLowerCase()]}function d(a,b){var c=[];return angular.forEach(a,function(a){angular.isDefined(a.id)||(b+=1,a.id="cc-"+b),c.push(a.id)}),c}var e=null;window&&window.Highcharts?e=window.Highcharts:"undefined"!=typeof module&&"undefined"!=typeof exports&&"highcharts-ng"===module.exports&&(e=require("highcharts")),angular.module("highcharts-ng",[]).component("highchart",{bindings:{config:"<",changeDetection:"<",disableChangeDetection:"<"},controller:a}),a.$inject=["$element","$timeout"];var f={stock:"StockChart",map:"Map",chart:"Chart"}}(); -------------------------------------------------------------------------------- /example/charts/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var myapp = angular.module('myapp', ["highcharts-ng"]); 4 | 5 | myapp.controller('myctrl', function ($scope) { 6 | 7 | $scope.chartTypes = [ 8 | {"id": "line", "title": "Line"}, 9 | {"id": "spline", "title": "Smooth line"}, 10 | {"id": "area", "title": "Area"}, 11 | {"id": "areaspline", "title": "Smooth area"}, 12 | {"id": "column", "title": "Column"}, 13 | {"id": "bar", "title": "Bar"}, 14 | {"id": "pie", "title": "Pie"}, 15 | {"id": "scatter", "title": "Scatter"} 16 | ]; 17 | 18 | $scope.dashStyles = [ 19 | {"id": "Solid", "title": "Solid"}, 20 | {"id": "ShortDash", "title": "ShortDash"}, 21 | {"id": "ShortDot", "title": "ShortDot"}, 22 | {"id": "ShortDashDot", "title": "ShortDashDot"}, 23 | {"id": "ShortDashDotDot", "title": "ShortDashDotDot"}, 24 | {"id": "Dot", "title": "Dot"}, 25 | {"id": "Dash", "title": "Dash"}, 26 | {"id": "LongDash", "title": "LongDash"}, 27 | {"id": "DashDot", "title": "DashDot"}, 28 | {"id": "LongDashDot", "title": "LongDashDot"}, 29 | {"id": "LongDashDotDot", "title": "LongDashDotDot"} 30 | ]; 31 | 32 | $scope.chartSeries = [ 33 | {"name": "Some data", "data": [1, 2, 4, 7, 3], id: 's1'}, 34 | {"name": "Some data 3", "data": [3, 1, null, 5, 2], connectNulls: true, id: 's2'}, 35 | {"name": "Some data 2", "data": [5, 2, 2, 3, 5], type: "column", id: 's3'}, 36 | {"name": "My Super Column", "data": [1, 1, 2, 3, 2], type: "column", id: 's4'} 37 | ]; 38 | 39 | $scope.chartStack = [ 40 | {"id": '', "title": "No"}, 41 | {"id": "normal", "title": "Normal"}, 42 | {"id": "percent", "title": "Percent"} 43 | ]; 44 | 45 | $scope.addPoints = function () { 46 | var seriesArray = $scope.chartConfig.series; 47 | var rndIdx = Math.floor(Math.random() * seriesArray.length); 48 | seriesArray[rndIdx].data = seriesArray[rndIdx].data.concat([1, 10, 20]); 49 | }; 50 | 51 | var seriesId = 0; 52 | var yAxisId = 0; 53 | var xAxisId = 0; 54 | 55 | $scope.addAxis = function(xy) { 56 | /* 57 | Adds a Y Axis 58 | */ 59 | var id; 60 | var axis; 61 | if (xy==='y') { 62 | yAxisId += 1; 63 | id = yAxisId; 64 | axis = 'yAxis'; 65 | } else { 66 | xAxisId += 1; 67 | id = xAxisId; 68 | axis = 'xAxis'; 69 | } 70 | 71 | 72 | var rnd = []; 73 | for (var i = 0; i < 10; i++) { 74 | rnd.push(Math.floor(Math.random() * 20) + 1); 75 | } 76 | if (!$scope.chartConfig[axis]) { 77 | $scope.chartConfig[axis] = []; 78 | } 79 | $scope.chartConfig[axis].push({ 80 | min: Math.min.apply(null, rnd), 81 | max: Math.max.apply(null, rnd), 82 | title: { 83 | text: xy + "-Axis" + id.toString() 84 | }, 85 | id: xy + 'Axis_' + id 86 | }); 87 | }; 88 | 89 | 90 | $scope.addSeries = function () { 91 | var rnd = [] 92 | for (var i = 0; i < 10; i++) { 93 | rnd.push(Math.floor(Math.random() * 20) + 1) 94 | } 95 | var sId = '__series' + seriesId++; 96 | $scope.chartConfig.series.push({ 97 | data: rnd, 98 | id: sId 99 | }); 100 | }; 101 | 102 | $scope.removeRandomSeries = function () { 103 | var seriesArray = $scope.chartConfig.series; 104 | var rndIdx = Math.floor(Math.random() * seriesArray.length); 105 | seriesArray.splice(rndIdx, 1); 106 | }; 107 | 108 | $scope.removeSeries = function (id) { 109 | var seriesArray = $scope.chartConfig.series; 110 | seriesArray.splice(id, 1); 111 | }; 112 | 113 | $scope.toggleHighCharts = function () { 114 | this.chartConfig.useHighStocks = !this.chartConfig.useHighStocks; 115 | }; 116 | 117 | $scope.replaceAllSeries = function () { 118 | var data = [ 119 | { name: "first", data: [10], id: 'a' }, 120 | { name: "second", data: [3], id: 'b' }, 121 | { name: "third", data: [13], id: 'c' } 122 | ]; 123 | $scope.chartConfig.series = data; 124 | }; 125 | 126 | $scope.chartConfig = { 127 | 128 | chart: { 129 | height: 500, 130 | width: 500, 131 | type: 'line' 132 | }, 133 | plotOptions: { 134 | series: { 135 | stacking: '' 136 | } 137 | }, 138 | series: $scope.chartSeries, 139 | title: { 140 | text: 'Hello' 141 | } 142 | } 143 | 144 | $scope.reflow = function () { 145 | $scope.$broadcast('highchartsng.reflow'); 146 | }; 147 | 148 | 149 | }); 150 | -------------------------------------------------------------------------------- /example/charts/general-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |

Highcharts-ng example

15 | 16 |
17 |
18 |
19 |
20 |
21 | 22 |
23 |
24 | 25 |
26 |
27 |
28 | {{ chartConfig | json }}
29 |                     
30 |
31 | {{ chartConfig }}
32 |                     
33 |
34 |
{{chartConfig.getChartObj().chartHeight}}
35 |
36 |
37 |
Title
38 |
Subtitle
39 |
Width
40 |
Height
41 |
Default Type
42 |
Stack
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
Min:
53 |
Max:
54 |

Series

55 |
56 |
57 |
Title
58 |
Type
59 |
Color
60 |
Width
61 |
Dash Style
62 |
63 |
64 |
65 |
66 | 67 |
68 |
69 |
70 |
71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /example/charts/highstocks-app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var myapp = angular.module('myapp', ["highcharts-ng"]); 4 | 5 | myapp.controller('myctrl', function ($scope) { 6 | 7 | 8 | $scope.chartConfig = { 9 | subtitle: { 10 | text: 'Click and drag to zoom in.' 11 | }, 12 | chart: { 13 | height: 500, 14 | width: 500, 15 | backgroundColor: 'transparent', 16 | zoomType: 'xy', 17 | resetZoomButton: { 18 | position: { 19 | x: 0, 20 | y: -35 21 | }, 22 | theme: { 23 | fill: 'white', 24 | stroke: 'silver', 25 | r: 0, 26 | states: { 27 | hover: { 28 | fill: '#41739D', 29 | style: { 30 | color: 'white' 31 | } 32 | } 33 | } 34 | } 35 | } 36 | }, 37 | navigator: { 38 | enabled: true, 39 | series: { 40 | data: [] 41 | } 42 | }, 43 | rangeSelector: { 44 | enabled: false 45 | }, 46 | plotOptions: { 47 | series: { 48 | lineWidth: 1, 49 | fillOpacity: 0.5 50 | 51 | }, 52 | column: { 53 | stacking: 'normal' 54 | }, 55 | area: { 56 | stacking: 'normal', 57 | marker: { 58 | enabled: false 59 | } 60 | } 61 | 62 | }, 63 | exporting: false, 64 | xAxis: [{ 65 | type: 'datetime' 66 | }], 67 | yAxis: [ 68 | 69 | { // Primary yAxis 70 | 71 | min: 0, 72 | allowDecimals: false, 73 | title: { 74 | text: 'number of notification', 75 | style: { 76 | color: '#80a3ca' 77 | } 78 | }, 79 | labels: { 80 | format: '{value}', 81 | style: { 82 | color: '#80a3ca' 83 | } 84 | } 85 | 86 | 87 | }, 88 | { // Secondary yAxis 89 | min: 0, 90 | allowDecimals: false, 91 | title: { 92 | text: 'usage time', 93 | style: { 94 | color: '#c680ca' 95 | } 96 | }, 97 | labels: { 98 | format: '{value}', 99 | style: { 100 | color: '#c680ca' 101 | } 102 | }, 103 | opposite: true 104 | 105 | } 106 | ], 107 | 108 | legend: { 109 | enabled: false 110 | }, 111 | title: { 112 | text: ' ' 113 | }, 114 | credits: { 115 | enabled: false 116 | }, 117 | 118 | loading: false, 119 | tooltip: { 120 | crosshairs: [ 121 | { 122 | width: 1, 123 | dashStyle: 'dash', 124 | color: '#898989' 125 | }, 126 | { 127 | width: 1, 128 | dashStyle: 'dash', 129 | color: '#898989' 130 | } 131 | ], 132 | headerFormat: '
{point.key}
', 133 | pointFormat: '

{series.name}

{point.y:,.0f} {series.tooltipOptions.valueSuffix}

', 134 | borderWidth: 1, 135 | borderRadius: 5, 136 | borderColor: '#a4a4a4', 137 | shadow: false, 138 | useHTML: true, 139 | percentageDecimals: 2, 140 | backgroundColor: "rgba(255,255,255,.7)", 141 | style: { 142 | padding: 0 143 | }, 144 | shared: true 145 | 146 | }, 147 | 148 | series: [ 149 | { 150 | id: 'iphoneNotificationData', 151 | name: 'Notifications', 152 | data: [[1426204800000, 12], [1426464000000, 6], [1426550400000, 10], [1426636800000, 3]], 153 | type: 'column', 154 | yAxis: 0, 155 | color: '#80a3ca' 156 | }, 157 | { 158 | id: 'iphoneUsageData', 159 | name: 'Usage Time', 160 | data: [[1426291200000, 5], [1426809600000, 26]], 161 | type: 'line', 162 | yAxis: 1, 163 | tooltip: { 164 | valueSuffix: ' sec' 165 | }, 166 | color: '#c680ca' 167 | } 168 | ], 169 | 170 | 171 | 172 | }; 173 | 174 | 175 | }); 176 | -------------------------------------------------------------------------------- /example/charts/highstocks-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 22 | 23 | 24 |

HighStocks Example

25 | 26 |
27 |
28 |
29 |
30 |
31 | 32 |
33 | 34 |
35 | 36 |
37 |
38 |
39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /example/lazyload/app.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Simple highcharts-ng maps example. 3 | */ 4 | angular 5 | .module('app', ['highcharts-ng-lazyload']) 6 | .config(['highchartsNGProvider', function (highchartsNGProvider) { 7 | highchartsNGProvider.lazyLoad([highchartsNGProvider.HIGHCHART, "maps/modules/map.js", "mapdata/custom/world.js"]); 8 | }]) 9 | .controller('MapController', function (highchartsNG, $scope) { 10 | var countries = { 11 | europe: 'France, Germany, Russia', 12 | asia: 'Japan, China' 13 | }, 14 | defaultSeriesData = { 15 | allAreas: false, 16 | name: '', 17 | countries: '', 18 | data: [], 19 | dataLabels: { 20 | enabled: true, 21 | color: 'white', 22 | formatter: function () { 23 | if (this.point.value) { 24 | return this.point.name; 25 | } 26 | } 27 | }, 28 | tooltip: { 29 | enabled: true, 30 | headerFormat: '', 31 | pointFormat: '{point.name}: {series.name}' 32 | } 33 | }; 34 | 35 | this.makeSeries = function (name, countries) { 36 | var seriesData = angular.copy(defaultSeriesData); 37 | 38 | seriesData.name = name; 39 | seriesData.countries = countries; 40 | seriesData.data = this.makeSeriesData(countries); 41 | 42 | return seriesData; 43 | }; 44 | 45 | this.makeSeriesData = function (string) { 46 | var list = ('' + string).split(','), 47 | data = []; 48 | 49 | angular.forEach(list, function (country) { 50 | data.push({ 51 | name: country.replace(/^\s+|\s+$/, ''), 52 | value: 1 53 | }); 54 | }); 55 | 56 | return data; 57 | }; 58 | 59 | this.setSeriesData = function (series, string) { 60 | series.data = this.makeSeriesData(string); 61 | }; 62 | 63 | this.addSeries = function () { 64 | $scope.chartConfig.series.push(this.makeSeries()); 65 | }; 66 | 67 | this.removeSeries = function (key) { 68 | $scope.chartConfig.series.splice(key, 1); 69 | 70 | if (1 == $scope.chartConfig.series.length) { 71 | $scope.chartConfig.series[0].allAreas = true; 72 | } 73 | }; 74 | $scope.chartConfig = { 75 | options: { 76 | legend: { 77 | enabled: false 78 | }, 79 | plotOptions: { 80 | 81 | }, 82 | }, 83 | chartType: 'map', 84 | title: { 85 | text: 'Highcharts-ng map example' 86 | }, 87 | series: [ 88 | this.makeSeries('Europe', countries.europe), 89 | this.makeSeries('Asia', countries.asia) 90 | ] 91 | }; 92 | 93 | $scope.chartConfig.series[0].allAreas = true; 94 | highchartsNG.getHighcharts().then(function(Highcharts){ 95 | $scope.chartConfig.options.plotOptions.map = { 96 | mapData: Highcharts.maps['custom/world'], 97 | joinBy: ['name'] 98 | }; 99 | }); 100 | }); 101 | -------------------------------------------------------------------------------- /example/lazyload/example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Highcharts-ng maps example 7 | 8 | 9 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 |
24 |
25 | 26 |
27 |
28 |
29 |
30 | 31 |
32 | 33 |
34 |
35 |
36 | 41 |
42 |
43 |
44 | 45 | 46 |
47 |
48 | 49 | 50 |
51 |
52 |
53 | 56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | 64 |
65 |
66 |
67 |
68 |
69 |
70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /example/maps/app.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Simple highcharts-ng maps example. 3 | */ 4 | angular 5 | .module('app', ['highcharts-ng']) 6 | .controller('MapController', function() { 7 | var countries = { 8 | europe: 'France, Germany, Russia', 9 | asia: 'Japan, China' 10 | }, 11 | defaultSeriesData = { 12 | allAreas: false, 13 | name: '', 14 | countries: '', 15 | data: [], 16 | dataLabels: { 17 | enabled: true, 18 | color: 'white', 19 | formatter: function () { 20 | if (this.point.value) { 21 | return this.point.name; 22 | } 23 | } 24 | }, 25 | tooltip: { 26 | enabled: true, 27 | headerFormat: '', 28 | pointFormat: '{point.name}: {series.name}' 29 | } 30 | } 31 | ; 32 | 33 | this.makeSeries = function(name, countries) { 34 | var seriesData = angular.copy(defaultSeriesData); 35 | 36 | seriesData.name = name; 37 | seriesData.countries = countries; 38 | seriesData.data = this.makeSeriesData(countries); 39 | 40 | return seriesData; 41 | }; 42 | 43 | this.makeSeriesData = function(string) { 44 | var list = ('' + string).split(','), 45 | data = [] 46 | ; 47 | 48 | angular.forEach(list, function(country) { 49 | data.push({ 50 | name: country.replace(/^\s+|\s+$/, ''), 51 | value: 1 52 | }); 53 | }); 54 | 55 | return data; 56 | }; 57 | 58 | this.setSeriesData = function(series, string) { 59 | series.data = this.makeSeriesData(string); 60 | }; 61 | 62 | this.addSeries = function() { 63 | this.config.series.push(this.makeSeries()); 64 | }; 65 | 66 | this.removeSeries = function(key) { 67 | this.config.series.splice(key, 1); 68 | 69 | if (1 == this.config.series.length) { 70 | this.config.series[0].allAreas = true; 71 | } 72 | }; 73 | 74 | this.config = { 75 | legend: { 76 | enabled: false 77 | }, 78 | plotOptions: { 79 | map: { 80 | mapData: Highcharts.maps['custom/world'], 81 | joinBy: ['name'] 82 | } 83 | }, 84 | animation: true, 85 | chartType: 'map', 86 | title: { 87 | text: 'Highcharts-ng map example' 88 | }, 89 | series: [ 90 | this.makeSeries('Europe', countries.europe), 91 | this.makeSeries('Asia', countries.asia) 92 | ] 93 | }; 94 | 95 | this.config.series[0].allAreas = true; 96 | }) 97 | ; 98 | -------------------------------------------------------------------------------- /example/maps/example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Highcharts-ng maps example 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 |
25 |
26 | 27 |
28 |
29 |
30 |
31 | 32 |
33 | 34 |
35 |
36 |
37 | 41 |
42 |
43 |
44 | 45 | 46 |
47 |
48 | 49 | 50 |
51 |
52 |
53 | 56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | 64 |
65 |
66 |
67 |
68 |
69 |
70 | 71 | 72 | -------------------------------------------------------------------------------- /jsfiddles/basic/demo.details: -------------------------------------------------------------------------------- 1 | --- 2 | name: Basic Highcharts-ng demo 3 | description: Basic Highcharts-ng demo 4 | authors: 5 | - pablojim 6 | normalize_css: no 7 | ... 8 | -------------------------------------------------------------------------------- /jsfiddles/basic/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 |
8 |
9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 | 17 |
18 |
19 |
20 | 21 |

See Highcharts-ng on github

22 | -------------------------------------------------------------------------------- /jsfiddles/basic/demo.js: -------------------------------------------------------------------------------- 1 | //See: https://github.com/pablojim/highcharts-ng 2 | 3 | $(function () { 4 | var myapp = angular.module('myapp', ["highcharts-ng"]); 5 | 6 | myapp.controller('myctrl', function ($scope) { 7 | 8 | $scope.addPoints = function () { 9 | var seriesArray = $scope.chartConfig.series 10 | var rndIdx = Math.floor(Math.random() * seriesArray.length); 11 | seriesArray[rndIdx].data = seriesArray[rndIdx].data.concat([1, 10, 20]) 12 | }; 13 | 14 | var series = 0; 15 | $scope.addSeries = function () { 16 | var rnd = [] 17 | for (var i = 0; i < 10; i++) { 18 | rnd.push(Math.floor(Math.random() * 20) + 1) 19 | } 20 | $scope.chartConfig.series.push({ 21 | data: rnd, 22 | id: 'series_' + series++ 23 | }) 24 | } 25 | 26 | $scope.removeRandomSeries = function () { 27 | var seriesArray = $scope.chartConfig.series 28 | var rndIdx = Math.floor(Math.random() * seriesArray.length); 29 | seriesArray.splice(rndIdx, 1) 30 | } 31 | 32 | $scope.swapChartType = function () { 33 | if (this.chartConfig.chart.type === 'line') { 34 | this.chartConfig.chart.type = 'bar' 35 | } else { 36 | this.chartConfig.chart.type = 'line' 37 | this.chartConfig.chart.zoomType = 'x' 38 | } 39 | } 40 | 41 | $scope.chartConfig = { 42 | chart: { 43 | type: 'bar' 44 | }, 45 | series: [{ 46 | data: [10, 15, 12, 8, 7], 47 | id: 'series1' 48 | }], 49 | title: { 50 | text: 'Hello' 51 | } 52 | } 53 | 54 | }); 55 | }) 56 | -------------------------------------------------------------------------------- /jsfiddles/disabled_change_detection/demo.details: -------------------------------------------------------------------------------- 1 | --- 2 | name: Disabled change detection demo 3 | description: Disabled change detection Highcharts-ng demo 4 | authors: 5 | - ngehlert 6 | normalize_css: no 7 | ... 8 | -------------------------------------------------------------------------------- /jsfiddles/disabled_change_detection/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 |
8 |
9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 | 17 |
18 |
19 |
20 | 21 |

See Highcharts-ng on github

22 | -------------------------------------------------------------------------------- /jsfiddles/disabled_change_detection/demo.js: -------------------------------------------------------------------------------- 1 | //See: https://github.com/pablojim/highcharts-ng 2 | 3 | $(function () { 4 | var myapp = angular.module('myapp', ["highcharts-ng"]); 5 | 6 | myapp.controller('myctrl', function ($scope) { 7 | 8 | $scope.addPoints = function () { 9 | var seriesArray = $scope.chartConfig.series 10 | var rndIdx = Math.floor(Math.random() * seriesArray.length); 11 | seriesArray[rndIdx].data = seriesArray[rndIdx].data.concat([1, 10, 20]) 12 | }; 13 | 14 | var series = 0; 15 | $scope.addSeries = function () { 16 | var rnd = [] 17 | for (var i = 0; i < 10; i++) { 18 | rnd.push(Math.floor(Math.random() * 20) + 1) 19 | } 20 | $scope.chartConfig.series.push({ 21 | data: rnd, 22 | id: 'series_' + series++ 23 | }) 24 | } 25 | 26 | $scope.removeRandomSeries = function () { 27 | var seriesArray = $scope.chartConfig.series 28 | var rndIdx = Math.floor(Math.random() * seriesArray.length); 29 | seriesArray.splice(rndIdx, 1) 30 | } 31 | 32 | $scope.swapChartType = function () { 33 | if (this.chartConfig.chart.type === 'line') { 34 | this.chartConfig.chart.type = 'bar' 35 | } else { 36 | this.chartConfig.chart.type = 'line' 37 | this.chartConfig.chart.zoomType = 'x' 38 | } 39 | } 40 | 41 | $scope.chartConfig = { 42 | chart: { 43 | type: 'bar' 44 | }, 45 | series: [{ 46 | data: [10, 15, 12, 8, 7], 47 | id: 'series1' 48 | }], 49 | title: { 50 | text: 'Hello' 51 | } 52 | } 53 | 54 | }); 55 | }) 56 | -------------------------------------------------------------------------------- /jsfiddles/dynamic_axis/demo.details: -------------------------------------------------------------------------------- 1 | --- 2 | name: Basic Highcharts-ng demo 3 | description: Dynamic axis Highcharts-ng demo 4 | authors: 5 | - yoshi9143 6 | normalize_css: no 7 | ... 8 | -------------------------------------------------------------------------------- /jsfiddles/dynamic_axis/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 |
8 |
9 | 10 | 11 | 12 | 13 |
14 |
15 | 16 |
17 |
18 |
19 | 20 |

See Highcharts-ng on github

21 | -------------------------------------------------------------------------------- /jsfiddles/dynamic_axis/demo.js: -------------------------------------------------------------------------------- 1 | //See: https://github.com/pablojim/highcharts-ng 2 | 3 | $(function () { 4 | var myapp = angular.module('myapp', ["highcharts-ng"]); 5 | 6 | myapp.controller('myctrl', function ($scope) { 7 | 8 | $scope.addPoints = function () { 9 | var seriesArray = $scope.chartConfig.series; 10 | var rndIdx = Math.floor(Math.random() * seriesArray.length); 11 | seriesArray[rndIdx].data = seriesArray[rndIdx].data.concat([1, 10, 20]); 12 | }; 13 | 14 | var seriesIdx = 0; 15 | var yAxisIdx = 0; 16 | $scope.addYAxisFromSeries = function(seriesData) { 17 | /* 18 | Adds a Y Axis given seriesData (Array) 19 | */ 20 | yAxisIdx += 1; 21 | $scope.chartConfig.yAxis.push({ 22 | min: Math.min.apply(null, seriesData), 23 | max: Math.max.apply(null, seriesData), 24 | title: { 25 | text: "Y-Axis" + yAxisIdx.toString() 26 | }, 27 | id: 'yAxis_' + yAxisIdx 28 | }); 29 | }; 30 | 31 | $scope.addSeries = function () { 32 | seriesIdx += 1; 33 | var rnd = []; 34 | for (var i = 0; i < 10; i++) { 35 | rnd.push(Math.floor(Math.random() * 20) + 1); 36 | } 37 | $scope.addYAxisFromSeries(rnd); 38 | $scope.chartConfig.series.push({ 39 | data: rnd, 40 | yAxis: 'yAxis_' + yAxisIdx, 41 | id: 'series_' + seriesIdx 42 | }); 43 | } 44 | 45 | $scope.removeRandomSeries = function () { 46 | var seriesArray = $scope.chartConfig.series; 47 | var yAxisArray = $scope.chartConfig.yAxis; 48 | var rndIdx = Math.floor(Math.random() * seriesArray.length); 49 | seriesArray.splice(rndIdx, 1); 50 | yAxisArray.splice(rndIdx, 1); 51 | } 52 | 53 | $scope.chartConfig = { 54 | chart: { 55 | type: 'line' 56 | }, 57 | navigator: { 58 | enabled: true 59 | }, 60 | series: [{ 61 | data: [10, 15, 12, 8, 7, 3, 5, 7, 10, 12, 5], 62 | yAxis: 'yAxis_0', 63 | id: 'series_0' 64 | }], 65 | title: { 66 | text: 'Hello' 67 | }, 68 | xAxis: [{ 69 | type: 'datetime' 70 | }], 71 | yAxis: [{ // Primary yAxis 72 | title: { 73 | text: 'number of notification', 74 | }, 75 | id: 'yAxis_0' 76 | }], 77 | }; 78 | 79 | }); 80 | }) 81 | -------------------------------------------------------------------------------- /jsfiddles/multi_axis/demo.details: -------------------------------------------------------------------------------- 1 | --- 2 | name: Basic Highcharts-ng demo 3 | description: Multi axis Highcharts-ng demo 4 | authors: 5 | - pablojim 6 | normalize_css: no 7 | ... 8 | -------------------------------------------------------------------------------- /jsfiddles/multi_axis/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 |
8 |
9 | 10 | 11 | 12 | 13 |
14 |
15 | 16 |
17 |
18 |
19 | 20 |

See Highcharts-ng on github

21 | -------------------------------------------------------------------------------- /jsfiddles/multi_axis/demo.js: -------------------------------------------------------------------------------- 1 | //See: https://github.com/pablojim/highcharts-ng 2 | 3 | $(function () { 4 | var myapp = angular.module('myapp', ["highcharts-ng"]); 5 | 6 | myapp.controller('myctrl', function ($scope) { 7 | 8 | $scope.addPoints = function () { 9 | var seriesArray = $scope.chartConfig.series; 10 | var rndIdx = Math.floor(Math.random() * seriesArray.length); 11 | seriesArray[rndIdx].data = seriesArray[rndIdx].data.concat([1, 10, 20]); 12 | }; 13 | 14 | var series = 0; 15 | $scope.addSeries = function () { 16 | var rnd = []; 17 | for (var i = 0; i < 10; i++) { 18 | rnd.push(Math.floor(Math.random() * 20) + 1); 19 | } 20 | $scope.chartConfig.series.push({ 21 | data: rnd, 22 | id: 'series_' + series++ 23 | }); 24 | } 25 | 26 | $scope.removeRandomSeries = function () { 27 | var seriesArray = $scope.chartConfig.series 28 | var rndIdx = Math.floor(Math.random() * seriesArray.length); 29 | seriesArray.splice(rndIdx, 1); 30 | } 31 | 32 | $scope.chartConfig = { 33 | chart: { 34 | type: 'line' 35 | }, 36 | series: [{ 37 | data: [10, 15, 12, 8, 7], 38 | id: 'series1' 39 | }], 40 | title: { 41 | text: 'Hello' 42 | }, 43 | xAxis: [{ 44 | type: 'datetime' 45 | }], 46 | yAxis: [{ // Primary yAxis 47 | title: { 48 | text: 'number of notification', 49 | } 50 | }, { // Secondary yAxis 51 | title: { 52 | text: 'usage time', 53 | }, 54 | opposite: true 55 | }], 56 | }; 57 | 58 | }); 59 | }) 60 | -------------------------------------------------------------------------------- /jsfiddles/polar/demo.css: -------------------------------------------------------------------------------- 1 | highchart { 2 | width: 100%; 3 | display: block; 4 | } 5 | -------------------------------------------------------------------------------- /jsfiddles/polar/demo.details: -------------------------------------------------------------------------------- 1 | --- 2 | name: Highcharts-ng Polar 3 | description: A Highcharts-ng polar example. 4 | resources: 5 | ... 6 | -------------------------------------------------------------------------------- /jsfiddles/polar/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 |
10 |
11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 |
20 | 21 |
22 |
23 |
24 |
25 | 26 |

See Highcharts-ng on github

27 | -------------------------------------------------------------------------------- /jsfiddles/polar/demo.js: -------------------------------------------------------------------------------- 1 | $(function () { 2 | //See: https://github.com/pablojim/highcharts-ng 3 | var myapp = angular.module('myapp', ["highcharts-ng"]); 4 | 5 | myapp.controller('myctrl', function ($scope) { 6 | 7 | $scope.addPoints = function () { 8 | var seriesArray = $scope.chartConfig.series 9 | var rndIdx = Math.floor(Math.random() * seriesArray.length); 10 | seriesArray[rndIdx].data = seriesArray[rndIdx].data.concat([1, 10, 20]) 11 | }; 12 | 13 | var series = 0; 14 | $scope.addSeries = function () { 15 | var rnd = [] 16 | for (var i = 0; i < 10; i++) { 17 | rnd.push(Math.floor(Math.random() * 20) + 1) 18 | } 19 | $scope.chartConfig.series.push({ 20 | data: rnd, 21 | id: 'series_' + series++ 22 | }) 23 | } 24 | 25 | $scope.removeRandomSeries = function () { 26 | var seriesArray = $scope.chartConfig.series 27 | var rndIdx = Math.floor(Math.random() * seriesArray.length); 28 | seriesArray.splice(rndIdx, 1) 29 | } 30 | 31 | $scope.swapChartType = function () { 32 | this.chartConfig.chart.polar = !this.chartConfig.chart.polar; 33 | 34 | } 35 | 36 | $scope.chartConfig = { 37 | chart: { 38 | polar: true 39 | }, 40 | 41 | title: { 42 | text: 'Highcharts Polar Chart' 43 | }, 44 | 45 | pane: { 46 | startAngle: 0, 47 | endAngle: 360 48 | }, 49 | 50 | xAxis: { 51 | tickInterval: 45, 52 | min: 0, 53 | max: 360, 54 | labels: { 55 | formatter: function () { 56 | return this.value + '°'; 57 | } 58 | } 59 | }, 60 | 61 | yAxis: { 62 | min: 0 63 | }, 64 | 65 | plotOptions: { 66 | series: { 67 | pointStart: 0, 68 | pointInterval: 45 69 | }, 70 | column: { 71 | pointPadding: 0, 72 | groupPadding: 0 73 | } 74 | }, 75 | 76 | series: [{ 77 | type: 'column', 78 | name: 'Column', 79 | data: [8, 7, 6, 5, 4, 3, 2, 1], 80 | pointPlacement: 'between' 81 | }, { 82 | type: 'line', 83 | name: 'Line', 84 | data: [1, 2, 3, 4, 5, 6, 7, 8] 85 | }, { 86 | type: 'area', 87 | name: 'Area', 88 | data: [1, 8, 2, 7, 3, 6, 4, 5] 89 | }] 90 | } 91 | 92 | }); 93 | }) 94 | -------------------------------------------------------------------------------- /jsfiddles/recreating/demo.details: -------------------------------------------------------------------------------- 1 | --- 2 | name: Recreating chart demo 3 | description: Recreating chart demo 4 | authors: 5 | - ngehlert 6 | normalize_css: no 7 | ... 8 | -------------------------------------------------------------------------------- /jsfiddles/recreating/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 |
8 |
9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 | 17 |
18 |
19 |
20 | 21 |

See Highcharts-ng on github

22 | -------------------------------------------------------------------------------- /jsfiddles/recreating/demo.js: -------------------------------------------------------------------------------- 1 | //See: https://github.com/pablojim/highcharts-ng 2 | 3 | $(function () { 4 | var myapp = angular.module('myapp', ["highcharts-ng"]); 5 | 6 | myapp.controller('myctrl', function ($scope) { 7 | 8 | $scope.addPoints = function () { 9 | var seriesArray = $scope.chartConfig.series 10 | var rndIdx = Math.floor(Math.random() * seriesArray.length); 11 | seriesArray[rndIdx].data = seriesArray[rndIdx].data.concat([1, 10, 20]) 12 | 13 | // this is the important row, creating a new object 14 | $scope.chartConfig = angular.copy(this.chartConfig); 15 | }; 16 | 17 | var series = 0; 18 | $scope.addSeries = function () { 19 | var rnd = [] 20 | for (var i = 0; i < 10; i++) { 21 | rnd.push(Math.floor(Math.random() * 20) + 1) 22 | } 23 | $scope.chartConfig.series.push({ 24 | data: rnd, 25 | id: 'series_' + series++ 26 | }) 27 | 28 | // this is the important row, creating a new object 29 | $scope.chartConfig = angular.copy(this.chartConfig); 30 | } 31 | 32 | $scope.removeRandomSeries = function () { 33 | var seriesArray = $scope.chartConfig.series 34 | var rndIdx = Math.floor(Math.random() * seriesArray.length); 35 | seriesArray.splice(rndIdx, 1) 36 | 37 | // this is the important row, creating a new object 38 | $scope.chartConfig = angular.copy(this.chartConfig); 39 | } 40 | 41 | $scope.swapChartType = function () { 42 | if (this.chartConfig.chart.type === 'line') { 43 | this.chartConfig.chart.type = 'bar' 44 | } else { 45 | this.chartConfig.chart.type = 'line' 46 | this.chartConfig.chart.zoomType = 'x' 47 | } 48 | 49 | // this is the important row, creating a new object 50 | $scope.chartConfig = angular.copy(this.chartConfig); 51 | }; 52 | 53 | $scope.chartConfig = { 54 | chart: { 55 | type: 'bar' 56 | }, 57 | series: [{ 58 | data: [10, 15, 12, 8, 7], 59 | id: 'series1' 60 | }], 61 | title: { 62 | text: 'Hello' 63 | } 64 | } 65 | 66 | }); 67 | }) 68 | -------------------------------------------------------------------------------- /jsfiddles/resizing/demo.details: -------------------------------------------------------------------------------- 1 | --- 2 | name: Resizing demo 3 | description: Resizing the chart to scren size 4 | authors: 5 | - pablojim 6 | - houssemba 7 | normalize_css: no 8 | ... 9 | -------------------------------------------------------------------------------- /jsfiddles/resizing/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 |
10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 | 18 |
19 |
20 |
21 | 22 |

See Highcharts-ng on github

23 | -------------------------------------------------------------------------------- /jsfiddles/resizing/demo.js: -------------------------------------------------------------------------------- 1 | //See: https://github.com/pablojim/highcharts-ng 2 | 3 | $(function () { 4 | var myapp = angular.module('myapp', ["highcharts-ng"]); 5 | 6 | myapp.controller('myctrl', function ($scope) { 7 | 8 | $scope.addPoints = function () { 9 | var seriesArray = $scope.chartConfig.series 10 | var rndIdx = Math.floor(Math.random() * seriesArray.length); 11 | seriesArray[rndIdx].data = seriesArray[rndIdx].data.concat([1, 10, 20]) 12 | }; 13 | 14 | var series = 0; 15 | $scope.addSeries = function () { 16 | var rnd = [] 17 | for (var i = 0; i < 10; i++) { 18 | rnd.push(Math.floor(Math.random() * 20) + 1) 19 | } 20 | $scope.chartConfig.series.push({ 21 | data: rnd, 22 | id: 'series_' + series++ 23 | }) 24 | } 25 | 26 | $scope.removeRandomSeries = function () { 27 | var seriesArray = $scope.chartConfig.series 28 | var rndIdx = Math.floor(Math.random() * seriesArray.length); 29 | seriesArray.splice(rndIdx, 1) 30 | } 31 | 32 | $scope.swapChartType = function () { 33 | if (this.chartConfig.chart.type === 'line') { 34 | this.chartConfig.chart.type = 'bar' 35 | } else { 36 | this.chartConfig.chart.type = 'line' 37 | this.chartConfig.chart.zoomType = 'x' 38 | } 39 | } 40 | 41 | $scope.chartConfig = { 42 | chart: { 43 | type: 'bar' 44 | }, 45 | series: [{ 46 | data: [10, 15, 12, 8, 7], 47 | id: 'series1' 48 | }], 49 | title: { 50 | text: 'Hello' 51 | } 52 | } 53 | 54 | }); 55 | }) 56 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | module.exports = function(config) { 3 | config.set({ 4 | 5 | // base path, that will be used to resolve files and exclude 6 | basePath: '', 7 | 8 | preprocessors: { 9 | 'app/scripts/**/*.js': 'coverage' 10 | }, 11 | 12 | frameworks: ['jasmine'], 13 | 14 | // list of files / patterns to load in the browser 15 | files: [ 16 | 'node_modules/angular/angular.js', 17 | 'node_modules/jquery/dist/jquery.js', 18 | 'node_modules/angular-mocks/angular-mocks.js', 19 | 'test/highcharts-mock.js', 20 | 'src/*.js', 21 | 'test/spec/*.js' 22 | ], 23 | 24 | // list of files to exclude 25 | exclude: [], 26 | 27 | // test results reporter to use 28 | // possible values: dots || progress || growl 29 | reporters: ['progress', 'coverage'], 30 | 31 | // web server port 32 | port: 8080, 33 | 34 | // cli runner port 35 | runnerPort: 9100, 36 | 37 | // enable / disable colors in the output (reporters and logs) 38 | colors: true, 39 | 40 | // level of logging 41 | // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG 42 | logLevel: 'LOG_INFO', 43 | 44 | // enable / disable watching file and executing tests whenever any file changes 45 | autoWatch: false, 46 | 47 | // Start these browsers, currently available: 48 | // - Chrome 49 | // - ChromeCanary 50 | // - Firefox 51 | // - Opera 52 | // - Safari (only Mac) 53 | // - PhantomJS 54 | // - IE (only Windows) 55 | browsers: ['Chrome'], 56 | 57 | // If browser does not capture in given timeout [ms], kill it 58 | captureTimeout: 5000, 59 | 60 | // Continuous Integration mode 61 | // if true, it capture browsers, run tests and exit 62 | singleRun: false, 63 | 64 | coverageReporter: { 65 | type: 'html', 66 | dir: 'coverage/' 67 | }, 68 | plugins: [ 69 | require('karma-jasmine'), 70 | require('karma-coverage'), 71 | require('karma-phantomjs-launcher'), 72 | require('karma-chrome-launcher'), 73 | ] 74 | 75 | }); 76 | }; 77 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "highcharts-ng", 3 | "version": "1.2.2-dev", 4 | "description": "highcharts-ng", 5 | "keywords": [ 6 | "angular" 7 | ], 8 | "homepage": "https://github.com/pablojim/highcharts-ng", 9 | "author": { 10 | "name": "Barry Fitzgerald", 11 | "email": "", 12 | "url": "https://github.com/pablojim" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/pablojim/highcharts-ng.git" 17 | }, 18 | "license": "MIT", 19 | "devDependencies": { 20 | "angular": "^1.5.7", 21 | "angular-mocks": "^1.5.7", 22 | "connect-livereload": "~0.5.3", 23 | "grunt": "^1.0.1", 24 | "grunt-banner": "^0.6.0", 25 | "grunt-bump": "^0.8.0", 26 | "grunt-cli": "^1.2.0", 27 | "grunt-contrib-clean": "^1.0.0", 28 | "grunt-contrib-concat": "^1.0.1", 29 | "grunt-contrib-connect": "^1.0.2", 30 | "grunt-contrib-copy": "^1.0.0", 31 | "grunt-contrib-jshint": "^1.0.0", 32 | "grunt-contrib-uglify": "^1.0.1", 33 | "grunt-contrib-watch": "^1.0.0", 34 | "grunt-karma": "^2.0.0", 35 | "grunt-open": "~0.2.2", 36 | "jasmine-core": "^2.4.1", 37 | "jquery": "^3.1.0", 38 | "karma": "^1.1.1", 39 | "karma-chrome-launcher": "^1.0.1", 40 | "karma-coverage": "^1.1.0", 41 | "karma-jasmine": "^1.0.2", 42 | "karma-phantomjs-launcher": "^1.0.1", 43 | "load-grunt-tasks": "^3.5.0", 44 | "phantomjs-prebuilt": "^2.1.7" 45 | }, 46 | "scripts": { 47 | "build": "grunt", 48 | "test": "grunt test" 49 | }, 50 | "main": "./dist/highcharts-ng", 51 | "dependencies": { 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/highcharts-ng.css: -------------------------------------------------------------------------------- 1 | highchart { 2 | display: block; 3 | width: 100%; 4 | max-width: 100%; 5 | } 6 | -------------------------------------------------------------------------------- /src/highcharts-ng.js: -------------------------------------------------------------------------------- 1 | if (typeof module !== 'undefined' && typeof exports !== 'undefined' && module.exports === exports){ 2 | module.exports = 'highcharts-ng'; 3 | } 4 | 5 | (function () { 6 | 'use strict'; 7 | /*global angular: false*/ 8 | var Highcharts = null; 9 | 10 | if (window && window.Highcharts) { 11 | Highcharts = window.Highcharts; 12 | } else if (typeof module !== 'undefined' && typeof exports !== 'undefined' && 13 | module.exports === 'highcharts-ng' 14 | ) { 15 | Highcharts = require('highcharts'); 16 | } 17 | 18 | 19 | angular.module('highcharts-ng', []) 20 | .component('highchart', { 21 | bindings: { 22 | config: '<', 23 | changeDetection: '<', 24 | disableChangeDetection: '<' 25 | }, 26 | controller: HighChartNGController 27 | }); 28 | 29 | HighChartNGController.$inject = ['$element', '$timeout']; 30 | 31 | function HighChartNGController($element, $timeout) { 32 | var initialized = false; 33 | var seriesId = 0; 34 | var yAxisId = 0; 35 | var xAxisId = 0; 36 | var ctrl = this; 37 | var prevConfig = {}; 38 | var mergedConfig = {}; 39 | var detector = ctrl.changeDetection || angular.equals; 40 | 41 | this.$onInit = function () { 42 | initChart(); 43 | initialized = true; 44 | }; 45 | 46 | this.$onChanges = function(changesObject) { 47 | if (changesObject.config && changesObject.config.currentValue !== undefined) { 48 | if (!initialized) { 49 | return; 50 | } 51 | initChart(); 52 | } 53 | }; 54 | 55 | this.removeItems = function (newItems, chartItems, id, toIgnore) { 56 | if (newItems && Array.isArray(newItems)) { 57 | var ids = ensureIds(newItems, id); 58 | for (var i = chartItems.length - 1; i >= 0; i -= 1) { 59 | var a = chartItems[i]; 60 | if ((toIgnore.indexOf(a.options.id) < 0) && (ids.indexOf(a.options.id) < 0)) { 61 | //if we don't set redraw to true, it can create 62 | //glitches in the chart's rendering where the series 63 | //doesn't completely re-render 64 | a.remove(true); 65 | } 66 | } 67 | } 68 | 69 | }; 70 | 71 | this.removeUnlinkedObjects = function (mergedConfig) { 72 | /* 73 | Removes unlinked objects, items that have been removed in the config, 74 | but not yet removed from the HighChart object 75 | */ 76 | //First check to see if there are any axes that need to be removed 77 | //If a series is linked to the axis, it will be removed by HighCharts 78 | this.removeItems(mergedConfig.yAxis, ctrl.chart.yAxis, yAxisId, 'navigator-y-axis'); 79 | this.removeItems(mergedConfig.xAxis, ctrl.chart.xAxis, xAxisId, 'navigator-x-axis'); 80 | this.removeItems(mergedConfig.series, ctrl.chart.series, seriesId, 'highcharts-navigator-series'); 81 | //TODO do we need to handle removing series from the config that highcharts has removed as part 82 | //of removing axes? 83 | }; 84 | 85 | this.addAnyNewAxes = function (configAxes, chart, isX) { 86 | if (configAxes && Array.isArray(configAxes)) { 87 | angular.forEach(configAxes, function (s) { 88 | if (!chart.get(s.id)) { 89 | chart.addAxis(s, isX); 90 | } 91 | }); 92 | } 93 | }; 94 | 95 | this.$doCheck = function () { 96 | if (ctrl.disableChangeDetection === true) { 97 | return; 98 | } 99 | if (!detector(ctrl.config, prevConfig)) { 100 | prevConfig = angular.merge({}, ctrl.config); 101 | mergedConfig = getMergedOptions($element, ctrl.config, seriesId); 102 | 103 | //Remove any unlinked objects before adding 104 | this.removeUnlinkedObjects(mergedConfig); 105 | 106 | //Allows dynamic adding Axes 107 | this.addAnyNewAxes(mergedConfig.yAxis, ctrl.chart, false); 108 | this.addAnyNewAxes(mergedConfig.xAxis, ctrl.chart, true); 109 | 110 | //Allows dynamic adding of series 111 | if (mergedConfig.series) { 112 | // Add any new series 113 | angular.forEach(ctrl.config.series, function (s) { 114 | if (!ctrl.chart.get(s.id)) { 115 | ctrl.chart.addSeries(s); 116 | } 117 | }); 118 | } 119 | 120 | ctrl.chart.update(mergedConfig, true); 121 | } 122 | }; 123 | 124 | this.$onDestroy = function () { 125 | if (ctrl.chart) { 126 | try { 127 | ctrl.chart.destroy(); 128 | } catch (ex) { 129 | // fail silently as highcharts will throw exception if element doesn't exist 130 | } 131 | 132 | $timeout(function () { 133 | $element.remove(); 134 | }, 0); 135 | } 136 | }; 137 | 138 | function initChart() { 139 | prevConfig = angular.merge({}, ctrl.config); 140 | mergedConfig = getMergedOptions($element, ctrl.config, seriesId); 141 | ctrl.chart = new Highcharts[getChartType(mergedConfig)](mergedConfig); 142 | ctrl.config.getChartObj = function () { 143 | return ctrl.chart; 144 | }; 145 | 146 | // Fix resizing bug 147 | // https://github.com/pablojim/highcharts-ng/issues/550 148 | var originalWidth = $element[0].clientWidth; 149 | var originalHeight = $element[0].clientHeight; 150 | $timeout(function () { 151 | if ($element[0].clientWidth !== 0 && $element[0].clientHeight !== 0 && ($element[0].clientWidth !== originalWidth || $element[0].clientHeight !== originalHeight)) { 152 | ctrl.chart.reflow(); 153 | } 154 | }, 0, false); 155 | } 156 | } 157 | 158 | 159 | function getMergedOptions(element, config, seriesId) { 160 | var mergedOptions = {}; 161 | 162 | var defaultOptions = { 163 | chart: { 164 | events: {} 165 | }, 166 | title: {}, 167 | subtitle: {}, 168 | series: [], 169 | credits: {}, 170 | plotOptions: {}, 171 | navigator: {}, 172 | }; 173 | 174 | if (config) { 175 | //check all series and axis ids are set 176 | if (config.series) { 177 | ensureIds(config.series, seriesId); 178 | } 179 | 180 | mergedOptions = angular.merge(defaultOptions, config); 181 | } else { 182 | mergedOptions = defaultOptions; 183 | } 184 | mergedOptions.chart.renderTo = element[0]; 185 | 186 | //check chart type is set 187 | return mergedOptions; 188 | } 189 | 190 | var chartTypeMap = { 191 | 'stock': 'StockChart', 192 | 'map': 'Map', 193 | 'chart': 'Chart' 194 | }; 195 | 196 | function getChartType(config) { 197 | if (config === undefined || config.chartType === undefined) return 'Chart'; 198 | return chartTypeMap[('' + config.chartType).toLowerCase()]; 199 | } 200 | 201 | function ensureIds(chartCollection, collectionId) { 202 | /* 203 | Ensures each item in the iteratble chartCollection has an id, 204 | and if not auto-generates one incrementing collectionId 205 | */ 206 | var ids = []; 207 | angular.forEach(chartCollection, function (s) { 208 | if (!angular.isDefined(s.id)) { 209 | collectionId += 1; 210 | s.id = 'cc-' + collectionId; 211 | } 212 | ids.push(s.id); 213 | }); 214 | 215 | return ids; 216 | } 217 | 218 | 219 | }()); 220 | -------------------------------------------------------------------------------- /test/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "browser": true, 4 | "esnext": true, 5 | "bitwise": true, 6 | "camelcase": false, 7 | "curly": false, 8 | "eqeqeq": true, 9 | "immed": true, 10 | "indent": 2, 11 | "latedef": true, 12 | "newcap": true, 13 | "noarg": true, 14 | "quotmark": "single", 15 | "regexp": true, 16 | "undef": true, 17 | "unused": false, 18 | "strict": false, 19 | "globalstrict": false, 20 | "trailing": true, 21 | "smarttabs": true, 22 | "predef": [ 23 | "$", 24 | "angular", 25 | "describe", 26 | "beforeEach", 27 | "afterEach", 28 | "inject", 29 | "it", 30 | "expect", 31 | "HighCharts", 32 | "window", 33 | "module", 34 | "jasmine" 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /test/highcharts-mock.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | window.Highcharts = (function () { 4 | var ns = {}; 5 | 6 | ns.reset = function () { 7 | ns.chart = jasmine.createSpyObj('chart', [ 8 | 'redraw', 9 | 'setTitle', 10 | 'hideLoading', 11 | 'destroy', 12 | 'get', 13 | 'addSeries', 14 | 'update']); 15 | ns.chart.series = []; 16 | ns.usedChartConstructor = null; 17 | ns.options = null; 18 | }; 19 | 20 | ns.Chart = function (opt) { 21 | ns.options = opt; 22 | ns.usedChartConstructor = 'Chart'; 23 | return ns.chart; 24 | }; 25 | ns.StockChart = function (opt) { 26 | ns.options = opt; 27 | ns.usedChartConstructor = 'StockChart'; 28 | return this.chart; 29 | }; 30 | ns.Map = function (opt) { 31 | ns.options = opt; 32 | ns.usedChartConstructor = 'Map'; 33 | return ns.chart; 34 | }; 35 | return ns; 36 | }()); 37 | 38 | 39 | -------------------------------------------------------------------------------- /test/spec/highcharts-ng.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('Module: highchartsNg', function () { 4 | var scope, 5 | $sandbox, 6 | $compile, 7 | $timeout, 8 | options, 9 | title, 10 | destroyed, 11 | usedChartConstructor, 12 | chart; 13 | 14 | 15 | // load the controller's module 16 | beforeEach(module('highcharts-ng')); 17 | 18 | beforeEach(inject(function ($injector, $rootScope, _$compile_, _$timeout_) { 19 | title = {}; 20 | destroyed = false; 21 | scope = $rootScope; 22 | 23 | window.Highcharts.reset(); 24 | chart = window.Highcharts.chart; 25 | 26 | $compile = _$compile_; 27 | $timeout = _$timeout_; 28 | 29 | $sandbox = $('
').appendTo($('body')); 30 | })); 31 | 32 | afterEach(function () { 33 | $sandbox.remove(); 34 | scope.$destroy(); 35 | }); 36 | 37 | var templates = { 38 | 'default': { 39 | scope: {chartConfig: {}}, 40 | element: '' 41 | }, 42 | 'simpleChartConfig': { 43 | scope: { 44 | chartConfig: { 45 | chart: {type: 'bar'}, 46 | series: [{data: [1, 2]}] 47 | } 48 | }, 49 | element: '' 50 | }, 51 | 'stockChartConfig': { 52 | scope: { 53 | chartConfig: { 54 | chartType: 'stock' 55 | } 56 | }, 57 | element: '' 58 | } 59 | }; 60 | 61 | function compileDirective(template) { 62 | template = template ? templates[template] : templates['default']; 63 | angular.extend(scope, template.scope || templates['default'].scope); 64 | var $element = $(template.element).appendTo($sandbox); 65 | $element = $compile($element)(scope); 66 | scope.$digest(); 67 | return $element; 68 | } 69 | 70 | it('uses default options', function () { 71 | compileDirective(); 72 | 73 | expect(options).not.toBe({}); 74 | }); 75 | 76 | it('passes options to highcharts', function () { 77 | compileDirective('simpleChartConfig'); 78 | options = window.Highcharts.options; 79 | expect(options.chart.type).toBe('bar'); 80 | expect(options.chart.series).toBe(templates.simpleChartConfig.series); 81 | }); 82 | 83 | describe('Respects chartType', function () { 84 | beforeEach(function () { 85 | compileDirective('stockChartConfig'); 86 | }); 87 | 88 | it('uses highstocks', function () { 89 | usedChartConstructor = window.Highcharts.usedChartConstructor; 90 | expect(usedChartConstructor).toBe('StockChart'); 91 | }); 92 | }); 93 | 94 | describe('when the scope is destroyed', function () { 95 | var elm; 96 | 97 | beforeEach(function () { 98 | elm = compileDirective(); 99 | scope.$destroy(); 100 | }); 101 | 102 | it('destroys the chart', function () { 103 | expect(chart.destroy).toHaveBeenCalled(); 104 | }); 105 | 106 | it('removes the element', function () { 107 | $timeout.flush(); 108 | 109 | expect($sandbox.children().length).toBe(0); 110 | }); 111 | }); 112 | }); 113 | --------------------------------------------------------------------------------