Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / trace-viewer / third_party / tvcm / src / tvcm / ui / chart_base.html
index a48e459..bbcfe81 100644 (file)
@@ -1,8 +1,13 @@
+<!DOCTYPE html>
 <!--
-Copyright 2014 The Chromium Authors. All rights reserved.
+Copyright (c) 2014 The Chromium Authors. All rights reserved.
 Use of this source code is governed by a BSD-style license that can be
 found in the LICENSE file.
 -->
+<link rel="import" href="/tvcm/ui.html">
+<link rel="import" href="/tvcm/ui/color_scheme.html">
+<link rel="import" href="/tvcm/ui/d3.html">
+
 <style>
   .chart-base #title {
     font-size: 16pt;
@@ -10,6 +15,8 @@ found in the LICENSE file.
 
   .chart-base {
     font-size: 12pt;
+    -webkit-user-select: none;
+    cursor: default;
   }
 
   .chart-base .axis path,
@@ -19,6 +26,7 @@ found in the LICENSE file.
     stroke: #000;
   }
 </style>
+
 <template id="chart-base-template">
   <svg> <!-- svg tag is dropped by ChartBase.decorate. -->
     <g xmlns="http://www.w3.org/2000/svg" id="chart-area">
@@ -28,3 +36,258 @@ found in the LICENSE file.
     </g>
   </svg>
 </template>
