diff --git a/README.md b/README.md index b43718a..e36ecc2 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ angular.module('MyModule', ['amChartsDirective']) ``` -#### [You can play with a working JS Fiddle example here!](http://jsfiddle.net/w3vpc35o/41/) +#### [JSFiddle Example here](http://jsfiddle.net/w3vpc35o/41/) #### Quick sample code @@ -84,6 +84,77 @@ $scope.amChartOptions = { }] } ``` + +#### Promise based chart rendering + +``` javascript + +// this function returns our chart data as a promise + $scope.dataFromPromise = function(){ + var deferred = $q.defer(); + + var data = [{ + year: 2005, + income: 23.5, + expenses: 18.1 + }, { + year: 2006, + income: 26.2, + expenses: 22.8 + }, { + year: 2007, + income: 30.1, + expenses: 23.9 + }, { + year: 2008, + income: 29.5, + expenses: 25.1 + }, { + year: 2009, + income: 24.6, + expenses: 25 + }]; + + deferred.resolve(data) + return deferred.promise; + }; + + // We can optionally pass a promise to the options attribute on the AmChartsDirective + // to delay the chart rendering until the promise resolves + $scope.amChartOptions = $timeout(function(){ + return { + // we can also use a promise for the data property to delay the rendering of + // the chart till we actually have data + data: $scope.dataFromPromise(), + type: "serial", + theme: 'black', + categoryField: "year", + rotate: true, + pathToImages: 'https://cdnjs.cloudflare.com/ajax/libs/amcharts/3.13.0/images/', + legend: { + enabled: true + }, + chartScrollbar: { + enabled: true, + }, + categoryAxis: { + gridPosition: "start", + parseDates: false + }, + valueAxes: [{ + position: "top", + title: "Million USD" + }], + graphs: [{ + type: "column", + title: "Income", + valueField: "income", + fillAlphas: 1, + }] + } + }, 1000) + +``` ##### If you do not specify a category field or a value field, the directive will assume the category field is at index [0] and the value field is at index [1]. Using the example above, 'year' would be the category field, and 'income' would be the value field. diff --git a/dist/amChartsDirective.js b/dist/amChartsDirective.js index 058731b..ebdc8be 100644 --- a/dist/amChartsDirective.js +++ b/dist/amChartsDirective.js @@ -18,218 +18,230 @@ angular.module('amChartsDirective', []).directive('amChart', ['$q', function ($q $el.attr('id', id); var chart; - // we can't render a chart without any data - if ($scope.options.data) { - var renderChart = function (amChartOptions) { - var o = amChartOptions || $scope.options; - - // set height and width - var height = $scope.height || '100%'; - var width = $scope.width || '100%'; - - $el.css({ - 'height': height, - 'width': width - }); + // allow $scope.options to be a promise + $q.when($scope.options).then(function(options){ + // we can't render a chart without any data + if (options.data) { + var renderChart = function (amChartOptions) { + var o = amChartOptions || options; + + // set height and width + var height = $scope.height || '100%'; + var width = $scope.width || '100%'; + + $el.css({ + 'height': height, + 'width': width + }); - // instantiate new chart object - if (o.type === 'xy') { - chart = o.theme ? new AmCharts.AmXYChart(AmCharts.themes[o.theme]) : new AmCharts.AmXYChart(); - } else if (o.type === 'pie') { - chart = o.theme ? new AmCharts.AmPieChart(AmCharts.themes[o.theme]) : new AmCharts.AmPieChart(); - } else { - chart = o.theme ? new AmCharts.AmSerialChart(AmCharts.themes[o.theme]) : new AmCharts.AmSerialChart(); - } + // instantiate new chart object + if (o.type === 'xy') { + chart = o.theme ? new AmCharts.AmXYChart(AmCharts.themes[o.theme]) : new AmCharts.AmXYChart(); + } else if (o.type === 'pie') { + chart = o.theme ? new AmCharts.AmPieChart(AmCharts.themes[o.theme]) : new AmCharts.AmPieChart(); + } else if (o.type === 'funnel') { + chart = o.theme ? new AmCharts.AmFunnelChart(AmCharts.themes[o.theme]) : new AmCharts.AmFunnelChart(); + } else if (o.type === 'radar') { + chart = o.theme ? new AmCharts.AmRadarChart(AmCharts.themes[o.theme]) : new AmCharts.AmRadarChart(); + } else { + chart = o.theme ? new AmCharts.AmSerialChart(AmCharts.themes[o.theme]) : new AmCharts.AmSerialChart(); + } + + /** set some default values that amCharts doesnt provide **/ + $q.when(o.data) + .then(function (data) { + + chart.dataProvider = data; + // if a category field is not specified, attempt to use the first field from an object in the array + chart.categoryField = o.categoryField || Object.keys(o.data[0])[0]; + chart.startDuration = 0.5; // default animation length, because everyone loves a little pizazz + + // AutoMargin is on by default, but the default 20px all around seems to create unnecessary white space around the control + chart.autoMargins = true; + chart.marginTop = 0; + chart.marginLeft = 0; + chart.marginBottom = 0; + chart.marginRight = 0; + + // modify default creditsPosition + chart.creditsPosition = 'top-right'; + + var chartKeys = Object.keys(o); + for (var i = 0; i < chartKeys.length; i++) { + if (typeof o[chartKeys[i]] !== 'object' && typeof o[chartKeys[i]] !== 'function') { + chart[chartKeys[i]] = o[chartKeys[i]]; + } + } - /** set some default values that amCharts doesnt provide **/ - $q.when(o.data) - .then(function (data) { + function generateGraphProperties(data) { + // Assign Category Axis Properties + if (o.categoryAxis) { + var categoryAxis = chart.categoryAxis; + + if (categoryAxis) { + /* if we need to create any default values, we should assign them here */ + categoryAxis.parseDates = true; + + var keys = Object.keys(o.categoryAxis); + for (var i = 0; i < keys.length; i++) { + if (!angular.isObject(o.categoryAxis[keys[i]]) || angular.isArray(o.categoryAxis[keys[i]])) { + categoryAxis[keys[i]] = o.categoryAxis[keys[i]]; + } else { + console.log('Stripped categoryAxis obj ' + keys[i]); + } + } + chart.categoryAxis = categoryAxis; + } + } - chart.dataProvider = data; - // if a category field is not specified, attempt to use the first field from an object in the array - chart.categoryField = o.categoryField || Object.keys(o.data[0])[0]; - chart.startDuration = 0.5; // default animation length, because everyone loves a little pizazz - - // AutoMargin is on by default, but the default 20px all around seems to create unnecessary white space around the control - chart.autoMargins = true; - chart.marginTop = 0; - chart.marginLeft = 0; - chart.marginBottom = 0; - chart.marginRight = 0; - - // modify default creditsPosition - chart.creditsPosition = 'top-right'; - - var chartKeys = Object.keys(o); - for (var i = 0; i < chartKeys.length; i++) { - if (typeof o[chartKeys[i]] !== 'object' && typeof o[chartKeys[i]] !== 'function') { - chart[chartKeys[i]] = o[chartKeys[i]]; - } - } + // Create value axis - function generateGraphProperties(data) { - // Assign Category Axis Properties - if (o.categoryAxis) { - var categoryAxis = chart.categoryAxis; + /* if we need to create any default values, we should assign them here */ - if (categoryAxis) { - /* if we need to create any default values, we should assign them here */ - categoryAxis.parseDates = true; + var addValueAxis = function (a) { + var valueAxis = new AmCharts.ValueAxis(); - var keys = Object.keys(o.categoryAxis); + var keys = Object.keys(a); for (var i = 0; i < keys.length; i++) { - if (!angular.isObject(o.categoryAxis[keys[i]]) || angular.isArray(o.categoryAxis[keys[i]])) { - categoryAxis[keys[i]] = o.categoryAxis[keys[i]]; - } else { - console.log('Stripped categoryAxis obj ' + keys[i]); + if (typeof a[keys[i]] !== 'object') { + valueAxis[keys[i]] = a[keys[i]]; } } - chart.categoryAxis = categoryAxis; - } - } + chart.addValueAxis(valueAxis); + }; - // Create value axis + if (o.valueAxes && o.valueAxes.length > 0) { + for (var i = 0; i < o.valueAxes.length; i++) { + addValueAxis(o.valueAxes[i]); + } + } - /* if we need to create any default values, we should assign them here */ - var addValueAxis = function (a) { - var valueAxis = new AmCharts.ValueAxis(); + //reusable function to create graph + var addGraph = function (g) { + var graph = new AmCharts.AmGraph(); + /** set some default values that amCharts doesnt provide **/ + // if a category field is not specified, attempt to use the second field from an object in the array as a default value + graph.valueField = g.valueField || Object.keys(o.data[0])[1]; + graph.balloonText = '[[category]]: [[value]]'; + if (g) { + var keys = Object.keys(g); + // iterate over all of the properties in the graph object and apply them to the new AmGraph + for (var i = 0; i < keys.length; i++) { + graph[keys[i]] = g[keys[i]]; + } + } + chart.addGraph(graph); + }; - var keys = Object.keys(a); - for (var i = 0; i < keys.length; i++) { - if (typeof a[keys[i]] !== 'object') { - valueAxis[keys[i]] = a[keys[i]]; + // create the graphs + if (o.graphs && o.graphs.length > 0) { + for (var i = 0; i < o.graphs.length; i++) { + addGraph(o.graphs[i]); } + } else { + addGraph(); } - chart.addValueAxis(valueAxis); - }; - if (o.valueAxes && o.valueAxes.length > 0) { - for (var i = 0; i < o.valueAxes.length; i++) { - addValueAxis(o.valueAxes[i]); + var chartCursor = new AmCharts.ChartCursor(); + if (o.chartCursor) { + var keys = Object.keys(o.chartCursor); + for (var i = 0; i < keys.length; i++) { + if (typeof o.chartCursor[keys[i]] !== 'object') { + chartCursor[keys[i]] = o.chartCursor[keys[i]]; + } + } } - } + chart.addChartCursor(chartCursor); - - //reusable function to create graph - var addGraph = function (g) { - var graph = new AmCharts.AmGraph(); - /** set some default values that amCharts doesnt provide **/ - // if a category field is not specified, attempt to use the second field from an object in the array as a default value - graph.valueField = g.valueField || Object.keys(o.data[0])[1]; - graph.balloonText = '[[category]]: [[value]]'; - if (g) { - var keys = Object.keys(g); - // iterate over all of the properties in the graph object and apply them to the new AmGraph + if (o.chartScrollbar) { + var scrollbar = new AmCharts.ChartScrollbar(); + var keys = Object.keys(o.chartScrollbar); for (var i = 0; i < keys.length; i++) { - graph[keys[i]] = g[keys[i]]; + scrollbar[keys[i]] = o.chartScrollbar[keys[i]]; } + chart.chartScrollbar = scrollbar; } - chart.addGraph(graph); - }; - // create the graphs - if (o.graphs && o.graphs.length > 0) { - for (var i = 0; i < o.graphs.length; i++) { - addGraph(o.graphs[i]); + if (o.balloon) { + chart.balloon = o.balloon; } - } else { - addGraph(); } - var chartCursor = new AmCharts.ChartCursor(); - if (o.chartCursor) { - var keys = Object.keys(o.chartCursor); - for (var i = 0; i < keys.length; i++) { - if (typeof o.chartCursor[keys[i]] !== 'object') { - chartCursor[keys[i]] = o.chartCursor[keys[i]]; - } + function generatePieProperties() { + if (o.balloon) { + chart.balloon = o.balloon; } } - chart.addChartCursor(chartCursor); - if (o.chartScrollbar) { - var scrollbar = new AmCharts.ChartScrollbar(); - var keys = Object.keys(o.chartScrollbar); + if (o.legend) { + var legend = new AmCharts.AmLegend(); + var keys = Object.keys(o.legend); for (var i = 0; i < keys.length; i++) { - scrollbar[keys[i]] = o.chartScrollbar[keys[i]]; + legend[keys[i]] = o.legend[keys[i]]; } - chart.chartScrollbar = scrollbar; + chart.legend = legend; } - if (o.balloon) { - chart.balloon = o.balloon; + if (o.type === 'pie') { + generatePieProperties(); + } else { + generateGraphProperties(); } - } - function generatePieProperties() { - if (o.balloon) { - chart.balloon = o.balloon; + if (o.titles) { + for (var i = 0;i < o.titles.length;i++) { + var title = o.titles[i]; + chart.addTitle(title.text, title.size, title.color, title.alpha, title.bold); + }; } - } - if (o.legend) { - var legend = new AmCharts.AmLegend(); - var keys = Object.keys(o.legend); - for (var i = 0; i < keys.length; i++) { - legend[keys[i]] = o.legend[keys[i]]; + if(o.export) { + chart.export = o.export; } - chart.legend = legend; - } - - if (o.type === 'pie') { - generatePieProperties(); - } else { - generateGraphProperties(); - } - if (o.titles) { - for (var i = 0;i < o.titles.length;i++) { - var title = o.titles[i]; - chart.addTitle(title.text, title.size, title.color, title.alpha, title.bold); - }; - } + // WRITE + chart.write(id); - // WRITE - chart.write(id); + }); + }; //renderchart - }); - }; //renderchart + // Render the chart + renderChart(); - // Render the chart - renderChart(); + // EVENTS ========================================================================= - // EVENTS ========================================================================= + $scope.$on('amCharts.triggerChartAnimate', function (event, id) { + if (id === $el[0].id || !id) { + chart.animateAgain(); + } + }); - $scope.$on('amCharts.triggerChartAnimate', function (event, id) { - if (id === $el[0].id || !id) { - chart.animateAgain(); - } - }); + $scope.$on('amCharts.updateData', function (event, data, id) { + if (id === $el[0].id || !id) { + chart.dataProvider = data; + chart.validateData(); + } - $scope.$on('amCharts.updateData', function (event, data, id) { - if (id === $el[0].id || !id) { - chart.dataProvider = data; - chart.validateData(); - } + }); - }); + $scope.$on('amCharts.validateNow', function (event, validateData, skipEvents, id) { + if (id === $el[0].id || !id) { + chart.validateNow(validateData === undefined ? true : validateData, + skipEvents === undefined ? false : skipEvents); + } + }); - $scope.$on('amCharts.validateNow', function (event, validateData, skipEvents, id) { - if (id === $el[0].id || !id) { - chart.validateNow(validateData === undefined ? true : validateData, - skipEvents === undefined ? false : skipEvents); - } - }); + $scope.$on('amCharts.renderChart', function (event, amChartOptions, id) { + if (id === $el[0].id || !id) { + renderChart(amChartOptions); + } + }); + } + }); - $scope.$on('amCharts.renderChart', function (event, amChartOptions, id) { - if (id === $el[0].id || !id) { - renderChart(amChartOptions); - } - }); - } } }; }]);