• 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 */
15import { BaseElement, element } from '../../../../base-ui/BaseElement';
16import { TraceRowObject } from './TraceRowObject';
17import { TraceRow } from './TraceRow';
18import { log } from '../../../../log/Log';
19
20@element('trace-row-recycler-view')
21export class TraceRowRecyclerView extends BaseElement {
22  private recycler: boolean = true;
23  private gasketEL: HTMLDivElement | null | undefined;
24  private vessel: HTMLDivElement | null | undefined;
25  private visibleRowsCount: number = 0;
26  private visibleObjects: TraceRowObject<any>[] = [];
27  private totalHeight: number = 0;
28
29  private _dataSource: Array<TraceRowObject<any>> = [];
30  private _renderType: string = 'div';
31
32  get dataSource(): Array<TraceRowObject<any>> {
33    return this._dataSource;
34  }
35
36  set dataSource(value: Array<TraceRowObject<any>>) {
37    log('dataSource TraceRowObject size :' + value.length);
38    this._dataSource = value;
39    this.measureHeight();
40    this.initUI();
41    let els = [...this.shadowRoot!.querySelectorAll<TraceRow<any>>('.recycler-cell')];
42    for (let i = 0; i < els.length; i++) {
43      this.refreshRow(els[i], this.visibleObjects[i]);
44    }
45  }
46
47  get renderType(): string {
48    return this._renderType;
49  }
50
51  set renderType(value: string) {
52    this._renderType = value;
53  }
54
55  refreshRow(el: TraceRow<any>, obj: TraceRowObject<any>) {
56    if (!obj) {
57      return;
58    }
59    el.obj = obj;
60    el.folder = obj.folder;
61    el.style.top = `${obj.top}px`;
62    el.name = obj.name || '';
63    if (obj.children) {
64      el.setAttribute('children', ``);
65    } else {
66      el.removeAttribute('children');
67    }
68    el.style.visibility = 'visible';
69    el.rowId = obj.rowId;
70    el.rowType = obj.rowType;
71    el.rowParentId = obj.rowParentId;
72    el.expansion = obj.expansion;
73    el.rowHidden = obj.rowHidden;
74    el.setAttribute('height', `${obj.rowHeight}`);
75    requestAnimationFrame(() => {});
76  }
77
78  initElements(): void {
79    this.vessel = this.shadowRoot?.querySelector<HTMLDivElement>('.vessel');
80    this.gasketEL = this.shadowRoot?.querySelector<HTMLDivElement>('.gasket');
81    let els: Array<TraceRow<any>> | undefined | null;
82    this.vessel!.onscroll = (ev) => {
83      let top = this.vessel!.scrollTop;
84      let skip = 0;
85      for (let index = 0; index < this.visibleObjects.length; index++) {
86        if (this.visibleObjects[index].top >= top) {
87          skip = this.visibleObjects[index].rowIndex - 1;
88          break;
89        }
90      }
91      if (skip < 0) skip = 0;
92      if (!els) els = [...this.shadowRoot!.querySelectorAll<TraceRow<any>>('.recycler-cell')];
93      for (let i = 0; i < els.length; i++) {
94        let obj = this.visibleObjects[i + skip];
95        this.refreshRow(els[i], obj);
96      }
97    };
98  }
99
100  measureHeight() {
101    this.visibleObjects = this.dataSource.filter((it) => !it.rowHidden);
102    this.totalHeight = this.visibleObjects.map((it) => it.rowHeight).reduce((a, b) => a + b);
103    let totalHeight = 0;
104    for (let i = 0; i < this.visibleObjects.length; i++) {
105      this.visibleObjects[i].top = totalHeight;
106      this.visibleObjects[i].rowIndex = i;
107      totalHeight += this.visibleObjects[i].rowHeight;
108      this.visibleObjects[i].preObject = i == 0 ? null : this.visibleObjects[i - 1];
109      this.visibleObjects[i].nextObject = i == this.visibleObjects.length - 1 ? null : this.visibleObjects[i + 1];
110    }
111    this.gasketEL && (this.gasketEL.style.height = `${this.totalHeight}px`);
112  }
113
114  initUI() {
115    this.visibleRowsCount = Math.ceil(this.clientHeight / 40);
116    if (this.visibleRowsCount >= this.visibleObjects.length) {
117      this.visibleRowsCount = this.visibleObjects.length;
118    }
119    if (!this.recycler) this.visibleRowsCount = this.dataSource.length;
120    for (let i = 0; i <= this.visibleRowsCount; i++) {
121      let el = new TraceRow<any>({
122        canvasNumber: 1,
123        alpha: true,
124        contextId: '2d',
125        isOffScreen: true,
126      });
127      el.className = 'recycler-cell';
128      this.vessel?.appendChild(el);
129      el.addEventListener('expansion-change', (ev: any) => {
130        el.obj!.expansion = ev.detail.expansion;
131        for (let j = 0; j < this.dataSource.length; j++) {
132          if (this.dataSource[j].rowParentId == ev.detail.rowId) {
133            this.dataSource[j].rowHidden = !ev.detail.expansion;
134          }
135        }
136        this.measureHeight();
137        let els = [...this.shadowRoot!.querySelectorAll<TraceRow<any>>('.recycler-cell')];
138        let top = this.vessel!.scrollTop;
139        let skip = 0;
140        for (let i = 0; i < this.visibleObjects.length; i++) {
141          if (this.visibleObjects[i].top >= top) {
142            skip = this.visibleObjects[i].rowIndex - 1;
143            break;
144          }
145        }
146        if (skip < 0) skip = 0;
147        for (let i = 0; i < els.length; i++) {
148          let obj = this.visibleObjects[i + skip];
149          this.refreshRow(els[i], obj);
150        }
151      });
152    }
153  }
154
155  initHtml(): string {
156    return `
157        <style>
158        :host{
159            width:100%;
160            height:100%;
161            display: block;
162            position:relative;
163        }
164        .vessel{
165            width:100%;
166            height:100%;
167            overflow: auto;
168            position: absolute;
169            display: block;
170        }
171        .gasket{
172            width:100%;
173            height:auto;
174            top: 0;
175            left: 0;
176            right:0;
177            bottom:0;
178            visibility: hidden;
179        }
180        .recycler-cell{
181            position: absolute;
182            width:100%;
183            visibility: hidden;
184            top: 0;
185            left: 0;
186        }
187        </style>
188        <div class="vessel">
189            <div class="gasket"></div>
190        </div>
191
192        `;
193  }
194}
195