1 <!DOCTYPE html> 2 <!-- 3 Copyright (c) 2015 The Chromium Authors. All rights reserved. 4 Use of this source code is governed by a BSD-style license that can be 5 found in the LICENSE file. 6 --> 7 8 <link rel="import" href="/base/sorted_array_utils.html"> 9 <link rel="import" href="/model/proxy_selectable_item.html"> 10 <link rel="import" href="/ui/base/color_scheme.html"> 11 <link rel="import" href="/ui/base/event_presenter.html"> 12 <link rel="import" href="/ui/base/heading.html"> 13 <link rel="import" href="/ui/base/ui.html"> 14 <link rel="import" href="/ui/tracks/track.html"> 15 16 <style> 17 .letter-dot-track { 18 height: 18px; 19 } 20 </style> 21 22 <script> 23 'use strict'; 24 25 tr.exportTo('tr.ui.tracks', function() { 26 var EventPresenter = tr.ui.b.EventPresenter; 27 var SelectionState = tr.model.SelectionState; 28 29 /** 30 * A track that displays an array of dots with filled letters inside them. 31 * @constructor 32 * @extends {Track} 33 */ 34 var LetterDotTrack = tr.ui.b.define( 35 'letter-dot-track', tr.ui.tracks.Track); 36 37 LetterDotTrack.prototype = { 38 __proto__: tr.ui.tracks.Track.prototype, 39 40 decorate: function(viewport) { 41 tr.ui.tracks.Track.prototype.decorate.call(this, viewport); 42 this.classList.add('letter-dot-track'); 43 this.items_ = undefined; 44 45 this.heading_ = document.createElement('tr-ui-heading'); 46 this.appendChild(this.heading_); 47 }, 48 49 set heading(heading) { 50 this.heading_.heading = heading; 51 }, 52 53 get heading() { 54 return this.heading_.heading; 55 }, 56 57 set tooltip(tooltip) { 58 this.heading_.tooltip = tooltip; 59 }, 60 61 get items() { 62 return this.items_; 63 }, 64 65 set items(items) { 66 this.items_ = items; 67 this.invalidateDrawingContainer(); 68 }, 69 70 get height() { 71 return window.getComputedStyle(this).height; 72 }, 73 74 set height(height) { 75 this.style.height = height; 76 }, 77 78 get dumpRadiusView() { 79 return 7 * (window.devicePixelRatio || 1); 80 }, 81 82 draw: function(type, viewLWorld, viewRWorld) { 83 if (this.items_ === undefined) 84 return; 85 switch (type) { 86 case tr.ui.tracks.DrawType.GENERAL_EVENT: 87 this.drawLetterDots_(viewLWorld, viewRWorld); 88 break; 89 } 90 }, 91 92 drawLetterDots_: function(viewLWorld, viewRWorld) { 93 var ctx = this.context(); 94 var pixelRatio = window.devicePixelRatio || 1; 95 96 var bounds = this.getBoundingClientRect(); 97 var height = bounds.height * pixelRatio; 98 var halfHeight = height * 0.5; 99 var twoPi = Math.PI * 2; 100 var palette = tr.ui.b.getColorPalette(); 101 var highlightIdBoost = tr.ui.b.paletteProperties.highlightIdBoost; 102 103 // Culling parameters. 104 var dt = this.viewport.currentDisplayTransform; 105 var dumpRadiusView = this.dumpRadiusView; 106 var itemRadiusWorld = dt.xViewVectorToWorld(height); 107 108 // Draw the memory dumps. 109 var items = this.items_; 110 var loI = tr.b.findLowIndexInSortedArray( 111 items, 112 function(item) { return item.start; }, 113 viewLWorld); 114 115 var oldFont = ctx.font; 116 ctx.font = '400 ' + Math.floor(9 * pixelRatio) + 'px Arial'; 117 ctx.strokeStyle = 'rgb(0,0,0)'; 118 ctx.textBaseline = 'middle'; 119 ctx.textAlign = 'center'; 120 121 var drawItems = function(selected) { 122 for (var i = loI; i < items.length; ++i) { 123 var item = items[i]; 124 var x = item.start; 125 if (x - itemRadiusWorld > viewRWorld) 126 break; 127 if (item.selected !== selected) 128 continue; 129 var xView = dt.xWorldToView(x); 130 131 ctx.fillStyle = EventPresenter.getSelectableItemColor(item); 132 ctx.beginPath(); 133 ctx.arc(xView, halfHeight, dumpRadiusView + 0.5, 0, twoPi); 134 ctx.fill(); 135 if (item.selected) { 136 ctx.lineWidth = 3; 137 ctx.strokeStyle = 'rgb(100,100,0)'; 138 ctx.stroke(); 139 140 ctx.beginPath(); 141 ctx.arc(xView, halfHeight, dumpRadiusView, 0, twoPi); 142 ctx.lineWidth = 1.5; 143 ctx.strokeStyle = 'rgb(255,255,0)'; 144 ctx.stroke(); 145 } else { 146 ctx.lineWidth = 1; 147 ctx.strokeStyle = 'rgb(0,0,0)'; 148 ctx.stroke(); 149 } 150 151 ctx.fillStyle = 'rgb(255, 255, 255)'; 152 ctx.fillText(item.dotLetter, xView, halfHeight); 153 } 154 }; 155 156 // Draw unselected items first to make sure they don't occlude selected 157 // items. 158 drawItems(false); 159 drawItems(true); 160 161 ctx.lineWidth = 1; 162 ctx.font = oldFont; 163 }, 164 165 addEventsToTrackMap: function(eventToTrackMap) { 166 if (this.items_ === undefined) 167 return; 168 169 this.items_.forEach(function(item) { 170 item.addToTrackMap(eventToTrackMap, this); 171 }, this); 172 }, 173 174 addIntersectingEventsInRangeToSelectionInWorldSpace: function( 175 loWX, hiWX, viewPixWidthWorld, selection) { 176 if (this.items_ === undefined) 177 return; 178 179 var itemRadiusWorld = viewPixWidthWorld * this.dumpRadiusView; 180 tr.b.iterateOverIntersectingIntervals( 181 this.items_, 182 function(x) { return x.start - itemRadiusWorld; }, 183 function(x) { return 2 * itemRadiusWorld; }, 184 loWX, hiWX, 185 function(item) { 186 item.addToSelection(selection); 187 }.bind(this)); 188 }, 189 190 /** 191 * Add the item to the left or right of the provided event, if any, to the 192 * selection. 193 * @param {event} The current event item. 194 * @param {Number} offset Number of slices away from the event to look. 195 * @param {Selection} selection The selection to add an event to, 196 * if found. 197 * @return {boolean} Whether an event was found. 198 * @private 199 */ 200 addEventNearToProvidedEventToSelection: function(event, offset, selection) { 201 if (this.items_ === undefined) 202 return; 203 204 var items = this.items_; 205 var index = tr.b.findFirstIndexInArray(items, function(item) { 206 return item.modelItem === event; 207 }); 208 if (index === -1) 209 return false; 210 211 var newIndex = index + offset; 212 if (newIndex >= 0 && newIndex < items.length) { 213 items[newIndex].addToSelection(selection); 214 return true; 215 } 216 return false; 217 }, 218 219 addAllEventsMatchingFilterToSelection: function(filter, selection) { 220 }, 221 222 addClosestEventToSelection: function(worldX, worldMaxDist, loY, hiY, 223 selection) { 224 if (this.items_ === undefined) 225 return; 226 227 var item = tr.b.findClosestElementInSortedArray( 228 this.items_, 229 function(x) { return x.start; }, 230 worldX, 231 worldMaxDist); 232 233 if (!item) 234 return; 235 236 item.addToSelection(selection); 237 } 238 }; 239 240 /** 241 * A filled dot with a letter inside it. 242 * 243 * @constructor 244 * @extends {ProxySelectableItem} 245 */ 246 function LetterDot(modelItem, dotLetter, colorId, start) { 247 tr.model.ProxySelectableItem.call(this, modelItem); 248 this.dotLetter = dotLetter; 249 this.colorId = colorId; 250 this.start = start; 251 }; 252 253 LetterDot.prototype = { 254 __proto__: tr.model.ProxySelectableItem.prototype 255 }; 256 257 return { 258 LetterDotTrack: LetterDotTrack, 259 LetterDot: LetterDot 260 }; 261 }); 262 </script> 263