+
+<script>
+'use strict';
+
+tvcm.exportTo('tvcm.ui', function() {
+  var THIS_DOC = document.currentScript.ownerDocument;
+
+  var svgNS = 'http://www.w3.org/2000/svg';
+  var highlightIdBoost = tvcm.ui.getColorPaletteHighlightIdBoost();
+
+  function getColorOfKey(key, selected) {
+    var id = tvcm.ui.getStringColorId(key);
+    if (selected)
+      id += highlightIdBoost;
+    return tvcm.ui.getColorPalette()[id];
+  }
+
+  /**
+   * A virtual base class for basic charts that provides X and Y axes, if
+   * needed, a title, and legend.
+   *
+   * @constructor
+   */
+  var ChartBase = tvcm.ui.define('svg', undefined, svgNS);
+
+  ChartBase.prototype = {
+    __proto__: HTMLUnknownElement.prototype,
+
+    decorate: function() {
+      this.classList.add('chart-base');
+      this.chartTitle_ = undefined;
+      this.data_ = undefined;
+      this.seriesKeys_ = undefined;
+      this.width_ = 400;
+      this.height_ = 300;
+
+      // This should use tvcm.instantiateTemplate. However, creating
+      // svg-namespaced elements inside a template isn't possible. Thus, this
+      // hack.
+      var template = THIS_DOC.querySelector('#chart-base-template');
+      var svgEl = template.content.querySelector('svg');
+      for (var i = 0; i < svgEl.children.length; i++)
+        this.appendChild(svgEl.children[i].cloneNode(true));
+
+      // svg likes to take over width & height properties for some reason. This
+      // works around it.
+      Object.defineProperty(
+          this, 'width', {
+            get: function() {
+              return this.width_;
+            },
+            set: function(width) {
+              this.width_ = width;
+              this.updateContents_();
+            }
+          });
+      Object.defineProperty(
+          this, 'height', {
+            get: function() {
+              return this.height_;
+            },
+            set: function(height) {
+              this.height_ = height;
+              this.updateContents_();
+            }
+          });
+    },
+
+    get chartTitle() {
+      return chartTitle_;
+    },
+
+    set chartTitle(chartTitle) {
+      this.chartTitle_ = chartTitle;
+      this.updateContents_();
+    },
+
+    get chartAreaElement() {
+      return this.querySelector('#chart-area');
+    },
+
+    get data() {
+      return this.data_;
+    },
+
+    setSize: function(size) {
+      this.width_ = size.width;
+      this.height_ = size.height;
+      this.updateContents_();
+    },
+
+    get margin() {
+      var margin = {top: 20, right: 20, bottom: 30, left: 50};
+      if (this.chartTitle_)
+        margin.top += 20;
+      return margin;
+    },
+
+    get chartAreaSize() {
+      var margin = this.margin;
+      return {
+        width: this.width_ - margin.left - margin.right,
+        height: this.height_ - margin.top - margin.bottom
+      };
+    },
+
+    getLegendKeys_: function() {
+      throw new Error('Not implemented');
+    },
+
+    updateScales_: function(width, height) {
+      throw new Error('Not implemented');
+    },
+
+    updateContents_: function() {
+      var margin = this.margin;
+      var width = this.chartAreaSize.width;
+      var height = this.chartAreaSize.height;
+
+      var thisSel = d3.select(this);
+      thisSel.attr('width', this.width_);
+      thisSel.attr('height', this.height_);
+
+      var chartAreaSel = d3.select(this.chartAreaElement);
+      chartAreaSel.attr(
+          'transform',
+          'translate(' + margin.left + ',' + margin.top + ')');
+
+      this.updateScales_(width, height);
+
+      // Axes.
+      if (this.xScale_ && this.yScale_) {
+        var xAxisRenderer = d3.svg.axis()
+            .scale(this.xScale_)
+            .orient('bottom');
+
+        var yAxisRenderer = d3.svg.axis()
+            .scale(this.yScale_)
+            .orient('left');
+
+        chartAreaSel.select('.x.axis')
+            .attr('transform', 'translate(0,' + height + ')')
+            .call(xAxisRenderer);
+
+        chartAreaSel.select('.y.axis')
+            .call(yAxisRenderer);
+      }
+
+      // Title.
+      var titleSel = chartAreaSel.select('#title');
+      if (this.chartTitle_) {
+        titleSel.attr('transform', 'translate(' + width * 0.5 + ',-5)')
+            .style('display', undefined)
+            .style('text-anchor', 'middle')
+            .attr('class', 'title')
+            .attr('width', width)
+            .text(this.chartTitle_);
+      } else {
+        titleSel.style('display', 'none');
+      }
+
+      // Basics
+      this.updateLegend_();
+    },
+
+    updateLegend_: function() {
+      var keys = this.getLegendKeys_();
+      if (keys === undefined)
+        return;
+
+      var chartAreaSel = d3.select(this.chartAreaElement);
+      var chartAreaSize = this.chartAreaSize;
+
+      var legendEntriesSel = chartAreaSel.selectAll('.legend')
+          .data(keys.slice().reverse());
+
+      legendEntriesSel.enter()
+          .append('g')
+          .attr('class', 'legend')
+          .attr('transform', function(d, i) {
+            return 'translate(0,' + i * 20 + ')';
+          }).append('text').text(function(key) {
+            return key;
+          });
+      legendEntriesSel.exit().remove();
+
+      legendEntriesSel.attr('x', chartAreaSize.width - 18)
+          .attr('width', 18)
+          .attr('height', 18)
+          .style('fill', function(key) {
+            var selected = this.currentHighlightedLegendKey === key;
+            return getColorOfKey(key, selected);
+          }.bind(this));
+
+      legendEntriesSel.selectAll('text')
+        .attr('x', chartAreaSize.width - 24)
+        .attr('y', 9)
+        .attr('dy', '.35em')
+        .style('text-anchor', 'end')
+        .text(function(d) { return d; });
+    },
+
+    get highlightedLegendKey() {
+      return this.highlightedLegendKey_;
+    },
+
+    set highlightedLegendKey(highlightedLegendKey) {
+      this.highlightedLegendKey_ = highlightedLegendKey;
+      this.updateHighlight_();
+    },
+
+    get currentHighlightedLegendKey() {
+      if (this.tempHighlightedLegendKey_)
+        return this.tempHighlightedLegendKey_;
+      return this.highlightedLegendKey_;
+    },
+
+    pushTempHighlightedLegendKey: function(key) {
+      if (this.tempHighlightedLegendKey_)
+        throw new Error('push cannot nest');
+      this.tempHighlightedLegendKey_ = key;
+      this.updateHighlight_();
+    },
+
+    popTempHighlightedLegendKey: function(key) {
+      if (this.tempHighlightedLegendKey_ != key)
+        throw new Error('pop cannot happen');
+      this.tempHighlightedLegendKey_ = undefined;
+      this.updateHighlight_();
+    },
+
+    updateHighlight_: function() {
+      // Update label colors.
+      var chartAreaSel = d3.select(this.chartAreaElement);
+      var legendEntriesSel = chartAreaSel.selectAll('.legend');
+
+      var that = this;
+      legendEntriesSel.each(function(key) {
+        var highlighted = key == that.currentHighlightedLegendKey;
+        var color = getColorOfKey(key, highlighted);
+        this.style.fill = color;
+        if (highlighted)
+          this.style.fontWeight = 'bold';
+        else
+          this.style.fontWeight = '';
+      });
+    }
+  };
+
+  return {
+    getColorOfKey: getColorOfKey,
+    ChartBase: ChartBase
+  };
+});
+</script>