Redesign the timeline details panel.

This redesigns the aspects of the timeline, particularly relating to
the details panel. First, selection mechanics are greatly simplified,
so items can be hovered while one is selected. Additionally, hovered
item names are now shown as part of the cursor. The details panel
now only shows details for selected items, and is moved to fill the
bottom of the screen; similarly, the timeline now fills the full width
of the screen.

Change-Id: I0acb88f898dcfd0a0327a38aa5eb995f118e1a1e
This commit is contained in:
Tim Buckley 2016-01-06 16:05:58 -07:00
parent a419142cb7
commit f1a1f1a650
5 changed files with 82 additions and 59 deletions

View File

@ -11,34 +11,12 @@ function timelineDetails() {
* @ngInject
*/
var controller = function($scope) {
$scope.item = null;
$scope.$watch('hoveredItem', function(value) {
if (value && !$scope.selectedItem) {
$scope.item = value;
} else if (!value && !$scope.selectedItem) {
$scope.item = null;
}
});
$scope.$watch('selectedItem', function(value) {
if (value) {
$scope.item = value;
} else {
if ($scope.hoveredItem) {
$scope.item = $scope.hoveredItem;
} else {
$scope.item = null;
}
}
});
};
return {
restrict: 'EA',
scope: {
'hoveredItem': '=',
'selectedItem': '='
'item': '='
},
controller: controller,
templateUrl: 'directives/timeline-details.html'

View File

@ -54,6 +54,14 @@ function timelineViewport($document) {
.style('text-anchor', 'middle')
.style('font', '9px sans-serif');
var cursorItemText = cursorGroup.append('text')
.attr('x', 0)
.attr('y', -22)
.attr('dy', '-.5ex')
.style('text-anchor', 'middle')
.style('font', '12px sans-serif')
.style('font-weight', 'bold');
var selectedRect = null;
var color = function(rect, color) {
@ -79,26 +87,24 @@ function timelineViewport($document) {
};
var rectMouseOver = function(d) {
if (selectedRect !== null) {
return;
}
timelineController.setHover(d);
scope.$apply();
color(d3.select(this), statusColorMap.hover);
if (!timelineController.selection
|| d !== timelineController.selection.item) {
color(d3.select(this), statusColorMap.hover);
}
};
var rectMouseOut = function(d) {
if (selectedRect !== null) {
return;
}
timelineController.clearHover();
scope.$apply();
var self = d3.select(this);
uncolor(d3.select(this));
if (!timelineController.selection
|| d !== timelineController.selection.item) {
var self = d3.select(this);
uncolor(d3.select(this));
}
};
var rectClick = function(d) {
@ -240,6 +246,26 @@ function timelineViewport($document) {
.attr('transform', 'translate(' + relX + ', 0)');
cursorText.text(d3.time.format('%X')(currentTime));
if (timelineController.hover) {
var name = timelineController.hover.name.split('.').pop();
cursorItemText.text(name);
var width = cursorItemText.node().getComputedTextLength();
var leftEdge = margin.left;
var rightEdge = timelineController.width + margin.left;
if (px + (width / 2) > rightEdge) {
cursorItemText.attr('dx', -(px - (rightEdge - width / 2)));
} else if (px - (width / 2) < leftEdge) {
cursorItemText.attr('dx', (leftEdge + width / 2) - px);
} else {
cursorItemText.attr('dx', 0);
}
} else {
cursorItemText.text('');
cursorItemText.attr('dx', 0);
}
}
});

View File

@ -42,7 +42,7 @@ function timeline($log, datasetService) {
self.dataRaw = [];
self.dstat = [];
self.margin = { top: 20, right: 10, bottom: 10, left: 80 };
self.margin = { top: 40, right: 10, bottom: 10, left: 80 };
self.width = 0;
self.height = 550 - this.margin.top - this.margin.bottom;

View File

@ -1,13 +1,27 @@
<div class="panel-body" ng-if="!item">
<i>Hover over a timeline item for details.</i>
<div ng-if="!item" class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Test Details</h3>
</div>
<div class="panel-body">
<i>Select a test above for details.</i>
</div>
</div>
<div class="panel-body" ng-if="!!item">
<div ng-if="!!item"
class="panel"
ng-class="{'panel-success': item.status == 'success', 'panel-info': item.status == 'skip', 'panel-danger': item.status == 'fail'}">
<div class="panel-heading">
<h3 class="panel-title">
Details: {{item.name | split:'.' | pickRight:1}}
<span class="label label-success"
ng-if="item.status == 'success'">success</span>
<span class="label label-info"
ng-if="item.status == 'skip'">skip</span>
<span class="label label-danger"
ng-if="item.status == 'fail'">fail</span>
</h3>
</div>
<table class="table table-bordered table-hover table-striped">
<tr>
<td>Name</td>
<td>{{item.name | split:'.' | pickRight:1}}</td>
</tr>
<tr>
<td>Class</td>
<td>{{item.name | split:'.' | pickRight:2}}</td>
@ -15,17 +29,27 @@
<td>Module</td>
<td>{{item.name | split:'.' | slice:0:-2 | join:'.'}}</td>
</tr>
<tr>
<td>Status</td>
<td>{{item.status}}</td>
</tr>
<tr>
<td>Tags</td>
<td>{{item.tags | join:', '}}</td>
</tr>
<tr>
<td>Duration</td>
<td>{{item.duration}} seconds</td>
<td>{{item.duration | number:1}} seconds</td>
</tr>
<tr>
<td>Start</td>
<td>{{item.startDate | date:'medium'}}</td>
</tr>
<tr>
<td>End</td>
<td>{{item.endDate | date:'medium'}}</td>
</tr>
</table>
<div class="panel-footer clearfix">
<div class="btn-group pull-right">
<a type="button"
class="btn btn-default">Details</a>
</div>
</div>
</div>

View File

@ -16,12 +16,11 @@
</div>
</div>
<div class="row" ng-if="!timeline.error">
<div class="col-lg-8">
<div class="col-lg-12">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"><fa name="clock-o" fw></fa> Timeline</h3>
<h3 class="panel-title">Timeline</h3>
</div>
<timeline class="panel-body"
dataset="timeline.dataset"
hovered-item="timeline.hoveredItem"
@ -33,15 +32,11 @@
</timeline>
</div>
</div>
<div class="col-lg-4">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"><fa name="info" fw></fa> Details</h3>
</div>
<timeline-details hovered-item="timeline.hoveredItem"
selected-item="timeline.selectedItem"></timeline-details>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<a name="details"></a>
<timeline-details item="timeline.selectedItem"></timeline-details>
</div>
</div>
</div>