• 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 {TraceRowObject} from "./TraceRowObject.js";
18import {TraceRow} from "./TraceRow.js";
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 container: 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
31    get dataSource(): Array<TraceRowObject<any>> {
32        return this._dataSource;
33    }
34
35    set dataSource(value: Array<TraceRowObject<any>>) {
36        this._dataSource = value;
37        this.measureHeight();
38        this.initUI();
39        let els = [...(this.shadowRoot!.querySelectorAll<TraceRow<any>>(".recycler-cell"))];
40        for (let i = 0; i < els.length; i++) {
41            this.refreshRow(els[i], this.visibleObjects[i]);
42        }
43    }
44
45    private _renderType: string = 'div';
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            el.drawObject();
77        })
78    }
79
80    initElements(): void {
81        this.container = this.shadowRoot?.querySelector<HTMLDivElement>(".container");
82        this.gasketEL = this.shadowRoot?.querySelector<HTMLDivElement>(".gasket");
83        let els: Array<TraceRow<any>> | undefined | null;
84        this.container!.onscroll = (ev) => {
85            let top = this.container!.scrollTop;
86            let skip = 0;
87            for (let i = 0; i < this.visibleObjects.length; i++) {
88                if (this.visibleObjects[i].top >= top) {
89                    skip = this.visibleObjects[i].rowIndex - 1;
90                    break;
91                }
92            }
93            if (skip < 0) skip = 0;
94            if (!els) els = [...(this.shadowRoot!.querySelectorAll<TraceRow<any>>(".recycler-cell"))];
95            for (let i = 0; i < els.length; i++) {
96                let obj = this.visibleObjects[i + skip];
97                this.refreshRow(els[i], obj);
98            }
99        }
100    }
101
102    measureHeight() {
103        this.visibleObjects = this.dataSource.filter(it => !it.rowHidden);
104        this.totalHeight = this.visibleObjects.map((it) => it.rowHeight).reduce((a, b) => a + b);
105        let totalHeight = 0;
106        for (let i = 0; i < this.visibleObjects.length; i++) {
107            this.visibleObjects[i].top = totalHeight;
108            this.visibleObjects[i].rowIndex = i;
109            totalHeight += this.visibleObjects[i].rowHeight;
110            this.visibleObjects[i].preObject = i == 0 ? null : this.visibleObjects[i - 1];
111            this.visibleObjects[i].nextObject = i == this.visibleObjects.length - 1 ? null : this.visibleObjects[i + 1];
112        }
113        this.gasketEL && (this.gasketEL.style.height = `${this.totalHeight}px`);
114    }
115
116    initUI() {
117        this.visibleRowsCount = Math.ceil(this.clientHeight / 40);
118        if (this.visibleRowsCount >= this.visibleObjects.length) {
119            this.visibleRowsCount = this.visibleObjects.length;
120        }
121        if (!this.recycler) this.visibleRowsCount = this.dataSource.length;
122        for (let i = 0; i <= this.visibleRowsCount; i++) {
123            let el = new TraceRow<any>({alpha: true, contextId: '2d', isOffScreen: true});
124            el.className = "recycler-cell"
125            this.container?.appendChild(el);
126            el.addEventListener('expansion-change', (ev: any) => {
127                el.obj!.expansion = ev.detail.expansion;
128                console.log(ev.detail, el.obj);
129                for (let j = 0; j < this.dataSource.length; j++) {
130                    if (this.dataSource[j].rowParentId == ev.detail.rowId) {
131                        this.dataSource[j].rowHidden = !ev.detail.expansion;
132                    }
133                }
134                this.measureHeight();
135                let els = [...(this.shadowRoot!.querySelectorAll<TraceRow<any>>(".recycler-cell"))];
136                let top = this.container!.scrollTop;
137                let skip = 0;
138                for (let i = 0; i < this.visibleObjects.length; i++) {
139                    if (this.visibleObjects[i].top >= top) {
140                        skip = this.visibleObjects[i].rowIndex - 1;
141                        break;
142                    }
143                }
144                if (skip < 0) skip = 0;
145                for (let i = 0; i < els.length; i++) {
146                    let obj = this.visibleObjects[i + skip];
147                    this.refreshRow(els[i], obj);
148                }
149            })
150        }
151    }
152
153    initHtml(): string {
154        return `
155<style>
156:host{
157    width:100%;
158    height:100%;
159    display: block;
160    position:relative;
161}
162.container{
163    width:100%;
164    height:100%;
165    overflow: auto;
166    position: absolute;
167    display: block;
168}
169.gasket{
170    width:100%;
171    height:auto;
172    top: 0;
173    left: 0;
174    right:0;
175    bottom:0;
176    visibility: hidden;
177}
178.recycler-cell{
179    position: absolute;
180    width:100%;
181    visibility: hidden;
182    top: 0;
183    left: 0;
184}
185</style>
186<div class="container">
187    <div class="gasket"></div>
188</div>
189
190`;
191    }
192
193}
194