summaryrefslogtreecommitdiffstats
path: root/sonar-server
diff options
context:
space:
mode:
authorStas Vilchik <vilchiks@gmail.com>2014-07-04 17:06:25 +0600
committerStas Vilchik <vilchiks@gmail.com>2014-07-04 17:06:34 +0600
commitbc7dddf031537bc5a658573c63f7bc9d73e633cb (patch)
tree8345e212e201be908d0fd635103e42e0f72566ae /sonar-server
parent0b07455499c27bd5d18acf8c5e59ab93ead4d11c (diff)
downloadsonarqube-bc7dddf031537bc5a658573c63f7bc9d73e633cb.tar.gz
sonarqube-bc7dddf031537bc5a658573c63f7bc9d73e633cb.zip
SONAR-5207 Treemap as a metric widget skeleton
Diffstat (limited to 'sonar-server')
-rw-r--r--sonar-server/Gruntfile.coffee2
-rw-r--r--sonar-server/src/main/coffee/widgets/base.coffee12
-rw-r--r--sonar-server/src/main/coffee/widgets/treemap.coffee96
-rw-r--r--sonar-server/src/main/coffee/widgets/word-cloud.coffee11
-rw-r--r--sonar-server/src/main/less/style.less42
5 files changed, 153 insertions, 10 deletions
diff --git a/sonar-server/Gruntfile.coffee b/sonar-server/Gruntfile.coffee
index 0f06e25c577..e49048f7eff 100644
--- a/sonar-server/Gruntfile.coffee
+++ b/sonar-server/Gruntfile.coffee
@@ -94,6 +94,7 @@ module.exports = (grunt) ->
'<%= pkg.assets %>js/widgets/pie-chart.js'
'<%= pkg.assets %>js/widgets/histogram.js'
'<%= pkg.assets %>js/widgets/word-cloud.js'
+ '<%= pkg.assets %>js/widgets/treemap.js'
'<%= pkg.assets %>js/top-search.js'
'<%= pkg.assets %>js/sortable.js'
'<%= pkg.assets %>js/common/inputs.js'
@@ -125,6 +126,7 @@ module.exports = (grunt) ->
'<%= pkg.assets %>js/widgets/pie-chart.js'
'<%= pkg.assets %>js/widgets/histogram.js'
'<%= pkg.assets %>js/widgets/word-cloud.js'
+ '<%= pkg.assets %>js/widgets/treemap.js'
'<%= pkg.assets %>js/top-search.js'
'<%= pkg.assets %>js/sortable.js'
'<%= pkg.assets %>js/common/inputs.js'
diff --git a/sonar-server/src/main/coffee/widgets/base.coffee b/sonar-server/src/main/coffee/widgets/base.coffee
index 133c15e464d..5531ceb2d92 100644
--- a/sonar-server/src/main/coffee/widgets/base.coffee
+++ b/sonar-server/src/main/coffee/widgets/base.coffee
@@ -2,6 +2,9 @@ window.SonarWidgets ?= {}
class BaseWidget
lineHeight: 20
+ colorLow: '#d62728'
+ colorHigh: '#85bb43'
+ colorUnknown: '#777'
constructor: ->
@@ -47,4 +50,11 @@ class BaseWidget
@
-window.SonarWidgets.BaseWidget = BaseWidget \ No newline at end of file
+ tooltip: (d) ->
+ title = d.longName
+ title += "\n#{@colorMetric.name}: #{@colorMetric.formattedValue d}" if @colorMetric.value(d)?
+ title += "\n#{@sizeMetric.name}: #{@sizeMetric.formattedValue d}" if @sizeMetric.value(d)?
+ title
+
+
+window.SonarWidgets.BaseWidget = BaseWidget
diff --git a/sonar-server/src/main/coffee/widgets/treemap.coffee b/sonar-server/src/main/coffee/widgets/treemap.coffee
new file mode 100644
index 00000000000..7cb065d02b4
--- /dev/null
+++ b/sonar-server/src/main/coffee/widgets/treemap.coffee
@@ -0,0 +1,96 @@
+class Treemap extends window.SonarWidgets.BaseWidget
+ sizeLow: 10
+ sizeHigh: 24
+
+
+ constructor: ->
+ @addField 'width', null
+ @addField 'height', null
+ @addField 'maxResultsReached', false
+ super
+
+
+ getNodes: ->
+ @treemap.nodes(children: @components()).filter (d) -> !d.children
+
+
+ renderTreemap: ->
+ @treemap = d3.layout.treemap()
+ @treemap.value (d) =>
+ @sizeMetric.value d
+ @cells = @box.selectAll('.treemap-cell').data @getNodes()
+
+ cellsEnter = @cells.enter().append 'div'
+ cellsEnter.classed 'treemap-cell', true
+ cellsEnter.attr 'title', (d) => @tooltip d
+ cellsEnter.style 'color', (d) =>
+ if @colorMetric.value(d)? then @color @colorMetric.value(d) else @colorUnknown
+ cellsEnter.style 'font-size', (d) => "#{@size @sizeMetric.value d}px"
+
+ cellsLink = cellsEnter.append('a').classed 'treemap-detach', true
+ cellsLink.attr 'target', '_blank'
+ cellsLink.attr 'href', (d) =>
+ url = @options().baseUrl + encodeURIComponent(d.key)
+ url += '?metric=' + encodeURIComponent(@colorMetric.key) if d.qualifier == 'CLA' || d.qualifier == 'FIL'
+ url
+ cellsLink.append('i').attr 'class', (d) -> "icon-qualifier-#{d.qualifier.toLowerCase()}"
+
+ @cellsInner = cellsEnter.append('div').classed 'treemap-inner', true
+ @cellsInner.text (d) -> d.longName
+ @cellsInner.style 'border-color', (d) =>
+ if @colorMetric.value(d)? then @color @colorMetric.value(d) else @colorUnknown
+
+ @attachEvents cellsEnter
+
+
+ attachEvents: (cells) ->
+
+
+ positionCells: ->
+ @cells.style 'left', (d) -> "#{d.x}px"
+ @cells.style 'top', (d) -> "#{d.y}px"
+ @cells.style 'width', (d) -> "#{d.dx}px"
+ @cells.style 'height', (d) -> "#{d.dy}px"
+ @cells.classed 'treemap-cell-small', (d) -> d.dy < 60
+ @cellsInner.style 'line-height', (d) -> "#{d.dy}px"
+
+
+ render: (container) ->
+ box = d3.select(container).append('div')
+ box.classed 'sonar-d3', true
+ @box = box.append('div').classed 'treemap-container', true
+
+ # Configure metrics
+ @addMetric 'colorMetric', 0
+ @addMetric 'sizeMetric', 1
+
+ # Configure scales
+ @color = d3.scale.linear().domain([0, 100])
+ if @colorMetric.direction == 1
+ @color.range [@colorLow, @colorHigh]
+ else
+ @color.range [@colorHigh, @colorLow]
+
+ sizeDomain = d3.extent @components(), (d) => @sizeMetric.value d
+ @size = d3.scale.linear().domain(sizeDomain).range [@sizeLow, @sizeHigh]
+
+ # Show maxResultsReached message
+ if @maxResultsReached()
+ maxResultsReachedLabel = box.append('div').text @options().maxItemsReachedMessage
+ maxResultsReachedLabel.classed 'max-results-reached-message', true
+
+ @renderTreemap()
+ super
+
+
+ update: ->
+ @width @box.property 'offsetWidth'
+ @height (@width() / 100.0 * @options().heightInPercents)
+ @box.style 'height', "#{@height()}px"
+ @treemap.size [@width(), @height()]
+ @cells.data @getNodes()
+ @positionCells()
+
+
+
+window.SonarWidgets.Treemap = Treemap
diff --git a/sonar-server/src/main/coffee/widgets/word-cloud.coffee b/sonar-server/src/main/coffee/widgets/word-cloud.coffee
index 1e09b55a6d5..1d98fd1add0 100644
--- a/sonar-server/src/main/coffee/widgets/word-cloud.coffee
+++ b/sonar-server/src/main/coffee/widgets/word-cloud.coffee
@@ -1,7 +1,4 @@
class WordCloud extends window.SonarWidgets.BaseWidget
- colorLow: '#d62728'
- colorHigh: '#1f77b4'
- colorUnknown: '#777'
sizeLow: 10
sizeHigh: 24
@@ -22,11 +19,7 @@ class WordCloud extends window.SonarWidgets.BaseWidget
url = @options().baseUrl + encodeURIComponent(d.key)
url += '?metric=' + encodeURIComponent(@colorMetric.key) if d.qualifier == 'CLA' || d.qualifier == 'FIL'
url
- wordsEnter.attr 'title', (d) =>
- title = d.longName
- title += " | #{@colorMetric.name}: #{@colorMetric.formattedValue d}" if @colorMetric.value(d)?
- title += " | #{@sizeMetric.name}: #{@sizeMetric.formattedValue d}" if @sizeMetric.value(d)?
- title
+ wordsEnter.attr 'title', (d) => @tooltip d
words.style 'color', (d) =>
if @colorMetric.value(d)? then @color @colorMetric.value(d) else @colorUnknown
@@ -67,4 +60,4 @@ class WordCloud extends window.SonarWidgets.BaseWidget
-window.SonarWidgets.WordCloud = WordCloud \ No newline at end of file
+window.SonarWidgets.WordCloud = WordCloud
diff --git a/sonar-server/src/main/less/style.less b/sonar-server/src/main/less/style.less
index d359113276f..aedda2cd0e9 100644
--- a/sonar-server/src/main/less/style.less
+++ b/sonar-server/src/main/less/style.less
@@ -2799,6 +2799,48 @@ div.rule-title {
fill: #777;
}
+.sonar-d3 .treemap-container {
+ position: relative;
+}
+
+.sonar-d3 .treemap-cell {
+ position: absolute;
+ border-right: 1px solid #fff;
+ border-bottom: 1px solid #fff;
+ .box-sizing(border-box);
+}
+
+.sonar-d3 .treemap-inner {
+ position: absolute;
+ z-index: 1;
+ top: 0; left: 0; bottom: 0; right: 0;
+ padding: 0 5px;
+ border: 1px solid;
+ text-align: center;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.sonar-d3 .treemap-detach {
+ position: absolute;
+ z-index: 2;
+ top: 5px; right: 5px;
+ line-height: 16px;
+ color: inherit;
+ opacity: 0.5;
+
+ &:hover { opacity: 1; }
+}
+
+.sonar-d3 .treemap-cell-small {
+ .treemap-inner { text-indent: -9999px; }
+ .treemap-detach {
+ top: 50%; left: 50%;
+ margin: -8px 0 0 -8px;
+ }
+}
+
/* ------------------- Admin pages ------------------- */