blob: 8aefc8d620b2ae981f46c4413d93a8418ad5e3a1 [file] [log] [blame]
<!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="/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';
tr.exportTo('tr.c.tracks', function() {
var EventPresenter = tr.c.EventPresenter;
var SelectionState = tr.model.SelectionState;
/**
* A track that displays an array of dots with filled letters inside them.
* @constructor
* @extends {HeadingTrack}
*/
var LetterDotTrack = tr.b.ui.define(
'letter-dot-track', tr.c.tracks.HeadingTrack);
LetterDotTrack.prototype = {
__proto__: tr.c.tracks.HeadingTrack.prototype,
decorate: function(viewport) {
tr.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 tr.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 = tr.b.ui.getColorPalette();
var highlightIdBoost = tr.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 = tr.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;
tr.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 = tr.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 = tr.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) {
tr.model.ProxySelectableItem.call(this, modelItem);
this.dotLetter = dotLetter;
this.colorId = colorId;
this.start = start;
};
LetterDot.prototype = {
__proto__: tr.model.ProxySelectableItem.prototype
};
return {
LetterDotTrack: LetterDotTrack,
LetterDot: LetterDot
};
});
</script>