From: Stas Vilchik Date: Wed, 11 Dec 2013 09:30:16 +0000 (+0600) Subject: Pie Chart mock X-Git-Tag: 4.2~1023 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=c9097cd1b6273d7b7f7156067118b9e92bb9c059;p=sonarqube.git Pie Chart mock --- diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/mock/example_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/mock/example_controller.rb index 0a3ce7fdd42..a2ec5634dbb 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/mock/example_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/mock/example_controller.rb @@ -33,5 +33,9 @@ class Mock::ExampleController < Api::ApiController "foo": "bar" } RESPONSE - end + end + + def pie_chart + + end end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_head.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_head.html.erb index 09c3d3152d4..a1fd777877a 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_head.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_head.html.erb @@ -50,6 +50,7 @@ <%= javascript_include_tag 'widgets/bubble-chart' %> <%= javascript_include_tag 'widgets/timeline' %> <%= javascript_include_tag 'widgets/stack-area' %> + <%= javascript_include_tag 'widgets/pie-chart' %> <%= javascript_include_tag 'select-list' %> diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/mock/example/pie_chart.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/mock/example/pie_chart.html.erb new file mode 100644 index 00000000000..f6dfdea0c02 --- /dev/null +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/mock/example/pie_chart.html.erb @@ -0,0 +1,80 @@ +
+ + diff --git a/sonar-server/src/main/webapp/javascripts/widgets/pie-chart.js b/sonar-server/src/main/webapp/javascripts/widgets/pie-chart.js new file mode 100644 index 00000000000..4bb174b4382 --- /dev/null +++ b/sonar-server/src/main/webapp/javascripts/widgets/pie-chart.js @@ -0,0 +1,275 @@ +/*global d3:false, baseUrl:false */ +/*jshint eqnull:true */ + +window.SonarWidgets = window.SonarWidgets == null ? {} : window.SonarWidgets; + +(function () { + + window.SonarWidgets.PieChart = function () { + // Set default values + this._data = []; + this._metrics = []; + this._width = window.SonarWidgets.PieChart.defaults.width; + this._height = window.SonarWidgets.PieChart.defaults.height; + this._margin = window.SonarWidgets.PieChart.defaults.margin; + this._legendWidth = window.SonarWidgets.PieChart.defaults.legendWidth; + + this._lineHeight = 20; + + // Export global variables + this.data = function (_) { + return param.call(this, '_data', _); + }; + + this.metrics = function (_) { + return param.call(this, '_metrics', _); + }; + + this.width = function (_) { + return param.call(this, '_width', _); + }; + + this.height = function (_) { + return param.call(this, '_height', _); + }; + + this.margin = function (_) { + return param.call(this, '_margin', _); + }; + + this.legendWidth = function (_) { + return param.call(this, '_legendWidth', _); + }; + }; + + window.SonarWidgets.PieChart.prototype.render = function (container) { + var widget = this, + containerS = container; + + container = d3.select(container); + + this.width(container.property('offsetWidth')); + + this.svg = container.append('svg') + .attr('class', 'sonar-d3'); + this.gWrap = this.svg.append('g'); + + this.plotWrap = this.gWrap.append('g'); + + this.gWrap + .attr('transform', trans(this.margin().left, this.margin().top)); + + + // Configure scales + this.color = d3.scale.category20(); + + + // Configure arc + this.arc = d3.svg.arc() + .innerRadius(0); + + + // Configure pie + this.pie = d3.layout.pie() + .sort(null) + .value(function(d) { return d.metric; }); + + + // Configure sectors + this.sectors = this.plotWrap.selectAll('.arc') + .data(this.pie(this.data())) + .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.pie(this.data())) + .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.data.name; }); + + + // Configure details + this._detailsHeight = this._lineHeight * 4; + + this.detailsWrap = this.gWrap.append('g') + .attr('width', this.legendWidth()); + + this.detailsColorIndicator = this.detailsWrap.append('rect') + .classed('details-color-indicator', true) + .attr('x', 0) + .attr('y', 0) + .attr('width', 4) + .attr('height', this._detailsHeight) + .style('opacity', 0); + + this._detailsMetric = [ + { name: 'Technical Dept', value: 8.5 }, + { name: 'Lines of Code', value: 362 }, + { name: 'Issues', value: 3 }, + { name: 'Coverage', value: 86 } + ]; + + + // Configure events + var enterHandler = function(sector, legend, 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 + ')'); + + updateMetrics(widget._detailsMetric); + + 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') + .text(function(d) { return d.name + ': ' + d.value; }); + + widget.detailsMetrics + .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') + .style('opacity', 1); + }; + + this.legends + .on('mouseenter', function(d, i) { + return enterHandler(widget.sectors[0][i], this, 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], i); + }) + .on('mouseleave', function(d, i) { + return leaveHandler(this, widget.legends[0][i]); + }); + + + // Update widget + this.update(containerS); + + return this; + }; + + + + window.SonarWidgets.PieChart.prototype.update = function(container) { + container = d3.select(container); + + var widget = this, + width = container.property('offsetWidth'); + this.width(width > 100 ? width : 100); + + + // Update svg canvas + this.svg + .attr('width', this.width()) + .attr('height', this.height()); + + + // Update available size + this.availableWidth = this.width() - this.margin().left - this.margin().right - this.legendWidth(); + this.availableHeight = this.height() - this.margin().top - this.margin().bottom; + + + // Update radius + this.radius = Math.min(this.availableWidth - this.legendWidth(), this.availableHeight) / 2; + + + // Update plot + this.plotWrap + .attr('transform', trans(this.radius, this.radius)); + + + // Update arc + this.arc.outerRadius(this.radius); + + + // Update legend + this.legendWrap + .attr('transform', trans(20 + this.radius * 2, 0 )); + + + // Update details + this.detailsWrap + .attr('transform', trans(20 + this.radius * 2, this.availableHeight - this._detailsHeight )); + + + // Update sectors + this.sectors.selectAll('path') + .transition() + .attr('d', this.arc); + + this.sectors.selectAll('text') + .attr('transform', function(d) { return 'translate(' + widget.arc.centroid(d) + ')'; }); + }; + + + + window.SonarWidgets.PieChart.defaults = { + width: 350, + height: 300, + margin: { top: 10, right: 10, bottom: 10, left: 10 }, + legendWidth: 250 + }; + + + + // Some helper functions + + // Gets or sets parameter + function param(name, value) { + if (value == null) { + return this[name]; + } else { + this[name] = value; + return this; + } + } + + // Helper for create the translate(x, y) string + function trans(left, top) { + return 'translate(' + left + ', ' + top + ')'; + } + +})(); diff --git a/sonar-server/src/main/webapp/stylesheets/style.css b/sonar-server/src/main/webapp/stylesheets/style.css index c7830f16dce..ef70b94a716 100644 --- a/sonar-server/src/main/webapp/stylesheets/style.css +++ b/sonar-server/src/main/webapp/stylesheets/style.css @@ -2458,6 +2458,45 @@ textarea.width100 { opacity: 0.25; } +.sonar-d3 .arc { + cursor: pointer; + transition: all 0.2s ease; +} + +.sonar-d3 .arc-active { + -webkit-transform: scale(1.05); +} + +.sonar-d3 .legend { + cursor: pointer; +} + +.sonar-d3 .legend-bullet { + transition: all 0.2s ease; +} + +.sonar-d3 .legend-text { + font-size: 11px; +} + +.sonar-d3 .legend-active .legend-bullet { + -webkit-transform: scale(1.4); + -webkit-transform-origin: center; +} + +.sonar-d3 .details-color-indicator { + fill: #fff; + transition: all 0.2s ease; +} + +.sonar-d3 .details-metric { + font-size: 11px; +} + +.sonar-d3 .details-metric-main { + font-weight: bold; +} + .sonar-d3 .info { } diff --git a/sonar-server/wro.xml b/sonar-server/wro.xml index 215716a06c4..11c1ba2ebe4 100644 --- a/sonar-server/wro.xml +++ b/sonar-server/wro.xml @@ -30,6 +30,7 @@ /javascripts/widgets/bubble-chart.js /javascripts/widgets/timeline.js /javascripts/widgets/stack-area.js + /javascripts/widgets/pie-chart.js /javascripts/select-list.js