1// Copyright (C) 2019 The Android Open Source Project 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use size file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15import * as m from 'mithril'; 16 17import {timeToString} from '../common/time'; 18import {TimeSpan} from '../common/time'; 19 20import {globals} from './globals'; 21import {gridlines} from './gridline_helper'; 22import {Panel, PanelSize} from './panel'; 23import {TRACK_SHELL_WIDTH} from './track_constants'; 24 25export interface BBox { 26 x: number; 27 y: number; 28 width: number; 29 height: number; 30} 31 32// Draws a vertical line with two horizontal tails at the left and right and 33// a label in the middle. It looks a bit like a stretched H: 34// |--- Label ---| 35// The |target| bounding box determines where to draw the H. 36// The |bounds| bounding box gives the visible region, this is used to adjust 37// the positioning of the label to ensure it is on screen. 38function drawHBar( 39 ctx: CanvasRenderingContext2D, target: BBox, bounds: BBox, label: string) { 40 ctx.fillStyle = '#222'; 41 42 const xLeft = Math.floor(target.x); 43 const xRight = Math.ceil(target.x + target.width); 44 const yMid = Math.floor(target.height / 2 + target.y); 45 const xWidth = xRight - xLeft; 46 47 // Draw horizontal bar of the H. 48 ctx.fillRect(xLeft, yMid, xWidth, 1); 49 // Draw left vertical bar of the H. 50 ctx.fillRect(xLeft, target.y, 1, target.height); 51 // Draw right vertical bar of the H. 52 ctx.fillRect(xRight, target.y, 1, target.height); 53 54 const labelWidth = ctx.measureText(label).width; 55 56 // Find a good position for the label: 57 // By default put the label in the middle of the H: 58 let labelXLeft = Math.floor(xWidth / 2 - labelWidth / 2 + xLeft); 59 60 if (labelWidth > target.width || labelXLeft < bounds.x || 61 (labelXLeft + labelWidth) > (bounds.x + bounds.width)) { 62 // It won't fit in the middle or would be at least partly out of bounds 63 // so put it either to the left or right: 64 if (xRight > bounds.x + bounds.width) { 65 // If the H extends off the right side of the screen the label 66 // goes on the left of the H. 67 labelXLeft = xLeft - labelWidth - 3; 68 } else { 69 // Otherwise the label goes on the right of the H. 70 labelXLeft = xRight + 3; 71 } 72 } 73 74 ctx.fillStyle = '#ffffff'; 75 ctx.fillRect(labelXLeft - 1, 0, labelWidth + 1, target.height); 76 77 ctx.textBaseline = 'middle'; 78 ctx.fillStyle = '#222'; 79 ctx.font = '10px Google Sans'; 80 ctx.fillText(label, labelXLeft, yMid); 81} 82 83export class TimeSelectionPanel extends Panel { 84 view() { 85 return m('.time-selection-panel'); 86 } 87 88 renderCanvas(ctx: CanvasRenderingContext2D, size: PanelSize) { 89 const range = globals.frontendLocalState.visibleWindowTime; 90 const timeScale = globals.frontendLocalState.timeScale; 91 92 ctx.fillStyle = '#999'; 93 ctx.fillRect(TRACK_SHELL_WIDTH - 1, 0, 2, size.height); 94 for (const xAndTime of gridlines(size.width, range, timeScale)) { 95 ctx.fillRect(xAndTime[0], 0, 1, size.height); 96 } 97 98 const selection = globals.state.currentSelection; 99 if (selection !== null && selection.kind === `TIMESPAN`) { 100 const start = Math.min(selection.startTs, selection.endTs); 101 const end = Math.max(selection.startTs, selection.endTs); 102 this.renderSpan(ctx, size, new TimeSpan(start, end)); 103 } 104 } 105 106 renderSpan(ctx: CanvasRenderingContext2D, size: PanelSize, span: TimeSpan) { 107 const timeScale = globals.frontendLocalState.timeScale; 108 const xLeft = timeScale.timeToPx(span.start); 109 const xRight = timeScale.timeToPx(span.end); 110 const label = timeToString(span.duration); 111 drawHBar( 112 ctx, 113 { 114 x: TRACK_SHELL_WIDTH + xLeft, 115 y: 0, 116 width: xRight - xLeft, 117 height: size.height 118 }, 119 {x: 0, y: 0, width: size.width, height: size.height}, 120 label); 121 } 122} 123