• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2022 Huawei Device Co., Ltd.
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 */
15
16import {BaseElement, element} from "../../../base-ui/BaseElement.js";
17import {TimeRuler} from "./timer-shaft/TimeRuler.js";
18import {Rect} from "./timer-shaft/Rect.js";
19import {RangeRuler, TimeRange} from "./timer-shaft/RangeRuler.js";
20import {SportRuler} from "./timer-shaft/SportRuler.js";
21import {procedurePool} from "../../database/Procedure.js";
22
23export function ns2s(ns: number): string {
24    let second1 = 1_000_000_000; // 1 second
25    let millisecond1 = 1_000_000; // 1 millisecond
26    let microsecond1 = 1_000; // 1 microsecond
27    let nanosecond1 = 1000.0;
28    let res;
29    if (ns >= second1) {
30        res = (ns / 1000 / 1000 / 1000).toFixed(1) + " s";
31    } else if (ns >= millisecond1) {
32        res = (ns / 1000 / 1000).toFixed(1) + " ms";
33    } else if (ns >= microsecond1) {
34        res = (ns / 1000).toFixed(1) + " μs";
35    } else if (ns > 0) {
36        res = ns.toFixed(1) + " ns";
37    } else {
38        res = ns.toFixed(1) + " s";
39    }
40    return res;
41}
42
43export function ns2x(ns: number, startNS: number, endNS: number, duration: number, rect: Rect) {
44    if (endNS == 0) {
45        endNS = duration;
46    }
47    let xSize: number = (ns - startNS) * rect.width / (endNS - startNS);
48    if (xSize < 0) {
49        xSize = 0;
50    }
51    if (xSize > rect.width) {
52        xSize = rect.width;
53    }
54    return xSize;
55}
56
57@element('timer-shaft-element')
58export class TimerShaftElement extends BaseElement {
59    public ctx: CanvasRenderingContext2D | undefined | null
60    public canvas: HTMLCanvasElement | null | undefined
61    public totalEL: HTMLDivElement | null | undefined
62    public timeTotalEL: HTMLSpanElement | null | undefined
63    public timeOffsetEL: HTMLSpanElement | null | undefined
64    public loadComplete: boolean = false
65    // @ts-ignore
66    offscreen: OffscreenCanvas | undefined;
67    isOffScreen: boolean = false;
68    rangeChangeHandler: ((timeRange: TimeRange) => void) | undefined = undefined
69    dpr = window.devicePixelRatio || 1;
70    frame: Rect = new Rect(0, 0, 0, 0);
71    must: boolean = true
72    hoverX: number = 0
73    hoverY: number = 0
74    canvasWidth: number = 0
75    canvasHeight: number = 0
76    protected timeRuler: TimeRuler | undefined;
77    protected rangeRuler: RangeRuler | undefined;
78    protected sportRuler: SportRuler | undefined;
79    private root: HTMLDivElement | undefined | null
80
81    _cpuUsage: Array<{ cpu: number, ro: number, rate: number }> = []
82
83    set cpuUsage(value: Array<{ cpu: number, ro: number, rate: number }>) {
84        this._cpuUsage = value;
85        if (this.rangeRuler) {
86            this.rangeRuler.cpuUsage = this._cpuUsage;
87        }
88    }
89
90    private _totalNS: number = 10_000_000_000;
91
92    get totalNS(): number {
93        return this._totalNS;
94    }
95
96    set totalNS(value: number) {
97        this._totalNS = value;
98        if (this.timeRuler) this.timeRuler.totalNS = value;
99        if (this.rangeRuler) this.rangeRuler.range.totalNS = value;
100        if (this.timeTotalEL) this.timeTotalEL.textContent = `${ns2s(value)}`
101        requestAnimationFrame(() => this.render())
102    }
103
104    private _startNS: number = 0;
105
106    get startNS(): number {
107        return this._startNS;
108    }
109
110    set startNS(value: number) {
111        this._startNS = value;
112    }
113
114    private _endNS: number = 10_000_000_000;
115
116    get endNS(): number {
117        return this._endNS;
118    }
119
120    set endNS(value: number) {
121        this._endNS = value;
122    }
123
124    isScaling(): boolean {
125        return this.rangeRuler?.isPress || false;
126    }
127
128    reset(): void {
129        this.loadComplete = false;
130        if (this.rangeRuler) {
131            this.rangeRuler.markA.frame.x = 0;
132            this.rangeRuler.markB.frame.x = this.rangeRuler.frame.width
133            this.rangeRuler.cpuUsage = []
134        }
135        this.totalNS = 10_000_000_000;
136    }
137
138    initElements(): void {
139        this.root = this.shadowRoot?.querySelector('.root')
140        this.canvas = this.shadowRoot?.querySelector('.panel')
141        this.totalEL = this.shadowRoot?.querySelector('.total')
142        this.timeTotalEL = this.shadowRoot?.querySelector('.time-total')
143        this.timeOffsetEL = this.shadowRoot?.querySelector('.time-offset')
144        procedurePool.timelineChange = (a: any) => {
145            this.rangeChangeHandler?.(a);
146        }
147    }
148
149    connectedCallback() {
150        if (this.canvas) {
151            if (this.isOffScreen) {
152                console.log("timeline offscreen");
153                // @ts-ignore
154                this.offscreen = this.canvas.transferControlToOffscreen();
155                return;
156            } else {
157                this.ctx = this.canvas?.getContext('2d', {alpha: true});
158            }
159        }
160        if (this.timeTotalEL) this.timeTotalEL.textContent = ns2s(this._totalNS)
161        if (this.timeOffsetEL) this.timeOffsetEL.textContent = ns2s(this._startNS)
162        const width = this.canvas?.clientWidth || 0;
163        const height = this.canvas?.clientHeight || 0;
164        if (!this.timeRuler) {
165            this.timeRuler = new TimeRuler(this.canvas, this.ctx!, new Rect(0, 0, width, 20), this._totalNS);
166        }
167        if (!this.sportRuler) {
168            this.sportRuler = new SportRuler(this.canvas, this.ctx!, new Rect(0, 100.5, width, height - 100));
169        }
170        if (!this.rangeRuler) {
171            this.rangeRuler = new RangeRuler(this.canvas, this.ctx!, new Rect(0, 25, width, 75), {
172                startX: 0,
173                endX: this.canvas?.clientWidth || 0,
174                startNS: 0,
175                endNS: this.totalNS,
176                totalNS: this.totalNS,
177                xs: [],
178                xsTxt: []
179            }, (a) => {
180                if (this.sportRuler) {
181                    this.sportRuler.range = a;
182                }
183                if (this.timeOffsetEL) {
184                    this.timeOffsetEL.textContent = ns2s(a.startNS)
185                }
186                if (this.loadComplete) {
187                    this.rangeChangeHandler?.(a)
188                }
189            });
190        }
191        this.rangeRuler.frame.width = width;
192        this.sportRuler.frame.width = width;
193        this.timeRuler.frame.width = width;
194        // @ts-ignore
195        let dpr = window.devicePixelRatio || window.webkitDevicePixelRatio || window.mozDevicePixelRatio || 1;
196    }
197
198
199    updateWidth(width: number) {
200        if (this.isOffScreen) {
201            this.frame.width = width - (this.totalEL?.clientWidth || 0);
202            this.frame.height = this.shadowRoot!.host.clientHeight || 0;
203            this.canvasWidth = Math.round((this.frame.width) * this.dpr);
204            this.canvasHeight = Math.round((this.frame.height) * this.dpr);
205            this.render();
206            return;
207        }
208        this.canvas!.width = width - (this.totalEL?.clientWidth || 0);
209        this.canvas!.height = this.shadowRoot!.host.clientHeight || 0;
210        let oldWidth = this.canvas!.width;
211        let oldHeight = this.canvas!.height;
212        this.canvas!.width = Math.round((oldWidth) * this.dpr);
213        this.canvas!.height = Math.round(oldHeight * this.dpr);
214        this.canvas!.style.width = oldWidth + 'px';
215        this.canvas!.style.height = oldHeight + 'px';
216        this.ctx?.scale(this.dpr, this.dpr);
217        this.ctx?.translate(0, 0)
218        this.rangeRuler!.frame.width = oldWidth;
219        this.sportRuler!.frame.width = oldWidth;
220        this.timeRuler!.frame.width = oldWidth;
221        this.rangeRuler?.fillX()
222        this.render()
223    }
224
225    documentOnMouseDown = (ev: MouseEvent) => {
226        if (this.isOffScreen) {
227            procedurePool.submitWithName(`timeline`, `timeline`, {
228                offscreen: this.must ? this.offscreen : undefined,
229                dpr: this.dpr,
230                hoverX: this.hoverX,
231                hoverY: this.hoverY,
232                canvasWidth: this.canvasWidth,
233                canvasHeight: this.canvasHeight,
234                offsetLeft: this.canvas?.offsetLeft || 0,
235                offsetTop: this.canvas?.offsetTop || 0,
236                mouseDown: {offsetX: ev.offsetX, offsetY: ev.offsetY},
237                mouseUp: null,
238                mouseMove: null,
239                mouseOut: null,
240                keyPressCode: null,
241                keyUpCode: null,
242                lineColor: "#dadada",
243                startNS: this.startNS,
244                endNS: this.endNS,
245                totalNS: this.totalNS,
246                frame: this.frame,
247            }, this.must ? this.offscreen : undefined, (res: any) => {
248                this.must = false;
249            })
250        } else {
251            this.rangeRuler?.mouseDown(ev);
252        }
253    }
254
255    documentOnMouseUp = (ev: MouseEvent) => {
256        if (this.isOffScreen) {
257            procedurePool.submitWithName(`timeline`, `timeline`, {
258                offscreen: this.must ? this.offscreen : undefined,
259                dpr: this.dpr,
260                hoverX: this.hoverX,
261                hoverY: this.hoverY,
262                canvasWidth: this.canvasWidth,
263                canvasHeight: this.canvasHeight,
264                offsetLeft: this.canvas?.offsetLeft || 0,
265                offsetTop: this.canvas?.offsetTop || 0,
266                mouseUp: {offsetX: ev.offsetX, offsetY: ev.offsetY},
267                mouseMove: null,
268                mouseOut: null,
269                keyPressCode: null,
270                keyUpCode: null,
271                lineColor: "#dadada",
272                startNS: this.startNS,
273                endNS: this.endNS,
274                totalNS: this.totalNS,
275                frame: this.frame,
276            }, this.must ? this.offscreen : undefined, (res: any) => {
277                this.must = false;
278            })
279        } else {
280            this.rangeRuler?.mouseUp(ev);
281            this.sportRuler?.mouseUp(ev);
282        }
283    }
284
285    documentOnMouseMove = (ev: MouseEvent) => {
286        if (this.isOffScreen) {
287            procedurePool.submitWithName(`timeline`, `timeline`, {
288                offscreen: this.must ? this.offscreen : undefined,
289                dpr: this.dpr,
290                hoverX: this.hoverX,
291                hoverY: this.hoverY,
292                canvasWidth: this.canvasWidth,
293                canvasHeight: this.canvasHeight,
294                offsetLeft: this.canvas?.offsetLeft || 0,
295                offsetTop: this.canvas?.offsetTop || 0,
296                mouseMove: {offsetX: ev.offsetX, offsetY: ev.offsetY},
297                mouseOut: null,
298                keyPressCode: null,
299                keyUpCode: null,
300                lineColor: "#dadada",
301                startNS: this.startNS,
302                endNS: this.endNS,
303                totalNS: this.totalNS,
304                frame: this.frame,
305            }, this.must ? this.offscreen : undefined, (res: any) => {
306                this.must = false;
307            })
308        } else {
309            this.rangeRuler?.mouseMove(ev);
310            this.sportRuler?.mouseMove(ev);
311        }
312    }
313
314    documentOnMouseOut = (ev: MouseEvent) => {
315        if (this.isOffScreen) {
316            procedurePool.submitWithName(`timeline`, `timeline`, {
317                offscreen: this.must ? this.offscreen : undefined,
318                dpr: this.dpr,
319                hoverX: this.hoverX,
320                hoverY: this.hoverY,
321                canvasWidth: this.canvasWidth,
322                canvasHeight: this.canvasHeight,
323                offsetLeft: this.canvas?.offsetLeft || 0,
324                offsetTop: this.canvas?.offsetTop || 0,
325                mouseOut: {offsetX: ev.offsetX, offsetY: ev.offsetY},
326                keyPressCode: null,
327                keyUpCode: null,
328                lineColor: "#dadada",
329                startNS: this.startNS,
330                endNS: this.endNS,
331                totalNS: this.totalNS,
332                frame: this.frame,
333            }, this.must ? this.offscreen : undefined, (res: any) => {
334                this.must = false;
335            })
336        } else {
337            this.rangeRuler?.mouseOut(ev);
338        }
339    }
340    documentOnKeyPress = (ev: KeyboardEvent) => {
341        if (this.isOffScreen) {
342            procedurePool.submitWithName(`timeline`, `timeline`, {
343                offscreen: this.must ? this.offscreen : undefined,
344                dpr: this.dpr,
345                hoverX: this.hoverX,
346                hoverY: this.hoverY,
347                canvasWidth: this.canvasWidth,
348                canvasHeight: this.canvasHeight,
349                keyPressCode: {key: ev.key},
350                keyUpCode: null,
351                lineColor: "#dadada",
352                startNS: this.startNS,
353                endNS: this.endNS,
354                totalNS: this.totalNS,
355                frame: this.frame,
356            }, this.must ? this.offscreen : undefined, (res: any) => {
357                this.must = false;
358            })
359        } else {
360            this.rangeRuler?.keyPress(ev);
361        }
362    }
363
364    documentOnKeyUp = (ev: KeyboardEvent) => {
365        if (this.isOffScreen) {
366            procedurePool.submitWithName(`timeline`, `timeline`, {
367                offscreen: this.must ? this.offscreen : undefined,
368                dpr: this.dpr,
369                hoverX: this.hoverX,
370                hoverY: this.hoverY,
371                canvasWidth: this.canvasWidth,
372                canvasHeight: this.canvasHeight,
373                keyPressCode: null,
374                keyUpCode: {key: ev.key},
375                lineColor: "#dadada",
376                startNS: this.startNS,
377                endNS: this.endNS,
378                totalNS: this.totalNS,
379                frame: this.frame,
380            }, this.must ? this.offscreen : undefined, (res: any) => {
381                this.must = false;
382            })
383        } else {
384            this.rangeRuler?.keyUp(ev);
385        }
386    }
387
388    disconnectedCallback() {
389    }
390
391    render() {
392        if (this.ctx) {
393            this.ctx.fillStyle = 'transparent';
394            this.ctx?.fillRect(0, 0, this.canvas?.width || 0, this.canvas?.height || 0)
395            this.timeRuler?.draw()
396            this.rangeRuler?.draw()
397            this.sportRuler?.draw()
398        } else {
399            procedurePool.submitWithName(`timeline`, `timeline`, {
400                offscreen: this.must ? this.offscreen : undefined,
401                dpr: this.dpr,
402                hoverX: this.hoverX,
403                hoverY: this.hoverY,
404                canvasWidth: this.canvasWidth,
405                canvasHeight: this.canvasHeight,
406                keyPressCode: null,
407                keyUpCode: null,
408                lineColor: "#dadada",
409                startNS: this.startNS,
410                endNS: this.endNS,
411                totalNS: this.totalNS,
412                frame: this.frame,
413            }, this.must ? this.offscreen : undefined, (res: any) => {
414                this.must = false;
415            })
416        }
417    }
418
419    modifyList(type: string, flag: any = {}) {
420        this.sportRuler?.modifyFlagList(type, flag)
421    }
422
423    initHtml(): string {
424        return `
425<style>
426:host{
427    box-sizing: border-box;
428    display: flex;
429    width: 100%;
430    height: 147px;
431    border-bottom: 1px solid var(--dark-background,#dadada);
432    border-top: 1px solid var(--dark-background,#dadada);
433}
434*{
435    box-sizing: border-box;
436}
437.root{
438    width: 100%;
439    height: 100%;
440    display: grid;
441    grid-template-rows: 100%;
442    grid-template-columns: 248px 1fr;
443    background: var(--dark-background4,#FFFFFF);
444}
445.total{
446    display: grid;
447    grid-template-columns: 1fr;
448    grid-template-rows: min-content 1fr;
449    background-color: transparent;
450}
451.panel{
452    color: var(--dark-border,#dadada);
453    width: 100%;
454    height: 100%;
455    overflow: visible;
456    background-color: var(--dark-background4,#ffffff);
457}
458.time-div{
459    box-sizing: border-box;
460    width: 100%;border-top: 1px solid var(--dark-background,#dadada);height: 100%;display: flex;justify-content: space-between;background-color: var(--dark-background1,white);color: var(--dark-color1,#212121);font-size: 0.7rem;
461    border-right: 1px solid var(--dark-background,#999);
462    padding: 2px 6px;
463    display: flex;justify-content: space-between;
464    user-select: none;
465}
466.time-total::after{
467    content: " +";
468}
469
470</style>
471<div class="root">
472    <div class="total">
473        <div style="width: 100%;height: 100px;background: var(--dark-background4,#F6F6F6)"></div>
474        <div class="time-div">
475            <span class="time-total">10</span>
476            <span class="time-offset">0</span>
477        </div>
478    </div>
479    <canvas class="panel"></canvas>
480</div>
481        `;
482    }
483}
484