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.utils');
8 tvcm.require('telemetry.web_components.ui.d3');
9 tvcm.requireTemplate('telemetry.web_components.ui.chart_base');
11 tvcm.exportTo('telemetry.web_components.ui', function() {
12 var svgNS = 'http://www.w3.org/2000/svg';
14 function getColorOfKey(key) {
15 var id = tracing.getStringColorId(key);
16 return tracing.getColorPalette()[id];
20 * A virtual base class for basic charts that provides X and Y axes, if
21 * needed, a title, and legend.
25 var ChartBase = tvcm.ui.define('svg', undefined, svgNS);
27 ChartBase.prototype = {
28 __proto__: HTMLUnknownElement.prototype,
30 decorate: function() {
31 this.classList.add('chart-base');
32 this.chartTitle_ = undefined;
33 this.data_ = undefined;
34 this.seriesKeys_ = undefined;
38 // This should use tvcm.instantiateTemplate. However, creating
39 // svg-namespaced elements inside a template isn't possible. Thus, this
41 var template = document.head.querySelector('#chart-base-template');
42 var svgEl = template.content.querySelector('svg');
43 for (var i = 0; i < svgEl.children.length; i++)
44 this.appendChild(svgEl.children[i].cloneNode(true));
51 set chartTitle(chartTitle) {
52 this.chartTitle_ = chartTitle;
53 this.updateContents_();
56 get chartAreaElement() {
57 return this.querySelector('#chart-area');
66 this.updateContents_();
74 this.height_ = height;
75 this.updateContents_();
83 var margin = {top: 20, right: 20, bottom: 30, left: 50};
90 var margin = this.margin;
92 width: this.width_ - margin.left - margin.right,
93 height: this.height_ - margin.top - margin.bottom
97 getLegendKeys_: function() {
98 throw new Error('Not implemented');
101 updateScales_: function(width, height) {
102 throw new Error('Not implemented');
105 updateContents_: function() {
106 var margin = this.margin;
107 var width = this.chartAreaSize.width;
108 var height = this.chartAreaSize.height;
110 var thisSel = d3.select(this);
111 thisSel.attr('width', this.width_);
112 thisSel.attr('height', this.height_);
114 var chartAreaSel = d3.select(this.chartAreaElement);
117 'translate(' + margin.left + ',' + margin.top + ')');
119 this.updateScales_(width, height);
122 if (this.xScale_ && this.yScale_) {
123 var xAxisRenderer = d3.svg.axis()
127 var yAxisRenderer = d3.svg.axis()
131 chartAreaSel.select('.x.axis')
132 .attr('transform', 'translate(0,' + height + ')')
133 .call(xAxisRenderer);
135 chartAreaSel.select('.y.axis')
136 .call(yAxisRenderer);
140 var titleSel = chartAreaSel.select('#title');
141 if (this.chartTitle_) {
142 titleSel.attr('transform', 'translate(' + width * 0.5 + ',-5)')
143 .style('display', undefined)
144 .style('text-anchor', 'middle')
145 .attr('class', 'title')
146 .attr('width', width)
147 .text(this.chartTitle_);
149 titleSel.style('display', 'none');
152 this.updateLegend_();
155 updateLegend_: function() {
156 var keys = this.getLegendKeys_();
158 var chartAreaSel = d3.select(this.chartAreaElement);
159 var chartAreaSize = this.chartAreaSize;
161 var legendEntriesSel = chartAreaSel.selectAll('.legend')
162 .data(keys.slice().reverse());
164 legendEntriesSel.enter()
166 .attr('class', 'legend')
167 .attr('transform', function(d, i) {
168 return 'translate(0,' + i * 20 + ')';
169 }).append('text').text(function(key) {
172 legendEntriesSel.exit().remove();
174 legendEntriesSel.attr('x', chartAreaSize.width - 18)
177 .style('fill', function(key) {
178 return getColorOfKey(key);
181 legendEntriesSel.selectAll('text')
182 .attr('x', chartAreaSize.width - 24)
185 .style('text-anchor', 'end')
186 .text(function(d) { return d; });
191 getColorOfKey: getColorOfKey,