diff --git a/Gruntfile.js b/Gruntfile.js index f1291a7..133bcb0 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,42 +1,69 @@ module.exports = function(grunt) { - grunt.initConfig({ - pkg: grunt.file.readJSON('package.json'), - makeDemos: { - demos: { - options: { - mainTemplate: 'index.ejs', - out: 'demos' - } - }, - gh_pages: { - options: { - mainTemplate: 'index.ghpages.ejs', - out: './' - } - } - }, - uglify: { - src: { - options: { - banner: '/*! <%= pkg.name %> - v<%= pkg.version %>*/\n\n' - }, - files: { - 'dist/angular-fusioncharts.min.js': ['src/angular-fusioncharts.js'] - } - } + grunt.initConfig({ + pkg: grunt.file.readJSON('package.json'), + makeDemos: { + demos: { + options: { + mainTemplate: 'index.ejs', + out: 'demos' + } + }, + gh_pages: { + options: { + mainTemplate: 'index.ghpages.ejs', + out: './' + } + } + }, + uglify: { + src: { + options: { + banner: '/*! <%= pkg.name %> - v<%= pkg.version %>*/\n\n' }, - copy: { - core: { - files: [ - {src:'dist/angular-fusioncharts.min.js', dest: 'demos/js/angular-fusioncharts.min.js'}, - {src:'src/angular-fusioncharts.js', dest: 'dist/angular-fusioncharts.js'} - ] - } + files: { + 'dist/angular-fusioncharts.min.js': ['src/angular-fusioncharts.js'] + } + } + }, + copy: { + core: { + files: [ + { + src: 'dist/angular-fusioncharts.min.js', + dest: 'demos/js/angular-fusioncharts.min.js' + }, + { + src: 'src/angular-fusioncharts.js', + dest: 'dist/angular-fusioncharts.js' + } + ] + } + }, + watch: { + options: { + livereload: true + }, + taskName: { + files: ['src/*.js', 'example/*.*'], + tasks: ['default'] + } + }, + connect: { + server: { + options: { + port: 8080, + base: './', + livereload: true } - }); - grunt.loadNpmTasks('grunt-contrib-uglify'); - grunt.loadNpmTasks('grunt-contrib-copy'); - grunt.loadTasks('./grunt-tasks'); - //grunt.registerTask('default', ['makeDemos:demos', 'uglify', 'copy']); // For gh-pages branch only - grunt.registerTask('default', ['uglify', 'copy']); // For other branches + } + } + }); + grunt.loadNpmTasks('grunt-contrib-connect'); + grunt.loadNpmTasks('grunt-contrib-uglify'); + grunt.loadNpmTasks('grunt-contrib-copy'); + grunt.loadTasks('./grunt-tasks'); + grunt.loadNpmTasks('grunt-contrib-watch'); + //grunt.registerTask('default', ['makeDemos:demos', 'uglify', 'copy']); // For gh-pages branch only + grunt.registerTask('default', ['uglify', 'copy']); // For other branches + grunt.registerTask('watch-server', ['connect', 'watch']); }; diff --git a/README.md b/README.md index 347ae32..303376a 100644 --- a/README.md +++ b/README.md @@ -1,157 +1,184 @@ # angularjs-fusioncharts -Simple and effective AngularJS charts plugin for FusionCharts. +A simple and lightweight official AngularJS component for FusionCharts JavaScript charting library. angularjs-fusioncharts enables you to add JavaScript charts in your AngularJS application without any hassle. -### Details -Use this AngularJS charts plugin to add interactive charts to your web and mobile applications using just a single directive. Choose from 90+ charts & 900+ maps from FusionCharts' core [JavaScript charts](http://www.fusioncharts.com/) library. +## [Demo](https://fusioncharts.github.io/angular-fusioncharts/) - You can access all the rich charting features like events, annotations, macros, themes, image-export etc. to make your visualizations stand-out. +- Github Repo: [https://github.com/fusioncharts/angularjs-fusioncharts](https://github.com/fusioncharts/angularjs-fusioncharts) +- Documentation: [https://www.fusioncharts.com/dev/getting-started/angular/angularjs/your-first-chart-using-angularjs](https://www.fusioncharts.com/dev/getting-started/angular/angularjs/your-first-chart-using-angularjs) +- Support: [https://www.fusioncharts.com/contact-support](https://www.fusioncharts.com/contact-support) +- FusionCharts + - Official Website: [https://www.fusioncharts.com/](https://www.fusioncharts.com/) + - Official NPM Package: [https://www.npmjs.com/package/fusioncharts](https://www.npmjs.com/package/fusioncharts) +- Issues: [https://github.com/fusioncharts/angularjs-fusioncharts/issues](https://github.com/fusioncharts/angularjs-fusioncharts/issues) - ### Installation - +--- - Install fusioncharts library - ```bash - $ npm install fusioncharts --save - ``` - Alternatively you can use downloaded fusioncharts files. +## Table of Contents +- [Getting Started](#getting-started) + - [Requirements](#requirements) + - [Installation](#installation) + - [Working with chart API](#working-with-apis) + - [Working with events](#working-with-events) +- [Quick Start](#quick-start) +- [Going Beyond Charts](#going-beyond-charts) +- [Usage and Integration of FusionTime](#usage-and-integration-of-fusiontime) +- [For Contributors](#for-contributors) +- [Licensing](#licensing) - Install angular 1.x.x - ```bash - # Any angular 1.x version is compatible - $ npm install angular@1.7.2 --save - ``` - - Install angularjs-fusioncharts module - ```bash - $ npm install angularjs-fusioncharts --save - ``` - Alternatively you can use downloaded angularjs-fusioncharts wrapper. - +## Getting Started -### Demos -To learn what you can do using this Angular charts plugin, explore some [live demos](http://www.fusioncharts.com/angularjs-charts/). +### Requirements + +- **Node.js**, **NPM/Yarn** installed globally in your OS. +- You've an **AngularJS** Application. +- **FusionCharts** installed in your project, as detailed below: + +### Installation + +To install `angularjs-fusioncharts` library, run: + +```bash +$ npm install angular-fusioncharts --save +``` + +To install `fusioncharts` library: + +```bash +$ npm install fusioncharts --save +``` + +## Quick Start -### Usage #### Step 1: Include angular-fusioncharts.js and fusioncharts + In your index.html + ```xml + ``` ### Step 2: Include ng-fusioncharts in your module + In the app, include ng-fusioncharts as a dependency. If you looking for where to add the dependency, look for the call to angular.module in your code. ```javascript -angular.module("myApp", ["ng-fusioncharts"]); +angular.module('myApp', ['ng-fusioncharts']); ``` ### Step 3: Add the fusioncharts directive + In your HTML, find the section where you wish to add the chart and add a
with the fusioncharts directive. We are assuming it's inside a controller called MyController which would change based on your usage. ```xml -
-
+ + ... +
+
+
-
+ ... + ``` -### Step 4:Populate required variables in controller -In the previous code, we are binding to a scope variable myDataSource, but that hasn't been defined yet. In your controller, set the DataSource as you would for a regular FusionCharts JSON format DataSource ([see this](http://docs.fusioncharts.com/tutorial-getting-started-your-first-charts-building-your-first-chart.html) tutorial for a general introduction to this format). +### Step 4: Populate required variables in controller +In the previous code, we are binding to a scope variable myDataSource, but that hasn't been defined yet. In your controller, set the DataSource as you would for a regular FusionCharts JSON format DataSource ([see this](http://docs.fusioncharts.com/tutorial-getting-started-your-first-charts-building-your-first-chart.html) tutorial for a general introduction to this format). ```javascript -app.controller('MyController', function($scope){ +app.controller('MyController', function($scope) { $scope.dataSource = { - "chart": { - "caption": "Countries With Most Oil Reserves [2017-18]", - "subCaption": "In MMbbl = One Million barrels", - "xAxisName": "Country", - "yAxisName": "Reserves (MMbbl)", - "numberSuffix": "K", - "theme": "fusion" + chart: { + caption: 'Countries With Most Oil Reserves [2017-18]', + subCaption: 'In MMbbl = One Million barrels', + xAxisName: 'Country', + yAxisName: 'Reserves (MMbbl)', + numberSuffix: 'K', + theme: 'fusion' }, - "data": [ - { "label": "Venezuela", "value": "290" }, - { "label": "Saudi", "value": "260" }, - { "label": "Canada", "value": "180" }, - { "label": "Iran", "value": "140" }, - { "label": "Russia", "value": "115" }, - { "label": "UAE", "value": "100" }, - { "label": "US", "value": "30" }, - { "label": "China", "value": "30" } + data: [ + { label: 'Venezuela', value: '290' }, + { label: 'Saudi', value: '260' }, + { label: 'Canada', value: '180' }, + { label: 'Iran', value: '140' }, + { label: 'Russia', value: '115' }, + { label: 'UAE', value: '100' }, + { label: 'US', value: '30' }, + { label: 'China', value: '30' } ] }; - }); ``` + And your chart should display when you load the page. ### Using `require()` syntax + In script.js + ```javascript -// Require AngularJS +// Require AngularJS var angular = require('angular'); -// Require FusionCharts +// Require FusionCharts var FusionCharts = require('fusioncharts'); -// Include angularjs-fusioncharts +// Include angularjs-fusioncharts require('angularjs-fusioncharts'); -// Require Chart modules +// Require Chart modules var Charts = require('fusioncharts/fusioncharts.charts'); -// Require Fusion theme -var FusionTheme = require('fusioncharts/themes/fusioncharts.theme.fusion'); - // Initialize Charts with FusionCharts instance Charts(FusionCharts); -// Initialize FusionTheme with FusionCharts instance -FusionTheme(FusionCharts); - -var app = angular.module('myApp', [ 'ng-fusioncharts' ]); +var app = angular.module('myApp', ['ng-fusioncharts']); -app.controller('MyController', ['$scope', function($scope) { - $scope.dataSource = { - "chart": { - "caption": "Countries With Most Oil Reserves [2017-18]", - "subCaption": "In MMbbl = One Million barrels", - "xAxisName": "Country", - "yAxisName": "Reserves (MMbbl)", - "numberSuffix": "K", - "theme": "fusion" - }, - "data": [ - { "label": "Venezuela", "value": "290" }, - { "label": "Saudi", "value": "260" }, - { "label": "Canada", "value": "180" }, - { "label": "Iran", "value": "140" }, - { "label": "Russia", "value": "115" }, - { "label": "UAE", "value": "100" }, - { "label": "US", "value": "30" }, - { "label": "China", "value": "30" } - ] - }; -}]); +app.controller('MyController', [ + '$scope', + function($scope) { + $scope.dataSource = { + chart: { + caption: 'Countries With Most Oil Reserves [2017-18]', + subCaption: 'In MMbbl = One Million barrels', + xAxisName: 'Country', + yAxisName: 'Reserves (MMbbl)', + numberSuffix: 'K' + }, + data: [ + { label: 'Venezuela', value: '290' }, + { label: 'Saudi', value: '260' }, + { label: 'Canada', value: '180' }, + { label: 'Iran', value: '140' }, + { label: 'Russia', value: '115' }, + { label: 'UAE', value: '100' }, + { label: 'US', value: '30' }, + { label: 'China', value: '30' } + ] + }; + } +]); ``` -Use a bundler like `browserify` to bundle the script + +Use a bundler like `browserify` to bundle the script See the installation docs [here](http://browserify.org/) ```bash $ browserify script.js -o bundle.js ``` + In `index.html` + ```xml @@ -167,26 +194,25 @@ In `index.html` width="600" height="400" type="column2d" - datasource="{{myDataSource}}"> + datasource="{{dataSource}}">
- - ``` -Load it in browser , Chart should get displayed -### Listening to events +Load it in browser , Chart should get displayed + +## Working with Events Fusincharts events can be subscribed by attaching scope functions to event attributes. All the events attributes start with `fcevent-` -followed by the event name in lowercase +followed by the event name in lowercase Usage in template : ```xml - ``` + In the given above template, `rollover` is the scope function that needs to be defined in the controller's code. For more on this read [here](https://www.fusioncharts.com/dev/api/fusioncharts/fusioncharts-events) -``` +```js var app = angular.module('myApp', ['ng-fusioncharts']); -app.controller('MyController', function($scope){ - $scope.myDataSource = { - "chart": { - "caption": "Countries With Most Oil Reserves [2017-18]", - "subCaption": "In MMbbl = One Million barrels", - "xAxisName": "Country", - "yAxisName": "Reserves (MMbbl)", - "numberSuffix": "K", - "theme": "fusion" - }, - "data": [ - { "label": "Venezuela", "value": "290" }, - { "label": "Saudi", "value": "260" }, - { "label": "Canada", "value": "180" }, - { "label": "Iran", "value": "140" }, - { "label": "Russia", "value": "115" }, - { "label": "UAE", "value": "100" }, - { "label": "US", "value": "30" }, - { "label": "China", "value": "30" } - ] - }; +app.controller('MyController', function($scope) { + $scope.myDataSource = { + chart: { + caption: 'Countries With Most Oil Reserves [2017-18]', + subCaption: 'In MMbbl = One Million barrels', + xAxisName: 'Country', + yAxisName: 'Reserves (MMbbl)', + numberSuffix: 'K', + theme: 'fusion' + }, + data: [ + { label: 'Venezuela', value: '290' }, + { label: 'Saudi', value: '260' }, + { label: 'Canada', value: '180' }, + { label: 'Iran', value: '140' }, + { label: 'Russia', value: '115' }, + { label: 'UAE', value: '100' }, + { label: 'US', value: '30' }, + { label: 'China', value: '30' } + ] + }; - $scope.rollover = function(event, name){ - console.log(event, name); - } + $scope.rollover = function(event, data) { + console.log(event, data); + }; }); ``` Get the list of fusioncharts' [events](https://www.fusioncharts.com/dev/advanced-chart-configurations/events/classifying-events) -### Chart API +## Working with APIs -FusionCharts chart instance is made available from the ```initialized``` event. It provides the chart instance as a parameter which can be used to call FusionCharts methods. +FusionCharts chart instance is made available from the `initialized` event. It provides the chart instance as a parameter which can be used to call FusionCharts methods. -In template, we add ```initialized``` event +In template, we add `initialized` event ```xml + ... +``` + +In your `script.js` + +```js +// If you haven't imported angulajs, angularjs-fusioncharts and fusioncharts in your html file and used require() syntax instead then add the following code from START to END: + +// START +var angular = require('angular'); +var FusionCharts = require('fusioncharts'); +require('angularjs-fusioncharts'); + +// Require TimeSeries module +var TimeSeries = require('fusioncharts/fusioncharts.timeseries'); + +// Initialize Charts with FusionCharts instance +TimeSeries(FusionCharts); +var app = angular.module('myApp', ['ng-fusioncharts']); +// END + +var jsonify = res => res.json(); +var dataFetch = fetch( + 'https://raw.githubusercontent.com/fusioncharts/dev_centre_docs/fusiontime-beta-release/charts-resources/fusiontime/online-sales-single-series/data.json' +).then(jsonify); +var schemaFetch = fetch( + 'https://raw.githubusercontent.com/fusioncharts/dev_centre_docs/fusiontime-beta-release/charts-resources/fusiontime/online-sales-single-series/schema.json' +).then(jsonify); + +var app = angular.module('myApp', ['ng-fusioncharts']); + +app.controller('MyController', function($scope) { + $scope.dataSource = { + caption: { text: 'Online Sales of a SuperStore in the US' }, + data: null, + yAxis: [ + { + plot: [ + { + value: 'Sales ($)' + } + ] + } + ] + }; + + Promise.all([dataFetch, schemaFetch]).then(res => { + const data = res[0]; + const schema = res[1]; + const fusionTable = new FusionCharts.DataStore().createDataTable( + data, + schema + ); + $scope.$apply(function() { + $scope.dataSource.data = fusionTable; + }); + }); +}); +``` + +Use a bundler like `browserify` to bundle the script +See the installation docs [here](http://browserify.org/) + +```bash +$ browserify script.js -o bundle.js +``` + +Again in your `index.html` + +```xml + + + + + + + +
+
+ // When using TimeSeries pass your dataSource in "datasource-dt" attribute not in "datasource". +
+
+ + +``` + +**Important note :- If the chart's datasource has an instance of dataStore like in case of timeseries then you must use the new `datasource-dt` attribute for passing the data in html** + +Useful links for FusionTime + +- [How FusionTime works](https://www.fusioncharts.com/dev/fusiontime/getting-started/how-fusion-time-works) +- [Create your first chart](https://www.fusioncharts.com/dev/fusiontime/getting-started/create-your-first-chart-in-fusiontime) + +## For Contributors + +- Clone the repository and install dependencies + +``` +$ git clone https://github.com/fusioncharts/angularjs-fusioncharts.git +$ cd angularjs-fusioncharts +$ npm i +$ npm run dev +``` -### Documentation -To dive deeper, please view the [official documentation](http://www.fusioncharts.com/dev/using-with-javascript-libraries/angularjs/introduction.html). +## Going Beyond Charts +- Explore 20+ pre-built business specific dashboards for different industries like energy and manufacturing to business functions like sales, marketing and operations [here](https://www.fusioncharts.com/explore/dashboards). +- See [Data Stories](https://www.fusioncharts.com/explore/data-stories) built using FusionCharts’ interactive JavaScript visualizations and learn how to communicate real-world narratives through underlying data to tell compelling stories. -### Features +## Licensing - - Add a chart using just a single directive. - - Auto-updates your chart object on modifying scope. - - Angular-friendly events let you call controller functions directly from the chart. - - Offers advanced control by giving you access to full FusionCharts object. - - Has variety of ways to add a chart, from JSON URL to Scope Array Binding. - - Plenty of examples and good documentation. +The FusionCharts React component is open-source and distributed under the terms of the MIT/X11 License. However, you will need to download and include FusionCharts library in your page separately, which has a [separate license](https://www.fusioncharts.com/buy). diff --git a/dist/angular-fusioncharts.js b/dist/angular-fusioncharts.js index 65450ec..c051e8c 100644 --- a/dist/angular-fusioncharts.js +++ b/dist/angular-fusioncharts.js @@ -20,467 +20,746 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. (function() { - var fc = angular.module('ng-fusioncharts', []), + var fc = angular.module('ng-fusioncharts', []), scope = { - width: '@', - height: '@', - data: '@', - dataset: '@', - categories: '@', - chart: '@', - linkeddata: '@', - trendlines: '@', - vtrendlines: '@', - annotations: '@', - colorrange: '@', - lineset: '@', - axis: '@', - connectors: '@', - pointers: '@', - value: '@', - processes: '@', - tasks: '@', - rows: '@', - columns: '@', - map: '@', - markers: '@', - initialized:'&' + width: '@', + height: '@', + data: '@', + dataset: '@', + categories: '@', + chart: '@', + linkeddata: '@', + trendlines: '@', + vtrendlines: '@', + annotations: '@', + colorrange: '@', + lineset: '@', + axis: '@', + connectors: '@', + pointers: '@', + value: '@', + processes: '@', + tasks: '@', + rows: '@', + columns: '@', + map: '@', + markers: '@', + initialized: '&', + datasourceDt: '=datasourceDt' }, - fcEvents = ['beforelinkeditemopen','linkeditemopened','beforelinkeditemclose','linkeditemclosed','printreadystatechange','dataloadrequestcompleted','dataloaderror','dataloadcancelled','dataloadrequestcancelled','dataupdated','dataupdatecancelled','dataloadrequested','beforedataupdate','realtimeupdatecomplete','chartcleared','slicingend','slicingstart','entityrollout','entityrollover','entityclick','connectorrollover','connectorrollout','connectorclick','markerrollover','markerrollout','markerclick','pagenavigated','rotationend','rotationstart','centerlabelrollover','centerlabelrollout','centerlabelclick','centerlabelchanged','chartclick','chartmousemove','chartrollover','chartrollout','backgroundloaded','backgroundloaderror','legenditemclicked','legenditemrollover','legenditemrollout','logorollover','logorollout','logoclick','logoloaded','logoloaderror','beforeexport','exported','exportcancelled','beforeprint','printcomplete','printcancelled','datalabelclick','datalabelrollover','datalabelrollout','scrollstart','scrollend','onscroll','zoomreset','zoomedout','zoomedin','zoomed','zoommodechanged','pinned','datarestored','beforedatasubmit','datasubmiterror','datasubmitted','datasubmitcancelled','chartupdated','nodeadded','nodeupdated','nodedeleted','connectoradded','connectorupdated','connectordeleted','labeladded','labeldeleted','selectionremoved','selectionstart','selectionend','labelclick','labelrollover','labelrollout','labeldragstart','labeldragend','dataplotdragstart','dataplotdragend','processclick','processrollover','processrollout','categoryclick','categoryrollover','categoryrollout','milestoneclick','milestonerollover','milestonerollout','charttypechanged','overlaybuttonclick','loaded','rendered','drawcomplete','rendercomplete','datainvalid','dataxmlinvalid','dataloaded','nodatatodisplay','legendpointerdragstart','legendpointerdragstop','legendrangeupdated','alertcomplete','realtimeupdateerror','dataplotrollover','dataplotrollout','dataplotclick','linkclicked','beforerender','rendercancelled','beforeresize','resized','resizecancelled','beforedispose','disposed','disposecancelled','linkedchartinvoked','beforedrilldown','drilldown','beforedrillup','drillup','drilldowncancelled','drillupcancelled'], + fcEvents = [ + 'beforelinkeditemopen', + 'linkeditemopened', + 'beforelinkeditemclose', + 'linkeditemclosed', + 'printreadystatechange', + 'dataloadrequestcompleted', + 'dataloaderror', + 'dataloadcancelled', + 'dataloadrequestcancelled', + 'dataupdated', + 'dataupdatecancelled', + 'dataloadrequested', + 'beforedataupdate', + 'realtimeupdatecomplete', + 'chartcleared', + 'slicingend', + 'slicingstart', + 'entityrollout', + 'entityrollover', + 'entityclick', + 'connectorrollover', + 'connectorrollout', + 'connectorclick', + 'markerrollover', + 'markerrollout', + 'markerclick', + 'pagenavigated', + 'rotationend', + 'rotationstart', + 'centerlabelrollover', + 'centerlabelrollout', + 'centerlabelclick', + 'centerlabelchanged', + 'chartclick', + 'chartmousemove', + 'chartrollover', + 'chartrollout', + 'backgroundloaded', + 'backgroundloaderror', + 'legenditemclicked', + 'legenditemrollover', + 'legenditemrollout', + 'logorollover', + 'logorollout', + 'logoclick', + 'logoloaded', + 'logoloaderror', + 'beforeexport', + 'exported', + 'exportcancelled', + 'beforeprint', + 'printcomplete', + 'printcancelled', + 'datalabelclick', + 'datalabelrollover', + 'datalabelrollout', + 'scrollstart', + 'scrollend', + 'onscroll', + 'zoomreset', + 'zoomedout', + 'zoomedin', + 'zoomed', + 'zoommodechanged', + 'pinned', + 'datarestored', + 'beforedatasubmit', + 'datasubmiterror', + 'datasubmitted', + 'datasubmitcancelled', + 'chartupdated', + 'nodeadded', + 'nodeupdated', + 'nodedeleted', + 'connectoradded', + 'connectorupdated', + 'connectordeleted', + 'labeladded', + 'labeldeleted', + 'selectionremoved', + 'selectionstart', + 'selectionend', + 'labelclick', + 'labelrollover', + 'labelrollout', + 'labeldragstart', + 'labeldragend', + 'dataplotdragstart', + 'dataplotdragend', + 'processclick', + 'processrollover', + 'processrollout', + 'categoryclick', + 'categoryrollover', + 'categoryrollout', + 'milestoneclick', + 'milestonerollover', + 'milestonerollout', + 'charttypechanged', + 'overlaybuttonclick', + 'loaded', + 'rendered', + 'drawcomplete', + 'rendercomplete', + 'datainvalid', + 'dataxmlinvalid', + 'dataloaded', + 'nodatatodisplay', + 'legendpointerdragstart', + 'legendpointerdragstop', + 'legendrangeupdated', + 'alertcomplete', + 'realtimeupdateerror', + 'dataplotrollover', + 'dataplotrollout', + 'dataplotclick', + 'linkclicked', + 'beforerender', + 'rendercancelled', + 'beforeresize', + 'resized', + 'resizecancelled', + 'beforedispose', + 'disposed', + 'disposecancelled', + 'linkedchartinvoked', + 'beforedrilldown', + 'drilldown', + 'beforedrillup', + 'drillup', + 'drilldowncancelled', + 'drillupcancelled' + ], currIndex, eventName, eventsLen = fcEvents.length; - for (currIndex = 0; currIndex < eventsLen; currIndex++){ - eventName = 'fcevent' + fcEvents[currIndex][0].toUpperCase() + fcEvents[currIndex].slice(1); - scope[eventName] = '&'; - } + for (currIndex = 0; currIndex < eventsLen; currIndex++) { + eventName = + 'fcevent' + + fcEvents[currIndex][0].toUpperCase() + + fcEvents[currIndex].slice(1); + scope[eventName] = '&'; + } + fc.directive('fusioncharts', [ + '$http', + function($http) { + return { + scope: scope, + link: function(scope, element, attrs) { + function updateData(key, data) { + scope.datasourceDt.key = data; + chart.setJSONData(scope.datasourceDt); + } - fc.directive('fusioncharts', ['$http', function($http) { - return { - scope: scope, - link: function(scope, element, attrs) { - var observeConf = { - // non-data componenet observers - NDCObserver: { - 'width': { - ifExist: false, - observer: function(newVal) { - if (newVal && chartConfigObject.width != newVal) { - chartConfigObject.width = newVal; - chart.resizeTo(scope.width, scope.height); - } - } - }, - 'height': { - ifExist: false, - observer: function(newVal) { - if (newVal && chartConfigObject.height != newVal) { - chartConfigObject.height = newVal; - chart.resizeTo(scope.width, scope.height); - } - } - }, + function createWatchersForAttrs(datasource) { + const keys = Object.keys(datasource); + keys.forEach(function(key) { + const isDeep = key !== 'data'; + scope.$watch( + 'datasourceDt.' + key, + function(newData, oldData) { + if (newData !== oldData && isDeep) updateData(key, newData); + }, + isDeep + ); + }); + } - 'datasource': { - ifExist: true, - observer: function(newVal) { - if (dataStringStore.dataSource != newVal) { - dataStringStore.dataSource = newVal; - if (chartConfigObject.dataFormat === 'json') { - chartConfigObject.dataSource = JSON.parse(newVal); - setChartData(); - } else { - chartConfigObject.dataSource = newVal; - if (chartConfigObject.dataFormat === 'xml') { - chart.setXMLData(newVal); - } else if (chartConfigObject.dataFormat === 'jsonurl') { - chart.setJSONUrl(newVal); - } else if (chartConfigObject.dataFormat === 'xmlurl') { - chart.setXMLUrl(newVal); - } - } - } - } - }, - 'type': { - ifExist: false, - observer: function(newVal) { - if (newVal && chartConfigObject.type != newVal) { - chartConfigObject.type = newVal; - // createFCChart(); - chart.chartType(newVal); - } - } - }, - 'config': { - ifExist: false, - observer: function(newVal) { - var configObj, - attr, - doReRender = false; - if (newVal) { - configObj = JSON.parse(newVal); - for (attr in configObj) { - // detect the value change - if (chartConfigObject[attr] != configObj[attr]) { - doReRender = true; - chartConfigObject[attr] = configObj[attr]; - } - } - if (doReRender) { - createFCChart(); - } - } - } - } - }, - // data componenet observers - DCObserver: { - 'chart': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.chart != newVal) { - dataStringStore.chart = newVal; - chartConfigObject.dataSource.chart = JSON.parse(newVal); - setChartData(); - } - } - }, - 'data': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.data != newVal) { - dataStringStore.data = newVal; - chartConfigObject.dataSource.data = JSON.parse(newVal); - setChartData(); - } - } - }, - 'categories': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.categories != newVal) { - dataStringStore.categories = newVal; - chartConfigObject.dataSource.categories = JSON.parse(newVal); - setChartData(); - } - } - }, - 'dataset': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.dataset != newVal) { - dataStringStore.dataset = newVal; - chartConfigObject.dataSource.dataset = JSON.parse(newVal); - setChartData(); - } - } - }, - 'linkeddata': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.linkeddata != newVal) { - dataStringStore.linkeddata = newVal; - chartConfigObject.dataSource.linkeddata = JSON.parse(newVal); - setChartData(); - } - } - }, - 'trendlines': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.trendlines != newVal) { - dataStringStore.trendlines = newVal; - chartConfigObject.dataSource.trendlines = JSON.parse(newVal); - setChartData(); - } - } - }, - 'vtrendlines': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.vtrendlines != newVal) { - dataStringStore.vtrendlines = newVal; - chartConfigObject.dataSource.vtrendlines = JSON.parse(newVal); - setChartData(); - } - } - }, - 'annotations': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.annotations != newVal) { - dataStringStore.annotations = newVal; - chartConfigObject.dataSource.annotations = JSON.parse(newVal); - setChartData(); - } - } - }, - 'colorrange': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.colorrange != newVal) { - dataStringStore.colorrange = newVal; - chartConfigObject.dataSource.colorrange = JSON.parse(newVal); - setChartData(); - } - } - }, - 'lineset': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.lineset != newVal) { - dataStringStore.lineset = newVal; - chartConfigObject.dataSource.lineset = JSON.parse(newVal); - setChartData(); - } - } - }, - 'axis': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.axis != newVal) { - dataStringStore.axis = newVal; - chartConfigObject.dataSource.axis = JSON.parse(newVal); - setChartData(); - } - } - }, - 'connectors': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.connectors != newVal) { - dataStringStore.connectors = newVal; - chartConfigObject.dataSource.connectors = JSON.parse(newVal); - setChartData(); - } - } - }, - 'pointers': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.pointers != newVal) { - dataStringStore.pointers = newVal; - chartConfigObject.dataSource.pointers = JSON.parse(newVal); - setChartData(); - } - } - }, - 'value': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.value != newVal) { - dataStringStore.value = newVal; - chartConfigObject.dataSource.value = JSON.parse(newVal); - setChartData(); - } - } - }, - 'processes': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.processes != newVal) { - dataStringStore.processes = newVal; - chartConfigObject.dataSource.processes = JSON.parse(newVal); - setChartData(); - } - } - }, - 'tasks': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.tasks != newVal) { - dataStringStore.tasks = newVal; - chartConfigObject.dataSource.tasks = JSON.parse(newVal); - setChartData(); - } - } - }, - 'rows': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.rows != newVal) { - dataStringStore.rows = newVal; - chartConfigObject.dataSource.rows = JSON.parse(newVal); - setChartData(); - } - } - }, - 'columns': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.columns != newVal) { - dataStringStore.columns = newVal; - chartConfigObject.dataSource.columns = JSON.parse(newVal); - setChartData(); - } - } - }, - 'map': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.map != newVal) { - dataStringStore.map = newVal; - chartConfigObject.dataSource.map = JSON.parse(newVal); - setChartData(); - } - }, - }, - 'markers': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.markers != newVal) { - dataStringStore.markers = newVal; - chartConfigObject.dataSource.markers = JSON.parse(newVal); - setChartData(); - } - } - }, - } - }, - eventsObj = {}, - attribs = Object.keys(attrs), - chart = null, - events = { - '*': function(ev, props) { - if (eventsObj.hasOwnProperty(ev.eventType)) { - eventsObj[ev.eventType](ev, props); - } - } - }, - setDataTimer, - setChartData = function() { - // clear previous dataUpdate timer - if (setDataTimer) { - clearTimeout(setDataTimer); - } - // Update the data with setTimeout - // This will solve the issue of consiquitive data update within very small interval - setDataTimer = setTimeout(function() { - if (chart && chart.setJSONData) { - chart.setJSONData(chartConfigObject.dataSource); - } - }, 0); + if (scope.datasourceDt) { + scope.$watch( + 'datasourceDt.data', + function(newData, oldData) { + if (newData !== oldData) updateData(newData, 'data'); + }, + false + ); + createWatchersForAttrs(scope.datasourceDt); + } - // chart.setJSONData(chartConfigObject.dataSource); - }, - createFCChart = function() { - // dispose if previous chart exists - if (chart && chart.dispose) { - chart.dispose(); - } - chart = new FusionCharts(chartConfigObject); - scope.initialized && scope.initialized({ chart: chart }); - for(currIndex = 0; currIndex < eventsLen ; currIndex++){ - eventName = 'fcevent' + fcEvents[currIndex][0].toUpperCase() + fcEvents[currIndex].slice(1); - // assign all events on chart instance - (function(eventName){ - chart.addEventListener(fcEvents[currIndex], function(event, args){ - scope[eventName] && scope[eventName]({ event:event, args: args }); - }); - })(eventName); + var observeConf = { + // non-data componenet observers + NDCObserver: { + width: { + ifExist: false, + observer: function(newVal) { + if (newVal && chartConfigObject.width != newVal) { + chartConfigObject.width = newVal; + chart.resizeTo(scope.width, scope.height); + } + } + }, + height: { + ifExist: false, + observer: function(newVal) { + if (newVal && chartConfigObject.height != newVal) { + chartConfigObject.height = newVal; + chart.resizeTo(scope.width, scope.height); + } + } + }, + datasource: { + ifExist: true, + observer: function(newVal) { + if (dataStringStore.dataSource != newVal) { + dataStringStore.dataSource = newVal; + if (chartConfigObject.dataFormat === 'json') { + chartConfigObject.dataSource = JSON.parse(newVal); + setChartData(); + } else { + chartConfigObject.dataSource = newVal; + if (chartConfigObject.dataFormat === 'xml') { + chart.setXMLData(newVal); + } else if (chartConfigObject.dataFormat === 'jsonurl') { + chart.setJSONUrl(newVal); + } else if (chartConfigObject.dataFormat === 'xmlurl') { + chart.setXMLUrl(newVal); } - /* @todo validate the ready function whether it can be replaced in a better way */ - angular.element(document).ready(function(){ - element.ready(function(){ - // Render the chart only when angular is done compiling the element and DOM. - chart = chart.render(); - scope[attrs.chartobject] = chart; - }); - }); - }, - dataStringStore = {}, - i, - attr, - _eobj, - key, - observableAttr, - chartConfigObject, - configObj, - dataComponent, - eventScopeArr, - l; - - if (attrs.events) { - eventScopeArr = attrs.events.split("."); - l = eventScopeArr.length; - _eobj = scope.$parent; - for (i = 0; i < l; i += 1){ - _eobj = _eobj && _eobj[eventScopeArr[i]]; + } + } + } + }, + type: { + ifExist: false, + observer: function(newVal) { + if (newVal && chartConfigObject.type != newVal) { + chartConfigObject.type = newVal; + // createFCChart(); + chart.chartType(newVal); } - if (_eobj) { - for (key in _eobj) { - if (_eobj.hasOwnProperty(key)) { - eventsObj[key.toLowerCase()] = _eobj[key]; - } + } + }, + config: { + ifExist: false, + observer: function(newVal) { + var configObj, + attr, + doReRender = false; + if (newVal) { + configObj = JSON.parse(newVal); + for (attr in configObj) { + // detect the value change + if (chartConfigObject[attr] != configObj[attr]) { + doReRender = true; + chartConfigObject[attr] = configObj[attr]; } + } + if (doReRender) { + createFCChart(); + } } + } } - for (i = 0; i < attribs.length; i++) { - attr = attribs[i]; - if (attr.match(/^on/i)) { - key = attr.slice(2).toLowerCase(); - eventsObj[key] = scope.$parent[attrs[attr]]; + }, + // data componenet observers + DCObserver: { + chart: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.chart != newVal + ) { + dataStringStore.chart = newVal; + chartConfigObject.dataSource.chart = JSON.parse(newVal); + setChartData(); + } + } + }, + data: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.data != newVal + ) { + dataStringStore.data = newVal; + chartConfigObject.dataSource.data = JSON.parse(newVal); + setChartData(); + } + } + }, + categories: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.categories != newVal + ) { + dataStringStore.categories = newVal; + chartConfigObject.dataSource.categories = JSON.parse( + newVal + ); + setChartData(); + } + } + }, + dataset: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.dataset != newVal + ) { + dataStringStore.dataset = newVal; + chartConfigObject.dataSource.dataset = JSON.parse(newVal); + setChartData(); + } + } + }, + linkeddata: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.linkeddata != newVal + ) { + dataStringStore.linkeddata = newVal; + chartConfigObject.dataSource.linkeddata = JSON.parse( + newVal + ); + setChartData(); + } + } + }, + trendlines: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.trendlines != newVal + ) { + dataStringStore.trendlines = newVal; + chartConfigObject.dataSource.trendlines = JSON.parse( + newVal + ); + setChartData(); + } + } + }, + vtrendlines: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.vtrendlines != newVal + ) { + dataStringStore.vtrendlines = newVal; + chartConfigObject.dataSource.vtrendlines = JSON.parse( + newVal + ); + setChartData(); + } + } + }, + annotations: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.annotations != newVal + ) { + dataStringStore.annotations = newVal; + chartConfigObject.dataSource.annotations = JSON.parse( + newVal + ); + setChartData(); + } + } + }, + colorrange: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.colorrange != newVal + ) { + dataStringStore.colorrange = newVal; + chartConfigObject.dataSource.colorrange = JSON.parse( + newVal + ); + setChartData(); + } + } + }, + lineset: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.lineset != newVal + ) { + dataStringStore.lineset = newVal; + chartConfigObject.dataSource.lineset = JSON.parse(newVal); + setChartData(); + } + } + }, + axis: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.axis != newVal + ) { + dataStringStore.axis = newVal; + chartConfigObject.dataSource.axis = JSON.parse(newVal); + setChartData(); + } + } + }, + connectors: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.connectors != newVal + ) { + dataStringStore.connectors = newVal; + chartConfigObject.dataSource.connectors = JSON.parse( + newVal + ); + setChartData(); + } + } + }, + pointers: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.pointers != newVal + ) { + dataStringStore.pointers = newVal; + chartConfigObject.dataSource.pointers = JSON.parse( + newVal + ); + setChartData(); + } + } + }, + value: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.value != newVal + ) { + dataStringStore.value = newVal; + chartConfigObject.dataSource.value = JSON.parse(newVal); + setChartData(); + } + } + }, + processes: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.processes != newVal + ) { + dataStringStore.processes = newVal; + chartConfigObject.dataSource.processes = JSON.parse( + newVal + ); + setChartData(); + } + } + }, + tasks: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.tasks != newVal + ) { + dataStringStore.tasks = newVal; + chartConfigObject.dataSource.tasks = JSON.parse(newVal); + setChartData(); } + } + }, + rows: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.rows != newVal + ) { + dataStringStore.rows = newVal; + chartConfigObject.dataSource.rows = JSON.parse(newVal); + setChartData(); + } + } + }, + columns: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.columns != newVal + ) { + dataStringStore.columns = newVal; + chartConfigObject.dataSource.columns = JSON.parse(newVal); + setChartData(); + } + } + }, + map: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.map != newVal + ) { + dataStringStore.map = newVal; + chartConfigObject.dataSource.map = JSON.parse(newVal); + setChartData(); + } + } + }, + markers: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.markers != newVal + ) { + dataStringStore.markers = newVal; + chartConfigObject.dataSource.markers = JSON.parse(newVal); + setChartData(); + } + } + } + } + }, + eventsObj = {}, + attribs = Object.keys(attrs), + chart = null, + events = { + '*': function(ev, props) { + if (eventsObj.hasOwnProperty(ev.eventType)) { + eventsObj[ev.eventType](ev, props); + } + } + }, + setDataTimer, + setChartData = function() { + // clear previous dataUpdate timer + if (setDataTimer) { + clearTimeout(setDataTimer); + } + // Update the data with setTimeout + // This will solve the issue of consiquitive data update within very small interval + setDataTimer = setTimeout(function() { + if (chart && chart.setJSONData) { + chart.setJSONData(chartConfigObject.dataSource); } + }, 0); + // chart.setJSONData(chartConfigObject.dataSource); + }, + createFCChart = function() { + // dispose if previous chart exists + if (chart && chart.dispose) { + chart.dispose(); + } + chart = new FusionCharts(chartConfigObject); + scope.initialized && scope.initialized({ chart: chart }); + for (currIndex = 0; currIndex < eventsLen; currIndex++) { + eventName = + 'fcevent' + + fcEvents[currIndex][0].toUpperCase() + + fcEvents[currIndex].slice(1); + // assign all events on chart instance + (function(eventName) { + chart.addEventListener(fcEvents[currIndex], function( + event, + args + ) { + scope[eventName] && + scope[eventName]({ event: event, args: args }); + }); + })(eventName); + } + /* @todo validate the ready function whether it can be replaced in a better way */ + angular.element(document).ready(function() { + element.ready(function() { + // Render the chart only when angular is done compiling the element and DOM. + chart = chart.render(); + scope[attrs.chartobject] = chart; + }); + }); + }, + dataStringStore = {}, + i, + attr, + _eobj, + key, + observableAttr, + chartConfigObject, + configObj, + dataComponent, + eventScopeArr, + l; - chartConfigObject = { - type: attrs.type, - width: attrs.width, - height: attrs.height, - renderAt: element[0], - id: attrs.chartid, - dataFormat: attrs.dataformat || 'json', - dataSource: {}, - events: events - }; + if (attrs.events) { + eventScopeArr = attrs.events.split('.'); + l = eventScopeArr.length; + _eobj = scope.$parent; + for (i = 0; i < l; i += 1) { + _eobj = _eobj && _eobj[eventScopeArr[i]]; + } + if (_eobj) { + for (key in _eobj) { + if (_eobj.hasOwnProperty(key)) { + eventsObj[key.toLowerCase()] = _eobj[key]; + } + } + } + } + for (i = 0; i < attribs.length; i++) { + attr = attribs[i]; + if (attr.match(/^on/i)) { + key = attr.slice(2).toLowerCase(); + eventsObj[key] = scope.$parent[attrs[attr]]; + } + } + chartConfigObject = { + type: attrs.type, + width: attrs.width, + height: attrs.height, + renderAt: element[0], + id: attrs.chartid, + dataFormat: attrs.dataformat || 'json', + dataSource: {}, + events: events + }; - for (observableAttr in observeConf.NDCObserver) { - attrConfig = observeConf.NDCObserver[observableAttr]; - if (attrConfig.ifExist === false || attrs[observableAttr]) { - attrs.$observe(observableAttr, attrConfig.observer); - } - } + for (observableAttr in observeConf.NDCObserver) { + attrConfig = observeConf.NDCObserver[observableAttr]; + if (attrConfig.ifExist === false || attrs[observableAttr]) { + attrs.$observe(observableAttr, attrConfig.observer); + } + } - if (attrs.datasource) { - chartConfigObject.dataSource = (chartConfigObject.dataFormat === 'json') ? JSON.parse(attrs.datasource) : attrs.datasource; - dataStringStore.dataSource = attrs.datasource; - } + if (attrs.datasource) { + chartConfigObject.dataSource = + chartConfigObject.dataFormat === 'json' + ? JSON.parse(attrs.datasource) + : attrs.datasource; + dataStringStore.dataSource = attrs.datasource; + } - for (observableAttr in observeConf.DCObserver) { - attrConfig = observeConf.DCObserver[observableAttr]; - dataComponent = attrs[observableAttr]; - if (dataComponent) { - attrs.$observe(observableAttr, attrConfig.observer); - dataStringStore[observableAttr] = dataComponent; - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource === "object") { - chartConfigObject.dataSource[observableAttr] = JSON.parse(dataComponent); - } - } else if (attrConfig.ifExist === false) { - attrs.$observe(observableAttr, attrConfig.observer); - } - } + for (observableAttr in observeConf.DCObserver) { + attrConfig = observeConf.DCObserver[observableAttr]; + dataComponent = attrs[observableAttr]; + if (dataComponent) { + attrs.$observe(observableAttr, attrConfig.observer); + dataStringStore[observableAttr] = dataComponent; + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource === 'object' + ) { + chartConfigObject.dataSource[observableAttr] = JSON.parse( + dataComponent + ); + } + } else if (attrConfig.ifExist === false) { + attrs.$observe(observableAttr, attrConfig.observer); + } + } - // add configurations from config - if (attrs.config) { - configObj = JSON.parse(attrs.config); - for (attr in configObj) { - chartConfigObject[attr] = configObj[attr]; - } - } + // add configurations from config + if (attrs.config) { + configObj = JSON.parse(attrs.config); + for (attr in configObj) { + chartConfigObject[attr] = configObj[attr]; + } + } - createFCChart(); + createFCChart(); - scope.$on('$destroy', function () { - // on destroy free used resources to avoid memory leaks - if (chart && chart.dispose) { - chart.dispose(); - } - }); + scope.$on('$destroy', function() { + // on destroy free used resources to avoid memory leaks + if (chart && chart.dispose) { + chart.dispose(); } - }; - }]); -}()); + }); + } + }; + } + ]); +})(); diff --git a/dist/angular-fusioncharts.min.js b/dist/angular-fusioncharts.min.js index fd16208..ece3036 100644 --- a/dist/angular-fusioncharts.min.js +++ b/dist/angular-fusioncharts.min.js @@ -1,3 +1,3 @@ -/*! angularjs-fusioncharts - v4.0.2*/ +/*! angularjs-fusioncharts - v4.0.3*/ -!function(){var a,b,c=angular.module("ng-fusioncharts",[]),d={width:"@",height:"@",data:"@",dataset:"@",categories:"@",chart:"@",linkeddata:"@",trendlines:"@",vtrendlines:"@",annotations:"@",colorrange:"@",lineset:"@",axis:"@",connectors:"@",pointers:"@",value:"@",processes:"@",tasks:"@",rows:"@",columns:"@",map:"@",markers:"@",initialized:"&"},e=["beforelinkeditemopen","linkeditemopened","beforelinkeditemclose","linkeditemclosed","printreadystatechange","dataloadrequestcompleted","dataloaderror","dataloadcancelled","dataloadrequestcancelled","dataupdated","dataupdatecancelled","dataloadrequested","beforedataupdate","realtimeupdatecomplete","chartcleared","slicingend","slicingstart","entityrollout","entityrollover","entityclick","connectorrollover","connectorrollout","connectorclick","markerrollover","markerrollout","markerclick","pagenavigated","rotationend","rotationstart","centerlabelrollover","centerlabelrollout","centerlabelclick","centerlabelchanged","chartclick","chartmousemove","chartrollover","chartrollout","backgroundloaded","backgroundloaderror","legenditemclicked","legenditemrollover","legenditemrollout","logorollover","logorollout","logoclick","logoloaded","logoloaderror","beforeexport","exported","exportcancelled","beforeprint","printcomplete","printcancelled","datalabelclick","datalabelrollover","datalabelrollout","scrollstart","scrollend","onscroll","zoomreset","zoomedout","zoomedin","zoomed","zoommodechanged","pinned","datarestored","beforedatasubmit","datasubmiterror","datasubmitted","datasubmitcancelled","chartupdated","nodeadded","nodeupdated","nodedeleted","connectoradded","connectorupdated","connectordeleted","labeladded","labeldeleted","selectionremoved","selectionstart","selectionend","labelclick","labelrollover","labelrollout","labeldragstart","labeldragend","dataplotdragstart","dataplotdragend","processclick","processrollover","processrollout","categoryclick","categoryrollover","categoryrollout","milestoneclick","milestonerollover","milestonerollout","charttypechanged","overlaybuttonclick","loaded","rendered","drawcomplete","rendercomplete","datainvalid","dataxmlinvalid","dataloaded","nodatatodisplay","legendpointerdragstart","legendpointerdragstop","legendrangeupdated","alertcomplete","realtimeupdateerror","dataplotrollover","dataplotrollout","dataplotclick","linkclicked","beforerender","rendercancelled","beforeresize","resized","resizecancelled","beforedispose","disposed","disposecancelled","linkedchartinvoked","beforedrilldown","drilldown","beforedrillup","drillup","drilldowncancelled","drillupcancelled"],f=e.length;for(a=0;a + + + + + + Document + + + + + + + + +
+
+
+ +
+ + diff --git a/example/index.js b/example/index.js new file mode 100644 index 0000000..da6b591 --- /dev/null +++ b/example/index.js @@ -0,0 +1,65 @@ +var jsonify = res => res.json(); +var dataFetch = fetch( + 'https://raw.githubusercontent.com/fusioncharts/dev_centre_docs/fusiontime-beta-release/charts-resources/fusiontime/online-sales-single-series/data.json' +).then(jsonify); +var schemaFetch = fetch( + 'https://raw.githubusercontent.com/fusioncharts/dev_centre_docs/fusiontime-beta-release/charts-resources/fusiontime/online-sales-single-series/schema.json' +).then(jsonify); + +var app = angular.module('myApp', ['ng-fusioncharts']); + +app.controller('MyController', function($scope) { + $scope.timeSeriesDS = { + caption: { text: 'Online Sales of a SuperStore in the US' }, + data: null, + yAxis: [ + { + plot: [ + { + value: 'Sales ($)' + } + ] + } + ] + }; + + $scope.columnDS = { + chart: { + caption: 'Countries With Most Oil Reserves [2017-18]', + subCaption: 'In MMbbl = One Million barrels', + xAxisName: 'Country', + yAxisName: 'Reserves (MMbbl)', + numberSuffix: 'K', + theme: 'fusion' + }, + data: [ + { label: 'Venezuela', value: '290' }, + { label: 'Saudi', value: '260' }, + { label: 'Canada', value: '180' }, + { label: 'Iran', value: '140' }, + { label: 'Russia', value: '115' }, + { label: 'UAE', value: '100' }, + { label: 'US', value: '30' }, + { label: 'China', value: '30' } + ] + }; + + $scope.update = function() { + $scope.timeSeriesDS.caption.text = 'Something Else'; + $scope.columnDS.chart.caption = 'Something Else'; + }; + + Promise.all([dataFetch, schemaFetch]).then(res => { + const data = res[0]; + const schema = res[1]; + const fusionTable = new FusionCharts.DataStore().createDataTable( + data, + schema + ); + $scope.$apply(function() { + $scope.timeSeriesDS.data = fusionTable; + }); + }); +}); + +// getData(); diff --git a/package.json b/package.json index 7d52775..6c9822b 100644 --- a/package.json +++ b/package.json @@ -12,12 +12,20 @@ "bugs": { "url": "https://github.com/fusioncharts/angularjs-fusioncharts/issues" }, + "scripts": { + "dev": "npx grunt watch-server", + "build": "npx grunt" + }, "homepage": "https://www.fusioncharts.com/angularjs-charts/", "dependencies": {}, "devDependencies": { + "angular": "^1.7.2", "ejs": "^1.0.0", + "fusioncharts": "^3.13.3-sr.1", "grunt": "^0.4.5", + "grunt-contrib-connect": "^2.0.0", "grunt-contrib-copy": "^0.7.0", - "grunt-contrib-uglify": "^0.6.0" + "grunt-contrib-uglify": "^0.6.0", + "grunt-contrib-watch": "^1.1.0" } } diff --git a/src/angular-fusioncharts.js b/src/angular-fusioncharts.js index 65450ec..c051e8c 100644 --- a/src/angular-fusioncharts.js +++ b/src/angular-fusioncharts.js @@ -20,467 +20,746 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. (function() { - var fc = angular.module('ng-fusioncharts', []), + var fc = angular.module('ng-fusioncharts', []), scope = { - width: '@', - height: '@', - data: '@', - dataset: '@', - categories: '@', - chart: '@', - linkeddata: '@', - trendlines: '@', - vtrendlines: '@', - annotations: '@', - colorrange: '@', - lineset: '@', - axis: '@', - connectors: '@', - pointers: '@', - value: '@', - processes: '@', - tasks: '@', - rows: '@', - columns: '@', - map: '@', - markers: '@', - initialized:'&' + width: '@', + height: '@', + data: '@', + dataset: '@', + categories: '@', + chart: '@', + linkeddata: '@', + trendlines: '@', + vtrendlines: '@', + annotations: '@', + colorrange: '@', + lineset: '@', + axis: '@', + connectors: '@', + pointers: '@', + value: '@', + processes: '@', + tasks: '@', + rows: '@', + columns: '@', + map: '@', + markers: '@', + initialized: '&', + datasourceDt: '=datasourceDt' }, - fcEvents = ['beforelinkeditemopen','linkeditemopened','beforelinkeditemclose','linkeditemclosed','printreadystatechange','dataloadrequestcompleted','dataloaderror','dataloadcancelled','dataloadrequestcancelled','dataupdated','dataupdatecancelled','dataloadrequested','beforedataupdate','realtimeupdatecomplete','chartcleared','slicingend','slicingstart','entityrollout','entityrollover','entityclick','connectorrollover','connectorrollout','connectorclick','markerrollover','markerrollout','markerclick','pagenavigated','rotationend','rotationstart','centerlabelrollover','centerlabelrollout','centerlabelclick','centerlabelchanged','chartclick','chartmousemove','chartrollover','chartrollout','backgroundloaded','backgroundloaderror','legenditemclicked','legenditemrollover','legenditemrollout','logorollover','logorollout','logoclick','logoloaded','logoloaderror','beforeexport','exported','exportcancelled','beforeprint','printcomplete','printcancelled','datalabelclick','datalabelrollover','datalabelrollout','scrollstart','scrollend','onscroll','zoomreset','zoomedout','zoomedin','zoomed','zoommodechanged','pinned','datarestored','beforedatasubmit','datasubmiterror','datasubmitted','datasubmitcancelled','chartupdated','nodeadded','nodeupdated','nodedeleted','connectoradded','connectorupdated','connectordeleted','labeladded','labeldeleted','selectionremoved','selectionstart','selectionend','labelclick','labelrollover','labelrollout','labeldragstart','labeldragend','dataplotdragstart','dataplotdragend','processclick','processrollover','processrollout','categoryclick','categoryrollover','categoryrollout','milestoneclick','milestonerollover','milestonerollout','charttypechanged','overlaybuttonclick','loaded','rendered','drawcomplete','rendercomplete','datainvalid','dataxmlinvalid','dataloaded','nodatatodisplay','legendpointerdragstart','legendpointerdragstop','legendrangeupdated','alertcomplete','realtimeupdateerror','dataplotrollover','dataplotrollout','dataplotclick','linkclicked','beforerender','rendercancelled','beforeresize','resized','resizecancelled','beforedispose','disposed','disposecancelled','linkedchartinvoked','beforedrilldown','drilldown','beforedrillup','drillup','drilldowncancelled','drillupcancelled'], + fcEvents = [ + 'beforelinkeditemopen', + 'linkeditemopened', + 'beforelinkeditemclose', + 'linkeditemclosed', + 'printreadystatechange', + 'dataloadrequestcompleted', + 'dataloaderror', + 'dataloadcancelled', + 'dataloadrequestcancelled', + 'dataupdated', + 'dataupdatecancelled', + 'dataloadrequested', + 'beforedataupdate', + 'realtimeupdatecomplete', + 'chartcleared', + 'slicingend', + 'slicingstart', + 'entityrollout', + 'entityrollover', + 'entityclick', + 'connectorrollover', + 'connectorrollout', + 'connectorclick', + 'markerrollover', + 'markerrollout', + 'markerclick', + 'pagenavigated', + 'rotationend', + 'rotationstart', + 'centerlabelrollover', + 'centerlabelrollout', + 'centerlabelclick', + 'centerlabelchanged', + 'chartclick', + 'chartmousemove', + 'chartrollover', + 'chartrollout', + 'backgroundloaded', + 'backgroundloaderror', + 'legenditemclicked', + 'legenditemrollover', + 'legenditemrollout', + 'logorollover', + 'logorollout', + 'logoclick', + 'logoloaded', + 'logoloaderror', + 'beforeexport', + 'exported', + 'exportcancelled', + 'beforeprint', + 'printcomplete', + 'printcancelled', + 'datalabelclick', + 'datalabelrollover', + 'datalabelrollout', + 'scrollstart', + 'scrollend', + 'onscroll', + 'zoomreset', + 'zoomedout', + 'zoomedin', + 'zoomed', + 'zoommodechanged', + 'pinned', + 'datarestored', + 'beforedatasubmit', + 'datasubmiterror', + 'datasubmitted', + 'datasubmitcancelled', + 'chartupdated', + 'nodeadded', + 'nodeupdated', + 'nodedeleted', + 'connectoradded', + 'connectorupdated', + 'connectordeleted', + 'labeladded', + 'labeldeleted', + 'selectionremoved', + 'selectionstart', + 'selectionend', + 'labelclick', + 'labelrollover', + 'labelrollout', + 'labeldragstart', + 'labeldragend', + 'dataplotdragstart', + 'dataplotdragend', + 'processclick', + 'processrollover', + 'processrollout', + 'categoryclick', + 'categoryrollover', + 'categoryrollout', + 'milestoneclick', + 'milestonerollover', + 'milestonerollout', + 'charttypechanged', + 'overlaybuttonclick', + 'loaded', + 'rendered', + 'drawcomplete', + 'rendercomplete', + 'datainvalid', + 'dataxmlinvalid', + 'dataloaded', + 'nodatatodisplay', + 'legendpointerdragstart', + 'legendpointerdragstop', + 'legendrangeupdated', + 'alertcomplete', + 'realtimeupdateerror', + 'dataplotrollover', + 'dataplotrollout', + 'dataplotclick', + 'linkclicked', + 'beforerender', + 'rendercancelled', + 'beforeresize', + 'resized', + 'resizecancelled', + 'beforedispose', + 'disposed', + 'disposecancelled', + 'linkedchartinvoked', + 'beforedrilldown', + 'drilldown', + 'beforedrillup', + 'drillup', + 'drilldowncancelled', + 'drillupcancelled' + ], currIndex, eventName, eventsLen = fcEvents.length; - for (currIndex = 0; currIndex < eventsLen; currIndex++){ - eventName = 'fcevent' + fcEvents[currIndex][0].toUpperCase() + fcEvents[currIndex].slice(1); - scope[eventName] = '&'; - } + for (currIndex = 0; currIndex < eventsLen; currIndex++) { + eventName = + 'fcevent' + + fcEvents[currIndex][0].toUpperCase() + + fcEvents[currIndex].slice(1); + scope[eventName] = '&'; + } + fc.directive('fusioncharts', [ + '$http', + function($http) { + return { + scope: scope, + link: function(scope, element, attrs) { + function updateData(key, data) { + scope.datasourceDt.key = data; + chart.setJSONData(scope.datasourceDt); + } - fc.directive('fusioncharts', ['$http', function($http) { - return { - scope: scope, - link: function(scope, element, attrs) { - var observeConf = { - // non-data componenet observers - NDCObserver: { - 'width': { - ifExist: false, - observer: function(newVal) { - if (newVal && chartConfigObject.width != newVal) { - chartConfigObject.width = newVal; - chart.resizeTo(scope.width, scope.height); - } - } - }, - 'height': { - ifExist: false, - observer: function(newVal) { - if (newVal && chartConfigObject.height != newVal) { - chartConfigObject.height = newVal; - chart.resizeTo(scope.width, scope.height); - } - } - }, + function createWatchersForAttrs(datasource) { + const keys = Object.keys(datasource); + keys.forEach(function(key) { + const isDeep = key !== 'data'; + scope.$watch( + 'datasourceDt.' + key, + function(newData, oldData) { + if (newData !== oldData && isDeep) updateData(key, newData); + }, + isDeep + ); + }); + } - 'datasource': { - ifExist: true, - observer: function(newVal) { - if (dataStringStore.dataSource != newVal) { - dataStringStore.dataSource = newVal; - if (chartConfigObject.dataFormat === 'json') { - chartConfigObject.dataSource = JSON.parse(newVal); - setChartData(); - } else { - chartConfigObject.dataSource = newVal; - if (chartConfigObject.dataFormat === 'xml') { - chart.setXMLData(newVal); - } else if (chartConfigObject.dataFormat === 'jsonurl') { - chart.setJSONUrl(newVal); - } else if (chartConfigObject.dataFormat === 'xmlurl') { - chart.setXMLUrl(newVal); - } - } - } - } - }, - 'type': { - ifExist: false, - observer: function(newVal) { - if (newVal && chartConfigObject.type != newVal) { - chartConfigObject.type = newVal; - // createFCChart(); - chart.chartType(newVal); - } - } - }, - 'config': { - ifExist: false, - observer: function(newVal) { - var configObj, - attr, - doReRender = false; - if (newVal) { - configObj = JSON.parse(newVal); - for (attr in configObj) { - // detect the value change - if (chartConfigObject[attr] != configObj[attr]) { - doReRender = true; - chartConfigObject[attr] = configObj[attr]; - } - } - if (doReRender) { - createFCChart(); - } - } - } - } - }, - // data componenet observers - DCObserver: { - 'chart': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.chart != newVal) { - dataStringStore.chart = newVal; - chartConfigObject.dataSource.chart = JSON.parse(newVal); - setChartData(); - } - } - }, - 'data': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.data != newVal) { - dataStringStore.data = newVal; - chartConfigObject.dataSource.data = JSON.parse(newVal); - setChartData(); - } - } - }, - 'categories': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.categories != newVal) { - dataStringStore.categories = newVal; - chartConfigObject.dataSource.categories = JSON.parse(newVal); - setChartData(); - } - } - }, - 'dataset': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.dataset != newVal) { - dataStringStore.dataset = newVal; - chartConfigObject.dataSource.dataset = JSON.parse(newVal); - setChartData(); - } - } - }, - 'linkeddata': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.linkeddata != newVal) { - dataStringStore.linkeddata = newVal; - chartConfigObject.dataSource.linkeddata = JSON.parse(newVal); - setChartData(); - } - } - }, - 'trendlines': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.trendlines != newVal) { - dataStringStore.trendlines = newVal; - chartConfigObject.dataSource.trendlines = JSON.parse(newVal); - setChartData(); - } - } - }, - 'vtrendlines': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.vtrendlines != newVal) { - dataStringStore.vtrendlines = newVal; - chartConfigObject.dataSource.vtrendlines = JSON.parse(newVal); - setChartData(); - } - } - }, - 'annotations': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.annotations != newVal) { - dataStringStore.annotations = newVal; - chartConfigObject.dataSource.annotations = JSON.parse(newVal); - setChartData(); - } - } - }, - 'colorrange': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.colorrange != newVal) { - dataStringStore.colorrange = newVal; - chartConfigObject.dataSource.colorrange = JSON.parse(newVal); - setChartData(); - } - } - }, - 'lineset': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.lineset != newVal) { - dataStringStore.lineset = newVal; - chartConfigObject.dataSource.lineset = JSON.parse(newVal); - setChartData(); - } - } - }, - 'axis': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.axis != newVal) { - dataStringStore.axis = newVal; - chartConfigObject.dataSource.axis = JSON.parse(newVal); - setChartData(); - } - } - }, - 'connectors': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.connectors != newVal) { - dataStringStore.connectors = newVal; - chartConfigObject.dataSource.connectors = JSON.parse(newVal); - setChartData(); - } - } - }, - 'pointers': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.pointers != newVal) { - dataStringStore.pointers = newVal; - chartConfigObject.dataSource.pointers = JSON.parse(newVal); - setChartData(); - } - } - }, - 'value': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.value != newVal) { - dataStringStore.value = newVal; - chartConfigObject.dataSource.value = JSON.parse(newVal); - setChartData(); - } - } - }, - 'processes': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.processes != newVal) { - dataStringStore.processes = newVal; - chartConfigObject.dataSource.processes = JSON.parse(newVal); - setChartData(); - } - } - }, - 'tasks': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.tasks != newVal) { - dataStringStore.tasks = newVal; - chartConfigObject.dataSource.tasks = JSON.parse(newVal); - setChartData(); - } - } - }, - 'rows': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.rows != newVal) { - dataStringStore.rows = newVal; - chartConfigObject.dataSource.rows = JSON.parse(newVal); - setChartData(); - } - } - }, - 'columns': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.columns != newVal) { - dataStringStore.columns = newVal; - chartConfigObject.dataSource.columns = JSON.parse(newVal); - setChartData(); - } - } - }, - 'map': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.map != newVal) { - dataStringStore.map = newVal; - chartConfigObject.dataSource.map = JSON.parse(newVal); - setChartData(); - } - }, - }, - 'markers': { - ifExist: true, - observer: function(newVal) { - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource == "object" && dataStringStore.markers != newVal) { - dataStringStore.markers = newVal; - chartConfigObject.dataSource.markers = JSON.parse(newVal); - setChartData(); - } - } - }, - } - }, - eventsObj = {}, - attribs = Object.keys(attrs), - chart = null, - events = { - '*': function(ev, props) { - if (eventsObj.hasOwnProperty(ev.eventType)) { - eventsObj[ev.eventType](ev, props); - } - } - }, - setDataTimer, - setChartData = function() { - // clear previous dataUpdate timer - if (setDataTimer) { - clearTimeout(setDataTimer); - } - // Update the data with setTimeout - // This will solve the issue of consiquitive data update within very small interval - setDataTimer = setTimeout(function() { - if (chart && chart.setJSONData) { - chart.setJSONData(chartConfigObject.dataSource); - } - }, 0); + if (scope.datasourceDt) { + scope.$watch( + 'datasourceDt.data', + function(newData, oldData) { + if (newData !== oldData) updateData(newData, 'data'); + }, + false + ); + createWatchersForAttrs(scope.datasourceDt); + } - // chart.setJSONData(chartConfigObject.dataSource); - }, - createFCChart = function() { - // dispose if previous chart exists - if (chart && chart.dispose) { - chart.dispose(); - } - chart = new FusionCharts(chartConfigObject); - scope.initialized && scope.initialized({ chart: chart }); - for(currIndex = 0; currIndex < eventsLen ; currIndex++){ - eventName = 'fcevent' + fcEvents[currIndex][0].toUpperCase() + fcEvents[currIndex].slice(1); - // assign all events on chart instance - (function(eventName){ - chart.addEventListener(fcEvents[currIndex], function(event, args){ - scope[eventName] && scope[eventName]({ event:event, args: args }); - }); - })(eventName); + var observeConf = { + // non-data componenet observers + NDCObserver: { + width: { + ifExist: false, + observer: function(newVal) { + if (newVal && chartConfigObject.width != newVal) { + chartConfigObject.width = newVal; + chart.resizeTo(scope.width, scope.height); + } + } + }, + height: { + ifExist: false, + observer: function(newVal) { + if (newVal && chartConfigObject.height != newVal) { + chartConfigObject.height = newVal; + chart.resizeTo(scope.width, scope.height); + } + } + }, + datasource: { + ifExist: true, + observer: function(newVal) { + if (dataStringStore.dataSource != newVal) { + dataStringStore.dataSource = newVal; + if (chartConfigObject.dataFormat === 'json') { + chartConfigObject.dataSource = JSON.parse(newVal); + setChartData(); + } else { + chartConfigObject.dataSource = newVal; + if (chartConfigObject.dataFormat === 'xml') { + chart.setXMLData(newVal); + } else if (chartConfigObject.dataFormat === 'jsonurl') { + chart.setJSONUrl(newVal); + } else if (chartConfigObject.dataFormat === 'xmlurl') { + chart.setXMLUrl(newVal); } - /* @todo validate the ready function whether it can be replaced in a better way */ - angular.element(document).ready(function(){ - element.ready(function(){ - // Render the chart only when angular is done compiling the element and DOM. - chart = chart.render(); - scope[attrs.chartobject] = chart; - }); - }); - }, - dataStringStore = {}, - i, - attr, - _eobj, - key, - observableAttr, - chartConfigObject, - configObj, - dataComponent, - eventScopeArr, - l; - - if (attrs.events) { - eventScopeArr = attrs.events.split("."); - l = eventScopeArr.length; - _eobj = scope.$parent; - for (i = 0; i < l; i += 1){ - _eobj = _eobj && _eobj[eventScopeArr[i]]; + } + } + } + }, + type: { + ifExist: false, + observer: function(newVal) { + if (newVal && chartConfigObject.type != newVal) { + chartConfigObject.type = newVal; + // createFCChart(); + chart.chartType(newVal); } - if (_eobj) { - for (key in _eobj) { - if (_eobj.hasOwnProperty(key)) { - eventsObj[key.toLowerCase()] = _eobj[key]; - } + } + }, + config: { + ifExist: false, + observer: function(newVal) { + var configObj, + attr, + doReRender = false; + if (newVal) { + configObj = JSON.parse(newVal); + for (attr in configObj) { + // detect the value change + if (chartConfigObject[attr] != configObj[attr]) { + doReRender = true; + chartConfigObject[attr] = configObj[attr]; } + } + if (doReRender) { + createFCChart(); + } } + } } - for (i = 0; i < attribs.length; i++) { - attr = attribs[i]; - if (attr.match(/^on/i)) { - key = attr.slice(2).toLowerCase(); - eventsObj[key] = scope.$parent[attrs[attr]]; + }, + // data componenet observers + DCObserver: { + chart: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.chart != newVal + ) { + dataStringStore.chart = newVal; + chartConfigObject.dataSource.chart = JSON.parse(newVal); + setChartData(); + } + } + }, + data: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.data != newVal + ) { + dataStringStore.data = newVal; + chartConfigObject.dataSource.data = JSON.parse(newVal); + setChartData(); + } + } + }, + categories: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.categories != newVal + ) { + dataStringStore.categories = newVal; + chartConfigObject.dataSource.categories = JSON.parse( + newVal + ); + setChartData(); + } + } + }, + dataset: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.dataset != newVal + ) { + dataStringStore.dataset = newVal; + chartConfigObject.dataSource.dataset = JSON.parse(newVal); + setChartData(); + } + } + }, + linkeddata: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.linkeddata != newVal + ) { + dataStringStore.linkeddata = newVal; + chartConfigObject.dataSource.linkeddata = JSON.parse( + newVal + ); + setChartData(); + } + } + }, + trendlines: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.trendlines != newVal + ) { + dataStringStore.trendlines = newVal; + chartConfigObject.dataSource.trendlines = JSON.parse( + newVal + ); + setChartData(); + } + } + }, + vtrendlines: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.vtrendlines != newVal + ) { + dataStringStore.vtrendlines = newVal; + chartConfigObject.dataSource.vtrendlines = JSON.parse( + newVal + ); + setChartData(); + } + } + }, + annotations: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.annotations != newVal + ) { + dataStringStore.annotations = newVal; + chartConfigObject.dataSource.annotations = JSON.parse( + newVal + ); + setChartData(); + } + } + }, + colorrange: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.colorrange != newVal + ) { + dataStringStore.colorrange = newVal; + chartConfigObject.dataSource.colorrange = JSON.parse( + newVal + ); + setChartData(); + } + } + }, + lineset: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.lineset != newVal + ) { + dataStringStore.lineset = newVal; + chartConfigObject.dataSource.lineset = JSON.parse(newVal); + setChartData(); + } + } + }, + axis: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.axis != newVal + ) { + dataStringStore.axis = newVal; + chartConfigObject.dataSource.axis = JSON.parse(newVal); + setChartData(); + } + } + }, + connectors: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.connectors != newVal + ) { + dataStringStore.connectors = newVal; + chartConfigObject.dataSource.connectors = JSON.parse( + newVal + ); + setChartData(); + } + } + }, + pointers: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.pointers != newVal + ) { + dataStringStore.pointers = newVal; + chartConfigObject.dataSource.pointers = JSON.parse( + newVal + ); + setChartData(); + } + } + }, + value: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.value != newVal + ) { + dataStringStore.value = newVal; + chartConfigObject.dataSource.value = JSON.parse(newVal); + setChartData(); + } + } + }, + processes: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.processes != newVal + ) { + dataStringStore.processes = newVal; + chartConfigObject.dataSource.processes = JSON.parse( + newVal + ); + setChartData(); + } + } + }, + tasks: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.tasks != newVal + ) { + dataStringStore.tasks = newVal; + chartConfigObject.dataSource.tasks = JSON.parse(newVal); + setChartData(); } + } + }, + rows: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.rows != newVal + ) { + dataStringStore.rows = newVal; + chartConfigObject.dataSource.rows = JSON.parse(newVal); + setChartData(); + } + } + }, + columns: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.columns != newVal + ) { + dataStringStore.columns = newVal; + chartConfigObject.dataSource.columns = JSON.parse(newVal); + setChartData(); + } + } + }, + map: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.map != newVal + ) { + dataStringStore.map = newVal; + chartConfigObject.dataSource.map = JSON.parse(newVal); + setChartData(); + } + } + }, + markers: { + ifExist: true, + observer: function(newVal) { + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource == 'object' && + dataStringStore.markers != newVal + ) { + dataStringStore.markers = newVal; + chartConfigObject.dataSource.markers = JSON.parse(newVal); + setChartData(); + } + } + } + } + }, + eventsObj = {}, + attribs = Object.keys(attrs), + chart = null, + events = { + '*': function(ev, props) { + if (eventsObj.hasOwnProperty(ev.eventType)) { + eventsObj[ev.eventType](ev, props); + } + } + }, + setDataTimer, + setChartData = function() { + // clear previous dataUpdate timer + if (setDataTimer) { + clearTimeout(setDataTimer); + } + // Update the data with setTimeout + // This will solve the issue of consiquitive data update within very small interval + setDataTimer = setTimeout(function() { + if (chart && chart.setJSONData) { + chart.setJSONData(chartConfigObject.dataSource); } + }, 0); + // chart.setJSONData(chartConfigObject.dataSource); + }, + createFCChart = function() { + // dispose if previous chart exists + if (chart && chart.dispose) { + chart.dispose(); + } + chart = new FusionCharts(chartConfigObject); + scope.initialized && scope.initialized({ chart: chart }); + for (currIndex = 0; currIndex < eventsLen; currIndex++) { + eventName = + 'fcevent' + + fcEvents[currIndex][0].toUpperCase() + + fcEvents[currIndex].slice(1); + // assign all events on chart instance + (function(eventName) { + chart.addEventListener(fcEvents[currIndex], function( + event, + args + ) { + scope[eventName] && + scope[eventName]({ event: event, args: args }); + }); + })(eventName); + } + /* @todo validate the ready function whether it can be replaced in a better way */ + angular.element(document).ready(function() { + element.ready(function() { + // Render the chart only when angular is done compiling the element and DOM. + chart = chart.render(); + scope[attrs.chartobject] = chart; + }); + }); + }, + dataStringStore = {}, + i, + attr, + _eobj, + key, + observableAttr, + chartConfigObject, + configObj, + dataComponent, + eventScopeArr, + l; - chartConfigObject = { - type: attrs.type, - width: attrs.width, - height: attrs.height, - renderAt: element[0], - id: attrs.chartid, - dataFormat: attrs.dataformat || 'json', - dataSource: {}, - events: events - }; + if (attrs.events) { + eventScopeArr = attrs.events.split('.'); + l = eventScopeArr.length; + _eobj = scope.$parent; + for (i = 0; i < l; i += 1) { + _eobj = _eobj && _eobj[eventScopeArr[i]]; + } + if (_eobj) { + for (key in _eobj) { + if (_eobj.hasOwnProperty(key)) { + eventsObj[key.toLowerCase()] = _eobj[key]; + } + } + } + } + for (i = 0; i < attribs.length; i++) { + attr = attribs[i]; + if (attr.match(/^on/i)) { + key = attr.slice(2).toLowerCase(); + eventsObj[key] = scope.$parent[attrs[attr]]; + } + } + chartConfigObject = { + type: attrs.type, + width: attrs.width, + height: attrs.height, + renderAt: element[0], + id: attrs.chartid, + dataFormat: attrs.dataformat || 'json', + dataSource: {}, + events: events + }; - for (observableAttr in observeConf.NDCObserver) { - attrConfig = observeConf.NDCObserver[observableAttr]; - if (attrConfig.ifExist === false || attrs[observableAttr]) { - attrs.$observe(observableAttr, attrConfig.observer); - } - } + for (observableAttr in observeConf.NDCObserver) { + attrConfig = observeConf.NDCObserver[observableAttr]; + if (attrConfig.ifExist === false || attrs[observableAttr]) { + attrs.$observe(observableAttr, attrConfig.observer); + } + } - if (attrs.datasource) { - chartConfigObject.dataSource = (chartConfigObject.dataFormat === 'json') ? JSON.parse(attrs.datasource) : attrs.datasource; - dataStringStore.dataSource = attrs.datasource; - } + if (attrs.datasource) { + chartConfigObject.dataSource = + chartConfigObject.dataFormat === 'json' + ? JSON.parse(attrs.datasource) + : attrs.datasource; + dataStringStore.dataSource = attrs.datasource; + } - for (observableAttr in observeConf.DCObserver) { - attrConfig = observeConf.DCObserver[observableAttr]; - dataComponent = attrs[observableAttr]; - if (dataComponent) { - attrs.$observe(observableAttr, attrConfig.observer); - dataStringStore[observableAttr] = dataComponent; - if (chartConfigObject.dataFormat === 'json' && typeof chartConfigObject.dataSource === "object") { - chartConfigObject.dataSource[observableAttr] = JSON.parse(dataComponent); - } - } else if (attrConfig.ifExist === false) { - attrs.$observe(observableAttr, attrConfig.observer); - } - } + for (observableAttr in observeConf.DCObserver) { + attrConfig = observeConf.DCObserver[observableAttr]; + dataComponent = attrs[observableAttr]; + if (dataComponent) { + attrs.$observe(observableAttr, attrConfig.observer); + dataStringStore[observableAttr] = dataComponent; + if ( + chartConfigObject.dataFormat === 'json' && + typeof chartConfigObject.dataSource === 'object' + ) { + chartConfigObject.dataSource[observableAttr] = JSON.parse( + dataComponent + ); + } + } else if (attrConfig.ifExist === false) { + attrs.$observe(observableAttr, attrConfig.observer); + } + } - // add configurations from config - if (attrs.config) { - configObj = JSON.parse(attrs.config); - for (attr in configObj) { - chartConfigObject[attr] = configObj[attr]; - } - } + // add configurations from config + if (attrs.config) { + configObj = JSON.parse(attrs.config); + for (attr in configObj) { + chartConfigObject[attr] = configObj[attr]; + } + } - createFCChart(); + createFCChart(); - scope.$on('$destroy', function () { - // on destroy free used resources to avoid memory leaks - if (chart && chart.dispose) { - chart.dispose(); - } - }); + scope.$on('$destroy', function() { + // on destroy free used resources to avoid memory leaks + if (chart && chart.dispose) { + chart.dispose(); } - }; - }]); -}()); + }); + } + }; + } + ]); +})();