blob: 2728073aca93ab917ff14b046e044f75e4205d73 [file] [log] [blame]
Michail Schwaba86aae42018-07-20 11:58:28 -04001// Copyright (C) 2018 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this 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
Primiano Tuccif30cd9c2018-08-13 01:53:26 +020015import {TimeSpan} from '../common/time';
16
17import {TimeScale} from './time_scale';
Michail Schwaba86aae42018-07-20 11:58:28 -040018
Michail Schwab7e4b89e2018-07-27 10:48:40 -040019export const DESIRED_PX_PER_STEP = 80;
Michail Schwaba86aae42018-07-20 11:58:28 -040020
Michail Schwab7e4b89e2018-07-27 10:48:40 -040021export function drawGridLines(
Deepanjan Roy4bc80b12018-08-02 10:26:45 -040022 ctx: CanvasRenderingContext2D,
Michail Schwab7e4b89e2018-07-27 10:48:40 -040023 x: TimeScale,
Primiano Tuccif30cd9c2018-08-13 01:53:26 +020024 timeSpan: TimeSpan,
Michail Schwab7e4b89e2018-07-27 10:48:40 -040025 height: number): void {
Primiano Tuccie36ca632018-08-21 14:32:23 +020026 const width = x.deltaTimeToPx(timeSpan.duration);
Michail Schwab7e4b89e2018-07-27 10:48:40 -040027 const desiredSteps = width / DESIRED_PX_PER_STEP;
Primiano Tuccif30cd9c2018-08-13 01:53:26 +020028 const step = getGridStepSize(timeSpan.duration, desiredSteps);
29 const start = Math.round(timeSpan.start / step) * step;
Michail Schwaba86aae42018-07-20 11:58:28 -040030
Michail Schwab7e4b89e2018-07-27 10:48:40 -040031 ctx.strokeStyle = '#999999';
32 ctx.lineWidth = 1;
Michail Schwaba86aae42018-07-20 11:58:28 -040033
Primiano Tuccif30cd9c2018-08-13 01:53:26 +020034 for (let sec = start; sec < timeSpan.end; sec += step) {
35 const xPos = Math.floor(x.timeToPx(sec)) + 0.5;
Michail Schwab7e4b89e2018-07-27 10:48:40 -040036
37 if (xPos >= 0 && xPos <= width) {
38 ctx.beginPath();
39 ctx.moveTo(xPos, 0);
40 ctx.lineTo(xPos, height);
41 ctx.stroke();
Michail Schwaba86aae42018-07-20 11:58:28 -040042 }
43 }
Michail Schwab7e4b89e2018-07-27 10:48:40 -040044}
Michail Schwaba86aae42018-07-20 11:58:28 -040045
Michail Schwab7e4b89e2018-07-27 10:48:40 -040046/**
Primiano Tuccif30cd9c2018-08-13 01:53:26 +020047 * Returns the step size of a grid line in seconds.
48 * The returned step size has two properties:
Michail Schwab7e4b89e2018-07-27 10:48:40 -040049 * (1) It is 1, 2, or 5, multiplied by some integer power of 10.
50 * (2) The number steps in |range| produced by |stepSize| is as close as
51 * possible to |desiredSteps|.
52 */
Primiano Tuccif30cd9c2018-08-13 01:53:26 +020053export function getGridStepSize(range: number, desiredSteps: number): number {
Michail Schwab7e4b89e2018-07-27 10:48:40 -040054 // First, get the largest possible power of 10 that is smaller than the
55 // desired step size, and set it to the current step size.
56 // For example, if the range is 2345ms and the desired steps is 10, then the
57 // desired step size is 234.5 and the step size will be set to 100.
58 const desiredStepSize = range / desiredSteps;
59 const zeros = Math.floor(Math.log10(desiredStepSize));
60 const initialStepSize = Math.pow(10, zeros);
61
62 // This function first calculates how many steps within the range a certain
63 // stepSize will produce, and returns the difference between that and
64 // desiredSteps.
65 const distToDesired = (evaluatedStepSize: number) =>
66 Math.abs(range / evaluatedStepSize - desiredSteps);
67
68 // We know that |initialStepSize| is a power of 10, and
69 // initialStepSize <= desiredStepSize <= 10 * initialStepSize. There are four
70 // possible candidates for final step size: 1, 2, 5 or 10 * initialStepSize.
71 // We pick the candidate that minimizes distToDesired(stepSize).
72 const stepSizeMultipliers = [2, 5, 10];
73
74 let minimalDistance = distToDesired(initialStepSize);
75 let minimizingStepSize = initialStepSize;
76
77 for (const multiplier of stepSizeMultipliers) {
78 const newStepSize = multiplier * initialStepSize;
79 const newDistance = distToDesired(newStepSize);
80 if (newDistance < minimalDistance) {
81 minimalDistance = newDistance;
82 minimizingStepSize = newStepSize;
Michail Schwaba86aae42018-07-20 11:58:28 -040083 }
Michail Schwaba86aae42018-07-20 11:58:28 -040084 }
Michail Schwab7e4b89e2018-07-27 10:48:40 -040085 return minimizingStepSize;
Michail Schwaba86aae42018-07-20 11:58:28 -040086}