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 { SelectionData } from '../bean/BoxSelection';
18import { Utils } from './trace/base/Utils';
19
20@element('stack-bar')
21export class StackBar extends BaseElement {
22  private vessel: HTMLDivElement | undefined | null;
23
24  static get observedAttributes(): string[] {
25    return ['mode']; // max min hidden show 三种状态
26  }
27
28  set data(val: Array<SelectionData>) {
29    let map = new Map<string, StackValue>();
30    for (let v of val) {
31      if (map.has(v.stateJX)) {
32        let sv = map.get(v.stateJX);
33        sv!.value = sv!.value + v.wallDuration;
34        sv!.state = `${v.stateJX} : ${sv!.value.toFixed(5)}ms`;
35      } else {
36        let sv = new StackValue();
37        sv.value = v.wallDuration;
38        sv.state = `${v.stateJX} : ${sv.value.toFixed(5)}ms`;
39        sv.color = Utils.getStateColor(v.state);
40        map.set(v.stateJX, sv);
41      }
42    }
43    let totalDuration = 0;
44    let arr: Array<StackValue> = [];
45    for (let key of map.keys()) {
46      if (key === ' ') {
47        totalDuration = map.get(key)!.value;
48      } else {
49        arr.push(map.get(key)!);
50      }
51    }
52    arr.sort((a, b) => a.value - b.value);
53    this.vessel!.innerHTML = '';
54    for (let stackValue of arr) {
55      this.vessel!.appendChild(this.createBarElement(stackValue, totalDuration));
56    }
57  }
58
59  initElements(): void {
60    this.vessel = this.shadowRoot?.querySelector('#vessel');
61  }
62
63  initHtml(): string {
64    return `
65        <style>
66            :host([mode='hidden']){
67                display: none;
68            }
69            :host{
70                display: block;
71                /*background-color: rebeccapurple;*/
72            }
73            .state-text{
74                width: 10%;display: inline-block;overflow: hidden;white-space: nowrap;padding: 5px; margin-right: 2px;font-size: 9pt;
75            }
76            </style>
77            <div style="display: flex;flex-direction: row;" id="vessel">
78            </div>
79        `;
80  }
81
82  getStateWidth(state: string): number {
83    let canvas = document.createElement('canvas');
84    let context = canvas.getContext('2d');
85    context!.font = '9pt';
86    let metrics = context!.measureText(state);
87    return metrics.width;
88  }
89
90  createBarElement(sv: StackValue, total: number): HTMLDivElement {
91    let bar = document.createElement('div');
92    bar.setAttribute('class', 'state-text');
93    bar.setAttribute('need-width', `${this.getStateWidth(sv.state)}`);
94    bar.style.backgroundColor = sv.color;
95    bar.textContent = sv.state;
96    if (sv.state.startsWith('Sleeping')) {
97      bar.style.color = '#555555';
98    } else {
99      bar.style.color = '#ffffff';
100    }
101    let weight = ((sv.value * 1.0) / total) * 100.0;
102    if (weight < 1) {
103      weight = 1;
104    }
105    bar.style.width = `${weight}%`;
106    bar.addEventListener('mouseover', (): void => {
107      let needWidth = parseFloat(bar.getAttribute('need-width')!);
108      let trueWidth = parseFloat(window.getComputedStyle(bar).width);
109      if (trueWidth < needWidth) {
110        bar.style.width = `${needWidth + 100}px`;
111      }
112    });
113    bar.addEventListener('mouseleave', (): void => {
114      let weight = ((sv.value * 1.0) / total) * 100.0;
115      if (weight < 1) {
116        weight = 1;
117      }
118      bar.style.width = `${weight}%`;
119    });
120    return bar;
121  }
122}
123
124export class StackValue {
125  state: string = '';
126  color: string = '';
127  value: number = 0;
128}
129