• 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';
17import { TimeRuler } from './timer-shaft/TimeRuler';
18import { Rect } from './timer-shaft/Rect';
19import { RangeRuler, TimeRange } from './timer-shaft/RangeRuler';
20import { SlicesTime, SportRuler } from './timer-shaft/SportRuler';
21import { procedurePool } from '../../database/Procedure';
22import { Flag } from './timer-shaft/Flag';
23import { info } from '../../../log/Log';
24import { TraceSheet } from './base/TraceSheet';
25import { SelectionParam } from '../../bean/BoxSelection';
26import { type SpSystemTrace, CurrentSlicesTime } from '../SpSystemTrace';
27import './timer-shaft/CollapseButton';
28import { TimerShaftElementHtml } from './TimerShaftElement.html';
29import { SpChartList } from './SpChartList';
30//随机生成十六位进制颜色
31export function randomRgbColor(): string {
32  let r = Math.floor(Math.random() * 255);
33  let g = Math.floor(Math.random() * 255);
34  let b = Math.floor(Math.random() * 255);
35  if (r * 0.299 + g * 0.587 + b * 0.114 < 192) {
36    let r16 = r.toString(16).length === 1 && r.toString(16) <= 'f' ? 0 + r.toString(16) : r.toString(16);
37    let g16 = g.toString(16).length === 1 && g.toString(16) <= 'f' ? 0 + g.toString(16) : g.toString(16);
38    let b16 = b.toString(16).length === 1 && b.toString(16) <= 'f' ? 0 + b.toString(16) : b.toString(16);
39    let color = '#' + r16 + g16 + b16;
40    return color;
41  } else {
42    return randomRgbColor();
43  }
44}
45
46export function ns2s(ns: number): string {
47  let oneSecond = 1_000_000_000; // 1 second
48  let oneMillisecond = 1_000_000; // 1 millisecond
49  let oneMicrosecond = 1_000; // 1 microsecond
50  let nanosecond1 = 1000.0;
51  let result;
52  if (ns >= oneSecond) {
53    result = (ns / 1000 / 1000 / 1000).toFixed(1) + ' s';
54  } else if (ns >= oneMillisecond) {
55    result = (ns / 1000 / 1000).toFixed(1) + ' ms';
56  } else if (ns >= oneMicrosecond) {
57    result = (ns / 1000).toFixed(1) + ' μs';
58  } else if (ns > 0) {
59    result = ns.toFixed(1) + ' ns';
60  } else {
61    result = ns.toFixed(1) + ' s';
62  }
63  return result;
64}
65
66export function ns2UnitS(ns: number, scale: number): string {
67  let oneSecond = 1_000_000_000; // 1 second
68  let result;
69  if (scale >= 10_000_000_000) {
70    result = (ns / oneSecond).toFixed(0) + ' s';
71  } else if (scale >= 1_000_000_000) {
72    result = (ns / oneSecond).toFixed(1) + ' s';
73  } else if (scale >= 100_000_000) {
74    result = (ns / oneSecond).toFixed(2) + ' s';
75  } else if (scale >= 10_000_000) {
76    result = (ns / oneSecond).toFixed(3) + ' s';
77  } else if (scale >= 1_000_000) {
78    result = (ns / oneSecond).toFixed(4) + ' s';
79  } else if (scale >= 100_000) {
80    result = (ns / oneSecond).toFixed(5) + ' s';
81  } else {
82    result = (ns / oneSecond).toFixed(6) + ' s';
83  }
84  return result;
85}
86
87export function ns2x(ns: number, startNS: number, endNS: number, duration: number, rect: Rect): number {
88  if (endNS === 0) {
89    endNS = duration;
90  }
91  let xSize: number = ((ns - startNS) * rect.width) / (endNS - startNS);
92  if (xSize < 0) {
93    xSize = 0;
94  }
95  if (xSize > rect.width) {
96    xSize = rect.width;
97  }
98  return xSize;
99}
100
101@element('timer-shaft-element')
102export class TimerShaftElement extends BaseElement {
103  // @ts-ignore
104  offscreen: OffscreenCanvas | undefined;
105  isOffScreen: boolean = false;
106  public ctx: CanvasRenderingContext2D | undefined | null;
107  public canvas: HTMLCanvasElement | null | undefined;
108  public totalEL: HTMLDivElement | null | undefined;
109  public timeTotalEL: HTMLSpanElement | null | undefined;
110  public timeOffsetEL: HTMLSpanElement | null | undefined;
111  public collectGroup: HTMLDivElement | null | undefined;
112  public collect1: HTMLInputElement | null | undefined;
113  public loadComplete: boolean = false;
114  public collecBtn: HTMLElement | null | undefined;
115  rangeChangeHandler: ((timeRange: TimeRange) => void) | undefined = undefined;
116  rangeClickHandler: ((sliceTime: SlicesTime | undefined | null) => void) | undefined = undefined;
117  flagChangeHandler: ((hoverFlag: Flag | undefined | null, selectFlag: Flag | undefined | null) => void) | undefined =
118    undefined;
119  flagClickHandler: ((flag: Flag | undefined | null) => void) | undefined = undefined;
120  /**
121   * 离线渲染需要的变量
122   */
123  dpr = window.devicePixelRatio || 1;
124  frame: Rect = new Rect(0, 0, 0, 0);
125  must: boolean = true;
126  hoverX: number = 0;
127  hoverY: number = 0;
128  canvasWidth: number = 0;
129  canvasHeight: number = 0;
130  _cpuUsage: Array<{ cpu: number; ro: number; rate: number }> = [];
131  protected timeRuler: TimeRuler | undefined;
132  protected _rangeRuler: RangeRuler | undefined;
133  protected _sportRuler: SportRuler | undefined;
134  private root: HTMLDivElement | undefined | null;
135  private _totalNS: number = 10_000_000_000;
136  private _startNS: number = 0;
137  private _endNS: number = 10_000_000_000;
138  private traceSheetEL: TraceSheet | undefined | null;
139  private sliceTime: SlicesTime | undefined | null;
140  public selectionList: Array<SelectionParam> = [];
141  public selectionMap: Map<string, SelectionParam> = new Map<string, SelectionParam>();
142  public usageEL: HTMLDivElement | null | undefined;
143  public timerShaftEL: TimerShaftElement | null | undefined;
144  public rowsPaneEL: HTMLDivElement | null | undefined;
145  public favoriteChartListEL: SpChartList | undefined | null;
146  _checkExpand: boolean = false; //是否展开
147  _usageFoldHeight: number = 56.25; //初始化时折叠的负载区高度
148  usageExpandHeight: number = 75; //给定的展开的负载区高度
149  _cpuUsageCount: Array<{ cpu: number; ro: number; rate: number }> = [];
150
151  get sportRuler(): SportRuler | undefined {
152    return this._sportRuler;
153  }
154
155  get rangeRuler(): RangeRuler | undefined {
156    return this._rangeRuler;
157  }
158
159  set cpuUsage(value: Array<{ cpu: number; ro: number; rate: number }>) {
160    info('set cpuUsage values :', value);
161    this._cpuUsage = value;
162
163    this._cpuUsageCount = value;
164    if (this._cpuUsageCount.length) {
165      this.usageEL!.innerHTML = 'CPU Usage';
166    }
167
168    if (this._rangeRuler) {
169      this._rangeRuler.cpuUsage = this._cpuUsage;
170    }
171  }
172
173  get checkExpand(): boolean {
174    return this._checkExpand;
175  }
176
177  set checkExpand(value: boolean) {
178    this._checkExpand = value;
179  }
180
181  get usageFoldHeight(): number {
182    return this._usageFoldHeight;
183  }
184  set usageFoldHeight(value: number) {
185    this._usageFoldHeight = value;
186  }
187
188  get totalNS(): number {
189    return this._totalNS;
190  }
191
192  set totalNS(value: number) {
193    info('set totalNS values :', value);
194    this._totalNS = value;
195    if (this.timeRuler) {
196      this.timeRuler.totalNS = value;
197    }
198    if (this._rangeRuler) {
199      this._rangeRuler.range.totalNS = value;
200    }
201    if (this.timeTotalEL) {
202      this.timeTotalEL.textContent = `${ns2s(value)}`;
203    }
204    requestAnimationFrame(() => this.render());
205  }
206
207  get startNS(): number {
208    return this._startNS;
209  }
210
211  set startNS(value: number) {
212    this._startNS = value;
213  }
214
215  get endNS(): number {
216    return this._endNS;
217  }
218
219  set endNS(value: number) {
220    this._endNS = value;
221  }
222
223  reset(): void {
224    this.loadComplete = false;
225    this.totalNS = 10_000_000_000;
226    this.startNS = 0;
227    this.endNS = 10_000_000_000;
228    if (this._rangeRuler) {
229      this._rangeRuler.drawMark = false;
230      this._rangeRuler.range.totalNS = this.totalNS;
231      this._rangeRuler.markAObj.frame.x = 0;
232      this._rangeRuler.markBObj.frame.x = this._rangeRuler.frame.width;
233      this._rangeRuler.cpuUsage = [];
234      this.sportRuler!.flagList.length = 0;
235      this.sportRuler!.slicesTimeList.length = 0;
236      this.selectionList.length = 0;
237      this.selectionMap.clear();
238      this._rangeRuler.rangeRect = new Rect(0, 25, this.canvas?.clientWidth || 0, 75);
239      this.sportRuler!.isRangeSelect = false;
240      this.setSlicesMark();
241    }
242    this.removeTriangle('inverted');
243    this.setRangeNS(0, this.endNS);
244    //---------------每次导入trace时触发渲染-----------------
245    if (this._rangeRuler && this._sportRuler) {
246      this.canvas!.width = this.canvas!.clientWidth || 0;
247      sessionStorage.setItem('foldHeight', String(56.25));
248      if (this._checkExpand && this._checkExpand === true) {
249        this._checkExpand = false;
250        sessionStorage.setItem('expand', String(this._checkExpand));
251      }
252      sessionStorage.setItem('expand', String(this._checkExpand));
253      this.usageEL!.innerHTML = '';
254      this.usageEL!.style.height = `${100 - 56.25}px`;
255      this.usageEL!.style.lineHeight = `${100 - 56.25}px`;
256      this.timerShaftEL!.style.height = `${146 - 56.25 + 2}px`;
257      this.canvas!.style.height = `${146 - 56.25}px`;
258      this.canvas!.height = 146 - 56.25;
259      this.rowsPaneEL!.style.maxHeight = '100%';
260      this._sportRuler.frame.y = 43.75;
261
262      this.render();
263      this._checkExpand = true;
264      this._cpuUsageCount = []; //清空判断数据
265    }
266  }
267
268  initElements(): void {
269    this.root = this.shadowRoot?.querySelector('.root');
270    this.canvas = this.shadowRoot?.querySelector('.panel');
271    this.totalEL = this.shadowRoot?.querySelector('.total');
272    this.collect1 = this.shadowRoot?.querySelector('#collect1');
273    this.timeTotalEL = this.shadowRoot?.querySelector('.time-total');
274    this.timeOffsetEL = this.shadowRoot?.querySelector('.time-offset');
275    this.collecBtn = this.shadowRoot?.querySelector('.time-collect');
276    this.collectGroup = this.shadowRoot?.querySelector('.collect_group');
277    this.collectGroup?.addEventListener('click', (e) => {
278      // @ts-ignore
279      if (e.target && e.target.tagName === 'INPUT') {
280        // @ts-ignore
281        window.publish(window.SmartEvent.UI.CollectGroupChange, e.target.value);
282      }
283    });
284    // @ts-ignore
285    procedurePool.timelineChange = (a: unknown): void => this.rangeChangeHandler?.(a);
286    // @ts-ignore
287    window.subscribe(window.SmartEvent.UI.TimeRange, (b) => this.setRangeNS(b.startNS, b.endNS));
288    // -----------------------------点击负载区展开折叠---------------------------------
289    this.usageEL = this.shadowRoot?.querySelector('.cpu-usage');
290    this.timerShaftEL = this.shadowRoot!.host.parentNode?.querySelector('.timer-shaft');
291    this.rowsPaneEL = this.shadowRoot!.host.parentNode?.querySelector('.rows-pane');
292    this.favoriteChartListEL = this.shadowRoot!.host.parentNode?.querySelector('#favorite-chart-list');
293    const height = this.canvas?.clientHeight || 0;
294    // 点击cpu usage部分,切换折叠展开
295    this.usageEL?.addEventListener('click', (e) => {
296      if (this._rangeRuler && this.sportRuler && this._cpuUsageCount.length) {
297        // 计算需要被收起来的高度:总高度75-(总高度/cpu数量)* 2
298        this._usageFoldHeight = this.usageExpandHeight - (this.usageExpandHeight / this._rangeRuler.cpuCountData!) * 2;
299        this.canvas!.width = this.canvas!.clientWidth || 0;
300        if (this._checkExpand) {
301          sessionStorage.setItem('expand', String(this._checkExpand));
302          sessionStorage.setItem('foldHeight', String(this._usageFoldHeight));
303          this.usageEL!.style.height = '100px';
304          this.usageEL!.style.lineHeight = '100px';
305          this.timerShaftEL!.style.height = `${height + 2}px`;
306          this.canvas!.style.height = `${height}px`;
307          this.canvas!.height = height;
308          this._rangeRuler.frame.height = 75;
309          this.sportRuler.frame.y = 100;
310          this.render();
311          this._checkExpand = false;
312          this.favoriteChartListEL?.refreshFavoriteCanvas(); //刷新收藏泳道画布高度
313        } else {
314          sessionStorage.setItem('expand', String(this._checkExpand));
315          sessionStorage.setItem('foldHeight', String(this._usageFoldHeight));
316          this.usageEL!.style.height = `${100 - this._usageFoldHeight}px`;
317          this.usageEL!.style.lineHeight = `${100 - this._usageFoldHeight}px`;
318          this.timerShaftEL!.style.height = `${height - this._usageFoldHeight + 2}px`;
319          this.canvas!.style.height = `${height - this._usageFoldHeight}px`;
320          this.canvas!.height = height - this._usageFoldHeight;
321          this._rangeRuler.frame.height = 75 - this._usageFoldHeight;
322          this.sportRuler.frame.y = 100 - this._usageFoldHeight;
323          this.render();
324          this._checkExpand = true;
325          this.favoriteChartListEL?.refreshFavoriteCanvas(); //刷新收藏泳道画布高度
326        }
327      }
328    });
329  }
330
331  getRangeRuler(): RangeRuler | undefined {
332    return this._rangeRuler;
333  }
334
335  connectedCallback(): RangeRuler | undefined {
336    if (this.canvas) {
337      if (this.isOffScreen) {
338        // @ts-ignore
339        this.offscreen = this.canvas.transferControlToOffscreen();
340        return;
341      } else {
342        this.ctx = this.canvas?.getContext('2d', { alpha: true });
343      }
344    }
345    if (this.timeTotalEL) {
346      this.timeTotalEL.textContent = ns2s(this._totalNS);
347    }
348    if (this.timeOffsetEL && this._rangeRuler) {
349      this.timeOffsetEL.textContent = ns2UnitS(this._startNS, this._rangeRuler.getScale());
350    }
351    const width = this.canvas?.clientWidth || 0;
352    const height = this.canvas?.clientHeight || 0;
353    this.setTimeRuler(width);
354    this.setSportRuler(width, height);
355    this.setRangeRuler(width);
356  }
357
358  private setTimeRuler(width: number): void {
359    if (!this.timeRuler) {
360      this.timeRuler = new TimeRuler(this, new Rect(0, 0, width, 20), this._totalNS);
361    }
362    this.timeRuler.frame.width = width;
363  }
364
365  private setSportRuler(width: number, height: number): void {
366    if (!this._sportRuler) {
367      this._sportRuler = new SportRuler(
368        this,
369        new Rect(0, 100, width, height - 100),
370        (hoverFlag, selectFlag) => {
371          this.flagChangeHandler?.(hoverFlag, selectFlag);
372        },
373        (flag) => {
374          this.flagClickHandler?.(flag);
375        },
376        (slicetime) => {
377          this.rangeClickHandler?.(slicetime);
378        }
379      );
380    }
381    this._sportRuler.frame.width = width;
382  }
383
384  private setRangeRuler(width: number): void {
385    if (!this._rangeRuler) {
386      this._rangeRuler = new RangeRuler(
387        this,
388        new Rect(0, 25, width, 75 - this._usageFoldHeight),
389        {
390          slicesTime: {
391            startTime: null,
392            endTime: null,
393            color: null,
394          },
395          scale: 0,
396          startX: 0,
397          endX: this.canvas?.clientWidth || 0,
398          startNS: 0,
399          endNS: this.totalNS,
400          totalNS: this.totalNS,
401          refresh: true,
402          xs: [],
403          xsTxt: [],
404        },
405        (a) => {
406          if (a.startNS >= 0 && a.endNS >= 0) {
407            if (this._sportRuler) {
408              this._sportRuler.range = a;
409            }
410            if (this.timeOffsetEL && this._rangeRuler) {
411              this.timeOffsetEL.textContent = ns2UnitS(a.startNS, this._rangeRuler.getScale());
412            }
413            if (this.loadComplete) {
414              this.rangeChangeHandler?.(a);
415            }
416          }
417        }
418      );
419    }
420    this._rangeRuler.frame.width = width;
421  }
422
423  setRangeNS(startNS: number, endNS: number): void {
424    info('set startNS values :' + startNS + 'endNS values : ' + endNS);
425    this._rangeRuler?.setRangeNS(startNS, endNS);
426  }
427
428  getRange(): TimeRange | undefined {
429    return this._rangeRuler?.getRange();
430  }
431
432  updateWidth(width: number): void {
433    this.dpr = window.devicePixelRatio || 1;
434    this.canvas!.width = width - (this.totalEL?.clientWidth || 0);
435    this.canvas!.height = this.shadowRoot!.host.clientHeight || 0;
436    let oldWidth = this.canvas!.width;
437    let oldHeight = this.canvas!.height;
438    this.canvas!.width = Math.ceil(oldWidth * this.dpr);
439    this.canvas!.height = Math.ceil(oldHeight * this.dpr);
440    this.canvas!.style.width = oldWidth + 'px';
441    this.canvas!.style.height = oldHeight + 'px';
442    this.ctx?.scale(this.dpr, this.dpr);
443    this.ctx?.translate(0, 0);
444    this._rangeRuler!.frame.width = oldWidth;
445    this._sportRuler!.frame.width = oldWidth;
446    this.timeRuler!.frame.width = oldWidth;
447    this._rangeRuler?.fillX();
448    this.render();
449  }
450
451  documentOnMouseDown = (ev: MouseEvent): void => {
452    // @ts-ignore
453    if ((window as unknown).isSheetMove) {
454      return;
455    }
456    this._rangeRuler?.mouseDown(ev);
457  };
458
459  documentOnMouseUp = (ev: MouseEvent): void => {
460    // @ts-ignore
461    if ((window as unknown).isSheetMove) {
462      return;
463    }
464    this._rangeRuler?.mouseUp(ev);
465    this.sportRuler?.mouseUp(ev);
466  };
467
468  documentOnMouseMove = (ev: MouseEvent, trace: SpSystemTrace): void => {
469    trace.style.cursor = 'default';
470    let x = ev.offsetX - (this.canvas?.offsetLeft || 0); // 鼠标的x轴坐标
471    let y = ev.offsetY; // 鼠标的y轴坐标
472    let findSlicestime = this.sportRuler?.findSlicesTime(x, y); // 查找帽子
473    if (!findSlicestime) {
474      // 如果在该位置没有找到一个“帽子”,则可以显示一个旗子。
475      this.sportRuler?.showHoverFlag();
476      this._rangeRuler?.mouseMove(ev, trace);
477      if (this.sportRuler?.edgeDetection(ev)) {
478        this.sportRuler?.mouseMove(ev);
479      } else {
480        this.sportRuler?.mouseOut(ev);
481      }
482    } else {
483      this.sportRuler?.clearHoverFlag();
484      this.sportRuler?.modifyFlagList(null); //重新绘制旗子,清除hover flag
485    }
486  };
487
488  documentOnMouseOut = (ev: MouseEvent): void => {
489    this._rangeRuler?.mouseOut(ev);
490    this.sportRuler?.mouseOut(ev);
491  };
492
493  documentOnKeyPress = (ev: KeyboardEvent, currentSlicesTime?: CurrentSlicesTime): void => {
494    // @ts-ignore
495    if ((window as unknown).flagInputFocus) {
496      return;
497    }
498    this._rangeRuler?.keyPress(ev, currentSlicesTime);
499    this.sportRuler?.clearHoverFlag();
500  };
501
502  documentOnKeyUp = (ev: KeyboardEvent): void => {
503    // @ts-ignore
504    if ((window as unknown).flagInputFocus) {
505      return;
506    }
507    this._rangeRuler?.keyUp(ev);
508  };
509
510  disconnectedCallback(): void {}
511
512  firstRender = true;
513
514  lineColor(): string {
515    return window.getComputedStyle(this.canvas!, null).getPropertyValue('color');
516  }
517
518  render(): void {
519    this.dpr = window.devicePixelRatio || 1;
520    if (this.ctx) {
521      this.ctx.fillStyle = 'transparent';
522      this.ctx?.fillRect(0, 0, this.canvas?.width || 0, this.canvas?.height || 0);
523      this.timeRuler?.draw();
524      this._rangeRuler?.draw();
525      this._sportRuler?.draw();
526    } else {
527      procedurePool.submitWithName(
528        'timeline',
529        'timeline',
530        {
531          offscreen: this.must ? this.offscreen : undefined, //是否离屏
532          dpr: this.dpr, //屏幕dpr值
533          hoverX: this.hoverX,
534          hoverY: this.hoverY,
535          canvasWidth: this.canvasWidth,
536          canvasHeight: this.canvasHeight,
537          keyPressCode: null,
538          keyUpCode: null,
539          lineColor: '#dadada',
540          startNS: this.startNS,
541          endNS: this.endNS,
542          totalNS: this.totalNS,
543          frame: this.frame,
544        },
545        this.must ? this.offscreen : undefined,
546        (res: unknown) => {
547          this.must = false;
548        }
549      );
550    }
551  }
552
553  modifyFlagList(flag: Flag | null | undefined): void {
554    this._sportRuler?.modifyFlagList(flag);
555  }
556
557  modifySlicesList(slicestime: SlicesTime | null | undefined): void {
558    this._sportRuler?.modifySicesTimeList(slicestime);
559  }
560  cancelPressFrame(): void {
561    this._rangeRuler?.cancelPressFrame();
562  }
563
564  cancelUpFrame(): void {
565    this._rangeRuler?.cancelUpFrame();
566  }
567
568  stopWASD(ev: unknown): void {
569    // @ts-ignore
570    this._rangeRuler?.keyUp(ev);
571  }
572
573  drawTriangle(time: number, type: string): number {
574    if (this._sportRuler) {
575      return this._sportRuler?.drawTriangle(time, type);
576    }
577    return 0;
578  }
579
580  removeTriangle(type: string): void {
581    this._sportRuler?.removeTriangle(type);
582  }
583
584  setSlicesMark(
585    startTime: null | number = null,
586    endTime: null | number = null,
587    shiftKey: null | boolean = false
588  ): SlicesTime | null | undefined {
589    let sliceTime = this._sportRuler?.setSlicesMark(startTime, endTime, shiftKey);
590    if (sliceTime && sliceTime !== undefined) {
591      this.traceSheetEL?.displayCurrent(sliceTime); // 给当前pane准备数据
592
593      // 取最新创建的那个selection对象
594      let selection = this.selectionList[this.selectionList.length - 1];
595      if (selection) {
596        selection.isCurrentPane = true; // 设置当前面板为可以显示的状态
597        //把刚刚创建的slicetime和selection对象关联起来,以便后面再次选中“跑道”的时候显示对应的面板。
598        this.selectionMap.set(sliceTime.id, selection);
599        this.traceSheetEL?.rangeSelect(selection); // 显示选中区域对应的面板
600      }
601    }
602    return sliceTime;
603  }
604
605  displayCollect(showCollect: boolean): void {
606    if (showCollect) {
607      this.collecBtn!.style.display = 'flex';
608    } else {
609      this.collecBtn!.style.display = 'none';
610    }
611  }
612
613  initHtml(): string {
614    return TimerShaftElementHtml;
615  }
616}
617