blob: 775d010c8019d8571ac2083dad447e56eaf26428 [file] [log] [blame]
Chris Craik93216d02015-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
8<link rel="import" href="/core/tracks/heading_track.html">
Chris Craikf516a622015-04-01 17:52:39 -07009<link rel="import" href="/base/ui/color_scheme.html">
Chris Craik93216d02015-03-05 13:58:42 -080010<link rel="import" href="/base/sorted_array_utils.html">
11<link rel="import" href="/base/ui.html">
12<style>
13.letter-dot-track {
14 height: 18px;
15}
16</style>
17
18<script>
19'use strict';
20
21tv.exportTo('tv.c.tracks', function() {
22 var SelectionState = tv.c.trace_model.SelectionState;
Chris Craik93216d02015-03-05 13:58:42 -080023
24 /**
25 * A track that displays an array of dots with filled letters inside them.
26 * @constructor
27 * @extends {HeadingTrack}
28 */
29 var LetterDotTrack = tv.b.ui.define(
30 'letter-dot-track', tv.c.tracks.HeadingTrack);
31
32 LetterDotTrack.prototype = {
33 __proto__: tv.c.tracks.HeadingTrack.prototype,
34
35 decorate: function(viewport) {
36 tv.c.tracks.HeadingTrack.prototype.decorate.call(this, viewport);
37 this.classList.add('letter-dot-track');
38 this.items_ = undefined;
39 },
40
41 getModelEventFromItem: function(item) {
42 throw new Error('Not implemented.');
43 },
44
45 get items() {
46 return this.items_;
47 },
48
49 set items(items) {
50 this.items_ = items;
51 this.invalidateDrawingContainer();
52 },
53
54 get height() {
55 return window.getComputedStyle(this).height;
56 },
57
58 set height(height) {
59 this.style.height = height;
60 },
61
62 get dumpRadiusView() {
63 return 7 * (window.devicePixelRatio || 1);
64 },
65
66 draw: function(type, viewLWorld, viewRWorld) {
67 if (this.items_ === undefined)
68 return;
69 switch (type) {
70 case tv.c.tracks.DrawType.SLICE:
71 this.drawSlices_(viewLWorld, viewRWorld);
72 break;
73 }
74 },
75
76 drawSlices_: function(viewLWorld, viewRWorld) {
77 var ctx = this.context();
78 var pixelRatio = window.devicePixelRatio || 1;
79
80 var bounds = this.getBoundingClientRect();
81 var height = bounds.height * pixelRatio;
82 var halfHeight = height * 0.5;
83 var twoPi = Math.PI * 2;
84 var palette = tv.b.ui.getColorPalette();
85 var highlightIdBoost = tv.b.ui.paletteProperties.highlightIdBoost;
86
87 // Culling parameters.
88 var dt = this.viewport.currentDisplayTransform;
89 var dumpRadiusView = this.dumpRadiusView;
90 var itemRadiusWorld = dt.xViewVectorToWorld(height);
91
92 // Draw the memory dumps.
93 var items = this.items_;
94 var loI = tv.b.findLowIndexInSortedArray(
95 items,
96 function(item) { return item.start; },
97 viewLWorld);
98
99 var oldFont = ctx.font;
100 ctx.font = '400 ' + Math.floor(9 * pixelRatio) + 'px Arial';
101 ctx.strokeStyle = 'rgb(0,0,0)';
102 ctx.textBaseline = 'middle';
103 ctx.textAlign = 'center';
Chris Craik93216d02015-03-05 13:58:42 -0800104
Chris Craikf516a622015-04-01 17:52:39 -0700105 var drawItems = function(selected) {
106 for (var i = loI; i < items.length; ++i) {
107 var item = items[i];
108 var x = item.start;
109 if (x - itemRadiusWorld > viewRWorld)
110 break;
111 if (item.selected !== selected)
112 continue;
113 var xView = dt.xWorldToView(x);
Chris Craik93216d02015-03-05 13:58:42 -0800114
Chris Craikf516a622015-04-01 17:52:39 -0700115 if (item.selected)
116 ctx.fillStyle = palette[item.colorId + highlightIdBoost];
117 else
118 ctx.fillStyle = palette[item.colorId];
Chris Craik93216d02015-03-05 13:58:42 -0800119 ctx.beginPath();
Chris Craikf516a622015-04-01 17:52:39 -0700120 ctx.arc(xView, halfHeight, dumpRadiusView + 0.5, 0, twoPi);
121 ctx.fill();
122 if (item.selected) {
123 ctx.lineWidth = 3;
124 ctx.strokeStyle = 'rgb(100,100,0)';
125 ctx.stroke();
Chris Craik93216d02015-03-05 13:58:42 -0800126
Chris Craikf516a622015-04-01 17:52:39 -0700127 ctx.beginPath();
128 ctx.arc(xView, halfHeight, dumpRadiusView, 0, twoPi);
129 ctx.lineWidth = 1.5;
130 ctx.strokeStyle = 'rgb(255,255,0)';
131 ctx.stroke();
132 } else {
133 ctx.lineWidth = 1;
134 ctx.strokeStyle = 'rgb(0,0,0)';
135 ctx.stroke();
136 }
137
138 ctx.fillStyle = 'rgb(255, 255, 255)';
139 ctx.fillText(item.dotLetter, xView, halfHeight);
140 }
141 };
142
143 // Draw unselected items first to make sure they don't occlude selected
144 // items.
145 drawItems(false);
146 drawItems(true);
147
Chris Craik93216d02015-03-05 13:58:42 -0800148 ctx.lineWidth = 1;
149 ctx.font = oldFont;
150
151 // For performance reasons we only check the SelectionState of the first
152 // memory dump. If it's DIMMED we assume that all are DIMMED.
153 // TODO(petrcermak): Allow partial highlight.
154 var selectionState = SelectionState.NONE;
155 if (items.length &&
156 items[0].selectionState === SelectionState.DIMMED) {
157 selectionState = SelectionState.DIMMED;
158 }
159
160 // Dim the track when there is an active highlight.
161 if (selectionState === SelectionState.DIMMED) {
162 var width = bounds.width * pixelRatio;
163 ctx.fillStyle = 'rgba(255,255,255,0.5)';
164 ctx.fillRect(0, 0, width, height);
165 }
166 },
167
168 addEventsToTrackMap: function(eventToTrackMap) {
169 if (this.items_ === undefined)
170 return;
171
172 this.items_.forEach(function(item) {
173 var event = this.getModelEventFromItem(item);
174 if (event)
175 eventToTrackMap.addEvent(event, this);
176 }, this);
177 },
178
179 addIntersectingItemsInRangeToSelectionInWorldSpace: function(
180 loWX, hiWX, viewPixWidthWorld, selection) {
181 if (this.items_ === undefined)
182 return;
183
184 var itemRadiusWorld = viewPixWidthWorld * this.dumpRadiusView;
185 tv.b.iterateOverIntersectingIntervals(
186 this.items_,
187 function(x) { return x.start - itemRadiusWorld; },
188 function(x) { return 2 * itemRadiusWorld; },
189 loWX, hiWX,
190 function(item) {
191 var event = this.getModelEventFromItem(item);
192 if (event)
193 selection.push(event);
194 }.bind(this));
195 },
196
197 /**
198 * Add the item to the left or right of the provided event, if any, to the
199 * selection.
200 * @param {event} The current event item.
201 * @param {Number} offset Number of slices away from the event to look.
202 * @param {Selection} selection The selection to add an event to,
203 * if found.
204 * @return {boolean} Whether an event was found.
205 * @private
206 */
207 addItemNearToProvidedEventToSelection: function(event, offset, selection) {
208 if (this.items_ === undefined)
209 return;
210
211 var items = this.items_;
212 var index = items.indexOf(event);
213 var newIndex = index + offset;
214 if (newIndex >= 0 && newIndex < items.length) {
215 var event = this.getModelEventFromItem(items[newIndex]);
216 if (event)
217 selection.push(event);
218 return true;
219 }
220 return false;
221 },
222
223 addAllObjectsMatchingFilterToSelection: function(filter, selection) {
224 },
225
226 addClosestEventToSelection: function(worldX, worldMaxDist, loY, hiY,
227 selection) {
228 if (this.items_ === undefined)
229 return;
230
231 var item = tv.b.findClosestElementInSortedArray(
232 this.items_,
233 function(x) { return x.start; },
234 worldX,
235 worldMaxDist);
236
237 if (!item)
238 return;
239
240 var event = this.getModelEventFromItem(item);
241 if (event)
242 selection.push(event);
243 }
244 };
245
246 return {
247 LetterDotTrack: LetterDotTrack
248 };
249});
250</script>