1*6dbdd20aSAndroid Build Coastguard Worker// Copyright (C) 2018 The Android Open Source Project 2*6dbdd20aSAndroid Build Coastguard Worker// 3*6dbdd20aSAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*6dbdd20aSAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*6dbdd20aSAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*6dbdd20aSAndroid Build Coastguard Worker// 7*6dbdd20aSAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*6dbdd20aSAndroid Build Coastguard Worker// 9*6dbdd20aSAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*6dbdd20aSAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*6dbdd20aSAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*6dbdd20aSAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*6dbdd20aSAndroid Build Coastguard Worker// limitations under the License. 14*6dbdd20aSAndroid Build Coastguard Worker 15*6dbdd20aSAndroid Build Coastguard Workerimport {assertTrue} from '../base/logging'; 16*6dbdd20aSAndroid Build Coastguard Workerimport {duration, time, Time, TimeSpan} from '../base/time'; 17*6dbdd20aSAndroid Build Coastguard Worker 18*6dbdd20aSAndroid Build Coastguard Workerconst micros = 1000n; 19*6dbdd20aSAndroid Build Coastguard Workerconst millis = 1000n * micros; 20*6dbdd20aSAndroid Build Coastguard Workerconst seconds = 1000n * millis; 21*6dbdd20aSAndroid Build Coastguard Workerconst minutes = 60n * seconds; 22*6dbdd20aSAndroid Build Coastguard Workerconst hours = 60n * minutes; 23*6dbdd20aSAndroid Build Coastguard Workerconst days = 24n * hours; 24*6dbdd20aSAndroid Build Coastguard Worker 25*6dbdd20aSAndroid Build Coastguard Worker// These patterns cover the entire range of 0 - 2^63-1 nanoseconds 26*6dbdd20aSAndroid Build Coastguard Workerconst patterns: [bigint, string][] = [ 27*6dbdd20aSAndroid Build Coastguard Worker [1n, '|'], 28*6dbdd20aSAndroid Build Coastguard Worker [2n, '|:'], 29*6dbdd20aSAndroid Build Coastguard Worker [5n, '|....'], 30*6dbdd20aSAndroid Build Coastguard Worker [10n, '|....:....'], 31*6dbdd20aSAndroid Build Coastguard Worker [20n, '|.:.'], 32*6dbdd20aSAndroid Build Coastguard Worker [50n, '|....'], 33*6dbdd20aSAndroid Build Coastguard Worker [100n, '|....:....'], 34*6dbdd20aSAndroid Build Coastguard Worker [200n, '|.:.'], 35*6dbdd20aSAndroid Build Coastguard Worker [500n, '|....'], 36*6dbdd20aSAndroid Build Coastguard Worker [1n * micros, '|....:....'], 37*6dbdd20aSAndroid Build Coastguard Worker [2n * micros, '|.:.'], 38*6dbdd20aSAndroid Build Coastguard Worker [5n * micros, '|....'], 39*6dbdd20aSAndroid Build Coastguard Worker [10n * micros, '|....:....'], 40*6dbdd20aSAndroid Build Coastguard Worker [20n * micros, '|.:.'], 41*6dbdd20aSAndroid Build Coastguard Worker [50n * micros, '|....'], 42*6dbdd20aSAndroid Build Coastguard Worker [100n * micros, '|....:....'], 43*6dbdd20aSAndroid Build Coastguard Worker [200n * micros, '|.:.'], 44*6dbdd20aSAndroid Build Coastguard Worker [500n * micros, '|....'], 45*6dbdd20aSAndroid Build Coastguard Worker [1n * millis, '|....:....'], 46*6dbdd20aSAndroid Build Coastguard Worker [2n * millis, '|.:.'], 47*6dbdd20aSAndroid Build Coastguard Worker [5n * millis, '|....'], 48*6dbdd20aSAndroid Build Coastguard Worker [10n * millis, '|....:....'], 49*6dbdd20aSAndroid Build Coastguard Worker [20n * millis, '|.:.'], 50*6dbdd20aSAndroid Build Coastguard Worker [50n * millis, '|....'], 51*6dbdd20aSAndroid Build Coastguard Worker [100n * millis, '|....:....'], 52*6dbdd20aSAndroid Build Coastguard Worker [200n * millis, '|.:.'], 53*6dbdd20aSAndroid Build Coastguard Worker [500n * millis, '|....'], 54*6dbdd20aSAndroid Build Coastguard Worker [1n * seconds, '|....:....'], 55*6dbdd20aSAndroid Build Coastguard Worker [2n * seconds, '|.:.'], 56*6dbdd20aSAndroid Build Coastguard Worker [5n * seconds, '|....'], 57*6dbdd20aSAndroid Build Coastguard Worker [10n * seconds, '|....:....'], 58*6dbdd20aSAndroid Build Coastguard Worker [30n * seconds, '|.:.:.'], 59*6dbdd20aSAndroid Build Coastguard Worker [1n * minutes, '|.....'], 60*6dbdd20aSAndroid Build Coastguard Worker [2n * minutes, '|.:.'], 61*6dbdd20aSAndroid Build Coastguard Worker [5n * minutes, '|.....'], 62*6dbdd20aSAndroid Build Coastguard Worker [10n * minutes, '|....:....'], 63*6dbdd20aSAndroid Build Coastguard Worker [30n * minutes, '|.:.:.'], 64*6dbdd20aSAndroid Build Coastguard Worker [1n * hours, '|.....'], 65*6dbdd20aSAndroid Build Coastguard Worker [2n * hours, '|.:.'], 66*6dbdd20aSAndroid Build Coastguard Worker [6n * hours, '|.....'], 67*6dbdd20aSAndroid Build Coastguard Worker [12n * hours, '|.....:.....'], 68*6dbdd20aSAndroid Build Coastguard Worker [1n * days, '|.:.'], 69*6dbdd20aSAndroid Build Coastguard Worker [2n * days, '|.:.'], 70*6dbdd20aSAndroid Build Coastguard Worker [5n * days, '|....'], 71*6dbdd20aSAndroid Build Coastguard Worker [10n * days, '|....:....'], 72*6dbdd20aSAndroid Build Coastguard Worker [20n * days, '|.:.'], 73*6dbdd20aSAndroid Build Coastguard Worker [50n * days, '|....'], 74*6dbdd20aSAndroid Build Coastguard Worker [100n * days, '|....:....'], 75*6dbdd20aSAndroid Build Coastguard Worker [200n * days, '|.:.'], 76*6dbdd20aSAndroid Build Coastguard Worker [500n * days, '|....'], 77*6dbdd20aSAndroid Build Coastguard Worker [1000n * days, '|....:....'], 78*6dbdd20aSAndroid Build Coastguard Worker [2000n * days, '|.:.'], 79*6dbdd20aSAndroid Build Coastguard Worker [5000n * days, '|....'], 80*6dbdd20aSAndroid Build Coastguard Worker [10000n * days, '|....:....'], 81*6dbdd20aSAndroid Build Coastguard Worker [20000n * days, '|.:.'], 82*6dbdd20aSAndroid Build Coastguard Worker [50000n * days, '|....'], 83*6dbdd20aSAndroid Build Coastguard Worker [100000n * days, '|....:....'], 84*6dbdd20aSAndroid Build Coastguard Worker [200000n * days, '|.:.'], 85*6dbdd20aSAndroid Build Coastguard Worker]; 86*6dbdd20aSAndroid Build Coastguard Worker 87*6dbdd20aSAndroid Build Coastguard Worker// Returns the optimal step size and pattern of ticks within the step. 88*6dbdd20aSAndroid Build Coastguard Workerexport function getPattern(minPatternSize: bigint): [duration, string] { 89*6dbdd20aSAndroid Build Coastguard Worker for (const [size, pattern] of patterns) { 90*6dbdd20aSAndroid Build Coastguard Worker if (size >= minPatternSize) { 91*6dbdd20aSAndroid Build Coastguard Worker return [size, pattern]; 92*6dbdd20aSAndroid Build Coastguard Worker } 93*6dbdd20aSAndroid Build Coastguard Worker } 94*6dbdd20aSAndroid Build Coastguard Worker 95*6dbdd20aSAndroid Build Coastguard Worker throw new Error('Pattern not defined for this minsize'); 96*6dbdd20aSAndroid Build Coastguard Worker} 97*6dbdd20aSAndroid Build Coastguard Worker 98*6dbdd20aSAndroid Build Coastguard Workerfunction tickPatternToArray(pattern: string): TickType[] { 99*6dbdd20aSAndroid Build Coastguard Worker const array = Array.from(pattern); 100*6dbdd20aSAndroid Build Coastguard Worker return array.map((char) => { 101*6dbdd20aSAndroid Build Coastguard Worker switch (char) { 102*6dbdd20aSAndroid Build Coastguard Worker case '|': 103*6dbdd20aSAndroid Build Coastguard Worker return TickType.MAJOR; 104*6dbdd20aSAndroid Build Coastguard Worker case ':': 105*6dbdd20aSAndroid Build Coastguard Worker return TickType.MEDIUM; 106*6dbdd20aSAndroid Build Coastguard Worker case '.': 107*6dbdd20aSAndroid Build Coastguard Worker return TickType.MINOR; 108*6dbdd20aSAndroid Build Coastguard Worker default: 109*6dbdd20aSAndroid Build Coastguard Worker // This is almost certainly a developer/fat-finger error 110*6dbdd20aSAndroid Build Coastguard Worker throw Error(`Invalid char "${char}" in pattern "${pattern}"`); 111*6dbdd20aSAndroid Build Coastguard Worker } 112*6dbdd20aSAndroid Build Coastguard Worker }); 113*6dbdd20aSAndroid Build Coastguard Worker} 114*6dbdd20aSAndroid Build Coastguard Worker 115*6dbdd20aSAndroid Build Coastguard Workerexport enum TickType { 116*6dbdd20aSAndroid Build Coastguard Worker MAJOR, 117*6dbdd20aSAndroid Build Coastguard Worker MEDIUM, 118*6dbdd20aSAndroid Build Coastguard Worker MINOR, 119*6dbdd20aSAndroid Build Coastguard Worker} 120*6dbdd20aSAndroid Build Coastguard Worker 121*6dbdd20aSAndroid Build Coastguard Workerexport interface Tick { 122*6dbdd20aSAndroid Build Coastguard Worker type: TickType; 123*6dbdd20aSAndroid Build Coastguard Worker time: time; 124*6dbdd20aSAndroid Build Coastguard Worker} 125*6dbdd20aSAndroid Build Coastguard Worker 126*6dbdd20aSAndroid Build Coastguard Workerexport const MIN_PX_PER_STEP = 120; 127*6dbdd20aSAndroid Build Coastguard Workerexport function getMaxMajorTicks(width: number) { 128*6dbdd20aSAndroid Build Coastguard Worker return Math.max(1, Math.floor(width / MIN_PX_PER_STEP)); 129*6dbdd20aSAndroid Build Coastguard Worker} 130*6dbdd20aSAndroid Build Coastguard Worker 131*6dbdd20aSAndroid Build Coastguard Workerexport function* generateTicks( 132*6dbdd20aSAndroid Build Coastguard Worker timeSpan: TimeSpan, 133*6dbdd20aSAndroid Build Coastguard Worker maxMajorTicks: number, 134*6dbdd20aSAndroid Build Coastguard Worker offset: time = Time.ZERO, 135*6dbdd20aSAndroid Build Coastguard Worker): Generator<Tick> { 136*6dbdd20aSAndroid Build Coastguard Worker assertTrue(timeSpan.duration > 0n, 'timeSpan.duration cannot be lte 0'); 137*6dbdd20aSAndroid Build Coastguard Worker assertTrue(maxMajorTicks > 0, 'maxMajorTicks cannot be lte 0'); 138*6dbdd20aSAndroid Build Coastguard Worker 139*6dbdd20aSAndroid Build Coastguard Worker timeSpan = timeSpan.translate(-offset); 140*6dbdd20aSAndroid Build Coastguard Worker const minStepSize = BigInt( 141*6dbdd20aSAndroid Build Coastguard Worker Math.floor(Number(timeSpan.duration) / maxMajorTicks), 142*6dbdd20aSAndroid Build Coastguard Worker ); 143*6dbdd20aSAndroid Build Coastguard Worker const [patternSize, pattern] = getPattern(minStepSize); 144*6dbdd20aSAndroid Build Coastguard Worker const tickPattern = tickPatternToArray(pattern); 145*6dbdd20aSAndroid Build Coastguard Worker 146*6dbdd20aSAndroid Build Coastguard Worker const stepSize = patternSize / BigInt(tickPattern.length); 147*6dbdd20aSAndroid Build Coastguard Worker const start = Time.quantFloor(timeSpan.start, patternSize); 148*6dbdd20aSAndroid Build Coastguard Worker const end = timeSpan.end; 149*6dbdd20aSAndroid Build Coastguard Worker let patternIndex = 0; 150*6dbdd20aSAndroid Build Coastguard Worker 151*6dbdd20aSAndroid Build Coastguard Worker for ( 152*6dbdd20aSAndroid Build Coastguard Worker let time = start; 153*6dbdd20aSAndroid Build Coastguard Worker time < end; 154*6dbdd20aSAndroid Build Coastguard Worker time = Time.add(time, stepSize), patternIndex++ 155*6dbdd20aSAndroid Build Coastguard Worker ) { 156*6dbdd20aSAndroid Build Coastguard Worker if (time >= timeSpan.start) { 157*6dbdd20aSAndroid Build Coastguard Worker patternIndex = patternIndex % tickPattern.length; 158*6dbdd20aSAndroid Build Coastguard Worker const type = tickPattern[patternIndex]; 159*6dbdd20aSAndroid Build Coastguard Worker yield {type, time: Time.add(time, offset)}; 160*6dbdd20aSAndroid Build Coastguard Worker } 161*6dbdd20aSAndroid Build Coastguard Worker } 162*6dbdd20aSAndroid Build Coastguard Worker} 163