1fb726d48Sopenharmony_ci/*
2fb726d48Sopenharmony_ci * Copyright (C) 2022 Huawei Device Co., Ltd.
3fb726d48Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4fb726d48Sopenharmony_ci * you may not use this file except in compliance with the License.
5fb726d48Sopenharmony_ci * You may obtain a copy of the License at
6fb726d48Sopenharmony_ci *
7fb726d48Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8fb726d48Sopenharmony_ci *
9fb726d48Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10fb726d48Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11fb726d48Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12fb726d48Sopenharmony_ci * See the License for the specific language governing permissions and
13fb726d48Sopenharmony_ci * limitations under the License.
14fb726d48Sopenharmony_ci */
15fb726d48Sopenharmony_ci
16fb726d48Sopenharmony_ciimport { BaseElement, element } from '../../base-ui/BaseElement';
17fb726d48Sopenharmony_ciimport { SelectionData } from '../bean/BoxSelection';
18fb726d48Sopenharmony_ciimport { Utils } from './trace/base/Utils';
19fb726d48Sopenharmony_ci
20fb726d48Sopenharmony_ci@element('stack-bar')
21fb726d48Sopenharmony_ciexport class StackBar extends BaseElement {
22fb726d48Sopenharmony_ci  private vessel: HTMLDivElement | undefined | null;
23fb726d48Sopenharmony_ci
24fb726d48Sopenharmony_ci  static get observedAttributes(): string[] {
25fb726d48Sopenharmony_ci    return ['mode']; // max min hidden show 三种状态
26fb726d48Sopenharmony_ci  }
27fb726d48Sopenharmony_ci
28fb726d48Sopenharmony_ci  set data(val: Array<SelectionData>) {
29fb726d48Sopenharmony_ci    let map = new Map<string, StackValue>();
30fb726d48Sopenharmony_ci    for (let v of val) {
31fb726d48Sopenharmony_ci      if (map.has(v.stateJX)) {
32fb726d48Sopenharmony_ci        let sv = map.get(v.stateJX);
33fb726d48Sopenharmony_ci        sv!.value = sv!.value + v.wallDuration;
34fb726d48Sopenharmony_ci        sv!.state = `${v.stateJX} : ${sv!.value.toFixed(5)}ms`;
35fb726d48Sopenharmony_ci      } else {
36fb726d48Sopenharmony_ci        let sv = new StackValue();
37fb726d48Sopenharmony_ci        sv.value = v.wallDuration;
38fb726d48Sopenharmony_ci        sv.state = `${v.stateJX} : ${sv.value.toFixed(5)}ms`;
39fb726d48Sopenharmony_ci        sv.color = Utils.getStateColor(v.state);
40fb726d48Sopenharmony_ci        map.set(v.stateJX, sv);
41fb726d48Sopenharmony_ci      }
42fb726d48Sopenharmony_ci    }
43fb726d48Sopenharmony_ci    let totalDuration = 0;
44fb726d48Sopenharmony_ci    let arr: Array<StackValue> = [];
45fb726d48Sopenharmony_ci    for (let key of map.keys()) {
46fb726d48Sopenharmony_ci      if (key === ' ') {
47fb726d48Sopenharmony_ci        totalDuration = map.get(key)!.value;
48fb726d48Sopenharmony_ci      } else {
49fb726d48Sopenharmony_ci        arr.push(map.get(key)!);
50fb726d48Sopenharmony_ci      }
51fb726d48Sopenharmony_ci    }
52fb726d48Sopenharmony_ci    arr.sort((a, b) => a.value - b.value);
53fb726d48Sopenharmony_ci    this.vessel!.innerHTML = '';
54fb726d48Sopenharmony_ci    for (let stackValue of arr) {
55fb726d48Sopenharmony_ci      this.vessel!.appendChild(this.createBarElement(stackValue, totalDuration));
56fb726d48Sopenharmony_ci    }
57fb726d48Sopenharmony_ci  }
58fb726d48Sopenharmony_ci
59fb726d48Sopenharmony_ci  initElements(): void {
60fb726d48Sopenharmony_ci    this.vessel = this.shadowRoot?.querySelector('#vessel');
61fb726d48Sopenharmony_ci  }
62fb726d48Sopenharmony_ci
63fb726d48Sopenharmony_ci  initHtml(): string {
64fb726d48Sopenharmony_ci    return `
65fb726d48Sopenharmony_ci        <style>
66fb726d48Sopenharmony_ci            :host([mode='hidden']){
67fb726d48Sopenharmony_ci                display: none;
68fb726d48Sopenharmony_ci            }
69fb726d48Sopenharmony_ci            :host{
70fb726d48Sopenharmony_ci                display: block;
71fb726d48Sopenharmony_ci                /*background-color: rebeccapurple;*/
72fb726d48Sopenharmony_ci            }
73fb726d48Sopenharmony_ci            .state-text{
74fb726d48Sopenharmony_ci                width: 10%;display: inline-block;overflow: hidden;white-space: nowrap;padding: 5px; margin-right: 2px;font-size: 9pt;
75fb726d48Sopenharmony_ci            }
76fb726d48Sopenharmony_ci            </style>
77fb726d48Sopenharmony_ci            <div style="display: flex;flex-direction: row;" id="vessel">
78fb726d48Sopenharmony_ci            </div>
79fb726d48Sopenharmony_ci        `;
80fb726d48Sopenharmony_ci  }
81fb726d48Sopenharmony_ci
82fb726d48Sopenharmony_ci  getStateWidth(state: string): number {
83fb726d48Sopenharmony_ci    let canvas = document.createElement('canvas');
84fb726d48Sopenharmony_ci    let context = canvas.getContext('2d');
85fb726d48Sopenharmony_ci    context!.font = '9pt';
86fb726d48Sopenharmony_ci    let metrics = context!.measureText(state);
87fb726d48Sopenharmony_ci    return metrics.width;
88fb726d48Sopenharmony_ci  }
89fb726d48Sopenharmony_ci
90fb726d48Sopenharmony_ci  createBarElement(sv: StackValue, total: number): HTMLDivElement {
91fb726d48Sopenharmony_ci    let bar = document.createElement('div');
92fb726d48Sopenharmony_ci    bar.setAttribute('class', 'state-text');
93fb726d48Sopenharmony_ci    bar.setAttribute('need-width', `${this.getStateWidth(sv.state)}`);
94fb726d48Sopenharmony_ci    bar.style.backgroundColor = sv.color;
95fb726d48Sopenharmony_ci    bar.textContent = sv.state;
96fb726d48Sopenharmony_ci    if (sv.state.startsWith('Sleeping')) {
97fb726d48Sopenharmony_ci      bar.style.color = '#555555';
98fb726d48Sopenharmony_ci    } else {
99fb726d48Sopenharmony_ci      bar.style.color = '#ffffff';
100fb726d48Sopenharmony_ci    }
101fb726d48Sopenharmony_ci    let weight = ((sv.value * 1.0) / total) * 100.0;
102fb726d48Sopenharmony_ci    if (weight < 1) {
103fb726d48Sopenharmony_ci      weight = 1;
104fb726d48Sopenharmony_ci    }
105fb726d48Sopenharmony_ci    bar.style.width = `${weight}%`;
106fb726d48Sopenharmony_ci    bar.addEventListener('mouseover', (): void => {
107fb726d48Sopenharmony_ci      let needWidth = parseFloat(bar.getAttribute('need-width')!);
108fb726d48Sopenharmony_ci      let trueWidth = parseFloat(window.getComputedStyle(bar).width);
109fb726d48Sopenharmony_ci      if (trueWidth < needWidth) {
110fb726d48Sopenharmony_ci        bar.style.width = `${needWidth + 100}px`;
111fb726d48Sopenharmony_ci      }
112fb726d48Sopenharmony_ci    });
113fb726d48Sopenharmony_ci    bar.addEventListener('mouseleave', (): void => {
114fb726d48Sopenharmony_ci      let weight = ((sv.value * 1.0) / total) * 100.0;
115fb726d48Sopenharmony_ci      if (weight < 1) {
116fb726d48Sopenharmony_ci        weight = 1;
117fb726d48Sopenharmony_ci      }
118fb726d48Sopenharmony_ci      bar.style.width = `${weight}%`;
119fb726d48Sopenharmony_ci    });
120fb726d48Sopenharmony_ci    return bar;
121fb726d48Sopenharmony_ci  }
122fb726d48Sopenharmony_ci}
123fb726d48Sopenharmony_ci
124fb726d48Sopenharmony_ciexport class StackValue {
125fb726d48Sopenharmony_ci  state: string = '';
126fb726d48Sopenharmony_ci  color: string = '';
127fb726d48Sopenharmony_ci  value: number = 0;
128fb726d48Sopenharmony_ci}
129