// Copyright (C) 2018 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import {assertTrue} from '../base/logging'; import {duration, Span, time} from '../base/time'; import { HighPrecisionTime, HighPrecisionTimeSpan, } from '../common/high_precision_time'; export class TimeScale { private _start: HighPrecisionTime; private _durationNanos: number; readonly pxSpan: PxSpan; private _nanosPerPx = 0; static fromHPTimeSpan(span: Span, pxSpan: PxSpan) { return new TimeScale(span.start, span.duration.nanos, pxSpan); } constructor(start: HighPrecisionTime, durationNanos: number, pxSpan: PxSpan) { this.pxSpan = pxSpan; this._start = start; this._durationNanos = durationNanos; if (durationNanos <= 0 || pxSpan.delta <= 0) { this._nanosPerPx = 1; } else { this._nanosPerPx = durationNanos / pxSpan.delta; } } get timeSpan(): Span { const end = this._start.addNanos(this._durationNanos); return new HighPrecisionTimeSpan(this._start, end); } timeToPx(ts: time): number { // WARNING: Number(bigint) can be surprisingly slow. Avoid in hotpath. const timeOffsetNanos = Number(ts - this._start.base) - this._start.offset; return this.pxSpan.start + timeOffsetNanos / this._nanosPerPx; } hpTimeToPx(time: HighPrecisionTime): number { const timeOffsetNanos = time.sub(this._start).nanos; return this.pxSpan.start + timeOffsetNanos / this._nanosPerPx; } // Convert pixels to a high precision time object, which can be futher // converted to other time formats. pxToHpTime(px: number): HighPrecisionTime { const offsetNanos = (px - this.pxSpan.start) * this._nanosPerPx; return this._start.addNanos(offsetNanos); } durationToPx(dur: duration): number { // WARNING: Number(bigint) can be surprisingly slow. Avoid in hotpath. return Number(dur) / this._nanosPerPx; } pxDeltaToDuration(pxDelta: number): HighPrecisionTime { const time = pxDelta * this._nanosPerPx; return HighPrecisionTime.fromNanos(time); } } export class PxSpan { static readonly ZERO = new PxSpan(0, 0); constructor(private _start: number, private _end: number) { assertTrue(_start <= _end, 'PxSpan start > end'); } get start(): number { return this._start; } get end(): number { return this._end; } get delta(): number { return this._end - this._start; } }