this._height = window.SonarWidgets.PieChart.defaults.height;
this._margin = window.SonarWidgets.PieChart.defaults.margin;
this._legendWidth = window.SonarWidgets.PieChart.defaults.legendWidth;
+ this._legendMargin = window.SonarWidgets.PieChart.defaults.legendMargin;
+ this._detailsWidth = window.SonarWidgets.PieChart.defaults.detailsWidth;
this._lineHeight = 20;
this.legendWidth = function (_) {
return param.call(this, '_legendWidth', _);
};
+
+ this.legendMargin = function (_) {
+ return param.call(this, '_legendMargin', _);
+ };
+
+ this.detailsWidth = function (_) {
+ return param.call(this, '_detailsWidth', _);
+ };
};
window.SonarWidgets.PieChart.prototype.render = function (container) {
.attr('class', 'sonar-d3');
this.gWrap = this.svg.append('g');
- this.plotWrap = this.gWrap.append('g');
+ this.plotWrap = this.gWrap.append('g')
+ .classed('plot', true);
this.gWrap
.attr('transform', trans(this.margin().left, this.margin().top));
this.getMainMetric = function(d) {
return d.measures[widget.mainMetric].val;
};
+ this.fm = function(value, name) {
+ var type = this.metrics()[name].type;
+
+ switch (type) {
+ case 'FLOAT':
+ return d3.format('.1f')(value);
+ case 'INT':
+ return d3.format('d')(value);
+ default :
+ return value;
+ }
+ };
// Configure scales
- this.color = d3.scale.category20();
+ this.color = d3.scale.category10();
// Configure arc
.value(function(d) { return widget.getMainMetric(d); });
- // Configure sectors
- this.sectors = this.plotWrap.selectAll('.arc')
- .data(this.pie(this.components()))
- .enter().append('g').attr('class', 'arc');
-
- this.sectors.append('path')
- .style('fill', function(d, i) { return widget.color(i); });
-
-
- // Configure legend
- this.legendWrap = this.gWrap.append('g')
- .attr('width', this.legendWidth());
-
- this.legends = this.legendWrap.selectAll('.legend')
- .data(this.components());
-
- this.legends.enter().append('g')
- .attr('class', 'legend')
- .attr('transform', function(d, i) { return trans(0, 10 + i * widget._lineHeight); });
-
- this.legends.append('circle')
- .attr('class', 'legend-bullet')
- .attr('r', 4)
- .style('fill', function(d, i) { return widget.color(i); });
-
- this.legends.append('text')
- .attr('class', 'legend-text')
- .attr('transform', trans(10, 3))
- .text(function(d) { return d.name; });
-
-
// Configure details
- this._detailsHeight = this._lineHeight * 4;
+ this._metricsCount = Object.keys(this.metrics()).length + 1;
+ this._detailsHeight = this._lineHeight * this._metricsCount;
this.detailsWrap = this.gWrap.append('g')
.attr('width', this.legendWidth());
.attr('height', this._detailsHeight)
.style('opacity', 0);
-
- // Configure events
- var enterHandler = function(sector, legend, d, i) {
- var scaleFactor = (widget.radius + 5) / widget.radius;
- d3.select(legend)
- .classed('legend-active', true);
- d3.select(sector)
- .classed('arc-active', true)
- .style('-webkit-transform', 'scale(' + scaleFactor + ')');
-
- var metrics = widget.metricsPriority().map(function(m) {
- return {
- name: widget.metrics()[m].name,
- value: d.measures[m].val
- };
- });
- updateMetrics(metrics);
-
- widget.detailsColorIndicator
- .style('opacity', 1)
- .style('fill', widget.color(i));
- },
-
- leaveHandler = function(sector, legend) {
- d3.select(legend).classed('legend-active', false);
- d3.select(sector)
- .classed('arc-active', false)
- .style('-webkit-transform', 'scale(1)');
- widget.detailsColorIndicator
- .style('opacity', 0);
- widget.detailsMetrics
- .style('opacity', 0);
- },
-
- updateMetrics = function(metrics) {
-
- widget.detailsMetrics = widget.detailsWrap.selectAll('.details-metric')
- .data(metrics);
-
- widget.detailsMetrics.enter().append('text')
- .classed('details-metric', true)
- .classed('details-metric-main', function(d, i) { return i === 0; })
- .attr('transform', function(d, i) { return trans(10, i * widget._lineHeight); })
- .attr('dy', '1.2em');
-
- widget.detailsMetrics
- .text(function(d) { return d.name + ': ' + d.value; })
- .style('opacity', 1);
-
- widget.detailsMetrics.exit().remove();
- };
-
- this.legends
- .on('mouseenter', function(d, i) {
- return enterHandler(widget.sectors[0][i], this, d, i);
- })
- .on('mouseleave', function(d, i) {
- return leaveHandler(widget.sectors[0][i], this);
- });
-
- this.sectors
- .on('mouseenter', function(d, i) {
- return enterHandler(this, widget.legends[0][i], d.data, i);
- })
- .on('mouseleave', function(d, i) {
- return leaveHandler(this, widget.legends[0][i]);
- });
+ this.donutLabel = this.plotWrap.append('text')
+ .attr('dy', '0.35em')
+ .style('text-anchor', 'middle')
+ .style('opacity', 0);
// Update widget
// Update available size
- this.availableWidth = this.width() - this.margin().left - this.margin().right - this.legendWidth();
+ this.availableWidth = this.width() - this.margin().left - this.margin().right -
+ this.legendWidth() - this.legendMargin();
this.availableHeight = this.height() - this.margin().top - this.margin().bottom;
-
-
- // Update radius
this.radius = Math.min(this.availableWidth, this.availableHeight) / 2;
// Update arc
this.arc
+ .innerRadius(this.radius / 2)
.outerRadius(this.radius);
- // Update legend
- this.legendWrap
- .attr('transform', trans(20 + this.radius * 2, 0 ));
+ // Configure sectors
+ this.sectors = this.plotWrap.selectAll('.arc')
+ .data(this.pie(this.components()));
+
+ this.sectors
+ .enter()
+ .append('path')
+ .classed('arc', true)
+ .style('fill', function(d, i) { return widget.color(i); });
+
+ this.sectors
+ .transition()
+ .attr('d', this.arc);
+
+ this.sectors
+ .exit().remove();
// Update details
this.detailsWrap
- .attr('transform', trans(20 + this.radius * 2, this.availableHeight - this._detailsHeight ));
+ .attr('width', this.legendWidth())
+ .attr('transform', trans(
+ this.legendMargin() + 2 * this.radius, this.radius - this._detailsHeight / 2
+ ));
-
- // Update sectors
- this.sectors.selectAll('path')
+ this.donutLabel
.transition()
- .attr('d', this.arc);
+ .style('font-size', (this.radius / 6) + 'px');
+
+
+ // Configure events
+ var enterHandler = function(sector, d, i) {
+ var metrics = widget.metricsPriority().map(function(m) {
+ return {
+ name: widget.metrics()[m].name,
+ value: widget.fm(d.measures[m].val, m)
+ };
+ });
+ metrics.unshift({ name: d.name });
+ updateMetrics(metrics);
+
+ widget.donutLabel
+ .style('opacity', 1)
+ .text(widget.fm(widget.getMainMetric(d), widget.mainMetric));
+
+ widget.detailsColorIndicator
+ .style('opacity', 1)
+ .style('fill', widget.color(i));
+ },
+
+ leaveHandler = function() {
+ widget.detailsColorIndicator
+ .style('opacity', 0);
+ widget.detailsMetrics
+ .style('opacity', 0);
+ widget.donutLabel
+ .style('opacity', 0)
+ .text('');
+ },
+
+ updateMetrics = function(metrics) {
+
+ widget.detailsMetrics = widget.detailsWrap.selectAll('.details-metric')
+ .data(metrics);
+
+ widget.detailsMetrics.enter().append('text')
+ .classed('details-metric', true)
+ .classed('details-metric-main', function(d, i) { return i === 0; })
+ .attr('transform', function(d, i) { return trans(10, i * widget._lineHeight); })
+ .attr('dy', '1.2em');
+
+ widget.detailsMetrics
+ .text(function(d) { return d.name + (d.value ? ': ' + d.value : ''); })
+ .style('opacity', 1);
+
+ widget.detailsMetrics.exit().remove();
+ };
+
+ this.sectors
+ .on('mouseenter', function(d, i) {
+ return enterHandler(this, d.data, i);
+ })
+ .on('mouseleave', leaveHandler);
};
width: 350,
height: 300,
margin: { top: 10, right: 10, bottom: 10, left: 10 },
- legendWidth: 250
+ legendWidth: 160,
+ legendMargin: 30
};