Upstream version 7.35.144.0
[platform/framework/web/crosswalk.git] / src / tools / telemetry / telemetry / web_components / ui / bar_chart.js
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 'use strict';
6
7 tvcm.require('tvcm.range');
8 tvcm.require('tracing.color_scheme');
9 tvcm.require('telemetry.web_components.ui.d3');
10 tvcm.require('telemetry.web_components.ui.chart_base');
11
12 tvcm.requireStylesheet('telemetry.web_components.ui.bar_chart');
13
14 tvcm.exportTo('telemetry.web_components.ui', function() {
15   var ChartBase = telemetry.web_components.ui.ChartBase;
16   var getColorOfKey = telemetry.web_components.ui.getColorOfKey;
17
18   /**
19    * @constructor
20    */
21   var BarChart = tvcm.ui.define('bar-chart', ChartBase);
22
23   BarChart.prototype = {
24     __proto__: ChartBase.prototype,
25
26     decorate: function() {
27       ChartBase.prototype.decorate.call(this);
28       this.classList.add('bar-chart');
29
30       this.xScale_ = undefined;
31       this.xSubScale_ = undefined;
32       this.yScale_ = undefined;
33
34       this.data_ = undefined;
35       this.xLabelValues_ = undefined;
36       this.xLabelKey_ = undefined;
37       this.seriesKeys_ = undefined;
38     },
39
40     get data() {
41       return this.data_;
42     },
43
44     get xLabelKey() {
45       return this.xLabelKey_;
46     },
47
48     setDataAndXLabelKey: function(data, xLabelKey) {
49       if (data !== undefined) {
50         // Figure out what the series keys are. E.g. for {label: 'a', value1: 3,
51         // value2: 4} compute ['value1', 'value2'].
52         var seriesKeys = [];
53         d3.keys(data[0]).forEach(function(k) {
54           if (k == xLabelKey)
55             return;
56           seriesKeys.push(k);
57         });
58
59         // Figure out the x labels in the data set. E.g. from
60         //   [{label: 'a', ...}, {label: 'b', ...}]
61         // we would commpute ['a', 'y'].
62         var xLabelValues = [];
63         var seenXLabelValues = {};
64         data.forEach(function(d) {
65           var xLabelValue = d[xLabelKey];
66           if (seenXLabelValues[xLabelValue])
67             throw new Error('Label ' + xLabelValue + ' has been used already');
68           xLabelValues.push(xLabelValue);
69           seenXLabelValues[xLabelValue] = true;
70         }, this);
71         this.xLabelKey_ = xLabelKey;
72         this.seriesKeys_ = seriesKeys;
73         this.xLabelValues_ = xLabelValues;
74       } else {
75         this.xLabelKey_ = undefined;
76         this.seriesKeys_ = undefined;
77         this.xLabelValues_ = undefined;
78       }
79       this.data_ = data;
80       this.updateContents_();
81     },
82
83     getLegendKeys_: function() {
84       if (this.seriesKeys_ &&
85           this.seriesKeys_.length > 1)
86         return this.seriesKeys_.slice();
87       return [];
88     },
89
90     updateScales_: function(width, height) {
91       if (this.data_ === undefined) {
92         this.xScale_ = undefined;
93         this.xSubScale_ = undefined;
94         this.yScale_ = undefined;
95         return;
96       }
97
98       // xScale maps x labels to a position in the overall timeline.
99       this.xScale_ = d3.scale.ordinal();
100       this.xScale_.rangeRoundBands([0, width], .1);
101       this.xScale_.domain(this.xLabelValues_);
102
103       // xSubScale maps an individual series to a position within its group
104       // of related bars.
105       this.xSubScale_ = d3.scale.ordinal();
106       this.xSubScale_.domain(this.seriesKeys_)
107           .rangeRoundBands([0, this.xScale_.rangeBand()]);
108
109       // Regular mapping of values to the full chart height.
110       var yRange = new tvcm.Range();
111       this.data_.forEach(function(d) {
112         this.seriesKeys_.forEach(function(k) {
113           yRange.addValue(d[k]);
114         }, this);
115       }, this);
116       this.yScale_ = d3.scale.linear();
117       this.yScale_.range([height, 0]);
118
119       this.yScale_.domain([yRange.min, yRange.max]);
120     },
121
122     updateContents_: function() {
123       ChartBase.prototype.updateContents_.call(this);
124       if (!this.data_)
125         return;
126
127       var width = this.chartAreaSize.width;
128       var height = this.chartAreaSize.height;
129
130       var chartAreaSel = d3.select(this.chartAreaElement);
131
132       // An index-group has the rects from the same array index in the source
133       // data set.
134       var indexGroupSel = chartAreaSel.selectAll('.index-group')
135           .data(this.data_);
136       indexGroupSel.enter().append('g')
137           .attr('class', '.index-group')
138           .attr('transform', function(d) {
139             var k = d[this.xLabelKey_];
140             return 'translate(' + this.xScale_(k) + ',0)';
141           }.bind(this));
142       indexGroupSel.exit().remove();
143
144       // Within an index group, create a rect for each actual value.
145       var rectsSel = indexGroupSel.selectAll('rect')
146         .data(function(d) {
147             // 'd' is an index in the original array. We want to extract out the
148             // actual values from it from this.seriesKeys_. This we turn into
149             // {name: seriesKey, value: d[seriesKey]} objects that then get
150             // data-bound to each rect.
151             var values = [];
152             for (var i = 0; i < this.seriesKeys_.length; i++) {
153               var k = this.seriesKeys_[i];
154               values.push({name: k,
155                            value: d[k]});
156             }
157             return values;
158           }.bind(this));
159
160       rectsSel.enter().append('rect')
161         .attr('width', this.xSubScale_.rangeBand())
162         .attr('x', function(d) {
163             return this.xSubScale_(d.name);
164           }.bind(this))
165         .attr('y', function(d) {
166             return this.yScale_(d.value);
167           }.bind(this))
168         .attr('height', function(d) {
169             return height - this.yScale_(d.value);
170           }.bind(this))
171         .style('fill', function(d) {
172             return getColorOfKey(d.name);
173           });
174     }
175   };
176
177   return {
178     BarChart: BarChart
179   };
180 });