| <!DOCTYPE html> |
| <!-- |
| Copyright (c) 2015 The Chromium Authors. All rights reserved. |
| Use of this source code is governed by a BSD-style license that can be |
| found in the LICENSE file. |
| --> |
| |
| <link rel="import" href="/core/event_presenter.html"> |
| <link rel="import" href="/core/trace_model/proxy_selectable_item.html"> |
| <link rel="import" href="/core/tracks/heading_track.html"> |
| <link rel="import" href="/base/ui/color_scheme.html"> |
| <link rel="import" href="/base/sorted_array_utils.html"> |
| <link rel="import" href="/base/ui.html"> |
| <style> |
| .letter-dot-track { |
| height: 18px; |
| } |
| </style> |
| |
| <script> |
| 'use strict'; |
| |
| tv.exportTo('tv.c.tracks', function() { |
| var EventPresenter = tv.c.EventPresenter; |
| var SelectionState = tv.c.trace_model.SelectionState; |
| |
| /** |
| * A track that displays an array of dots with filled letters inside them. |
| * @constructor |
| * @extends {HeadingTrack} |
| */ |
| var LetterDotTrack = tv.b.ui.define( |
| 'letter-dot-track', tv.c.tracks.HeadingTrack); |
| |
| LetterDotTrack.prototype = { |
| __proto__: tv.c.tracks.HeadingTrack.prototype, |
| |
| decorate: function(viewport) { |
| tv.c.tracks.HeadingTrack.prototype.decorate.call(this, viewport); |
| this.classList.add('letter-dot-track'); |
| this.items_ = undefined; |
| }, |
| |
| get items() { |
| return this.items_; |
| }, |
| |
| set items(items) { |
| this.items_ = items; |
| this.invalidateDrawingContainer(); |
| }, |
| |
| get height() { |
| return window.getComputedStyle(this).height; |
| }, |
| |
| set height(height) { |
| this.style.height = height; |
| }, |
| |
| get dumpRadiusView() { |
| return 7 * (window.devicePixelRatio || 1); |
| }, |
| |
| draw: function(type, viewLWorld, viewRWorld) { |
| if (this.items_ === undefined) |
| return; |
| switch (type) { |
| case tv.c.tracks.DrawType.GENERAL_EVENT: |
| this.drawLetterDots_(viewLWorld, viewRWorld); |
| break; |
| } |
| }, |
| |
| drawLetterDots_: function(viewLWorld, viewRWorld) { |
| var ctx = this.context(); |
| var pixelRatio = window.devicePixelRatio || 1; |
| |
| var bounds = this.getBoundingClientRect(); |
| var height = bounds.height * pixelRatio; |
| var halfHeight = height * 0.5; |
| var twoPi = Math.PI * 2; |
| var palette = tv.b.ui.getColorPalette(); |
| var highlightIdBoost = tv.b.ui.paletteProperties.highlightIdBoost; |
| |
| // Culling parameters. |
| var dt = this.viewport.currentDisplayTransform; |
| var dumpRadiusView = this.dumpRadiusView; |
| var itemRadiusWorld = dt.xViewVectorToWorld(height); |
| |
| // Draw the memory dumps. |
| var items = this.items_; |
| var loI = tv.b.findLowIndexInSortedArray( |
| items, |
| function(item) { return item.start; }, |
| viewLWorld); |
| |
| var oldFont = ctx.font; |
| ctx.font = '400 ' + Math.floor(9 * pixelRatio) + 'px Arial'; |
| ctx.strokeStyle = 'rgb(0,0,0)'; |
| ctx.textBaseline = 'middle'; |
| ctx.textAlign = 'center'; |
| |
| var drawItems = function(selected) { |
| for (var i = loI; i < items.length; ++i) { |
| var item = items[i]; |
| var x = item.start; |
| if (x - itemRadiusWorld > viewRWorld) |
| break; |
| if (item.selected !== selected) |
| continue; |
| var xView = dt.xWorldToView(x); |
| |
| ctx.fillStyle = EventPresenter.getSelectableItemColor(item); |
| ctx.beginPath(); |
| ctx.arc(xView, halfHeight, dumpRadiusView + 0.5, 0, twoPi); |
| ctx.fill(); |
| if (item.selected) { |
| ctx.lineWidth = 3; |
| ctx.strokeStyle = 'rgb(100,100,0)'; |
| ctx.stroke(); |
| |
| ctx.beginPath(); |
| ctx.arc(xView, halfHeight, dumpRadiusView, 0, twoPi); |
| ctx.lineWidth = 1.5; |
| ctx.strokeStyle = 'rgb(255,255,0)'; |
| ctx.stroke(); |
| } else { |
| ctx.lineWidth = 1; |
| ctx.strokeStyle = 'rgb(0,0,0)'; |
| ctx.stroke(); |
| } |
| |
| ctx.fillStyle = 'rgb(255, 255, 255)'; |
| ctx.fillText(item.dotLetter, xView, halfHeight); |
| } |
| }; |
| |
| // Draw unselected items first to make sure they don't occlude selected |
| // items. |
| drawItems(false); |
| drawItems(true); |
| |
| ctx.lineWidth = 1; |
| ctx.font = oldFont; |
| }, |
| |
| addEventsToTrackMap: function(eventToTrackMap) { |
| if (this.items_ === undefined) |
| return; |
| |
| this.items_.forEach(function(item) { |
| item.addToTrackMap(eventToTrackMap, this); |
| }, this); |
| }, |
| |
| addIntersectingEventsInRangeToSelectionInWorldSpace: function( |
| loWX, hiWX, viewPixWidthWorld, selection) { |
| if (this.items_ === undefined) |
| return; |
| |
| var itemRadiusWorld = viewPixWidthWorld * this.dumpRadiusView; |
| tv.b.iterateOverIntersectingIntervals( |
| this.items_, |
| function(x) { return x.start - itemRadiusWorld; }, |
| function(x) { return 2 * itemRadiusWorld; }, |
| loWX, hiWX, |
| function(item) { |
| item.addToSelection(selection); |
| }.bind(this)); |
| }, |
| |
| /** |
| * Add the item to the left or right of the provided event, if any, to the |
| * selection. |
| * @param {event} The current event item. |
| * @param {Number} offset Number of slices away from the event to look. |
| * @param {Selection} selection The selection to add an event to, |
| * if found. |
| * @return {boolean} Whether an event was found. |
| * @private |
| */ |
| addEventNearToProvidedEventToSelection: function(event, offset, selection) { |
| if (this.items_ === undefined) |
| return; |
| |
| var items = this.items_; |
| var index = tv.b.findFirstIndexInArray(items, function(item) { |
| return item.modelItem === event; |
| }); |
| if (index === -1) |
| return false; |
| |
| var newIndex = index + offset; |
| if (newIndex >= 0 && newIndex < items.length) { |
| items[newIndex].addToSelection(selection); |
| return true; |
| } |
| return false; |
| }, |
| |
| addAllEventsMatchingFilterToSelection: function(filter, selection) { |
| }, |
| |
| addClosestEventToSelection: function(worldX, worldMaxDist, loY, hiY, |
| selection) { |
| if (this.items_ === undefined) |
| return; |
| |
| var item = tv.b.findClosestElementInSortedArray( |
| this.items_, |
| function(x) { return x.start; }, |
| worldX, |
| worldMaxDist); |
| |
| if (!item) |
| return; |
| |
| item.addToSelection(selection); |
| } |
| }; |
| |
| /** |
| * A filled dot with a letter inside it. |
| * |
| * @constructor |
| * @extends {ProxySelectableItem} |
| */ |
| function LetterDot(modelItem, dotLetter, colorId, start) { |
| tv.c.trace_model.ProxySelectableItem.call(this, modelItem); |
| this.dotLetter = dotLetter; |
| this.colorId = colorId; |
| this.start = start; |
| }; |
| |
| LetterDot.prototype = { |
| __proto__: tv.c.trace_model.ProxySelectableItem.prototype |
| }; |
| |
| return { |
| LetterDotTrack: LetterDotTrack, |
| LetterDot: LetterDot |
| }; |
| }); |
| </script> |