blob: 1ff0396f4597b6693785029286e6a1260f8912db [file] [log] [blame]
Chris Craikb122baf2015-03-05 13:58:42 -08001<!DOCTYPE html>
2<!--
3Copyright (c) 2015 The Chromium Authors. All rights reserved.
4Use of this source code is governed by a BSD-style license that can be
5found in the LICENSE file.
6-->
7
Chris Craikb122baf2015-03-05 13:58:42 -08008<link rel="import" href="/base/ui.html">
Chris Craik19832152015-04-16 15:43:38 -07009<link rel="import" href="/core/tracks/chart_transform.html">
10<link rel="import" href="/core/tracks/heading_track.html">
Chris Craikb122baf2015-03-05 13:58:42 -080011
12<style>
13.chart-track {
14 height: 30px;
15 position: relative;
16}
17</style>
18
19<script>
20'use strict';
21
22tv.exportTo('tv.c.tracks', function() {
23
Chris Craikb122baf2015-03-05 13:58:42 -080024 /**
Chris Craik19832152015-04-16 15:43:38 -070025 * A track that displays a chart.
26 *
Chris Craikb122baf2015-03-05 13:58:42 -080027 * @constructor
28 * @extends {HeadingTrack}
29 */
Chris Craikb122baf2015-03-05 13:58:42 -080030 var ChartTrack =
31 tv.b.ui.define('chart-track', tv.c.tracks.HeadingTrack);
32
33 ChartTrack.prototype = {
34 __proto__: tv.c.tracks.HeadingTrack.prototype,
35
36 decorate: function(viewport) {
37 tv.c.tracks.HeadingTrack.prototype.decorate.call(this, viewport);
38 this.classList.add('chart-track');
Chris Craik19832152015-04-16 15:43:38 -070039 this.series_ = undefined;
40
41 // GUID -> {axis: ChartAxis, series: [ChartSeries]}.
42 this.axisGuidToAxisData_ = undefined;
43
44 // The maximum top and bottom padding of all series.
45 this.topPadding_ = undefined;
46 this.bottomPadding_ = undefined;
Chris Craikb122baf2015-03-05 13:58:42 -080047 },
48
Chris Craik19832152015-04-16 15:43:38 -070049 get series() {
50 return this.series_;
Chris Craikb122baf2015-03-05 13:58:42 -080051 },
52
Chris Craik19832152015-04-16 15:43:38 -070053 /**
54 * Set the list of chart series to be displayed on this track. The list
55 * is assumed to be sorted in increasing z-order (i.e. the last series in
56 * the list will be drawn at the top).
57 */
58 set series(series) {
59 this.series_ = series;
60 this.calculateAxisDataAndPadding_();
Chris Craikb122baf2015-03-05 13:58:42 -080061 this.invalidateDrawingContainer();
62 },
63
64 get height() {
65 return window.getComputedStyle(this).height;
66 },
67
68 set height(height) {
69 this.style.height = height;
70 this.invalidateDrawingContainer();
71 },
72
73 get hasVisibleContent() {
Chris Craik19832152015-04-16 15:43:38 -070074 return !!this.series && this.series.length > 0;
Chris Craikb122baf2015-03-05 13:58:42 -080075 },
76
Chris Craik19832152015-04-16 15:43:38 -070077 calculateAxisDataAndPadding_: function() {
78 if (!this.series_) {
79 this.axisGuidToAxisData_ = undefined;
80 this.topPadding_ = undefined;
81 this.bottomPadding_ = undefined;
82 return;
83 }
84
85 var axisGuidToAxisData = {};
86 var topPadding = 0;
87 var bottomPadding = 0;
88
89 this.series_.forEach(function(series) {
90 var axis = series.axis;
91 var axisGuid = axis.guid;
92 if (!(axisGuid in axisGuidToAxisData)) {
93 axisGuidToAxisData[axisGuid] = {
94 axis: axis,
95 series: []
96 };
97 }
98 axisGuidToAxisData[axisGuid].series.push(series);
99 topPadding = Math.max(topPadding, series.topPadding);
100 bottomPadding = Math.max(bottomPadding, series.bottomPadding);
101 }, this);
102
103 this.axisGuidToAxisData_ = axisGuidToAxisData;
104 this.topPadding_ = topPadding;
105 this.bottomPadding_ = bottomPadding;
Chris Craikb122baf2015-03-05 13:58:42 -0800106 },
107
108 draw: function(type, viewLWorld, viewRWorld) {
109 switch (type) {
Chris Craik19832152015-04-16 15:43:38 -0700110 case tv.c.tracks.DrawType.GENERAL_EVENT:
111 this.drawChart_(viewLWorld, viewRWorld);
Chris Craikb122baf2015-03-05 13:58:42 -0800112 break;
113 }
114 },
115
Chris Craik19832152015-04-16 15:43:38 -0700116 drawChart_: function(viewLWorld, viewRWorld) {
117 if (!this.series_)
118 return;
Chris Craikb122baf2015-03-05 13:58:42 -0800119
120 var ctx = this.context();
Chris Craik19832152015-04-16 15:43:38 -0700121
122 // Get track drawing parameters.
123 var displayTransform = this.viewport.currentDisplayTransform;
Chris Craikb122baf2015-03-05 13:58:42 -0800124 var pixelRatio = window.devicePixelRatio || 1;
Chris Craikb122baf2015-03-05 13:58:42 -0800125 var bounds = this.getBoundingClientRect();
Chris Craik19832152015-04-16 15:43:38 -0700126 var highDetails = this.viewport.highDetails;
127
128 // Pre-multiply all device-independent pixel parameters with the pixel
129 // ratio to avoid unnecessary recomputation in the performance-critical
130 // drawing code.
Chris Craik19832152015-04-16 15:43:38 -0700131 var width = bounds.width * pixelRatio;
Chris Craikb122baf2015-03-05 13:58:42 -0800132 var height = bounds.height * pixelRatio;
Chris Craik19832152015-04-16 15:43:38 -0700133 var topPadding = this.topPadding_ * pixelRatio;
134 var bottomPadding = this.bottomPadding_ * pixelRatio;
Chris Craikb122baf2015-03-05 13:58:42 -0800135
Chris Craik19832152015-04-16 15:43:38 -0700136 // Set up clipping.
137 ctx.save();
138 ctx.beginPath();
139 ctx.rect(0, 0, width, height);
140 ctx.clip();
Chris Craikb122baf2015-03-05 13:58:42 -0800141
Chris Craik19832152015-04-16 15:43:38 -0700142 // Draw all series in the increasing z-order.
143 this.series_.forEach(function(series) {
144 var chartTransform = new tv.c.tracks.ChartTransform(
Chris Craik44c28202015-05-12 17:25:16 -0700145 displayTransform, series.axis, width, height, topPadding,
Chris Craik19832152015-04-16 15:43:38 -0700146 bottomPadding, pixelRatio);
147 series.draw(ctx, chartTransform, highDetails);
148 }, this);
Chris Craikb122baf2015-03-05 13:58:42 -0800149
Chris Craik19832152015-04-16 15:43:38 -0700150 // Stop clipping.
151 ctx.restore();
Chris Craikb122baf2015-03-05 13:58:42 -0800152 },
153
154 addEventsToTrackMap: function(eventToTrackMap) {
Chris Craik19832152015-04-16 15:43:38 -0700155 // TODO(petrcermak): Consider adding the series to the track map instead
156 // of the track (a potential performance optimization).
157 this.series_.forEach(function(series) {
158 series.points.forEach(function(point) {
159 point.addToTrackMap(eventToTrackMap, this);
160 }, this);
161 }, this);
Chris Craikb122baf2015-03-05 13:58:42 -0800162 },
163
Chris Craik44c28202015-05-12 17:25:16 -0700164 addIntersectingEventsInRangeToSelectionInWorldSpace: function(
Chris Craikb122baf2015-03-05 13:58:42 -0800165 loWX, hiWX, viewPixWidthWorld, selection) {
Chris Craik19832152015-04-16 15:43:38 -0700166 this.series_.forEach(function(series) {
Chris Craik44c28202015-05-12 17:25:16 -0700167 series.addIntersectingEventsInRangeToSelectionInWorldSpace(
Chris Craik19832152015-04-16 15:43:38 -0700168 loWX, hiWX, viewPixWidthWorld, selection);
169 }, this);
Chris Craikb122baf2015-03-05 13:58:42 -0800170 },
171
Chris Craik44c28202015-05-12 17:25:16 -0700172 addEventNearToProvidedEventToSelection: function(event, offset, selection) {
Chris Craik19832152015-04-16 15:43:38 -0700173 var foundItem = false;
174 this.series_.forEach(function(series) {
Chris Craik44c28202015-05-12 17:25:16 -0700175 foundItem = foundItem || series.addEventNearToProvidedEventToSelection(
Chris Craik19832152015-04-16 15:43:38 -0700176 event, offset, selection);
177 }, this);
178 return foundItem;
Chris Craikb122baf2015-03-05 13:58:42 -0800179 },
180
Chris Craik44c28202015-05-12 17:25:16 -0700181 addAllEventsMatchingFilterToSelection: function(filter, selection) {
Chris Craik19832152015-04-16 15:43:38 -0700182 // Do nothing.
Chris Craikb122baf2015-03-05 13:58:42 -0800183 },
184
185 addClosestEventToSelection: function(worldX, worldMaxDist, loY, hiY,
186 selection) {
Chris Craik19832152015-04-16 15:43:38 -0700187 this.series_.forEach(function(series) {
188 series.addClosestEventToSelection(
189 worldX, worldMaxDist, loY, hiY, selection);
190 }, this);
Chris Craikb122baf2015-03-05 13:58:42 -0800191 },
192
Chris Craik19832152015-04-16 15:43:38 -0700193 /**
194 * Automatically set the bounds of all axes on this track from the range of
195 * values of all series (in this track) associated with each of them.
196 *
197 * See the description of ChartAxis.autoSetFromRange for the optional
198 * configuration argument flags.
199 */
200 autoSetAllAxes: function(opt_config) {
201 tv.b.iterItems(this.axisGuidToAxisData_, function(axisGuid, axisData) {
202 var axis = axisData.axis;
203 var series = axisData.series;
204 axis.autoSetFromSeries(series, opt_config);
205 }, this);
206 },
207
208 /**
209 * Automatically set the bounds of the provided axis from the range of
210 * values of all series (in this track) associated with it.
211 *
212 * See the description of ChartAxis.autoSetFromRange for the optional
213 * configuration argument flags.
214 */
215 autoSetAxis: function(axis, opt_config) {
216 var series = this.axisGuidToAxisData_[axis.guid].series;
217 axis.autoSetFromSeries(series, opt_config);
Chris Craikb122baf2015-03-05 13:58:42 -0800218 }
219 };
220
221 return {
222 ChartTrack: ChartTrack
223 };
224});
225</script>