我有以下javascript:
/**
* Init
*/
var data = scope.dataset;
var outerWidth = scope.outerWidth;
var outerHeight = scope.outerHeight;
var margin = {
left: 130,
top: 0,
right: 0,
bottom: 30
};
var barPadding = 0.2;
var xColumn = scope.xColumn;
var yColumn = scope.yColumn;
var innerWidth = outerWidth - margin.left - margin.right;
var innerHeight = outerHeight - margin.top - margin.bottom;
var svg = d3.select("#chartArea").append("svg")
.attr("width", outerWidth)
.attr("height", outerHeight);
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([0, 0])
.html(function (d) {
return d[yColumn] + ": <span style='color:#008000'>" + d[xColumn];
});
var g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var xAxisG = g.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + innerHeight + ")");
var yAxisG = g.append("g")
.attr("class", "y axis");
var xScale = d3.scale.linear().range([0, innerWidth]);
var yScale = d3.scale.ordinal().rangeBands([0, innerHeight], barPadding);
var xAxis = d3.svg.axis().scale(xScale).orient("bottom")
.ticks(d3.max(data, function (d) {
return d[xColumn];
})) // Use approximately 5 ticks marks.
.tickFormat(d3.format("s")) // Use intelligent abbreviations, e.g. 5M for 5 Million
.outerTickSize(0); // Turn off the marks at the end of the axis.
var yAxis = d3.svg.axis().scale(yScale).orient("left")
.outerTickSize(1); // Turn off the marks at the end of the axis.
svg.call(tip);
/**
* Render function renders the chart with given data
* @param data
*/
function render(data) {
xScale.domain([0, d3.max(data, function (d) {
return d[xColumn];
})]);
yScale.domain(data.map(function (d) {
return d[yColumn];
}));
xAxisG.call(xAxis);
yAxisG.call(yAxis);
var bars = g.selectAll("rect").data(data);
bars.enter().append("rect")
.attr("height", yScale.rangeBand())
.attr('class', 'vertical_bar')
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
bars.transition()
.attr("x", 0)
.attr("y", function (d) {
return yScale(d[yColumn]);
})
.attr("width", function (d) {
return xScale(d[xColumn]);
});
bars.exit().remove();
}
/**
* Watchers for data change
*/
scope.$watch('xColumn', function (newValue, oldValue) {
if (newValue) {
xColumn = newValue;
}
}, true);
scope.$watch('yColumn', function (newValue, oldValue) {
if (newValue) {
yColumn = newValue;
}
}, true);
scope.$watch('dataset', function (newValue, oldValue) {
if (newValue) {
render(newValue);
}
}, true);
然而,当我运行此操作时,我收到以下错误:
Error: Invalid value for <rect> attribute width="NaN"
我真的看不出问题所在!
示例数据:{label: 'hello world', value: 5}
Xcolumn = null
这是我的完整代码:
app.controller('CompetenceOverviewController', ['$http', '$scope', '$sessionStorage', 'competenceStatService', '$log', 'Session', 'api', 'jobProfileService', 'divisionService', '$filter', function ($http, $scope, $sessionStorage, competenceStatService, $log, Session, api, jobProfileService, divisionService, $filter) {
$scope.xColumn = 'value';
$scope.yColumn = 'label';
$scope.dataSet = null;
$http.get(api.getUrl('aggregatedCompetences',[10,'gap'])).success(function(response){
var dataSet = [];
response.forEach(function (y) {
var obj = {label: y.title.name, value: y.average};
dataSet.push(obj);
});
$scope.dataSet = dataSet;
})
}]);
HTML
<vertical-bar-chart x-column="xColumn" y-column="yColumn" dataset="dataSet" outer-width="500" outer-height="500"></vertical-bar-chart>
指令
app.directive("verticalBarChart", ['LRM', '$sce', '$http', 'deviceDetector', function (LRM, $sce, $http, deviceDetector) {
return {
restrict: "E",
templateUrl: 'tpl/directives/lb-charts/vertical_bar_chart.html',
scope: {
outerWidth: '=',
outerHeight: '=',
xColumn: '=',
yColumn: '=',
dataset: '='
},
link: function (scope, element, attr) {
/**
* Init
*/
var data = scope.dataset;
var outerWidth = scope.outerWidth;
var outerHeight = scope.outerHeight;
var margin = {left: 130, top: 0, right: 0, bottom: 30};
var barPadding = 0.2;
var xColumn = scope.xColumn;
var yColumn = scope.yColumn;
var innerWidth = outerWidth - margin.left - margin.right;
var innerHeight = outerHeight - margin.top - margin.bottom;
var svg = d3.select("#chartArea").append("svg")
.attr("width", outerWidth)
.attr("height", outerHeight);
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([0, 0])
.html(function (d) {
return d[yColumn] + ": <span style='color:#008000'>" + d[xColumn];
});
var g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var xAxisG = g.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + innerHeight + ")");
var yAxisG = g.append("g")
.attr("class", "y axis");
var xScale = d3.scale.linear().range([0, innerWidth]);
var yScale = d3.scale.ordinal().rangeBands([0, innerHeight], barPadding);
var xAxis = d3.svg.axis().scale(xScale).orient("bottom")
.ticks(d3.max(data, function (d) {
return d[xColumn];
})) // Use approximately 5 ticks marks.
.tickFormat(d3.format("s")) // Use intelligent abbreviations, e.g. 5M for 5 Million
.outerTickSize(0); // Turn off the marks at the end of the axis.
var yAxis = d3.svg.axis().scale(yScale).orient("left")
.outerTickSize(1); // Turn off the marks at the end of the axis.
svg.call(tip);
/**
* Render function renders the chart with given data
* @param data
*/
function render(data) {
xScale.domain([0, d3.max(data, function (d) {
return d[xColumn];
})]);
yScale.domain(data.map(function (d) {
return d[yColumn];
}));
xAxisG.call(xAxis);
yAxisG.call(yAxis);
var bars = g.selectAll("rect").data(data);
bars.enter().append("rect")
.attr("height", yScale.rangeBand())
.attr('class', 'vertical_bar')
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
bars
.transition()
.attr("x", 0)
.attr("y", function (d) {
return yScale(d[yColumn]);
})
.attr("width", function (d) {
return xScale(d[xColumn]);
});
bars.exit().remove();
}
/**
* Watchers for data change
*/
scope.$watch('xColumn', function (newValue, oldValue) {
if (newValue) {
xColumn = newValue;
}
}, true);
scope.$watch('yColumn', function (newValue, oldValue) {
if (newValue) {
yColumn = newValue;
}
}, true);
scope.$watch('dataset', function (newValue, oldValue) {
if (newValue) {
if (xColumn == null) {
xColumn = scope.xColumn;
}
if (yColumn == null) {
yColumn = scope.yColumn;
}
render(newValue);
}
}, true);
}
};
}]);