Reputation: 345
I am trying to get a responsive nvd3 chart inside of an angular material grid. It seems to be working ok after I resize the window but does not go to the correct size at the initial load.
My approach was to wrap the nvd3 directive inside of a 'resize' directive. Then I could watch the parent element and update the chart's height and width on window resize. The problem I am running into is on load the parent div height and width properties seem to be 0. I tried using $timeout to apply the scope but this did not seem to work either.
angular.module('MyApp', ['ngMaterial', 'ngMessages', 'nvd3'])
.controller('AppCtrl', function($scope) {
$scope.options = {
chart: {
type: 'discreteBarChart',
height: 450,
margin: {
top: 20,
right: 20,
bottom: 50,
left: 55
},
x: function(d) {
return d.label;
},
y: function(d) {
return d.value + (1e-10);
},
showValues: true,
valueFormat: function(d) {
return d3.format(',.4f')(d);
},
duration: 500,
xAxis: {
axisLabel: 'X Axis'
},
yAxis: {
axisLabel: 'Y Axis',
axisLabelDistance: -10
}
}
};
$scope.data = [{
key: "Cumulative Return",
values: [{
"label": "A",
"value": -29.765957771107
}, {
"label": "B",
"value": 0
}, {
"label": "C",
"value": 32.807804682612
}, {
"label": "D",
"value": 196.45946739256
}, {
"label": "E",
"value": 0.19434030906893
}, {
"label": "F",
"value": -98.079782601442
}, {
"label": "G",
"value": -13.925743130903
}, {
"label": "H",
"value": -5.1387322875705
}]
}]
}).directive('resize', function($window, $timeout) {
var linker = function(scope, element, attrs) {
var w = angular.element($window);
w.bind('resize', function() {
scope.$apply();
})
$timeout(function(){
updateHeight();
updateWidth();
scope.$apply();
})
scope.$watch(function() {
return element.parent()[0].clientHeight;
}, updateHeight);
scope.$watch(function() {
return element.parent()[0].clientWidth;
}, updateWidth);
function updateHeight() {
scope.options.chart.height = element.parent()[0].clientHeight;
}
function updateWidth() {
scope.options.chart.width = element.parent()[0].clientWidth;
}
};
return {
template: '<div style="height100%;width:100%;"><nvd3 options="options" data="data"></nvd3></div>',
restrict: "E",
link: linker,
scope: {
data: '=',
options: '='
}
};
});
.gridListdemoBasicUsage md-grid-list {
margin: 8px; }
.gridListdemoBasicUsage .gray {
background: #f5f5f5; }
.gridListdemoBasicUsage .green {
background: #b9f6ca; }
.gridListdemoBasicUsage .yellow {
background: #ffff8d; }
.gridListdemoBasicUsage .blue {
background: #84ffff; }
.gridListdemoBasicUsage .purple {
background: #b388ff; }
.gridListdemoBasicUsage .red {
background: #ff8a80; }
.gridListdemoBasicUsage md-grid-tile {
transition: all 400ms ease-out 50ms; }
<div ng-controller="AppCtrl as appCtrl" ng-cloak="" class="gridListdemoBasicUsage" ng-app="MyApp">
<md-grid-list md-cols-xs="1" md-cols-sm="2" md-cols-md="4" md-cols-gt-md="6" md-row-height-gt-md="1:1" md-row-height="2:2" md-gutter="12px" md-gutter-gt-sm="8px">
<md-grid-tile class="gray" md-rowspan="3" md-colspan="2" md-colspan-sm="1">
<resize options="options" data="data"></resize>
<md-grid-tile-footer>
<h3>#1: (3r x 2c)</h3>
</md-grid-tile-footer>
</md-grid-tile>
<md-grid-tile class="green">
<md-grid-tile-footer>
<h3>#2: (1r x 1c)</h3>
</md-grid-tile-footer>
</md-grid-tile>
<md-grid-tile class="yellow">
<md-grid-tile-footer>
<h3>#3: (1r x 1c)</h3>
</md-grid-tile-footer>
</md-grid-tile>
<md-grid-tile class="blue" md-rowspan="2">
<md-grid-tile-footer>
<h3>#4: (2r x 1c)</h3>
</md-grid-tile-footer>
</md-grid-tile>
<md-grid-tile class="red" md-rowspan="2" md-colspan="2" md-colspan-sm="1">
<md-grid-tile-footer>
<h3>#5: (2r x 2c)</h3>
</md-grid-tile-footer>
</md-grid-tile>
<md-grid-tile class="green" md-rowspan="2">
<md-grid-tile-footer>
<h3>#6: (2r x 1c)</h3>
</md-grid-tile-footer>
</md-grid-tile>
</md-grid-list>
</div>
please check out this codepen.
Thanks in advance
Update: I found a solution for my app using Angular nvd3s api.updateWithOptions(options). Still not working in the codepen. Could be a version difference in the code pen will attach final solution shortly.
Upvotes: 0
Views: 1217
Reputation: 378
I had the same issue with angular-nvd3 and angular-material. I can not explain why this happen and it is already reported as bug since June 2016 (see https://github.com/krispo/angular-nvd3/issues/454).
However, I was able to fix it with a simple
angular.element(document).ready(function () {})
block around $scope.data.
This example works for me:
Controller
angular.module('app')
.controller('pieChartCtrl', function($scope){
$scope.options = {
chart: {
type: 'pieChart',
height: 500,
x: function(d){return d.key;},
y: function(d){return d.y;},
showLabels: true,
duration: 500,
labelThreshold: 0.01,
labelSunbeamLayout: true,
legend: {
margin: {
top: 5,
right: 35,
bottom: 5,
left: 0
}
}
}
};
angular.element(document).ready(function () {
$scope.data = [
{
key: "One",
y: 5
},
{
key: "Two",
y: 2
},
{
key: "Three",
y: 9
},
{
key: "Four",
y: 7
},
{
key: "Five",
y: 4
},
{
key: "Six",
y: 3
},
{
key: "Seven",
y: .5
}
];
});
})
View
<div ng-controller="pieChartCtrl">
<nvd3 options="options" data="data"></nvd3>
</div>
Upvotes: 1