diff --git a/bower.json b/bower.json
index 3385707..b5ecc01 100644
--- a/bower.json
+++ b/bower.json
@@ -1,6 +1,6 @@
{
"name": "angular-charts",
- "version": "0.0.1",
+ "version": "0.1.0",
"authors": [
"chinmaymk"
],
diff --git a/dist/angular-charts.js b/dist/angular-charts.js
new file mode 100644
index 0000000..3e840f7
--- /dev/null
+++ b/dist/angular-charts.js
@@ -0,0 +1,872 @@
+/**
+* Main module
+*/
+angular.module('angularCharts', ['angularChartsTemplates']);
+/**
+* Main directive handling drawing of all charts
+*/
+angular.module('angularCharts').directive('acChart', [
+ '$templateCache',
+ '$compile',
+ '$window',
+ '$timeout',
+ function ($templateCache, $compile, $window, $timeout) {
+ /**
+ * Initialize some constants
+ * @type Array
+ */
+ var tooltip = [
+ 'display:none;',
+ 'position:absolute;',
+ 'border:1px solid #333;',
+ 'background-color:#161616;',
+ 'border-radius:5px;',
+ 'padding:5px;',
+ 'color:#fff;'
+ ].join('');
+ /**
+ * Utility function to call when we run out of colors!
+ * @return {[type]} [description]
+ */
+ function getRandomColor() {
+ var letters = '0123456789ABCDEF'.split('');
+ var color = '#';
+ for (var i = 0; i < 6; i++) {
+ color += letters[Math.round(Math.random() * 15)];
+ }
+ return color;
+ }
+ /**
+ * Main link function
+ * @param {[type]} scope [description]
+ * @param {[type]} element [description]
+ * @param {[type]} attrs [description]
+ * @return {[type]} [description]
+ */
+ function link(scope, element, attrs) {
+ var config = {
+ title: '',
+ tooltips: true,
+ labels: false,
+ mouseover: function () {
+ },
+ mouseout: function () {
+ },
+ click: function () {
+ },
+ legend: {
+ display: true,
+ position: 'left'
+ },
+ colors: [
+ 'steelBlue',
+ 'rgb(255,153,0)',
+ 'rgb(220,57,18)',
+ 'rgb(70,132,238)',
+ 'rgb(73,66,204)',
+ 'rgb(0,128,0)'
+ ],
+ innerRadius: 0,
+ lineLegend: 'lineEnd'
+ };
+ var totalWidth = element.width(), totalHeight = element.height();
+ var data, series, points, height, width, chartContainer, legendContainer, chartType, isAnimate = true, defaultColors = config.colors;
+ if (totalHeight === 0 || totalWidth === 0) {
+ throw new Error('Please set height and width for the chart element');
+ }
+ /**
+ * All the magic happens here
+ * handles extracting chart type
+ * getting data
+ * validating data
+ * drawing the chart
+ * @return {[type]} [description]
+ */
+ function init() {
+ prepareData();
+ setHeightWidth();
+ setContainers();
+ var chartFunc = getChartFunction(chartType);
+ chartFunc();
+ drawLegend();
+ }
+ /**
+ * Sets height and width of chart area based on legend
+ * used for setting radius, bar width of chart
+ */
+ function setHeightWidth() {
+ if (!config.legend.display) {
+ height = totalHeight;
+ width = totalWidth;
+ return;
+ }
+ switch (config.legend.position) {
+ case 'top':
+ case 'bottom':
+ height = totalHeight * 0.75;
+ width = totalWidth;
+ break;
+ case 'left':
+ case 'right':
+ height = totalHeight;
+ width = totalWidth * 0.75;
+ break;
+ }
+ }
+ /**
+ * Creates appropriate DOM structure for legend + chart
+ */
+ function setContainers() {
+ var container = $templateCache.get(config.legend.position);
+ element.html($compile(container)(scope));
+ chartContainer = element.find('.ac-chart');
+ legendContainer = element.find('.ac-legend');
+ height -= element.find('.ac-title').height();
+ }
+ /**
+ * Parses data from attributes
+ * @return {[type]} [description]
+ */
+ function prepareData() {
+ data = scope.acData;
+ chartType = scope.acChart;
+ series = data ? data.series || [] : [];
+ points = data ? data.data || [] : [];
+ if (scope.acConfig) {
+ angular.extend(config, scope.acConfig);
+ config.colors = config.colors.concat(defaultColors);
+ }
+ }
+ /**
+ * Returns appropriate chart function to call
+ * @param {[type]} type [description]
+ * @return {[type]} [description]
+ */
+ function getChartFunction(type) {
+ var charts = {
+ 'pie': pieChart,
+ 'bar': barChart,
+ 'line': lineChart,
+ 'area': areaChart,
+ 'point': pointChart
+ };
+ return charts[type];
+ }
+ /**
+ * Filters down the x axis labels if a limit is specified
+ */
+ function filterXAxis(xAxis, x) {
+ var allTicks = x.domain();
+ if (config.xAxisMaxTicks && allTicks.length > config.xAxisMaxTicks) {
+ var mod = Math.ceil(allTicks.length / config.xAxisMaxTicks);
+ xAxis.tickValues(allTicks.filter(function (e, i) {
+ return i % mod == 0;
+ }));
+ }
+ }
+ /**
+ * Draws a bar chart, grouped with negative value handling
+ * @return {[type]} [description]
+ */
+ function barChart() {
+ /**
+ * Setup date attributes
+ * @type {Object}
+ */
+ var margin = {
+ top: 0,
+ right: 20,
+ bottom: 30,
+ left: 40
+ };
+ width -= margin.left + margin.right;
+ height -= margin.top + margin.bottom;
+ var x = d3.scale.ordinal().rangeRoundBands([
+ 0,
+ width
+ ], 0.1);
+ var y = d3.scale.linear().range([
+ height,
+ 10
+ ]);
+ var x0 = d3.scale.ordinal().rangeRoundBands([
+ 0,
+ width
+ ], 0.1);
+ var yData = [0];
+ points.forEach(function (d) {
+ d.nicedata = d.y.map(function (e, i) {
+ yData.push(e);
+ return {
+ x: d.x,
+ y: e,
+ s: i,
+ tooltip: angular.isArray(d.tooltip) ? d.tooltip[i] : d.tooltip
+ };
+ });
+ });
+ var yMaxPoints = d3.max(points.map(function (d) {
+ return d.y.length;
+ }));
+ scope.yMaxData = yMaxPoints;
+ x.domain(points.map(function (d) {
+ return d.x;
+ }));
+ var padding = d3.max(yData) * 0.2;
+ y.domain([
+ d3.min(yData),
+ d3.max(yData) + padding
+ ]);
+ x0.domain(d3.range(yMaxPoints)).rangeRoundBands([
+ 0,
+ x.rangeBand()
+ ]);
+ /**
+ * Create scales using d3
+ * @type {[type]}
+ */
+ var xAxis = d3.svg.axis().scale(x).orient('bottom');
+ filterXAxis(xAxis, x);
+ var yAxis = d3.svg.axis().scale(y).orient('left').ticks(10).tickFormat(d3.format('s'));
+ /**
+ * Start drawing the chart!
+ * @type {[type]}
+ */
+ var svg = d3.select(chartContainer[0]).append('svg').attr('width', width + margin.left + margin.right).attr('height', height + margin.top + margin.bottom).append('g').attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+ svg.append('g').attr('class', 'x axis').attr('transform', 'translate(0,' + height + ')').call(xAxis);
+ svg.append('g').attr('class', 'y axis').call(yAxis);
+ /**
+ * Add bars
+ * @type {[type]}
+ */
+ var barGroups = svg.selectAll('.state').data(points).enter().append('g').attr('class', 'g').attr('transform', function (d) {
+ return 'translate(' + x(d.x) + ',0)';
+ });
+ var bars = barGroups.selectAll('rect').data(function (d) {
+ return d.nicedata;
+ }).enter().append('rect');
+ bars.attr('width', x0.rangeBand());
+ bars.attr('x', function (d, i) {
+ return x0(i);
+ }).attr('y', height).style('fill', function (d) {
+ return getColor(d.s);
+ }).attr('height', 0).transition().ease('cubic-in-out').duration(1000).attr('y', function (d) {
+ return y(Math.max(0, d.y));
+ }).attr('height', function (d) {
+ return Math.abs(y(d.y) - y(0));
+ });
+ /**
+ * Add events for tooltip
+ * @param {[type]} d [description]
+ * @return {[type]} [description]
+ */
+ bars.on('mouseover', function (d) {
+ makeToolTip({
+ value: d.y,
+ series: series[d.s],
+ index: d.x
+ }, d3.event);
+ config.mouseover(d, d3.event);
+ scope.$apply();
+ }).on('mouseleave', function (d) {
+ removeToolTip();
+ config.mouseout(d, d3.event);
+ scope.$apply();
+ }).on('mousemove', function (d) {
+ updateToolTip(d3.event);
+ }).on('click', function (d) {
+ config.click.call(d, d3.event);
+ scope.$apply();
+ });
+ /**
+ * Create labels
+ */
+ if (config.labels) {
+ barGroups.selectAll('not-a-class').data(function (d) {
+ return d.nicedata;
+ }).enter().append('text').attr('x', function (d, i) {
+ return x0(i);
+ }).attr('y', function (d) {
+ return height - Math.abs(y(d.y) - y(0));
+ }).text(function (d) {
+ return d.y;
+ });
+ }
+ /**
+ * Draw one zero line in case negative values exist
+ */
+ svg.append('line').attr('x1', width).attr('y1', y(0)).attr('y2', y(0)).style('stroke', 'silver');
+ }
+ /**
+ * Draws a line chart
+ * @return {[type]} [description]
+ */
+ function lineChart() {
+ var margin = {
+ top: 0,
+ right: 40,
+ bottom: 20,
+ left: 40
+ };
+ width -= margin.left + margin.right;
+ height -= margin.top + margin.bottom;
+ var x = d3.scale.ordinal().domain(points.map(function (d) {
+ return d.x;
+ })).rangeRoundBands([
+ 0,
+ width
+ ]);
+ var y = d3.scale.linear().range([
+ height,
+ 10
+ ]);
+ var xAxis = d3.svg.axis().scale(x).orient('bottom');
+ filterXAxis(xAxis, x);
+ var yAxis = d3.svg.axis().scale(y).orient('left').ticks(5).tickFormat(d3.format('s'));
+ var line = d3.svg.line().interpolate('cardinal').x(function (d) {
+ return getX(d.x);
+ }).y(function (d) {
+ return y(d.y);
+ });
+ var yData = [0];
+ var linedata = [];
+ points.forEach(function (d) {
+ d.y.map(function (e, i) {
+ yData.push(e);
+ });
+ });
+ var yMaxPoints = d3.max(points.map(function (d) {
+ return d.y.length;
+ }));
+ scope.yMaxData = yMaxPoints;
+ series.slice(0, yMaxPoints).forEach(function (value, index) {
+ var d = {};
+ d.series = value;
+ d.values = points.map(function (point) {
+ return point.y.map(function (e) {
+ return {
+ x: point.x,
+ y: e
+ };
+ })[index] || {
+ x: points[index].x,
+ y: 0
+ };
+ });
+ linedata.push(d);
+ });
+ var svg = d3.select(chartContainer[0]).append('svg').attr('width', width + margin.left + margin.right).attr('height', height + margin.top + margin.bottom).append('g').attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+ var padding = d3.max(yData) * 0.2;
+ y.domain([
+ d3.min(yData),
+ d3.max(yData) + padding
+ ]);
+ svg.append('g').attr('class', 'x axis').attr('transform', 'translate(0,' + height + ')').call(xAxis);
+ svg.append('g').attr('class', 'y axis').call(yAxis);
+ var point = svg.selectAll('.points').data(linedata).enter().append('g');
+ path = point.attr('points', 'points').append('path').attr('class', 'ac-line').style('stroke', function (d, i) {
+ return getColor(i);
+ }).attr('d', function (d) {
+ return line(d.values);
+ }).attr('stroke-width', '2').attr('fill', 'none');
+ /** Animation function
+ * [last description]
+ * @type {[type]}
+ */
+ var last = linedata[linedata.length - 1].values;
+ var totalLength = path.node().getTotalLength() + getX(last[last.length - 1].x);
+ path.attr('stroke-dasharray', totalLength + ' ' + totalLength).attr('stroke-dashoffset', totalLength).transition().duration(1500).ease('linear').attr('stroke-dashoffset', 0).attr('d', function (d) {
+ return line(d.values);
+ });
+ /**
+ * Add points
+ * @param {[type]} value [description]
+ * @param {[type]} key [description]
+ * @return {[type]} [description]
+ */
+ angular.forEach(linedata, function (value, key) {
+ var points = svg.selectAll('.circle').data(value.values).enter();
+ points.append('circle').attr('cx', function (d) {
+ return getX(d.x);
+ }).attr('cy', function (d) {
+ return y(d.y);
+ }).attr('r', 3).style('fill', getColor(linedata.indexOf(value))).style('stroke', getColor(linedata.indexOf(value))).on('mouseover', function (series) {
+ return function (d) {
+ makeToolTip({
+ index: d.x,
+ value: d.y,
+ series: series
+ }, d3.event);
+ config.mouseover(d, d3.event);
+ scope.$apply();
+ };
+ }(value.series)).on('mouseleave', function (d) {
+ removeToolTip();
+ config.mouseout(d, d3.event);
+ scope.$apply();
+ }).on('mousemove', function (d) {
+ updateToolTip(d3.event);
+ }).on('click', function (d) {
+ config.click(d, d3.event);
+ scope.$apply();
+ });
+ if (config.labels) {
+ points.append('text').attr('x', function (d) {
+ return getX(d.x);
+ }).attr('y', function (d) {
+ return y(d.y);
+ }).text(function (d) {
+ return d.y;
+ });
+ }
+ });
+ /**
+ * Labels at the end of line
+ */
+ if (config.lineLegend === 'lineEnd') {
+ point.append('text').datum(function (d) {
+ return {
+ name: d.series,
+ value: d.values[d.values.length - 1]
+ };
+ }).attr('transform', function (d) {
+ return 'translate(' + getX(d.value.x) + ',' + y(d.value.y) + ')';
+ }).attr('x', 3).text(function (d) {
+ return d.name;
+ });
+ }
+ /**
+ * Returns x point of line point
+ * @param {[type]} d [description]
+ * @return {[type]} [description]
+ */
+ function getX(d) {
+ return Math.round(x(d)) + x.rangeBand() / 2;
+ }
+ ;
+ return linedata;
+ }
+ /**
+ * Creates a nice area chart
+ * @return {[type]} [description]
+ */
+ function areaChart() {
+ var margin = {
+ top: 0,
+ right: 40,
+ bottom: 20,
+ left: 40
+ };
+ width -= margin.left + margin.right;
+ height -= margin.top + margin.bottom;
+ var x = d3.scale.ordinal().domain(points.map(function (d) {
+ return d.x;
+ })).rangeRoundBands([
+ 0,
+ width
+ ]);
+ var y = d3.scale.linear().range([
+ height,
+ 10
+ ]);
+ var xAxis = d3.svg.axis().scale(x).orient('bottom');
+ filterXAxis(xAxis, x);
+ var yAxis = d3.svg.axis().scale(y).orient('left').ticks(5).tickFormat(d3.format('s'));
+ var line = d3.svg.line().interpolate('cardinal').x(function (d) {
+ return getX(d.x);
+ }).y(function (d) {
+ return y(d.y);
+ });
+ var yData = [0];
+ var linedata = [];
+ points.forEach(function (d) {
+ d.y.map(function (e, i) {
+ yData.push(e);
+ });
+ });
+ var yMaxPoints = d3.max(points.map(function (d) {
+ return d.y.length;
+ }));
+ /**
+ * Important to set for legend
+ * @type {[type]}
+ */
+ scope.yMaxData = yMaxPoints;
+ series.slice(0, yMaxPoints).forEach(function (value, index) {
+ var d = {};
+ d.series = value;
+ d.values = points.map(function (point) {
+ return point.y.map(function (e) {
+ return {
+ x: point.x,
+ y: e
+ };
+ })[index] || {
+ x: points[index].x,
+ y: 0
+ };
+ });
+ linedata.push(d);
+ });
+ var svg = d3.select(chartContainer[0]).append('svg').attr('width', width + margin.left + margin.right).attr('height', height + margin.top + margin.bottom).append('g').attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+ var padding = d3.max(yData) * 0.2;
+ y.domain([
+ d3.min(yData),
+ d3.max(yData) + padding
+ ]);
+ svg.append('g').attr('class', 'x axis').attr('transform', 'translate(0,' + height + ')').call(xAxis);
+ svg.append('g').attr('class', 'y axis').call(yAxis);
+ var point = svg.selectAll('.points').data(linedata).enter().append('g');
+ var area = d3.svg.area().interpolate('basis').x(function (d) {
+ return getX(d.x);
+ }).y0(function (d) {
+ return y(0);
+ }).y1(function (d) {
+ return y(0 + d.y);
+ });
+ point.append('path').attr('class', 'area').attr('d', function (d) {
+ return area(d.values);
+ }).style('fill', function (d, i) {
+ return getColor(i);
+ }).style('opacity', '0.7');
+ function getX(d) {
+ return Math.round(x(d)) + x.rangeBand() / 2;
+ }
+ ;
+ }
+ /**
+ * Draws a beautiful pie chart
+ * @return {[type]} [description]
+ */
+ function pieChart() {
+ var radius = Math.min(width, height) / 2;
+ var svg = d3.select(chartContainer[0]).append('svg').attr('width', width).attr('height', height).append('g').attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');
+ var innerRadius = 0;
+ if (config.innerRadius) {
+ var configRadius = config.innerRadius;
+ if (typeof configRadius === 'string' && configRadius.indexOf('%') > 0) {
+ configRadius = radius * (1 - parseFloat(configRadius) * 0.01);
+ }
+ if (configRadius) {
+ innerRadius = radius - Number(configRadius);
+ }
+ }
+ scope.yMaxData = points.length;
+ var arc = d3.svg.arc().outerRadius(radius - 10).innerRadius(innerRadius);
+ var arcOver = d3.svg.arc().outerRadius(radius + 5).innerRadius(0);
+ var pie = d3.layout.pie().sort(null).value(function (d) {
+ return d.y[0];
+ });
+ var path = svg.selectAll('.arc').data(pie(points)).enter().append('g');
+ var arcs = path.append('path').style('fill', function (d, i) {
+ return getColor(i);
+ }).transition().ease('linear').duration(500).attrTween('d', tweenPie).attr('class', 'arc');
+ path.on('mouseover', function (d) {
+ makeToolTip({ value: d.data.y[0] }, d3.event);
+ d3.select(this).select('path').transition().duration(200).style('stroke', 'white').style('stroke-width', '2px');
+ config.mouseover(d, d3.event);
+ scope.$apply();
+ }).on('mouseleave', function (d) {
+ d3.select(this).select('path').transition().duration(200).style('stroke', '').style('stroke-width', '');
+ removeToolTip();
+ config.mouseout(d, d3.event);
+ scope.$apply();
+ }).on('mousemove', function (d) {
+ updateToolTip(d3.event);
+ }).on('click', function (d) {
+ config.click(d, d3.event);
+ scope.$apply();
+ });
+ if (!!config.labels) {
+ path.append('text').attr('transform', function (d) {
+ return 'translate(' + arc.centroid(d) + ')';
+ }).attr('dy', '.35em').style('text-anchor', 'middle').text(function (d) {
+ return d.data.y[0];
+ });
+ }
+ function tweenPie(b) {
+ b.innerRadius = 0;
+ var i = d3.interpolate({
+ startAngle: 0,
+ endAngle: 0
+ }, b);
+ return function (t) {
+ return arc(i(t));
+ };
+ }
+ }
+ function pointChart() {
+ var margin = {
+ top: 0,
+ right: 40,
+ bottom: 20,
+ left: 40
+ };
+ width -= margin.left - margin.right;
+ height -= margin.top - margin.bottom;
+ var x = d3.scale.ordinal().domain(points.map(function (d) {
+ return d.x;
+ })).rangeRoundBands([
+ 0,
+ width
+ ]);
+ var y = d3.scale.linear().range([
+ height,
+ 10
+ ]);
+ var xAxis = d3.svg.axis().scale(x).orient('bottom');
+ filterXAxis(xAxis, x);
+ var yAxis = d3.svg.axis().scale(y).orient('left').ticks(5).tickFormat(d3.format('s'));
+ var yData = [0];
+ var linedata = [];
+ points.forEach(function (d) {
+ d.y.map(function (e, i) {
+ yData.push(e);
+ });
+ });
+ var yMaxPoints = d3.max(points.map(function (d) {
+ return d.y.length;
+ }));
+ scope.yMaxPoints = yMaxPoints;
+ series.slice(0, yMaxPoints).forEach(function (value, index) {
+ var d = {};
+ d.series = value;
+ d.values = points.map(function (point) {
+ return point.y.map(function (e) {
+ return {
+ x: point.x,
+ y: e
+ };
+ })[index] || {
+ x: points[index].x,
+ y: 0
+ };
+ });
+ linedata.push(d);
+ });
+ var svg = d3.select(chartContainer[0]).append('svg').attr('width', width + margin.left + margin.right).attr('height', height + margin.top + margin.bottom).append('g').attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+ var padding = d3.max(yData) * 0.2;
+ y.domain([
+ d3.min(yData),
+ d3.max(yData) + padding
+ ]);
+ svg.append('g').attr('class', 'x axis').attr('transform', 'translate(0,' + height + ')').call(xAxis);
+ svg.append('g').attr('class', 'y axis').call(yAxis);
+ var point = svg.selectAll('.points').data(linedata).enter().append('g');
+ /**
+ * Add points
+ * @param {[type]} value [description]
+ * @param {[type]} key [description]
+ * @return {[type]} [description]
+ */
+ angular.forEach(linedata, function (value, key) {
+ var points = svg.selectAll('.circle').data(value.values).enter();
+ points.append('circle').attr('cx', function (d) {
+ return getX(d.x);
+ }).attr('cy', function (d) {
+ return y(d.y);
+ }).attr('r', 3).style('fill', getColor(linedata.indexOf(value))).style('stroke', getColor(linedata.indexOf(value))).on('mouseover', function (series) {
+ return function (d) {
+ makeToolTip({
+ index: d.x,
+ value: d.y,
+ series: series
+ }, d3.event);
+ config.mouseover(d, d3.event);
+ scope.$apply();
+ };
+ }(value.series)).on('mouseleave', function (d) {
+ removeToolTip();
+ config.mouseout(d, d3.event);
+ scope.$apply();
+ }).on('mousemove', function (d) {
+ updateToolTip(d3.event);
+ }).on('click', function (d) {
+ config.click(d, d3.event);
+ scope.$apply();
+ });
+ if (config.labels) {
+ points.append('text').attr('x', function (d) {
+ return getX(d.x);
+ }).attr('y', function (d) {
+ return y(d.y);
+ }).text(function (d) {
+ return d.y;
+ });
+ }
+ });
+ /**
+ * Returns x point of line point
+ * @param {[type]} d [description]
+ * @return {[type]} [description]
+ */
+ function getX(d) {
+ return Math.round(x(d)) + x.rangeBand() / 2;
+ }
+ ;
+ }
+ /**
+ * Creates and displays tooltip
+ * @return {[type]} [description]
+ */
+ function makeToolTip(data, event) {
+ if (!config.tooltips) {
+ return;
+ }
+ if (Object.prototype.toString.call(config.tooltips) == '[object Function]') {
+ data = config.tooltips(data);
+ } else {
+ data = data.value;
+ }
+ angular.element('
').html(data).appendTo('body').fadeIn('slow').css({
+ left: event.pageX + 20,
+ top: event.pageY - 30
+ });
+ }
+ /**
+ * Clears the tooltip from body
+ * @return {[type]} [description]
+ */
+ function removeToolTip() {
+ angular.element('.ac-tooltip').remove();
+ }
+ function updateToolTip(event) {
+ angular.element('.ac-tooltip').css({
+ left: event.pageX + 20,
+ top: event.pageY - 30
+ });
+ }
+ /**
+ * Adds data to legend
+ * @return {[type]} [description]
+ */
+ function drawLegend() {
+ scope.legends = [];
+ if (chartType == 'pie') {
+ angular.forEach(points, function (value, key) {
+ scope.legends.push({
+ color: config.colors[key],
+ title: value.x
+ });
+ });
+ }
+ if (chartType == 'bar' || chartType == 'area' || chartType == 'point' || chartType == 'line' && config.lineLegend === 'traditional') {
+ angular.forEach(series, function (value, key) {
+ scope.legends.push({
+ color: config.colors[key],
+ title: value
+ });
+ });
+ }
+ }
+ /**
+ * Checks if index is available in color
+ * else returns a random color
+ * @param {[type]} i [description]
+ * @return {[type]} [description]
+ */
+ function getColor(i) {
+ if (i < config.colors.length) {
+ return config.colors[i];
+ } else {
+ var color = getRandomColor();
+ config.colors.push(color);
+ return color;
+ }
+ }
+ var w = angular.element($window);
+ var resizePromise = null;
+ w.bind('resize', function (ev) {
+ resizePromise && $timeout.cancel(resizePromise);
+ resizePromise = $timeout(function () {
+ totalWidth = element.width();
+ totalHeight = element.height();
+ init();
+ }, 100);
+ });
+ scope.getWindowDimensions = function () {
+ return {
+ 'h': w.height(),
+ 'w': w.width()
+ };
+ };
+ //let the party begin!
+ //add some watchers
+ scope.$watch('acChart', function () {
+ init();
+ }, true);
+ scope.$watch('acData', function () {
+ init();
+ }, true);
+ scope.$watch('acConfig', function () {
+ init();
+ }, true);
+ }
+ return {
+ restrict: 'EA',
+ link: link,
+ transclude: 'true',
+ scope: {
+ acChart: '=',
+ acData: '=',
+ acConfig: '='
+ }
+ };
+ }
+]);
+angular.module('angularChartsTemplates', ['left', 'right']);
+
+angular.module("left", []).run(["$templateCache", function($templateCache) {
+ $templateCache.put("left",
+ "\n" +
+ "\n" +
+ "\n" +
+ "{{acConfig.title}}
\n" +
+ "\n" +
+ "
\n" +
+ " \n" +
+ " | \n" +
+ " | \n" +
+ "
\n" +
+ "
\n" +
+ "
\n" +
+ "\n" +
+ "
");
+}]);
+
+angular.module("right", []).run(["$templateCache", function($templateCache) {
+ $templateCache.put("right",
+ "\n" +
+ "\n" +
+ "{{acConfig.title}}
\n" +
+ "\n" +
+ "
\n" +
+ "\n" +
+ "
\n" +
+ " \n" +
+ " | \n" +
+ " | \n" +
+ "
\n" +
+ "
\n" +
+ "
");
+}]);
diff --git a/dist/angular-charts.min.js b/dist/angular-charts.min.js
new file mode 100644
index 0000000..a9c853a
--- /dev/null
+++ b/dist/angular-charts.min.js
@@ -0,0 +1 @@
+angular.module("angularCharts",["angularChartsTemplates"]),angular.module("angularCharts").directive("acChart",["$templateCache","$compile","$window","$timeout",function(a,b,c,d){function e(){for(var a="0123456789ABCDEF".split(""),b="#",c=0;6>c;c++)b+=a[Math.round(15*Math.random())];return b}function f(f,h){function i(){l(),j(),k();var a=m(F);a(),w()}function j(){if(!G.legend.display)return B=I,void(C=H);switch(G.legend.position){case"top":case"bottom":B=.75*I,C=H;break;case"left":case"right":B=I,C=.75*H}}function k(){var c=a.get(G.legend.position);h.html(b(c)(f)),D=h.find(".ac-chart"),E=h.find(".ac-legend"),B-=h.find(".ac-title").height()}function l(){y=f.acData,F=f.acChart,z=y?y.series||[]:[],A=y?y.data||[]:[],f.acConfig&&(angular.extend(G,f.acConfig),G.colors=G.colors.concat(J))}function m(a){var b={pie:r,bar:o,line:p,area:q,point:s};return b[a]}function n(a,b){var c=b.domain();if(G.xAxisMaxTicks&&c.length>G.xAxisMaxTicks){var d=Math.ceil(c.length/G.xAxisMaxTicks);a.tickValues(c.filter(function(a,b){return b%d==0}))}}function o(){var a={top:0,right:20,bottom:30,left:40};C-=a.left+a.right,B-=a.top+a.bottom;var b=d3.scale.ordinal().rangeRoundBands([0,C],.1),c=d3.scale.linear().range([B,10]),d=d3.scale.ordinal().rangeRoundBands([0,C],.1),e=[0];A.forEach(function(a){a.nicedata=a.y.map(function(b,c){return e.push(b),{x:a.x,y:b,s:c,tooltip:angular.isArray(a.tooltip)?a.tooltip[c]:a.tooltip}})});var g=d3.max(A.map(function(a){return a.y.length}));f.yMaxData=g,b.domain(A.map(function(a){return a.x}));var h=.2*d3.max(e);c.domain([d3.min(e),d3.max(e)+h]),d.domain(d3.range(g)).rangeRoundBands([0,b.rangeBand()]);var i=d3.svg.axis().scale(b).orient("bottom");n(i,b);var j=d3.svg.axis().scale(c).orient("left").ticks(10).tickFormat(d3.format("s")),k=d3.select(D[0]).append("svg").attr("width",C+a.left+a.right).attr("height",B+a.top+a.bottom).append("g").attr("transform","translate("+a.left+","+a.top+")");k.append("g").attr("class","x axis").attr("transform","translate(0,"+B+")").call(i),k.append("g").attr("class","y axis").call(j);var l=k.selectAll(".state").data(A).enter().append("g").attr("class","g").attr("transform",function(a){return"translate("+b(a.x)+",0)"}),m=l.selectAll("rect").data(function(a){return a.nicedata}).enter().append("rect");m.attr("width",d.rangeBand()),m.attr("x",function(a,b){return d(b)}).attr("y",B).style("fill",function(a){return x(a.s)}).attr("height",0).transition().ease("cubic-in-out").duration(1e3).attr("y",function(a){return c(Math.max(0,a.y))}).attr("height",function(a){return Math.abs(c(a.y)-c(0))}),m.on("mouseover",function(a){t({value:a.y,series:z[a.s],index:a.x},d3.event),G.mouseover(a,d3.event),f.$apply()}).on("mouseleave",function(a){u(),G.mouseout(a,d3.event),f.$apply()}).on("mousemove",function(){v(d3.event)}).on("click",function(a){G.click.call(a,d3.event),f.$apply()}),G.labels&&l.selectAll("not-a-class").data(function(a){return a.nicedata}).enter().append("text").attr("x",function(a,b){return d(b)}).attr("y",function(a){return B-Math.abs(c(a.y)-c(0))}).text(function(a){return a.y}),k.append("line").attr("x1",C).attr("y1",c(0)).attr("y2",c(0)).style("stroke","silver")}function p(){function a(a){return Math.round(c(a))+c.rangeBand()/2}var b={top:0,right:40,bottom:20,left:40};C-=b.left+b.right,B-=b.top+b.bottom;var c=d3.scale.ordinal().domain(A.map(function(a){return a.x})).rangeRoundBands([0,C]),d=d3.scale.linear().range([B,10]),e=d3.svg.axis().scale(c).orient("bottom");n(e,c);var g=d3.svg.axis().scale(d).orient("left").ticks(5).tickFormat(d3.format("s")),h=d3.svg.line().interpolate("cardinal").x(function(b){return a(b.x)}).y(function(a){return d(a.y)}),i=[0],j=[];A.forEach(function(a){a.y.map(function(a){i.push(a)})});var k=d3.max(A.map(function(a){return a.y.length}));f.yMaxData=k,z.slice(0,k).forEach(function(a,b){var c={};c.series=a,c.values=A.map(function(a){return a.y.map(function(b){return{x:a.x,y:b}})[b]||{x:A[b].x,y:0}}),j.push(c)});var l=d3.select(D[0]).append("svg").attr("width",C+b.left+b.right).attr("height",B+b.top+b.bottom).append("g").attr("transform","translate("+b.left+","+b.top+")"),m=.2*d3.max(i);d.domain([d3.min(i),d3.max(i)+m]),l.append("g").attr("class","x axis").attr("transform","translate(0,"+B+")").call(e),l.append("g").attr("class","y axis").call(g);var o=l.selectAll(".points").data(j).enter().append("g");path=o.attr("points","points").append("path").attr("class","ac-line").style("stroke",function(a,b){return x(b)}).attr("d",function(a){return h(a.values)}).attr("stroke-width","2").attr("fill","none");var p=j[j.length-1].values,q=path.node().getTotalLength()+a(p[p.length-1].x);return path.attr("stroke-dasharray",q+" "+q).attr("stroke-dashoffset",q).transition().duration(1500).ease("linear").attr("stroke-dashoffset",0).attr("d",function(a){return h(a.values)}),angular.forEach(j,function(b){var c=l.selectAll(".circle").data(b.values).enter();c.append("circle").attr("cx",function(b){return a(b.x)}).attr("cy",function(a){return d(a.y)}).attr("r",3).style("fill",x(j.indexOf(b))).style("stroke",x(j.indexOf(b))).on("mouseover",function(a){return function(b){t({index:b.x,value:b.y,series:a},d3.event),G.mouseover(b,d3.event),f.$apply()}}(b.series)).on("mouseleave",function(a){u(),G.mouseout(a,d3.event),f.$apply()}).on("mousemove",function(){v(d3.event)}).on("click",function(a){G.click(a,d3.event),f.$apply()}),G.labels&&c.append("text").attr("x",function(b){return a(b.x)}).attr("y",function(a){return d(a.y)}).text(function(a){return a.y})}),"lineEnd"===G.lineLegend&&o.append("text").datum(function(a){return{name:a.series,value:a.values[a.values.length-1]}}).attr("transform",function(b){return"translate("+a(b.value.x)+","+d(b.value.y)+")"}).attr("x",3).text(function(a){return a.name}),j}function q(){function a(a){return Math.round(c(a))+c.rangeBand()/2}var b={top:0,right:40,bottom:20,left:40};C-=b.left+b.right,B-=b.top+b.bottom;var c=d3.scale.ordinal().domain(A.map(function(a){return a.x})).rangeRoundBands([0,C]),d=d3.scale.linear().range([B,10]),e=d3.svg.axis().scale(c).orient("bottom");n(e,c);var g=d3.svg.axis().scale(d).orient("left").ticks(5).tickFormat(d3.format("s")),h=(d3.svg.line().interpolate("cardinal").x(function(b){return a(b.x)}).y(function(a){return d(a.y)}),[0]),i=[];A.forEach(function(a){a.y.map(function(a){h.push(a)})});var j=d3.max(A.map(function(a){return a.y.length}));f.yMaxData=j,z.slice(0,j).forEach(function(a,b){var c={};c.series=a,c.values=A.map(function(a){return a.y.map(function(b){return{x:a.x,y:b}})[b]||{x:A[b].x,y:0}}),i.push(c)});var k=d3.select(D[0]).append("svg").attr("width",C+b.left+b.right).attr("height",B+b.top+b.bottom).append("g").attr("transform","translate("+b.left+","+b.top+")"),l=.2*d3.max(h);d.domain([d3.min(h),d3.max(h)+l]),k.append("g").attr("class","x axis").attr("transform","translate(0,"+B+")").call(e),k.append("g").attr("class","y axis").call(g);var m=k.selectAll(".points").data(i).enter().append("g"),o=d3.svg.area().interpolate("basis").x(function(b){return a(b.x)}).y0(function(){return d(0)}).y1(function(a){return d(0+a.y)});m.append("path").attr("class","area").attr("d",function(a){return o(a.values)}).style("fill",function(a,b){return x(b)}).style("opacity","0.7")}function r(){function a(a){a.innerRadius=0;var b=d3.interpolate({startAngle:0,endAngle:0},a);return function(a){return g(b(a))}}var b=Math.min(C,B)/2,c=d3.select(D[0]).append("svg").attr("width",C).attr("height",B).append("g").attr("transform","translate("+C/2+","+B/2+")"),d=0;if(G.innerRadius){var e=G.innerRadius;"string"==typeof e&&e.indexOf("%")>0&&(e=b*(1-.01*parseFloat(e))),e&&(d=b-Number(e))}f.yMaxData=A.length;{var g=d3.svg.arc().outerRadius(b-10).innerRadius(d),h=(d3.svg.arc().outerRadius(b+5).innerRadius(0),d3.layout.pie().sort(null).value(function(a){return a.y[0]})),i=c.selectAll(".arc").data(h(A)).enter().append("g");i.append("path").style("fill",function(a,b){return x(b)}).transition().ease("linear").duration(500).attrTween("d",a).attr("class","arc")}i.on("mouseover",function(a){t({value:a.data.y[0]},d3.event),d3.select(this).select("path").transition().duration(200).style("stroke","white").style("stroke-width","2px"),G.mouseover(a,d3.event),f.$apply()}).on("mouseleave",function(a){d3.select(this).select("path").transition().duration(200).style("stroke","").style("stroke-width",""),u(),G.mouseout(a,d3.event),f.$apply()}).on("mousemove",function(){v(d3.event)}).on("click",function(a){G.click(a,d3.event),f.$apply()}),G.labels&&i.append("text").attr("transform",function(a){return"translate("+g.centroid(a)+")"}).attr("dy",".35em").style("text-anchor","middle").text(function(a){return a.data.y[0]})}function s(){function a(a){return Math.round(c(a))+c.rangeBand()/2}var b={top:0,right:40,bottom:20,left:40};C-=b.left-b.right,B-=b.top-b.bottom;var c=d3.scale.ordinal().domain(A.map(function(a){return a.x})).rangeRoundBands([0,C]),d=d3.scale.linear().range([B,10]),e=d3.svg.axis().scale(c).orient("bottom");n(e,c);var g=d3.svg.axis().scale(d).orient("left").ticks(5).tickFormat(d3.format("s")),h=[0],i=[];A.forEach(function(a){a.y.map(function(a){h.push(a)})});var j=d3.max(A.map(function(a){return a.y.length}));f.yMaxPoints=j,z.slice(0,j).forEach(function(a,b){var c={};c.series=a,c.values=A.map(function(a){return a.y.map(function(b){return{x:a.x,y:b}})[b]||{x:A[b].x,y:0}}),i.push(c)});var k=d3.select(D[0]).append("svg").attr("width",C+b.left+b.right).attr("height",B+b.top+b.bottom).append("g").attr("transform","translate("+b.left+","+b.top+")"),l=.2*d3.max(h);d.domain([d3.min(h),d3.max(h)+l]),k.append("g").attr("class","x axis").attr("transform","translate(0,"+B+")").call(e),k.append("g").attr("class","y axis").call(g);k.selectAll(".points").data(i).enter().append("g");angular.forEach(i,function(b){var c=k.selectAll(".circle").data(b.values).enter();c.append("circle").attr("cx",function(b){return a(b.x)}).attr("cy",function(a){return d(a.y)}).attr("r",3).style("fill",x(i.indexOf(b))).style("stroke",x(i.indexOf(b))).on("mouseover",function(a){return function(b){t({index:b.x,value:b.y,series:a},d3.event),G.mouseover(b,d3.event),f.$apply()}}(b.series)).on("mouseleave",function(a){u(),G.mouseout(a,d3.event),f.$apply()}).on("mousemove",function(){v(d3.event)}).on("click",function(a){G.click(a,d3.event),f.$apply()}),G.labels&&c.append("text").attr("x",function(b){return a(b.x)}).attr("y",function(a){return d(a.y)}).text(function(a){return a.y})})}function t(a,b){G.tooltips&&(a="[object Function]"==Object.prototype.toString.call(G.tooltips)?G.tooltips(a):a.value,angular.element('').html(a).appendTo("body").fadeIn("slow").css({left:b.pageX+20,top:b.pageY-30}))}function u(){angular.element(".ac-tooltip").remove()}function v(a){angular.element(".ac-tooltip").css({left:a.pageX+20,top:a.pageY-30})}function w(){f.legends=[],"pie"==F&&angular.forEach(A,function(a,b){f.legends.push({color:G.colors[b],title:a.x})}),("bar"==F||"area"==F||"point"==F||"line"==F&&"traditional"===G.lineLegend)&&angular.forEach(z,function(a,b){f.legends.push({color:G.colors[b],title:a})})}function x(a){if(a\n .axis path,\n .axis line {\n fill: none;\n stroke: #333;\n }\n .ac-line {\n fill:none;\n stroke-width:2px;\n }\n\n\n{{acConfig.title}}
\n\n\n
")}]),angular.module("right",[]).run(["$templateCache",function(a){a.put("right","\n\n{{acConfig.title}}
\n\n
\n")}]);
\ No newline at end of file
diff --git a/package.json b/package.json
index cefd529..77e2c75 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "utopia",
- "version": "0.0.1",
- "description": "ERROR: No README.md file found!",
+ "version": "0.1.0",
+ "description": "angular directives for common charts using d3, for more information visit",
"main": "Gruntfile.js",
"dependencies": {
"grunt": "~0.4.1",