Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / trace-viewer / third_party / tvcm / src / tvcm / ui / pie_chart.js
index 63533af..d6ec020 100644 (file)
@@ -6,6 +6,7 @@
 
 tvcm.require('tvcm.range');
 tvcm.require('tvcm.ui.d3');
+tvcm.require('tvcm.ui.dom_helpers');
 tvcm.require('tvcm.ui.chart_base');
 
 tvcm.requireStylesheet('tvcm.ui.pie_chart');
@@ -14,6 +15,8 @@ tvcm.exportTo('tvcm.ui', function() {
   var ChartBase = tvcm.ui.ChartBase;
   var getColorOfKey = tvcm.ui.getColorOfKey;
 
+  var MIN_RADIUS = 100;
+
   /**
    * @constructor
    */
@@ -30,8 +33,18 @@ tvcm.exportTo('tvcm.ui', function() {
       this.seriesKeys_ = undefined;
 
       var chartAreaSel = d3.select(this.chartAreaElement);
-      this.pieGroup_ = chartAreaSel.append('g')
-        .attr('class', 'pie-group')
+      var pieGroupSel = chartAreaSel.append('g')
+        .attr('class', 'pie-group');
+      this.pieGroup_ = pieGroupSel.node();
+
+      this.pathsGroup_ = pieGroupSel.append('g')
+        .attr('class', 'paths')
+        .node();
+      this.labelsGroup_ = pieGroupSel.append('g')
+        .attr('class', 'labels')
+        .node();
+      this.linesGroup_ = pieGroupSel.append('g')
+        .attr('class', 'lines')
         .node();
     },
 
@@ -66,10 +79,50 @@ tvcm.exportTo('tvcm.ui', function() {
       this.updateContents_();
     },
 
+    get margin() {
+      var margin = {top: 0, right: 0, bottom: 0, left: 0};
+      if (this.chartTitle_)
+        margin.top += 40;
+      return margin;
+    },
+
+    getMinSize: function() {
+      if (!tvcm.ui.isElementAttachedToDocument(this))
+        throw new Error('Cannot measure when unattached');
+      this.updateContents_();
+
+      var labelSel = d3.select(this.labelsGroup_).selectAll('.label');
+      var maxLabelWidth = -Number.MAX_VALUE;
+      var leftTextHeightSum = 0;
+      var rightTextHeightSum = 0;
+      labelSel.each(function(l) {
+        var r = this.getBoundingClientRect();
+        maxLabelWidth = Math.max(maxLabelWidth, r.width);
+        if (this.style.textAnchor == 'end') {
+          leftTextHeightSum += r.height;
+        } else {
+          rightTextHeightSum += r.height;
+        }
+      });
+
+      var titleWidth = this.querySelector(
+          '#title').getBoundingClientRect().width;
+      var margin = this.margin;
+      var marginWidth = margin.left + margin.right;
+      var marginHeight = margin.top + margin.bottom;
+      return {
+        width: Math.max(2 * MIN_RADIUS + 2 * maxLabelWidth,
+                        titleWidth * 1.1) + marginWidth,
+        height: marginHeight + Math.max(2 * MIN_RADIUS,
+                                        leftTextHeightSum,
+                                        rightTextHeightSum) * 1.25
+      };
+    },
+
+
     getLegendKeys_: function() {
-      if (this.data_ === undefined)
-        return [];
-      return this.seriesKeys_;
+      // This class creates its own legend, instead of using ChartBase.
+      return undefined;
     },
 
     updateScales_: function(width, height) {
@@ -84,31 +137,132 @@ tvcm.exportTo('tvcm.ui', function() {
 
       var width = this.chartAreaSize.width;
       var height = this.chartAreaSize.height;
-      var radius = Math.min(width, height) / 2;
+      var radius = Math.max(MIN_RADIUS, Math.min(width, height) / 2);
 
-      var pieGroupSel = d3.select(this.pieGroup_);
-      pieGroupSel.attr('transform',
-                       'translate(' + width / 2 + ',' + height / 2 + ')');
+      d3.select(this.pieGroup_).attr(
+          'transform',
+          'translate(' + width / 2 + ',' + height / 2 + ')');
 
       // Bind the pie layout to its data
       var pieLayout = d3.layout.pie()
         .value(function(d) { return d.value; })
         .sort(null);
 
-      var piePathsSel = pieGroupSel.datum(this.data_).selectAll('path')
-        .data(pieLayout);
+      var piePathsSel = d3.select(this.pathsGroup_)
+          .datum(this.data_)
+          .selectAll('path')
+          .data(pieLayout);
 
+      function midAngle(d) {
+        return d.startAngle + (d.endAngle - d.startAngle) / 2;
+      }
 
-      var arcRenderer = d3.svg.arc()
+      var pathsArc = d3.svg.arc()
         .innerRadius(0)
-        .outerRadius(radius - 20);
+        .outerRadius(radius - 30);
+
+      var valueLabelArc = d3.svg.arc()
+        .innerRadius(radius - 100)
+        .outerRadius(radius - 30);
+
+      var lineBeginArc = d3.svg.arc()
+        .innerRadius(radius - 50)
+        .outerRadius(radius - 50);
+
+      var lineEndArc = d3.svg.arc()
+        .innerRadius(radius)
+        .outerRadius(radius);
+
+      // Paths.
       piePathsSel.enter().append('path')
+        .attr('class', 'arc')
         .attr('fill', function(d, i) {
             var origData = this.data_[i];
-            return getColorOfKey(origData.label);
+            var highlighted = (origData.label ===
+                               this.currentHighlightedLegendKey);
+            return getColorOfKey(origData.label, highlighted);
+          }.bind(this))
+        .attr('d', pathsArc)
+        .on('click', function(d, i) {
+            var origData = this.data_[i];
+            if (origData.onClick)
+              origData.onClick(d, i);
+            d3.event.stopPropagation();
           }.bind(this))
-        .attr('d', arcRenderer);
+        .on('mouseenter', function(d, i) {
+            var origData = this.data_[i];
+            this.pushTempHighlightedLegendKey(origData.label);
+          }.bind(this))
+        .on('mouseleave', function(d, i) {
+            var origData = this.data_[i];
+            this.popTempHighlightedLegendKey(origData.label);
+          }.bind(this));
+
+      // Value labels.
+      piePathsSel.enter().append('text')
+        .attr('class', 'arc-text')
+        .attr('transform', function(d) {
+            return 'translate(' + valueLabelArc.centroid(d) + ')';
+          })
+        .attr('dy', '.35em')
+        .style('text-anchor', 'middle')
+        .text(function(d, i) {
+            var origData = this.data_[i];
+            if (origData.valueText === undefined)
+              return '';
+
+            if (d.endAngle - d.startAngle < 0.4)
+              return '';
+            return origData.valueText;
+          }.bind(this));
+
       piePathsSel.exit().remove();
+
+      // Labels.
+      var labelSel = d3.select(this.labelsGroup_).selectAll('.label')
+          .data(pieLayout(this.data_));
+      labelSel.enter()
+          .append('text')
+          .attr('class', 'label')
+          .attr('dy', '.35em');
+
+      labelSel.text(function(d) {
+        return d.data.label;
+      });
+      labelSel.attr('transform', function(d) {
+        var pos = lineEndArc.centroid(d);
+        pos[0] = radius * (midAngle(d) < Math.PI ? 1 : -1);
+        return 'translate(' + pos + ')';
+      });
+      labelSel.style('text-anchor', function(d) {
+        return midAngle(d) < Math.PI ? 'start' : 'end';
+      });
+
+      // Lines.
+      var lineSel = d3.select(this.linesGroup_).selectAll('.line')
+          .data(pieLayout(this.data_));
+      lineSel.enter()
+        .append('polyline')
+        .attr('class', 'line')
+        .attr('dy', '.35em');
+      lineSel.attr('points', function(d) {
+        var pos = lineEndArc.centroid(d);
+        pos[0] = radius * 0.95 * (midAngle(d) < Math.PI ? 1 : -1);
+        return [lineBeginArc.centroid(d), lineEndArc.centroid(d), pos];
+      });
+    },
+
+    updateHighlight_: function() {
+      ChartBase.prototype.updateHighlight_.call(this);
+      // Update color of pie segments.
+      var pathsGroupSel = d3.select(this.pathsGroup_);
+      var that = this;
+      pathsGroupSel.selectAll('.arc').each(function(d, i) {
+        var origData = that.data_[i];
+        var highlighted = origData.label == that.currentHighlightedLegendKey;
+        var color = getColorOfKey(origData.label, highlighted);
+        this.style.fill = color;
+      });
     }
   };