From a5ad58fc721017101c325db0a646aa91b69f8abe Mon Sep 17 00:00:00 2001 From: Chris Nicola Date: Wed, 19 Nov 2014 16:28:03 -0800 Subject: [PATCH] Handle visibility changes more robustly Since Angular can change visibility states during digest changes we check to see if the chart is visible whenever the digest runs with a general $watch. We also check the size in case the area has changed in size in some way. Also a small fix for d3-pie to keep it from drawing multiple charts during redraw. --- angularD3.js | 66 ++++++++++++++------------- angularD3.min.js | 2 +- app/index.html | 1 + app/scripts/controllers/main.coffee | 6 +-- bower.json | 2 +- package.json | 2 +- src/angularD3/directives/arc.coffee | 2 +- src/angularD3/directives/axis.coffee | 32 ++++++------- src/angularD3/directives/bars.coffee | 2 +- src/angularD3/directives/chart.coffee | 30 +++++++++--- src/angularD3/directives/line.coffee | 2 +- src/angularD3/directives/pie.coffee | 4 +- 12 files changed, 86 insertions(+), 65 deletions(-) diff --git a/angularD3.js b/angularD3.js index ba77ea4..309ad00 100644 --- a/angularD3.js +++ b/angularD3.js @@ -40,7 +40,7 @@ if (!((data != null) && data.length !== 0)) { return; } - radius = Math.min(chartController.innerWidth(), chartController.innerHeight()) / 2; + radius = Math.min(chartController.innerWidth, chartController.innerHeight) / 2; center.attr("transform", "translate(" + radius + "," + radius + ")"); arc = d3.svg.arc().outerRadius(radius).innerRadius(radius * innerRadius).startAngle(0).endAngle(function(d) { return d / 100 * 2 * Math.PI; @@ -213,27 +213,27 @@ range = function() { if (options.orientation === 'top' || options.orientation === 'bottom') { if (options.reverse != null) { - return [chartController.innerWidth(), 0]; + return [chartController.innerWidth, 0]; } else { - return [0, chartController.innerWidth()]; + return [0, chartController.innerWidth]; } } else { if (options.reverse != null) { - return [0, chartController.innerHeight()]; + return [0, chartController.innerHeight]; } else { - return [chartController.innerHeight(), 0]; + return [chartController.innerHeight, 0]; } } }; translation = function() { if (options.orientation === 'bottom') { - return "translate(0, " + (chartController.innerHeight()) + ")"; + return "translate(0, " + chartController.innerHeight + ")"; } else if (options.orientation === 'top') { return "translate(0, 0)"; } else if (options.orientation === 'left') { return "translate(0, 0)"; } else if (options.orientation === 'right') { - return "translate(" + (chartController.innerWidth()) + ", 0)"; + return "translate(" + chartController.innerWidth + ", 0)"; } }; if (options.scale === 'time') { @@ -274,24 +274,24 @@ }; positionLabel = function(label) { if (options.orientation === 'bottom') { - return label.attr("x", "" + (chartController.innerWidth() / 2)).attr("dy", "" + chartController.margin.bottom).attr("style", "text-anchor: middle;"); + return label.attr("x", "" + (chartController.innerWidth / 2)).attr("dy", "" + chartController.margin.bottom).attr("style", "text-anchor: middle;"); } else if (options.orientation === 'top') { - return label.attr("x", "" + (chartController.innerWidth() / 2)).attr("dy", "" + (-chartController.margin.top)).attr("style", "text-anchor: middle;"); + return label.attr("x", "" + (chartController.innerWidth / 2)).attr("dy", "" + (-chartController.margin.top)).attr("style", "text-anchor: middle;"); } else if (options.orientation === 'left') { - return label.attr("x", "-" + (chartController.innerHeight() / 2)).attr("dy", "" + (-chartController.margin.left + 18)).attr("style", "text-anchor: middle;").attr("transform", "rotate(-90)"); + return label.attr("x", "-" + (chartController.innerHeight / 2)).attr("dy", "" + (-chartController.margin.left + 18)).attr("style", "text-anchor: middle;").attr("transform", "rotate(-90)"); } else if (options.orientation === 'right') { - return label.attr("x", "" + (chartController.innerHeight() / 2)).attr("dy", "" + (-chartController.margin.right + 18)).attr("style", "text-anchor: middle;").attr("transform", "rotate(90)"); + return label.attr("x", "" + (chartController.innerHeight / 2)).attr("dy", "" + (-chartController.margin.right + 18)).attr("style", "text-anchor: middle;").attr("transform", "rotate(90)"); } }; drawGrid = function(grid) { if (options.orientation === 'bottom') { - return grid.call(getAxis().tickSize(chartController.innerHeight(), 0, 0).tickFormat('')); + return grid.call(getAxis().tickSize(chartController.innerHeight, 0, 0).tickFormat('')); } else if (options.orientation === 'top') { - return grid.attr("transform", "translate(0, " + (chartController.innerHeight()) + ")").call(getAxis().tickSize(chartController.innerHeight(), 0, 0).tickFormat('')); + return grid.attr("transform", "translate(0, " + chartController.innerHeight + ")").call(getAxis().tickSize(chartController.innerHeight, 0, 0).tickFormat('')); } else if (options.orientation === 'left') { - return grid.attr("transform", "translate(" + (chartController.innerWidth()) + ", 0)").call(getAxis().tickSize(chartController.innerWidth(), 0, 0).tickFormat('')); + return grid.attr("transform", "translate(" + chartController.innerWidth + ", 0)").call(getAxis().tickSize(chartController.innerWidth, 0, 0).tickFormat('')); } else if (options.orientation === 'right') { - return grid.call(getAxis().tickSize(chartController.innerWidth(), 0, 0).tickFormat('')); + return grid.call(getAxis().tickSize(chartController.innerWidth, 0, 0).tickFormat('')); } }; adjustTickLabels = function(g) { @@ -413,7 +413,7 @@ x = chartController.getScale(options.xscale || options.x); y = chartController.getScale(options.yscale || options.y); chart = chartController.getChart(); - height = chartController.innerHeight(); + height = chartController.innerHeight; width = options.width; barsElements = null; redraw = function(data) { @@ -458,7 +458,7 @@ scope: true, controller: [ '$scope', '$element', '$attrs', '$window', '$timeout', function($scope, $el, $attrs, $window, $timeout) { - var binding, chart, debounce, elements, scales, sortOrder, svg, + var binding, chart, debounce, elements, height, scales, sortOrder, svg, updateSize, width, _this = this; scales = $scope.scales = {}; elements = $scope.elements = []; @@ -470,18 +470,12 @@ left: 10 }; svg = d3.select($el[0]).append('svg').attr('class', "d3").attr("width", "100%").attr("height", "100%"); - this.width = function() { + width = function() { return $el[0].offsetWidth; }; - this.height = function() { + height = function() { return $el[0].offsetHeight; }; - this.innerWidth = function() { - return _this.width() - _this.margin.left - _this.margin.right; - }; - this.innerHeight = function() { - return _this.height() - _this.margin.top - _this.margin.bottom; - }; chart = svg.append("g").attr("transform", "translate(" + this.margin.left + "," + this.margin.top + ")"); this.getSvg = function() { return svg; @@ -507,13 +501,21 @@ order: Number(order) }); }; + updateSize = function() { + if (_this.width !== width() || _this.height !== height()) { + _this.width = width(); + _this.height = height(); + _this.innerWidth = _this.width - _this.margin.left - _this.margin.right; + _this.innerHeight = _this.height - _this.margin.top - _this.margin.bottom; + return _this.redraw(); + } + }; sortOrder = function(a, b) { return a.order - b.order; }; debounce = null; this.redraw = function() { - var _this = this; - if (debounce) { + if (debounce || _this.width === 0 || _this.height === 0) { return; } return debounce = $timeout(function() { @@ -533,12 +535,14 @@ return _results; }, $attrs.updateInterval || 200); }; - $window.addEventListener('resize', this.redraw); + $window.addEventListener('resize', updateSize); if ($attrs.watch === 'deep') { $scope.$watch(binding, this.redraw, true); } else { $scope.$watch(binding, this.redraw); } + $scope.$watch(updateSize); + updateSize(); } ] }; @@ -660,7 +664,7 @@ options = angular.extend(defaults(), attrs); x = chartController.getScale(options.xscale || options.x); y = chartController.getScale(options.yscale || options.y); - height = chartController.innerHeight(); + height = chartController.innerHeight; line = d3.svg.line().x(function(d) { return x(d[options.x]); }).y(function(d) { @@ -725,11 +729,11 @@ center = null; redraw = function(data) { var arc, arcTween, getPosition, label, labelArc, padding, prevbb, radius, slice; - center = chartController.getChart().append("g").attr("class", "pie"); + center || (center = chartController.getChart().append("g").attr("class", "pie")); if (!((data != null) && data.length !== 0)) { return; } - radius = Math.min(chartController.innerWidth(), chartController.innerHeight()) / 2; + radius = Math.min(chartController.innerWidth, chartController.innerHeight) / 2; center.attr("transform", "translate(" + radius + "," + radius + ")"); arc = d3.svg.arc().outerRadius(radius).innerRadius(radius * innerRadius); arcTween = function(a) { diff --git a/angularD3.min.js b/angularD3.min.js index 9222991..0c8720a 100644 --- a/angularD3.min.js +++ b/angularD3.min.js @@ -1 +1 @@ -!function(){angular.module("ad3",[])}.call(this),function(){angular.module("ad3").directive("d3Arc",function(){var a;return a=function(){return{x:0,y:1,innerRadius:0,labelRadius:0,transition:"cubic-in-out",transitionDuration:1e3,value:"value",label:"label"}},{restrict:"E",require:"^d3Chart",link:function(b,c,d,e){var f,g,h,i,j,k,l,m;return l=angular.extend(a(),d),i=e.getChart(),j=parseFloat(l.innerRadius),k=parseFloat(l.labelRadius),h=null,g=null,f=null,m=function(a){var b,c,d,i;return h||(h=e.getChart().append("g").attr("class","arc")),g||(g=h.append("path")),f||(f=h.append("text").attr("class","arc-label").attr("dy","0.35em").style("text-anchor","middle")),null!=a&&0!==a.length?(i=Math.min(e.innerWidth(),e.innerHeight())/2,h.attr("transform","translate("+i+","+i+")"),b=d3.svg.arc().outerRadius(i).innerRadius(i*j).startAngle(0).endAngle(function(a){return 2*(a/100)*Math.PI}),c=function(a){var c;return null==this._current&&(this._current=0),c=d3.interpolate(this._current,a),this._current=a,function(a){return b(c(a))}},d=d3.svg.arc().outerRadius(i*k).innerRadius(i*k),g.datum(a[l.value]).transition().ease(l.transition).duration(l.transitionDuration).attrTween("d",c),f.text(a[l.label])):void 0},e.registerElement(m,l.order)}}})}.call(this),function(){angular.module("ad3").directive("d3Area",function(){var a;return a=function(){return{}},{restrict:"E",require:"^d3Chart",link:function(b,c,d,e){var f,g,h,i,j,k,l;return i=angular.extend(a(),d),k=e.getScale(i.xscale||i.x),l=e.getScale(i.yscale||i.y),i.vertical?(f=d3.svg.area().y(function(a){return k(a.x)}).x0(0).x1(function(a){return l(a.y)}),h=d3.svg.area().y(function(a){return k(a.x)}).x0(function(a){return l(a.y0)}).x1(function(a){return l(a.y+a.y0)})):(f=d3.svg.area().x(function(a){return k(a.x)}).y0(e.innerHeight).y1(function(a){return l(a.y)}),h=d3.svg.area().x(function(a){return k(a.x)}).y0(function(a){return l(a.y0)}).y1(function(a){return l(a.y+a.y0)})),g=null,j=function(a){var c,d,j,k,l,m,n;return g||(g=e.getChart().append("g").attr("class","area")),null!=a&&0!==a.length&&(null!=i.y&&(d=i.y),null!=i.columns&&(d=b.$eval(i.columns)),null!=d&&(angular.isString(d)&&(d=d.split(",").map(function(a){return a.trim()})),0!==d.length))?(j=function(){var b,c,e;for(e=[],b=0,c=d.length;c>b;b++)k=d[b],e.push({name:k,values:function(){var b,c,d;for(d=[],b=0,c=a.length;c>b;b++)n=a[b],d.push({x:n[i.x],y:n[k]});return d}()});return e}(),l=d3.layout.stack().values(function(a){return a.values}),null!=i.offset&&l.offset(i.offset),m=l(j),c=g.selectAll("path.area").data(m),c.enter().append("path"),c.attr("class",function(a){return"area "+a.name}).transition().duration(500).attr("d",function(a,b){return 0===b?f(a.values):h(a.values)}),c.exit().attr("d",function(a,b){return 0===b?f(a.values):h(a.values)}).remove()):void 0},null!=i.columns&&b.$watch(i.columns,e.redraw,!0),e.registerElement(j,i.order)}}})}.call(this),function(){angular.module("ad3").directive("d3Axis",function(){var a;return a=function(){return{orientation:"bottom",ticks:"5",extent:!1}},{priority:1,restrict:"E",require:"^d3Chart",link:function(b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q,r;return l=angular.extend(a(),d),n=function(){return"top"===l.orientation||"bottom"===l.orientation?null!=l.reverse?[e.innerWidth(),0]:[0,e.innerWidth()]:null!=l.reverse?[0,e.innerHeight()]:[e.innerHeight(),0]},q=function(){return"bottom"===l.orientation?"translate(0, "+e.innerHeight()+")":"top"===l.orientation?"translate(0, 0)":"left"===l.orientation?"translate(0, 0)":"right"===l.orientation?"translate("+e.innerWidth()+", 0)":void 0},p="time"===l.scale?d3.time.scale():l.scale?d3.scale[l.scale]():d3.scale.linear(),i=function(){var a,c,d;return a=d3.svg.axis().scale(p).orient(l.orientation),l.ticks&&a.ticks(l.ticks),l.timeScale&&a.ticks(d3.time[l.timeScale],l.timeInterval),l.tickValues&&a.tickValues(b.$eval(l.tickValues)),l.tickSize&&(d=l.tickSize.split(","),a.innerTickSize(d[0]),a.outerTickSize(d[1])),null!=l.format&&(c=d3.format(l.format),a.tickFormat(c)),null!=l.timeFormat&&(c=d3.time.format(l.timeFormat),a.tickFormat(function(a){return c(new Date(a))})),a},m=function(a){return"bottom"===l.orientation?a.attr("x",""+e.innerWidth()/2).attr("dy",""+e.margin.bottom).attr("style","text-anchor: middle;"):"top"===l.orientation?a.attr("x",""+e.innerWidth()/2).attr("dy",""+-e.margin.top).attr("style","text-anchor: middle;"):"left"===l.orientation?a.attr("x","-"+e.innerHeight()/2).attr("dy",""+(-e.margin.left+18)).attr("style","text-anchor: middle;").attr("transform","rotate(-90)"):"right"===l.orientation?a.attr("x",""+e.innerHeight()/2).attr("dy",""+(-e.margin.right+18)).attr("style","text-anchor: middle;").attr("transform","rotate(90)"):void 0},h=function(a){return"bottom"===l.orientation?a.call(i().tickSize(e.innerHeight(),0,0).tickFormat("")):"top"===l.orientation?a.attr("transform","translate(0, "+e.innerHeight()+")").call(i().tickSize(e.innerHeight(),0,0).tickFormat("")):"left"===l.orientation?a.attr("transform","translate("+e.innerWidth()+", 0)").call(i().tickSize(e.innerWidth(),0,0).tickFormat("")):"right"===l.orientation?a.call(i().tickSize(e.innerWidth(),0,0).tickFormat("")):void 0},f=function(a){var b,c,d;return d=a.selectAll(".tick text"),l.tickDy&&d.attr("dy",l.tickDy),l.tickDx&&d.attr("dx",l.tickDx),l.tickAnchor&&d.style("text-anchor",l.tickAnchor),c=d3.select(d[0].slice(-1)[0]),l.lastTickDy&&c.attr("dy",l.lastTickDy),l.lastTickDx&&c.attr("dx",l.lastTickDx),l.lastTickAnchor&&c.style("text-anchor",l.lastTickAnchor),b=d3.select(d[0][0]),l.firstTickDy&&b.attr("dy",l.firstTickDy),l.firstTickDx&&b.attr("dx",l.firstTickDx),l.listTickAnchor?b.style("text-anchor",l.firstTickAnchor):void 0},g=null,j=null,k=null,o=function(a){var b;return g||(g=e.getChart().append("g").attr("class","axis axis-"+l.orientation+" axis-"+l.name).attr("transform",q())),l.label&&(k||(k=g.append("text").attr("class","axis-label").text(l.label))),l.grid&&(j||(j=e.getChart().append("g").attr("class","axis-grid axis-grid-"+l.name))),null!=a&&0!==a.length?(k&&m(k.transition().duration(500)),g.transition().duration(500).attr("transform",q()).call(i()).selectAll("tick text").tween("attr.dx",null).tween("attr.dy",null).tween("style.text-anchor",null),null!=j&&h(j.transition().duration(500)),b=g.selectAll(".tick text"),g.call(f)):void 0},r=function(a){var c,d;if(null!=a&&0!==a.length)return p.range(n()),l.domain,d=l.filter?b.$eval(""+l.filter+"(data)",{data:a}):function(){var b,d,e;for(e=[],b=0,d=a.length;d>b;b++)c=a[b],e.push(c[l.name]);return e}(),l.extent?p.domain(d3.extent(d)):p.domain([0,d3.max(d)])},e.addScale(l.name,p,r),e.registerElement(o,l.order),null!=l.tickValues?b.$watch(l.tickValues,e.redraw,!0):void 0}}})}.call(this),function(){angular.module("ad3").directive("d3Bars",function(){var a;return a=function(){return{x:0,y:1,width:15}},{restrict:"E",require:"^d3Chart",link:function(b,c,d,e){var f,g,h,i,j,k,l,m;return i=angular.extend(a(),d),l=e.getScale(i.xscale||i.x),m=e.getScale(i.yscale||i.y),g=e.getChart(),h=e.innerHeight(),k=i.width,f=null,j=function(a){var b;return f||(f=e.getChart().append("g").attr("class","bars")),null!=a&&0!==a.length?(b=f.selectAll("rect.bar").data(a),b.exit().transition().duration(500).attr("y",function(){return h}).attr("height",0).remove(),b.transition().duration(500).attr("x",function(a){return l(a[i.x])-k/2}).attr("y",function(a){return m(a[i.y])}).attr("height",function(a){return h-m(a[i.y])}).attr("width",k),b.enter().append("rect").attr("class",function(a,b){return"bar bar-"+b}).attr("x",function(a){return l(a[i.x])-k/2}).attr("width",k).attr("y",h).attr("height",0).transition().duration(500).attr("y",function(a){return m(a[i.y])}).attr("height",function(a){return h-m(a[i.y])})):void 0},e.registerElement(j,i.order)}}})}.call(this),function(){angular.module("ad3").directive("d3Chart",function(){return{restrict:"EA",scope:!0,controller:["$scope","$element","$attrs","$window","$timeout",function(a,b,c,d,e){var f,g,h,i,j,k,l,m=this;j=a.scales={},i=a.elements=[],f=a.binding=c.data,this.margin=a.$eval(c.margin)||{top:10,right:10,bottom:10,left:10},l=d3.select(b[0]).append("svg").attr("class","d3").attr("width","100%").attr("height","100%"),this.width=function(){return b[0].offsetWidth},this.height=function(){return b[0].offsetHeight},this.innerWidth=function(){return m.width()-m.margin.left-m.margin.right},this.innerHeight=function(){return m.height()-m.margin.top-m.margin.bottom},g=l.append("g").attr("transform","translate("+this.margin.left+","+this.margin.top+")"),this.getSvg=function(){return l},this.getChart=function(){return g},this.addScale=function(a,b,c){return j[a]={scale:b,update:c}},this.getScale=function(a){return j[a].scale},this.registerElement=function(a,b){return null==b&&(b=0),i.push({redraw:a,order:Number(b)})},k=function(a,b){return a.order-b.order},h=null,this.redraw=function(){return h?void 0:h=e(function(){var b,c,d,e,g,l,m,n;h=null,b=a.$eval(f);for(d in j)e=j[d],e.update(b);for(m=i.sort(k),n=[],g=0,l=m.length;l>g;g++)c=m[g],n.push(c.redraw(b));return n},c.updateInterval||200)},d.addEventListener("resize",this.redraw),"deep"===c.watch?a.$watch(f,this.redraw,!0):a.$watch(f,this.redraw)}]}})}.call(this),function(){angular.module("ad3").directive("d3Data",["d3Service",function(a){return{restrict:"E",scope:!1,link:function(b,c,d){var e,f,g,h;return h=d.src,f=d.data,d.accessor&&(e=b.$eval(d.accessor)),d.callback&&(g=b.$eval(d.callback)),a.csv(h,e,g).then(function(a){return b[f]=a},function(){throw"Error loading CSV via D3"})}}}])}.call(this),function(){angular.module("ad3").directive("d3Gradient",function(){var a;return a={transition:500},{restrict:"E",require:"^d3Chart",link:function(b,c,d,e){var f,g,h;return g=e.getSvg(),f=g.insert("defs","g").append("linearGradient").attr("id",d.ref),["x1","x2","y1","y2"].forEach(function(a){return d.$observe(a,function(b){return f.attr(a,b)})}),h=a.transition,d.$observe("transition",function(a){return null!=a?h=a:void 0}),b.$watch(d.stops,function(a){return null!=a?(a=f.selectAll("stop").data(a),a.enter().append("stop"),a.attr("offset",function(a){return a.offset}).attr("stop-color",function(a){return a.color}).attr("stop-opacity",function(a){return null!=a.opacity?a.opacity:1}),a.exit().remove()):void 0})}}})}.call(this),function(){angular.module("ad3").directive("d3Include",function(){return{restrict:"E",require:"^d3Chart",link:function(a,b,c,d){var e,f;return e=d.getChart(),f=e.append("g").attr("class","includes"),f.html(b.html())}}})}.call(this),function(){angular.module("ad3").directive("d3Line",function(){var a;return a=function(){return{x:0,y:1}},{restrict:"E",require:"^d3Chart",link:function(b,c,d,e){var f,g,h,i,j,k,l;return i=angular.extend(a(),d),k=e.getScale(i.xscale||i.x),l=e.getScale(i.yscale||i.y),f=e.innerHeight(),g=d3.svg.line().x(function(a){return k(a[i.x])}).y(function(a){return l(a[i.y])}),h=null,j=function(a){return h||(h=e.getChart().append("path").attr("class","line line-"+(i.name||i.y)).style("fill","none").style("stroke",i.stroke)),null!=a&&0!==a.length?h.datum(a).transition().duration(500).attr("d",g):void 0},e.registerElement(j,i.order)}}})}.call(this),function(){angular.module("ad3").directive("d3Pie",function(){var a;return a=function(){return{x:0,y:1,innerRadius:0,labelRadius:.7,transition:"cubic-in-out",transitionDuration:800,minOffset:12,value:"value"}},{restrict:"E",require:"^d3Chart",link:function(b,c,d,e){var f,g,h,i,j,k,l,m,n;return k=angular.extend(a(),d),g=e.getChart(),i=parseFloat(k.innerRadius),j=parseFloat(k.labelRadius),d.colors&&(h=function(){switch(d.colors){case"category20":return d3.scale.category20();case"category20b":return d3.scale.category20b();case"category20c":return d3.scale.category20c()}}()),l=d3.layout.pie().sort(null).value(function(a){return a[k.value]}),n=null,f=null,m=function(a){var b,c,g,m,n,o,p,q,r;return f=e.getChart().append("g").attr("class","pie"),null!=a&&0!==a.length?(q=Math.min(e.innerWidth(),e.innerHeight())/2,f.attr("transform","translate("+q+","+q+")"),b=d3.svg.arc().outerRadius(q).innerRadius(q*i),c=function(a){var c;return c=d3.interpolate(this._current,a),this._current=c(0),function(a){return b(c(a))}},n=d3.svg.arc().outerRadius(q*j).innerRadius(q*j),r=f.selectAll(".pie").data(l(a)),r.enter().append("path").attr("class",function(a,b){return"pie pie-"+b}).attr("d",b).each(function(a){return this._current=a}),d.colors&&r.style("fill",function(a,b){return h?h(b):a[d.color]}),r.exit().remove(),r.transition().ease(k.transition).duration(k.transitionDuration).attrTween("d",c),k.label?(p=null,o=+k.minOffset,g=function(a){var b,c,d,e,f,g,h,i,l;return h=n.centroid(a),k.avoidCollisions&&(i=[h[0],h[1]],this._position&&(i[0]-=this._position[0],i[1]-=this._position[1]),l=_.transform(this.getBoundingClientRect(),function(a,b,c){switch(c){case"left":return a[c]=b-o+i[0];case"top":return a[c]=b-o+i[1];case"right":return a[c]=b+o+i[0];case"bottom":return a[c]=b+o+i[1]}}),!p||l.rightp.right||l.bottomp.bottom||(d=l.left+(l.right-l.left)/2,e=l.top+(l.bottom-l.top)/2,b=p.left+(p.right-p.left)/2,c=p.top+(p.bottom-p.top)/2,f=Math.sqrt(Math.pow(d-b,2)+Math.pow(e-c,2))/2,g=d3.svg.arc().outerRadius(q*j+f).innerRadius(q*j+f),h=g.centroid(a)),this._position=h,p=l),"translate("+h+")"},m=f.selectAll("text").data(l(a)),m.enter().append("text").style("text-anchor","middle").attr("class",function(a,b){return"pie-label pie-label-"+b}),m.exit().remove(),m.text(function(b,c){return a[c][k.label]}),m.transition().ease(k.transition).duration(k.transitionDuration).attr("transform",g)):void 0):void 0},e.registerElement(m,k.order)}}})}.call(this),function(){angular.module("ad3").provider("d3Service",function(){var a;return a=this.defaults={},this.$get=["$cacheFactory","$rootScope","$q",function(b,c,d){var e;return e=a.cache||b("d3Service"),{csv:function(a,b,f){var g,h;return h=d.defer(),g=e.get(a),g&&(f&&f(rows),h.resolve(g)),d3.csv(a,b,function(b){return c.$apply(function(){return f&&f(b),b?(e.put(a,b),h.resolve(b)):h.reject()})}),h.promise}}}],this})}.call(this); \ No newline at end of file +!function(){angular.module("ad3",[])}.call(this),function(){angular.module("ad3").directive("d3Arc",function(){var a;return a=function(){return{x:0,y:1,innerRadius:0,labelRadius:0,transition:"cubic-in-out",transitionDuration:1e3,value:"value",label:"label"}},{restrict:"E",require:"^d3Chart",link:function(b,c,d,e){var f,g,h,i,j,k,l,m;return l=angular.extend(a(),d),i=e.getChart(),j=parseFloat(l.innerRadius),k=parseFloat(l.labelRadius),h=null,g=null,f=null,m=function(a){var b,c,d,i;return h||(h=e.getChart().append("g").attr("class","arc")),g||(g=h.append("path")),f||(f=h.append("text").attr("class","arc-label").attr("dy","0.35em").style("text-anchor","middle")),null!=a&&0!==a.length?(i=Math.min(e.innerWidth,e.innerHeight)/2,h.attr("transform","translate("+i+","+i+")"),b=d3.svg.arc().outerRadius(i).innerRadius(i*j).startAngle(0).endAngle(function(a){return 2*(a/100)*Math.PI}),c=function(a){var c;return null==this._current&&(this._current=0),c=d3.interpolate(this._current,a),this._current=a,function(a){return b(c(a))}},d=d3.svg.arc().outerRadius(i*k).innerRadius(i*k),g.datum(a[l.value]).transition().ease(l.transition).duration(l.transitionDuration).attrTween("d",c),f.text(a[l.label])):void 0},e.registerElement(m,l.order)}}})}.call(this),function(){angular.module("ad3").directive("d3Area",function(){var a;return a=function(){return{}},{restrict:"E",require:"^d3Chart",link:function(b,c,d,e){var f,g,h,i,j,k,l;return i=angular.extend(a(),d),k=e.getScale(i.xscale||i.x),l=e.getScale(i.yscale||i.y),i.vertical?(f=d3.svg.area().y(function(a){return k(a.x)}).x0(0).x1(function(a){return l(a.y)}),h=d3.svg.area().y(function(a){return k(a.x)}).x0(function(a){return l(a.y0)}).x1(function(a){return l(a.y+a.y0)})):(f=d3.svg.area().x(function(a){return k(a.x)}).y0(e.innerHeight).y1(function(a){return l(a.y)}),h=d3.svg.area().x(function(a){return k(a.x)}).y0(function(a){return l(a.y0)}).y1(function(a){return l(a.y+a.y0)})),g=null,j=function(a){var c,d,j,k,l,m,n;return g||(g=e.getChart().append("g").attr("class","area")),null!=a&&0!==a.length&&(null!=i.y&&(d=i.y),null!=i.columns&&(d=b.$eval(i.columns)),null!=d&&(angular.isString(d)&&(d=d.split(",").map(function(a){return a.trim()})),0!==d.length))?(j=function(){var b,c,e;for(e=[],b=0,c=d.length;c>b;b++)k=d[b],e.push({name:k,values:function(){var b,c,d;for(d=[],b=0,c=a.length;c>b;b++)n=a[b],d.push({x:n[i.x],y:n[k]});return d}()});return e}(),l=d3.layout.stack().values(function(a){return a.values}),null!=i.offset&&l.offset(i.offset),m=l(j),c=g.selectAll("path.area").data(m),c.enter().append("path"),c.attr("class",function(a){return"area "+a.name}).transition().duration(500).attr("d",function(a,b){return 0===b?f(a.values):h(a.values)}),c.exit().attr("d",function(a,b){return 0===b?f(a.values):h(a.values)}).remove()):void 0},null!=i.columns&&b.$watch(i.columns,e.redraw,!0),e.registerElement(j,i.order)}}})}.call(this),function(){angular.module("ad3").directive("d3Axis",function(){var a;return a=function(){return{orientation:"bottom",ticks:"5",extent:!1}},{priority:1,restrict:"E",require:"^d3Chart",link:function(b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q,r;return l=angular.extend(a(),d),n=function(){return"top"===l.orientation||"bottom"===l.orientation?null!=l.reverse?[e.innerWidth,0]:[0,e.innerWidth]:null!=l.reverse?[0,e.innerHeight]:[e.innerHeight,0]},q=function(){return"bottom"===l.orientation?"translate(0, "+e.innerHeight+")":"top"===l.orientation?"translate(0, 0)":"left"===l.orientation?"translate(0, 0)":"right"===l.orientation?"translate("+e.innerWidth+", 0)":void 0},p="time"===l.scale?d3.time.scale():l.scale?d3.scale[l.scale]():d3.scale.linear(),i=function(){var a,c,d;return a=d3.svg.axis().scale(p).orient(l.orientation),l.ticks&&a.ticks(l.ticks),l.timeScale&&a.ticks(d3.time[l.timeScale],l.timeInterval),l.tickValues&&a.tickValues(b.$eval(l.tickValues)),l.tickSize&&(d=l.tickSize.split(","),a.innerTickSize(d[0]),a.outerTickSize(d[1])),null!=l.format&&(c=d3.format(l.format),a.tickFormat(c)),null!=l.timeFormat&&(c=d3.time.format(l.timeFormat),a.tickFormat(function(a){return c(new Date(a))})),a},m=function(a){return"bottom"===l.orientation?a.attr("x",""+e.innerWidth/2).attr("dy",""+e.margin.bottom).attr("style","text-anchor: middle;"):"top"===l.orientation?a.attr("x",""+e.innerWidth/2).attr("dy",""+-e.margin.top).attr("style","text-anchor: middle;"):"left"===l.orientation?a.attr("x","-"+e.innerHeight/2).attr("dy",""+(-e.margin.left+18)).attr("style","text-anchor: middle;").attr("transform","rotate(-90)"):"right"===l.orientation?a.attr("x",""+e.innerHeight/2).attr("dy",""+(-e.margin.right+18)).attr("style","text-anchor: middle;").attr("transform","rotate(90)"):void 0},h=function(a){return"bottom"===l.orientation?a.call(i().tickSize(e.innerHeight,0,0).tickFormat("")):"top"===l.orientation?a.attr("transform","translate(0, "+e.innerHeight+")").call(i().tickSize(e.innerHeight,0,0).tickFormat("")):"left"===l.orientation?a.attr("transform","translate("+e.innerWidth+", 0)").call(i().tickSize(e.innerWidth,0,0).tickFormat("")):"right"===l.orientation?a.call(i().tickSize(e.innerWidth,0,0).tickFormat("")):void 0},f=function(a){var b,c,d;return d=a.selectAll(".tick text"),l.tickDy&&d.attr("dy",l.tickDy),l.tickDx&&d.attr("dx",l.tickDx),l.tickAnchor&&d.style("text-anchor",l.tickAnchor),c=d3.select(d[0].slice(-1)[0]),l.lastTickDy&&c.attr("dy",l.lastTickDy),l.lastTickDx&&c.attr("dx",l.lastTickDx),l.lastTickAnchor&&c.style("text-anchor",l.lastTickAnchor),b=d3.select(d[0][0]),l.firstTickDy&&b.attr("dy",l.firstTickDy),l.firstTickDx&&b.attr("dx",l.firstTickDx),l.listTickAnchor?b.style("text-anchor",l.firstTickAnchor):void 0},g=null,j=null,k=null,o=function(a){var b;return g||(g=e.getChart().append("g").attr("class","axis axis-"+l.orientation+" axis-"+l.name).attr("transform",q())),l.label&&(k||(k=g.append("text").attr("class","axis-label").text(l.label))),l.grid&&(j||(j=e.getChart().append("g").attr("class","axis-grid axis-grid-"+l.name))),null!=a&&0!==a.length?(k&&m(k.transition().duration(500)),g.transition().duration(500).attr("transform",q()).call(i()).selectAll("tick text").tween("attr.dx",null).tween("attr.dy",null).tween("style.text-anchor",null),null!=j&&h(j.transition().duration(500)),b=g.selectAll(".tick text"),g.call(f)):void 0},r=function(a){var c,d;if(null!=a&&0!==a.length)return p.range(n()),l.domain,d=l.filter?b.$eval(""+l.filter+"(data)",{data:a}):function(){var b,d,e;for(e=[],b=0,d=a.length;d>b;b++)c=a[b],e.push(c[l.name]);return e}(),l.extent?p.domain(d3.extent(d)):p.domain([0,d3.max(d)])},e.addScale(l.name,p,r),e.registerElement(o,l.order),null!=l.tickValues?b.$watch(l.tickValues,e.redraw,!0):void 0}}})}.call(this),function(){angular.module("ad3").directive("d3Bars",function(){var a;return a=function(){return{x:0,y:1,width:15}},{restrict:"E",require:"^d3Chart",link:function(b,c,d,e){var f,g,h,i,j,k,l,m;return i=angular.extend(a(),d),l=e.getScale(i.xscale||i.x),m=e.getScale(i.yscale||i.y),g=e.getChart(),h=e.innerHeight,k=i.width,f=null,j=function(a){var b;return f||(f=e.getChart().append("g").attr("class","bars")),null!=a&&0!==a.length?(b=f.selectAll("rect.bar").data(a),b.exit().transition().duration(500).attr("y",function(){return h}).attr("height",0).remove(),b.transition().duration(500).attr("x",function(a){return l(a[i.x])-k/2}).attr("y",function(a){return m(a[i.y])}).attr("height",function(a){return h-m(a[i.y])}).attr("width",k),b.enter().append("rect").attr("class",function(a,b){return"bar bar-"+b}).attr("x",function(a){return l(a[i.x])-k/2}).attr("width",k).attr("y",h).attr("height",0).transition().duration(500).attr("y",function(a){return m(a[i.y])}).attr("height",function(a){return h-m(a[i.y])})):void 0},e.registerElement(j,i.order)}}})}.call(this),function(){angular.module("ad3").directive("d3Chart",function(){return{restrict:"EA",scope:!0,controller:["$scope","$element","$attrs","$window","$timeout",function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p=this;k=a.scales={},i=a.elements=[],f=a.binding=c.data,this.margin=a.$eval(c.margin)||{top:10,right:10,bottom:10,left:10},m=d3.select(b[0]).append("svg").attr("class","d3").attr("width","100%").attr("height","100%"),o=function(){return b[0].offsetWidth},j=function(){return b[0].offsetHeight},g=m.append("g").attr("transform","translate("+this.margin.left+","+this.margin.top+")"),this.getSvg=function(){return m},this.getChart=function(){return g},this.addScale=function(a,b,c){return k[a]={scale:b,update:c}},this.getScale=function(a){return k[a].scale},this.registerElement=function(a,b){return null==b&&(b=0),i.push({redraw:a,order:Number(b)})},n=function(){return p.width!==o()||p.height!==j()?(p.width=o(),p.height=j(),p.innerWidth=p.width-p.margin.left-p.margin.right,p.innerHeight=p.height-p.margin.top-p.margin.bottom,p.redraw()):void 0},l=function(a,b){return a.order-b.order},h=null,this.redraw=function(){return h||0===p.width||0===p.height?void 0:h=e(function(){var b,c,d,e,g,j,m,n;h=null,b=a.$eval(f);for(d in k)e=k[d],e.update(b);for(m=i.sort(l),n=[],g=0,j=m.length;j>g;g++)c=m[g],n.push(c.redraw(b));return n},c.updateInterval||200)},d.addEventListener("resize",n),"deep"===c.watch?a.$watch(f,this.redraw,!0):a.$watch(f,this.redraw),a.$watch(n),n()}]}})}.call(this),function(){angular.module("ad3").directive("d3Data",["d3Service",function(a){return{restrict:"E",scope:!1,link:function(b,c,d){var e,f,g,h;return h=d.src,f=d.data,d.accessor&&(e=b.$eval(d.accessor)),d.callback&&(g=b.$eval(d.callback)),a.csv(h,e,g).then(function(a){return b[f]=a},function(){throw"Error loading CSV via D3"})}}}])}.call(this),function(){angular.module("ad3").directive("d3Gradient",function(){var a;return a={transition:500},{restrict:"E",require:"^d3Chart",link:function(b,c,d,e){var f,g,h;return g=e.getSvg(),f=g.insert("defs","g").append("linearGradient").attr("id",d.ref),["x1","x2","y1","y2"].forEach(function(a){return d.$observe(a,function(b){return f.attr(a,b)})}),h=a.transition,d.$observe("transition",function(a){return null!=a?h=a:void 0}),b.$watch(d.stops,function(a){return null!=a?(a=f.selectAll("stop").data(a),a.enter().append("stop"),a.attr("offset",function(a){return a.offset}).attr("stop-color",function(a){return a.color}).attr("stop-opacity",function(a){return null!=a.opacity?a.opacity:1}),a.exit().remove()):void 0})}}})}.call(this),function(){angular.module("ad3").directive("d3Include",function(){return{restrict:"E",require:"^d3Chart",link:function(a,b,c,d){var e,f;return e=d.getChart(),f=e.append("g").attr("class","includes"),f.html(b.html())}}})}.call(this),function(){angular.module("ad3").directive("d3Line",function(){var a;return a=function(){return{x:0,y:1}},{restrict:"E",require:"^d3Chart",link:function(b,c,d,e){var f,g,h,i,j,k,l;return i=angular.extend(a(),d),k=e.getScale(i.xscale||i.x),l=e.getScale(i.yscale||i.y),f=e.innerHeight,g=d3.svg.line().x(function(a){return k(a[i.x])}).y(function(a){return l(a[i.y])}),h=null,j=function(a){return h||(h=e.getChart().append("path").attr("class","line line-"+(i.name||i.y)).style("fill","none").style("stroke",i.stroke)),null!=a&&0!==a.length?h.datum(a).transition().duration(500).attr("d",g):void 0},e.registerElement(j,i.order)}}})}.call(this),function(){angular.module("ad3").directive("d3Pie",function(){var a;return a=function(){return{x:0,y:1,innerRadius:0,labelRadius:.7,transition:"cubic-in-out",transitionDuration:800,minOffset:12,value:"value"}},{restrict:"E",require:"^d3Chart",link:function(b,c,d,e){var f,g,h,i,j,k,l,m,n;return k=angular.extend(a(),d),g=e.getChart(),i=parseFloat(k.innerRadius),j=parseFloat(k.labelRadius),d.colors&&(h=function(){switch(d.colors){case"category20":return d3.scale.category20();case"category20b":return d3.scale.category20b();case"category20c":return d3.scale.category20c()}}()),l=d3.layout.pie().sort(null).value(function(a){return a[k.value]}),n=null,f=null,m=function(a){var b,c,g,m,n,o,p,q,r;return f||(f=e.getChart().append("g").attr("class","pie")),null!=a&&0!==a.length?(q=Math.min(e.innerWidth,e.innerHeight)/2,f.attr("transform","translate("+q+","+q+")"),b=d3.svg.arc().outerRadius(q).innerRadius(q*i),c=function(a){var c;return c=d3.interpolate(this._current,a),this._current=c(0),function(a){return b(c(a))}},n=d3.svg.arc().outerRadius(q*j).innerRadius(q*j),r=f.selectAll(".pie").data(l(a)),r.enter().append("path").attr("class",function(a,b){return"pie pie-"+b}).attr("d",b).each(function(a){return this._current=a}),d.colors&&r.style("fill",function(a,b){return h?h(b):a[d.color]}),r.exit().remove(),r.transition().ease(k.transition).duration(k.transitionDuration).attrTween("d",c),k.label?(p=null,o=+k.minOffset,g=function(a){var b,c,d,e,f,g,h,i,l;return h=n.centroid(a),k.avoidCollisions&&(i=[h[0],h[1]],this._position&&(i[0]-=this._position[0],i[1]-=this._position[1]),l=_.transform(this.getBoundingClientRect(),function(a,b,c){switch(c){case"left":return a[c]=b-o+i[0];case"top":return a[c]=b-o+i[1];case"right":return a[c]=b+o+i[0];case"bottom":return a[c]=b+o+i[1]}}),!p||l.rightp.right||l.bottomp.bottom||(d=l.left+(l.right-l.left)/2,e=l.top+(l.bottom-l.top)/2,b=p.left+(p.right-p.left)/2,c=p.top+(p.bottom-p.top)/2,f=Math.sqrt(Math.pow(d-b,2)+Math.pow(e-c,2))/2,g=d3.svg.arc().outerRadius(q*j+f).innerRadius(q*j+f),h=g.centroid(a)),this._position=h,p=l),"translate("+h+")"},m=f.selectAll("text").data(l(a)),m.enter().append("text").style("text-anchor","middle").attr("class",function(a,b){return"pie-label pie-label-"+b}),m.exit().remove(),m.text(function(b,c){return a[c][k.label]}),m.transition().ease(k.transition).duration(k.transitionDuration).attr("transform",g)):void 0):void 0},e.registerElement(m,k.order)}}})}.call(this),function(){angular.module("ad3").provider("d3Service",function(){var a;return a=this.defaults={},this.$get=["$cacheFactory","$rootScope","$q",function(b,c,d){var e;return e=a.cache||b("d3Service"),{csv:function(a,b,f){var g,h;return h=d.defer(),g=e.get(a),g&&(f&&f(rows),h.resolve(g)),d3.csv(a,b,function(b){return c.$apply(function(){return f&&f(b),b?(e.put(a,b),h.resolve(b)):h.reject()})}),h.promise}}}],this})}.call(this); \ No newline at end of file diff --git a/app/index.html b/app/index.html index bca153b..afd8349 100644 --- a/app/index.html +++ b/app/index.html @@ -31,6 +31,7 @@

Anguar D3

A set of basic directives that support declarative charts and graphs powered by D3

+

Get the source on Github

diff --git a/app/scripts/controllers/main.coffee b/app/scripts/controllers/main.coffee index 009c397..85cc284 100644 --- a/app/scripts/controllers/main.coffee +++ b/app/scripts/controllers/main.coffee @@ -9,19 +9,19 @@ angular.module('angularD3App').controller 'MainCtrl', ($scope, $interval) -> $interval -> val = Math.random() * 100 $scope.arcs.arc1 = { value: val, label: "#{val.toFixed(0)}%" } - , 1000 * 2 + , 1000 * 5 $interval -> val = Math.random() * 100 $scope.arcs.arc2 = { value: val, label: "#{val.toFixed(0)}%" } - , 1000 * 2.5 + , 1000 * 5 $interval -> if $scope.columns.length == 3 $scope.columns = ['savings', 'optimal'] else $scope.columns = ['savings', 'total', 'optimal'] - , 1000 * 2.5 + , 1000 * 10 $scope.stackDomain = (data) -> values = for value in data diff --git a/bower.json b/bower.json index 5bcc239..b937de1 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "angularD3", - "version": "0.0.24", + "version": "0.0.27", "main": "angularD3.js", "ignore": [ ".*", diff --git a/package.json b/package.json index 911ac36..c9cd282 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "angular-d3", - "version": "0.0.25", + "version": "0.0.27", "dependencies": {}, "devDependencies": { "grunt": "~0.4.1", diff --git a/src/angularD3/directives/arc.coffee b/src/angularD3/directives/arc.coffee index 4503018..ff77296 100644 --- a/src/angularD3/directives/arc.coffee +++ b/src/angularD3/directives/arc.coffee @@ -33,7 +33,7 @@ angular.module('ad3').directive 'd3Arc', -> return unless data? and data.length isnt 0 - radius = Math.min(chartController.innerWidth(), chartController.innerHeight())/2 + radius = Math.min(chartController.innerWidth, chartController.innerHeight)/2 center.attr("transform", "translate(" + radius + "," + radius + ")") diff --git a/src/angularD3/directives/axis.coffee b/src/angularD3/directives/axis.coffee index 3b2ba59..2c913b9 100644 --- a/src/angularD3/directives/axis.coffee +++ b/src/angularD3/directives/axis.coffee @@ -14,24 +14,24 @@ angular.module('ad3').directive 'd3Axis', -> range = -> if options.orientation is 'top' or options.orientation is 'bottom' if options.reverse? - [chartController.innerWidth(), 0] + [chartController.innerWidth, 0] else - [0 ,chartController.innerWidth()] + [0 ,chartController.innerWidth] else if options.reverse? - [0, chartController.innerHeight()] + [0, chartController.innerHeight] else - [chartController.innerHeight(), 0] + [chartController.innerHeight, 0] translation = -> if options.orientation is 'bottom' - "translate(0, #{chartController.innerHeight()})" + "translate(0, #{chartController.innerHeight})" else if options.orientation is 'top' "translate(0, 0)" else if options.orientation is 'left' "translate(0, 0)" else if options.orientation is 'right' - "translate(#{chartController.innerWidth()}, 0)" + "translate(#{chartController.innerWidth}, 0)" if options.scale is 'time' scale = d3.time.scale() @@ -62,41 +62,41 @@ angular.module('ad3').directive 'd3Axis', -> positionLabel = (label) -> if options.orientation is 'bottom' - label.attr("x", "#{chartController.innerWidth() / 2}") + label.attr("x", "#{chartController.innerWidth / 2}") .attr("dy", "#{chartController.margin.bottom}") .attr("style", "text-anchor: middle;") else if options.orientation is 'top' - label.attr("x", "#{chartController.innerWidth() / 2}") + label.attr("x", "#{chartController.innerWidth / 2}") .attr("dy", "#{-chartController.margin.top}") .attr("style", "text-anchor: middle;") else if options.orientation is 'left' - label.attr("x", "-#{chartController.innerHeight() / 2}") + label.attr("x", "-#{chartController.innerHeight / 2}") .attr("dy", "#{-chartController.margin.left + 18}") .attr("style", "text-anchor: middle;") .attr("transform", "rotate(-90)") else if options.orientation is 'right' - label.attr("x", "#{chartController.innerHeight() / 2}") + label.attr("x", "#{chartController.innerHeight / 2}") .attr("dy", "#{-chartController.margin.right + 18}") .attr("style", "text-anchor: middle;") .attr("transform", "rotate(90)") drawGrid = (grid) -> if options.orientation is 'bottom' - grid.call(getAxis().tickSize(chartController.innerHeight(), 0, 0) + grid.call(getAxis().tickSize(chartController.innerHeight, 0, 0) .tickFormat('') ) else if options.orientation is 'top' - grid.attr("transform", "translate(0, #{chartController.innerHeight()})") - .call(getAxis().tickSize(chartController.innerHeight(), 0, 0) + grid.attr("transform", "translate(0, #{chartController.innerHeight})") + .call(getAxis().tickSize(chartController.innerHeight, 0, 0) .tickFormat('') ) else if options.orientation is 'left' - grid.attr("transform", "translate(#{chartController.innerWidth()}, 0)") - .call(getAxis().tickSize(chartController.innerWidth(), 0, 0) + grid.attr("transform", "translate(#{chartController.innerWidth}, 0)") + .call(getAxis().tickSize(chartController.innerWidth, 0, 0) .tickFormat('') ) else if options.orientation is 'right' - grid.call(getAxis().tickSize(chartController.innerWidth(), 0, 0) + grid.call(getAxis().tickSize(chartController.innerWidth, 0, 0) .tickFormat('') ) diff --git a/src/angularD3/directives/bars.coffee b/src/angularD3/directives/bars.coffee index 36bcc42..e840de4 100644 --- a/src/angularD3/directives/bars.coffee +++ b/src/angularD3/directives/bars.coffee @@ -14,7 +14,7 @@ angular.module('ad3').directive 'd3Bars', -> y = chartController.getScale(options.yscale or options.y) chart = chartController.getChart() - height = chartController.innerHeight() + height = chartController.innerHeight width = options.width barsElements = null diff --git a/src/angularD3/directives/chart.coffee b/src/angularD3/directives/chart.coffee index 96e323c..18c4188 100644 --- a/src/angularD3/directives/chart.coffee +++ b/src/angularD3/directives/chart.coffee @@ -14,10 +14,8 @@ angular.module('ad3').directive 'd3Chart', -> .attr("height", "100%") # Used to calculated widths based on SVG margins - @width = -> $el[0].offsetWidth - @height = -> $el[0].offsetHeight - @innerWidth = => @width() - @margin.left - @margin.right - @innerHeight = => @height() - @margin.top - @margin.bottom + width = -> $el[0].offsetWidth + height = -> $el[0].offsetHeight chart = svg.append("g") .attr("transform", "translate(" + @margin.left + "," + @margin.top + ")") @@ -28,10 +26,20 @@ angular.module('ad3').directive 'd3Chart', -> @getScale = (name) -> scales[name].scale @registerElement = (el, order = 0) -> elements.push { redraw: el, order: Number(order) } + updateSize = => + if @width != width() or @height != height() + @width = width() + @height = height() + @innerWidth = @width - @margin.left - @margin.right + @innerHeight = @height - @margin.top - @margin.bottom + # Redraw if the chart size has changed + @redraw() + sortOrder = (a, b) -> a.order - b.order debounce = null - @redraw = -> - return if debounce + @redraw = => + # We don't bother to redraw if the chart isn't visible + return if debounce or @width is 0 or @height is 0 debounce = $timeout => debounce = null data = $scope.$eval(binding) @@ -40,11 +48,19 @@ angular.module('ad3').directive 'd3Chart', -> for element in elements.sort(sortOrder) element.redraw(data) , $attrs.updateInterval or 200 - $window.addEventListener 'resize', @redraw + + $window.addEventListener 'resize', updateSize + if $attrs.watch is 'deep' $scope.$watch binding, @redraw, true else $scope.$watch binding, @redraw + # We check the size on all scope events since scope can affect chart + # visibility and if the chart area is resized while not visible it won't + # update. + $scope.$watch updateSize + + updateSize() return ] diff --git a/src/angularD3/directives/line.coffee b/src/angularD3/directives/line.coffee index 98d407b..774aa83 100644 --- a/src/angularD3/directives/line.coffee +++ b/src/angularD3/directives/line.coffee @@ -11,7 +11,7 @@ angular.module('ad3').directive 'd3Line', -> options = angular.extend(defaults(), attrs) x = chartController.getScale(options.xscale or options.x) y = chartController.getScale(options.yscale or options.y) - height = chartController.innerHeight() + height = chartController.innerHeight line = d3.svg.line() .x((d) -> x(d[options.x])) diff --git a/src/angularD3/directives/pie.coffee b/src/angularD3/directives/pie.coffee index 8301f5a..dec561e 100644 --- a/src/angularD3/directives/pie.coffee +++ b/src/angularD3/directives/pie.coffee @@ -36,11 +36,11 @@ angular.module('ad3').directive 'd3Pie', -> center = null redraw = (data) -> - center = chartController.getChart().append("g").attr("class", "pie") + center ||= chartController.getChart().append("g").attr("class", "pie") return unless data? and data.length isnt 0 - radius = Math.min(chartController.innerWidth(), chartController.innerHeight())/2 + radius = Math.min(chartController.innerWidth, chartController.innerHeight)/2 center.attr("transform", "translate(" + radius + "," + radius + ")")