blob: c54496d0970a4dc27b1f10c822c85f32a5ff6c64 [file] [log] [blame]
<!DOCTYPE html>
<!--
Copyright (c) 2013 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="stylesheet" href="/ui/tracks/rect_track.css">
<link rel="import" href="/base/sorted_array_utils.html">
<link rel="import" href="/model/proxy_selectable_item.html">
<link rel="import" href="/ui/base/draw_helpers.html">
<link rel="import" href="/ui/base/fast_rect_renderer.html">
<link rel="import" href="/ui/base/heading.html">
<link rel="import" href="/ui/base/ui.html">
<link rel="import" href="/ui/tracks/track.html">
<script>
'use strict';
tr.exportTo('tr.ui.tracks', function() {
/**
* A track that displays an array of Rect objects.
* @constructor
* @extends {Track}
*/
var RectTrack = tr.ui.b.define(
'rect-track', tr.ui.tracks.Track);
RectTrack.prototype = {
__proto__: tr.ui.tracks.Track.prototype,
decorate: function(viewport) {
tr.ui.tracks.Track.prototype.decorate.call(this, viewport);
this.classList.add('rect-track');
this.asyncStyle_ = false;
this.rects_ = null;
this.heading_ = document.createElement('tr-ui-heading');
this.appendChild(this.heading_);
},
set heading(heading) {
this.heading_.heading = heading;
},
get heading() {
return this.heading_.heading;
},
set tooltip(tooltip) {
this.heading_.tooltip = tooltip;
},
set selectionGenerator(generator) {
this.heading_.selectionGenerator = generator;
},
set expanded(expanded) {
this.heading_.expanded = !!expanded;
},
set arrowVisible(arrowVisible) {
this.heading_.arrowVisible = !!arrowVisible;
},
get expanded() {
return this.heading_.expanded;
},
get asyncStyle() {
return this.asyncStyle_;
},
set asyncStyle(v) {
this.asyncStyle_ = !!v;
},
get rects() {
return this.rects_;
},
set rects(rects) {
this.rects_ = rects || [];
this.invalidateDrawingContainer();
},
get height() {
return window.getComputedStyle(this).height;
},
set height(height) {
this.style.height = height;
this.invalidateDrawingContainer();
},
get hasVisibleContent() {
return this.rects_.length > 0;
},
draw: function(type, viewLWorld, viewRWorld) {
switch (type) {
case tr.ui.tracks.DrawType.GENERAL_EVENT:
this.drawRects_(viewLWorld, viewRWorld);
break;
}
},
drawRects_: function(viewLWorld, viewRWorld) {
var ctx = this.context();
ctx.save();
var bounds = this.getBoundingClientRect();
tr.ui.b.drawSlices(
ctx,
this.viewport.currentDisplayTransform,
viewLWorld,
viewRWorld,
bounds.height,
this.rects_,
this.asyncStyle_);
ctx.restore();
if (bounds.height <= 6)
return;
var fontSize, yOffset;
if (bounds.height < 15) {
fontSize = 6;
yOffset = 1.0;
} else {
fontSize = 10;
yOffset = 2.5;
}
tr.ui.b.drawLabels(
ctx,
this.viewport.currentDisplayTransform,
viewLWorld,
viewRWorld,
this.rects_,
this.asyncStyle_,
fontSize,
yOffset);
},
addEventsToTrackMap: function(eventToTrackMap) {
if (this.rects_ === undefined || this.rects_ === null)
return;
this.rects_.forEach(function(rect) {
rect.addToTrackMap(eventToTrackMap, this);
}, this);
},
addIntersectingEventsInRangeToSelectionInWorldSpace: function(
loWX, hiWX, viewPixWidthWorld, selection) {
function onRect(rect) {
rect.addToSelection(selection);
}
onRect = onRect.bind(this);
tr.b.iterateOverIntersectingIntervals(this.rects_,
function(x) { return x.start; },
function(x) { return x.duration; },
loWX, hiWX,
onRect);
},
/**
* Add the item to the left or right of the provided event, if any, to the
* selection.
* @param {rect} The current rect.
* @param {Number} offset Number of rects 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) {
var index = tr.b.findFirstIndexInArray(this.rects_, function(rect) {
return rect.modelItem === event;
});
if (index === -1)
return false;
var newIndex = index + offset;
if (newIndex < 0 || newIndex >= this.rects_.length)
return false;
this.rects_[newIndex].addToSelection(selection);
return true;
},
addAllEventsMatchingFilterToSelection: function(filter, selection) {
for (var i = 0; i < this.rects_.length; ++i) {
// TODO(petrcermak): Rather than unpacking the proxy item here,
// we should probably add an addToSelectionIfMatching(selection, filter)
// method to SelectableItem (#900).
var modelItem = this.rects_[i].modelItem;
if (!modelItem)
continue;
if (filter.matchSlice(modelItem))
selection.push(modelItem);
}
},
addClosestEventToSelection: function(worldX, worldMaxDist, loY, hiY,
selection) {
var rect = tr.b.findClosestIntervalInSortedIntervals(
this.rects_,
function(x) { return x.start; },
function(x) { return x.end; },
worldX,
worldMaxDist);
if (!rect)
return;
rect.addToSelection(selection);
}
};
/**
* A filled rectangle with a title.
*
* @constructor
* @extends {ProxySelectableItem}
*/
function Rect(modelItem, title, colorId, start, duration) {
tr.model.ProxySelectableItem.call(this, modelItem);
this.title = title;
this.colorId = colorId;
this.start = start;
this.duration = duration;
this.end = start + duration;
};
Rect.prototype = {
__proto__: tr.model.ProxySelectableItem.prototype
};
return {
RectTrack: RectTrack,
Rect: Rect
};
});
</script>