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.
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');
12 tvcm.requireStylesheet('telemetry.web_components.ui.bar_chart');
14 tvcm.exportTo('telemetry.web_components.ui', function() {
15 var ChartBase = telemetry.web_components.ui.ChartBase;
16 var getColorOfKey = telemetry.web_components.ui.getColorOfKey;
21 var BarChart = tvcm.ui.define('bar-chart', ChartBase);
23 BarChart.prototype = {
24 __proto__: ChartBase.prototype,
26 decorate: function() {
27 ChartBase.prototype.decorate.call(this);
28 this.classList.add('bar-chart');
30 this.xScale_ = undefined;
31 this.xSubScale_ = undefined;
32 this.yScale_ = undefined;
34 this.data_ = undefined;
35 this.xLabelValues_ = undefined;
36 this.xLabelKey_ = undefined;
37 this.seriesKeys_ = undefined;
45 return this.xLabelKey_;
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'].
53 d3.keys(data[0]).forEach(function(k) {
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;
71 this.xLabelKey_ = xLabelKey;
72 this.seriesKeys_ = seriesKeys;
73 this.xLabelValues_ = xLabelValues;
75 this.xLabelKey_ = undefined;
76 this.seriesKeys_ = undefined;
77 this.xLabelValues_ = undefined;
80 this.updateContents_();
83 getLegendKeys_: function() {
84 if (this.seriesKeys_ &&
85 this.seriesKeys_.length > 1)
86 return this.seriesKeys_.slice();
90 updateScales_: function(width, height) {
91 if (this.data_ === undefined) {
92 this.xScale_ = undefined;
93 this.xSubScale_ = undefined;
94 this.yScale_ = undefined;
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_);
103 // xSubScale maps an individual series to a position within its group
105 this.xSubScale_ = d3.scale.ordinal();
106 this.xSubScale_.domain(this.seriesKeys_)
107 .rangeRoundBands([0, this.xScale_.rangeBand()]);
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]);
116 this.yScale_ = d3.scale.linear();
117 this.yScale_.range([height, 0]);
119 this.yScale_.domain([yRange.min, yRange.max]);
122 updateContents_: function() {
123 ChartBase.prototype.updateContents_.call(this);
127 var width = this.chartAreaSize.width;
128 var height = this.chartAreaSize.height;
130 var chartAreaSel = d3.select(this.chartAreaElement);
132 // An index-group has the rects from the same array index in the source
134 var indexGroupSel = chartAreaSel.selectAll('.index-group')
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)';
142 indexGroupSel.exit().remove();
144 // Within an index group, create a rect for each actual value.
145 var rectsSel = indexGroupSel.selectAll('rect')
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.
152 for (var i = 0; i < this.seriesKeys_.length; i++) {
153 var k = this.seriesKeys_[i];
154 values.push({name: k,
160 rectsSel.enter().append('rect')
161 .attr('width', this.xSubScale_.rangeBand())
162 .attr('x', function(d) {
163 return this.xSubScale_(d.name);
165 .attr('y', function(d) {
166 return this.yScale_(d.value);
168 .attr('height', function(d) {
169 return height - this.yScale_(d.value);
171 .style('fill', function(d) {
172 return getColorOfKey(d.name);