• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<!DOCTYPE html>
2<html lang="en">
3<head>
4    <meta charset="UTF-8">
5    <title>Report</title>
6    <style>
7        * {
8            box-sizing: border-box;
9        }
10
11        html,
12        body {
13            height: 100%;
14            margin: 0;
15            padding: 0;
16        }
17
18        lit-tabs {
19            padding-top: 10px;
20        }
21
22        lit-tabpane {
23            padding: 20px;
24        }
25    </style>
26</head>
27<body>
28<script type="module">
29    window.getShadowRoot = (el)=>{
30        if(el.parentNode){
31            return window.getShadowRoot(el.parentNode)
32        }else{
33            return el;
34        }
35    };
36    window.getShadowElement = (el)=>{
37        if(el.parentElement){
38            return window.getShadowElement(el.parentElement)
39        }else{
40            return el;
41        }
42    };
43    class LitIcon extends HTMLElement {
44        static get observedAttributes() {
45            return ["name", "size", "color", "path"]
46        }
47
48        constructor() {
49            super();
50            const shadowRoot = this.attachShadow({mode: 'open'});
51            shadowRoot.innerHTML = `
52        <style>
53        :host{
54            font-size: inherit;
55            display: inline-block;
56            transition: .3s;
57         }
58         :host([spin]){
59            animation: rotate 1.75s linear infinite;
60         }
61         @keyframes rotate {
62            to{
63                transform: rotate(360deg);
64            }
65         }
66         .icon{
67            display: block;
68            width: 1em;
69            height: 1em;
70            margin: auto;
71            fill: currentColor;
72            overflow: hidden;
73         }
74        </style>
75        <svg style="display: none" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
76            <symbol id="icon-ellipsis" viewBox="0 0 1024 1024"><path d="M232 511m-56 0a56 56 0 1 0 112 0 56 56 0 1 0-112 0Z"></path><path d="M512 511m-56 0a56 56 0 1 0 112 0 56 56 0 1 0-112 0Z"></path><path d="M792 511m-56 0a56 56 0 1 0 112 0 56 56 0 1 0-112 0Z"></path></symbol>
77            <symbol id="icon-doubleleft" viewBox="0 0 1024 1024"><path d="M272.9 512l265.4-339.1c4.1-5.2 0.4-12.9-6.3-12.9h-77.3c-4.9 0-9.6 2.3-12.6 6.1L186.8 492.3c-9.1 11.6-9.1 27.9 0 39.5l255.3 326.1c3 3.9 7.7 6.1 12.6 6.1H532c6.7 0 10.4-7.7 6.3-12.9L272.9 512z"></path><path d="M576.9 512l265.4-339.1c4.1-5.2 0.4-12.9-6.3-12.9h-77.3c-4.9 0-9.6 2.3-12.6 6.1L490.8 492.3c-9.1 11.6-9.1 27.9 0 39.5l255.3 326.1c3 3.9 7.7 6.1 12.6 6.1H836c6.7 0 10.4-7.7 6.3-12.9L576.9 512z"></path></symbol>
78            <symbol id="icon-doubleright" viewBox="0 0 1024 1024"><path d="M533.2 492.3L277.9 166.1c-3-3.9-7.7-6.1-12.6-6.1H188c-6.7 0-10.4 7.7-6.3 12.9L447.1 512 181.7 851.1c-4.1 5.2-0.4 12.9 6.3 12.9h77.3c4.9 0 9.6-2.3 12.6-6.1l255.3-326.1c9.1-11.7 9.1-27.9 0-39.5z"></path><path d="M837.2 492.3L581.9 166.1c-3-3.9-7.7-6.1-12.6-6.1H492c-6.7 0-10.4 7.7-6.3 12.9L751.1 512 485.7 851.1c-4.1 5.2-0.4 12.9 6.3 12.9h77.3c4.9 0 9.6-2.3 12.6-6.1l255.3-326.1c9.1-11.7 9.1-27.9 0-39.5z"></path></symbol>
79            <symbol id="icon-close-circle-fill" viewBox="0 0 1024 1024"><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64z m165.4 618.2l-66-0.3L512 563.4l-99.3 118.4-66.1 0.3c-4.4 0-8-3.5-8-8 0-1.9 0.7-3.7 1.9-5.2l130.1-155L340.5 359c-1.2-1.5-1.9-3.3-1.9-5.2 0-4.4 3.6-8 8-8l66.1 0.3L512 464.6l99.3-118.4 66-0.3c4.4 0 8 3.5 8 8 0 1.9-0.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"></path></symbol>
80<!--            <symbol id="icon-left" viewBox="0 0 1024 1024"><path d="M724 218.3V141c0-6.7-7.7-10.4-12.9-6.3L260.3 486.8c-16.4 12.8-16.4 37.5 0 50.3l450.8 352.1c5.3 4.1 12.9 0.4 12.9-6.3v-77.3c0-4.9-2.3-9.6-6.1-12.6l-360-281 360-281.1c3.8-3 6.1-7.7 6.1-12.6z"></path></symbol>-->
81<!--            <symbol id="icon-right" viewBox="0 0 1024 1024"><path d="M765.7 486.8L314.9 134.7c-5.3-4.1-12.9-0.4-12.9 6.3v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1c16.4-12.8 16.4-37.6 0-50.4z"></path></symbol>-->
82        </svg>
83        <svg class="icon" id="icon" aria-hidden="true" viewBox="0 0 ${this.view} ${this.view}">
84             ${this.path ? '<path id="path"></path>' : '<use id="use"></use>'}
85        </svg>
86        `
87        }
88
89        get view() {
90            return this.getAttribute("view") || 1024;
91        }
92
93        get name() {
94            return this.getAttribute("name");
95        }
96
97        get path() {
98            return this.getAttribute("path");
99        }
100
101        set name(value) {
102            this.setAttribute("name", value);
103        }
104
105        set path(value) {
106            this.setAttribute("path", value);
107        }
108
109        get size() {
110            return this.getAttribute("size") || "";
111        }
112
113        get color() {
114            return this.getAttribute("color") || "";
115        }
116
117        set size(value) {
118            this.setAttribute("size", value);
119        }
120
121        set color(value) {
122            this.setAttribute("color", value);
123        }
124
125        get spin() {
126            return this.hasAttribute('spin');
127        }
128
129        set spin(value) {
130            if (value) {
131                this.setAttribute('spin','')
132            }else{
133                this.removeAttribute('spin');
134            }
135        }
136
137        //当 custom element首次被插入文档DOM时,被调用。
138        connectedCallback() {
139            this.icon = this.shadowRoot.getElementById("icon");
140            this.use = this.shadowRoot.querySelector("use")
141            this.d = this.shadowRoot.querySelector("path");
142            this.size && (this.size = this.size);
143            this.color && (this.color = this.color);
144            this.name && (this.name = this.name);
145            this.path && (this.path = this.path);
146        }
147
148        //当 custom element从文档DOM中删除时,被调用。
149        disconnectedCallback() {
150
151        }
152
153        //当 custom element被移动到新的文档时,被调用。
154        adoptedCallback() {
155            console.log('Custom square element moved to new page.');
156        }
157
158        //当 custom element增加、删除、修改自身属性时,被调用。
159        attributeChangedCallback(name, oldValue, newValue) {
160            if (name === "name" && this.use) {
161                this.use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', `#icon-${newValue}`);
162            }
163            if (name === "path" && this.d) {
164                this.d.setAttribute("d", newValue);
165            }
166            if (name === "color" && this.icon) {
167                this.icon.style.color = newValue;
168            }
169            if (name === "size" && this.icon) {
170                this.icon.style.fontSize = newValue + "px";
171            }
172        }
173    }
174    if (!customElements.get('lit-icon')) {
175        customElements.define('lit-icon', LitIcon);
176    }
177
178    class LitInput extends HTMLElement {
179        static get observedAttributes() {
180            return [
181                'placeholder',//显示提示文字
182                'block',//属性将使按钮适合其父宽度。
183                'icon',//图标,如果配置了 slot='prefix' icon将失效
184                'bordered',//是否有边框
185                'allow-clear',//是否有清除
186                'rows',//表示行数,默认input 设置rows 后 显示为textarea
187                'maxlength',//允许输入多少个字符 默认没有限制
188                'type',//password  number  text
189                'pattern',//正则表达式
190                'error-text',//错误提示文字
191                'error-placement',//错误提示文字方向
192                'required',//是否开始验证
193                'value',//值
194            ];
195        }
196        get value(){
197            return this.getAttribute('value')||'';
198        }
199
200        set value(value) {
201            this.setAttribute('value',value);
202        }
203        get required(){
204            return this.hasAttribute('required');
205        }
206
207        set required(value) {
208            if (value) {
209                this.setAttribute('required', "");
210            }else{
211                this.removeAttribute('required');
212            }
213        }
214        get pattern(){
215            return this.getAttribute('pattern')||'';
216        }
217
218        set pattern(value) {
219            this.setAttribute('pattern', value);
220        }
221        get errorText(){
222            return this.getAttribute('error-text')||'该项为必填项';
223        }
224        set errorText(value) {
225            this.setAttribute('error-text',value)
226        }
227        get errorPlacement(){
228            return this.getAttribute('error-placement')||'top';
229        }
230        set errorPlacement(value) {
231            this.setAttribute('error-placement',value)
232        }
233        get type(){
234            return this.getAttribute('type');
235        }
236        set type(value){
237            this.setAttribute('type', value);
238        }
239        get maxlength(){
240            return this.getAttribute('maxlength')||'';
241        }
242
243        set maxlength(value) {
244            this.setAttribute('maxlength',value)
245        }
246        get rows(){
247            return this.getAttribute('rows');
248        }
249        set rows(value){
250            this.setAttribute('rows',value);
251        }
252        get allowClear() {
253            return this.hasAttribute('allow-clear');
254        }
255
256        set allowClear(value) {
257            if (value) {
258                this.setAttribute('allow-clear', '');
259            } else {
260                this.removeAttribute('allow-clear');
261            }
262        }
263
264        get bordered() {
265            return this.getAttribute('bordered') || "true";
266        }
267
268        set bordered(value) {
269            if (value) {
270                this.setAttribute('bordered', 'true');
271            } else {
272                this.setAttribute('bordered', 'false')
273            }
274        }
275
276        get icon() {
277            return this.getAttribute('icon') || null;
278        }
279
280        set icon(value) {
281            this.setAttribute('icon', value)
282        }
283
284        get block() {
285            return this.hasAttribute('block')
286        }
287
288        set block(value) {
289            if (value) {
290                this.setAttribute('block', '');
291            } else {
292                this.removeAttribute('block')
293            }
294        }
295
296        get placeholder() {
297            return this.getAttribute('placeholder') || '';
298        }
299
300        set placeholder(value) {
301            this.setAttribute('placeholder', value);
302        }
303
304        constructor() {
305            super();
306            const shadowRoot = this.attachShadow({mode: 'open'});
307            shadowRoot.innerHTML = `
308        <style>
309:host{
310    ${this.bordered === 'true' ? 'border: 1px solid #e9e9e9;' : ''}
311    display: inline-flex;
312    box-sizing: border-box;
313    position:relative;
314    align-items: ${this.rows?'flex-start':'center'};
315    transition: all .3s;
316    border-radius: 2px;
317    font-size: 14px;
318    color: #333;
319    ${this.block ? 'display: flex;' : ''}
320    box-sizing: border-box;
321 }
322 :host(:hover){
323    ${this.bordered === 'true' ? 'border: 1px solid #65b687;' : ''}
324    ${this.bordered === 'true' ? 'box-shadow: 0 0 10px #65b68766;' : ''}
325 }
326 *{
327    box-sizing: border-box;
328 }
329 .input{
330    outline: none;
331    border: 0px;
332    font-size: inherit;
333    color: inherit;
334    width: 100%;
335    height: 100%;
336    vertical-align:middle;
337    line-height:inherit;
338    height:inherit;
339    padding: 6px 6px 6px ${this.icon ? '6px' : '11px'};
340    max-height: inherit;
341    box-sizing: border-box;
342 }
343 /*去掉type=number 后面的增减箭头*/
344input::-webkit-outer-spin-button,
345input::-webkit-inner-spin-button {
346    -webkit-appearance: none;
347
348}
349
350input[type='number'] {
351    -moz-appearance: textfield;
352}
353
354 lit-tips{
355    flex: 1;
356    height: 100%;
357    width: 100%;
358 }
359 lit-tips{
360    flex: 1;
361    align-items: center;
362 }
363:host(:not([allow-clear])) .clear-btn{
364    display: flex;
365    visibility: hidden;
366    transition: all .3s;
367    opacity: 0;
368}
369:host([allow-clear]) .clear-btn{
370    opacity: 0;
371    position:absolute;
372    right: 0;
373    top: .5rem;
374    visibility: hidden;
375    transition: all .3s;
376    display: flex;
377    margin-right: 6px;
378    transform: translateY(0%);
379    color: #bfbfbf;
380}
381:host([allow-clear]) .clear-btn:hover{
382    color: #8c8c8c;
383}
384
385.area{
386    outline: none;
387    border: 0px;
388    width: 100%;
389    font-size: inherit;
390    vertical-align:middle;
391    min-height: calc(2rem);
392    max-height: calc(${this.rows} * 1rem);
393    padding: 6px 6px 6px ${this.icon ? '6px' : '11px'};
394    box-sizing: border-box;
395    resize:vertical;
396}
397
398:host(:not([type=password])) .pwd-btn,
399:host(:not([type=tel])) .pwd-btn{
400    display: none;
401    visibility: hidden;
402    transition: all .3s;
403    opacity: 0;
404}
405:host([type=password]) .pwd-btn,
406:host([type=tel]) .pwd-btn{
407    opacity: 1;
408    position:absolute;
409    right: 0;
410    top: .5rem;
411    visibility: visible;
412    transition: all .3s;
413    display: flex;
414    margin-right: 6px;
415    transform: translateY(0%);
416    color: #bfbfbf;
417}
418/*:host([type=password]) input{*/
419/*    -webkit-text-security:none;*/
420/*    text-security:none;*/
421/*}*/
422:host([type=password]) .pwd-btn:hover,
423:host([type=tel]) .pwd-btn:hover{
424    color: #8c8c8c;
425}
426
427</style>
428<slot name="prefix">${this.icon ? `<lit-icon name="${this.icon}" style="margin-left: 11px;color: inherit;font-size: inherit;${this.rows ? 'transform: translateY(50%);' : ''}"></lit-icon>` : ``}</slot>
429<lit-tips tips="${this.errorText}" placement="${this.errorPlacement}" color="#f4615c" offset="12px" show="false">
430    ${this.hasAttribute('rows')?
431                `<textarea class="area" rows="${this.rows}" value="${this.value}" placeholder="${this.placeholder}" cols="27" maxlength="${this.maxlength}" onscroll="this.rows++;"></textarea>`
432                :
433                `<input type="${this.type}" value="${this.value}" class="input" placeholder="${this.placeholder}"  >`}
434
435    <lit-icon class="clear-btn" name="close-circle-fill"></lit-icon>
436    <lit-icon class="pwd-btn" name="eye-fill"></lit-icon>
437</lit-tips>
438<slot name="suffix" ></slot>
439        `
440        }
441
442        //当 custom element首次被插入文档DOM时,被调用。
443        connectedCallback() {
444            this.reg = new RegExp(this.pattern);
445            this.inputElement = this.shadowRoot.querySelector('.input');
446            this.areaElement = this.shadowRoot.querySelector('.area');
447            this.clearElement = this.shadowRoot.querySelector('.clear-btn');
448            this.pwdElement = this.shadowRoot.querySelector('.pwd-btn');
449
450            this.pwdElement.onclick=(e)=>{
451                if(this.inputElement.getAttribute('type')==='password'){
452                    this.pwdElement.name = 'eyeclose-fill';
453                    this.inputElement.setAttribute('type','tel');
454                }else if(this.inputElement.getAttribute('type')==='tel'){
455                    this.inputElement.setAttribute('type','password');
456                    this.pwdElement.name = 'eye-fill';
457                }
458            }
459
460            if(this.areaElement){
461                this.clearElement.onclick=e=>{
462                    this.areaElement.value = '';
463                    this.clearElement.style.visibility = 'hidden';
464                    this.clearElement.style.opacity = '0';
465                    this.value=this.areaElement.value;
466                    this.dispatchEvent(new CustomEvent('onClear',e));
467                    this.clearError();
468                }
469                this.areaElement.oninput=e=>{
470                    if(this.allowClear){
471                        if(this.areaElement.value.length>0){
472                            this.clearElement.style.visibility = 'visible';
473                            this.clearElement.style.opacity = '1';
474                        }else{
475                            this.clearElement.style.visibility = 'hidden';
476                            this.clearElement.style.opacity = '0';
477                        }
478                    }
479                    this.value=this.areaElement.value;
480                    this.verify();
481                    this.dispatchEvent(new CustomEvent('input',e));
482                }
483                this.areaElement.onchange=e=>{
484                    this.value=this.areaElement.value;
485                    this.verify();
486                    this.dispatchEvent(new CustomEvent('change',e));
487                }
488                this.areaElement.onfocus=e=>{
489                    this.value=this.areaElement.value;
490                    this.verify();
491                    this.dispatchEvent(new CustomEvent('focus',e));
492                }
493                this.areaElement.onblur=e=>{
494                    this.value=this.areaElement.value;
495                    this.dispatchEvent(new CustomEvent('blur',e));
496                }
497                this.areaElement.onkeydown=e=>{
498                    if (e.key==='Enter') {
499                        this.value=this.areaElement.value;
500                        this.verify();
501                        this.dispatchEvent(new CustomEvent('onPressEnter',e));
502                    }
503                    this.dispatchEvent(new CustomEvent('keydown',e));
504                }
505                this.areaElement.onkeyup=e=>{
506                    this.dispatchEvent(new CustomEvent('keyup',e));
507                }
508                this.areaElement.onselect=e=>{
509                    this.dispatchEvent(new CustomEvent('select',e));
510                }
511                this.areaElement.onclick=e=>{
512                    this.dispatchEvent(new CustomEvent('click',e));
513                }
514            }
515            if (this.inputElement) {
516                this.clearElement.onclick=e=>{
517                    this.inputElement.value = '';
518                    this.clearElement.style.visibility = 'hidden';
519                    this.clearElement.style.opacity = '0';
520                    this.value=this.inputElement.value;
521                    this.dispatchEvent(new CustomEvent('onClear',e));
522                    this.clearError();
523                }
524                this.inputElement.oninput=e=>{
525                    if(this.allowClear){
526                        if(this.inputElement.value.length>0){
527                            this.clearElement.style.visibility = 'visible';
528                            this.clearElement.style.opacity = '1';
529                        }else{
530                            this.clearElement.style.visibility = 'hidden';
531                            this.clearElement.style.opacity = '0';
532                        }
533                    }
534                    this.value=this.inputElement.value;
535                    this.verify();
536                    this.dispatchEvent(new CustomEvent('input',e));
537                }
538                this.inputElement.onchange=e=>{
539                    this.value=this.inputElement.value;
540                    this.verify();
541                    this.dispatchEvent(new CustomEvent('change',e));
542                }
543                this.inputElement.onfocus=e=>{
544                    this.value=this.inputElement.value;
545                    this.verify();
546                    this.dispatchEvent(new CustomEvent('focus',e));
547                }
548                this.inputElement.onblur=e=>{
549                    this.dispatchEvent(new CustomEvent('blur',e));
550                }
551                this.inputElement.onkeydown=e=>{
552                    if (e.key==='Enter') {
553                        this.value=this.inputElement.value;
554                        this.verify();
555                        this.dispatchEvent(new CustomEvent('onPressEnter',e));
556                    }
557                    this.dispatchEvent(new CustomEvent('keydown',e));
558                }
559                this.inputElement.onkeyup=e=>{
560                    this.dispatchEvent(new CustomEvent('keyup',e));
561                }
562                this.inputElement.onselect=e=>{
563                    this.dispatchEvent(new CustomEvent('select',e));
564                }
565                this.inputElement.onclick=e=>{
566                    this.dispatchEvent(new CustomEvent('click',e));
567                }
568            }
569
570        }
571
572        //当 custom element从文档DOM中删除时,被调用。
573        disconnectedCallback() {
574
575        }
576
577        //当 custom element被移动到新的文档时,被调用。
578        adoptedCallback() {
579            console.log('Custom square element moved to new page.');
580        }
581
582        //当 custom element增加、删除、修改自身属性时,被调用。
583        attributeChangedCallback(name, oldValue, newValue) {
584            if (name === 'value') {
585                // console.log(name,oldValue,newValue);
586                // console.log(this.inputElement);
587                if(this.inputElement){
588                    this.inputElement.value=newValue
589                }else if(this.areaElement){
590                    this.areaElement.value=newValue;
591                }
592            }
593        }
594        verify(){
595            if(this.required){
596                let result;
597                if(this.hasAttribute('rows')){
598                    result= this.reg.test(this.areaElement.value);
599                }else{
600                    result= this.reg.test(this.inputElement.value);
601                }
602                if (result){
603                    this.shadowRoot.querySelector('lit-tips').show='false'
604                }else{
605                    this.shadowRoot.querySelector('lit-tips').show='true'
606                }
607                return result;
608            }else{
609                return true;
610            }
611        }
612        clearError(){
613            this.shadowRoot.querySelector('lit-tips').show='false'
614        }
615    }
616    if (!customElements.get('lit-input')) {
617        customElements.define('lit-input', LitInput);
618    }
619
620    class LitLoading extends HTMLElement {
621        static get observedAttributes() { return ['color','size'] }
622
623        constructor() {
624            super();
625            const shadowRoot = this.attachShadow({ mode: 'open' });
626            shadowRoot.innerHTML = `
627        <style>
628        :host{
629            font-size:inherit;
630            display:inline-flex;
631            align-items: center;
632            justify-content:center;
633            color:var(--themeColor,#42b983);
634        }
635        .loading{
636            display: block;
637            width: 1em;
638            height: 1em;
639            margin: auto;
640            animation: rotate 1.4s linear infinite;
641        }
642        .circle {
643            stroke: currentColor;
644            animation:  progress 1.4s ease-in-out infinite;
645            stroke-dasharray: 80px, 200px;
646            stroke-dashoffset: 0px;
647            transition:.3s;
648        }
649        :host(:not(:empty)) .loading{
650            margin:.5em;
651        }
652        @keyframes rotate{
653            to{
654                transform: rotate(360deg);
655            }
656        }
657        @keyframes progress {
658            0% {
659              stroke-dasharray: 1px, 200px;
660              stroke-dashoffset: 0px;
661            }
662            50% {
663              stroke-dasharray: 100px, 200px;
664              stroke-dashoffset: -15px;
665            }
666            100% {
667              stroke-dasharray: 100px, 200px;
668              stroke-dashoffset: -125px;
669            }
670        }
671        </style>
672        <svg class="loading" id="loading" viewBox="22 22 44 44"><circle class="circle" cx="44" cy="44" r="20.2" fill="none" stroke-width="3.6"></circle></svg>
673        <slot></slot>
674        `
675        }
676
677        get size() {
678            return this.getAttribute('size')||'';
679        }
680
681        get color() {
682            return this.getAttribute('color')||'';
683        }
684
685        set size(value) {
686            this.setAttribute('size', value);
687        }
688
689        set color(value) {
690            this.setAttribute('color', value);
691        }
692
693        connectedCallback() {
694            this.loading = this.shadowRoot.getElementById('loading');
695            this.size && (this.size = this.size);
696            this.color && (this.color = this.color);
697        }
698
699        attributeChangedCallback (name, oldValue, newValue) {
700            if( name == 'color' && this.loading){
701                this.loading.style.color = newValue;
702            }
703            if( name == 'size' && this.loading){
704                this.loading.style.fontSize = newValue + 'px';
705            }
706        }
707    }
708    if (!customElements.get('lit-loading')) {
709        customElements.define('lit-loading', LitLoading);
710    }
711
712    class LitPagination extends HTMLElement {
713        static get observedAttributes() {
714            return [
715                "current",//当前页码
716                "total",//总条数
717                "page-size",//每页条数
718                "disabled",//禁用分页
719                'show-size-changer',//显示每页条目数select
720                'show-quick-jumper',//显示跳至多少页
721                'page-size-options',//指定每页可以显示多少条 默认 [10,20,50,100]
722                'simple',//简洁模式
723            ]
724        }
725        get pageSizeOptions(){
726            return this.getAttribute('page-size-options');
727        }
728        set pageSizeOptions(value){
729            this.setAttribute('page-size-options', '');
730        }
731
732        get current() {
733            return this.getAttribute('current') || '1';
734        }
735
736        set current(value) {
737            this.setAttribute('current', value);
738        }
739
740        get total() {
741            return this.getAttribute('total') || '50';
742        }
743
744        set total(value) {
745            this.setAttribute('total', value);
746        }
747
748        get pageSize() {
749            return this.getAttribute('page-size') || '10';
750        }
751
752        set pageSize(value) {
753            this.setAttribute('page-size', value);
754        }
755
756        get disabled() {
757            return this.hasAttribute('disabled');
758        }
759
760        set disabled(value) {
761            if (value) {
762                this.setAttribute('disabled', '');
763            } else {
764                this.removeAttribute('disabled');
765            }
766        }
767
768        get showSizeChanger() {
769            return this.hasAttribute('show-size-changer')
770        }
771
772        set showSizeChanger(value) {
773            if (value) {
774                this.setAttribute('show-size-changer', '');
775            } else {
776                this.removeAttribute('show-size-changer');
777            }
778        }
779
780        get showQuickJumper() {
781            return this.hasAttribute('show-quick-jumper')
782        }
783
784        set showQuickJumper(value) {
785            if (value) {
786                this.setAttribute('show-quick-jumper', '');
787            } else {
788                this.removeAttribute('show-quick-jumper');
789            }
790        }
791
792        get simple() {
793            return this.hasAttribute('simple');
794        }
795
796        set simple(value) {
797            if (value) {
798                this.setAttribute('simple', '');
799            } else {
800                this.removeAttribute('simple');
801            }
802        }
803
804        constructor() {
805            super();
806            const shadowRoot = this.attachShadow({mode: 'open'});
807            shadowRoot.innerHTML = `
808<style>
809:host{
810     display: flex;
811     width: max-content;
812}
813.root{
814    display: inline-flex;
815    /*grid-template-columns: repeat(auto-fill,35px);*/
816    /*column-gap: 8px;*/
817    /*row-gap: 8px;*/
818    user-select: none;
819}
820.item{
821    box-sizing: border-box;
822    color: #333;
823    transition: all .3s;
824    width: 35px;
825    height: 35px;
826    margin-left: 6px;
827    padding: 6px 10px;
828    border: 1px solid #ececec;
829    border-radius: 3px;
830    cursor: pointer;
831    display: inline-flex;
832    align-items: center;
833    justify-content: center;
834}
835.item-dir{
836    color: #333;
837    transition: all .3s;
838    padding: 5px 10px;
839    /*border: 1px solid #ececec;*/
840    /*border-radius: 3px;*/
841    cursor: pointer;
842    display: inline-flex;
843    align-items: center;
844    justify-content: center;
845}
846.item:not([disable]):hover{
847    color:#42b983;
848    border: 1px solid #42b983;
849}
850.item[selected]{
851    color:#42b983;
852    border: 1px solid #42b983;
853}
854.item[disable]{
855    /*background-color: #f5f5f5;*/
856    fill: #c7c7c7;
857    color: #c7c7c7;
858    cursor: not-allowed;
859}
860
861:host([show-quick-jumper]) .jump-root{
862    grid-column: span 4;
863    margin-left: 6px;
864    display: inline-flex;
865    align-items: center;
866}
867:host(:not([show-quick-jumper])) .jump-root{
868    display: none;
869}
870
871:host([show-size-changer]) .pages-change{
872    display: inline-flex;
873    grid-column: span 3;
874    width: 120px;
875    margin-left: 6px;
876    font-size: .9rem;
877}
878:host(:not([show-size-changer])) .pages-change{
879    display: none;
880}
881</style>
882<div style="display: grid;grid-template-columns: max-content 1fr;">
883    <div style="display: inline-flex;align-items: center" id="showTotal">
884        <slot id="st" name="showTotal"></slot>
885    </div>
886    <div class="root">
887<!--        <lit-icon class="item left-arrow" name="left" ></lit-icon>-->
888        <svg class="item left-arrow" viewBox="0 0 1024 1024" aria-hidden="true" >
889            <path d="M724 218.3V141c0-6.7-7.7-10.4-12.9-6.3L260.3 486.8c-16.4 12.8-16.4 37.5 0 50.3l450.8 352.1c5.3 4.1 12.9 0.4 12.9-6.3v-77.3c0-4.9-2.3-9.6-6.1-12.6l-360-281 360-281.1c3.8-3 6.1-7.7 6.1-12.6z"></path>
890        </svg>
891        <div class="item first">1</div>
892        <lit-icon class="item-dir double-left" name="ellipsis" ></lit-icon>
893<!--        <svg class="item-dir double-left" viewBox="0 0 1024 1024" aria-hidden="true" style="width: 16px;width: 16px;">-->
894<!--            <path d="M232 511m-56 0a56 56 0 1 0 112 0 56 56 0 1 0-112 0Z"></path><path d="M512 511m-56 0a56 56 0 1 0 112 0 56 56 0 1 0-112 0Z"></path><path d="M792 511m-56 0a56 56 0 1 0 112 0 56 56 0 1 0-112 0Z"></path>-->
895<!--        </svg>-->
896        <div class="item one">2</div>
897        <div class="item two">3</div>
898        <div class="item three">4</div>
899        <div class="item four">5</div>
900        <div class="item five">6</div>
901        <lit-icon class="item-dir double-right" name="ellipsis" ></lit-icon>
902<!--        <svg class="item-dir double-right" viewBox="0 0 1024 1024" aria-hidden="true" style="width: 16px;width: 16px;">-->
903<!--            <path d="M232 511m-56 0a56 56 0 1 0 112 0 56 56 0 1 0-112 0Z"></path><path d="M512 511m-56 0a56 56 0 1 0 112 0 56 56 0 1 0-112 0Z"></path><path d="M792 511m-56 0a56 56 0 1 0 112 0 56 56 0 1 0-112 0Z"></path>-->
904<!--        </svg>-->
905        <div class="item last">1</div>
906<!--        <lit-icon class="item right-arrow" name="right"></lit-icon>-->
907        <svg class="item right-arrow" viewBox="0 0 1024 1024" aria-hidden="true" >
908            <path d="M765.7 486.8L314.9 134.7c-5.3-4.1-12.9-0.4-12.9 6.3v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1c16.4-12.8 16.4-37.6 0-50.4z"></path>
909        </svg>
910        <lit-select class="pages-change" default-value="10"></lit-select>
911        <div class="jump-root">
912            <label style="font-size: .9rem;color: #333;margin-right: 5px">跳至</label>
913            <lit-input type="number" class="jump" style="width: 80px;height: 100%"></lit-input>
914            <label style="font-size: .9rem;color: #333;margin-left: 5px">页</label>
915        </div>
916    </div>
917
918</div>
919
920        `
921        }
922
923        //当 custom element首次被插入文档DOM时,被调用。
924        connectedCallback() {
925            this.slotShowTotal=null;
926            this.rootElement = this.shadowRoot.querySelector('.root');
927            let st = this.shadowRoot.querySelector('#st');
928            st.addEventListener('slotchange',()=>{
929                let elements = st.assignedElements();
930                if(elements.length>0){
931                    this.slotShowTotal = elements[0];
932                }
933                if (this.slotShowTotal) {
934                    let cloneNode = this.slotShowTotal.render({
935                        total: this._total,
936                        range: [1,this._pages],
937                    }).content.cloneNode(true);
938                    this.shadowRoot.querySelector('#showTotal').append(cloneNode);
939                }
940            })
941            this.leftArrow = this.shadowRoot.querySelector('.left-arrow');
942            this.first = this.shadowRoot.querySelector('.first');
943            this.doubleLeft = this.shadowRoot.querySelector('.double-left');
944            this.one = this.shadowRoot.querySelector('.one');
945            this.two = this.shadowRoot.querySelector('.two');
946            this.three = this.shadowRoot.querySelector('.three');
947            this.four = this.shadowRoot.querySelector('.four');
948            this.five = this.shadowRoot.querySelector('.five');
949            this.doubleRight = this.shadowRoot.querySelector('.double-right');
950            this.last = this.shadowRoot.querySelector('.last');
951            this.rightArrow = this.shadowRoot.querySelector('.right-arrow');
952            this.pagesChange = this.shadowRoot.querySelector('.pages-change');
953            this.jump = this.shadowRoot.querySelector('.jump');
954            this.nodes = [this.one, this.two, this.three, this.four, this.five]
955
956            let jsonArray = JSON.parse(this.pageSizeOptions);
957            if (jsonArray){
958                this.pagesChange.dataSource=jsonArray.map(a=>{
959                    return {key:a, val:`${a} 条/页`,}
960                });
961                this.pagesChange.value = jsonArray[0]+'';
962                this.pageSize = jsonArray[0]+'';
963            }else {
964                this.pagesChange.dataSource=[10,20,50,100].map(a=>{
965                    return {key:a, val:`${a} 条/页`,}
966                });
967                this.pagesChange.value ='10';
968                this.pageSize = '10';
969            }
970
971            this.jump.addEventListener('onPressEnter',e=>{
972                if (e.target.value) {
973                    this.current=e.target.value;
974                    e.target.value = '';
975                    this.match();
976                }
977            });
978            this.pagesChange.onchange = e => {
979                // console.log(e.detail);
980                this.pageSize = e.detail.value;
981                this.match();
982                if (this.slotShowTotal) {
983                    let cloneNode = this.slotShowTotal.render({
984                        total: this._total,
985                        range: [1,this._pages],
986                    }).content.cloneNode(true);
987                    this.shadowRoot.querySelector('#showTotal').lastElementChild.remove();
988                    this.shadowRoot.querySelector('#showTotal').append(cloneNode);
989                }
990                this.dispatchEvent(new CustomEvent('onShowSizeChange',{
991                    detail:{
992                        current:parseInt(this.current),
993                        size:parseInt(this.pageSize)
994                    }
995                }))
996            }
997
998            this.leftArrow.onclick = (e) => {
999                if (this._current > 1) {
1000                    this.current = `${this._current - 1}`
1001                    this.match();
1002                }
1003            }
1004            this.rightArrow.onclick = (e) => {
1005                if (this._current < this._pages) {
1006                    this.current = `${this._current + 1}`
1007                    this.match();
1008                }
1009            }
1010            let nodeClickHandler = e => {
1011                this.current = `${e.currentTarget.val}`;
1012                this.match();
1013            };
1014            this.first.onclick = nodeClickHandler;
1015            this.nodes.forEach(a => a.onclick = nodeClickHandler);
1016            this.last.onclick = nodeClickHandler;
1017            this.doubleLeft.onmouseover = e => {
1018                e.target.name = 'doubleleft';
1019            }
1020            this.doubleLeft.onmouseout = e => {
1021                e.target.name = 'ellipsis'
1022            }
1023            this.doubleLeft.onclick = e => {
1024                let k = this._current - 5;
1025                if (k < 1) k = 1;
1026                this.current = `${k}`;
1027                this.match();
1028            }
1029            this.doubleRight.onmouseover = e => {
1030                e.target.name = 'doubleright';
1031            }
1032            this.doubleRight.onmouseout = e => {
1033                e.target.name = 'ellipsis'
1034            }
1035            this.doubleRight.onclick = e => {
1036                let k = this._current + 5;
1037                if (k > this._pages) k = this._pages;
1038                this.current = `${k}`;
1039                this.match();
1040            }
1041            this.match();
1042        }
1043
1044        match() {
1045            this._current = parseInt(this.current);
1046            this._total = parseInt(this.total);
1047            this._pageSize = parseInt(this.pageSize);
1048            this._pages = Math.ceil(this._total / this._pageSize)
1049            if(this._current>this._pages){
1050                this._current = this._pages;
1051                this.current = `${this._pages}`;
1052            }else if(this._current<1){
1053                this._current = 1;
1054                this.current = `1`;
1055            }
1056            //是否展示 pageSize 切换器,当 total 大于 50 时默认为 true
1057            // if(this._total>50) this.setAttribute('show-size-changer', '');
1058
1059            // console.log(`${this._total} ${this._current}/${this._pages} ${this._pageSize}`);
1060            if (this._current === 1) {
1061                this.leftArrow.setAttribute('disable', '');
1062            } else {
1063                this.leftArrow.removeAttribute('disable');
1064            }
1065            if (this._current === this._pages) {
1066                this.rightArrow.setAttribute('disable', '');
1067            } else {
1068                this.rightArrow.removeAttribute('disable');
1069            }
1070            this.hiddenNode(this.first, this.last, this.one, this.two, this.three, this.four, this.five, this.doubleLeft, this.doubleRight)
1071            if (this._pages <= 5) {
1072                for (let i = 0; i < this._pages; i++) {
1073                    this.displayNode(this.nodes[i]);
1074                    this.item(this.nodes[i], i + 1);
1075                }
1076            } else if (this._pages === 6) {
1077                this.displayNode(this.first);
1078                this.item(this.first, 1);
1079                for (let i = 0; i < this._pages; i++) {
1080                    this.displayNode(this.nodes[i]);
1081                    this.item(this.nodes[i], i + 2);
1082                }
1083            } else {
1084                this.displayNode(this.one, this.two, this.three, this.four, this.five)
1085                if (this._current - 3 > 1 && this._current + 3 < this._pages) { // 左边溢出 右边溢出
1086                    this.displayNode(this.first, this.last, this.doubleLeft, this.doubleRight);
1087                    this.item(this.first, 1);
1088                    this.item(this.last, this._pages);
1089                    this.item(this.one, this._current - 2);
1090                    this.item(this.two, this._current - 1);
1091                    this.item(this.three, this._current);
1092                    this.item(this.four, this._current + 1);
1093                    this.item(this.five, this._current + 2);
1094                } else if (this._current - 3 === 1 && this._current + 3 < this._pages) {//左边刚好 右边溢出
1095                    this.displayNode(this.first, this.last, this.doubleRight);
1096                    this.item(this.first, 1)
1097                    this.item(this.last, this._pages)
1098                    for (let i = 0; i < this.nodes.length; i++) {
1099                        this.item(this.nodes[i], i + 2);
1100                    }
1101                } else if (this._current - 3 < 1 && this._current + 3 < this._pages) {  //左边不够 右边溢出
1102                    this.displayNode(this.last, this.doubleRight);
1103                    this.item(this.last, this._pages)
1104                    for (let i = 0; i < this.nodes.length; i++) {
1105                        this.item(this.nodes[i], i + 1);
1106                    }
1107                } else if (this._current - 3 > 1 && this._current + 3 === this._pages) {// 左边溢出 右边刚好
1108                    this.displayNode(this.first, this.last, this.doubleLeft);
1109                    this.item(this.first, 1);
1110                    this.item(this.last, this._pages);
1111                    this.item(this.nodes[0], this._pages - 5);
1112                    this.item(this.nodes[1], this._pages - 4);
1113                    this.item(this.nodes[2], this._pages - 3);
1114                    this.item(this.nodes[3], this._pages - 2);
1115                    this.item(this.nodes[4], this._pages - 1);
1116                } else if (this._current - 3 === 1 && this._current + 3 === this._pages) {// 左边刚好 右边刚好
1117                    this.displayNode(this.first, this.last);
1118                    this.item(this.first, 1);
1119                    for (let i = 0; i < this._pages; i++) {
1120                        this.displayNode(this.nodes[i]);
1121                        this.item(this.nodes[i], i + 2);
1122                    }
1123                    this.item(this.last, 7);
1124                } else if (this._current - 3 < 1 && this._current + 3 === this._pages) {// 左边不够 右边刚好
1125                    this.displayNode(this.last);
1126                    this.item(this.last, this._pages)
1127                    for (let i = 0; i < this.nodes.length; i++) {
1128                        this.item(this.nodes[i], i + 1);
1129                    }
1130                } else if (this._current - 3 > 1 && this._current + 3 > this._pages) { //左边溢出 右边不够
1131                    this.displayNode(this.first, this.doubleLeft)
1132                    this.item(this.first, 1);
1133                    this.item(this.nodes[0], this._pages - 4);
1134                    this.item(this.nodes[1], this._pages - 3);
1135                    this.item(this.nodes[2], this._pages - 2);
1136                    this.item(this.nodes[3], this._pages - 1);
1137                    this.item(this.nodes[4], this._pages - 0);
1138                } else if (this._current - 3 === 1 && this._current + 3 > this._pages) { //左边刚好 右边不够
1139                    this.displayNode(this.first);
1140                    this.item(this.first, 1);
1141                    this.item(this.nodes[0], this._pages - 4);
1142                    this.item(this.nodes[1], this._pages - 3);
1143                    this.item(this.nodes[2], this._pages - 2);
1144                    this.item(this.nodes[3], this._pages - 1);
1145                    this.item(this.nodes[4], this._pages - 0);
1146                } else if (this._current - 3 < 1 && this._current + 3 > this._pages) { //左边不够 右边不够
1147                    //限定了 pages>6 这种情况不存在
1148                }
1149            }
1150        }
1151
1152        item(el, val) {
1153            el.val = val;
1154            el.textContent = val;
1155            if (val === this._current) {
1156                el.setAttribute('selected', '');
1157            } else {
1158                el.removeAttribute('selected');
1159            }
1160        }
1161
1162        displayNode() {
1163            [...arguments].forEach(a => a.style.display = 'flex');
1164        }
1165
1166        hiddenNode(n) {
1167            [...arguments].forEach(a => a.style.display = 'none');
1168        }
1169
1170        //当 custom element从文档DOM中删除时,被调用。
1171        disconnectedCallback() {
1172        }
1173
1174        //当 custom element被移动到新的文档时,被调用。
1175        adoptedCallback() {
1176        }
1177
1178        //当 custom element增加、删除、修改自身属性时,被调用。
1179        attributeChangedCallback(name, oldValue, newValue) {
1180            if (name === 'current') {
1181                this.dispatchEvent(new CustomEvent('onChange', {
1182                    detail: {
1183                        page: parseInt(newValue),
1184                        pageSize: this._pageSize
1185                    }
1186                }));
1187            }else if(name === 'total'){
1188                this.dispatchEvent(new CustomEvent('onChange', {
1189                    detail: {
1190                        total: parseInt(newValue),
1191                        current: this._current,
1192                        pageSize: this._pageSize
1193                    }
1194                }));
1195                this.match()
1196            }
1197
1198        }
1199    }
1200    if (!customElements.get('lit-pagination')) {
1201        customElements.define('lit-pagination', LitPagination);
1202    }
1203
1204    class LitPieChart extends HTMLElement {
1205        static get observedAttributes() { return [] }
1206
1207        constructor() {
1208            super();
1209            const shadowRoot = this.attachShadow({ mode: 'open' });
1210            shadowRoot.innerHTML = `
1211        <style>
1212        :host{
1213            font-size:inherit;
1214            display:inline-flex;
1215            align-items: center;
1216            justify-content:center;
1217            color:#42b983;
1218        }
1219        </style>
1220        <div style="display: flex;flex-direction: row;width: 100%;padding: 15px">
1221            <div style="display: flex;flex-direction: column;align-items: center;width: 40%">
1222                <div id="chartTitle" style="width:auto;font-size: 20px;margin-bottom: 15px;text-overflow: ellipsis;white-space: nowrap"></div>
1223                <canvas id="chartView" width="200" height="200" ></canvas>
1224            </div>
1225            <div id="labelDiv" style="margin-top: 45px">
1226                <div id="legendDiv"></div>
1227                <div id="pageOptionDiv" style="display: none;flex-direction: row;margin-top: 15px">
1228                    <div id="previous" style="cursor: pointer">previous</div>
1229                    <div id="page" style="margin-left: 10px;margin-right: 10px">1/9</div>
1230                    <div id="next" style="cursor: pointer">next</div>
1231                </div>
1232            </div>
1233            <div id="tip" style="display: none;position: absolute;z-index: 999;width: auto;height: auto;background-color: #fff;
1234                    border-radius: 3px;border:1px solid #eee;box-shadow: 0px 0px 2px 2px #aaa;padding: 10px">
1235                <div id="tipName" style="width: auto;font-weight: bold;margin-bottom: 10px"></div>
1236                <div id="tipValue" style="width: auto;font-weight: bold"></div>
1237            </div>
1238        </div>
1239        <slot></slot>
1240        `
1241        }
1242
1243        get dataSource() {
1244            return this.ds || [];
1245        }
1246
1247        set dataSource(value) {
1248            this.ds = value;
1249            if(this.ds){
1250                this.page = 0;
1251                let p = parseInt((this.ds.length / this.pageSize).toString());
1252                this.totalPage = this.ds.length % this.pageSize > 0 ? (p + 1) : p
1253                if(this.totalPage > 9){
1254                    this.totalPage = 9;
1255                }
1256                let tempAngel = -1 / 4 * 2 * Math.PI; // 饼图的起始角度
1257                this.ds.forEach(item=>{
1258                    item.startAngel = tempAngel; // 起始弧度
1259                    item.angel = item.value * 2 * Math.PI;
1260                    item.endAngel = (tempAngel + item.angel); //结束弧度
1261                    if(item.endAngel > Math.PI * 3 / 2){
1262                        item.endAngel = Math.PI * 3 / 2;
1263                    }
1264                    tempAngel += item.angel;
1265                });
1266                this.updateOptionStatus()
1267                this.addChartLegend();
1268            }
1269            this.renderChart();
1270        }
1271
1272        get title(){
1273            return this.ct || ''
1274        }
1275
1276        set title(value){
1277            this.ct = value;
1278            if(value){
1279                this.chartTitle.innerText = value.length > 50 ? value.slice(0,49)+'...' : value;
1280            }
1281        }
1282
1283
1284        connectedCallback() {
1285            this.pageSize = 14;
1286            this.page = 0;
1287            this.chartView = this.shadowRoot.getElementById('chartView');
1288            this.chartView.width = window.devicePixelRatio * this.chartView.width;
1289            this.chartView.height = window.devicePixelRatio * this.chartView.height;
1290            this.chartTitle = this.shadowRoot.getElementById('chartTitle');
1291            this.labelDiv = this.shadowRoot.getElementById('legendDiv');
1292            this.tip = this.shadowRoot.getElementById('tip');
1293            this.tipName = this.shadowRoot.getElementById('tipName');
1294            this.tipValue = this.shadowRoot.getElementById('tipValue');
1295            this.pageOptionDiv = this.shadowRoot.getElementById('pageOptionDiv');
1296            this.previousBt = this.shadowRoot.getElementById('previous')
1297            this.pageDiv = this.shadowRoot.getElementById('page')
1298            this.nextBt = this.shadowRoot.getElementById('next')
1299            this.previousBt.addEventListener('click',this.previousPage.bind(this))
1300            this.nextBt.addEventListener('click',this.nextPage.bind(this))
1301            this.chartView.addEventListener('mousemove',this.mouseMove.bind(this));
1302            this.chartView.addEventListener('click',this.mouseClick.bind(this));
1303            this.chartView.addEventListener('mouseout',this.mouseOut.bind(this));
1304        }
1305
1306        mouseMove(event){
1307            const mousePos = this.getMousePost(event)
1308            const result = this.containPoint(mousePos)
1309            if(result){
1310                this.tip.style.left = (event.clientX + 40) + 'px';
1311                this.tip.style.top = (event.clientY - 40) + 'px';
1312                this.tip.style.display = 'flex';
1313                this.tip.style.flexDirection = 'column';
1314                this.tipName.innerText = result.name
1315                this.tipValue.innerText = result.time + ' (' + (result.value * 100).toFixed(1) + '%)'
1316            }else{
1317                this.tip.style.display = 'none';
1318                if(this.selectItem != null){
1319                    this.selectItem = undefined;
1320                    this.renderChart()
1321                }
1322            }
1323        }
1324
1325        mouseOut(event){
1326            this.tip.style.display = 'none';
1327            if(this.selectItem != null){
1328                this.selectItem = undefined;
1329                this.renderChart()
1330            }
1331        }
1332
1333        mouseClick(event){
1334            if(this.selectItem && this.hasOwnProperty('chartClickListener')){
1335                this.chartClickListener(this.selectItem)
1336            }
1337        }
1338
1339        attributeChangedCallback (name, oldValue, newValue) {
1340
1341        }
1342
1343        // clientX,clientY
1344        // 判断鼠标在 canvas 的位置
1345        getMousePost(event) {
1346            // 获取鼠标的位置
1347            const { clientX, clientY } = event
1348            //  获取 canvas 的边界位置
1349            const { top, left } = this.chartView.getBoundingClientRect()
1350            //  计算鼠标在 canvas 在位置
1351            const x = (clientX - left)
1352            const y = (clientY - top)
1353            return { x, y }
1354        }
1355
1356        //  判断是不是在 canvas上
1357        containPoint(mousePos) {
1358            let selector = undefined;
1359            let centerX = this.centerX
1360            let centerY = this.centerY
1361            const [subX,subY] = [centerX - mousePos.x,centerY - mousePos.y]
1362            //圆心到鼠标 的位置
1363            const len = Math.sqrt(subX * subX + subY * subY)
1364            //判断是否在圆内
1365            const inChart = len < this.chartRadius
1366            // 判断是不是在 startAngleendAngle
1367            if(inChart){
1368                if (this.ds) {
1369                    let angle = Math.atan2(centerY - mousePos.y, centerX - mousePos.x) * (180 / Math.PI);
1370                    let pointAngle = 0;
1371                    if(angle >= 90){
1372                        pointAngle = -(180 - angle);
1373                    }else if(angle >= 0 && angle < 90){
1374                        pointAngle = 270 + angle;
1375                    }else if(angle < 0 && angle >= -90){
1376                        pointAngle = 270 + angle;
1377                    }else{
1378                        pointAngle = 90 + 180 + angle;
1379                    }
1380                    let pa = pointAngle / 180 * Math.PI;
1381                    if(pa > 0){
1382                        pa = pa - Math.PI / 2
1383                    }
1384                    for(let item of this.ds){
1385                        if(pa >= item.startAngel && pa < item.endAngel){
1386                            selector = item;
1387                            if(item != this.selectItem){
1388                                this.selectItem = item;
1389                                this.renderChart()
1390                            }
1391                            break;
1392                        }
1393                    }
1394                }
1395            }
1396            return selector
1397        }
1398
1399        renderChart(){
1400            if(this.ds){
1401                let context = this.chartView.getContext("2d")
1402                //清除画布
1403                context.clearRect(0,0,this.chartView.width,this.chartView.height)
1404                this.centerX = this.chartView.width / 2;
1405                this.centerY = this.chartView.height / 2; // 圆心坐标
1406                let labelX,labelY; // label 文字绘制位置
1407                let radius = this.chartView.height / 2 - 10; // 原型半径
1408                this.chartRadius = radius;
1409                let offset = radius / 6;
1410                let size = this.ds.length;
1411                this.ds.forEach(item => {
1412                    if(item == this.selectItem){
1413                        context.beginPath();
1414                        context.moveTo(this.centerX,this.centerY);
1415                        context.arc(this.centerX,this.centerY,radius + 5,item.startAngel,item.endAngel);
1416                        context.fillStyle = this.colorRgbWithAlpha(item.color);
1417                        context.fill();
1418                        context.closePath()
1419                    }
1420                    context.beginPath();
1421                    context.moveTo(this.centerX,this.centerY);
1422                    context.arc(this.centerX,this.centerY,radius,item.startAngel,item.endAngel);
1423                    context.fillStyle = item.color;
1424                    context.fill();
1425                    if(size > 1){
1426                        context.strokeStyle = '#ffffff'
1427                        context.stroke()
1428                    }
1429                    if(item.value > 0.045){
1430                        let text = (item.value * 100).toFixed(1) + '%';
1431                        context.font = '13px Microsoft Yahei';
1432                        context.moveTo(this.centerX,this.centerY)
1433                        context.fillStyle = '#ffffff';
1434                        let textWidth = context.measureText(text).width;
1435                        if(size == 1){
1436                            context.fillText(text,this.centerX - textWidth / 2,this.centerY);
1437                        }else{
1438                            let textAngel = item.startAngel + item.angel * 0.5; // 文字角度
1439                            labelX = this.centerX + Math.cos(textAngel) * (radius - offset);
1440                            labelY = this.centerY + Math.sin(textAngel) * (radius - offset);
1441                            context.fillText(text,labelX - textWidth / 2,labelY);
1442                        }
1443                    }
1444                    context.closePath()
1445                })
1446            }
1447        }
1448
1449        addChartLegend(){
1450            this.labelDiv.innerText = '';
1451            if(this.ds.length <= 15){
1452                this.pageOptionDiv.style.display = 'none';
1453                this.ds.forEach(item=>{
1454                    this.labelDiv.appendChild(this.createChartLegend(item))
1455                });
1456            }else{
1457                this.pageOptionDiv.style.display = 'flex';
1458                for(let i = this.page * this.pageSize; i < (this.page + 1) * this.pageSize; i++){
1459                    if(i < this.ds.length){
1460                        this.labelDiv.appendChild(this.createChartLegend(this.ds[i]))
1461                    }else{
1462                        break;
1463                    }
1464                }
1465                if(this.page == 9 && this.ds.length > 126){
1466                    this.labelDiv.appendChild(this.createChartLegend(this.ds[this.ds.length - 1]))
1467                }
1468            }
1469            this.pageDiv.innerText = `${this.page + 1}/${this.totalPage}`
1470        }
1471
1472        previousPage(){
1473            if(this.page > 0){
1474                this.page = this.page - 1;
1475            }
1476            this.addChartLegend();
1477            this.updateOptionStatus()
1478        }
1479
1480        nextPage(){
1481            if(this.page < this.totalPage - 1){
1482                this.page = this.page + 1;
1483            }
1484            this.addChartLegend();
1485            this.updateOptionStatus()
1486        }
1487
1488        updateOptionStatus(){
1489            if(this.page == 0){
1490                this.previousBt.setAttribute("disabled",'true');
1491                this.previousBt.style.color = '#999'
1492            }else{
1493                this.previousBt.style.color = '#42b983'
1494                this.previousBt.removeAttribute("disabled");
1495            }
1496            if(this.page + 1 == this.totalPage){
1497                this.nextBt.style.color = '#999'
1498                this.nextBt.setAttribute("disabled",'true');
1499            }else{
1500                this.nextBt.style.color = '#42b983'
1501                this.nextBt.removeAttribute('disabled')
1502            }
1503        }
1504
1505        createChartLegend(item){
1506            let legend = document.createElement('div');
1507            legend.style.display = 'flex';
1508            legend.style.alignItems = 'center';
1509            legend.style.marginBottom = '5px';
1510            legend.style.cursor = 'pointer';
1511            let icon = document.createElement('div');
1512            icon.style.backgroundColor = item.color;
1513            icon.style.borderRadius = '5px';
1514            icon.style.width = '10px';
1515            icon.style.height = '10px';
1516            icon.style.marginRight = '10px';
1517            let span = document.createElement('span');
1518            span.style.fontSize = '14px';
1519            span.style.width = '800px';
1520            span.style.whiteSpace = 'nowrap';
1521            span.style.textOverflow = 'ellipsis';
1522            span.style.overflow = 'hidden';
1523            span.innerText = item.name;
1524            legend.appendChild(icon);
1525            legend.appendChild(span);
1526            legend.addEventListener('mouseover',e => {
1527                this.selectItem = item;
1528                this.renderChart()
1529            });
1530            legend.addEventListener('click',e => {
1531                this.selectItem = item;
1532                this.mouseClick(e);
1533            });
1534            legend.addEventListener('mouseout',e => {
1535                this.selectItem = undefined;
1536                this.renderChart()
1537            });
1538            return legend;
1539        }
1540
1541        colorRgbWithAlpha(sColor){
1542            let reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
1543            sColor = sColor.toLowerCase();
1544            if(sColor && reg.test(sColor)){
1545                if(sColor.length === 4){
1546                    let sColorNew = "#";
1547                    for(let i=1; i<4; i+=1){
1548                        sColorNew += sColor.slice(i,i+1).concat(sColor.slice(i,i+1));
1549                    }
1550                    sColor = sColorNew;
1551                }
1552                //处理六位的颜色值
1553                let sColorChange = [];
1554                for(let i=1; i<7; i+=2){
1555                    sColorChange.push(parseInt("0x"+sColor.slice(i,i+2)));
1556                }
1557                sColorChange.push(0.6)
1558                return `rgb(${sColorChange[0]},${sColorChange[1]},${sColorChange[2]},${sColorChange[3]})`
1559            }else{
1560                return sColor;
1561            }
1562        };
1563    }
1564    if (!customElements.get('lit-pie-chart')) {
1565        customElements.define('lit-pie-chart', LitPieChart);
1566    }
1567
1568    class LitSelect extends HTMLElement {
1569        static get observedAttributes() {
1570            return [
1571                'value',//默认值
1572                'default-value',//默认值
1573                'placeholder',//placeholder
1574                'disabled',
1575                'loading',//是否处于加载状态
1576                'allow-clear',//是否允许清除
1577                'show-search',//是否允许搜索
1578                'list-height',//设置弹窗滚动高度 默认256px
1579                'border',//是否显示边框
1580                'mode',// mode='multiple'多选
1581            ];
1582        }
1583
1584        get value() {
1585            return this.getAttribute('value') || this.defaultValue;
1586        }
1587
1588        set value(value) {
1589            this.setAttribute('value', value);
1590        }
1591
1592        get border() {
1593            return this.getAttribute('border') || 'true';
1594        }
1595
1596        set border(value) {
1597            if (value) {
1598                this.setAttribute('border', 'true');
1599            } else {
1600                this.setAttribute('border', 'false');
1601            }
1602        }
1603
1604        get listHeight() {
1605            return this.getAttribute('list-height') || '256px';
1606        }
1607
1608        set listHeight(value) {
1609            this.setAttribute('list-height', value);
1610        }
1611
1612        get defaultPlaceholder() {
1613            return this.getAttribute('placeholder') || '请选择';
1614        }
1615
1616        get showSearch() {
1617            return this.hasAttribute('show-search');
1618        }
1619
1620        set defaultValue(value) {
1621            this.setAttribute('default-value', value);
1622        }
1623
1624        get defaultValue() {
1625            return this.getAttribute('default-value') || '';
1626        }
1627
1628        set placeholder(value) {
1629            this.setAttribute('placeholder', value);
1630        }
1631
1632        get placeholder() {
1633            return this.getAttribute('placeholder') || this.defaultPlaceholder;
1634        }
1635
1636        get loading() {
1637            return this.hasAttribute('loading');
1638        }
1639
1640        set loading(value) {
1641            if (value) {
1642                this.setAttribute('loading', '');
1643            } else {
1644                this.removeAttribute('loading')
1645            }
1646        }
1647
1648        constructor() {
1649            super();
1650            const shadowRoot = this.attachShadow({mode: 'open'});
1651            shadowRoot.innerHTML = `
1652        <style>
1653:host{
1654    display: inline-flex;
1655    position: relative;
1656    overflow: visible;
1657    cursor: pointer;
1658    transition: all .3s;
1659    border-radius: 2px;
1660    outline: none;
1661    -webkit-user-select:none ;
1662    -moz-user-select:none;
1663    user-select:none;
1664    /*width: 100%;*/
1665}
1666:host(:not([border])),
1667:host([border='true']){
1668    border: 1px solid #dcdcdc;
1669}
1670input{
1671    border: 0;
1672    outline: none;
1673    background-color: transparent;
1674    cursor: pointer;
1675    transition: all .3s;
1676    -webkit-user-select:none ;
1677    -moz-user-select:none;
1678    user-select:none;
1679    display: inline-flex;
1680}
1681:host(:not([mode]))  input{
1682    width: 100%;
1683}
1684:host([mode])  input{
1685    padding: 6px 0px;
1686}
1687:host([mode])  .root{
1688    padding: 1px 8px;
1689}
1690.root{
1691    position: relative;
1692    padding: 6px 8px;
1693    display: flex;
1694    align-items: center;
1695    justify-content: space-between;
1696    transition: all .3s;
1697    border-radius: 2px;
1698    background-color: #fff;
1699    outline: none;
1700    font-size: 1rem;
1701    z-index: 2;
1702    -webkit-user-select:none ;
1703    -moz-user-select:none;
1704    user-select:none;
1705    width: 100%;
1706}
1707.body{
1708    max-height: ${this.listHeight};
1709    position: absolute;
1710    top: 100%;
1711    z-index: 99;
1712    padding-top: 5px;
1713    margin-top: 2px;
1714    background-color: #fff;
1715    width: 100%;
1716    transition: all 0.2s;
1717    transform: scaleY(.6);
1718    visibility: hidden;
1719    opacity: 0;
1720    transform-origin: top center;
1721    display: block;
1722    flex-direction: column;
1723    box-shadow: 0 5px 15px 0px #00000033;
1724    border-radius: 2px;
1725    overflow: auto;
1726}
1727.icon{
1728    pointer-events: none;
1729}
1730.noSelect{
1731  -webkit-touch-callout:none; /* iOS Safari */
1732  -webkit-user-select:none;   /* Chrome/Safari/Opera */
1733  -khtml-user-select:none;    /* Konqueror */
1734  -moz-user-select:none;      /* Firefox */
1735  -ms-user-select:none;       /* Internet Explorer/Edge */
1736  user-select:none;           /* Non-prefixed version */
1737}
1738
1739:host(:not([border]):not([disabled]):focus),
1740:host([border='true']:not([disabled]):focus),
1741:host(:not([border]):not([disabled]):hover),
1742:host([border='true']:not([disabled]):hover){
1743    border:1px solid #42b983
1744}
1745:host(:not([disabled]):focus) .body,
1746:host(:not([disabled]):focus-within) .body{
1747    transform: scaleY(1);
1748    opacity: 1;
1749    z-index: 99;
1750    visibility: visible;
1751}
1752:host(:not([disabled]):focus)  input{
1753    color: #bebebe;
1754}
1755:host(:not([border])[disabled]) *,
1756:host([border='true'][disabled]) *{
1757    background-color: #f5f5f5;
1758    color: #b7b7b7;
1759    cursor: not-allowed;
1760}
1761:host([border='false'][disabled]) *{
1762    color: #b7b7b7;
1763    cursor: not-allowed;
1764}
1765:host([loading]) .loading{
1766    display: flex;
1767}
1768:host([loading]) .icon{
1769    display: none;
1770}
1771:host(:not([loading])) .loading{
1772    display: none;
1773}
1774:host(:not([loading])) .icon{
1775    display: flex;
1776}
1777:host(:not([allow-clear])) .clear{
1778    display: none;
1779}
1780.clear{
1781    display: none;
1782    color: #bfbfbf;
1783}
1784.clear:hover{
1785    color: #8c8c8c;
1786}
1787.search{
1788    display: none;
1789    color: #bfbfbf;
1790}
1791.multipleRoot{
1792    display: flex;
1793    flex-direction: column;
1794    flex-wrap: wrap;
1795    flex-flow: wrap;
1796    align-items: center;
1797    width: 100%;
1798}
1799.tag{
1800    display: inline-flex;
1801    align-items: center;
1802    background-color: #f5f5f5;
1803    padding: 1px 4px;
1804    height: auto;
1805    font-size: .75rem;
1806    font-weight: bold;
1807    color: #242424;
1808    overflow: auto;
1809    position: relative;
1810    margin-right: 4px;
1811    margin-top: 1px;
1812    margin-bottom: 1px;
1813}
1814.tag-close{
1815    font-size: .8rem;
1816    padding: 2px;
1817    margin-left: 0px;
1818    color: #999999;
1819}
1820.tag-close:hover{
1821    color: #333;
1822}
1823
1824</style>
1825<div class="root noSelect" tabindex="0" hidefocus="true">
1826    <div class="multipleRoot">
1827        <input placeholder="${this.placeholder}" style="" autocomplete="off" ${this.showSearch ? '' : 'readonly'} tabindex="0">
1828    </div><!--多选-->
1829    <lit-loading class="loading" size="12"></lit-loading>
1830    <!--<lit-icon class="icon" name='down' color="#c3c3c3"></lit-icon>-->
1831    <svg class="icon" viewBox="0 0 1024 1024" aria-hidden="true" style="width: 16px;width: 16px;fill: #c3c3c3">
1832        <path d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3 0.1-12.7-6.4-12.7z"></path>
1833    </svg>
1834<!--    <lit-icon class="clear" name='close-circle-fill'></lit-icon>-->
1835    <svg class="clear" viewBox="0 0 1024 1024" aria-hidden="true" style="width: 16px;width: 16px;">
1836        <path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64z m165.4 618.2l-66-0.3L512 563.4l-99.3 118.4-66.1 0.3c-4.4 0-8-3.5-8-8 0-1.9 0.7-3.7 1.9-5.2l130.1-155L340.5 359c-1.2-1.5-1.9-3.3-1.9-5.2 0-4.4 3.6-8 8-8l66.1 0.3L512 464.6l99.3-118.4 66-0.3c4.4 0 8 3.5 8 8 0 1.9-0.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"></path>
1837    </svg>
1838<!--    <lit-icon class="search" name='search'></lit-icon>-->
1839    <svg class="search" viewBox="0 0 1024 1024" aria-hidden="true" style="width: 16px;width: 16px;">
1840        <path d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6c3.2 3.2 8.4 3.2 11.6 0l43.6-43.5c3.2-3.2 3.2-8.4 0-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"></path>
1841    </svg>
1842</div>
1843<div class="body">
1844    <slot></slot>
1845    <slot name="footer"></slot>
1846</div>
1847        `
1848        }
1849
1850        isMultiple() {
1851            return this.hasAttribute('mode') && this.getAttribute('mode') === 'multiple'
1852        }
1853
1854        newTag(value, text) {
1855            let tag = document.createElement('div');
1856            let icon = document.createElement('lit-icon');
1857            icon.classList.add('tag-close')
1858            icon.name = 'close'
1859            let span = document.createElement('span');
1860            tag.classList.add('tag');
1861            span.dataset['value'] = value;
1862            span.textContent = text;
1863            tag.append(span);
1864            tag.append(icon);
1865            icon.onclick = ev => {
1866                tag.parentElement.removeChild(tag);
1867                this.querySelector(`lit-select-option[value=${value}]`).removeAttribute('selected')
1868                if (this.shadowRoot.querySelectorAll('.tag').length == 0) {
1869                    this.inputElement.style.width = 'auto';
1870                    this.inputElement.placeholder = this.defaultPlaceholder;
1871                }
1872                ev.stopPropagation();
1873            }
1874            tag.value = value;
1875            tag.dataset['value'] = value;
1876            tag.text = text;
1877            tag.dataset['text'] = text;
1878            return tag;
1879        }
1880
1881        //当 custom element首次被插入文档DOM时,被调用。
1882        connectedCallback() {
1883            this.tabIndex = 0;//设置当前组件为可以获取焦点
1884            this.focused = false;
1885            this.inputElement = this.shadowRoot.querySelector('input');
1886            this.inputElement.style.width = '100%'
1887            this.clearElement = this.shadowRoot.querySelector('.clear');
1888            this.iconElement = this.shadowRoot.querySelector('.icon');
1889            this.searchElement = this.shadowRoot.querySelector('.search');
1890            this.multipleRootElement = this.shadowRoot.querySelector('.multipleRoot');
1891            // console.log(this.multipleRootElement);
1892            //点击清理 清空input值,展示placeholder,
1893            this.clearElement.onclick = ev => {
1894                if (this.isMultiple()) {
1895                    let delNodes = []
1896                    this.multipleRootElement.childNodes.forEach(a => {
1897                        if (a.tagName === 'DIV') {
1898                            delNodes.push(a);
1899                        }
1900                    })
1901                    for (let i = 0; i < delNodes.length; i++) {
1902                        delNodes[i].remove();
1903                    }
1904                    if (this.shadowRoot.querySelectorAll('.tag').length == 0) {
1905                        this.inputElement.style.width = 'auto';
1906                        this.inputElement.placeholder = this.defaultPlaceholder;
1907                    }
1908                }
1909                this.querySelectorAll('lit-select-option').forEach(a => a.removeAttribute('selected'));
1910                this.inputElement.value = ''
1911                this.clearElement.style.display = 'none';
1912                this.iconElement.style.display = 'flex';
1913                this.blur();
1914                ev.stopPropagation();//这里不会因为点击清理而触发 选择栏目显示或者隐藏
1915                this.dispatchEvent(new CustomEvent('onClear', {detail: ev}))//向外派发清理事件
1916            }
1917            //初始化时遍历所有的option节点
1918            this.initOptions();
1919            //当前控件点击时 如果时select本身 需要显示 或 隐藏选择栏目,通过this.focused变量控制(默认为false)
1920            this.onclick = ev => {
1921                if (ev.target.tagName === 'LIT-SELECT') {
1922                    if (!this.focused) {
1923                        this.inputElement.focus();
1924                        this.focused = true;
1925                    } else {
1926                        this.blur();
1927                        this.focused = false;
1928                    }
1929                }
1930            }
1931            this.onmouseover = this.onfocus = ev => {
1932                // console.log('onmouseover',ev);
1933                if (this.hasAttribute('allow-clear')) {
1934                    if (this.inputElement.value.length > 0 || this.inputElement.placeholder !== this.defaultPlaceholder) {
1935                        this.clearElement.style.display = 'flex'
1936                        this.iconElement.style.display = 'none';
1937                    } else {
1938                        this.clearElement.style.display = 'none'
1939                        this.iconElement.style.display = 'flex';
1940                    }
1941                }
1942            }
1943            this.onmouseout = this.onblur = ev => {
1944                // console.log('onmouseout',ev);
1945                if (this.hasAttribute('allow-clear')) {
1946                    this.clearElement.style.display = 'none';
1947                    this.iconElement.style.display = 'flex';
1948                }
1949                this.focused = false;
1950            }
1951            //输入框获取焦点时,value值 暂存于 placeholder  然后value值清空,这样值会以placeholder形式灰色展示,鼠标位于第一个字符
1952            this.inputElement.onfocus = ev => {
1953                if (this.hasAttribute('disabled')) return;//如果控件处于disabled状态 直接忽略
1954                if (this.inputElement.value.length > 0) {
1955                    this.inputElement.placeholder = this.inputElement.value;
1956                    this.inputElement.value = ''
1957                }
1958                if (this.hasAttribute('show-search')) {//如果有show-search属性 需要显示放大镜,隐藏向下的箭头
1959                    this.searchElement.style.display = 'flex';
1960                    this.iconElement.style.display = 'none';
1961                }
1962                this.querySelectorAll('lit-select-option').forEach(a => {//input获取焦点时显示所有可选项,相当于清理了搜索结果
1963                    a.style.display = 'flex';
1964                })
1965            }
1966            //当输入框失去焦点的时候 placeholder 的值 保存到value上,input显示值
1967            this.inputElement.onblur = ev => {
1968                if (this.hasAttribute('disabled')) return;//如果控件处于disabled状态 直接忽略
1969                if (this.isMultiple()) {
1970                    if (this.hasAttribute('show-search')) {//如果有show-search属性 失去焦点需要 隐藏放大镜图标,显示默认的向下箭头图标
1971                        this.searchElement.style.display = 'none';
1972                        this.iconElement.style.display = 'flex';
1973                    }
1974                } else {
1975                    if (this.inputElement.placeholder !== this.defaultPlaceholder) {//如果placeholder为 请输入(默认值)不做处理
1976                        this.inputElement.value = this.inputElement.placeholder; //placeholder 保存的值放入 value中
1977                        this.inputElement.placeholder = this.defaultPlaceholder;//placeholder 值为 默认值(请输入)
1978                    }
1979                    if (this.hasAttribute('show-search')) {//如果有show-search属性 失去焦点需要 隐藏放大镜图标,显示默认的向下箭头图标
1980                        this.searchElement.style.display = 'none';
1981                        this.iconElement.style.display = 'flex';
1982                    }
1983                }
1984            }
1985            //输入框每次文本变化 会匹配搜索的option 显示或者隐藏,达到搜索的效果
1986            this.inputElement.oninput = ev => {
1987                // console.log(ev.target.value);
1988                let els = [...this.querySelectorAll('lit-select-option')];
1989                if (!ev.target.value) {
1990                    els.forEach(a => a.style.display = 'flex');
1991                } else {
1992                    els.forEach(a => {
1993                        let value = a.getAttribute('value');
1994                        // console.log(value.toLowerCase(), ev.target.value.toLowerCase());
1995                        if (value.toLowerCase().indexOf(ev.target.value.toLowerCase()) !== -1 ||
1996                            a.textContent.toLowerCase().indexOf(ev.target.value.toLowerCase()) !== -1) {
1997                            a.style.display = 'flex';
1998                        } else {
1999                            a.style.display = 'none';
2000                        }
2001                    })
2002                }
2003            }
2004            //输入框按下回车键,自动输入当前搜索出来的第一行,及display!='none'的第一个,搜索会隐藏其他行
2005            this.inputElement.onkeydown = ev => {
2006                if (ev.key === 'Backspace') {
2007                    if (this.isMultiple()) {
2008                        let tag = this.multipleRootElement.lastElementChild.previousElementSibling;
2009                        if (tag) {
2010                            console.log(tag.value);
2011                            this.querySelector(`lit-select-option[value=${tag.value}]`).removeAttribute('selected');
2012                            tag.remove()
2013                            if (this.shadowRoot.querySelectorAll('.tag').length == 0) {
2014                                this.inputElement.style.width = 'auto';
2015                                this.inputElement.placeholder = this.defaultPlaceholder;
2016                            }
2017                        }
2018                    } else {
2019                        this.clear();
2020                        this.dispatchEvent(new CustomEvent('onClear', {detail: ev}))//向外派发清理事件
2021                    }
2022                } else if (ev.key === 'Enter') {
2023                    let filter = [...this.querySelectorAll('lit-select-option')].filter(a => a.style.display !== 'none');
2024                    if (filter.length > 0) {
2025                        this.inputElement.value = filter[0].textContent;
2026                        this.inputElement.placeholder = filter[0].textContent;
2027                        this.blur();
2028                        this.dispatchEvent(new CustomEvent('change', {
2029                            detail: {
2030                                selected: true,
2031                                value: filter[0].getAttribute('value'),
2032                                text: filter[0].textContent
2033                            }
2034                        }));//向外层派发change事件,返回当前选中项
2035                    }
2036                }
2037            }
2038        }
2039
2040        initOptions() {
2041            this.querySelectorAll('lit-select-option').forEach(a => {
2042                //如果节点的值为 当前控件的默认值 defalut-value则 显示该值对应的option文本
2043                if (this.isMultiple()) {
2044                    a.setAttribute('check', '');
2045                    if (a.getAttribute('value') === this.defaultValue) {
2046                        let tag = this.newTag(a.getAttribute('value'), a.textContent);
2047                        this.multipleRootElement.insertBefore(tag, this.inputElement);
2048                        this.inputElement.placeholder = '';
2049                        this.inputElement.value = '';
2050                        this.inputElement.style.width = '1px';
2051                        a.setAttribute('selected', '');
2052                    }
2053                    // this.inputElement.focus();
2054                } else {
2055                    if (a.getAttribute('value') === this.defaultValue) {
2056                        this.inputElement.value = a.textContent;
2057                        a.setAttribute('selected', '');
2058                    }
2059                }
2060                //每个option设置onSelected事件 接受当前点击的option
2061                a.addEventListener('onSelected', (e) => {
2062                    // console.log(e.detail);
2063                    //所有option设置为未选中状态
2064                    if (this.isMultiple()) {//多选
2065                        if (a.hasAttribute('selected')) {
2066                            // console.log(e.detail.value);
2067                            let tag = this.shadowRoot.querySelector(`div[data-value=${e.detail.value}]`);
2068                            // console.log(tag);
2069                            tag.parentElement.removeChild(tag);
2070                            e.detail.selected = false;
2071                        } else {
2072                            let tag = this.newTag(e.detail.value, e.detail.text);
2073                            this.multipleRootElement.insertBefore(tag, this.inputElement);
2074                            this.inputElement.placeholder = '';
2075                            this.inputElement.value = '';
2076                            this.inputElement.style.width = '1px';
2077                        }
2078                        if (this.shadowRoot.querySelectorAll('.tag').length == 0) {
2079                            this.inputElement.style.width = 'auto';
2080                            this.inputElement.placeholder = this.defaultPlaceholder;
2081                        }
2082                        this.inputElement.focus();
2083                    } else {//单选
2084                        [...this.querySelectorAll('lit-select-option')].forEach(a => a.removeAttribute('selected'))
2085                        this.blur();//失去焦点,隐藏选择栏目列表
2086                        this.inputElement.value = e.detail.text;
2087                    }
2088                    //设置当前option为选择状态
2089                    if (a.hasAttribute('selected')) {
2090                        a.removeAttribute('selected')
2091                    } else {
2092                        a.setAttribute('selected', '')
2093                    }
2094                    //设置input的值为当前选择的文本
2095                    this.dispatchEvent(new CustomEvent('change', {detail: e.detail}));//向外层派发change事件,返回当前选中项
2096                })
2097            })
2098        }
2099
2100        //js调用清理选项
2101        clear() {
2102            this.inputElement.value = '';
2103            this.inputElement.placeholder = this.defaultPlaceholder;
2104        }
2105
2106        //重置为默认值
2107        reset() {
2108            this.querySelectorAll('lit-select-option').forEach(a => {
2109                //如果节点的值为 当前控件的默认值 defalut-value则 显示该值对应的option文本
2110                [...this.querySelectorAll('lit-select-option')].forEach(a => a.removeAttribute('selected'))
2111                if (a.getAttribute('value') === this.defaultValue) {
2112                    this.inputElement.value = a.textContent;
2113                    a.setAttribute('selected', '');
2114                }
2115            })
2116        }
2117
2118        //当 custom element从文档DOM中删除时,被调用。
2119        disconnectedCallback() {
2120
2121        }
2122
2123        //当 custom element被移动到新的文档时,被调用。
2124        adoptedCallback() {
2125            console.log('Custom square element moved to new page.');
2126        }
2127
2128        //当 custom element增加、删除、修改自身属性时,被调用。
2129        attributeChangedCallback(name, oldValue, newValue) {
2130            if (name === 'value' && this.inputElement) {
2131                if (newValue) {
2132                    [...this.querySelectorAll('lit-select-option')].forEach(a => {
2133                        if (a.getAttribute('value') === newValue) {
2134                            a.setAttribute('selected', '');
2135                            this.inputElement.value = a.textContent;
2136                        } else {
2137                            a.removeAttribute('selected')
2138                        }
2139                    })
2140                } else {
2141                    this.clear();
2142                }
2143            }
2144        }
2145
2146        set dataSource(value) {
2147            value.forEach(a => {
2148                let option = document.createElement('lit-select-option');
2149                option.setAttribute('value', a.key);
2150                option.textContent = a.val;
2151                this.append(option)
2152            })
2153            this.initOptions();
2154        }
2155
2156    }
2157    if (!customElements.get('lit-select')) {
2158        customElements.define('lit-select', LitSelect);
2159    }
2160
2161    class LitSelectGroup extends HTMLElement {
2162        static get observedAttributes() {
2163            return ['label']
2164        }
2165
2166        get label() {
2167            return this.getAttribute('label') || '';
2168        }
2169
2170        set label(value) {
2171            this.setAttribute('label', value);
2172        }
2173
2174        constructor() {
2175            super();
2176            const shadowRoot = this.attachShadow({mode: 'open'});
2177            shadowRoot.innerHTML = `
2178        <style>
2179        :host{
2180            display: flex;
2181            flex-direction: column;
2182            /*padding-left: 10px;*/
2183        }
2184        .lab{
2185            padding: 8px 10px 8px 10px;
2186            font-size: .5rem;
2187            color: #8c8c8c;
2188        }
2189        ::slotted(lit-select-option){
2190            padding-left: 20px;
2191        }
2192        </style>
2193        <div class="lab">${this.label}</div>
2194        <slot></slot>
2195        `
2196        }
2197
2198        //当 custom element首次被插入文档DOM时,被调用。
2199        connectedCallback() {
2200
2201        }
2202
2203        //当 custom element从文档DOM中删除时,被调用。
2204        disconnectedCallback() {
2205
2206        }
2207
2208        //当 custom element被移动到新的文档时,被调用。
2209        adoptedCallback() {
2210            console.log('Custom square element moved to new page.');
2211        }
2212
2213        //当 custom element增加、删除、修改自身属性时,被调用。
2214        attributeChangedCallback(name, oldValue, newValue) {
2215
2216        }
2217    }
2218    if (!customElements.get('lit-select-group')) {
2219        customElements.define('lit-select-group', LitSelectGroup);
2220    }
2221
2222    class LitSelectOption extends HTMLElement {
2223        static get observedAttributes() {
2224            return ['selected','disabled','check']
2225        }
2226
2227        constructor() {
2228            super();
2229            const shadowRoot = this.attachShadow({mode: 'open'});
2230            shadowRoot.innerHTML = `
2231        <style>
2232        :host{
2233            display: flex;
2234            padding: 8px 10px;
2235            transition: all .3s;
2236            color: #333;
2237            tab-index: -1;
2238            overflow: scroll;
2239            align-items: center;
2240            justify-content: space-between;
2241        }
2242        :host(:not([disabled])[selected]){
2243            background-color: #e9f7fe;
2244            font-weight: bold;
2245        }
2246        :host(:not([disabled]):not([selected]):hover){
2247            background-color: #f5f5f5;
2248        }
2249        :host([disabled]){
2250            cursor: not-allowed;
2251            color: #bfbfbf;
2252        }
2253        :host([selected][check]) .check{
2254             display: flex;
2255        }
2256        :host(:not([selected])) .check{
2257             display: none;
2258        }
2259        :host(:not([check])) .check{
2260            display: none;
2261        }
2262        </style>
2263        <slot></slot>
2264        <lit-icon class="check" name="check"></lit-icon>
2265        `
2266        }
2267
2268        //当 custom element首次被插入文档DOM时,被调用。
2269        connectedCallback() {
2270            if(!this.hasAttribute('disabled')){
2271                this.onclick=ev => {
2272                        this.dispatchEvent(new CustomEvent('onSelected', {
2273                            detail: {
2274                            selected:true,
2275                            value: this.getAttribute('value'),
2276                            text: this.textContent
2277                            }
2278                        }))
2279                }
2280            }
2281
2282        }
2283
2284        //当 custom element从文档DOM中删除时,被调用。
2285        disconnectedCallback() {
2286
2287        }
2288
2289        //当 custom element被移动到新的文档时,被调用。
2290        adoptedCallback() {
2291            console.log('Custom square element moved to new page.');
2292        }
2293
2294        //当 custom element增加、删除、修改自身属性时,被调用。
2295        attributeChangedCallback(name, oldValue, newValue) {
2296
2297        }
2298    }
2299    if (!customElements.get('lit-select-option')) {
2300        customElements.define('lit-select-option', LitSelectOption);
2301    }
2302
2303    class LitTable extends HTMLElement {
2304        static get observedAttributes() {
2305            return ['scroll-y', 'selectable','defaultOrderColumn']
2306        }
2307
2308        get selectable() {
2309            return this.hasAttribute('selectable');
2310        }
2311
2312        set selectable(value) {
2313            if (value) {
2314                this.setAttribute('selectable', '');
2315            } else {
2316                this.removeAttribute('selectable');
2317            }
2318        }
2319
2320        get scrollY() {
2321            return this.getAttribute('scroll-y') || 'auto';
2322        }
2323
2324        set scrollY(value) {
2325            this.setAttribute('scroll-y', value);
2326        }
2327
2328        get dataSource() {
2329            return this.ds || [];
2330        }
2331
2332        set dataSource(value) {
2333            this.ds = value;
2334            if (this.hasAttribute('tree')) {
2335                this.renderTreeTable();
2336            } else {
2337                this.renderTable();
2338            }
2339        }
2340
2341        constructor() {
2342            super();
2343            const shadowRoot = this.attachShadow({mode: 'open'});
2344            shadowRoot.innerHTML = `
2345<style>
2346:host{
2347    display: grid;
2348    grid-template-columns: repeat(1,1fr);
2349    overflow: auto;
2350    /*width: 500px;*/
2351    width: 100%;
2352    height: 100%;
2353}
2354.tr{
2355    display: grid;
2356    transition: all .3s;
2357}
2358.tr:nth-of-type(even){
2359    background-color: #fcfcfc;
2360}
2361/*.tr:not(:last-of-type):not(:first-of-type){*/
2362/*    border-top: 1px solid #f0f0f0;*/
2363/*}*/
2364/*.tr:last-of-type{*/
2365/*    border-top: 1px solid #f0f0f0;*/
2366/*    border-bottom: 1px solid #f0f0f0;*/
2367/*}*/
2368.tr{
2369    background-color: #fff;
2370}
2371.tr:hover{
2372    background-color: #f3f3f3; /*antd #fafafa 42b983*/
2373}
2374.td{
2375    background-color: inherit;
2376    box-sizing: border-box;
2377    padding: 10px;
2378    display: flex;
2379    justify-content: flex-start;
2380    align-items: center;
2381    width: 100%;
2382    height: auto;
2383    /*overflow: auto;*/
2384    border-left: 1px solid #f0f0f0;
2385}
2386.td-order{
2387    /*background: green;*/
2388}
2389.td-order:before{
2390
2391}
2392.td:last-of-type{
2393    border-right: 1px solid #f0f0f0;
2394}
2395.table{
2396     color: #262626;
2397}
2398:host(:not([noheader])) .thead{
2399    display: grid;
2400    position: sticky;
2401    top: 0;
2402    font-weight: bold;
2403    font-size: .9rem;
2404    color: #fff;
2405    /*width: 100%;*/
2406    background-color: #42b983;
2407    z-index: 1;
2408}
2409/*配置有 noheader 表示不限时表头,tbody上添加 border-top*/
2410:host([noheader]) .thead{
2411    display: none;
2412    position: sticky;
2413    top: 0;
2414    font-weight: bold;
2415    font-size: .9rem;
2416    color: #fff;
2417    /*width: 100%;*/
2418    background-color: #42b983;
2419    z-index: 1;
2420}
2421:host([noheader]) .tbody{
2422    border-top: 1px solid #f0f0f0;
2423}
2424
2425.tbody{
2426    width: 100%;
2427    height: ${this.scrollY};
2428    display: grid;
2429    grid-template-columns: 1fr;
2430    row-gap: 1px;
2431    column-gap: 1px;
2432    background-color: #f0f0f0;
2433    border-bottom: 1px solid #f0f0f0;
2434    /*overflow:  auto;*/
2435    ${this.scrollY === 'auto' ? '' : 'overflow-y: auto'};
2436}
2437.th{
2438    display: grid;
2439    background-color: #42b983;
2440    /*position: sticky;*/
2441    /*top: 0;*/
2442}
2443
2444.tree-icon{
2445    font-size: 1.2rem;
2446    width: 20px;
2447    height: 20px;
2448    padding-right: 5px;
2449    padding-left: 5px;
2450    cursor: pointer;
2451}
2452.tree-icon:hover{
2453    color: #42b983;
2454}
2455.row-checkbox,row-checkbox-all{
2456
2457}
2458
2459.up-svg{
2460    position: absolute;
2461    right: 5px;
2462    top: 8px;
2463    width: 15px;
2464    height: 15px;
2465}
2466.down-svg{
2467    position: absolute;
2468    right: 5px;
2469    bottom: 8px;
2470    width: 15px;
2471    height: 15px;
2472}
2473</style>
2474
2475<slot id="slot" style="display: none"></slot>
2476<div class="table">
2477    <div class="thead"></div>
2478    <div class="tbody"></div>
2479</div>
2480        `
2481
2482        }
2483
2484        /*根据column[]嵌套结构得到 grid css布局描述*/
2485
2486        //当 custom element首次被插入文档DOM时,被调用。
2487        connectedCallback() {
2488            this.st = this.shadowRoot.querySelector('#slot');
2489            this.tableElement = this.shadowRoot.querySelector('.table');
2490            this.theadElement = this.shadowRoot.querySelector('.thead');
2491            this.tbodyElement = this.shadowRoot.querySelector('.tbody');
2492            this.tableColumns = this.querySelectorAll('lit-table-column');
2493            this.colCount = this.tableColumns.length;
2494            this.st.addEventListener('slotchange', (event) => {
2495                this.theadElement.innerHTML = '';
2496                setTimeout(() => {
2497                    this.columns = this.st.assignedElements();
2498
2499                    let rowElement = document.createElement('div');
2500                    rowElement.classList.add('th');
2501                    if (this.selectable) {
2502                        let box = document.createElement('div');
2503                        box.style.display = 'flex';
2504                        box.style.justifyContent = 'center';
2505                        box.style.alignItems = 'center';
2506                        box.style.gridArea = "_checkbox_";
2507                        box.classList.add('td');
2508                        box.style.backgroundColor = "#ffffff66";
2509                        let checkbox = document.createElement('lit-checkbox');
2510                        checkbox.classList.add('row-checkbox-all');
2511                        // checkbox.style.boxShadow = '0 0 1px #fff';
2512                        // console.log(checkbox.shadowRoot.querySelector('input'));
2513                        checkbox.onchange = e => {
2514                            this.shadowRoot.querySelectorAll('.row-checkbox').forEach(a => a.checked = e.detail.checked);
2515                            if (e.detail.checked) {
2516                                this.shadowRoot.querySelectorAll('.tr').forEach(a => a.setAttribute('checked', ''));
2517                            } else {
2518                                this.shadowRoot.querySelectorAll('.tr').forEach(a => a.removeAttribute('checked'));
2519                            }
2520                        }
2521
2522                        box.appendChild(checkbox);
2523                        rowElement.appendChild(box);
2524                    }
2525
2526                    // let getGridDesc = (columns)=>{
2527                    //     columns.forEach(a=>{
2528                    //         // console.log(a);
2529                    //         if(a.tagName==='LIT-TABLE-GROUP'){
2530                    //             let children = [...a.querySelectorAll('lit-table-column')];
2531                    //             // console.log(children);
2532                    //             getGridDesc(children)
2533                    //         }else{
2534                    //             // console.log([...a.querySelectorAll('lit-table-column')]);
2535                    //         }
2536                    //     })
2537                    // }
2538                    // getGridDesc(this.columns);
2539                    let area = [], gridTemplateColumns = [];
2540                    let resolvingArea = (columns, x, y) => {
2541                        columns.forEach((a, i) => {
2542                            // console.log(a.getAttribute('key'),i);
2543                            if (!area[y]) area[y] = []
2544                            let key = a.getAttribute('key') || a.getAttribute('title')
2545                            if (a.tagName === 'LIT-TABLE-GROUP') {
2546                                let len = a.querySelectorAll('lit-table-column').length;
2547                                let children = [...a.children].filter(a => a.tagName !== 'TEMPLATE');
2548                                if (children.length > 0) {
2549                                    resolvingArea(children, x, y + 1);
2550                                }
2551                                for (let j = 0; j < len; j++) {
2552                                    area[y][x] = {x, y, t: key};
2553                                    x++;
2554                                }
2555                                let h = document.createElement('div');
2556                                h.classList.add('td');
2557                                h.style.justifyContent = a.getAttribute('align')
2558                                h.style.borderBottom = '1px solid #f0f0f0'
2559                                h.style.gridArea = key;
2560                                h.innerText = a.title;
2561                                if (a.hasAttribute('fixed')) {
2562                                    this.fixed(h, a.getAttribute('fixed'), "#42b983")
2563                                }
2564                                rowElement.append(h);
2565                            } else if (a.tagName === 'LIT-TABLE-COLUMN') {
2566                                area[y][x] = {x, y, t: key};
2567                                x++;
2568                                let h = document.createElement('div');
2569                                h.classList.add('td');
2570                                if (a.hasAttribute('order')) {
2571                                    h.sortType = 0;
2572                                    h.classList.add('td-order');
2573                                    h.style.position = "relative"
2574                                    let NS = "http://www.w3.org/2000/svg";
2575                                    let upSvg = document.createElementNS(NS,"svg");
2576                                    let upPath = document.createElementNS(NS,"path");
2577                                    upSvg.setAttribute('fill', '#efefef');
2578                                    upSvg.setAttribute('viewBox', '0 0 1024 1024');
2579                                    upSvg.setAttribute('stroke', '#000000');
2580                                    upSvg.classList.add('up-svg');
2581                                    // upPath.setAttribute("d", "M890.5 755.3L537.9 269.2c-12.8-17.6-39-17.6-51.7 0L133.5 755.3c-3.8 5.3-0.1 12.7 6.5 12.7h75c5.1 0 9.9-2.5 12.9-6.6L512 369.8l284.1 391.6c3 4.1 7.8 6.6 12.9 6.6h75c6.5 0 10.3-7.4 6.5-12.7z");
2582                                    upPath.setAttribute("d", "M858.9 689L530.5 308.2c-9.4-10.9-27.5-10.9-37 0L165.1 689c-12.2 14.2-1.2 35 18.5 35h656.8c19.7 0 30.7-20.8 18.5-35z");
2583                                    // upPath.setAttribute("fill", "#ffffff");
2584                                    // upPath.setAttribute("stroke-width", "2px");
2585                                    // upPath.setAttribute("stroke", "rgba(207, 219, 230, 1)");
2586                                    // upPath.setAttribute("marker-end", "url(#markerArrow)");
2587                                    upSvg.appendChild(upPath);
2588                                    let downSvg = document.createElementNS(NS,"svg");
2589                                    let downPath = document.createElementNS(NS,"path");
2590                                    downSvg.setAttribute('fill', '#efefef');
2591                                    downSvg.setAttribute('viewBox', '0 0 1024 1024');
2592                                    downSvg.setAttribute('stroke', '#efefef');
2593                                    downSvg.classList.add('down-svg');
2594                                    // downPath.setAttribute("d", "M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3 0.1-12.7-6.4-12.7z");
2595                                    downPath.setAttribute("d", "M840.4 300H183.6c-19.7 0-30.7 20.8-18.5 35l328.4 380.8c9.4 10.9 27.5 10.9 37 0L858.9 335c12.2-14.2 1.2-35-18.5-35z");
2596                                    // downPath.setAttribute("fill", "#ffffff");
2597                                    // downPath.setAttribute("stroke-width", "2px");
2598                                    // downPath.setAttribute("stroke", "rgba(207, 219, 230, 1)");
2599                                    // downPath.setAttribute("marker-end", "url(#markerArrow)");
2600                                    downSvg.appendChild(downPath)
2601                                    if(i == 0){
2602                                        h.sortType = 2; // 默认以第一列 降序排序 作为默认排序
2603                                        upSvg.setAttribute('fill', '#efefef');
2604                                        downSvg.setAttribute('fill', '#333');
2605                                    }
2606                                    h.appendChild(upSvg);
2607                                    h.appendChild(downSvg);
2608                                    h.onclick = ev => {
2609                                        this.shadowRoot.querySelectorAll('.td-order svg').forEach(it=>{
2610                                            it.setAttribute('fill', '#efefef');
2611                                            it.setAttribute('fill', '#efefef');
2612                                            it.sortType = 0;
2613                                        })
2614                                        if (h.sortType == undefined || h.sortType == null) {
2615                                            h.sortType = 0;
2616                                        } else if (h.sortType === 2) {
2617                                            h.sortType = 0;
2618                                        } else {
2619                                            h.sortType += 1;
2620                                        }
2621                                        // if(h.sortType == 2){
2622                                        //     h.sortType = 1
2623                                        // }else{
2624                                        //     h.sortType = 2
2625                                        // }
2626                                        switch (h.sortType){
2627                                            case 1:
2628                                                upSvg.setAttribute('fill', '#333');
2629                                                downSvg.setAttribute('fill', '#efefef');
2630                                                break;
2631                                            case 2:
2632                                                upSvg.setAttribute('fill', '#efefef');
2633                                                downSvg.setAttribute('fill', '#333');
2634                                                break;
2635                                            default:
2636                                                upSvg.setAttribute('fill', "#efefef");
2637                                                downSvg.setAttribute('fill', "#efefef");
2638                                                break;
2639                                        }
2640                                        this.dispatchEvent(new CustomEvent("ColumnClick", {
2641                                            detail: {
2642                                                sort: h.sortType, key: key
2643                                            }, composed: true
2644                                        }))
2645                                    }
2646                                }
2647                                h.style.justifyContent = a.getAttribute('align')
2648                                gridTemplateColumns.push(a.getAttribute('width') || '1fr');
2649                                h.style.gridArea = key;
2650                                let titleLabel = document.createElement("label");
2651                                titleLabel.textContent = a.title;
2652                                // h.innerText = a.title;
2653                                h.appendChild(titleLabel);
2654                                if (a.hasAttribute('fixed')) {
2655                                    this.fixed(h, a.getAttribute('fixed'), "#42b983")
2656                                }
2657                                rowElement.append(h);
2658                            }
2659
2660                            // console.log(str)
2661                            // console.log(a.title,i,a.querySelectorAll('lit-table-column').length);
2662                        })
2663                    }
2664                    resolvingArea(this.columns, 0, 0);
2665                    area.forEach((rows, j, array) => {
2666                        for (let i = 0; i < this.colCount; i++) {
2667                            if (!rows[i]) rows[i] = array[j - 1][i];
2668                        }
2669                    })
2670
2671                    // console.log(a.map(aa=>aa.t).join(' '));
2672                    // console.log(gridTemplateColumns.join(' '));
2673                    this.gridTemplateColumns = gridTemplateColumns.join(' ');
2674                    if (this.selectable) {
2675                        let s = area.map(a => '"_checkbox_ ' + (a.map(aa => aa.t).join(' ')) + '"').join(' ');
2676                        rowElement.style.gridTemplateColumns = "60px " + gridTemplateColumns.join(' ');//`repeat(${this.colCount},1fr)`
2677                        rowElement.style.gridTemplateRows = `repeat(${area.length},1fr)`
2678                        rowElement.style.gridTemplateAreas = s
2679                    } else {
2680                        let s = area.map(a => '"' + (a.map(aa => aa.t).join(' ')) + '"').join(' ');
2681                        rowElement.style.gridTemplateColumns = gridTemplateColumns.join(' ');//`repeat(${this.colCount},1fr)`
2682                        rowElement.style.gridTemplateRows = `repeat(${area.length},1fr)`
2683                        rowElement.style.gridTemplateAreas = s
2684                    }
2685                    this.theadElement.append(rowElement);
2686                    if (this.hasAttribute('tree')) {
2687                        this.renderTreeTable();
2688                    } else {
2689                        this.renderTable();
2690                    }
2691                });
2692
2693            });
2694
2695            // this.shadowRoot.addEventListener("load", function (event) {
2696            //     console.log("DOM fully loaded and parsed");
2697            // });
2698        }
2699
2700        //当 custom element从文档DOM中删除时,被调用。
2701        disconnectedCallback() {
2702
2703        }
2704
2705        //当 custom element被移动到新的文档时,被调用。
2706        adoptedCallback() {
2707            console.log('Custom square element moved to new page.');
2708        }
2709
2710        //当 custom element增加、删除、修改自身属性时,被调用。
2711        attributeChangedCallback(name, oldValue, newValue) {
2712
2713        }
2714
2715        fixed(td, placement, bgColor, zIndex) {
2716            td.style.position = 'sticky';
2717            if (placement === "left") {
2718                td.style.left = '0px';
2719                // td.style.borderRight = '1px solid #f0f0f0';
2720                td.style.boxShadow = '3px 0px 5px #33333333'
2721                // td.style.backgroundColor=bgColor
2722            } else if (placement === "right") {
2723                td.style.right = '0px';
2724                td.style.boxShadow = '-3px 0px 5px #33333333'
2725                // td.style.borderLeft = '1px solid #f0f0f0';
2726                // td.style.backgroundColor=bgColor
2727            }
2728        }
2729
2730        /*渲染成表格*/
2731        renderTable() {
2732            let that = this;
2733            if (!this.columns) return;
2734            if (!this.ds) return; // 如果没有设置数据源,直接返回
2735            this.tbodyElement.innerHTML = '';//清空表格内容
2736            // this.style.gridTemplateRows = `repeat(${this.ds.length}*2 ,1fr)`;
2737            this.ds.forEach(rowData => {
2738                let rowElement = document.createElement('div');
2739                rowElement.classList.add('tr');
2740                rowElement.data = rowData;
2741                let gridTemplateColumns = []
2742                //如果table配置了selectable(选择行模式) 单独在行头部添加一个 checkbox
2743                if (this.selectable) {
2744                    let box = document.createElement('div');
2745                    box.style.display = 'flex';
2746                    box.style.justifyContent = 'center';
2747                    box.style.alignItems = 'center';
2748                    box.classList.add('td');
2749                    let checkbox = document.createElement('lit-checkbox');
2750                    checkbox.classList.add('row-checkbox');
2751                    checkbox.onchange = (e) => {//checkbox 的是否选中 会影响  行对应的 div上是否有 checked属性,用于标记
2752                        if (e.detail.checked) {
2753                            rowElement.setAttribute('checked', "");
2754                        } else {
2755                            rowElement.removeAttribute('checked');
2756                        }
2757                    }
2758                    box.appendChild(checkbox);
2759                    rowElement.appendChild(box);
2760                }
2761                this.tableColumns.forEach(cl => {
2762                    let dataIndex = cl.getAttribute('data-index');
2763                    gridTemplateColumns.push(cl.getAttribute('width') || '1fr')
2764                    if (cl.template) {//如果自定义渲染,从模版中渲染得到节点
2765                        let cloneNode = cl.template.render(rowData).content.cloneNode(true);
2766                        // cloneNode.classList.add('td');
2767                        let d = document.createElement('div');
2768                        d.classList.add('td');
2769                        d.style.justifyContent = cl.getAttribute('align')
2770                        if (cl.hasAttribute('fixed')) {
2771                            this.fixed(d, cl.getAttribute('fixed'), "#ffffff")
2772                        }
2773                        d.append(cloneNode);
2774                        rowElement.append(d);
2775                    } else {
2776                        let td = document.createElement('div');
2777                        td.classList.add('td');
2778                        td.style.justifyContent = cl.getAttribute('align')
2779                        if (cl.hasAttribute('fixed')) {
2780                            this.fixed(td, cl.getAttribute('fixed'), "#ffffff")
2781                        }
2782                        // td.style.position='sticky';
2783                        // td.innerHTML = rowData[dataIndex];
2784                        td.innerHTML =`<code style="padding:0;margin:0">${rowData[dataIndex].toString().replace('\n',"")}</code>`;
2785                        // console.log(cl,cl.template);
2786                        rowElement.append(td);
2787                    }
2788
2789                })
2790                if (this.selectable) { //如果 带选择的table 前面添加一个 60px的列
2791                    rowElement.style.gridTemplateColumns = '60px ' + gridTemplateColumns.join(' ');//`repeat(${this.colCount},1fr)`
2792                } else {
2793                    rowElement.style.gridTemplateColumns = gridTemplateColumns.join(' ');//`repeat(${this.colCount},1fr)`
2794                }
2795                rowElement.onclick = e => {
2796                    this.dispatchEvent(new CustomEvent('onRowClick', {detail: rowData, composed: true}));
2797                }
2798                this.tbodyElement.append(rowElement);
2799            })
2800        }
2801
2802        /*渲染树表结构*/
2803        renderTreeTable() {
2804            if (!this.columns) return;
2805            if (!this.ds) return;
2806            this.tbodyElement.innerHTML = '';
2807            /*通过list 构建 tree 结构*/
2808            let ids = JSON.parse(this.getAttribute('tree') || `["id","pid"]`);
2809            let toTreeData = (data, id, pid) => {
2810                let cloneData = JSON.parse(JSON.stringify(data));
2811                return cloneData.filter(father => {
2812                    let branchArr = cloneData.filter(child => father[id] == child[pid]);
2813                    branchArr.length > 0 ? father['children'] = branchArr : '';
2814                    return !father[pid];
2815                });
2816            }
2817            let treeData = toTreeData(this.ds, ids[0], ids[1]);//
2818            // console.log(treeData);
2819            let offset = 30;
2820            let offsetVal = offset;
2821            const drawRow = (arr, parentNode) => {
2822                arr.forEach(rowData => {
2823                    let rowElement = document.createElement('div');
2824                    rowElement.classList.add('tr');
2825                    rowElement.data = rowData;
2826                    let gridTemplateColumns = [];
2827                    if (this.selectable) {
2828                        let box = document.createElement('div');
2829                        box.style.display = 'flex';
2830                        box.style.justifyContent = 'center';
2831                        box.style.alignItems = 'center';
2832                        box.classList.add('td');
2833                        let checkbox = document.createElement('lit-checkbox');
2834                        checkbox.classList.add('row-checkbox');
2835                        checkbox.onchange = (e) => {
2836                            if (e.detail.checked) {
2837                                rowElement.setAttribute('checked', "");
2838                            } else {
2839                                rowElement.removeAttribute('checked');
2840                            }
2841                            const changeChildNode = (rowElement, checked) => {
2842                                let id = rowElement.getAttribute('id');
2843                                let pid = rowElement.getAttribute('pid');
2844                                this.shadowRoot.querySelectorAll(`div[pid=${id}]`).forEach(a => {
2845                                    a.querySelector('.row-checkbox').checked = checked;
2846                                    if (checked) {
2847                                        a.setAttribute('checked', '');
2848                                    } else {
2849                                        a.removeAttribute('checked');
2850                                    }
2851                                    changeChildNode(a, checked);
2852                                });
2853                            };
2854                            changeChildNode(rowElement, e.detail.checked);
2855                        }
2856                        box.appendChild(checkbox);
2857                        rowElement.appendChild(box);
2858                    }
2859                    this.tableColumns.forEach((cl, index) => {
2860                        let dataIndex = cl.getAttribute('data-index');
2861                        gridTemplateColumns.push(cl.getAttribute('width') || '1fr')
2862                        let td;
2863                        if (cl.template) {
2864                            let cloneNode = cl.template.render(rowData).content.cloneNode(true);
2865                            // cloneNode.classList.add('td');
2866                            td = document.createElement('div');
2867                            td.classList.add('td');
2868                            td.style.justifyContent = cl.getAttribute('align')
2869                            if (cl.hasAttribute('fixed')) {
2870                                this.fixed(td, cl.getAttribute('fixed'), "#ffffff")
2871                            }
2872                            td.append(cloneNode);
2873                        } else {
2874                            td = document.createElement('div');
2875                            td.classList.add('td');
2876                            td.style.justifyContent = cl.getAttribute('align')
2877                            if (cl.hasAttribute('fixed')) {
2878                                this.fixed(td, cl.getAttribute('fixed'), "#ffffff")
2879                            }
2880                            // td.style.position='sticky';
2881                            td.innerHTML = rowData[dataIndex];
2882                            // console.log(cl,cl.template);
2883                        }
2884                        if (index === 0) {
2885                            if (rowData.children && rowData.children.length > 0) {
2886                                let btn = document.createElement('lit-icon');
2887                                btn.classList.add('tree-icon');
2888                                btn.name = 'minus-square';
2889                                td.insertBefore(btn, td.firstChild);
2890                                td.style.paddingLeft = (offsetVal - 30) + 'px';
2891                                btn.onclick = (e) => {
2892                                    const foldNode = (rowElement) => {
2893                                        let id = rowElement.getAttribute('id');
2894                                        let pid = rowElement.getAttribute('pid');
2895                                        this.shadowRoot.querySelectorAll(`div[pid=${id}]`).forEach(a => {
2896                                            let id = a.getAttribute('id');
2897                                            let pid = a.getAttribute('pid');
2898                                            a.style.display = 'none';
2899                                            foldNode(a);
2900                                        });
2901                                        if (rowElement.querySelector('.tree-icon')) {
2902                                            rowElement.querySelector('.tree-icon').name = 'plus-square';
2903                                        }
2904                                        rowElement.removeAttribute('expand');
2905                                    };
2906                                    const expendNode = (rowElement) => {
2907                                        let id = rowElement.getAttribute('id');
2908                                        let pid = rowElement.getAttribute('pid');
2909                                        this.shadowRoot.querySelectorAll(`div[pid=${id}]`).forEach(a => {
2910                                            let id = a.getAttribute('id');
2911                                            let pid = a.getAttribute('pid');
2912                                            a.style.display = '';
2913                                            // expendNode(a);
2914                                        });
2915                                        if (rowElement.querySelector('.tree-icon')) {
2916                                            rowElement.querySelector('.tree-icon').name = 'minus-square';
2917                                        }
2918                                        rowElement.setAttribute('expand', '');
2919                                    }
2920                                    if (rowElement.hasAttribute('expand')) {
2921                                        foldNode(rowElement);
2922                                    } else {
2923                                        expendNode(rowElement);
2924                                    }
2925                                };
2926                            } else {
2927                                td.style.paddingLeft = offsetVal + 'px';
2928                            }
2929                        }
2930                        rowElement.append(td);
2931
2932                    })
2933                    if (this.selectable) {
2934                        rowElement.style.gridTemplateColumns = '60px ' + gridTemplateColumns.join(' ');//`repeat(${this.colCount},1fr)`
2935                    } else {
2936                        rowElement.style.gridTemplateColumns = gridTemplateColumns.join(' ');//`repeat(${this.colCount},1fr)`
2937                    }
2938                    rowElement.onclick = e => {
2939                        // console.log(rowElement.style.gridTemplateColumns);
2940                        // LitMessage.info(JSON.stringify(rowData));
2941                    }
2942                    parentNode.append(rowElement);
2943                    rowElement.setAttribute('id', rowData[ids[0]]);
2944                    rowElement.setAttribute('pid', rowData[ids[1]]);
2945                    rowElement.setAttribute('expand', '');
2946                    if (rowData.children && rowData.children.length > 0) {
2947                        //有子节点的 前面加上 + 图标 表示可以展开节点
2948
2949                        offsetVal = offsetVal + offset;
2950                        drawRow(rowData.children, parentNode);
2951                        offsetVal = offsetVal - offset;
2952                    }
2953                });
2954            };
2955            drawRow(treeData, this.tbodyElement);
2956        }
2957
2958        //获取选中的行数据
2959        getCheckRows() {
2960            return [...this.shadowRoot.querySelectorAll('div[class=tr][checked]')].map(a => a.data).map(a => {
2961                delete a['children'];
2962                return a;
2963            });
2964        }
2965
2966        deleteRowsCondition(fn) {
2967            this.shadowRoot.querySelectorAll("div[class=tr]").forEach(tr => {
2968                if (fn(tr.data)) {
2969                    tr.remove();
2970                }
2971            })
2972        }
2973    }
2974    if (!customElements.get('lit-table')) {
2975        customElements.define('lit-table', LitTable);
2976    }
2977
2978    class LitTableColumn extends HTMLElement {
2979        static get observedAttributes() {
2980            return ['name','order']
2981        }
2982
2983        constructor() {
2984            super();
2985            const shadowRoot = this.attachShadow({mode: 'open'});
2986            shadowRoot.innerHTML = `
2987<style>
2988:host{ }
2989</style>
2990<slot id="slot"></slot>
2991        `
2992        }
2993        //当 custom element首次被插入文档DOM时,被调用。
2994        connectedCallback() {
2995            this.template=null;
2996            this.st = this.shadowRoot.querySelector('#slot')
2997            this.st.addEventListener('slotchange', () => {
2998                const elements = this.st.assignedElements({flatten: false});
2999                if(elements.length>0){
3000                    this.template = elements[0];
3001                }
3002            })
3003        }
3004
3005        //当 custom element从文档DOM中删除时,被调用。
3006        disconnectedCallback() {
3007
3008        }
3009
3010        //当 custom element被移动到新的文档时,被调用。
3011        adoptedCallback() {
3012            console.log('Custom square element moved to new page.');
3013        }
3014
3015        //当 custom element增加、删除、修改自身属性时,被调用。
3016        attributeChangedCallback(name, oldValue, newValue) {
3017
3018        }
3019    }
3020    if (!customElements.get('lit-table-column')) {
3021        customElements.define('lit-table-column', LitTableColumn);
3022    }
3023
3024    class LitTableGroup extends HTMLElement {
3025        static get observedAttributes() {
3026            return ['title']
3027        }
3028
3029        get title() {
3030            return this.getAttribute('title');
3031        }
3032
3033        set title(value) {
3034            this.setAttribute('title', value);
3035        }
3036
3037        constructor() {
3038            super();
3039            const shadowRoot = this.attachShadow({mode: 'open'});
3040            shadowRoot.innerHTML = `
3041        <style>
3042        :host{ }
3043        </style>
3044        <slot id="sl"></slot>
3045        `
3046        }
3047
3048        //当 custom element首次被插入文档DOM时,被调用。
3049        connectedCallback() {
3050
3051        }
3052
3053        //当 custom element从文档DOM中删除时,被调用。
3054        disconnectedCallback() {
3055
3056        }
3057
3058        //当 custom element被移动到新的文档时,被调用。
3059        adoptedCallback() {
3060            console.log('Custom square element moved to new page.');
3061        }
3062
3063        //当 custom element增加、删除、修改自身属性时,被调用。
3064        attributeChangedCallback(name, oldValue, newValue) {
3065
3066        }
3067    }
3068    if (!customElements.get('lit-table-group')) {
3069        customElements.define('lit-table-group', LitTableGroup);
3070    }
3071
3072    class LitTabpane extends HTMLElement {
3073        static get observedAttributes() {return ['tab','key','disabled','icon','closeable','hide'];}
3074        constructor() {
3075            super();
3076            const shadowRoot = this.attachShadow({mode: 'open'});
3077            shadowRoot.innerHTML = `
3078<style>
3079:host(){
3080    scroll-behavior: smooth;
3081    -webkit-overflow-scrolling: touch;
3082    overflow: auto;
3083    width: 100%;
3084}
3085</style>
3086<slot></slot>
3087`
3088        }
3089
3090        get tab(){
3091            return this.getAttribute('tab');
3092        }
3093
3094        set tab(value) {
3095            this.setAttribute("tab", value);
3096        }
3097
3098        get icon() {
3099            return this.getAttribute("icon");
3100        }
3101
3102        get disabled(){
3103            return this.getAttribute('disabled')!==null;
3104        }
3105
3106        set disabled(value) {
3107            if(value===null||value===false){
3108                this.removeAttribute("disabled");
3109            }else{
3110                this.setAttribute("disabled",value);
3111            }
3112        }
3113        get closeable(){
3114            return this.getAttribute('closeable')!==null;
3115        }
3116        set closeable(value){
3117            if(value===null||value===false){
3118                this.removeAttribute("closeable");
3119            }else{
3120                this.setAttribute("closeable",value);
3121            }
3122        }
3123
3124        get key(){
3125            return this.getAttribute("key");
3126        }
3127        set key(value) {
3128            this.setAttribute("key", value);
3129        }
3130
3131        get hide(){
3132            return this.getAttribute('hide')!==null;
3133        }
3134        set hide(value){
3135            if(value===null||value===false){
3136                this.removeAttribute("hide");
3137            }else{
3138                this.setAttribute("hide",value);
3139            }
3140        }
3141
3142        //当 custom element首次被插入文档DOM时,被调用。
3143        connectedCallback() {}
3144
3145        //当 custom element从文档DOM中删除时,被调用。
3146        disconnectedCallback() {}
3147
3148        //当 custom element被移动到新的文档时,被调用。
3149        adoptedCallback() {}
3150
3151        //当 custom element增加、删除、修改自身属性时,被调用。
3152        attributeChangedCallback(name, oldValue, newValue) {
3153            if(oldValue!==newValue && newValue!==undefined){
3154                if(name==='tab'&&this.parentNode){
3155                    this.parentNode.updateLabel && this.parentNode.updateLabel(this.key,newValue);
3156                }
3157                if(name==='disabled'&&this.parentNode){
3158                    this.parentNode.updateDisabled && this.parentNode.updateDisabled(this.key,newValue);
3159                }
3160                if(name==='closeable'&&this.parentNode){
3161                    this.parentNode.updateCloseable && this.parentNode.updateCloseable(this.key, newValue);
3162                }
3163                if(name==='hide'&&this.parentNode){
3164                    this.parentNode.updateCloseable && this.parentNode.updateHide(this.key, newValue);
3165                }
3166            }
3167        }
3168    }
3169    if (!customElements.get('lit-tabpane')) {
3170        customElements.define('lit-tabpane', LitTabpane);
3171    }
3172
3173    class LitTabs extends HTMLElement {
3174        static get observedAttributes() {
3175            //mode = flat(default) | card
3176            //position = top | top-left | top-center | top-right | left | left-top | left-center | left-bottom | right | bottom
3177            return ['activekey', 'mode', 'position']
3178        }
3179
3180        constructor() {
3181            super();
3182            const shadowRoot = this.attachShadow({mode: 'open'});
3183            shadowRoot.innerHTML = `
3184        <style>
3185        :host{
3186            display: block;
3187            text-align: unset;
3188            color: #252525;
3189            background-color: #fff;
3190            box-shadow: #00000033 0 0 10px ;
3191            /*padding: 10px;*/
3192            /*margin-right: 10px;*/
3193        }
3194        ::slotted(lit-tabpane){
3195            box-sizing:border-box;
3196            width:100%;
3197            height:100%;
3198            /*padding:10px;*/
3199            flex-shrink:0;
3200            overflow:auto;
3201        }
3202        .nav-item{
3203            display: inline-flex;
3204            justify-content: center;
3205            align-items: center;
3206            padding: 6px 0px 6px 12px;
3207            font-size: .9rem;
3208            font-weight: normal;
3209            cursor: pointer;
3210            transition: all 0.3s;
3211            flex-shrink: 0;
3212        }
3213        .nav-item lit-icon{
3214            margin-right: 2px;
3215            font-size: inherit;
3216        }
3217        .nav-item:hover{
3218            color: #42b983;
3219        }
3220        .nav-item[data-disabled]{
3221            pointer-events: all;
3222            cursor: not-allowed;
3223            color: #bfbfbf;
3224        }
3225        .nav-item[data-selected]{
3226            color: #42b983;;
3227        }
3228        .tab-content{
3229            display: block;
3230            background-color: #fff;
3231            flex:1;
3232        }
3233
3234        /*
3235         *   top  top-left top-center top-right
3236         */
3237        :host(:not([position])) .nav-root,
3238        :host([position^='top']) .nav-root{
3239            display: flex;
3240            position: relative;
3241            justify-content: center;
3242            align-items: center;
3243        }
3244        :host(:not([mode]):not([position])) .tab-line,/*移动的线条*/
3245        :host([mode='flat'][position^='top']) .tab-line{
3246            position:absolute;
3247            bottom: 2px;
3248            background-color: #42b983;
3249            height: 2px;
3250            transform: translateY(100%);
3251            transition: all 0.3s;
3252        }
3253
3254        :host(:not([position])) .tab-nav-container,
3255        :host([position^='top']) .tab-nav-container{
3256            display: flex;
3257            position: relative;
3258            flex-direction: column;
3259            overflow-y: hidden;
3260            overflow-x: auto;
3261            overflow: -moz-scrollbars-none;
3262            -ms-overflow-style: none;
3263            transition: all 0.3s;
3264            flex: 1;
3265            /*background: linear-gradient(90deg,white 30%, transparent),radial-gradient(at 0 50%, rgba(0,0,0,.2),transparent 70%);*/
3266            /*background-repeat: no-repeat;*/
3267            /*background-size: 50px 100%, 15px 100%;*/
3268            /*background-attachment: local,scroll,local,scroll;*/
3269            /*border-bottom: #f0f0f0 1px solid;*/
3270        }
3271        :host([position='top']) .tab-nav,
3272        :host([position='top-left']) .tab-nav{
3273            display: flex;
3274            position: relative;
3275            justify-content: flex-start;
3276        }
3277        :host([position='top-center']) .tab-nav{
3278            display: flex;
3279            justify-content: center;
3280        }
3281        :host([position='top-right']) .tab-nav{
3282            display: flex;
3283            justify-content: flex-end;
3284        }
3285
3286        :host([position^='top'][mode='card']) .nav-item{
3287            border-top: 1px solid #f0f0f0;
3288            border-left: 1px solid #f0f0f0;
3289            border-right: 1px solid #f0f0f0;
3290            border-bottom: 1px solid #f0f0f0;
3291            bottom: 0px;
3292            margin-right: 2px;
3293            position: relative;
3294        }
3295        :host([position^='top']) .tab-nav-bg-line{
3296            position: absolute;bottom: 0;height: 1px;background-color: #f0f0f0;width: 100%
3297        }
3298        :host([position^='top'][mode='card']) .nav-item:not([data-selected]){
3299            background-color: #f6f6f6;
3300            border-bottom: 1px solid #f0f0f0;
3301        }
3302        :host([position^='top'][mode='card']) .nav-item[data-selected]{
3303            background-color: #ffffff;
3304            border-bottom: 1px solid #fff;
3305            bottom: 0px;
3306        }
3307        /*
3308            bottom bottom-left bottom-center bottom-right
3309        */
3310        :host([position^='bottom']) .tab{
3311            display: flex;
3312            flex-direction: column-reverse;
3313        }
3314        :host([mode='flat'][position^='bottom']) .tab-line{
3315            position:absolute;
3316            top: -3px;
3317            background-color: #42b983;
3318            height: 2px;
3319            transform: translateY(-100%);
3320            transition: all 0.3s;
3321        }
3322        :host([position^='bottom']) .tab-nav-container{
3323            display: flex;
3324            position: relative;
3325            flex-direction: column;
3326            overflow-x: auto;
3327            overflow-y: visible;
3328            overflow: -moz-scrollbars-none;
3329            -ms-overflow-style: none;
3330            transition: all 0.3s;
3331            flex: 1;
3332            /*background: linear-gradient(90deg,white 30%, transparent),radial-gradient(at 0 50%, rgba(0,0,0,.2),transparent 70%);*/
3333            /*background-repeat: no-repeat;*/
3334            /*background-size: 50px 100%, 15px 100%;*/
3335            /*background-attachment: local,scroll,local,scroll;*/
3336            border-top: #f0f0f0 1px solid;
3337        }
3338        :host([position^='bottom']) .nav-root{
3339            display: flex;
3340            justify-content: center;
3341            align-items: center;
3342        }
3343        :host([position='bottom']) .tab-nav,
3344        :host([position='bottom-left']) .tab-nav{
3345            display: flex;
3346            position: relative;
3347            justify-content: flex-start;
3348        }
3349        :host([position='bottom-center']) .tab-nav{
3350            display: flex;
3351            justify-content: center;
3352        }
3353        :host([position='bottom-right']) .tab-nav{
3354            display: flex;
3355            justify-content: flex-end;
3356        }
3357        :host([position^='bottom'][mode='card']) .nav-item{
3358            border-top: 1px solid #ffffff;
3359            border-left: 1px solid #f0f0f0;
3360            border-right: 1px solid #f0f0f0;
3361            border-bottom: 1px solid #f0f0f0;
3362            top: -1px;
3363            margin-right: 2px;
3364            position: relative;
3365        }
3366        :host([position^='bottom']) .tab-nav-bg-line{
3367            position: absolute;top: 0;height: 1px;background-color: #f0f0f0;width: 100%
3368        }
3369        :host([position^='bottom'][mode='card']) .nav-item:not([data-selected]){
3370            background-color: #f5f5f5;
3371            border-top: 1px solid #f0f0f0;
3372        }
3373        :host([position^='bottom'][mode='card']) .nav-item[data-selected]{
3374            background-color: #ffffff;
3375            border-top: 1px solid #fff;
3376            top: -1px;
3377        }
3378        /*
3379        left left-top left-center left-bottom
3380        */
3381        :host([position^='left']) .tab{
3382            display: flex;
3383            flex-direction: row;
3384        }
3385        :host([mode='flat'][position^='left']) .tab-line{
3386            position:absolute;
3387            right: 1px;
3388            background-color: #42b983;
3389            width: 3px;
3390            transform: translateX(100%);
3391            transition: all 0.3s;
3392        }
3393        :host([position^='left']) .tab-nav-container{
3394            display: flex;
3395            position: relative;
3396            flex-direction: row;
3397            overflow-x: auto;
3398            overflow-y: visible;
3399            overflow: -moz-scrollbars-none;
3400            -ms-overflow-style: none;
3401            transition: all 0.3s;
3402            flex: 1;
3403            /*background: linear-gradient(90deg,white 30%, transparent),radial-gradient(at 0 50%, rgba(0,0,0,.2),transparent 70%);*/
3404            /*background-repeat: no-repeat;*/
3405            /*background-size: 50px 100%, 15px 100%;*/
3406            /*background-attachment: local,scroll,local,scroll;*/
3407            border-right: #f0f0f0 1px solid;
3408        }
3409        :host([position^='left']) .nav-root{
3410            display: flex;
3411            flex-direction: column;
3412            justify-content: center;
3413            align-items: center;
3414        }
3415        :host([position='left']) .tab-nav,
3416        :host([position='left-top']) .tab-nav{
3417            display: flex;
3418            position: relative;
3419            flex-direction: column;
3420            justify-content: flex-start;
3421        }
3422        :host([position='left-center']) .tab-nav{
3423            display: flex;
3424            position: relative;
3425            flex-direction: column;
3426            justify-content: center;
3427        }
3428        :host([position='left-bottom']) .tab-nav{
3429            display: flex;
3430            position: relative;
3431            flex-direction: column;
3432            justify-content: flex-end;
3433        }
3434        :host([position^='left'][mode='card']) .nav-item{
3435            border-top: 1px solid #f0f0f0;
3436            border-left: 1px solid #f0f0f0;
3437            border-right: 1px solid #ffffff;
3438            border-bottom: 1px solid #f0f0f0;
3439            right: -1px;
3440            margin-bottom: 2px;
3441            position: relative;
3442        }
3443        :host([position^='left']) .tab-nav-bg-line{
3444            position: absolute;right: 0;width: 1px;background-color: #f0f0f0;width: 100%
3445        }
3446        :host([position^='left'][mode='card']) .nav-item:not([data-selected]){
3447            background-color: #f5f5f5;
3448            border-right: 1px solid #f0f0f0;
3449        }
3450        :host([position^='left'][mode='card']) .nav-item[data-selected]{
3451            background-color: #ffffff;
3452            border-bottom: 1px solid #fff;
3453            right: -1px;
3454        }
3455        /*
3456        right right-top right-center right-bottom
3457        */
3458        :host([position^='right']) .tab{
3459            display: flex;
3460            flex-direction: row-reverse;
3461        }
3462        :host([mode='flat'][position^='right']) .tab-line{
3463            position:absolute;
3464            left: 1px;
3465            background-color: #42b983;
3466            width: 3px;
3467            transform: translateX(-100%);
3468            transition: all 0.3s;
3469        }
3470        :host([position^='right']) .tab-nav-container{
3471            display: flex;
3472            position: relative;
3473            flex-direction: row-reverse;
3474            overflow-x: auto;
3475            overflow-y: visible;
3476            overflow: -moz-scrollbars-none;
3477            -ms-overflow-style: none;
3478            transition: all 0.3s;
3479            flex: 1;
3480            /*background: linear-gradient(90deg,white 30%, transparent),radial-gradient(at 0 50%, rgba(0,0,0,.2),transparent 70%);*/
3481            /*background-repeat: no-repeat;*/
3482            /*background-size: 50px 100%, 15px 100%;*/
3483            /*background-attachment: local,scroll,local,scroll;*/
3484            border-left: #f0f0f0 1px solid;
3485        }
3486        :host([position^='right']) .nav-root{
3487            display: flex;
3488            flex-direction: column;
3489            justify-content: center;
3490            align-items: center;
3491        }
3492        :host([position='right']) .tab-nav,
3493        :host([position='right-top']) .tab-nav{
3494            display: flex;
3495            position: relative;
3496            flex-direction: column;
3497            justify-content: flex-start;
3498        }
3499        :host([position='right-center']) .tab-nav{
3500            display: flex;
3501            position: relative;
3502            flex-direction: column;
3503            justify-content: center;
3504        }
3505        :host([position='right-bottom']) .tab-nav{
3506            display: flex;
3507            position: relative;
3508            flex-direction: column;
3509            justify-content: flex-end;
3510        }
3511        :host([position^='right'][mode='card']) .nav-item{
3512            border-top: 1px solid #f0f0f0;
3513            border-left: 1px solid #ffffff;
3514            border-right: 1px solid #f0f0f0;
3515            border-bottom: 1px solid #f0f0f0;
3516            left: -1px;
3517            margin-top: 2px;
3518            position: relative;
3519        }
3520        :host([position^='right']) .tab-nav-bg-line{
3521            position: absolute;left: 0;width: 1px;background-color: #f0f0f0;width: 100%
3522        }
3523        :host([position^='right'][mode='card']) .nav-item:not([data-selected]){
3524            background-color: #f5f5f5;
3525            border-left: 1px solid #f0f0f0;
3526        }
3527        :host([position^='right'][mode='card']) .nav-item[data-selected]{
3528            background-color: #ffffff;
3529            left: -1px;
3530        }
3531
3532
3533        .tab-nav-container::-webkit-scrollbar {
3534            display: none;
3535        }
3536
3537
3538        /*关闭的图标*/
3539        .close-icon:hover{
3540            color: #000;
3541        }
3542        .nav-item[data-closeable] .close-icon{
3543            display: block;
3544            padding: 5px 5px 5px 5px;
3545            color: #999;
3546        }
3547        .nav-item[data-closeable] .no-close-icon{
3548            display: none;
3549        }
3550        .nav-item:not([data-closeable]) .no-close-icon{
3551            display: block;
3552        }
3553        .nav-item:not([data-closeable]) .close-icon{
3554            display: none;
3555        }
3556        .nav-item:not([data-hide]){
3557            display: block;
3558        }
3559        .nav-item[data-hide]{
3560            display: none;
3561        }
3562
3563        </style>
3564        <style id="filter"></style>
3565        <div class="tab">
3566            <div class="nav-root">
3567                <slot name="left" style="flex:1"></slot>
3568                <div class="tab-nav-container" >
3569                    <div class="tab-nav-bg-line"></div>
3570                    <div class="tab-nav" id="nav"></div>
3571                    <div class="tab-line" id="tab-line"></div>
3572                </div>
3573                <slot name="right" style="flex:1"></slot>
3574            </div>
3575            <div class="tab-content">
3576                <slot id="slot">NEED CONTENT</slot>
3577            </div>
3578        </div>
3579        `
3580        }
3581
3582        get position() {
3583            return this.getAttribute('position') || 'top';
3584        }
3585
3586        set position(value) {
3587            this.setAttribute('position', value);
3588        }
3589
3590        get mode() {
3591            return this.getAttribute('mode') || 'flat';
3592        }
3593
3594        set mode(value) {
3595            this.setAttribute('mode', value);
3596        }
3597
3598        get activekey() {
3599            return this.getAttribute("activekey");
3600        }
3601
3602        set activekey(value) {
3603            this.setAttribute('activekey', value);
3604        }
3605
3606        updateLabel(key, value) {
3607            // console.log(key, value);
3608            if(this.nav){
3609                let item = this.nav.querySelector(`.nav-item[data-key='${key}']`);
3610                if(item){
3611                    item.querySelector("span").innerHTML=value;
3612                    this.initTabPos()
3613                }
3614            }
3615        }
3616
3617        updateDisabled(key, value) {
3618            // console.log(key, value);
3619            if(this.nav){
3620                let item = this.nav.querySelector(`.nav-item[data-key='${key}']`);
3621                if(item){
3622                    if(value){
3623                        item.setAttribute('data-disabled','')
3624                    }else{
3625                        item.removeAttribute('data-disabled');
3626                    }
3627                    this.initTabPos()
3628                }
3629            }
3630        }
3631        updateCloseable(key,value){
3632            if(this.nav){
3633                let item = this.nav.querySelector(`.nav-item[data-key='${key}']`);
3634                if(item){
3635                    if(value){
3636                        item.setAttribute('data-closeable','')
3637                    }else{
3638                        item.removeAttribute('data-closeable');
3639                    }
3640                    this.initTabPos()
3641                }
3642            }
3643        }
3644        updateHide(key,value){
3645            if(this.nav){
3646                let item = this.nav.querySelector(`.nav-item[data-key='${key}']`);
3647                if(item){
3648                    if(value){
3649                        item.setAttribute('data-hide','')
3650                    }else{
3651                        item.removeAttribute('data-hide');
3652                    }
3653                    this.initTabPos()
3654                }
3655            }
3656        }
3657
3658        initTabPos() {
3659            const items = this.nav.querySelectorAll(".nav-item");
3660            Array.from(items).forEach((a, index) => {
3661                this.tabPos[a.dataset.key] = {
3662                    index: index,
3663                    width: a.offsetWidth,
3664                    height: a.offsetHeight,
3665                    left: a.offsetLeft,
3666                    top: a.offsetTop,
3667                    label: a.textContent
3668                }
3669            })
3670            if (this.activekey) {
3671                if (this.position.startsWith('left')) {
3672                    this.line.style = `height:${this.tabPos[this.activekey].height}px;transform:translate(100%,${this.tabPos[this.activekey].top}px)`;
3673                } else if (this.position.startsWith('top')) {
3674                    if (this.tabPos[this.activekey]) {
3675                        this.line.style = `width:${this.tabPos[this.activekey].width}px;transform:translate(${this.tabPos[this.activekey].left}px,100%)`;
3676                    }
3677                } else if (this.position.startsWith('right')) {
3678                    this.line.style = `height:${this.tabPos[this.activekey].height}px;transform:translate(-100%,${this.tabPos[this.activekey].top}px)`;
3679                } else if (this.position.startsWith('bottom')) {
3680                    this.line.style = `width:${this.tabPos[this.activekey].width}px;transform:translate(${this.tabPos[this.activekey].left}px,100%)`;
3681                }
3682            }
3683        }
3684
3685        //当 custom element首次被插入文档DOM时,被调用。
3686        connectedCallback() {
3687            let that = this;
3688            this.tabPos = {}
3689            this.nav = this.shadowRoot.querySelector('#nav')
3690            this.line = this.shadowRoot.querySelector('#tab-line')
3691            this.slots = this.shadowRoot.querySelector('#slot');
3692            this.slots.addEventListener('slotchange', () => {
3693                const elements = this.slots.assignedElements();
3694                let panes = this.querySelectorAll('lit-tabpane');
3695                if (this.activekey) {
3696                    panes.forEach(a => {
3697                        if (a.key === this.activekey) {
3698                            a.style.display = 'block'
3699                        } else {
3700                            a.style.display = 'none';
3701                        }
3702                    })
3703                } else {
3704                    panes.forEach((a, index) => {
3705                        if (index === 0) {
3706                            a.style.display = 'block'
3707                            this.activekey = a.key
3708                        } else {
3709                            a.style.display = 'none';
3710                        }
3711                    })
3712                }
3713
3714                let navHtml = "";
3715                elements.forEach(a => {
3716                    if (a.disabled) {
3717                        navHtml += `<div class="nav-item" data-key="${a.key}" data-disabled ${a.closeable?'data-closeable':''} ${a.hide?'data-hide':''}>
3718                    ${a.icon ? `<lit-icon name='${a.icon}'></lit-icon>` : ``}
3719                    <span>${a.tab}</span>
3720                    <lit-icon class="close-icon" name='close' size="12"></lit-icon><div class="no-close-icon" style="margin-right: 12px"></div>
3721                    </div>`;
3722                    } else {
3723                        if (a.key === this.activekey) {
3724                            navHtml += `<div class="nav-item" data-key="${a.key}" data-selected ${a.closeable?'data-closeable':''} ${a.hide?'data-hide':''}>
3725                        ${a.icon ? `<lit-icon name='${a.icon}'></lit-icon>` : ``}
3726                        <span>${a.tab}</span>
3727                        <lit-icon class="close-icon" name='close' size="12"></lit-icon><div class="no-close-icon" style="margin-right: 12px"></div>
3728                        </div>`;
3729                        } else {
3730                            navHtml += `<div class="nav-item" data-key="${a.key}" ${a.closeable?'data-closeable':''} ${a.hide?'data-hide':''}>
3731                            ${a.icon ? `<lit-icon name='${a.icon}'></lit-icon>` : ``}
3732                            <span>${a.tab}</span>
3733                            <lit-icon class="close-icon" name='close' size="12"></lit-icon><div class="no-close-icon" style="margin-right: 12px"></div>
3734                            </div>`;
3735                        }
3736
3737                    }
3738                })
3739                this.nav.innerHTML = navHtml;
3740                this.initTabPos()
3741                this.nav.querySelectorAll('.close-icon').forEach(a => {
3742                    a.onclick = (e) => {
3743                        e.stopPropagation();
3744                        const closeKey = e.target.parentElement.dataset.key;
3745                        console.log(closeKey);
3746                        console.log(e.target.parentElement.parentElement);
3747                        this.nav.removeChild(e.target.parentElement)
3748                        let elements = this.slots.assignedElements();
3749                        let closeElement = elements.filter(a => a.key === closeKey)[0];
3750                        closeElement.parentElement.removeChild(closeElement)
3751                        if (closeElement.style.display !== 'none') {
3752                            elements = this.slots.assignedElements();
3753                            let elArr = elements.filter(a => !a.hasAttribute('disabled'));
3754                            if (elArr.length > 0) {
3755                                elArr[0].style.display = 'block';
3756                                this.activekey = elArr[0].key
3757                            }
3758                        }
3759                    }
3760                });
3761            })
3762            this.nav.onclick = (e) => {
3763                if (e.target.closest('div').hasAttribute('data-disabled')) return;
3764                let key = e.target.closest('div').dataset.key;
3765                this.activeByKey(key)
3766                let label = e.target.closest('div').querySelector('span').textContent;
3767                this.dispatchEvent(new CustomEvent('onTabClick',{detail:{key:key,tab:label}}))
3768            };
3769        }
3770        set onTabClick(fn){
3771            this.addEventListener('onTabClick', fn);
3772        }
3773        activeByKey(key){
3774            if (key === null || key === undefined) return; //如果没有key 不做相应
3775            this.nav.querySelectorAll('.nav-item').forEach(a => {
3776                if (a.getAttribute('data-key') === key) {
3777                    a.setAttribute('data-selected', 'true');
3778                } else {
3779                    a.removeAttribute('data-selected');
3780                }
3781            })
3782            let tbp = this.querySelector(`lit-tabpane[key='${key}']`);
3783            let panes = this.querySelectorAll('lit-tabpane');
3784            panes.forEach(a => {
3785                if (a.key === key) {
3786                    a.style.display = 'block';
3787                    this.activekey = a.key;
3788                    this.initTabPos()
3789                } else {
3790                    a.style.display = 'none';
3791                }
3792            })
3793        }
3794        /*激活选中 key 对应的 pane  成功返回true,没有找到key对应的pane 返回false*/
3795        activePane(key){
3796            if (key === null || key === undefined) return false;
3797            let tbp = this.querySelector(`lit-tabpane[key='${key}']`);
3798            if(tbp){
3799                this.activeByKey(key)
3800                return true;
3801            }else{
3802                return false;
3803            }
3804        }
3805        //当 custom element从文档DOM中删除时,被调用。
3806        disconnectedCallback() {
3807
3808        }
3809
3810        //当 custom element被移动到新的文档时,被调用。
3811        adoptedCallback() {
3812            console.log('Custom square element moved to new page.');
3813        }
3814
3815        //当 custom element增加、删除、修改自身属性时,被调用。
3816        attributeChangedCallback(name, oldValue, newValue) {
3817            if(name==='activekey'&&this.nav&&oldValue!==newValue){
3818                this.activeByKey(newValue)
3819            }
3820        }
3821    }
3822    if (!customElements.get('lit-tabs')) {
3823        customElements.define('lit-tabs', LitTabs);
3824    }
3825
3826    class AppChartFlame extends HTMLElement {
3827        draw;
3828        drawC;
3829        rowHeight = 17;
3830
3831        static get observedAttributes() {
3832            return []
3833        }
3834
3835        constructor() {
3836            super();
3837            const shadowRoot = this.attachShadow({mode: 'open'});
3838            shadowRoot.innerHTML = `
3839        <style>
3840        :host{
3841            font-size:inherit;
3842            display:inline-flex;
3843            align-items: center;
3844            justify-content:center;
3845            height: 100%;
3846            width: 100%;
3847            margin-bottom: 40px;
3848        }
3849        canvas { border: 1px solid #e9e9e9; }
3850        #title{
3851            font-weight: bold;
3852            height: auto;
3853        }
3854        #title span{
3855            color: gray;
3856        }
3857        #funcNameSpan{
3858            display: inline-block;
3859            border: 1px solid #e9e9e9;
3860            box-sizing: border-box;
3861            border-radius: 2px;
3862            padding: 2px 8px;
3863            background: #fff;
3864             color: gray;
3865            flex: 3;
3866            margin-left: 10px;
3867        }
3868        #percentSpan{
3869            display: inline-block;
3870            border: 1px solid #e9e9e9;
3871            margin-left: 10px;
3872            box-sizing: border-box;
3873            border-radius: 2px;
3874            padding: 2px 8px;
3875            background: #fff;
3876            min-width: 160px;
3877            max-width: 160px;
3878            margin-left: 10px;
3879            width: 100px;
3880            height: 30px;
3881            color: gray;
3882        }
3883        #history{
3884            display: none;
3885            border: 1px solid #42b983;
3886            box-sizing: border-box;
3887            border-radius: 2px;
3888            padding: 2px 8px;
3889            background: #fff;
3890            width: 100px;
3891            margin-left: 10px;
3892            height: 30px;
3893            cursor: pointer;
3894            user-select: none;
3895        }
3896        #history:hover{
3897            background: #42b983;
3898            color: #fff;
3899        }
3900        #searchInput{
3901            height: 30px;
3902            margin-left: 10px;
3903            margin-right: 10px;
3904            flex: 1;
3905        }
3906        </style>
3907        <div style="position: relative;width: 100%">
3908            <div id="title">Process <span id="pid"></span> <span id="processName"></span> Thread <span id="tid"></span> <span id="threadName"></span><span id="sample"></span></div>
3909            <canvas id="panel" title=""></canvas>
3910            <div id="controller" style="position: absolute;top: 32px;display: flex;width: 100%">
3911                <span id="history">Zoom Out</span>
3912                <span id="funcNameSpan"></span>
3913                <span id="percentSpan"></span>
3914                <lit-input id="searchInput" placeholder="search"  allow-clear>Search</lit-input>
3915            </div>
3916        </div>
3917        <slot></slot>
3918        `
3919        }
3920
3921        connectedCallback() {
3922            this.history = [];
3923            this.panel = this.shadowRoot.getElementById('panel');
3924            this.controller = this.shadowRoot.getElementById('controller');
3925            this.funcNameSpan = this.shadowRoot.getElementById('funcNameSpan');
3926            this.percentSpan = this.shadowRoot.getElementById('percentSpan');
3927            this.historySpan = this.shadowRoot.getElementById('history');
3928            this.searchInput = this.shadowRoot.getElementById('searchInput');
3929            this.pid = this.shadowRoot.getElementById('pid');
3930            this.tid = this.shadowRoot.getElementById('tid');
3931            this.processName = this.shadowRoot.getElementById('processName');
3932            this.threadName = this.shadowRoot.getElementById('threadName');
3933            this.sample = this.shadowRoot.getElementById('sample');
3934            this.titleDiv = this.shadowRoot.getElementById('title');
3935            this.context = this.panel.getContext('2d');
3936            this.panel.width = this.shadowRoot.host.clientWidth;
3937            this.panel.height = this.shadowRoot.host.clientHeight;
3938            this.historySpan.onclick = e => {
3939                if (this.history.length > 2) {
3940                    this.history.pop();
3941                    this.zoomOut(this.history[this.history.length - 1])
3942                } else if (this.history.length == 2) {
3943                    this.history.pop();
3944                    this.zoomOut(this.history[this.history.length - 1])
3945                    this.historySpan.style.display = 'none';
3946                } else {
3947                    this.historySpan.style.display = 'none';
3948                }
3949            }
3950            this.searchInput.addEventListener("onPressEnter", (e) => {
3951                this.keyword = e.currentTarget.value;
3952                requestAnimationFrame(this.draw);
3953            })
3954            this.searchInput.addEventListener('onClear', e => {
3955                this.keyword = null;
3956                requestAnimationFrame(this.draw);
3957            })
3958            this.panel.onmouseover = (e) => {
3959                this.mouseState = 'mouseOver';
3960            }
3961            this.panel.onmouseleave = e => {
3962                this.mouseState = 'mouseLeave';
3963                this.mouseX = 0;
3964                this.mouseY = 0;
3965                requestAnimationFrame(this.draw)
3966            }
3967            this.panel.onmousemove = e => {
3968                const pos = e.currentTarget.getBoundingClientRect();
3969                this.mouseX = e.clientX - pos.left;
3970                this.mouseY = e.clientY - pos.top;
3971                this.mouseState = 'mouseMove';
3972                requestAnimationFrame(this.draw)
3973            }
3974            this.panel.onmousedown = e => {
3975                this.mouseState = 'mouseDown';
3976                // const pos = e.currentTarget.getBoundingClientRect();
3977                // this.mouseX = e.clientX - pos.left;
3978                // this.mouseY = e.clientY - pos.top;
3979                // requestAnimationFrame(this.draw)
3980            }
3981            this.panel.onmouseup = e => {
3982                this.mouseState = 'mouseUp';
3983                const pos = e.currentTarget.getBoundingClientRect();
3984                this.mouseX = e.clientX - pos.left;
3985                this.mouseY = e.clientY - pos.top;
3986                requestAnimationFrame(this.draw)
3987            }
3988            // this.panel.onclick = (e)=>{
3989            //     this.mouseState = 'mouseClick';
3990            // }
3991        }
3992
3993        set data(value) {
3994            this._data = value;
3995            this.type = value.type;
3996            this.reverse = value.reverse || false;
3997            if (value.CallOrder.symbol === -1) {
3998                this._c = value.CallOrder.callStack;
3999            } else {
4000                this._c = [value.CallOrder];
4001            }
4002            this.history.push(this._c)
4003            this.eventCountAllProcess = data.recordSampleInfo[window.eventIndex].eventCount
4004            if (value.pid) {
4005                this.eventCountCurrentProcess = data.recordSampleInfo[window.eventIndex].processes.filter(it => it.pid === value.pid)[0].eventCount
4006                this.pid.textContent = value.pid;
4007            } else {
4008                // this.titleDiv.style.display = 'none';
4009            }
4010            if (value.tid) {
4011                this.eventCountCurrentThread = data.recordSampleInfo[window.eventIndex].processes.filter(it => it.pid === value.pid)[0].threads.filter(it => it.tid === value.tid)[0].eventCount;
4012                this.tid.textContent = value.tid;
4013            }
4014            if (value.sampleCount) {
4015                this.sample.textContent = ' (Samples: ' + value.sampleCount + ")";
4016            }
4017            if (value.processName) {
4018                this.processName.textContent = value.processName ? `(${value.processName})` : '';
4019            }
4020            if (value.threadName) {
4021                this.threadName.textContent = value.threadName ? `(${value.threadName})` : '';
4022            }
4023            if (value.funcName) {
4024                this.titleDiv.innerHTML = `${value.funcName}`
4025                this.controller.style.top = `${this.titleDiv.clientHeight + 10}px`
4026            }
4027            this.maxDepth = this.getMaxDepth(this.data.CallOrder.callStack) + 5; //设置最大层级
4028            this.sumCount = this.data.CallOrder.subEvents; //设置根节点的 sumCount
4029            this.panel.height = this.maxDepth * this.rowHeight
4030            this.panel.width = this.shadowRoot.host.clientWidth
4031            this.makeHighRes(this.panel);
4032            requestAnimationFrame(this.draw);
4033        }
4034
4035        get data() {
4036            return this._data;
4037        }
4038
4039        set c(value) {
4040            this.historySpan.style.display = 'block';
4041            this._c = value;
4042            this.history.push(this._c)
4043            // 下面代码实现 canvas 随内容高度变化
4044            // this.maxDepth = this._getMaxDepth(value) + 5; //设置最大层级
4045            // this.panel.height = this.maxDepth * this.rowHeight
4046            // this.panel.width = this.shadowRoot.host.clientWidth;
4047            // this.makeHighRes(this.panel);
4048            requestAnimationFrame(this.draw);
4049        }
4050
4051        get c() {
4052            return this._c;
4053        }
4054
4055        zoomOut(value) {
4056            this._c = value;
4057            // 下面代码实现 canvas 随内容高度变化
4058            // this.maxDepth = this._getMaxDepth(value) + 5; //设置最大层级
4059            // // this.sumCount = value.reduce((acc, cur) => acc + cur.s, 0); //设置根节点的 sumCount
4060            // this.panel.height = this.maxDepth * this.rowHeight
4061            // this.panel.width = this.shadowRoot.host.clientWidth;
4062            // this.makeHighRes(this.panel);
4063            requestAnimationFrame(this.draw);
4064        }
4065
4066        makeHighRes(canvas) {
4067            let ctx = canvas.getContext('2d');
4068            let dpr = window.devicePixelRatio || window.webkitDevicePixelRatio || window.mozDevicePixelRatio || 1;
4069            let oldWidth = canvas.width;
4070            let oldHeight = canvas.height;
4071            canvas.width = Math.round(oldWidth * dpr);
4072            canvas.height = Math.round(oldHeight * dpr);
4073            canvas.style.width = oldWidth + 'px';
4074            canvas.style.height = oldHeight + 'px';
4075            ctx.scale(dpr, dpr);
4076            this.context = ctx;
4077            return ctx;
4078        }
4079
4080        draw = () => {
4081            // requestAnimationFrame(this.draw);
4082            let ctx = this.context;
4083            // ctx.clearRect(0, 0, this.panel.width, this.panel.height);
4084            let grad = ctx.createLinearGradient(0, 0, 0, this.panel.height / 2); //创建一个渐变色线性对象
4085            grad.addColorStop(0, "#eeeeee");                  //定义渐变色颜色
4086            grad.addColorStop(1, "#efefb1");
4087            ctx.fillStyle = grad;                         //设置fillStyle为当前的渐变对象
4088            ctx.fillRect(0, 0, this.panel.width, this.panel.height);
4089            if (this.data) {
4090                if (this.reverse) {
4091                    this.drawCReverse(
4092                        this.c,
4093                        1,
4094                        {
4095                            x: 0,
4096                            y: this.rowHeight * 4,
4097                            w: this.panel.clientWidth,
4098                            h: this.rowHeight
4099                        });
4100                } else {
4101                    this.drawC(
4102                        this.c,
4103                        1,
4104                        {
4105                            x: 0,
4106                            y: this.panel.clientHeight - this.rowHeight,
4107                            w: this.panel.clientWidth,
4108                            h: this.rowHeight
4109                        });
4110                }
4111            }
4112        }
4113
4114        getStatistics(c) {
4115            let statistics;//鼠标hover展示的百分比
4116            switch (this.type) {
4117                case 1: //current thread
4118                    statistics = c.subEvents * 100 / this.eventCountCurrentThread;
4119                    statistics = statistics.toFixed(2)
4120                    statistics = `${statistics}%`
4121                    break;
4122                case 2: // current process
4123                    statistics = c.subEvents * 100 / this.eventCountCurrentProcess;
4124                    statistics = statistics.toFixed(2)
4125                    statistics = `${statistics}%`
4126                    break;
4127                case 3: // all process
4128                    statistics = c.subEvents * 100 / this.eventCountAllProcess;
4129                    statistics = statistics.toFixed(2)
4130                    statistics = `${statistics}%`
4131                    break;
4132                case 4: //event count
4133                    statistics = c.subEvents;
4134                    statistics = `${statistics}`
4135                    break;
4136                case 5: //event count in milliseconds
4137                    statistics = c.subEvents / 1000000;
4138                    statistics = statistics.toFixed(3)
4139                    statistics = `${statistics} ms`
4140                    break;
4141                default: //current thread
4142                    statistics = c.subEvents * 100 / this.eventCountCurrentThread;
4143                    statistics = statistics.toFixed(2)
4144                    statistics = `${statistics}%`
4145                    break;
4146            }
4147            return statistics;
4148        }
4149
4150        //HTML反转义
4151        htmlDecode(text) {
4152            let temp = document.createElement("div");
4153            temp.innerHTML = text;
4154            let output = temp.innerText || temp.textContent;
4155            temp = null;
4156            return output;
4157        }
4158
4159        getFunctionName(f) {
4160            let funName = "";
4161            if (data.SymbolMap[f]) {
4162                funName = data.SymbolMap[f].symbol;
4163            } else {
4164                let f = c[i].symbol;
4165                console.log(`processId:${this.pid.textContent} processName:${this.processName.textContent} threadId:${this.tid.textContent} threadName:${this.threadName.textContent}`, c[i], "SymbolMap中没有对应的值")
4166            }
4167            return this.htmlDecode(funName);
4168        }
4169
4170        getColor(percent2, funName) {
4171            let heatColor;
4172            if (this.keyword && this.keyword.length > 0 && funName.indexOf(this.keyword) != -1) {
4173                heatColor = {r: 0x66, g: 0xad, b: 0xff};
4174            } else {
4175                heatColor = this.getHeatColor(percent2);
4176            }
4177            return heatColor;
4178        }
4179
4180        drawCReverse = (c, dept, rect) => {
4181            let ctx = this.context;
4182            let offset = 0
4183            for (let i = 0; i < c.length; i++) {
4184                let funName = this.getFunctionName(c[i].symbol);
4185                let funcId = c[i].symbol;
4186                let percent = c[i].subEvents * 100 / (c.reduce((acc, cur) => acc + cur.subEvents, 0));
4187                let percent2 = c[i].subEvents * 100 / this.sumCount;
4188                if (percent2 < 0.1) continue //过滤掉 百分比为0.1一下的节点
4189                let heatColor = this.getColor(percent2, funName);
4190                let w = rect.w * (percent / 100.0);
4191                if (w < 1) {
4192                    w = 1
4193                }
4194                let _x = rect.x + offset;
4195                //绘制填充矩形
4196                ctx.fillStyle = `rgba(${heatColor.r}, ${heatColor.g}, ${heatColor.b}, 1)`;
4197                ctx.fillRect(_x, rect.y + 2, w, rect.h - 2);
4198                // 绘制文本
4199                ctx.fillStyle = "rgba(0,0,0,1)";
4200                let txtWidth = ctx.measureText(funName).width;//文本长度
4201                let chartWidth = txtWidth / funName.length;//每个字符长度
4202                let number = (w - 6) / chartWidth;//可以显示多少字符
4203                if (number >= 4 && number < funName.length - 3) {
4204                    ctx.fillText(funName.slice(0, number - 3) + '...', _x + 3, rect.y + 13, w - 6)
4205                } else if (number >= 4) {
4206                    ctx.fillText(funName, _x + 3, rect.y + 13, w - 6)
4207                }
4208                let _rect = {
4209                    x: _x, y: rect.y, w: w, h: rect.h
4210                }
4211                c[i].rect = _rect;
4212
4213                if (this.mouseX > _x && this.mouseX < _x + w && this.mouseY > rect.h * 3 + (dept) * rect.h && this.mouseY < rect.h * 3 + (dept + 1) * rect.h) {
4214                    if (this.mouseState === 'mouseMove') {
4215                        //绘制边框矩形
4216                        // ctx.font = '12px serif';
4217                        ctx.lineWidth = 2;
4218                        ctx.strokeStyle = `#000000`;
4219                        ctx.strokeRect(_x, rect.y + 1, w - 1, rect.h);
4220                        this.funcNameSpan.textContent = funName
4221                        this.panel.title = funName
4222                        this.percentSpan.textContent = this.getStatistics(c[i]);
4223                    } else {
4224                        if (this.mouseState === 'mouseUp') {
4225                            this.mouseState = null;
4226                            if (!this.compareNodes(this.c, [c[i]])) {
4227                                this.c = [c[i]];
4228                            }
4229                        }
4230                    }
4231                } else {
4232                    ctx.lineWidth = 1;
4233                    // ctx.font = '11px serif';
4234                }
4235                offset += w;
4236                // console.log(_rect,dept,percent,funName);
4237                //递归绘制子节点
4238                if (c[i].callStack && c[i].callStack.length > 0) {
4239                    _rect.y = _rect.y + _rect.h
4240                    this.drawCReverse(c[i].callStack, dept + 1, _rect);
4241                }
4242            }
4243        }
4244        drawC = (c, dept, rect) => {
4245            let ctx = this.context;
4246            let offset = 0
4247            for (let i = 0; i < c.length; i++) {
4248                let funName = this.getFunctionName(c[i].symbol);
4249                // console.log(dept,this.data.SymbolMap[c[i].symbol].symbol);
4250                let funcId = c[i].symbol;
4251                let percent = c[i].subEvents * 100 / (c.reduce((acc, cur) => acc + cur.subEvents, 0));//sumCount;
4252                let percent2 = c[i].subEvents * 100 / this.sumCount;
4253                if (percent2 < 0.1) continue //过滤掉 百分比为0.1一下的节点
4254                let heatColor = this.getColor(percent2, funName);
4255                let w = rect.w * (percent / 100.0);
4256                if (w < 1) {
4257                    w = 1
4258                }
4259                let _x = rect.x + offset;
4260                //绘制填充矩形
4261                ctx.fillStyle = `rgba(${heatColor.r}, ${heatColor.g}, ${heatColor.b}, 1)`;
4262                ctx.fillRect(_x, rect.y + 2, w, rect.h - 2);
4263                // 绘制文本
4264                ctx.fillStyle = "rgba(0,0,0,1)";
4265                let txtWidth = ctx.measureText(funName).width;//文本长度
4266                let chartWidth = txtWidth / funName.length;//每个字符长度
4267                let number = (w - 6) / chartWidth;//可以显示多少字符
4268                if (number >= 4 && number < funName.length - 3) {
4269                    ctx.fillText(funName.slice(0, number - 3) + '...', _x + 3, rect.y + 13, w - 6)
4270                } else if (number >= 4) {
4271                    ctx.fillText(funName, _x + 3, rect.y + 13, w - 6)
4272                }
4273                let _rect = {
4274                    x: _x, y: rect.y, w: w, h: rect.h
4275                }
4276                c[i].rect = _rect;
4277
4278                if (this.mouseX > _x && this.mouseX < _x + w && this.mouseY > (this.maxDepth - dept) * rect.h && this.mouseY < (this.maxDepth - dept + 1) * rect.h) {
4279                    if (this.mouseState === 'mouseMove') {
4280                        //绘制边框矩形
4281                        // ctx.font = '12px serif';
4282                        ctx.lineWidth = 2;
4283                        ctx.strokeStyle = `#000000`;
4284                        ctx.strokeRect(_x, rect.y + 1, w - 1, rect.h);
4285                        this.funcNameSpan.textContent = funName
4286                        this.panel.title = funName
4287                        this.percentSpan.textContent = this.getStatistics(c[i]);
4288                    } else {
4289                        if (this.mouseState === 'mouseUp') {
4290                            this.mouseState = null;
4291                            if (!this.compareNodes(this.c, [c[i]])) {
4292                                this.c = [c[i]];
4293                            }
4294                        }
4295                    }
4296                } else {
4297                    ctx.lineWidth = 1;
4298                    // ctx.font = '11px serif';
4299                }
4300                offset += w;
4301                // console.log(_rect,dept,percent,funName);
4302                //递归绘制子节点
4303                if (c[i].callStack && c[i].callStack.length > 0) {
4304                    _rect.y = _rect.y - _rect.h
4305                    this.drawC(c[i].callStack, dept + 1, _rect);
4306                }
4307            }
4308        }
4309
4310        compareNode(na, nb) {
4311            let res = false;
4312            if (na.selfEvents === nb.selfEvents && na.subEvents === nb.subEvents && na.symbol === nb.symbol) {
4313                res = this.compareNodes(na.callStack || [], nb.callStack || []);
4314            }
4315            return res;
4316        }
4317
4318        compareNodes(a, b) {
4319            let res = false;
4320            if (a.length === b.length) {
4321                if (a.length === 0) {
4322                    return true;
4323                }
4324                for (let i = 0; i < a.length; i++) {
4325                    res = this.compareNode(a[i], b[i])
4326                }
4327            }
4328            return res;
4329        }
4330
4331        getMaxDepth(nodes) {
4332            let isArray = Array.isArray(nodes);
4333            let sumCount;
4334            if (isArray) {
4335                sumCount = nodes.reduce((acc, cur) => acc + cur.subEvents, 0);
4336            } else {
4337                sumCount = nodes.subEvents;
4338            }
4339            let width = sumCount * 100.0 / this.sumCount;
4340            if (width < 0.1) {
4341                return 0;
4342            }
4343            let children = isArray ? this.splitChildrenForNodes(nodes) : nodes.callStack;
4344            let childDepth = 0;
4345            if (children) {
4346                for (let child of children) {
4347                    childDepth = Math.max(childDepth, this.getMaxDepth(child));
4348                }
4349            }
4350            return childDepth + 1;
4351        }
4352
4353        splitChildrenForNodes(nodes) {
4354            let map = new Map();
4355            for (let node of nodes) {
4356                for (let child of node.callStack) {
4357                    let subNodes = map.get(child.symbol);
4358                    if (subNodes) {
4359                        subNodes.push(child);
4360                    } else {
4361                        map.set(child.symbol, [child]);
4362                    }
4363                }
4364            }
4365            let res = [];
4366            for (let subNodes of map.values()) {
4367                res.push(subNodes.length == 1 ? subNodes[0] : subNodes);
4368            }
4369            return res;
4370        }
4371
4372        getHeatColor(widthPercentage) {
4373            return {
4374                r: Math.floor(245 + 10 * (1 - widthPercentage * 0.01)),
4375                g: Math.floor(110 + 105 * (1 - widthPercentage * 0.01)),
4376                b: 100,
4377            };
4378        }
4379
4380        attributeChangedCallback(name, oldValue, newValue) {
4381        }
4382    }
4383    if (!customElements.get('app-chart-flame')) {
4384        customElements.define('app-chart-flame', AppChartFlame);
4385    }
4386
4387    class AppChartStatistics extends HTMLElement {
4388        static get observedAttributes() {
4389            return ['data']
4390        }
4391
4392        constructor() {
4393            super();
4394            const shadowRoot = this.attachShadow({mode: 'open'});
4395            this.color = [
4396                '#3391ff', // red
4397                '#ff9201', // green
4398                '#008078', // indigo
4399                '#0094c6', // orange
4400                '#ff7500', // light green
4401                '#2db3aa', // deep purple
4402                '#0076ff', // pink
4403                '#66adff', // purple
4404                '#73e6de', // blue
4405                '#535da6', // light blue
4406                '#ffab40', // lime
4407                '#38428c', // cyan
4408                '#7cdeff', // deep orange
4409                '#fbbf00', // blue gray
4410                '#2db4e2', // amber #ffc105
4411                '#ffd44a', // brown
4412                '#7a84cc', // teal
4413                '#ffe593', // yellow 0xffec3d
4414            ];
4415            shadowRoot.innerHTML = `
4416        <style>
4417        :host{
4418            font-size:inherit;
4419            display:inline-flex;
4420            align-items: center;
4421            justify-content:center;
4422            padding: 0;
4423            margin: 0;
4424            width: 100%;
4425        }
4426        </style>
4427        <div style="display: flex;flex-direction: column;width: 100%;height: auto">
4428            <lit-table id="tbl1" noheader style="height: auto;width: 100%;">
4429                <lit-table-column title="key" data-index="key" width="200px" key="key" ></lit-table-column>
4430                <lit-table-column title="value" data-index="value" key="value"></lit-table-column>
4431                <lit-table-column title="time" data-index="time" key="time"></lit-table-column>
4432            </lit-table>
4433            <div id="back" style="display: none;cursor: pointer;
4434                border-radius: 5px;width: 35px;justify-content: center;text-align: center;
4435                padding: 7px 15px 7px 15px;border: 1px solid #aaa;color: #555">back</div>
4436            <lit-pie-chart id="chart" style="height: auto;width: 100%"></lit-pie-chart>
4437        </div>
4438        <slot></slot>
4439        `
4440        }
4441
4442        set data(json){
4443            if(json.recordSampleInfo && json.recordSampleInfo.length > 0){
4444                this.eventInfo = json.recordSampleInfo[window.eventIndex];
4445            }
4446            this.processNameMap = json.processNameMap;
4447            this.threadNameMap = json.threadNameMap;
4448            this.symbolsFileList = json.symbolsFileList;
4449            this.SymbolMap = json.SymbolMap;
4450            let rows = [];
4451            if (json.deviceTime) {
4452                rows.push({key: 'Device Time', value: json.deviceTime,time:''});
4453            }
4454            if (json.deviceType) {
4455                rows.push({key: 'Device Type', value: json.deviceType,time:''});
4456            }
4457            if (json.osVersion) {
4458                rows.push({key: 'OS Version', value: json.osVersion,time:''});
4459            }
4460            if (json.deviceCommandLine) {
4461                rows.push({key:'Record cmdline',value: json.deviceCommandLine,time:''});
4462            }
4463            rows.push({key:'Total Samples',value: '' + json.totalRecordSamples,time:''});
4464            if(this.eventInfo){
4465                rows.push({key:'Event Type',value:this.eventInfo.eventConfigName,time:this.getSampleWeight(this.eventInfo.eventCount)});
4466                this.initChartData();
4467            }
4468            this.table.dataSource = rows;
4469        }
4470
4471        getSampleWeight(count){
4472            if(this.eventInfo.eventConfigName.includes('task-clock') || this.eventInfo.eventConfigName.includes('cpu-clock')){
4473                return (count / 1000000.0).toFixed(3) + ' ms'
4474            }else{
4475                return ''+count;
4476            }
4477        }
4478
4479        getProcessName(pid) {
4480            let name = this.processNameMap[pid];
4481            return name ? `Process: ${pid} (${name})` : 'Process: '+pid.toString();;
4482        }
4483
4484        getThreadName(tid) {
4485            let name = this.threadNameMap[tid];
4486            return name ? `Thread: ${tid} (${name})` : 'Thread: '+tid.toString();
4487        }
4488
4489        getLibName(fileId) {
4490            return 'Library: '+this.symbolsFileList[fileId];
4491        }
4492
4493        getFuncName(funcId) {
4494            return 'Function: '+this.SymbolMap[funcId].symbol;
4495        }
4496
4497        connectedCallback() {
4498            this.table = this.shadowRoot.getElementById('tbl1');
4499            this.chart = this.shadowRoot.getElementById('chart');
4500            this.backBt = this.shadowRoot.getElementById('back');
4501            this.backBt.addEventListener('mouseover',e=>{
4502                this.backBt.style.borderColor = '#42b983'
4503                this.backBt.style.color = '#42b983'
4504            })
4505            this.backBt.addEventListener('mouseout',e=>{
4506                this.backBt.style.borderColor = '#aaa'
4507                this.backBt.style.color = '#555'
4508            })
4509            this.chartMaxCount = 126;
4510            this.backBt.addEventListener('click',this.back.bind(this));
4511            this.chart.chartClickListener = (item) => {
4512                if(item && item.id != -1){
4513                    let ds = this.table.dataSource;
4514                    if(item.name.startsWith('Process')){
4515                        let pName = item.name.slice(8);
4516                        if(!ds.find(item => item.key == 'Process')){
4517                            ds.push({key:'Process',value:pName,time:item.time});
4518                        }
4519                        this.chart.title = 'Threads in process ' + pName;
4520                        let find = this.eventInfo.processes.find(process => item.id === process.pid);
4521                        this.clickProcess(find)
4522                    }else if(item.name.startsWith('Thread')){
4523                        let tName = item.name.slice(7);
4524                        if(!ds.find(item => item.key == 'Thread')){
4525                            ds.push({key:'Thread',value:tName,time:item.time});
4526                        }
4527                        this.chart.title = 'Libraries in thread ' + tName;
4528                        let find = this.clickProcessData.threads.find(thread => item.id === thread.tid);
4529                        this.clickThread(find);
4530                    }else if(item.name.startsWith('Library')){
4531                        let libName = item.name.slice(8);
4532                        if(!ds.find(item => item.key == 'Library')){
4533                            ds.push({key:'Library',value:libName,time:item.time});
4534                        }
4535                        this.chart.title = 'Function in library ' + libName;
4536                        let find = this.clickThreadData.libs.find(lib => item.id === lib.fileId);
4537                        this.clickLib(find);
4538                    }else{
4539                        // console.log(item)
4540                    }
4541                    this.table.dataSource = ds;
4542                }
4543            }
4544        }
4545
4546        initChartData(){
4547            if(Array.isArray(this.eventInfo.processes)){
4548                function compare(property){
4549                    return function (a,b) {
4550                        return b[property] - a[property]
4551                    }
4552                }
4553                this.eventInfo.processes.sort(compare('eventCount'))
4554                let chartSource = [];
4555                let otherValue = 0;
4556                this.eventInfo.processes.forEach((process,index) => {
4557                    if(index < 14){
4558                        chartSource.push({
4559                            id:process.pid,
4560                            name: this.getProcessName(process.pid),
4561                            value: (process.eventCount / this.eventInfo.eventCount).toFixed(3),
4562                            color: this.color[index],
4563                            time: this.getSampleWeight(process.eventCount)
4564                        });
4565                    }else{
4566                        otherValue += process.eventCount;
4567                    }
4568                })
4569                if(otherValue > 0){
4570                    chartSource.push({
4571                        id : -1,
4572                        name: 'Other',
4573                        value: (otherValue / this.eventInfo.eventCount).toFixed(3),
4574                        color: '#888888',
4575                        time: this.getSampleWeight(otherValue)
4576                    });
4577                }
4578                    chartSource.sort((a, b) => { return b.time - a.time })
4579                this.processDs = chartSource;
4580                this.chart.dataSource = chartSource;
4581                this.chart.title = 'Processes in event type ' + this.eventInfo.eventConfigName;
4582            }
4583        }
4584
4585        back(){
4586            if(this.currentLevel == 'Function in Library'){
4587                this.chart.title = 'Libraries in thread ' + this.getThreadName(this.clickThreadData.tid).slice(7);
4588                this.chart.dataSource = this.libDs;
4589                this.currentLevel = 'Library in Thread';
4590            }else if(this.currentLevel == 'Library in Thread'){
4591                this.chart.title = 'Threads in process ' + this.getProcessName(this.clickProcessData.pid).slice(8);
4592                this.chart.dataSource = this.threadDs
4593                this.currentLevel = 'Thread in Process';
4594            }else{
4595                this.chart.title = 'Processes in event type ' + this.eventInfo.eventConfigName;
4596                this.chart.dataSource = this.processDs
4597                this.backBt.style.display = 'none';
4598            }
4599            let row = this.table.dataSource;
4600            if(Array.isArray(row)){
4601                row.pop();
4602                this.table.dataSource = row;
4603            }
4604        }
4605
4606        /**
4607         * chart click process
4608         *
4609         * @param process
4610         */
4611        clickProcess(process)
4612        {
4613            if (process && process.threads) {
4614                this.backBt.style.display = 'flex';
4615                this.currentLevel = 'Thread in Process'
4616                this.clickProcessData = process;
4617                let chartSource = [];
4618                let chartTotal = 0;
4619                let count = 0;
4620                let filter = process.threads.filter(item => item.eventCount / process.eventCount > 0.001);
4621                let total = 0;
4622                filter.forEach(item=>{ total += item.eventCount });
4623                total = process.eventCount;
4624                for (let item of filter) {
4625                    if (count < this.chartMaxCount) {
4626                        chartSource.push({
4627                            id:item.tid,
4628                            name: this.getThreadName(item.tid),
4629                            value: (item.eventCount / total).toFixed(6),
4630                            color: this.color[count % this.color.length],
4631                            time: this.getSampleWeight(item.eventCount)
4632                        });
4633                        chartTotal += item.eventCount;
4634                        count ++;
4635                    }
4636                    if (count >= this.chartMaxCount) {
4637                        break;
4638                    }
4639                }
4640                if (count < this.chartMaxCount && chartTotal < process.eventCount) {
4641                    chartSource.push({
4642                        id : -1,
4643                        name: 'Other',
4644                        value: ((process.eventCount - chartTotal) / process.eventCount).toFixed(6),
4645                        color: '#888888',
4646                        time: this.getSampleWeight(process.eventCount - chartTotal)
4647                    });
4648                } else {
4649                    this.addOtherItem(count, total, chartTotal, chartSource)
4650                }
4651                chartSource.sort((a, b) => { return b.time - a.time })
4652                this.threadDs = chartSource;
4653                this.chart.dataSource = chartSource;
4654            }
4655        }
4656
4657        /**
4658         * chart click thread
4659         * @param thread
4660         */
4661        clickThread(thread)
4662        {
4663            if (thread && thread.libs) {
4664                this.currentLevel = 'Library in Thread'
4665                let chartSource = [];
4666                let chartTotal = 0;
4667                let count = 0;
4668                this.clickThreadData = thread;
4669                let filter = thread.libs.filter(item => item.eventCount / thread.eventCount > 0.001);
4670                let total = 0;
4671                filter.forEach(item=>{ total += item.eventCount });
4672                total = thread.eventCount;
4673                for (let item of filter) {
4674                    if (count < this.chartMaxCount) {
4675                        chartSource.push({
4676                            id:item.fileId,
4677                            name: this.getLibName(item.fileId),
4678                            value: (item.eventCount / total).toFixed(6),
4679                            color: this.color[count % this.color.length],
4680                            time: this.getSampleWeight(item.eventCount)
4681                        });
4682                        chartTotal += item.eventCount;
4683                        count ++;
4684                    }
4685                    if (count >= this.chartMaxCount) {
4686                        break;
4687                    }
4688                }
4689                if (count < this.chartMaxCount && chartTotal < thread.eventCount) {
4690                    chartSource.push({
4691                        id : -1,
4692                        name: 'Other',
4693                        value: ((thread.eventCount - chartTotal) / thread.eventCount).toFixed(6),
4694                        color: '#888888',
4695                        time: this.getSampleWeight(thread.eventCount - chartTotal)
4696                    });
4697                } else {
4698                    this.addOtherItem(count, total, chartTotal, chartSource)
4699                }
4700                chartSource.sort((a, b) => { return b.time - a.time })
4701                this.libDs = chartSource;
4702                this.chart.dataSource = chartSource;
4703            }
4704        }
4705
4706        /**
4707         * chart click lib
4708         * @param lib
4709         */
4710        clickLib(lib){
4711            if(lib && lib.functions){
4712                this.currentLevel = 'Function in Library'
4713                let chartSource = [];
4714                let chartTotal = 0;
4715                let count = 0;
4716                let filter = lib.functions.filter(item => item.counts[1] / lib.eventCount > 0.001);
4717                let total = lib.eventCount;
4718                let countTotal = 0;
4719                filter.forEach(item=>{ countTotal += item.counts[1]});
4720                for(let item of filter){
4721                    if(count < this.chartMaxCount){
4722                        chartSource.push({
4723                            id:item.symbol,
4724                            name: this.getFuncName(item.symbol),
4725                            value: (item.counts[1] / total).toFixed(6),
4726                            color: this.color[count % this.color.length],
4727                            time: this.getSampleWeight(item.counts[1])
4728                        });
4729                        chartTotal += item.counts[1];
4730                        count ++;
4731                    }
4732                    if(count >= this.chartMaxCount){
4733                        break;
4734                    }
4735                }
4736                if(count < this.chartMaxCount && countTotal < lib.eventCount){
4737                    chartSource.push({
4738                        id : -1,
4739                        name: 'Other',
4740                        value: ((lib.eventCount - countTotal) / lib.eventCount).toFixed(6),
4741                        color: '#888888',
4742                        time: this.getSampleWeight(lib.eventCount - countTotal)
4743                    });
4744                }else{
4745                    this.addOtherItem(count,total,chartTotal,chartSource)
4746                }
4747                    chartSource.sort((a, b) => { return b.time - a.time })
4748                this.chart.dataSource = chartSource;
4749            }
4750        }
4751
4752        addOtherItem(count,total,chartTotal,chartSource){
4753            if(count >= this.chartMaxCount && total - chartTotal > 0){
4754                chartSource.push({
4755                    id : -1,
4756                    name: 'Other',
4757                    value: ((total - chartTotal) / total).toFixed(6),
4758                    color: '#888888',
4759                    time: this.getSampleWeight(total - chartTotal)
4760                });
4761            }
4762        }
4763
4764        attributeChangedCallback(name, oldValue, newValue) {
4765            if (name == 'color' && this.loading) {
4766                this.loading.style.color = newValue;
4767            }
4768            if (name == 'size' && this.loading) {
4769                this.loading.style.fontSize = newValue + 'px';
4770            }
4771        }
4772    }
4773    if (!customElements.get('app-chart-statistics')) {
4774        customElements.define('app-chart-statistics', AppChartStatistics);
4775    }
4776
4777    class AppFlameGraph extends HTMLElement {
4778        static get observedAttributes() {
4779            return ['color', 'size']
4780        }
4781
4782        constructor() {
4783            super();
4784            const shadowRoot = this.attachShadow({mode: 'open'});
4785            shadowRoot.innerHTML = `
4786        <style>
4787        :host{
4788            font-size:inherit;
4789            display:inline-flex;
4790            align-items: center;
4791            justify-content:center;
4792            width: 100%;
4793        }
4794        </style>
4795        <div style="width: 100%;display: flex;flex-direction: column">
4796            <lit-select id="typeSelect" default-value="1" mode="single" style="width:40vw;margin-bottom: 10px;align-self: flex-end">
4797                    <lit-select-option value="1">Show percentage of event count relative to the current thread</lit-select-option>
4798                    <lit-select-option value="2">Show percentage of event count relative to the current process</lit-select-option>
4799                    <lit-select-option value="3">Show percentage of event count relative to all process</lit-select-option>
4800                    <lit-select-option value="4">show event count</lit-select-option>
4801                    <lit-select-option value="5">show event count in milliseconds</lit-select-option>
4802            </lit-select>
4803            <div id="panel" style="width: 100%"></div>
4804        </div>
4805        <slot></slot>
4806        `
4807        }
4808
4809        get data() {
4810            return this._json || null;
4811        }
4812
4813        set data(json) {
4814            //如果已经给过值,不重新刷新
4815            if (this.isFinished) {
4816                return;
4817            }
4818            this._json = json;
4819            this.panel = this.shadowRoot.getElementById('panel');
4820            this.panel.innerHTML = '';
4821            let processes = json.recordSampleInfo[window.eventIndex].processes;
4822            processes.slice(0).forEach(it => {
4823                it.threads.slice(0).forEach(th => {
4824                    let pid = it.pid;
4825                    let processName = json.processNameMap[it.pid];
4826                    let tid = th.tid;
4827                    let threadName = json.threadNameMap[th.tid];
4828                    let eventCount = th.eventCount;
4829                    let sampleCount = th.sampleCount;
4830                    let g = th.CallOrder;
4831                    let flame = document.createElement('app-chart-flame');
4832                    flame.style.width = '100%'
4833                    flame.style.height = 'auto';
4834                    flame.style.display = 'flex'
4835                    this.panel.appendChild(flame);
4836                    flame.data = {
4837                        type:this.type||1,
4838                        pid, processName, tid, threadName, eventCount, sampleCount, CallOrder:g
4839                    }
4840                    // console.log(pid,processName,tid,threadName,sampleCount,g);
4841                })
4842            })
4843            this.isFinished = true;
4844        }
4845
4846        connectedCallback() {
4847            this.isFinished = false;
4848            this.panel = this.shadowRoot.getElementById('panel');
4849            this.typeSelect = this.shadowRoot.getElementById('typeSelect');
4850            this.typeSelect.onchange = ev => {
4851                this.type = parseInt(ev.detail.value);
4852                this.isFinished = false;
4853                this.data = window.data;
4854            }
4855        }
4856
4857        attributeChangedCallback(name, oldValue, newValue) {
4858            if (name == 'color' && this.loading) {
4859                this.loading.style.color = newValue;
4860            }
4861            if (name == 'size' && this.loading) {
4862                this.loading.style.fontSize = newValue + 'px';
4863            }
4864        }
4865    }
4866    if (!customElements.get('app-flame-graph')) {
4867        customElements.define('app-flame-graph', AppFlameGraph);
4868    }
4869
4870    class AppFunction extends HTMLElement {
4871        static get observedAttributes() {
4872            return ['color', 'size']
4873        }
4874
4875        constructor() {
4876            super();
4877            const shadowRoot = this.attachShadow({mode: 'open'});
4878            shadowRoot.innerHTML = `
4879        <style>
4880        :host{
4881            font-size:inherit;
4882            display:inline-flex;
4883            align-items: center;
4884            justify-content:center;
4885            padding: 0;
4886            margin: 0;
4887            width: 100%;
4888        }
4889        </style>
4890        <div style="width: 100%;display: flex;flex-direction: column">
4891            <lit-table id="table" noheader style="width: 100%;">
4892                <lit-table-column title="key" data-index="key" width="200px" key="key" ></lit-table-column>
4893                <lit-table-column title="value" data-index="value" width="1fr" key="value"></lit-table-column>
4894            </lit-table>
4895            <lit-select id="typeSelect" default-value="1" mode="single" style="width:500px;margin-bottom: 10px;margin-top:10px;align-self: flex-end">
4896                    <lit-select-option value="1">Show percentage of event count relative to the current thread</lit-select-option>
4897                    <lit-select-option value="2">Show percentage of event count relative to the current process</lit-select-option>
4898                    <lit-select-option value="3">Show percentage of event count relative to all process</lit-select-option>
4899                    <lit-select-option value="4">show event count</lit-select-option>
4900                    <lit-select-option value="5">show event count in milliseconds</lit-select-option>
4901            </lit-select>
4902            <app-chart-flame id="flame1"></app-chart-flame>
4903            <app-chart-flame id="flame2"></app-chart-flame>
4904        </div>
4905        <slot></slot>
4906        `
4907        }
4908
4909        getNodesMatchingFuncId(root, funcId) {
4910            let nodes = [];
4911
4912            function recursiveFn(node) {
4913                if (node.symbol == funcId) {
4914                    nodes.push(node);
4915                } else {
4916                    for (let child of node.callStack) {
4917                        recursiveFn(child);
4918                    }
4919                }
4920            }
4921
4922            recursiveFn(root);
4923            return nodes;
4924        }
4925
4926        get dataSource() {
4927            return this._dataSource;
4928        }
4929
4930        getReverseData(rg, funId) {
4931
4932        }
4933
4934        set dataSource(val) {
4935            this._dataSource = val;
4936            this.table.dataSource = [
4937                {key: "Event Type", value: data.recordSampleInfo[window.eventIndex].eventConfigName},
4938                {key: "Process", value: val.process},
4939                {key: "Thread", value: val.thread},
4940                {key: "Library", value: val.library},
4941                {key: "Function", value: val.fun},
4942            ];
4943            let filterProcess = data.recordSampleInfo[window.eventIndex].processes.filter(it => it.pid === val.processId);
4944            let filterThread = filterProcess[0].threads.filter(it => it.tid === val.threadId);
4945            let filterG = filterThread[0].CallOrder
4946            let filterRG = filterThread[0].CalledOrder
4947            let c;
4948            let rc;
4949            let findF = (obj) => {
4950                if (Array.isArray(obj)) {
4951                    obj.forEach(it => {
4952                        if (it.symbol === val.funId) {
4953                            c = it;
4954                            return;
4955                        } else {
4956                            if (it.callStack && it.callStack.length > 0) {
4957                                findF(it.callStack);
4958                            }
4959                        }
4960                    })
4961                } else {
4962                    findF(obj.callStack);
4963                }
4964            }
4965            //合并倒树结构
4966            let mergeRc = () => {
4967                let rc = {};
4968                let _rc = this.getNodesMatchingFuncId(filterRG, val.funId);//将rg树中 为funId值的节点 形成一个数组
4969                let _sumCount = _rc.reduce((acc, cur) => acc + cur.subEvents, 0);//计算eventCount值
4970                let splitChildrenForNodes = (nodes) => {
4971                    let map = new Map();
4972                    for (let node of nodes) {
4973                        if (node.callStack) {
4974                            for (let child of node.callStack) {
4975                                let subNodes = map.get(child.symbol);
4976                                if (subNodes) {
4977                                    subNodes.push(child);
4978                                } else {
4979                                    map.set(child.symbol, [child]);
4980                                }
4981                            }
4982                        }
4983                    }
4984                    let res = [];
4985                    for (let key of map.keys()) {
4986                        let subNodes = map.get(key);
4987                        res.push({
4988                            selfEvents: 0,
4989                            subEvents: subNodes.reduce((acc, cur) => acc + cur.subEvents, 0),
4990                            symbol: key,
4991                            callStack: splitChildrenForNodes(subNodes)
4992                        })
4993                    }
4994                    return res;
4995                }
4996                let children = splitChildrenForNodes(_rc);
4997                return {
4998                    selfEvents: 0,
4999                    subEvents: _sumCount,
5000                    symbol: val.funId,
5001                    callStack: children
5002                }
5003            }
5004            findF(filterG)
5005            rc = mergeRc();
5006            this.flame1.data = {
5007                pid: val.processId,
5008                processName: val.processName,
5009                tid: val.threadId,
5010                threadName: val.threadName,
5011                eventCount: null,
5012                sampleCount: null,
5013                type: this.type || 1,
5014                funcName: `Functions called by ${val.fun}`,
5015                CallOrder: c
5016            }
5017
5018            this.flame2.data = {
5019                pid: val.processId,
5020                processName: val.processName,
5021                tid: val.threadId,
5022                threadName: val.threadName,
5023                eventCount: null,
5024                sampleCount: null,
5025                reverse: true,
5026                type: this.type || 1,
5027                funcName: `Functions calling ${val.fun}`,
5028                CallOrder: rc
5029            }
5030        }
5031
5032        connectedCallback() {
5033            this.table = this.shadowRoot.getElementById('table');
5034            this.flame1 = this.shadowRoot.getElementById('flame1');
5035            this.flame2 = this.shadowRoot.getElementById('flame2');
5036            this.typeSelect = this.shadowRoot.getElementById('typeSelect');
5037            this.typeSelect.onchange = (e) => {
5038                this.type = parseInt(e.detail.value);
5039                this.dataSource = this.dataSource;
5040            }
5041        }
5042
5043        attributeChangedCallback(name, oldValue, newValue) {
5044
5045        }
5046    }
5047    if (!customElements.get('app-function')) {
5048        customElements.define('app-function', AppFunction);
5049    }
5050
5051    class AppSimpleTable extends HTMLElement {
5052        static get observedAttributes() {
5053            return ['color', 'size']
5054        }
5055
5056        constructor() {
5057            super();
5058            const shadowRoot = this.attachShadow({mode: 'open'});
5059            shadowRoot.innerHTML = `
5060        <style>
5061        :host{
5062            font-size:inherit;
5063            display:inline-flex;
5064            align-items: center;
5065            justify-content:center;
5066        }
5067        .loading{
5068            display: block;
5069            width: 1em;
5070            height: 1em;
5071            margin: auto;
5072            animation: rotate 1.4s linear infinite;
5073        }
5074        .circle {
5075            stroke: currentColor;
5076            animation:  progress 1.4s ease-in-out infinite;
5077            stroke-dasharray: 80px, 200px;
5078            stroke-dashoffset: 0px;
5079            transition:.3s;
5080        }
5081        :host(:not(:empty)) .loading{
5082            margin:.5em;
5083        }
5084        @keyframes rotate{
5085            to{
5086                transform: rotate(360deg);
5087            }
5088        }
5089        @keyframes progress {
5090            0% {
5091              stroke-dasharray: 1px, 200px;
5092              stroke-dashoffset: 0px;
5093            }
5094            50% {
5095              stroke-dasharray: 100px, 200px;
5096              stroke-dashoffset: -15px;
5097            }
5098            100% {
5099              stroke-dasharray: 100px, 200px;
5100              stroke-dashoffset: -125px;
5101            }
5102        }
5103        </style>
5104        <div style="width: 100%;height: auto;">
5105            <svg class="loading" id="loading" viewBox="22 22 44 44"><circle class="circle" cx="44" cy="44" r="20.2" fill="none" stroke-width="3.6"></circle></svg>
5106            <div style="display: flex;flex-direction: column;align-items: flex-end;width: 100%;">
5107                <div style="display: flex;flex-direction: row;align-items: center;justify-content: space-between;width: 100%;margin-bottom: 10px">
5108                    <lit-input id="keyword" icon="search" placeholder="Please enter a keyword" style="width: 300px" allow-clear></lit-input>
5109                    <lit-select id="typeSelect" default-value="1" mode="single" style="width: 400px;margin-bottom: 10px">
5110                        <lit-select-option value="1">show percentage of event count</lit-select-option>
5111                        <lit-select-option value="2">show event count</lit-select-option>
5112                        <lit-select-option value="3">show event count in milliseconds</lit-select-option>
5113                    </lit-select>
5114                </div>
5115                <lit-table id="table" style="width: calc(100vw - 40px);">
5116                    <lit-table-column title="Total" data-index="total" width="100px" key="total" order></lit-table-column>
5117                    <lit-table-column title="Self" data-index="self" width="100px" key="self" order></lit-table-column>
5118                    <lit-table-column title="Samples" data-index="samples" width="100px" key="samples" order></lit-table-column>
5119                    <lit-table-column title="Process" data-index="process" width="250px" key="process" order></lit-table-column>
5120                    <lit-table-column title="Thread" data-index="thread" width="250px" key="thread" order></lit-table-column>
5121                    <lit-table-column title="Library" data-index="library" width="250px" key="library" order></lit-table-column>
5122                    <lit-table-column title="Function" data-index="fun" key="fun" order></lit-table-column>
5123                </lit-table>
5124                <div style="height: 140px">
5125                    <lit-pagination id="pagination" show-size-changer page-size="10" page-size-options="[20,50,200]" style="margin-top: 10px;">
5126    <!--                    <template slot="showTotal"><label>{{range[0]}}-{{range[1]}} of {{total}} items</label></template>-->
5127                    </lit-pagination>
5128                </div>
5129            </div>
5130
5131        </div>
5132        <slot></slot>
5133        `
5134        }
5135
5136        set data(json) {
5137            if (json.recordSampleInfo && json.recordSampleInfo.length > 0) {
5138                this.processNameMap = json.processNameMap;
5139                this.threadNameMap = json.threadNameMap;
5140                this.symbolsFileList = json.symbolsFileList;
5141                this.SymbolMap = json.SymbolMap;
5142                this.eventInfo = json.recordSampleInfo[window.eventIndex];
5143                this.initTableData().then(() => {
5144                    this.loading.style.display = 'none';
5145                    this.pagination.current = 1;
5146                    this.pagination.total = this.source.length;
5147                    this.table.dataSource = this.paginationHandler(1,this.pagination.pageSize);
5148                })
5149            }
5150        }
5151
5152        paginationHandler(page,pageSize,data) {
5153            let offset = (page - 1) * pageSize;
5154            let arr = [];
5155            if(this.searchKey && this.searchKey.length > 0 && data){
5156                arr = (offset + pageSize >= data.length) ? data.slice(offset, data.length) : data.slice(offset, offset + pageSize);
5157            }else{
5158                arr = (offset + pageSize >= this.source.length) ? this.source.slice(offset, this.source.length) : this.source.slice(offset, offset + pageSize);
5159            }
5160            arr.forEach(item=>{
5161                item.total = this.getSampleWeight(item.totalCount);
5162                item.self = this.getSampleWeight(item.selfCount);
5163            })
5164            return arr;
5165        }
5166
5167        async initTableData() {
5168            this.source = [];
5169            this.eventInfo.processes.forEach(process => {
5170                process.threads.forEach(thread => {
5171                    thread.libs.forEach(lib => {
5172                        lib.functions.forEach(fun => {
5173                            this.source.push({
5174                                process: this.getProcessName(process.pid),
5175                                processId:process.pid,
5176                                thread: this.getThreadName(thread.tid),
5177                                threadId:thread.tid,
5178                                library: this.getLibName(lib.fileId),
5179                                libraryId:lib.fileId,
5180                                fun: this.getFuncName(fun.symbol),
5181                                funId: fun.symbol,
5182                                totalCount: fun.counts[2],
5183                                selfCount: fun.counts[1],
5184                                samples: fun.counts[0],
5185                                total:this.getSampleWeight(fun.counts[2]),
5186                                self:this.getSampleWeight(fun.counts[1]),
5187                            });
5188                        })
5189                    })
5190                })
5191            });
5192            function compare(property) {
5193                return function (a, b) {
5194                    return b[property] - a[property]
5195                }
5196            }
5197            this.source.sort(compare('totalCount'))
5198        }
5199
5200        getSampleWeight(count) {
5201            if(this.eventType.value === '1'){
5202                return (count * 100.0 / this.eventInfo.eventCount).toFixed(2) + '%';
5203            }else if(this.eventType.value === '2'){
5204                return count + '';
5205            }else{
5206                return (count / 1000000.0).toFixed(3);
5207            }
5208        }
5209
5210        getProcessName(pid) {
5211            let name = this.processNameMap[pid];
5212            return name ? `${pid} (${name})` : pid.toString();
5213            ;
5214        }
5215
5216        getThreadName(tid) {
5217            let name = this.threadNameMap[tid];
5218            return name ? `${tid} (${name})` : tid.toString();
5219        }
5220
5221        getLibName(fileId) {
5222            return this.symbolsFileList[fileId];
5223        }
5224
5225        getFuncName(funcId) {
5226            return this.SymbolMap[funcId].symbol;
5227        }
5228
5229        get size() {
5230            return this.getAttribute('size') || '';
5231        }
5232
5233        get color() {
5234            return this.getAttribute('color') || '';
5235        }
5236
5237        set size(value) {
5238            this.setAttribute('size', value);
5239        }
5240
5241        set color(value) {
5242            this.setAttribute('color', value);
5243        }
5244
5245        connectedCallback() {
5246            this.suffix = '';
5247            this.loading = this.shadowRoot.getElementById('loading');
5248            this.keyword = this.shadowRoot.getElementById('keyword');
5249            this.eventType = this.shadowRoot.getElementById('typeSelect');
5250            this.pagination = this.shadowRoot.getElementById('pagination');
5251            this.table = this.shadowRoot.getElementById('table');
5252            this.eventType.addEventListener('change',this.updateTableSource.bind(this))
5253            this.pagination.addEventListener('onChange',this.updateTableSource.bind(this))
5254            this.pagination.addEventListener('onShowSizeChange',this.updateTableSource.bind(this))
5255            this.size && (this.size = this.size);
5256            this.color && (this.color = this.color);
5257            this.keyword.addEventListener('input',e=>{
5258                if(this.searchKey != this.keyword.value){
5259                    this.searchKey = this.keyword.value;
5260                    this.pagination.current = 1;
5261                    let ds = this.source.filter(item => item.process.indexOf(this.searchKey) != -1 || item.thread.indexOf(this.searchKey) != -1
5262                        || item.library.indexOf(this.searchKey) != -1 || item.fun.indexOf(this.searchKey) != -1);
5263                    this.pagination.total = ds.length;
5264                    this.table.dataSource = this.paginationHandler(this.pagination.current,parseInt(this.pagination.pageSize),ds);
5265                }
5266            })
5267            this.keyword.addEventListener('onClear',e=>{
5268                this.searchKey = undefined;
5269                this.pagination.current = 1;
5270                this.pagination.total = this.source.length;
5271                this.table.dataSource = this.paginationHandler(this.pagination.current,parseInt(this.pagination.pageSize));
5272            })
5273            this.table.addEventListener("ColumnClick",evt => {
5274                this.sortByColumn(evt.detail)
5275            })
5276        }
5277
5278        sortByColumn(detail){
5279            function compare(property,sort,type) {
5280                return function (a, b) {
5281                    if(type === 'number'){
5282                        return sort === 2 ? b[property] - a[property] : a[property] - b[property];
5283                    }else{
5284                        if(b[property] > a[property]){
5285                            return  sort === 2 ? 1 : -1;
5286                        }else if(b[property] == a[property]){
5287                            return 0;
5288                        }else{
5289                            return  sort === 2 ? -1 : 1;
5290                        }
5291                    }
5292                }
5293            }
5294
5295            console.log(detail.key)
5296            if(detail.key === 'total'){
5297                this.source.sort(compare('totalCount',detail.sort,'number'))
5298            } else if(detail.key === 'self'){
5299                this.source.sort(compare('selfCount',detail.sort,'number'))
5300            } else if(detail.key === 'samples'){
5301                this.source.sort(compare('samples',detail.sort,'number'))
5302            } else {
5303                this.source.sort(compare(detail.key,detail.sort,'string'))
5304            }
5305            this.pagination.current = 1;
5306            this.pagination.total = this.source.length;
5307            this.table.dataSource = this.paginationHandler(this.pagination.current,parseInt(this.pagination.pageSize));
5308        }
5309
5310        updateTableSource(e){
5311            if(e.type == 'change'){
5312                this.eventType.value = e.detail.value
5313                this.suffix = e.detail.value === '3' ? '(in ms)' : '';
5314            }
5315            this.table.dataSource = this.paginationHandler(this.pagination.current,parseInt(this.pagination.pageSize));
5316        }
5317
5318        attributeChangedCallback(name, oldValue, newValue) {
5319            if (name == 'color' && this.loading) {
5320                this.loading.style.color = newValue;
5321            }
5322            if (name == 'size' && this.loading) {
5323                this.loading.style.fontSize = newValue + 'px';
5324            }
5325        }
5326    }
5327    if (!customElements.get('app-simple-table')) {
5328        customElements.define('app-simple-table', AppSimpleTable);
5329    }
5330
5331    (function () {
5332
5333        function createPromise(callback) {
5334            if (callback) {
5335                return new Promise((resolve, _) => callback(resolve));
5336            }
5337            return new Promise((resolve, _) => resolve());
5338        }
5339
5340        function initGlobalObjects() {
5341            let recordData = document.querySelector('#record_data').textContent;
5342            if(recordData.trim().length>0){
5343                return new Promise((resolve, reject) => {
5344                    resolve(JSON.parse(recordData));
5345                })
5346            }else{
5347                return fetch('data.json').then(response => response.json())
5348            }
5349        }
5350        function waitDocumentReady() {
5351            return createPromise((resolve) =>  document.addEventListener("DOMContentLoaded", resolve));
5352        }
5353        createPromise()
5354            .then(waitDocumentReady)
5355            .then(initGlobalObjects)
5356            .then((json) => {
5357                window.data = json;
5358                window.eventIndex = 0;
5359                let eventSelector = document.querySelector('#events')
5360                if (json.recordSampleInfo && json.recordSampleInfo.length > 0) {
5361                    let events = [];
5362                    json.recordSampleInfo.forEach((e, index) => {
5363                        events.push({key:index+'',val:e.eventConfigName})
5364                    })
5365                    eventSelector.dataSource = events;
5366                }
5367                let chart = document.querySelector('#chart-statistics');
5368                let loading = document.querySelector('#loading');
5369                let table = document.querySelector('#sample-table');
5370                let appFunc = document.querySelector('#function');
5371                let flame = document.querySelector('#flame-graph');
5372                let tabs = document.querySelector('#tabs')
5373                let pane4 = document.querySelector('#pane4')
5374                chart.data = json;
5375                table.data = json;
5376                // flame.data = json;
5377                table.addEventListener('onRowClick', e => {
5378                    pane4.hide = false
5379                    tabs.activePane('4')
5380                    appFunc.dataSource = e.detail;
5381                })
5382                tabs.onTabClick = (e) => {
5383                    if (e.detail.key == 3) {
5384                        flame.isFinished = false;
5385                        flame.data = json;
5386                    }
5387                }
5388                eventSelector.addEventListener('change',(e)=>{
5389                    loading.style.display = 'flex'
5390                    pane4.hide = true
5391                    window.eventIndex = parseInt( e.detail.value);
5392                    chart.data = json;
5393                    table.data = json;
5394                    flame.isFinished = false;
5395                    flame.data = json;
5396                    if(tabs.activekey == '4'){
5397                        tabs.activePane('1')
5398                    }
5399                    loading.style.display = 'none'
5400                })
5401            })
5402    }())
5403</script>
5404<div style="width: 100%;height: 100%">
5405    <div style="width: 100%;display: flex;flex-direction: column;align-items: center">
5406        <lit-loading id="loading" size="32" style="display: none"></lit-loading>
5407    </div>
5408    <div style="display: flex;flex-direction: row;align-items: center;padding: 15px">
5409            <span style="font-weight: bold;margin-right: 10px">Event Type :</span>
5410            <lit-select id="events" default-value="0" style="width: 400px"></lit-select>
5411    </div>
5412    <lit-tabs id='tabs' position="top-left" activekey="1" mode="flat">
5413        <lit-tabpane id="pane1" tab="Chart Statistics" key="1">
5414            <app-chart-statistics id="chart-statistics"></app-chart-statistics>
5415        </lit-tabpane>
5416        <lit-tabpane id="pane2" tab="Sample Table" key="2">
5417            <app-simple-table id="sample-table"></app-simple-table>
5418        </lit-tabpane>
5419        <lit-tabpane id="pane3" tab="Flame Graph" key="3">
5420            <app-flame-graph id="flame-graph"></app-flame-graph>
5421        </lit-tabpane>
5422        <lit-tabpane id="pane4" tab="Function" key="4" hide>
5423            <app-function id="function" style="width: 100%"></app-function>
5424        </lit-tabpane>
5425    </lit-tabs>
5426</div>
5427<script id="record_data" type="application/json">
5428