<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Report</title>
    <style>
        * {
            box-sizing: border-box;
        }

        html,
        body {
            height: 100%;
            margin: 0;
            padding: 0;
        }

        lit-tabs {
            padding-top: 10px;
        }

        lit-tabpane {
            padding: 20px;
        }
    </style>
</head>
<body>
<script type="module">
    window.getShadowRoot = (el)=>{
        if (el.parentNode) {
            return window.getShadowRoot(el.parentNode);
        } else {
            return el;
        }
    };
    window.getShadowElement = (el)=>{
        if (el.parentElement) {
            return window.getShadowElement(el.parentElement);
        } else {
            return el;
        }
    };
    class LitIcon extends HTMLElement {
        static get observedAttributes() {
            return ['name', 'size', 'color', 'path'];
        }

        constructor() {
            super();
            const shadowRoot = this.attachShadow({mode: 'open'});
            shadowRoot.innerHTML = `
        <style>
        :host{
            font-size: inherit;
            display: inline-block;
            transition: .3s;
         }
         :host([spin]) {
            animation: rotate 1.75s linear infinite;
         }
         @keyframes rotate {
            to{
                transform: rotate(360deg);
            }
         }
         .icon{
            display: block;
            width: 1em;
            height: 1em;
            margin: auto;
            fill: currentColor;
            overflow: hidden;
         }
        </style>
        <svg style="display: none" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
            <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>
            <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>
            <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>
            <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>
<!--            <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>-->
<!--            <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>-->
        </svg>
        <svg class='icon' id='icon' aria-hidden="true" viewBox="0 0 ${this.view} ${this.view}">
             ${this.path ? '<path id="path"></path>' : '<use id="use"></use>'}
        </svg>
        `;
        }

        get view() {
            return this.getAttribute('view') || 1024;
        }

        get name() {
            return this.getAttribute('name');
        }

        get path() {
            return this.getAttribute('path');
        }

        set name(value) {
            this.setAttribute('name', value);
        }

        set path(value) {
            this.setAttribute('path', value);
        }

        get size() {
            return this.getAttribute('size') || '';
        }

        get color() {
            return this.getAttribute('color') || '';
        }

        set size(value) {
            this.setAttribute('size', value);
        }

        set color(value) {
            this.setAttribute('color', value);
        }

        get spin() {
            return this.hasAttribute('spin');
        }

        set spin(value) {
            if (value) {
                this.setAttribute('spin','');
            } else {
                this.removeAttribute('spin');
            }
        }

        // 当 custom element首次被插入文档DOM时,被调用。
        connectedCallback() {
            this.icon = this.shadowRoot.getElementById('icon');
            this.use = this.shadowRoot.querySelector('use');
            this.d = this.shadowRoot.querySelector('path');
            this.size && (this.size = this.size);
            this.color && (this.color = this.color);
            this.name && (this.name = this.name);
            this.path && (this.path = this.path);
        }

        // 当 custom element从文档DOM中删除时,被调用。
        disconnectedCallback() {

        }

        // 当 custom element被移动到新的文档时,被调用。
        adoptedCallback() {
            console.log('Custom square element moved to new page.');
        }

        // 当 custom element增加、删除、修改自身属性时,被调用。
        attributeChangedCallback(name, oldValue, newValue) {
            if (name === 'name' && this.use) {
                this.use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', `#icon-${newValue}`);
            }
            if (name === 'path' && this.d) {
                this.d.setAttribute('d', newValue);
            }
            if (name === 'color' && this.icon) {
                this.icon.style.color = newValue;
            }
            if (name === 'size' && this.icon) {
                this.icon.style.fontSize = newValue + 'px';
            }
        }
    }
    if (!customElements.get('lit-icon')) {
        customElements.define('lit-icon', LitIcon);
    }

    class LitInput extends HTMLElement {
        static get observedAttributes() {
            return [
                'placeholder',//显示提示文字
                'block',//属性将使按钮适合其父宽度。
                'icon',//图标,如果配置了 slot='prefix' icon将失效
                'bordered',//是否有边框
                'allow-clear',//是否有清除
                'rows',//表示行数,默认input 设置rows 后 显示为textarea
                'maxlength',//允许输入多少个字符 默认没有限制
                'type',//password  number  text
                'pattern',//正则表达式
                'error-text',//错误提示文字
                'error-placement',//错误提示文字方向
                'required',//是否开始验证
                'value'//值
            ];
        }
        get value() {
            return this.getAttribute('value')||'';
        }

        set value(value) {
            this.setAttribute('value',value);
        }
        get required() {
            return this.hasAttribute('required');
        }

        set required(value) {
            if (value) {
                this.setAttribute('required', '');
            } else {
                this.removeAttribute('required');
            }
        }
        get pattern() {
            return this.getAttribute('pattern')||'';
        }

        set pattern(value) {
            this.setAttribute('pattern', value);
        }
        get errorText() {
            return this.getAttribute('error-text')||'该项为必填项';
        }
        set errorText(value) {
            this.setAttribute('error-text',value);
        }
        get errorPlacement() {
            return this.getAttribute('error-placement')||'top';
        }
        set errorPlacement(value) {
            this.setAttribute('error-placement',value);
        }
        get type() {
            return this.getAttribute('type');
        }
        set type(value) {
            this.setAttribute('type', value);
        }
        get maxlength() {
            return this.getAttribute('maxlength')||'';
        }

        set maxlength(value) {
            this.setAttribute('maxlength',value)
        }
        get rows() {
            return this.getAttribute('rows');
        }
        set rows(value) {
            this.setAttribute('rows',value);
        }
        get allowClear() {
            return this.hasAttribute('allow-clear');
        }

        set allowClear(value) {
            if (value) {
                this.setAttribute('allow-clear', '');
            } else {
                this.removeAttribute('allow-clear');
            }
        }

        get bordered() {
            return this.getAttribute('bordered') || 'true';
        }

        set bordered(value) {
            if (value) {
                this.setAttribute('bordered', 'true');
            } else {
                this.setAttribute('bordered', 'false');
            }
        }

        get icon() {
            return this.getAttribute('icon') || null;
        }

        set icon(value) {
            this.setAttribute('icon', value);
        }

        get block() {
            return this.hasAttribute('block');
        }

        set block(value) {
            if (value) {
                this.setAttribute('block', '');
            } else {
                this.removeAttribute('block');
            }
        }

        get placeholder() {
            return this.getAttribute('placeholder') || '';
        }

        set placeholder(value) {
            this.setAttribute('placeholder', value);
        }

        constructor() {
            super();
            const shadowRoot = this.attachShadow({mode: 'open'});
            shadowRoot.innerHTML = `
        <style>
:host{
    ${this.bordered === 'true' ? 'border: 1px solid #e9e9e9;' : ''}
    display: inline-flex;
    box-sizing: border-box;
    position:relative;
    align-items: ${this.rows?'flex-start':'center'};
    transition: all .3s;
    border-radius: 2px;
    font-size: 14px;
    color: #333;
    ${this.block ? 'display: flex;' : ''}
    box-sizing: border-box;
 }
 :host(:hover) {
    ${this.bordered === 'true' ? 'border: 1px solid #65b687;' : ''}
    ${this.bordered === 'true' ? 'box-shadow: 0 0 10px #65b68766;' : ''}
 }
 *{
    box-sizing: border-box;
 }
 .input{
    outline: none;
    border: 0px;
    font-size: inherit;
    color: inherit;
    width: 100%;
    height: 100%;
    vertical-align:middle;
    line-height:inherit;
    height:inherit;
    padding: 6px 6px 6px ${this.icon ? '6px' : '11px'};
    max-height: inherit;
    box-sizing: border-box;
 }
 /*去掉type=number 后面的增减箭头*/
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
    -webkit-appearance: none;

}

input[type='number'] {
    -moz-appearance: textfield;
}

 lit-tips{
    flex: 1;
    height: 100%;
    width: 100%;
 }
 lit-tips{
    flex: 1;
    align-items: center;
 }
:host(:not([allow-clear])) .clear-btn{
    display: flex;
    visibility: hidden;
    transition: all .3s;
    opacity: 0;
}
:host([allow-clear]) .clear-btn{
    opacity: 0;
    position:absolute;
    right: 0;
    top: .5rem;
    visibility: hidden;
    transition: all .3s;
    display: flex;
    margin-right: 6px;
    transform: translateY(0%);
    color: #bfbfbf;
}
:host([allow-clear]) .clear-btn:hover{
    color: #8c8c8c;
}

.area{
    outline: none;
    border: 0px;
    width: 100%;
    font-size: inherit;
    vertical-align:middle;
    min-height: calc(2rem);
    max-height: calc(${this.rows} * 1rem);
    padding: 6px 6px 6px ${this.icon ? '6px' : '11px'};
    box-sizing: border-box;
    resize:vertical;
}

:host(:not([type=password])) .pwd-btn,
:host(:not([type=tel])) .pwd-btn{
    display: none;
    visibility: hidden;
    transition: all .3s;
    opacity: 0;
}
:host([type=password]) .pwd-btn,
:host([type=tel]) .pwd-btn{
    opacity: 1;
    position:absolute;
    right: 0;
    top: .5rem;
    visibility: visible;
    transition: all .3s;
    display: flex;
    margin-right: 6px;
    transform: translateY(0%);
    color: #bfbfbf;
}
/*:host([type=password]) input{*/
/*    -webkit-text-security:none;*/
/*    text-security:none;*/
/*}*/
:host([type=password]) .pwd-btn:hover,
:host([type=tel]) .pwd-btn:hover{
    color: #8c8c8c;
}

</style>
<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>
<lit-tips tips="${this.errorText}" placement="${this.errorPlacement}" color="#f4615c" offset="12px" show="false">
    ${this.hasAttribute('rows')?
                `<textarea class="area" rows="${this.rows}" value="${this.value}" placeholder="${this.placeholder}" cols="27" maxlength="${this.maxlength}" onscroll="this.rows++;"></textarea>`
                :
                `<input type="${this.type}" value="${this.value}" class="input" placeholder="${this.placeholder}"  >`}

    <lit-icon class="clear-btn" name="close-circle-fill"></lit-icon>
    <lit-icon class="pwd-btn" name="eye-fill"></lit-icon>
</lit-tips>
<slot name="suffix" ></slot>
        `;
        }

        // 当 custom element首次被插入文档DOM时,被调用。
        connectedCallback() {
            this.reg = new RegExp(this.pattern);
            this.inputElement = this.shadowRoot.querySelector('.input');
            this.areaElement = this.shadowRoot.querySelector('.area');
            this.clearElement = this.shadowRoot.querySelector('.clear-btn');
            this.pwdElement = this.shadowRoot.querySelector('.pwd-btn');

            this.pwdElement.onclick=(e)=>{
                if (this.inputElement.getAttribute('type')==='password') {
                    this.pwdElement.name = 'eyeclose-fill';
                    this.inputElement.setAttribute('type','tel');
                } else if (this.inputElement.getAttribute('type')==='tel') {
                    this.inputElement.setAttribute('type','password');
                    this.pwdElement.name = 'eye-fill';
                }
            }

            if (this.areaElement) {
                this.clearElement.onclick=e=>{
                    this.areaElement.value = '';
                    this.clearElement.style.visibility = 'hidden';
                    this.clearElement.style.opacity = '0';
                    this.value=this.areaElement.value;
                    this.dispatchEvent(new CustomEvent('onClear',e));
                    this.clearError();
                };
                this.areaElement.oninput=e=>{
                    if (this.allowClear) {
                        if (this.areaElement.value.length>0) {
                            this.clearElement.style.visibility = 'visible';
                            this.clearElement.style.opacity = '1';
                        } else {
                            this.clearElement.style.visibility = 'hidden';
                            this.clearElement.style.opacity = '0';
                        }
                    }
                    this.value=this.areaElement.value;
                    this.verify();
                    this.dispatchEvent(new CustomEvent('input',e));
                };
                this.areaElement.onchange=e=>{
                    this.value=this.areaElement.value;
                    this.verify();
                    this.dispatchEvent(new CustomEvent('change',e));
                };
                this.areaElement.onfocus=e=>{
                    this.value=this.areaElement.value;
                    this.verify();
                    this.dispatchEvent(new CustomEvent('focus',e));
                };
                this.areaElement.onblur=e=>{
                    this.value=this.areaElement.value;
                    this.dispatchEvent(new CustomEvent('blur',e));
                };
                this.areaElement.onkeydown=e=>{
                    if (e.key==='Enter') {
                        this.value=this.areaElement.value;
                        this.verify();
                        this.dispatchEvent(new CustomEvent('onPressEnter',e));
                    }
                    this.dispatchEvent(new CustomEvent('keydown',e));
                };
                this.areaElement.onkeyup=e=>{
                    this.dispatchEvent(new CustomEvent('keyup',e));
                };
                this.areaElement.onselect=e=>{
                    this.dispatchEvent(new CustomEvent('select',e));
                };
                this.areaElement.onclick=e=>{
                    this.dispatchEvent(new CustomEvent('click',e));
                };
            }
            if (this.inputElement) {
                this.clearElement.onclick=e=>{
                    this.inputElement.value = '';
                    this.clearElement.style.visibility = 'hidden';
                    this.clearElement.style.opacity = '0';
                    this.value=this.inputElement.value;
                    this.dispatchEvent(new CustomEvent('onClear',e));
                    this.clearError();
                };
                this.inputElement.oninput=e=>{
                    if (this.allowClear) {
                        if (this.inputElement.value.length>0) {
                            this.clearElement.style.visibility = 'visible';
                            this.clearElement.style.opacity = '1';
                        } else {
                            this.clearElement.style.visibility = 'hidden';
                            this.clearElement.style.opacity = '0';
                        }
                    }
                    this.value=this.inputElement.value;
                    this.verify();
                    this.dispatchEvent(new CustomEvent('input',e));
                };
                this.inputElement.onchange=e=>{
                    this.value=this.inputElement.value;
                    this.verify();
                    this.dispatchEvent(new CustomEvent('change',e));
                };
                this.inputElement.onfocus=e=>{
                    this.value=this.inputElement.value;
                    this.verify();
                    this.dispatchEvent(new CustomEvent('focus',e));
                };
                this.inputElement.onblur=e=>{
                    this.dispatchEvent(new CustomEvent('blur',e));
                };
                this.inputElement.onkeydown=e=>{
                    if (e.key==='Enter') {
                        this.value=this.inputElement.value;
                        this.verify();
                        this.dispatchEvent(new CustomEvent('onPressEnter',e));
                    }
                    this.dispatchEvent(new CustomEvent('keydown',e));
                };
                this.inputElement.onkeyup=e=>{
                    this.dispatchEvent(new CustomEvent('keyup',e));
                };
                this.inputElement.onselect=e=>{
                    this.dispatchEvent(new CustomEvent('select',e));
                };
                this.inputElement.onclick=e=>{
                    this.dispatchEvent(new CustomEvent('click',e));
                };
            }

        }

        // 当 custom element从文档DOM中删除时,被调用。
        disconnectedCallback() {

        }

        // 当 custom element被移动到新的文档时,被调用。
        adoptedCallback() {
            console.log('Custom square element moved to new page.');
        }

        // 当 custom element增加、删除、修改自身属性时,被调用。
        attributeChangedCallback(name, oldValue, newValue) {
            if (name === 'value') {
                if (this.inputElement) {
                    this.inputElement.value=newValue;
                } else if (this.areaElement) {
                    this.areaElement.value=newValue;
                }
            }
        }
        verify() {
            if (this.required) {
                let result;
                if (this.hasAttribute('rows')) {
                    result= this.reg.test(this.areaElement.value);
                } else {
                    result= this.reg.test(this.inputElement.value);
                }
                if (result) {
                    this.shadowRoot.querySelector('lit-tips').show='false';
                } else {
                    this.shadowRoot.querySelector('lit-tips').show='true';
                }
                return result;
            } else {
                return true;
            }
        }
        clearError() {
            this.shadowRoot.querySelector('lit-tips').show='false';
        }
    }
    if (!customElements.get('lit-input')) {
        customElements.define('lit-input', LitInput);
    }

    class LitLoading extends HTMLElement {
        static get observedAttributes() { return ['color','size']; }

        constructor() {
            super();
            const shadowRoot = this.attachShadow({ mode: 'open' });
            shadowRoot.innerHTML = `
        <style>
        :host{
            font-size:inherit;
            display:inline-flex;
            align-items: center;
            justify-content:center;
            color:var(--themeColor,#42b983);
        }
        .loading{
            display: block;
            width: 1em;
            height: 1em;
            margin: auto;
            animation: rotate 1.4s linear infinite;
        }
        .circle {
            stroke: currentColor;
            animation:  progress 1.4s ease-in-out infinite;
            stroke-dasharray: 80px, 200px;
            stroke-dashoffset: 0px;
            transition:.3s;
        }
        :host(:not(:empty)) .loading{
            margin:.5em;
        }
        @keyframes rotate{
            to{
                transform: rotate(360deg);
            }
        }
        @keyframes progress {
            0% {
              stroke-dasharray: 1px, 200px;
              stroke-dashoffset: 0px;
            }
            50% {
              stroke-dasharray: 100px, 200px;
              stroke-dashoffset: -15px;
            }
            100% {
              stroke-dasharray: 100px, 200px;
              stroke-dashoffset: -125px;
            }
        }
        </style>
        <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>
        <slot></slot>
        `;
        }

        get size() {
            return this.getAttribute('size')||'';
        }

        get color() {
            return this.getAttribute('color')||'';
        }

        set size(value) {
            this.setAttribute('size', value);
        }

        set color(value) {
            this.setAttribute('color', value);
        }

        connectedCallback() {
            this.loading = this.shadowRoot.getElementById('loading');
            this.size && (this.size = this.size);
            this.color && (this.color = this.color);
        }

        attributeChangedCallback (name, oldValue, newValue) {
            if ( name === 'color' && this.loading) {
                this.loading.style.color = newValue;
            }
            if ( name === 'size' && this.loading) {
                this.loading.style.fontSize = newValue + 'px';
            }
        }
    }
    if (!customElements.get('lit-loading')) {
        customElements.define('lit-loading', LitLoading);
    }

    class LitPagination extends HTMLElement {
        static get observedAttributes() {
            return [
                'current',// 当前页码
                'total',// 总条数
                'page-size',// 每页条数
                'disabled',// 禁用分页
                'show-size-changer',// 显示每页条目数select
                'show-quick-jumper',// 显示跳至多少页
                'page-size-options',// 指定每页可以显示多少条 默认 [10,20,50,100]
                'simple'// 简洁模式
            ];
        }
        get pageSizeOptions() {
            return this.getAttribute('page-size-options');
        }
        set pageSizeOptions(value) {
            this.setAttribute('page-size-options', '');
        }

        get current() {
            return this.getAttribute('current') || '1';
        }

        set current(value) {
            this.setAttribute('current', value);
        }

        get total() {
            return this.getAttribute('total') || '50';
        }

        set total(value) {
            this.setAttribute('total', value);
        }

        get pageSize() {
            return this.getAttribute('page-size') || '10';
        }

        set pageSize(value) {
            this.setAttribute('page-size', value);
        }

        get disabled() {
            return this.hasAttribute('disabled');
        }

        set disabled(value) {
            if (value) {
                this.setAttribute('disabled', '');
            } else {
                this.removeAttribute('disabled');
            }
        }

        get showSizeChanger() {
            return this.hasAttribute('show-size-changer');
        }

        set showSizeChanger(value) {
            if (value) {
                this.setAttribute('show-size-changer', '');
            } else {
                this.removeAttribute('show-size-changer');
            }
        }

        get showQuickJumper() {
            return this.hasAttribute('show-quick-jumper')
        }

        set showQuickJumper(value) {
            if (value) {
                this.setAttribute('show-quick-jumper', '');
            } else {
                this.removeAttribute('show-quick-jumper');
            }
        }

        get simple() {
            return this.hasAttribute('simple');
        }

        set simple(value) {
            if (value) {
                this.setAttribute('simple', '');
            } else {
                this.removeAttribute('simple');
            }
        }

        constructor() {
            super();
            const shadowRoot = this.attachShadow({mode: 'open'});
            shadowRoot.innerHTML = `
<style>
:host{
     display: flex;
     width: max-content;
}
.root{
    display: inline-flex;
    /*grid-template-columns: repeat(auto-fill,35px);*/
    /*column-gap: 8px;*/
    /*row-gap: 8px;*/
    user-select: none;
}
.item{
    box-sizing: border-box;
    color: #333;
    transition: all .3s;
    width: 35px;
    height: 35px;
    margin-left: 6px;
    padding: 6px 10px;
    border: 1px solid #ececec;
    border-radius: 3px;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.item-dir{
    color: #333;
    transition: all .3s;
    padding: 5px 10px;
    /*border: 1px solid #ececec;*/
    /*border-radius: 3px;*/
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.item:not([disable]):hover{
    color:#42b983;
    border: 1px solid #42b983;
}
.item[selected]{
    color:#42b983;
    border: 1px solid #42b983;
}
.item[disable]{
    /*background-color: #f5f5f5;*/
    fill: #c7c7c7;
    color: #c7c7c7;
    cursor: not-allowed;
}

:host([show-quick-jumper]) .jump-root{
    grid-column: span 4;
    margin-left: 6px;
    display: inline-flex;
    align-items: center;
}
:host(:not([show-quick-jumper])) .jump-root{
    display: none;
}

:host([show-size-changer]) .pages-change{
    display: inline-flex;
    grid-column: span 3;
    width: 120px;
    margin-left: 6px;
    font-size: .9rem;
}
:host(:not([show-size-changer])) .pages-change{
    display: none;
}
</style>
<div style="display: grid;grid-template-columns: max-content 1fr;">
    <div style="display: inline-flex;align-items: center" id="showTotal">
        <slot id="st" name="showTotal"></slot>
    </div>
    <div class="root">
<!--        <lit-icon class="item left-arrow" name="left" ></lit-icon>-->
        <svg class="item left-arrow" viewBox="0 0 1024 1024" aria-hidden="true" >
            <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>
        </svg>
        <div class="item first">1</div>
        <lit-icon class="item-dir double-left" name="ellipsis" ></lit-icon>
<!--        <svg class="item-dir double-left" viewBox="0 0 1024 1024" aria-hidden="true" style="width: 16px;width: 16px;">-->
<!--            <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>-->
<!--        </svg>-->
        <div class="item one">2</div>
        <div class="item two">3</div>
        <div class="item three">4</div>
        <div class="item four">5</div>
        <div class="item five">6</div>
        <lit-icon class="item-dir double-right" name="ellipsis" ></lit-icon>
<!--        <svg class="item-dir double-right" viewBox="0 0 1024 1024" aria-hidden="true" style="width: 16px;width: 16px;">-->
<!--            <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>-->
<!--        </svg>-->
        <div class="item last">1</div>
<!--        <lit-icon class="item right-arrow" name="right"></lit-icon>-->
        <svg class="item right-arrow" viewBox="0 0 1024 1024" aria-hidden="true" >
            <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>
        </svg>
        <lit-select class="pages-change" default-value="10"></lit-select>
        <div class="jump-root">
            <label style="font-size: .9rem;color: #333;margin-right: 5px">跳至</label>
            <lit-input type="number" class="jump" style="width: 80px;height: 100%"></lit-input>
            <label style="font-size: .9rem;color: #333;margin-left: 5px">页</label>
        </div>
    </div>

</div>

        `;
        }

        // 当 custom element首次被插入文档DOM时,被调用。
        connectedCallback() {
            this.slotShowTotal=null;
            this.rootElement = this.shadowRoot.querySelector('.root');
            let st = this.shadowRoot.querySelector('#st');
            st.addEventListener('slotchange',()=>{
                let elements = st.assignedElements();
                if (elements.length>0) {
                    this.slotShowTotal = elements[0];
                }
                if (this.slotShowTotal) {
                    let cloneNode = this.slotShowTotal.render({
                        total: this._total,
                        range: [1,this._pages],
                    }).content.cloneNode(true);
                    this.shadowRoot.querySelector('#showTotal').append(cloneNode);
                }
            });
            this.leftArrow = this.shadowRoot.querySelector('.left-arrow');
            this.first = this.shadowRoot.querySelector('.first');
            this.doubleLeft = this.shadowRoot.querySelector('.double-left');
            this.one = this.shadowRoot.querySelector('.one');
            this.two = this.shadowRoot.querySelector('.two');
            this.three = this.shadowRoot.querySelector('.three');
            this.four = this.shadowRoot.querySelector('.four');
            this.five = this.shadowRoot.querySelector('.five');
            this.doubleRight = this.shadowRoot.querySelector('.double-right');
            this.last = this.shadowRoot.querySelector('.last');
            this.rightArrow = this.shadowRoot.querySelector('.right-arrow');
            this.pagesChange = this.shadowRoot.querySelector('.pages-change');
            this.jump = this.shadowRoot.querySelector('.jump');
            this.nodes = [this.one, this.two, this.three, this.four, this.five];

            let jsonArray = JSON.parse(this.pageSizeOptions);
            if (jsonArray) {
                this.pagesChange.dataSource=jsonArray.map(a=>{
                    return {key:a, val:`${a} 条/页`,};
                });
                this.pagesChange.value = jsonArray[0]+'';
                this.pageSize = jsonArray[0]+'';
            } else {
                this.pagesChange.dataSource=[10,20,50,100].map(a=>{
                    return {key:a, val:`${a} 条/页`,};
                });
                this.pagesChange.value ='10';
                this.pageSize = '10';
            }

            this.jump.addEventListener('onPressEnter',e=>{
                if (e.target.value) {
                    this.current=e.target.value;
                    e.target.value = '';
                    this.match();
                }
            });
            this.pagesChange.onchange = e => {
                this.pageSize = e.detail.value;
                this.match();
                if (this.slotShowTotal) {
                    let cloneNode = this.slotShowTotal.render({
                        total: this._total,
                        range: [1,this._pages],
                    }).content.cloneNode(true);
                    this.shadowRoot.querySelector('#showTotal').lastElementChild.remove();
                    this.shadowRoot.querySelector('#showTotal').append(cloneNode);
                }
                this.dispatchEvent(new CustomEvent('onShowSizeChange',{
                    detail:{
                        current:parseInt(this.current),
                        size:parseInt(this.pageSize)
                    }
                }));
            };

            this.leftArrow.onclick = (e) => {
                if (this._current > 1) {
                    this.current = `${this._current - 1}`;
                    this.match();
                }
            };
            this.rightArrow.onclick = (e) => {
                if (this._current < this._pages) {
                    this.current = `${this._current + 1}`;
                    this.match();
                }
            };
            let nodeClickHandler = e => {
                this.current = `${e.currentTarget.val}`;
                this.match();
            };
            this.first.onclick = nodeClickHandler;
            this.nodes.forEach(a => a.onclick = nodeClickHandler);
            this.last.onclick = nodeClickHandler;
            this.doubleLeft.onmouseover = e => {
                e.target.name = 'doubleleft';
            };
            this.doubleLeft.onmouseout = e => {
                e.target.name = 'ellipsis'
            };
            this.doubleLeft.onclick = e => {
                let k = this._current - 5;
                if (k < 1) k = 1;
                this.current = `${k}`;
                this.match();
            };
            this.doubleRight.onmouseover = e => {
                e.target.name = 'doubleright';
            };
            this.doubleRight.onmouseout = e => {
                e.target.name = 'ellipsis'
            };
            this.doubleRight.onclick = e => {
                let k = this._current + 5;
                if (k > this._pages) k = this._pages;
                this.current = `${k}`;
                this.match();
            };
            this.match();
        }

        match() {
            this._current = parseInt(this.current);
            this._total = parseInt(this.total);
            this._pageSize = parseInt(this.pageSize);
            this._pages = Math.ceil(this._total / this._pageSize);
            if (this._current>this._pages) {
                this._current = this._pages;
                this.current = `${this._pages}`;
            } else if (this._current<1) {
                this._current = 1;
                this.current = `1`;
            }
            // 是否展示 pageSize 切换器,当 total 大于 50 时默认为 true
            // if (this._total>50) this.setAttribute('show-size-changer', '');

            // console.log(`${this._total} ${this._current}/${this._pages} ${this._pageSize}`);
            if (this._current === 1) {
                this.leftArrow.setAttribute('disable', '');
            } else {
                this.leftArrow.removeAttribute('disable');
            }
            if (this._current === this._pages) {
                this.rightArrow.setAttribute('disable', '');
            } else {
                this.rightArrow.removeAttribute('disable');
            }
            this.hiddenNode(this.first, this.last, this.one, this.two, this.three, this.four, this.five,
                            this.doubleLeft, this.doubleRight);
            if (this._pages <= 5) {
                for (let i = 0; i < this._pages; i++) {
                    this.displayNode(this.nodes[i]);
                    this.item(this.nodes[i], i + 1);
                }
            } else if (this._pages === 6) {
                this.displayNode(this.first);
                this.item(this.first, 1);
                for (let i = 0; i < this._pages; i++) {
                    this.displayNode(this.nodes[i]);
                    this.item(this.nodes[i], i + 2);
                }
            } else {
                this.displayNode(this.one, this.two, this.three, this.four, this.five);
                if (this._current - 3 > 1 && this._current + 3 < this._pages) { // 左边溢出 右边溢出
                    this.displayNode(this.first, this.last, this.doubleLeft, this.doubleRight);
                    this.item(this.first, 1);
                    this.item(this.last, this._pages);
                    this.item(this.one, this._current - 2);
                    this.item(this.two, this._current - 1);
                    this.item(this.three, this._current);
                    this.item(this.four, this._current + 1);
                    this.item(this.five, this._current + 2);
                } else if (this._current - 3 === 1 && this._current + 3 < this._pages) {//左边刚好 右边溢出
                    this.displayNode(this.first, this.last, this.doubleRight);
                    this.item(this.first, 1);
                    this.item(this.last, this._pages);
                    for (let i = 0; i < this.nodes.length; i++) {
                        this.item(this.nodes[i], i + 2);
                    }
                } else if (this._current - 3 < 1 && this._current + 3 < this._pages) {  //左边不够 右边溢出
                    this.displayNode(this.last, this.doubleRight);
                    this.item(this.last, this._pages);
                    for (let i = 0; i < this.nodes.length; i++) {
                        this.item(this.nodes[i], i + 1);
                    }
                } else if (this._current - 3 > 1 && this._current + 3 === this._pages) {// 左边溢出 右边刚好
                    this.displayNode(this.first, this.last, this.doubleLeft);
                    this.item(this.first, 1);
                    this.item(this.last, this._pages);
                    this.item(this.nodes[0], this._pages - 5);
                    this.item(this.nodes[1], this._pages - 4);
                    this.item(this.nodes[2], this._pages - 3);
                    this.item(this.nodes[3], this._pages - 2);
                    this.item(this.nodes[4], this._pages - 1);
                } else if (this._current - 3 === 1 && this._current + 3 === this._pages) {// 左边刚好 右边刚好
                    this.displayNode(this.first, this.last);
                    this.item(this.first, 1);
                    for (let i = 0; i < this._pages; i++) {
                        this.displayNode(this.nodes[i]);
                        this.item(this.nodes[i], i + 2);
                    }
                    this.item(this.last, 7);
                } else if (this._current - 3 < 1 && this._current + 3 === this._pages) {// 左边不够 右边刚好
                    this.displayNode(this.last);
                    this.item(this.last, this._pages);
                    for (let i = 0; i < this.nodes.length; i++) {
                        this.item(this.nodes[i], i + 1);
                    }
                } else if (this._current - 3 > 1 && this._current + 3 > this._pages) { //左边溢出 右边不够
                    this.displayNode(this.first, this.doubleLeft)
                    this.item(this.first, 1);
                    this.item(this.nodes[0], this._pages - 4);
                    this.item(this.nodes[1], this._pages - 3);
                    this.item(this.nodes[2], this._pages - 2);
                    this.item(this.nodes[3], this._pages - 1);
                    this.item(this.nodes[4], this._pages - 0);
                } else if (this._current - 3 === 1 && this._current + 3 > this._pages) { //左边刚好 右边不够
                    this.displayNode(this.first);
                    this.item(this.first, 1);
                    this.item(this.nodes[0], this._pages - 4);
                    this.item(this.nodes[1], this._pages - 3);
                    this.item(this.nodes[2], this._pages - 2);
                    this.item(this.nodes[3], this._pages - 1);
                    this.item(this.nodes[4], this._pages - 0);
                } else if (this._current - 3 < 1 && this._current + 3 > this._pages) { //左边不够 右边不够
                    //限定了 pages>6 这种情况不存在
                }
            }
        }

        item(el, val) {
            el.val = val;
            el.textContent = val;
            if (val === this._current) {
                el.setAttribute('selected', '');
            } else {
                el.removeAttribute('selected');
            }
        }

        displayNode() {
            [...arguments].forEach(a => a.style.display = 'flex');
        }

        hiddenNode(n) {
            [...arguments].forEach(a => a.style.display = 'none');
        }

        // 当 custom element从文档DOM中删除时,被调用。
        disconnectedCallback() {
        }

        // 当 custom element被移动到新的文档时,被调用。
        adoptedCallback() {
        }

        // 当 custom element增加、删除、修改自身属性时,被调用。
        attributeChangedCallback(name, oldValue, newValue) {
            if (name === 'current') {
                this.dispatchEvent(new CustomEvent('onChange', {
                    detail: {
                        page: parseInt(newValue),
                        pageSize: this._pageSize
                    }
                }));
            } else if (name === 'total') {
                this.dispatchEvent(new CustomEvent('onChange', {
                    detail: {
                        total: parseInt(newValue),
                        current: this._current,
                        pageSize: this._pageSize
                    }
                }));
                this.match();
            }

        }
    }
    if (!customElements.get('lit-pagination')) {
        customElements.define('lit-pagination', LitPagination);
    }

    class LitPieChart extends HTMLElement {
        static get observedAttributes() { return []; }

        constructor() {
            super();
            const shadowRoot = this.attachShadow({ mode: 'open' });
            shadowRoot.innerHTML = `
        <style>
        :host{
            font-size:inherit;
            display:inline-flex;
            align-items: center;
            justify-content:center;
            color:#42b983;
        }
        </style>
        <div style="display: flex;flex-direction: row;width: 100%;padding: 15px">
            <div style="display: flex;flex-direction: column;align-items: center;width: 40%">
                <div id="chartTitle" style="width:auto;font-size: 20px;margin-bottom: 15px;text-overflow: ellipsis;white-space: nowrap"></div>
                <canvas id="chartView" width="200" height="200" ></canvas>
            </div>
            <div id="labelDiv" style="margin-top: 45px">
                <div id="legendDiv"></div>
                <div id="pageOptionDiv" style="display: none;flex-direction: row;margin-top: 15px">
                    <div id="previous" style="cursor: pointer">previous</div>
                    <div id="page" style="margin-left: 10px;margin-right: 10px">1/9</div>
                    <div id="next" style="cursor: pointer">next</div>
                </div>
            </div>
            <div id="tip" style="display: none;position: absolute;z-index: 999;width: auto;height: auto;background-color: #fff;
                    border-radius: 3px;border:1px solid #eee;box-shadow: 0px 0px 2px 2px #aaa;padding: 10px">
                <div id="tipName" style="width: auto;font-weight: bold;margin-bottom: 10px"></div>
                <div id="tipValue" style="width: auto;font-weight: bold"></div>
            </div>
        </div>
        <slot></slot>
        `;
        }

        get dataSource() {
            return this.ds || [];
        }

        set dataSource(value) {
            this.ds = value;
            if (this.ds) {
                this.page = 0;
                let p = parseInt((this.ds.length / this.pageSize).toString());
                this.totalPage = this.ds.length % this.pageSize > 0 ? (p + 1) : p;
                if (this.totalPage > 9) {
                    this.totalPage = 9;
                }
                let tempAngel = -1 / 4 * 2 * Math.PI; // 饼图的起始角度
                this.ds.forEach(item=>{
                    item.startAngel = tempAngel; // 起始弧度
                    item.angel = item.value * 2 * Math.PI;
                    item.endAngel = (tempAngel + item.angel); //结束弧度
                    if (item.endAngel > Math.PI * 3 / 2) {
                        item.endAngel = Math.PI * 3 / 2;
                    }
                    tempAngel += item.angel;
                });
                this.updateOptionStatus();
                this.addChartLegend();
            }
            this.renderChart();
        }

        get title() {
            return this.ct || '';
        }

        set title(value) {
            this.ct = value;
            if (value) {
                this.chartTitle.innerText = value.length > 50 ? value.slice(0,49)+'...' : value;
            }
        }


        connectedCallback() {
            this.pageSize = 14;
            this.page = 0;
            this.chartView = this.shadowRoot.getElementById('chartView');
            this.chartView.width = window.devicePixelRatio * this.chartView.width;
            this.chartView.height = window.devicePixelRatio * this.chartView.height;
            this.chartTitle = this.shadowRoot.getElementById('chartTitle');
            this.labelDiv = this.shadowRoot.getElementById('legendDiv');
            this.tip = this.shadowRoot.getElementById('tip');
            this.tipName = this.shadowRoot.getElementById('tipName');
            this.tipValue = this.shadowRoot.getElementById('tipValue');
            this.pageOptionDiv = this.shadowRoot.getElementById('pageOptionDiv');
            this.previousBt = this.shadowRoot.getElementById('previous');
            this.pageDiv = this.shadowRoot.getElementById('page');
            this.nextBt = this.shadowRoot.getElementById('next');
            this.previousBt.addEventListener('click',this.previousPage.bind(this));
            this.nextBt.addEventListener('click',this.nextPage.bind(this));
            this.chartView.addEventListener('mousemove',this.mouseMove.bind(this));
            this.chartView.addEventListener('click',this.mouseClick.bind(this));
            this.chartView.addEventListener('mouseout',this.mouseOut.bind(this));
        }

        mouseMove(event) {
            const mousePos = this.getMousePost(event);
            const result = this.containPoint(mousePos);
            if (result) {
                this.tip.style.left = (event.clientX + 40) + 'px';
                this.tip.style.top = (event.clientY - 40) + 'px';
                this.tip.style.display = 'flex';
                this.tip.style.flexDirection = 'column';
                this.tipName.innerText = result.name;
                this.tipValue.innerText = result.time + ' (' + (result.value * 100).toFixed(1) + '%)';
            } else {
                this.tip.style.display = 'none';
                if (this.selectItem !== null) {
                    this.selectItem = undefined;
                    this.renderChart();
                }
            }
        }

        mouseOut(event) {
            this.tip.style.display = 'none';
            if (this.selectItem !== null) {
                this.selectItem = undefined;
                this.renderChart();
            }
        }

        mouseClick(event) {
            if (this.selectItem && this.hasOwnProperty('chartClickListener')) {
                this.chartClickListener(this.selectItem);
            }
        }

        attributeChangedCallback (name, oldValue, newValue) {

        }

        // clientX,clientY
        // 判断鼠标在 canvas 的位置
        getMousePost(event) {
            // 获取鼠标的位置
            const { clientX, clientY } = event;
            //  获取 canvas 的边界位置
            const { top, left } = this.chartView.getBoundingClientRect();
            //  计算鼠标在 canvas 在位置
            const x = (clientX - left);
            const y = (clientY - top);
            return { x, y };
        }

        //  判断是不是在 canvas上
        containPoint(mousePos) {
            let selector = undefined;
            let centerX = this.centerX;
            let centerY = this.centerY;
            const [subX,subY] = [centerX - mousePos.x,centerY - mousePos.y];
            // 圆心到鼠标 的位置
            const len = Math.sqrt(subX * subX + subY * subY);
            // 判断是否在圆内
            const inChart = len < this.chartRadius;
            // 判断是不是在 startAngle 和 endAngle
            if (inChart) {
                if (this.ds) {
                    let angle = Math.atan2(centerY - mousePos.y, centerX - mousePos.x) * (180 / Math.PI);
                    let pointAngle = 0;
                    if (angle >= 90) {
                        pointAngle = -(180 - angle);
                    } else if (angle >= 0 && angle < 90) {
                        pointAngle = 270 + angle;
                    } else if (angle < 0 && angle >= -90) {
                        pointAngle = 270 + angle;
                    } else {
                        pointAngle = 90 + 180 + angle;
                    }
                    let pa = pointAngle / 180 * Math.PI;
                    if (pa > 0) {
                        pa = pa - Math.PI / 2;
                    }
                    for (let item of this.ds) {
                        if (pa >= item.startAngel && pa < item.endAngel) {
                            selector = item;
                            if (item !== this.selectItem) {
                                this.selectItem = item;
                                this.renderChart();
                            }
                            break;
                        }
                    }
                }
            }
            return selector;
        }

        renderChart() {
            if (this.ds) {
                let context = this.chartView.getContext('2d');
                // 清除画布
                context.clearRect(0,0,this.chartView.width,this.chartView.height);
                this.centerX = this.chartView.width / 2;
                this.centerY = this.chartView.height / 2; // 圆心坐标
                let labelX,labelY; // label 文字绘制位置
                let radius = this.chartView.height / 2 - 10; // 原型半径
                this.chartRadius = radius;
                let offset = radius / 6;
                let size = this.ds.length;
                this.ds.forEach(item => {
                    if (item === this.selectItem) {
                        context.beginPath();
                        context.moveTo(this.centerX,this.centerY);
                        context.arc(this.centerX,this.centerY,radius + 5,item.startAngel,item.endAngel);
                        context.fillStyle = this.colorRgbWithAlpha(item.color);
                        context.fill();
                        context.closePath();
                    }
                    context.beginPath();
                    context.moveTo(this.centerX,this.centerY);
                    context.arc(this.centerX,this.centerY,radius,item.startAngel,item.endAngel);
                    context.fillStyle = item.color;
                    context.fill();
                    if (size > 1) {
                        context.strokeStyle = '#ffffff';
                        context.stroke();
                    }
                    if (item.value > 0.045) {
                        let text = (item.value * 100).toFixed(1) + '%';
                        context.font = '13px Microsoft Yahei';
                        context.moveTo(this.centerX,this.centerY);
                        context.fillStyle = '#ffffff';
                        let textWidth = context.measureText(text).width;
                        if (size === 1) {
                            context.fillText(text,this.centerX - textWidth / 2,this.centerY);
                        } else {
                            let textAngel = item.startAngel + item.angel * 0.5; // 文字角度
                            labelX = this.centerX + Math.cos(textAngel) * (radius - offset);
                            labelY = this.centerY + Math.sin(textAngel) * (radius - offset);
                            context.fillText(text,labelX - textWidth / 2,labelY);
                        }
                    }
                    context.closePath();
                })
            }
        }

        addChartLegend() {
            this.labelDiv.innerText = '';
            if (this.ds.length <= 15) {
                this.pageOptionDiv.style.display = 'none';
                this.ds.forEach(item=>{
                    this.labelDiv.appendChild(this.createChartLegend(item));
                });
            } else {
                this.pageOptionDiv.style.display = 'flex';
                for (let i = this.page * this.pageSize; i < (this.page + 1) * this.pageSize; i++) {
                    if (i < this.ds.length) {
                        this.labelDiv.appendChild(this.createChartLegend(this.ds[i]));
                    } else {
                        break;
                    }
                }
                if (this.page === 9 && this.ds.length > 126) {
                    this.labelDiv.appendChild(this.createChartLegend(this.ds[this.ds.length - 1]));
                }
            }
            this.pageDiv.innerText = `${this.page + 1}/${this.totalPage}`;
        }

        previousPage() {
            if (this.page > 0) {
                this.page = this.page - 1;
            }
            this.addChartLegend();
            this.updateOptionStatus();
        }

        nextPage() {
            if (this.page < this.totalPage - 1) {
                this.page = this.page + 1;
            }
            this.addChartLegend();
            this.updateOptionStatus();
        }

        updateOptionStatus() {
            if (this.page === 0) {
                this.previousBt.setAttribute('disabled','true');
                this.previousBt.style.color = '#999';
            } else {
                this.previousBt.style.color = '#42b983';
                this.previousBt.removeAttribute('disabled');
            }
            if (this.page + 1 === this.totalPage) {
                this.nextBt.style.color = '#999';
                this.nextBt.setAttribute('disabled','true');
            } else {
                this.nextBt.style.color = '#42b983';
                this.nextBt.removeAttribute('disabled');
            }
        }

        createChartLegend(item) {
            let legend = document.createElement('div');
            legend.style.display = 'flex';
            legend.style.alignItems = 'center';
            legend.style.marginBottom = '5px';
            legend.style.cursor = 'pointer';
            let icon = document.createElement('div');
            icon.style.backgroundColor = item.color;
            icon.style.borderRadius = '5px';
            icon.style.width = '10px';
            icon.style.height = '10px';
            icon.style.marginRight = '10px';
            let span = document.createElement('span');
            span.style.fontSize = '14px';
            span.style.width = '800px';
            span.style.whiteSpace = 'nowrap';
            span.style.textOverflow = 'ellipsis';
            span.style.overflow = 'hidden';
            span.innerText = item.name;
            legend.appendChild(icon);
            legend.appendChild(span);
            legend.addEventListener('mouseover',e => {
                this.selectItem = item;
                this.renderChart();
            });
            legend.addEventListener('click',e => {
                this.selectItem = item;
                this.mouseClick(e);
            });
            legend.addEventListener('mouseout',e => {
                this.selectItem = undefined;
                this.renderChart();
            });
            return legend;
        }

        colorRgbWithAlpha(sColor) {
            let reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
            sColor = sColor.toLowerCase();
            if (sColor && reg.test(sColor)) {
                if (sColor.length === 4) {
                    let sColorNew = '#';
                    for (let i=1; i<4; i+=1) {
                        sColorNew += sColor.slice(i,i+1).concat(sColor.slice(i,i+1));
                    }
                    sColor = sColorNew;
                }
                // 处理六位的颜色值
                let sColorChange = [];
                for (let i=1; i<7; i+=2) {
                    sColorChange.push(parseInt('0x'+sColor.slice(i,i+2)));
                }
                sColorChange.push(0.6);
                return `rgb(${sColorChange[0]},${sColorChange[1]},${sColorChange[2]},${sColorChange[3]})`;
            } else {
                return sColor;
            }
        };
    }
    if (!customElements.get('lit-pie-chart')) {
        customElements.define('lit-pie-chart', LitPieChart);
    }

    class LitSelect extends HTMLElement {
        static get observedAttributes() {
            return [
                'value',// 默认值
                'default-value',// 默认值
                'placeholder',//placeholder
                'disabled',
                'loading',// 是否处于加载状态
                'allow-clear',// 是否允许清除
                'show-search',// 是否允许搜索
                'list-height',// 设置弹窗滚动高度 默认256px
                'border',// 是否显示边框
                'mode',// mode='multiple'多选
            ];
        }

        get value() {
            return this.getAttribute('value') || this.defaultValue;
        }

        set value(value) {
            this.setAttribute('value', value);
        }

        get border() {
            return this.getAttribute('border') || 'true';
        }

        set border(value) {
            if (value) {
                this.setAttribute('border', 'true');
            } else {
                this.setAttribute('border', 'false');
            }
        }

        get listHeight() {
            return this.getAttribute('list-height') || '256px';
        }

        set listHeight(value) {
            this.setAttribute('list-height', value);
        }

        get defaultPlaceholder() {
            return this.getAttribute('placeholder') || '请选择';
        }

        get showSearch() {
            return this.hasAttribute('show-search');
        }

        set defaultValue(value) {
            this.setAttribute('default-value', value);
        }

        get defaultValue() {
            return this.getAttribute('default-value') || '';
        }

        set placeholder(value) {
            this.setAttribute('placeholder', value);
        }

        get placeholder() {
            return this.getAttribute('placeholder') || this.defaultPlaceholder;
        }

        get loading() {
            return this.hasAttribute('loading');
        }

        set loading(value) {
            if (value) {
                this.setAttribute('loading', '');
            } else {
                this.removeAttribute('loading');
            }
        }

        constructor() {
            super();
            const shadowRoot = this.attachShadow({mode: 'open'});
            shadowRoot.innerHTML = `
        <style>
:host{
    display: inline-flex;
    position: relative;
    overflow: visible;
    cursor: pointer;
    transition: all .3s;
    border-radius: 2px;
    outline: none;
    -webkit-user-select:none ;
    -moz-user-select:none;
    user-select:none;
    /*width: 100%;*/
}
:host(:not([border])),
:host([border='true']) {
    border: 1px solid #dcdcdc;
}
input{
    border: 0;
    outline: none;
    background-color: transparent;
    cursor: pointer;
    transition: all .3s;
    -webkit-user-select:none ;
    -moz-user-select:none;
    user-select:none;
    display: inline-flex;
}
:host(:not([mode]))  input{
    width: 100%;
}
:host([mode])  input{
    padding: 6px 0px;
}
:host([mode])  .root{
    padding: 1px 8px;
}
.root{
    position: relative;
    padding: 6px 8px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    transition: all .3s;
    border-radius: 2px;
    background-color: #fff;
    outline: none;
    font-size: 1rem;
    z-index: 2;
    -webkit-user-select:none ;
    -moz-user-select:none;
    user-select:none;
    width: 100%;
}
.body{
    max-height: ${this.listHeight};
    position: absolute;
    top: 100%;
    z-index: 99;
    padding-top: 5px;
    margin-top: 2px;
    background-color: #fff;
    width: 100%;
    transition: all 0.2s;
    transform: scaleY(.6);
    visibility: hidden;
    opacity: 0;
    transform-origin: top center;
    display: block;
    flex-direction: column;
    box-shadow: 0 5px 15px 0px #00000033;
    border-radius: 2px;
    overflow: auto;
}
.icon{
    pointer-events: none;
}
.noSelect{
  -webkit-touch-callout:none; /* iOS Safari */
  -webkit-user-select:none;
  -khtml-user-select:none;    /* Konqueror */
  -moz-user-select:none;      /* Firefox */
  -ms-user-select:none;       /* Internet Explorer/Edge */
  user-select:none;           /* Non-prefixed version */
}

:host(:not([border]):not([disabled]):focus),
:host([border='true']:not([disabled]):focus),
:host(:not([border]):not([disabled]):hover),
:host([border='true']:not([disabled]):hover) {
    border:1px solid #42b983
}
:host(:not([disabled]):focus) .body,
:host(:not([disabled]):focus-within) .body{
    transform: scaleY(1);
    opacity: 1;
    z-index: 99;
    visibility: visible;
}
:host(:not([disabled]):focus)  input{
    color: #bebebe;
}
:host(:not([border])[disabled]) *,
:host([border='true'][disabled]) *{
    background-color: #f5f5f5;
    color: #b7b7b7;
    cursor: not-allowed;
}
:host([border='false'][disabled]) *{
    color: #b7b7b7;
    cursor: not-allowed;
}
:host([loading]) .loading{
    display: flex;
}
:host([loading]) .icon{
    display: none;
}
:host(:not([loading])) .loading{
    display: none;
}
:host(:not([loading])) .icon{
    display: flex;
}
:host(:not([allow-clear])) .clear{
    display: none;
}
.clear{
    display: none;
    color: #bfbfbf;
}
.clear:hover{
    color: #8c8c8c;
}
.search{
    display: none;
    color: #bfbfbf;
}
.multipleRoot{
    display: flex;
    flex-direction: column;
    flex-wrap: wrap;
    flex-flow: wrap;
    align-items: center;
    width: 100%;
}
.tag{
    display: inline-flex;
    align-items: center;
    background-color: #f5f5f5;
    padding: 1px 4px;
    height: auto;
    font-size: .75rem;
    font-weight: bold;
    color: #242424;
    overflow: auto;
    position: relative;
    margin-right: 4px;
    margin-top: 1px;
    margin-bottom: 1px;
}
.tag-close{
    font-size: .8rem;
    padding: 2px;
    margin-left: 0px;
    color: #999999;
}
.tag-close:hover{
    color: #333;
}

</style>
<div class="root noSelect" tabindex="0" hidefocus="true">
    <div class="multipleRoot">
        <input placeholder="${this.placeholder}" style="" autocomplete="off" ${this.showSearch ? '' : 'readonly'} tabindex="0">
    </div><!--多选-->
    <lit-loading class="loading" size="12"></lit-loading>
    <!--<lit-icon class='icon' name='down' color="#c3c3c3"></lit-icon>-->
    <svg class='icon' viewBox="0 0 1024 1024" aria-hidden="true" style="width: 16px;width: 16px;fill: #c3c3c3">
        <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>
    </svg>
<!--    <lit-icon class="clear" name='close-circle-fill'></lit-icon>-->
    <svg class="clear" viewBox="0 0 1024 1024" aria-hidden="true" style="width: 16px;width: 16px;">
        <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>
    </svg>
<!--    <lit-icon class="search" name='search'></lit-icon>-->
    <svg class="search" viewBox="0 0 1024 1024" aria-hidden="true" style="width: 16px;width: 16px;">
        <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>
    </svg>
</div>
<div class="body">
    <slot></slot>
    <slot name="footer"></slot>
</div>
        `;
        }

        isMultiple() {
            return this.hasAttribute('mode') && this.getAttribute('mode') === 'multiple';
        }

        newTag(value, text) {
            let tag = document.createElement('div');
            let icon = document.createElement('lit-icon');
            icon.classList.add('tag-close');
            icon.name = 'close';
            let span = document.createElement('span');
            tag.classList.add('tag');
            span.dataset['value'] = value;
            span.textContent = text;
            tag.append(span);
            tag.append(icon);
            icon.onclick = ev => {
                tag.parentElement.removeChild(tag);
                this.querySelector(`lit-select-option[value=${value}]`).removeAttribute('selected');
                if (this.shadowRoot.querySelectorAll('.tag').length === 0) {
                    this.inputElement.style.width = 'auto';
                    this.inputElement.placeholder = this.defaultPlaceholder;
                }
                ev.stopPropagation();
            }
            tag.value = value;
            tag.dataset['value'] = value;
            tag.text = text;
            tag.dataset['text'] = text;
            return tag;
        }

        // 当 custom element首次被插入文档DOM时,被调用。
        connectedCallback() {
            this.tabIndex = 0;// 设置当前组件为可以获取焦点
            this.focused = false;
            this.inputElement = this.shadowRoot.querySelector('input');
            this.inputElement.style.width = '100%';
            this.clearElement = this.shadowRoot.querySelector('.clear');
            this.iconElement = this.shadowRoot.querySelector('.icon');
            this.searchElement = this.shadowRoot.querySelector('.search');
            this.multipleRootElement = this.shadowRoot.querySelector('.multipleRoot');
            // console.log(this.multipleRootElement);
            // 点击清理 清空input值,展示placeholder,
            this.clearElement.onclick = ev => {
                if (this.isMultiple()) {
                    let delNodes = [];
                    this.multipleRootElement.childNodes.forEach(a => {
                        if (a.tagName === 'DIV') {
                            delNodes.push(a);
                        }
                    });
                    for (let i = 0; i < delNodes.length; i++) {
                        delNodes[i].remove();
                    }
                    if (this.shadowRoot.querySelectorAll('.tag').length === 0) {
                        this.inputElement.style.width = 'auto';
                        this.inputElement.placeholder = this.defaultPlaceholder;
                    }
                }
                this.querySelectorAll('lit-select-option').forEach(a => a.removeAttribute('selected'));
                this.inputElement.value = '';
                this.clearElement.style.display = 'none';
                this.iconElement.style.display = 'flex';
                this.blur();
                ev.stopPropagation();// 这里不会因为点击清理而触发 选择栏目显示或者隐藏
                this.dispatchEvent(new CustomEvent('onClear', {detail: ev}));// 向外派发清理事件
            }
            // 初始化时遍历所有的option节点
            this.initOptions();
            // 当前控件点击时 如果时select本身 需要显示 或 隐藏选择栏目,通过this.focused变量控制(默认为false)
            this.onclick = ev => {
                if (ev.target.tagName === 'LIT-SELECT') {
                    if (!this.focused) {
                        this.inputElement.focus();
                        this.focused = true;
                    } else {
                        this.blur();
                        this.focused = false;
                    }
                }
            };
            this.onmouseover = this.onfocus = ev => {
                if (this.hasAttribute('allow-clear')) {
                    if (this.inputElement.value.length > 0 ||
                        this.inputElement.placeholder !== this.defaultPlaceholder) {
                        this.clearElement.style.display = 'flex';
                        this.iconElement.style.display = 'none';
                    } else {
                        this.clearElement.style.display = 'none';
                        this.iconElement.style.display = 'flex';
                    }
                }
            };
            this.onmouseout = this.onblur = ev => {
                if (this.hasAttribute('allow-clear')) {
                    this.clearElement.style.display = 'none';
                    this.iconElement.style.display = 'flex';
                }
                this.focused = false;
            }
            // 输入框获取焦点时,value值 暂存于 placeholder  然后value值清空
            // 这样值会以placeholder形式灰色展示,鼠标位于第一个字符
            this.inputElement.onfocus = ev => {
                if (this.hasAttribute('disabled')) return;// 如果控件处于disabled状态 直接忽略
                if (this.inputElement.value.length > 0) {
                    this.inputElement.placeholder = this.inputElement.value;
                    this.inputElement.value = '';
                }
                if (this.hasAttribute('show-search')) {// 如果有show-search属性 需要显示放大镜,隐藏向下的箭头
                    this.searchElement.style.display = 'flex';
                    this.iconElement.style.display = 'none';
                }
                // input获取焦点时显示所有可选项,相当于清理了搜索结果
                this.querySelectorAll('lit-select-option').forEach(a => {
                    a.style.display = 'flex';
                })
            }
            // 当输入框失去焦点的时候 placeholder 的值 保存到value上,input显示值
            this.inputElement.onblur = ev => {
                if (this.hasAttribute('disabled')) return;// 如果控件处于disabled状态 直接忽略
                if (this.isMultiple()) {
                    // 如果有show-search属性 失去焦点需要 隐藏放大镜图标,显示默认的向下箭头图标
                    if (this.hasAttribute('show-search')) {
                        this.searchElement.style.display = 'none';
                        this.iconElement.style.display = 'flex';
                    }
                } else {
                    // 如果placeholder为 请输入(默认值)不做处理
                    if (this.inputElement.placeholder !== this.defaultPlaceholder) {
                        this.inputElement.value = this.inputElement.placeholder; // placeholder 保存的值放入 value中
                        this.inputElement.placeholder = this.defaultPlaceholder;// placeholder 值为 默认值(请输入)
                    }
                    // 如果有show-search属性 失去焦点需要 隐藏放大镜图标,显示默认的向下箭头图标
                    if (this.hasAttribute('show-search')) {
                        this.searchElement.style.display = 'none';
                        this.iconElement.style.display = 'flex';
                    }
                }
            }
            // 输入框每次文本变化 会匹配搜索的option 显示或者隐藏,达到搜索的效果
            this.inputElement.oninput = ev => {
                let els = [...this.querySelectorAll('lit-select-option')];
                if (!ev.target.value) {
                    els.forEach(a => a.style.display = 'flex');
                } else {
                    els.forEach(a => {
                        let value = a.getAttribute('value');
                        if (value.toLowerCase().indexOf(ev.target.value.toLowerCase()) !== -1 ||
                            a.textContent.toLowerCase().indexOf(ev.target.value.toLowerCase()) !== -1) {
                            a.style.display = 'flex';
                        } else {
                            a.style.display = 'none';
                        }
                    })
                }
            }
            // 输入框按下回车键,自动输入当前搜索出来的第一行,及display!='none'的第一个,搜索会隐藏其他行
            this.inputElement.onkeydown = ev => {
                if (ev.key === 'Backspace') {
                    if (this.isMultiple()) {
                        let tag = this.multipleRootElement.lastElementChild.previousElementSibling;
                        if (tag) {
                            console.log(tag.value);
                            this.querySelector(`lit-select-option[value=${tag.value}]`).removeAttribute('selected');
                            tag.remove();
                            if (this.shadowRoot.querySelectorAll('.tag').length === 0) {
                                this.inputElement.style.width = 'auto';
                                this.inputElement.placeholder = this.defaultPlaceholder;
                            }
                        }
                    } else {
                        this.clear();
                        this.dispatchEvent(new CustomEvent('onClear', {detail: ev}));// 向外派发清理事件
                    }
                } else if (ev.key === 'Enter') {
                    let filter =
                        [...this.querySelectorAll('lit-select-option')].filter(a => a.style.display !== 'none');
                    if (filter.length > 0) {
                        this.inputElement.value = filter[0].textContent;
                        this.inputElement.placeholder = filter[0].textContent;
                        this.blur();
                        this.dispatchEvent(new CustomEvent('change', {
                            detail: {
                                selected: true,
                                value: filter[0].getAttribute('value'),
                                text: filter[0].textContent
                            }
                        }));// 向外层派发change事件,返回当前选中项
                    }
                }
            };
        }

        initOptions() {
            this.querySelectorAll('lit-select-option').forEach(a => {
                // 如果节点的值为 当前控件的默认值 defalut-value则 显示该值对应的option文本
                if (this.isMultiple()) {
                    a.setAttribute('check', '');
                    if (a.getAttribute('value') === this.defaultValue) {
                        let tag = this.newTag(a.getAttribute('value'), a.textContent);
                        this.multipleRootElement.insertBefore(tag, this.inputElement);
                        this.inputElement.placeholder = '';
                        this.inputElement.value = '';
                        this.inputElement.style.width = '1px';
                        a.setAttribute('selected', '');
                    }
                } else {
                    if (a.getAttribute('value') === this.defaultValue) {
                        this.inputElement.value = a.textContent;
                        a.setAttribute('selected', '');
                    }
                }
                // 每个option设置onSelected事件 接受当前点击的option
                a.addEventListener('onSelected', (e) => {
                    // 所有option设置为未选中状态
                    if (this.isMultiple()) {//多选
                        if (a.hasAttribute('selected')) {
                            let tag = this.shadowRoot.querySelector(`div[data-value=${e.detail.value}]`);
                            tag.parentElement.removeChild(tag);
                            e.detail.selected = false;
                        } else {
                            let tag = this.newTag(e.detail.value, e.detail.text);
                            this.multipleRootElement.insertBefore(tag, this.inputElement);
                            this.inputElement.placeholder = '';
                            this.inputElement.value = '';
                            this.inputElement.style.width = '1px';
                        }
                        if (this.shadowRoot.querySelectorAll('.tag').length === 0) {
                            this.inputElement.style.width = 'auto';
                            this.inputElement.placeholder = this.defaultPlaceholder;
                        }
                        this.inputElement.focus();
                    } else {// 单选
                        [...this.querySelectorAll('lit-select-option')].forEach(a => a.removeAttribute('selected'));
                        this.blur();// 失去焦点,隐藏选择栏目列表
                        this.inputElement.value = e.detail.text;
                    }
                    // 设置当前option为选择状态
                    if (a.hasAttribute('selected')) {
                        a.removeAttribute('selected');
                    } else {
                        a.setAttribute('selected', '');
                    }
                    // 设置input的值为当前选择的文本
                    // 向外层派发change事件,返回当前选中项
                    this.dispatchEvent(new CustomEvent('change', {detail: e.detail}));
                });
            });
        }

        // js调用清理选项
        clear() {
            this.inputElement.value = '';
            this.inputElement.placeholder = this.defaultPlaceholder;
        }

        // 重置为默认值
        reset() {
            this.querySelectorAll('lit-select-option').forEach(a => {
                // 如果节点的值为 当前控件的默认值 defalut-value则 显示该值对应的option文本
                [...this.querySelectorAll('lit-select-option')].forEach(a => a.removeAttribute('selected'));
                if (a.getAttribute('value') === this.defaultValue) {
                    this.inputElement.value = a.textContent;
                    a.setAttribute('selected', '');
                }
            });
        }

        // 当 custom element从文档DOM中删除时,被调用。
        disconnectedCallback() {

        }

        // 当 custom element被移动到新的文档时,被调用。
        adoptedCallback() {
            console.log('Custom square element moved to new page.');
        }

        // 当 custom element增加、删除、修改自身属性时,被调用。
        attributeChangedCallback(name, oldValue, newValue) {
            if (name === 'value' && this.inputElement) {
                if (newValue) {
                    [...this.querySelectorAll('lit-select-option')].forEach(a => {
                        if (a.getAttribute('value') === newValue) {
                            a.setAttribute('selected', '');
                            this.inputElement.value = a.textContent;
                        } else {
                            a.removeAttribute('selected');
                        }
                    });
                } else {
                    this.clear();
                }
            }
        }

        set dataSource(value) {
            value.forEach(a => {
                let option = document.createElement('lit-select-option');
                option.setAttribute('value', a.key);
                option.textContent = a.val;
                this.append(option);
            })
            this.initOptions();
        }

    }
    if (!customElements.get('lit-select')) {
        customElements.define('lit-select', LitSelect);
    }

    class LitSelectGroup extends HTMLElement {
        static get observedAttributes() {
            return ['label'];
        }

        get label() {
            return this.getAttribute('label') || '';
        }

        set label(value) {
            this.setAttribute('label', value);
        }

        constructor() {
            super();
            const shadowRoot = this.attachShadow({mode: 'open'});
            shadowRoot.innerHTML = `
        <style>
        :host{
            display: flex;
            flex-direction: column;
            /*padding-left: 10px;*/
        }
        .lab{
            padding: 8px 10px 8px 10px;
            font-size: .5rem;
            color: #8c8c8c;
        }
        ::slotted(lit-select-option) {
            padding-left: 20px;
        }
        </style>
        <div class='lab'>${this.label}</div>
        <slot></slot>
        `;
        }

        // 当 custom element首次被插入文档DOM时,被调用。
        connectedCallback() {

        }

        // 当 custom element从文档DOM中删除时,被调用。
        disconnectedCallback() {

        }

        // 当 custom element被移动到新的文档时,被调用。
        adoptedCallback() {
            console.log('Custom square element moved to new page.');
        }

        // 当 custom element增加、删除、修改自身属性时,被调用。
        attributeChangedCallback(name, oldValue, newValue) {

        }
    }
    if (!customElements.get('lit-select-group')) {
        customElements.define('lit-select-group', LitSelectGroup);
    }

    class LitSelectOption extends HTMLElement {
        static get observedAttributes() {
            return ['selected','disabled','check'];
        }

        constructor() {
            super();
            const shadowRoot = this.attachShadow({mode: 'open'});
            shadowRoot.innerHTML = `
        <style>
        :host{
            display: flex;
            padding: 8px 10px;
            transition: all .3s;
            color: #333;
            tab-index: -1;
            overflow: scroll;
            align-items: center;
            justify-content: space-between;
        }
        :host(:not([disabled])[selected]) {
            background-color: #e9f7fe;
            font-weight: bold;
        }
        :host(:not([disabled]):not([selected]):hover) {
            background-color: #f5f5f5;
        }
        :host([disabled]) {
            cursor: not-allowed;
            color: #bfbfbf;
        }
        :host([selected][check]) .check{
             display: flex;
        }
        :host(:not([selected])) .check{
             display: none;
        }
        :host(:not([check])) .check{
            display: none;
        }
        </style>
        <slot></slot>
        <lit-icon class='check' name='check'></lit-icon>
        `;
        }

        // 当 custom element首次被插入文档DOM时,被调用。
        connectedCallback() {
            if (!this.hasAttribute('disabled')) {
                this.onclick=ev => {
                        this.dispatchEvent(new CustomEvent('onSelected', {
                            detail: {
                            selected:true,
                            value: this.getAttribute('value'),
                            text: this.textContent
                            }
                        }));
                };
            }
        }

        // 当 custom element从文档DOM中删除时,被调用。
        disconnectedCallback() {

        }

        // 当 custom element被移动到新的文档时,被调用。
        adoptedCallback() {
            console.log('Custom square element moved to new page.');
        }

        // 当 custom element增加、删除、修改自身属性时,被调用。
        attributeChangedCallback(name, oldValue, newValue) {

        }
    }
    if (!customElements.get('lit-select-option')) {
        customElements.define('lit-select-option', LitSelectOption);
    }

    class LitTable extends HTMLElement {
        static get observedAttributes() {
            return ['scroll-y', 'selectable','defaultOrderColumn'];
        }

        get selectable() {
            return this.hasAttribute('selectable');
        }

        set selectable(value) {
            if (value) {
                this.setAttribute('selectable', '');
            } else {
                this.removeAttribute('selectable');
            }
        }

        get scrollY() {
            return this.getAttribute('scroll-y') || 'auto';
        }

        set scrollY(value) {
            this.setAttribute('scroll-y', value);
        }

        get dataSource() {
            return this.ds || [];
        }

        set dataSource(value) {
            this.ds = value;
            if (this.hasAttribute('tree')) {
                this.renderTreeTable();
            } else {
                this.renderTable();
            }
        }

        constructor() {
            super();
            const shadowRoot = this.attachShadow({mode: 'open'});
            shadowRoot.innerHTML = `
<style>
:host{
    display: grid;
    grid-template-columns: repeat(1,1fr);
    overflow: auto;
    /*width: 500px;*/
    width: 100%;
    height: 100%;
}
.tr{
    display: grid;
    transition: all .3s;
}
.tr:nth-of-type(even) {
    background-color: #fcfcfc;
}
/*.tr:not(:last-of-type):not(:first-of-type) {*/
/*    border-top: 1px solid #f0f0f0;*/
/*}*/
/*.tr:last-of-type{*/
/*    border-top: 1px solid #f0f0f0;*/
/*    border-bottom: 1px solid #f0f0f0;*/
/*}*/
.tr{
    background-color: #fff;
}
.tr:hover{
    background-color: #f3f3f3; /*antd #fafafa 42b983*/
}
.td{
    background-color: inherit;
    box-sizing: border-box;
    padding: 10px;
    display: flex;
    justify-content: flex-start;
    align-items: center;
    width: 100%;
    height: auto;
    /*overflow: auto;*/
    border-left: 1px solid #f0f0f0;
}
.td-order{
    /*background: green;*/
}
.td-order:before{

}
.td:last-of-type{
    border-right: 1px solid #f0f0f0;
}
.table{
     color: #262626;
}
:host(:not([noheader])) .thead{
    display: grid;
    position: sticky;
    top: 0;
    font-weight: bold;
    font-size: .9rem;
    color: #fff;
    /*width: 100%;*/
    background-color: #42b983;
    z-index: 1;
}
/*配置有 noheader 表示不限时表头,tbody上添加 border-top*/
:host([noheader]) .thead{
    display: none;
    position: sticky;
    top: 0;
    font-weight: bold;
    font-size: .9rem;
    color: #fff;
    /*width: 100%;*/
    background-color: #42b983;
    z-index: 1;
}
:host([noheader]) .tbody{
    border-top: 1px solid #f0f0f0;
}

.tbody{
    width: 100%;
    height: ${this.scrollY};
    display: grid;
    grid-template-columns: 1fr;
    row-gap: 1px;
    column-gap: 1px;
    background-color: #f0f0f0;
    border-bottom: 1px solid #f0f0f0;
    /*overflow:  auto;*/
    ${this.scrollY === 'auto' ? '' : 'overflow-y: auto'};
}
.th{
    display: grid;
    background-color: #42b983;
    /*position: sticky;*/
    /*top: 0;*/
}

.tree-icon{
    font-size: 1.2rem;
    width: 20px;
    height: 20px;
    padding-right: 5px;
    padding-left: 5px;
    cursor: pointer;
}
.tree-icon:hover{
    color: #42b983;
}
.row-checkbox,row-checkbox-all{

}

.up-svg{
    position: absolute;
    right: 5px;
    top: 8px;
    width: 15px;
    height: 15px;
}
.down-svg{
    position: absolute;
    right: 5px;
    bottom: 8px;
    width: 15px;
    height: 15px;
}
</style>

<slot id="slot" style="display: none"></slot>
<div class="table">
    <div class="thead"></div>
    <div class="tbody"></div>
</div>
        `;
        }

        /*根据column[]嵌套结构得到 grid css布局描述*/

        // 当 custom element首次被插入文档DOM时,被调用。
        connectedCallback() {
            this.st = this.shadowRoot.querySelector('#slot');
            this.tableElement = this.shadowRoot.querySelector('.table');
            this.theadElement = this.shadowRoot.querySelector('.thead');
            this.tbodyElement = this.shadowRoot.querySelector('.tbody');
            this.tableColumns = this.querySelectorAll('lit-table-column');
            this.colCount = this.tableColumns.length;
            this.st.addEventListener('slotchange', (event) => {
                this.theadElement.innerHTML = '';
                setTimeout(() => {
                    this.columns = this.st.assignedElements();

                    let rowElement = document.createElement('div');
                    rowElement.classList.add('th');
                    if (this.selectable) {
                        let box = document.createElement('div');
                        box.style.display = 'flex';
                        box.style.justifyContent = 'center';
                        box.style.alignItems = 'center';
                        box.style.gridArea = '_checkbox_';
                        box.classList.add('td');
                        box.style.backgroundColor = '#ffffff66';
                        let checkbox = document.createElement('lit-checkbox');
                        checkbox.classList.add('row-checkbox-all');
                        checkbox.onchange = e => {
                            this.shadowRoot.querySelectorAll('.row-checkbox').forEach(a => a.checked = e.detail.checked);
                            if (e.detail.checked) {
                                this.shadowRoot.querySelectorAll('.tr').forEach(a => a.setAttribute('checked', ''));
                            } else {
                                this.shadowRoot.querySelectorAll('.tr').forEach(a => a.removeAttribute('checked'));
                            }
                        };

                        box.appendChild(checkbox);
                        rowElement.appendChild(box);
                    }

                    let area = [], gridTemplateColumns = [];
                    let resolvingArea = (columns, x, y) => {
                        columns.forEach((a, i) => {
                            if (!area[y]) area[y] = [];
                            let key = a.getAttribute('key') || a.getAttribute('title');
                            if (a.tagName === 'LIT-TABLE-GROUP') {
                                let len = a.querySelectorAll('lit-table-column').length;
                                let children = [...a.children].filter(a => a.tagName !== 'TEMPLATE');
                                if (children.length > 0) {
                                    resolvingArea(children, x, y + 1);
                                }
                                for (let j = 0; j < len; j++) {
                                    area[y][x] = {x, y, t: key};
                                    x++;
                                }
                                let h = document.createElement('div');
                                h.classList.add('td');
                                h.style.justifyContent = a.getAttribute('align');
                                h.style.borderBottom = '1px solid #f0f0f0';
                                h.style.gridArea = key;
                                h.innerText = a.title;
                                if (a.hasAttribute('fixed')) {
                                    this.fixed(h, a.getAttribute('fixed'), '#42b983');
                                }
                                rowElement.append(h);
                            } else if (a.tagName === 'LIT-TABLE-COLUMN') {
                                area[y][x] = {x, y, t: key};
                                x++;
                                let h = document.createElement('div');
                                h.classList.add('td');
                                if (a.hasAttribute('order')) {
                                    h.sortType = 0;
                                    h.classList.add('td-order');
                                    h.style.position = 'relative';
                                    let NS = 'http://www.w3.org/2000/svg';
                                    let upSvg = document.createElementNS(NS,'svg');
                                    let upPath = document.createElementNS(NS,'path');
                                    upSvg.setAttribute('fill', '#efefef');
                                    upSvg.setAttribute('viewBox', '0 0 1024 1024');
                                    upSvg.setAttribute('stroke', '#000000');
                                    upSvg.classList.add('up-svg');
                                    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');

                                    upSvg.appendChild(upPath);
                                    let downSvg = document.createElementNS(NS,'svg');
                                    let downPath = document.createElementNS(NS,'path');
                                    downSvg.setAttribute('fill', '#efefef');
                                    downSvg.setAttribute('viewBox', '0 0 1024 1024');
                                    downSvg.setAttribute('stroke', '#efefef');
                                    downSvg.classList.add('down-svg');
                                    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');
                                    downSvg.appendChild(downPath);
                                    if (i === 0) {
                                        h.sortType = 2; // 默认以第一列 降序排序 作为默认排序
                                        upSvg.setAttribute('fill', '#efefef');
                                        downSvg.setAttribute('fill', '#333');
                                    }
                                    h.appendChild(upSvg);
                                    h.appendChild(downSvg);
                                    h.onclick = ev => {
                                        this.shadowRoot.querySelectorAll('.td-order svg').forEach(it=>{
                                            it.setAttribute('fill', '#efefef');
                                            it.setAttribute('fill', '#efefef');
                                            it.sortType = 0;
                                        });
                                        if (h.sortType === undefined || h.sortType === null) {
                                            h.sortType = 0;
                                        } else if (h.sortType === 2) {
                                            h.sortType = 0;
                                        } else {
                                            h.sortType += 1;
                                        }
                                        switch (h.sortType) {
                                            case 1:
                                                upSvg.setAttribute('fill', '#333');
                                                downSvg.setAttribute('fill', '#efefef');
                                                break;
                                            case 2:
                                                upSvg.setAttribute('fill', '#efefef');
                                                downSvg.setAttribute('fill', '#333');
                                                break;
                                            default:
                                                upSvg.setAttribute('fill', '#efefef');
                                                downSvg.setAttribute('fill', '#efefef');
                                                break;
                                        };
                                        this.dispatchEvent(new CustomEvent('ColumnClick', {
                                            detail: {
                                                sort: h.sortType, key: key
                                            }, composed: true
                                        }));
                                    };
                                }
                                h.style.justifyContent = a.getAttribute('align');
                                gridTemplateColumns.push(a.getAttribute('width') || '1fr');
                                h.style.gridArea = key;
                                let titleLabel = document.createElement('label');
                                titleLabel.textContent = a.title;
                                h.appendChild(titleLabel);
                                if (a.hasAttribute('fixed')) {
                                    this.fixed(h, a.getAttribute('fixed'), '#42b983');
                                }
                                rowElement.append(h);
                            }
                        });
                    };
                    resolvingArea(this.columns, 0, 0);
                    area.forEach((rows, j, array) => {
                        for (let i = 0; i < this.colCount; i++) {
                            if (!rows[i]) rows[i] = array[j - 1][i];
                        }
                    });

                    this.gridTemplateColumns = gridTemplateColumns.join(' ');
                    if (this.selectable) {
                        let s = area.map(a => '"_checkbox_ ' + (a.map(aa => aa.t).join(' ')) + '"').join(' ');
                        // `repeat(${this.colCount},1fr)`
                        rowElement.style.gridTemplateColumns = '60px ' + gridTemplateColumns.join(' ');
                        rowElement.style.gridTemplateRows = `repeat(${area.length},1fr)`;
                        rowElement.style.gridTemplateAreas = s;
                    } else {
                        let s = area.map(a => '"' + (a.map(aa => aa.t).join(' ')) + '"').join(' ');
                        // `repeat(${this.colCount},1fr)`
                        rowElement.style.gridTemplateColumns = gridTemplateColumns.join(' ');
                        rowElement.style.gridTemplateRows = `repeat(${area.length},1fr)`;
                        rowElement.style.gridTemplateAreas = s;
                    }
                    this.theadElement.append(rowElement);
                    if (this.hasAttribute('tree')) {
                        this.renderTreeTable();
                    } else {
                        this.renderTable();
                    }
                });

            });
        }

        // 当 custom element从文档DOM中删除时,被调用。
        disconnectedCallback() {

        }

        // 当 custom element被移动到新的文档时,被调用。
        adoptedCallback() {
            console.log('Custom square element moved to new page.');
        }

        // 当 custom element增加、删除、修改自身属性时,被调用。
        attributeChangedCallback(name, oldValue, newValue) {

        }

        fixed(td, placement, bgColor, zIndex) {
            td.style.position = 'sticky';
            if (placement === 'left') {
                td.style.left = '0px';
                td.style.boxShadow = '3px 0px 5px #33333333';
            } else if (placement === 'right') {
                td.style.right = '0px';
                td.style.boxShadow = '-3px 0px 5px #33333333';
            }
        }

        /*渲染成表格*/
        renderTable() {
            let that = this;
            if (!this.columns) return;
            if (!this.ds) return; // 如果没有设置数据源,直接返回
            this.tbodyElement.innerHTML = '';// 清空表格内容
            this.ds.forEach(rowData => {
                let rowElement = document.createElement('div');
                rowElement.classList.add('tr');
                rowElement.data = rowData;
                let gridTemplateColumns = [];
                // 如果table配置了selectable(选择行模式) 单独在行头部添加一个 checkbox
                if (this.selectable) {
                    let box = document.createElement('div');
                    box.style.display = 'flex';
                    box.style.justifyContent = 'center';
                    box.style.alignItems = 'center';
                    box.classList.add('td');
                    let checkbox = document.createElement('lit-checkbox');
                    checkbox.classList.add('row-checkbox');
                    checkbox.onchange = (e) => {// checkbox 的是否选中 会影响  行对应的 div上是否有 checked属性,用于标记
                        if (e.detail.checked) {
                            rowElement.setAttribute('checked', '');
                        } else {
                            rowElement.removeAttribute('checked');
                        }
                    };
                    box.appendChild(checkbox);
                    rowElement.appendChild(box);
                }
                this.tableColumns.forEach(cl => {
                    let dataIndex = cl.getAttribute('data-index');
                    gridTemplateColumns.push(cl.getAttribute('width') || '1fr');
                    if (cl.template) {// 如果自定义渲染,从模版中渲染得到节点
                        let cloneNode = cl.template.render(rowData).content.cloneNode(true);
                        let d = document.createElement('div');
                        d.classList.add('td');
                        d.style.justifyContent = cl.getAttribute('align');
                        if (cl.hasAttribute('fixed')) {
                            this.fixed(d, cl.getAttribute('fixed'), '#ffffff');
                        }
                        d.append(cloneNode);
                        rowElement.append(d);
                    } else {
                        let td = document.createElement('div');
                        td.classList.add('td');
                        td.style.justifyContent = cl.getAttribute('align');
                        if (cl.hasAttribute('fixed')) {
                            this.fixed(td, cl.getAttribute('fixed'), '#ffffff');
                        }

                        td.innerHTML =
                            `<code style='padding:0;margin:0'>${rowData[dataIndex].toString().replace('\n','')}</code>`;
                        rowElement.append(td);
                    }

                });
                if (this.selectable) { // 如果 带选择的table 前面添加一个 60px的列
                    // `repeat(${this.colCount},1fr)`
                    rowElement.style.gridTemplateColumns = '60px ' + gridTemplateColumns.join(' ');
                } else {
                    // `repeat(${this.colCount},1fr)`
                    rowElement.style.gridTemplateColumns = gridTemplateColumns.join(' ');
                }
                rowElement.onclick = e => {
                    this.dispatchEvent(new CustomEvent('onRowClick', {detail: rowData, composed: true}));
                };
                this.tbodyElement.append(rowElement);
            });
        }

        /*渲染树表结构*/
        renderTreeTable() {
            if (!this.columns) return;
            if (!this.ds) return;
            this.tbodyElement.innerHTML = '';
            /*通过list 构建 tree 结构*/
            let ids = JSON.parse(this.getAttribute('tree') || `['id','pid']`);
            let toTreeData = (data, id, pid) => {
                let cloneData = JSON.parse(JSON.stringify(data));
                return cloneData.filter(father => {
                    let branchArr = cloneData.filter(child => father[id] === child[pid]);
                    branchArr.length > 0 ? father['children'] = branchArr : '';
                    return !father[pid];
                });
            };
            let treeData = toTreeData(this.ds, ids[0], ids[1]);
            let offset = 30;
            let offsetVal = offset;
            const drawRow = (arr, parentNode) => {
                arr.forEach(rowData => {
                    let rowElement = document.createElement('div');
                    rowElement.classList.add('tr');
                    rowElement.data = rowData;
                    let gridTemplateColumns = [];
                    if (this.selectable) {
                        let box = document.createElement('div');
                        box.style.display = 'flex';
                        box.style.justifyContent = 'center';
                        box.style.alignItems = 'center';
                        box.classList.add('td');
                        let checkbox = document.createElement('lit-checkbox');
                        checkbox.classList.add('row-checkbox');
                        checkbox.onchange = (e) => {
                            if (e.detail.checked) {
                                rowElement.setAttribute('checked', '');
                            } else {
                                rowElement.removeAttribute('checked');
                            }
                            const changeChildNode = (rowElement, checked) => {
                                let id = rowElement.getAttribute('id');
                                let pid = rowElement.getAttribute('pid');
                                this.shadowRoot.querySelectorAll(`div[pid=${id}]`).forEach(a => {
                                    a.querySelector('.row-checkbox').checked = checked;
                                    if (checked) {
                                        a.setAttribute('checked', '');
                                    } else {
                                        a.removeAttribute('checked');
                                    }
                                    changeChildNode(a, checked);
                                });
                            };
                            changeChildNode(rowElement, e.detail.checked);
                        };
                        box.appendChild(checkbox);
                        rowElement.appendChild(box);
                    }
                    this.tableColumns.forEach((cl, index) => {
                        let dataIndex = cl.getAttribute('data-index');
                        gridTemplateColumns.push(cl.getAttribute('width') || '1fr');
                        let td;
                        if (cl.template) {
                            let cloneNode = cl.template.render(rowData).content.cloneNode(true);
                            td = document.createElement('div');
                            td.classList.add('td');
                            td.style.justifyContent = cl.getAttribute('align');
                            if (cl.hasAttribute('fixed')) {
                                this.fixed(td, cl.getAttribute('fixed'), '#ffffff');
                            }
                            td.append(cloneNode);
                        } else {
                            td = document.createElement('div');
                            td.classList.add('td');
                            td.style.justifyContent = cl.getAttribute('align')
                            if (cl.hasAttribute('fixed')) {
                                this.fixed(td, cl.getAttribute('fixed'), '#ffffff')
                            }
                            td.innerHTML = rowData[dataIndex];
                        }
                        if (index === 0) {
                            if (rowData.children && rowData.children.length > 0) {
                                let btn = document.createElement('lit-icon');
                                btn.classList.add('tree-icon');
                                btn.name = 'minus-square';
                                td.insertBefore(btn, td.firstChild);
                                td.style.paddingLeft = (offsetVal - 30) + 'px';
                                btn.onclick = (e) => {
                                    const foldNode = (rowElement) => {
                                        let id = rowElement.getAttribute('id');
                                        let pid = rowElement.getAttribute('pid');
                                        this.shadowRoot.querySelectorAll(`div[pid=${id}]`).forEach(a => {
                                            let id = a.getAttribute('id');
                                            let pid = a.getAttribute('pid');
                                            a.style.display = 'none';
                                            foldNode(a);
                                        });
                                        if (rowElement.querySelector('.tree-icon')) {
                                            rowElement.querySelector('.tree-icon').name = 'plus-square';
                                        }
                                        rowElement.removeAttribute('expand');
                                    };
                                    const expendNode = (rowElement) => {
                                        let id = rowElement.getAttribute('id');
                                        let pid = rowElement.getAttribute('pid');
                                        this.shadowRoot.querySelectorAll(`div[pid=${id}]`).forEach(a => {
                                            let id = a.getAttribute('id');
                                            let pid = a.getAttribute('pid');
                                            a.style.display = '';
                                        });
                                        if (rowElement.querySelector('.tree-icon')) {
                                            rowElement.querySelector('.tree-icon').name = 'minus-square';
                                        }
                                        rowElement.setAttribute('expand', '');
                                    };
                                    if (rowElement.hasAttribute('expand')) {
                                        foldNode(rowElement);
                                    } else {
                                        expendNode(rowElement);
                                    }
                                };
                            } else {
                                td.style.paddingLeft = offsetVal + 'px';
                            }
                        }
                        rowElement.append(td);

                    });
                    if (this.selectable) {
                        // `repeat(${this.colCount},1fr)`
                        rowElement.style.gridTemplateColumns = '60px ' + gridTemplateColumns.join(' ');
                    } else {
                        // `repeat(${this.colCount},1fr)`
                        rowElement.style.gridTemplateColumns = gridTemplateColumns.join(' ');
                    }
                    rowElement.onclick = e => {
                    };
                    parentNode.append(rowElement);
                    rowElement.setAttribute('id', rowData[ids[0]]);
                    rowElement.setAttribute('pid', rowData[ids[1]]);
                    rowElement.setAttribute('expand', '');
                    if (rowData.children && rowData.children.length > 0) {
                        // 有子节点的 前面加上 + 图标 表示可以展开节点
                        offsetVal = offsetVal + offset;
                        drawRow(rowData.children, parentNode);
                        offsetVal = offsetVal - offset;
                    }
                });
            };
            drawRow(treeData, this.tbodyElement);
        }

        // 获取选中的行数据
        getCheckRows() {
            return [...this.shadowRoot.querySelectorAll('div[class=tr][checked]')].map(a => a.data).map(a => {
                delete a['children'];
                return a;
            });
        }

        deleteRowsCondition(fn) {
            this.shadowRoot.querySelectorAll('div[class=tr]').forEach(tr => {
                if (fn(tr.data)) {
                    tr.remove();
                }
            });
        }
    }
    if (!customElements.get('lit-table')) {
        customElements.define('lit-table', LitTable);
    }

    class LitTableColumn extends HTMLElement {
        static get observedAttributes() {
            return ['name','order'];
        }

        constructor() {
            super();
            const shadowRoot = this.attachShadow({mode: 'open'});
            shadowRoot.innerHTML = `
<style>
:host{ }
</style>
<slot id='slot'></slot>
        `;
        }
        // 当 custom element首次被插入文档DOM时,被调用。
        connectedCallback() {
            this.template=null;
            this.st = this.shadowRoot.querySelector('#slot')
            this.st.addEventListener('slotchange', () => {
                const elements = this.st.assignedElements({flatten: false});
                if (elements.length>0) {
                    this.template = elements[0];
                }
            })
        }

        // 当 custom element从文档DOM中删除时,被调用。
        disconnectedCallback() {

        }

        // 当 custom element被移动到新的文档时,被调用。
        adoptedCallback() {
            console.log('Custom square element moved to new page.');
        }

        // 当 custom element增加、删除、修改自身属性时,被调用。
        attributeChangedCallback(name, oldValue, newValue) {

        }
    }
    if (!customElements.get('lit-table-column')) {
        customElements.define('lit-table-column', LitTableColumn);
    }

    class LitTableGroup extends HTMLElement {
        static get observedAttributes() {
            return ['title'];
        }

        get title() {
            return this.getAttribute('title');
        }

        set title(value) {
            this.setAttribute('title', value);
        }

        constructor() {
            super();
            const shadowRoot = this.attachShadow({mode: 'open'});
            shadowRoot.innerHTML = `
        <style>
        :host{ }
        </style>
        <slot id='sl'></slot>
        `;
        }

        // 当 custom element首次被插入文档DOM时,被调用。
        connectedCallback() {

        }

        // 当 custom element从文档DOM中删除时,被调用。
        disconnectedCallback() {

        }

        // 当 custom element被移动到新的文档时,被调用。
        adoptedCallback() {
            console.log('Custom square element moved to new page.');
        }

        // 当 custom element增加、删除、修改自身属性时,被调用。
        attributeChangedCallback(name, oldValue, newValue) {

        }
    }
    if (!customElements.get('lit-table-group')) {
        customElements.define('lit-table-group', LitTableGroup);
    }

    class LitTabpane extends HTMLElement {
        static get observedAttributes() {return ['tab','key','disabled','icon','closeable','hide'];}
        constructor() {
            super();
            const shadowRoot = this.attachShadow({mode: 'open'});
            shadowRoot.innerHTML = `
<style>
:host() {
    scroll-behavior: smooth;
    -webkit-overflow-scrolling: touch;
    overflow: auto;
    width: 100%;
}
</style>
<slot></slot>
`;
        }

        get tab() {
            return this.getAttribute('tab');
        }

        set tab(value) {
            this.setAttribute('tab', value);
        }

        get icon() {
            return this.getAttribute('icon');
        }

        get disabled() {
            return this.getAttribute('disabled')!==null;
        }

        set disabled(value) {
            if (value===null||value===false) {
                this.removeAttribute('disabled');
            } else {
                this.setAttribute('disabled',value);
            }
        }
        get closeable() {
            return this.getAttribute('closeable')!==null;
        }
        set closeable(value) {
            if (value===null||value===false) {
                this.removeAttribute('closeable');
            } else {
                this.setAttribute('closeable',value);
            }
        }

        get key() {
            return this.getAttribute('key');
        }
        set key(value) {
            this.setAttribute('key', value);
        }

        get hide() {
            return this.getAttribute('hide')!==null;
        }
        set hide(value) {
            if (value===null||value===false) {
                this.removeAttribute('hide');
            } else {
                this.setAttribute('hide',value);
            }
        }

        // 当 custom element首次被插入文档DOM时,被调用。
        connectedCallback() {}

        // 当 custom element从文档DOM中删除时,被调用。
        disconnectedCallback() {}

        // 当 custom element被移动到新的文档时,被调用。
        adoptedCallback() {}

        // 当 custom element增加、删除、修改自身属性时,被调用。
        attributeChangedCallback(name, oldValue, newValue) {
            if (oldValue!==newValue && newValue!==undefined) {
                if (name==='tab'&&this.parentNode) {
                    this.parentNode.updateLabel && this.parentNode.updateLabel(this.key,newValue);
                }
                if (name==='disabled'&&this.parentNode) {
                    this.parentNode.updateDisabled && this.parentNode.updateDisabled(this.key,newValue);
                }
                if (name==='closeable'&&this.parentNode) {
                    this.parentNode.updateCloseable && this.parentNode.updateCloseable(this.key, newValue);
                }
                if (name==='hide'&&this.parentNode) {
                    this.parentNode.updateCloseable && this.parentNode.updateHide(this.key, newValue);
                }
            }
        }
    }
    if (!customElements.get('lit-tabpane')) {
        customElements.define('lit-tabpane', LitTabpane);
    }

    class LitTabs extends HTMLElement {
        static get observedAttributes() {
            //mode = flat(default) | card
            //position = top | top-left | top-center | top-right | left | left-top | left-center | left-bottom | right | bottom
            return ['activekey', 'mode', 'position'];
        }

        constructor() {
            super();
            const shadowRoot = this.attachShadow({mode: 'open'});
            shadowRoot.innerHTML = `
        <style>
        :host{
            display: block;
            text-align: unset;
            color: #252525;
            background-color: #fff;
            box-shadow: #00000033 0 0 10px ;
            /*padding: 10px;*/
            /*margin-right: 10px;*/
        }
        ::slotted(lit-tabpane) {
            box-sizing:border-box;
            width:100%;
            height:100%;
            /*padding:10px;*/
            flex-shrink:0;
            overflow:auto;
        }
        .nav-item{
            display: inline-flex;
            justify-content: center;
            align-items: center;
            padding: 6px 0px 6px 12px;
            font-size: .9rem;
            font-weight: normal;
            cursor: pointer;
            transition: all 0.3s;
            flex-shrink: 0;
        }
        .nav-item lit-icon{
            margin-right: 2px;
            font-size: inherit;
        }
        .nav-item:hover{
            color: #42b983;
        }
        .nav-item[data-disabled]{
            pointer-events: all;
            cursor: not-allowed;
            color: #bfbfbf;
        }
        .nav-item[data-selected]{
            color: #42b983;;
        }
        .tab-content{
            display: block;
            background-color: #fff;
            flex:1;
        }

        /*
         *   top  top-left top-center top-right
         */
        :host(:not([position])) .nav-root,
        :host([position^='top']) .nav-root{
            display: flex;
            position: relative;
            justify-content: center;
            align-items: center;
        }
        :host(:not([mode]):not([position])) .tab-line,/*移动的线条*/
        :host([mode='flat'][position^='top']) .tab-line{
            position:absolute;
            bottom: 2px;
            background-color: #42b983;
            height: 2px;
            transform: translateY(100%);
            transition: all 0.3s;
        }

        :host(:not([position])) .tab-nav-container,
        :host([position^='top']) .tab-nav-container{
            display: flex;
            position: relative;
            flex-direction: column;
            overflow-y: hidden;
            overflow-x: auto;
            overflow: -moz-scrollbars-none;
            -ms-overflow-style: none;
            transition: all 0.3s;
            flex: 1;
            /*background: linear-gradient(90deg,white 30%, transparent),radial-gradient(at 0 50%, rgba(0,0,0,.2),transparent 70%);*/
            /*background-repeat: no-repeat;*/
            /*background-size: 50px 100%, 15px 100%;*/
            /*background-attachment: local,scroll,local,scroll;*/
            /*border-bottom: #f0f0f0 1px solid;*/
        }
        :host([position='top']) .tab-nav,
        :host([position='top-left']) .tab-nav{
            display: flex;
            position: relative;
            justify-content: flex-start;
        }
        :host([position='top-center']) .tab-nav{
            display: flex;
            justify-content: center;
        }
        :host([position='top-right']) .tab-nav{
            display: flex;
            justify-content: flex-end;
        }

        :host([position^='top'][mode='card']) .nav-item{
            border-top: 1px solid #f0f0f0;
            border-left: 1px solid #f0f0f0;
            border-right: 1px solid #f0f0f0;
            border-bottom: 1px solid #f0f0f0;
            bottom: 0px;
            margin-right: 2px;
            position: relative;
        }
        :host([position^='top']) .tab-nav-bg-line{
            position: absolute;bottom: 0;height: 1px;background-color: #f0f0f0;width: 100%
        }
        :host([position^='top'][mode='card']) .nav-item:not([data-selected]) {
            background-color: #f6f6f6;
            border-bottom: 1px solid #f0f0f0;
        }
        :host([position^='top'][mode='card']) .nav-item[data-selected]{
            background-color: #ffffff;
            border-bottom: 1px solid #fff;
            bottom: 0px;
        }
        /*
            bottom bottom-left bottom-center bottom-right
        */
        :host([position^='bottom']) .tab{
            display: flex;
            flex-direction: column-reverse;
        }
        :host([mode='flat'][position^='bottom']) .tab-line{
            position:absolute;
            top: -3px;
            background-color: #42b983;
            height: 2px;
            transform: translateY(-100%);
            transition: all 0.3s;
        }
        :host([position^='bottom']) .tab-nav-container{
            display: flex;
            position: relative;
            flex-direction: column;
            overflow-x: auto;
            overflow-y: visible;
            overflow: -moz-scrollbars-none;
            -ms-overflow-style: none;
            transition: all 0.3s;
            flex: 1;
            /*background: linear-gradient(90deg,white 30%, transparent),radial-gradient(at 0 50%, rgba(0,0,0,.2),transparent 70%);*/
            /*background-repeat: no-repeat;*/
            /*background-size: 50px 100%, 15px 100%;*/
            /*background-attachment: local,scroll,local,scroll;*/
            border-top: #f0f0f0 1px solid;
        }
        :host([position^='bottom']) .nav-root{
            display: flex;
            justify-content: center;
            align-items: center;
        }
        :host([position='bottom']) .tab-nav,
        :host([position='bottom-left']) .tab-nav{
            display: flex;
            position: relative;
            justify-content: flex-start;
        }
        :host([position='bottom-center']) .tab-nav{
            display: flex;
            justify-content: center;
        }
        :host([position='bottom-right']) .tab-nav{
            display: flex;
            justify-content: flex-end;
        }
        :host([position^='bottom'][mode='card']) .nav-item{
            border-top: 1px solid #ffffff;
            border-left: 1px solid #f0f0f0;
            border-right: 1px solid #f0f0f0;
            border-bottom: 1px solid #f0f0f0;
            top: -1px;
            margin-right: 2px;
            position: relative;
        }
        :host([position^='bottom']) .tab-nav-bg-line{
            position: absolute;top: 0;height: 1px;background-color: #f0f0f0;width: 100%
        }
        :host([position^='bottom'][mode='card']) .nav-item:not([data-selected]) {
            background-color: #f5f5f5;
            border-top: 1px solid #f0f0f0;
        }
        :host([position^='bottom'][mode='card']) .nav-item[data-selected]{
            background-color: #ffffff;
            border-top: 1px solid #fff;
            top: -1px;
        }
        /*
        left left-top left-center left-bottom
        */
        :host([position^='left']) .tab{
            display: flex;
            flex-direction: row;
        }
        :host([mode='flat'][position^='left']) .tab-line{
            position:absolute;
            right: 1px;
            background-color: #42b983;
            width: 3px;
            transform: translateX(100%);
            transition: all 0.3s;
        }
        :host([position^='left']) .tab-nav-container{
            display: flex;
            position: relative;
            flex-direction: row;
            overflow-x: auto;
            overflow-y: visible;
            overflow: -moz-scrollbars-none;
            -ms-overflow-style: none;
            transition: all 0.3s;
            flex: 1;
            /*background: linear-gradient(90deg,white 30%, transparent),radial-gradient(at 0 50%, rgba(0,0,0,.2),transparent 70%);*/
            /*background-repeat: no-repeat;*/
            /*background-size: 50px 100%, 15px 100%;*/
            /*background-attachment: local,scroll,local,scroll;*/
            border-right: #f0f0f0 1px solid;
        }
        :host([position^='left']) .nav-root{
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
        }
        :host([position='left']) .tab-nav,
        :host([position='left-top']) .tab-nav{
            display: flex;
            position: relative;
            flex-direction: column;
            justify-content: flex-start;
        }
        :host([position='left-center']) .tab-nav{
            display: flex;
            position: relative;
            flex-direction: column;
            justify-content: center;
        }
        :host([position='left-bottom']) .tab-nav{
            display: flex;
            position: relative;
            flex-direction: column;
            justify-content: flex-end;
        }
        :host([position^='left'][mode='card']) .nav-item{
            border-top: 1px solid #f0f0f0;
            border-left: 1px solid #f0f0f0;
            border-right: 1px solid #ffffff;
            border-bottom: 1px solid #f0f0f0;
            right: -1px;
            margin-bottom: 2px;
            position: relative;
        }
        :host([position^='left']) .tab-nav-bg-line{
            position: absolute;right: 0;width: 1px;background-color: #f0f0f0;width: 100%
        }
        :host([position^='left'][mode='card']) .nav-item:not([data-selected]) {
            background-color: #f5f5f5;
            border-right: 1px solid #f0f0f0;
        }
        :host([position^='left'][mode='card']) .nav-item[data-selected]{
            background-color: #ffffff;
            border-bottom: 1px solid #fff;
            right: -1px;
        }
        /*
        right right-top right-center right-bottom
        */
        :host([position^='right']) .tab{
            display: flex;
            flex-direction: row-reverse;
        }
        :host([mode='flat'][position^='right']) .tab-line{
            position:absolute;
            left: 1px;
            background-color: #42b983;
            width: 3px;
            transform: translateX(-100%);
            transition: all 0.3s;
        }
        :host([position^='right']) .tab-nav-container{
            display: flex;
            position: relative;
            flex-direction: row-reverse;
            overflow-x: auto;
            overflow-y: visible;
            overflow: -moz-scrollbars-none;
            -ms-overflow-style: none;
            transition: all 0.3s;
            flex: 1;
            /*background: linear-gradient(90deg,white 30%, transparent),radial-gradient(at 0 50%, rgba(0,0,0,.2),transparent 70%);*/
            /*background-repeat: no-repeat;*/
            /*background-size: 50px 100%, 15px 100%;*/
            /*background-attachment: local,scroll,local,scroll;*/
            border-left: #f0f0f0 1px solid;
        }
        :host([position^='right']) .nav-root{
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
        }
        :host([position='right']) .tab-nav,
        :host([position='right-top']) .tab-nav{
            display: flex;
            position: relative;
            flex-direction: column;
            justify-content: flex-start;
        }
        :host([position='right-center']) .tab-nav{
            display: flex;
            position: relative;
            flex-direction: column;
            justify-content: center;
        }
        :host([position='right-bottom']) .tab-nav{
            display: flex;
            position: relative;
            flex-direction: column;
            justify-content: flex-end;
        }
        :host([position^='right'][mode='card']) .nav-item{
            border-top: 1px solid #f0f0f0;
            border-left: 1px solid #ffffff;
            border-right: 1px solid #f0f0f0;
            border-bottom: 1px solid #f0f0f0;
            left: -1px;
            margin-top: 2px;
            position: relative;
        }
        :host([position^='right']) .tab-nav-bg-line{
            position: absolute;left: 0;width: 1px;background-color: #f0f0f0;width: 100%
        }
        :host([position^='right'][mode='card']) .nav-item:not([data-selected]) {
            background-color: #f5f5f5;
            border-left: 1px solid #f0f0f0;
        }
        :host([position^='right'][mode='card']) .nav-item[data-selected]{
            background-color: #ffffff;
            left: -1px;
        }


        .tab-nav-container::-webkit-scrollbar {
            display: none;
        }


        /*关闭的图标*/
        .close-icon:hover{
            color: #000;
        }
        .nav-item[data-closeable] .close-icon{
            display: block;
            padding: 5px 5px 5px 5px;
            color: #999;
        }
        .nav-item[data-closeable] .no-close-icon{
            display: none;
        }
        .nav-item:not([data-closeable]) .no-close-icon{
            display: block;
        }
        .nav-item:not([data-closeable]) .close-icon{
            display: none;
        }
        .nav-item:not([data-hide]) {
            display: block;
        }
        .nav-item[data-hide]{
            display: none;
        }

        </style>
        <style id="filter"></style>
        <div class="tab">
            <div class="nav-root">
                <slot name="left" style="flex:1"></slot>
                <div class="tab-nav-container" >
                    <div class="tab-nav-bg-line"></div>
                    <div class="tab-nav" id="nav"></div>
                    <div class="tab-line" id="tab-line"></div>
                </div>
                <slot name="right" style="flex:1"></slot>
            </div>
            <div class="tab-content">
                <slot id="slot">NEED CONTENT</slot>
            </div>
        </div>
        `;
        }

        get position() {
            return this.getAttribute('position') || 'top';
        }

        set position(value) {
            this.setAttribute('position', value);
        }

        get mode() {
            return this.getAttribute('mode') || 'flat';
        }

        set mode(value) {
            this.setAttribute('mode', value);
        }

        get activekey() {
            return this.getAttribute('activekey');
        }

        set activekey(value) {
            this.setAttribute('activekey', value);
        }

        updateLabel(key, value) {
            if (this.nav) {
                let item = this.nav.querySelector(`.nav-item[data-key='${key}']`);
                if (item) {
                    item.querySelector('span').innerHTML=value;
                    this.initTabPos();
                }
            }
        }

        updateDisabled(key, value) {
            if (this.nav) {
                let item = this.nav.querySelector(`.nav-item[data-key='${key}']`);
                if (item) {
                    if (value) {
                        item.setAttribute('data-disabled','');
                    } else {
                        item.removeAttribute('data-disabled');
                    }
                    this.initTabPos()
                }
            }
        }
        updateCloseable(key,value) {
            if (this.nav) {
                let item = this.nav.querySelector(`.nav-item[data-key='${key}']`);
                if (item) {
                    if (value) {
                        item.setAttribute('data-closeable','');
                    } else {
                        item.removeAttribute('data-closeable');
                    }
                    this.initTabPos();
                }
            }
        }
        updateHide(key,value) {
            if (this.nav) {
                let item = this.nav.querySelector(`.nav-item[data-key='${key}']`);
                if (item) {
                    if (value) {
                        item.setAttribute('data-hide','');
                    } else {
                        item.removeAttribute('data-hide');
                    }
                    this.initTabPos();
                }
            }
        }

        initTabPos() {
            const items = this.nav.querySelectorAll('.nav-item');
            Array.from(items).forEach((a, index) => {
                this.tabPos[a.dataset.key] = {
                    index: index,
                    width: a.offsetWidth,
                    height: a.offsetHeight,
                    left: a.offsetLeft,
                    top: a.offsetTop,
                    label: a.textContent
                };
            });
            if (this.activekey) {
                if (this.position.startsWith('left')) {
                    this.line.style =
                        `height:${this.tabPos[this.activekey].height}px;transform:translate(100%,${this.tabPos[this.activekey].top}px)`;
                } else if (this.position.startsWith('top')) {
                    if (this.tabPos[this.activekey]) {
                        this.line.style =
                            `width:${this.tabPos[this.activekey].width}px;transform:translate(${this.tabPos[this.activekey].left}px,100%)`;
                    }
                } else if (this.position.startsWith('right')) {
                    this.line.style =
                        `height:${this.tabPos[this.activekey].height}px;transform:translate(-100%,${this.tabPos[this.activekey].top}px)`;
                } else if (this.position.startsWith('bottom')) {
                    this.line.style =
                        `width:${this.tabPos[this.activekey].width}px;transform:translate(${this.tabPos[this.activekey].left}px,100%)`;
                }
            }
        }

        // 当 custom element首次被插入文档DOM时,被调用。
        connectedCallback() {
            let that = this;
            this.tabPos = {};
            this.nav = this.shadowRoot.querySelector('#nav');
            this.line = this.shadowRoot.querySelector('#tab-line');
            this.slots = this.shadowRoot.querySelector('#slot');
            this.slots.addEventListener('slotchange', () => {
                const elements = this.slots.assignedElements();
                let panes = this.querySelectorAll('lit-tabpane');
                if (this.activekey) {
                    panes.forEach(a => {
                        if (a.key === this.activekey) {
                            a.style.display = 'block';
                        } else {
                            a.style.display = 'none';
                        }
                    })
                } else {
                    panes.forEach((a, index) => {
                        if (index === 0) {
                            a.style.display = 'block';
                            this.activekey = a.key;
                        } else {
                            a.style.display = 'none';
                        }
                    })
                }

                let navHtml = '';
                elements.forEach(a => {
                    if (a.disabled) {
                        navHtml += `<div class='nav-item' data-key='${a.key}'' data-disabled ${a.closeable?'data-closeable':''} ${a.hide?'data-hide':''}>
                    ${a.icon ? `<lit-icon name='${a.icon}'></lit-icon>` : ``}
                    <span>${a.tab}</span>
                    <lit-icon class='close-icon' name='close' size='12'></lit-icon><div class='no-close-icon' style='margin-right: 12px'></div>
                    </div>`;
                    } else {
                        if (a.key === this.activekey) {
                            navHtml += `<div class='nav-item' data-key='${a.key}'' data-selected ${a.closeable?'data-closeable':''} ${a.hide?'data-hide':''}>
                        ${a.icon ? `<lit-icon name='${a.icon}'></lit-icon>` : ``}
                        <span>${a.tab}</span>
                        <lit-icon class='close-icon' name='close' size='12'></lit-icon><div class='no-close-icon' style='margin-right: 12px'></div>
                        </div>`;
                        } else {
                            navHtml += `<div class='nav-item' data-key='${a.key}' ${a.closeable?'data-closeable':''} ${a.hide?'data-hide':''}>
                            ${a.icon ? `<lit-icon name='${a.icon}'></lit-icon>` : ``}
                            <span>${a.tab}</span>
                            <lit-icon class='close-icon' name='close' size='12'></lit-icon><div class='no-close-icon' style='margin-right: 12px'></div>
                            </div>`;
                        }

                    }
                });
                this.nav.innerHTML = navHtml;
                this.initTabPos();
                this.nav.querySelectorAll('.close-icon').forEach(a => {
                    a.onclick = (e) => {
                        e.stopPropagation();
                        const closeKey = e.target.parentElement.dataset.key;
                        console.log(closeKey);
                        console.log(e.target.parentElement.parentElement);
                        this.nav.removeChild(e.target.parentElement);
                        let elements = this.slots.assignedElements();
                        let closeElement = elements.filter(a => a.key === closeKey)[0];
                        closeElement.parentElement.removeChild(closeElement);
                        if (closeElement.style.display !== 'none') {
                            elements = this.slots.assignedElements();
                            let elArr = elements.filter(a => !a.hasAttribute('disabled'));
                            if (elArr.length > 0) {
                                elArr[0].style.display = 'block';
                                this.activekey = elArr[0].key;
                            }
                        }
                    }
                });
            });
            this.nav.onclick = (e) => {
                if (e.target.closest('div').hasAttribute('data-disabled')) return;
                let key = e.target.closest('div').dataset.key;
                this.activeByKey(key);
                let label = e.target.closest('div').querySelector('span').textContent;
                this.dispatchEvent(new CustomEvent('onTabClick',{detail:{key:key,tab:label}}));
            };
        }
        set onTabClick(fn) {
            this.addEventListener('onTabClick', fn);
        }
        activeByKey(key) {
            if (key === null || key === undefined) return; // 如果没有key 不做相应
            this.nav.querySelectorAll('.nav-item').forEach(a => {
                if (a.getAttribute('data-key') === key) {
                    a.setAttribute('data-selected', 'true');
                } else {
                    a.removeAttribute('data-selected');
                }
            })
            let tbp = this.querySelector(`lit-tabpane[key='${key}']`);
            let panes = this.querySelectorAll('lit-tabpane');
            panes.forEach(a => {
                if (a.key === key) {
                    a.style.display = 'block';
                    this.activekey = a.key;
                    this.initTabPos()
                } else {
                    a.style.display = 'none';
                }
            })
        }
        /*激活选中 key 对应的 pane  成功返回true,没有找到key对应的pane 返回false*/
        activePane(key) {
            if (key === null || key === undefined) return false;
            let tbp = this.querySelector(`lit-tabpane[key='${key}']`);
            if (tbp) {
                this.activeByKey(key);
                return true;
            } else {
                return false;
            }
        }
        // 当 custom element从文档DOM中删除时,被调用。
        disconnectedCallback() {

        }

        // 当 custom element被移动到新的文档时,被调用。
        adoptedCallback() {
            console.log('Custom square element moved to new page.');
        }

        // 当 custom element增加、删除、修改自身属性时,被调用。
        attributeChangedCallback(name, oldValue, newValue) {
            if (name==='activekey'&&this.nav&&oldValue!==newValue) {
                this.activeByKey(newValue);
            }
        }
    }
    if (!customElements.get('lit-tabs')) {
        customElements.define('lit-tabs', LitTabs);
    }

    class AppChartFlame extends HTMLElement {
        draw;
        drawC;
        rowHeight = 17;

        static get observedAttributes() {
            return [];
        }

        constructor() {
            super();
            const shadowRoot = this.attachShadow({mode: 'open'});
            shadowRoot.innerHTML = `
        <style>
        :host{
            font-size:inherit;
            display:inline-flex;
            align-items: center;
            justify-content:center;
            height: 100%;
            width: 100%;
            margin-bottom: 40px;
        }
        canvas { border: 1px solid #e9e9e9; }
        #title{
            font-weight: bold;
            height: auto;
        }
        #title span{
            color: gray;
        }
        #funcNameSpan{
            display: inline-block;
            border: 1px solid #e9e9e9;
            box-sizing: border-box;
            border-radius: 2px;
            padding: 2px 8px;
            background: #fff;
             color: gray;
            flex: 3;
            margin-left: 10px;
        }
        #percentSpan{
            display: inline-block;
            border: 1px solid #e9e9e9;
            margin-left: 10px;
            box-sizing: border-box;
            border-radius: 2px;
            padding: 2px 8px;
            background: #fff;
            min-width: 160px;
            max-width: 160px;
            margin-left: 10px;
            width: 100px;
            height: 30px;
            color: gray;
        }
        #history{
            display: none;
            border: 1px solid #42b983;
            box-sizing: border-box;
            border-radius: 2px;
            padding: 2px 8px;
            background: #fff;
            width: 100px;
            margin-left: 10px;
            height: 30px;
            cursor: pointer;
            user-select: none;
        }
        #history:hover{
            background: #42b983;
            color: #fff;
        }
        #searchInput{
            height: 30px;
            margin-left: 10px;
            margin-right: 10px;
            flex: 1;
        }
        </style>
        <div style="position: relative;width: 100%">
            <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>
            <canvas id="panel" title=""></canvas>
            <div id="controller" style="position: absolute;top: 32px;display: flex;width: 100%">
                <span id="history">Zoom Out</span>
                <span id="funcNameSpan"></span>
                <span id="percentSpan"></span>
                <lit-input id="searchInput" placeholder="search"  allow-clear>Search</lit-input>
            </div>
        </div>
        <slot></slot>
        `
        }

        connectedCallback() {
            this.history = [];
            this.panel = this.shadowRoot.getElementById('panel');
            this.controller = this.shadowRoot.getElementById('controller');
            this.funcNameSpan = this.shadowRoot.getElementById('funcNameSpan');
            this.percentSpan = this.shadowRoot.getElementById('percentSpan');
            this.historySpan = this.shadowRoot.getElementById('history');
            this.searchInput = this.shadowRoot.getElementById('searchInput');
            this.pid = this.shadowRoot.getElementById('pid');
            this.tid = this.shadowRoot.getElementById('tid');
            this.processName = this.shadowRoot.getElementById('processName');
            this.threadName = this.shadowRoot.getElementById('threadName');
            this.sample = this.shadowRoot.getElementById('sample');
            this.titleDiv = this.shadowRoot.getElementById('title');
            this.context = this.panel.getContext('2d');
            this.panel.width = this.shadowRoot.host.clientWidth;
            this.panel.height = this.shadowRoot.host.clientHeight;
            this.historySpan.onclick = e => {
                if (this.history.length > 2) {
                    this.history.pop();
                    this.zoomOut(this.history[this.history.length - 1]);
                } else if (this.history.length === 2) {
                    this.history.pop();
                    this.zoomOut(this.history[this.history.length - 1]);
                    this.historySpan.style.display = 'none';
                } else {
                    this.historySpan.style.display = 'none';
                }
            };
            this.searchInput.addEventListener('onPressEnter', (e) => {
                this.keyword = e.currentTarget.value;
                requestAnimationFrame(this.draw);
            });
            this.searchInput.addEventListener('onClear', e => {
                this.keyword = null;
                requestAnimationFrame(this.draw);
            });
            this.panel.onmouseover = (e) => {
                this.mouseState = 'mouseOver';
            };
            this.panel.onmouseleave = e => {
                this.mouseState = 'mouseLeave';
                this.mouseX = 0;
                this.mouseY = 0;
                requestAnimationFrame(this.draw)
            };
            this.panel.onmousemove = e => {
                const pos = e.currentTarget.getBoundingClientRect();
                this.mouseX = e.clientX - pos.left;
                this.mouseY = e.clientY - pos.top;
                this.mouseState = 'mouseMove';
                requestAnimationFrame(this.draw)
            };
            this.panel.onmousedown = e => {
                this.mouseState = 'mouseDown';
            };
            this.panel.onmouseup = e => {
                this.mouseState = 'mouseUp';
                const pos = e.currentTarget.getBoundingClientRect();
                this.mouseX = e.clientX - pos.left;
                this.mouseY = e.clientY - pos.top;
                requestAnimationFrame(this.draw);
            };
        }

        set data(value) {
            this._data = value;
            this.type = value.type;
            this.reverse = value.reverse || false;
            if (value.CallOrder.symbol === -1) {
                this._c = value.CallOrder.callStack;
            } else {
                this._c = [value.CallOrder];
            }
            this.history.push(this._c);
            this.eventCountAllProcess = data.recordSampleInfo[window.eventIndex].eventCount;
            if (value.pid) {
                this.eventCountCurrentProcess =
                    data.recordSampleInfo[window.eventIndex].processes.filter(it => it.pid === value.pid)[0].eventCount;
                this.pid.textContent = value.pid;
            }
            if (value.tid) {
                this.eventCountCurrentThread =
                    data.recordSampleInfo[window.eventIndex].processes.filter(
                        it => it.pid === value.pid)[0].threads.filter(it => it.tid === value.tid)[0].eventCount;
                this.tid.textContent = value.tid;
            }
            if (value.sampleCount) {
                this.sample.textContent = ' (Samples: ' + value.sampleCount + ')';
            }
            if (value.processName) {
                this.processName.textContent = value.processName ? `(${value.processName})` : '';
            }
            if (value.threadName) {
                this.threadName.textContent = value.threadName ? `(${value.threadName})` : '';
            }
            if (value.funcName) {
                this.titleDiv.innerHTML = `${value.funcName}`;
                this.controller.style.top = `${this.titleDiv.clientHeight + 10}px`;
            }
            this.maxDepth = this.getMaxDepth(this.data.CallOrder.callStack) + 5; // 设置最大层级
            this.sumCount = this.data.CallOrder.subEvents; // 设置根节点的 sumCount
            this.panel.height = this.maxDepth * this.rowHeight;
            this.panel.width = this.shadowRoot.host.clientWidth;
            this.makeHighRes(this.panel);
            requestAnimationFrame(this.draw);
        }

        get data() {
            return this._data;
        }

        set c(value) {
            this.historySpan.style.display = 'block';
            this._c = value;
            this.history.push(this._c);
            // 下面代码实现 canvas 随内容高度变化
            requestAnimationFrame(this.draw);
        }

        get c() {
            return this._c;
        }

        zoomOut(value) {
            this._c = value;
            // 下面代码实现 canvas 随内容高度变化
            requestAnimationFrame(this.draw);
        }

        makeHighRes(canvas) {
            let ctx = canvas.getContext('2d');
            let dpr = window.devicePixelRatio || window.webkitDevicePixelRatio || window.mozDevicePixelRatio || 1;
            let oldWidth = canvas.width;
            let oldHeight = canvas.height;
            canvas.width = Math.round(oldWidth * dpr);
            canvas.height = Math.round(oldHeight * dpr);
            canvas.style.width = oldWidth + 'px';
            canvas.style.height = oldHeight + 'px';
            ctx.scale(dpr, dpr);
            this.context = ctx;
            return ctx;
        }

        draw = () => {
            let ctx = this.context;
            let grad = ctx.createLinearGradient(0, 0, 0, this.panel.height / 2); // 创建一个渐变色线性对象
            grad.addColorStop(0, '#eeeeee');                  // 定义渐变色颜色
            grad.addColorStop(1, '#efefb1');
            ctx.fillStyle = grad;                         // 设置fillStyle为当前的渐变对象
            ctx.fillRect(0, 0, this.panel.width, this.panel.height);
            if (this.data) {
                if (this.reverse) {
                    this.drawCReverse(
                        this.c,
                        1,
                        {
                            x: 0,
                            y: this.rowHeight * 4,
                            w: this.panel.clientWidth,
                            h: this.rowHeight
                        });
                } else {
                    this.drawC(
                        0,
                        this.c,
                        1,
                        {
                            x: 0,
                            y: this.panel.clientHeight - this.rowHeight,
                            w: this.panel.clientWidth,
                            h: this.rowHeight
                        });
                }
            }
        };

        getCount(c) {
            let count;// 鼠标hover展示的百分比
            count = c.subEvents;
            count = `${count}`;
            return count;
        }

        getStatistics(c) {
            let statistics;// 鼠标hover展示的百分比
            switch (this.type) {
                case 1: // current thread
                    statistics = c.subEvents * 100 / this.eventCountCurrentThread;
                    statistics = statistics.toFixed(2);
                    statistics = `${statistics}%`;
                    break;
                case 2: // current process
                    statistics = c.subEvents * 100 / this.eventCountCurrentProcess;
                    statistics = statistics.toFixed(2);
                    statistics = `${statistics}%`;
                    break;
                case 3: // all process
                    statistics = c.subEvents * 100 / this.eventCountAllProcess;
                    statistics = statistics.toFixed(2);
                    statistics = `${statistics}%`;
                    break;
                case 4: // event count
                    statistics = c.subEvents;
                    statistics = `${statistics}`;
                    break;
                case 5: // event count in milliseconds
                    statistics = c.subEvents / 1000000;
                    statistics = statistics.toFixed(3);
                    statistics = `${statistics} ms`;
                    break;
                default: //current thread
                    statistics = c.subEvents * 100 / this.eventCountCurrentThread;
                    statistics = statistics.toFixed(2);
                    statistics = `${statistics}%`;
                    break;
            }
            return statistics;
        }

        // HTML反转义
        htmlDecode(text) {
            let temp = document.createElement('div');
            temp.innerHTML = text;
            let output = temp.innerText || temp.textContent;
            temp = null;
            return output;
        }

        getFunctionName(f) {
            let funName = '';
            if (data.SymbolMap[f]) {
                funName = data.SymbolMap[f].symbol;
            } else {
                let f = c[i].symbol;
                console.log(`processId:${this.pid.textContent} processName:${this.processName.textContent}
                             threadId:${this.tid.textContent} threadName:${this.threadName.textContent}`,
                            c[i], "SymbolMap中没有对应的值");
            }
            return this.htmlDecode(funName);
        }

        getColor(percent2, funName) {
            let heatColor;
            if (this.keyword && this.keyword.length > 0 && funName.indexOf(this.keyword) !== -1) {
                heatColor = {r: 0x66, g: 0xad, b: 0xff};
            } else {
                if (funName.includes("url:")) {
                    heatColor = this.getJsHeatColor(percent2);
                } else if (funName.includes("JS:")) {
                    heatColor = this.getV8HeatColor(percent2);
                } else {
                    heatColor = this.getHeatColor(percent2);
                }
            }
            return heatColor;
        }

        getLibName(symbol) {
            let fileId = data.SymbolMap[symbol].file;
            return data.symbolsFileList[fileId];
        }

        drawCReverse = (c, dept, rect) => {
            let ctx = this.context;
            let offset = 0;
            for (let i = 0; i < c.length; i++) {
                let funName = this.getFunctionName(c[i].symbol);
                let funcId = c[i].symbol;
                let percent = c[i].subEvents * 100 / (c.reduce((acc, cur) => acc + cur.subEvents, 0));
                let percent2 = c[i].subEvents * 100 / this.sumCount;
                let heatColor = this.getColor(percent2, funName);
                let w = rect.w * (percent / 100.0);
                if (w < 1) {
                    w = 1;
                }
                let _x = rect.x + offset;
                // 绘制填充矩形
                ctx.fillStyle = `rgba(${heatColor.r}, ${heatColor.g}, ${heatColor.b}, 1)`;
                ctx.fillRect(_x, rect.y + 2, w, rect.h - 2);
                // 绘制文本
                ctx.fillStyle = 'rgba(0,0,0,1)';
                let txtWidth = ctx.measureText(funName).width;// 文本长度
                let chartWidth = txtWidth / funName.length;// 每个字符长度
                let number = (w - 6) / chartWidth;// 可以显示多少字符
                if (number >= 4 && number < funName.length - 3) {
                    ctx.fillText(funName.slice(0, number - 3) + '...', _x + 3, rect.y + 13, w - 6);
                } else if (number >= 4) {
                    ctx.fillText(funName, _x + 3, rect.y + 13, w - 6);
                }
                let _rect = {
                    x: _x, y: rect.y, w: w, h: rect.h
                };
                c[i].rect = _rect;

                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) {
                    if (this.mouseState === 'mouseMove') {
                        // 绘制边框矩形
                        ctx.lineWidth = 2;
                        ctx.strokeStyle = `#000000`;
                        ctx.strokeRect(_x, rect.y + 1, w - 1, rect.h);
                        let statisticNum = this.getStatistics(c[i]);
                        this.funcNameSpan.textContent = funName;
                        this.panel.title = funName + ': [' + statisticNum + ']';
                        this.percentSpan.textContent = statisticNum;
                    } else {
                        if (this.mouseState === 'mouseUp') {
                            this.mouseState = null;
                            if (!this.compareNodes(this.c, [c[i]])) {
                                this.c = [c[i]];
                            }
                        }
                    }
                } else {
                    ctx.lineWidth = 1;
                }
                offset += w;
                // 递归绘制子节点
                if (c[i].callStack && c[i].callStack.length > 0) {
                    _rect.y = _rect.y + _rect.h;
                    this.drawCReverse(c[i].callStack, dept + 1, _rect);
                }
            }
        }
        drawC = (parentEvents, c, dept, rect) => {
            let ctx = this.context;
            let offset = 0;
            if (parentEvents === 0) {
                parentEvents = c.reduce((acc, cur) => acc + cur.subEvents, 0);
            }
            for (let i = 0; i < c.length; i++) {
                let funName = this.getFunctionName(c[i].symbol);
                let funcId = c[i].symbol;
                let percent = c[i].subEvents * 100 / parentEvents;// sumCount;
                let percent2 = c[i].subEvents * 100 / this.sumCount;
                let heatColor = this.getColor(percent2, funName);
                let w = rect.w * (percent / 100.0);
                if (w < 1) {
                    w = 1;
                }
                let _x = rect.x + offset;
                // 绘制填充矩形
                ctx.fillStyle = `rgba(${heatColor.r}, ${heatColor.g}, ${heatColor.b}, 1)`;
                ctx.fillRect(_x, rect.y + 2, w, rect.h - 2);
                // 绘制文本
                ctx.fillStyle = 'rgba(0,0,0,1)';
                let txtWidth = ctx.measureText(funName).width;// 文本长度
                let chartWidth = txtWidth / funName.length;// 每个字符长度
                let number = (w - 6) / chartWidth;// 可以显示多少字符
                if (number >= 4 && number < funName.length - 3) {
                    ctx.fillText(funName.slice(0, number - 3) + '...', _x + 3, rect.y + 13, w - 6);
                } else if (number >= 4) {
                    ctx.fillText(funName, _x + 3, rect.y + 13, w - 6);
                }
                let _rect = {
                    x: _x, y: rect.y, w: w, h: rect.h
                };
                c[i].rect = _rect;

                if (this.mouseX > _x && this.mouseX < _x + w && this.mouseY > (this.maxDepth - dept) * rect.h &&
                    this.mouseY < (this.maxDepth - dept + 1) * rect.h) {
                    if (this.mouseState === 'mouseMove') {
                        // 绘制边框矩形
                        ctx.lineWidth = 2;
                        ctx.strokeStyle = `#000000`;
                        ctx.strokeRect(_x, rect.y + 1, w - 1, rect.h);
                        let statisticNum = this.getStatistics(c[i]);
                        let count = this.getCount(c[i]);
                        this.funcNameSpan.textContent = funName;
                        if (this.type === 1 || this.type === 2 || this.type === 3) {
                            this.panel.title = funName + ': [' + count + '  ' + statisticNum + ']\n' + this.getLibName(c[i].symbol);
                        } else {
                            this.panel.title = funName + ': [' + statisticNum + ']';
                        }
                        this.percentSpan.textContent = statisticNum;
                    } else {
                        if (this.mouseState === 'mouseUp') {
                            this.mouseState = null;
                            if (!this.compareNodes(this.c, [c[i]])) {
                                this.c = [c[i]];
                            }
                        }
                    }
                } else {
                    ctx.lineWidth = 1;
                }
                offset += w;
                // 递归绘制子节点
                if (c[i].callStack && c[i].callStack.length > 0) {
                    _rect.y = _rect.y - _rect.h;
                    this.drawC(c[i].subEvents, c[i].callStack, dept + 1, _rect);
                }
            }
        }

        compareNode(na, nb) {
            let res = false;
            if (na.selfEvents === nb.selfEvents && na.subEvents === nb.subEvents && na.symbol === nb.symbol) {
                res = this.compareNodes(na.callStack || [], nb.callStack || []);
            }
            return res;
        }

        compareNodes(a, b) {
            let res = false;
            if (a.length === b.length) {
                if (a.length === 0) {
                    return true;
                }
                for (let i = 0; i < a.length; i++) {
                    res = this.compareNode(a[i], b[i]);
                }
            }
            return res;
        }

        getMaxDepth(nodes) {
            let isArray = Array.isArray(nodes);
            let sumCount;
            if (isArray) {
                sumCount = nodes.reduce((acc, cur) => acc + cur.subEvents, 0);
            } else {
                sumCount = nodes.subEvents;
            }
            let width = sumCount * 100.0 / this.sumCount;
            if (width < 0.1) {
                return 0;
            }
            let children = isArray ? this.splitChildrenForNodes(nodes) : nodes.callStack;
            let childDepth = 0;
            if (children) {
                for (let child of children) {
                    childDepth = Math.max(childDepth, this.getMaxDepth(child));
                }
            }
            return childDepth + 1;
        }

        splitChildrenForNodes(nodes) {
            let map = new Map();
            for (let node of nodes) {
                for (let child of node.callStack) {
                    let subNodes = map.get(child.symbol);
                    if (subNodes) {
                        subNodes.push(child);
                    } else {
                        map.set(child.symbol, [child]);
                    }
                }
            }
            let res = [];
            for (let subNodes of map.values()) {
                res.push(subNodes.length === 1 ? subNodes[0] : subNodes);
            }
            return res;
        }

        getHeatColor(widthPercentage) {
            return {
                r: Math.floor(245 + 10 * (1 - widthPercentage * 0.01)),
                g: Math.floor(110 + 105 * (1 - widthPercentage * 0.01)),
                b: 100,
            };
        }

        getJsHeatColor(widthPercentage) {
            return {
                r: Math.floor(20 + 120 * (1 - widthPercentage * 0.01)),
                g: 200,
                b: Math.floor(0 + 120 * (1 - widthPercentage * 0.01)),
            };
        }
        getV8HeatColor(widthPercentage) {
            const clampedWidth = Math.min(Math.max(widthPercentage, 0), 100);
            return {
                r: Math.floor(20 + 160 * (1 - clampedWidth * 0.01)),
                g: 200,
                b: Math.floor(0 + 160 * (1 - clampedWidth * 0.01)),
            };
        }
        attributeChangedCallback(name, oldValue, newValue) {
        }
    }
    if (!customElements.get('app-chart-flame')) {
        customElements.define('app-chart-flame', AppChartFlame);
    }

    class AppChartStatistics extends HTMLElement {
        static get observedAttributes() {
            return ['data'];
        }

        constructor() {
            super();
            const shadowRoot = this.attachShadow({mode: 'open'});
            this.color = [
                '#3391ff', // red
                '#ff9201', // green
                '#008078', // indigo
                '#0094c6', // orange
                '#ff7500', // light green
                '#2db3aa', // deep purple
                '#0076ff', // pink
                '#66adff', // purple
                '#73e6de', // blue
                '#535da6', // light blue
                '#ffab40', // lime
                '#38428c', // cyan
                '#7cdeff', // deep orange
                '#fbbf00', // blue gray
                '#2db4e2', // amber #ffc105
                '#ffd44a', // brown
                '#7a84cc', // teal
                '#ffe593'  // yellow 0xffec3d
            ];
            shadowRoot.innerHTML = `
        <style>
        :host{
            font-size:inherit;
            display:inline-flex;
            align-items: center;
            justify-content:center;
            padding: 0;
            margin: 0;
            width: 100%;
        }
        </style>
        <div style="display: flex;flex-direction: column;width: 100%;height: auto">
            <lit-table id="tbl1" noheader style="height: auto;width: 100%;">
                <lit-table-column title="key" data-index="key" width="200px" key="key" ></lit-table-column>
                <lit-table-column title="value" data-index="value" key="value"></lit-table-column>
                <lit-table-column title="time" data-index="time" key="time"></lit-table-column>
            </lit-table>
            <div id="back" style="display: none;cursor: pointer;
                border-radius: 5px;width: 35px;justify-content: center;text-align: center;
                padding: 7px 15px 7px 15px;border: 1px solid #aaa;color: #555">back</div>
            <lit-pie-chart id="chart" style="height: auto;width: 100%"></lit-pie-chart>
        </div>
        <slot></slot>
        `;
        }

        set data(json) {
            if (json.recordSampleInfo && json.recordSampleInfo.length > 0) {
                this.eventInfo = json.recordSampleInfo[window.eventIndex];
            }
            this.processNameMap = json.processNameMap;
            this.threadNameMap = json.threadNameMap;
            this.symbolsFileList = json.symbolsFileList;
            this.SymbolMap = json.SymbolMap;
            let rows = [];
            if (json.deviceTime) {
                rows.push({key: 'Device Time', value: json.deviceTime,time:''});
            }
            if (json.deviceType) {
                rows.push({key: 'Device Type', value: json.deviceType,time:''});
            }
            if (json.osVersion) {
                rows.push({key: 'OS Version', value: json.osVersion,time:''});
            }
            rows.push({key: 'Script Version', value: '1.0.0.241031',time:''});
            if (json.deviceCommandLine) {
                rows.push({key:'Record cmdline',value: json.deviceCommandLine,time:''});
            }
            rows.push({key:'Total Samples',value: '' + json.totalRecordSamples,time:''});
            if (this.eventInfo) {
                rows.push({key:'Event Type',
                          value:this.eventInfo.eventConfigName,time:this.getSampleWeight(this.eventInfo.eventCount)});
                this.initChartData();
            }
            this.table.dataSource = rows;
        }

        getSampleWeight(count) {
            if (this.eventInfo.eventConfigName.includes('task-clock') ||
                this.eventInfo.eventConfigName.includes('cpu-clock')) {
                return (count / 1000000.0).toFixed(3) + ' ms';
            } else {
                return ''+count;
            }
        }

        getProcessName(pid) {
            let name = this.processNameMap[pid];
            return name ? `Process: ${pid} (${name})` : 'Process: '+pid.toString();
        }

        getThreadName(tid) {
            let name = this.threadNameMap[tid];
            return name ? `Thread: ${tid} (${name})` : 'Thread: '+tid.toString();
        }

        getLibName(fileId) {
            return 'Library: '+this.symbolsFileList[fileId];
        }

        getFuncName(funcId) {
            return 'Function: '+this.SymbolMap[funcId].symbol;
        }

        connectedCallback() {
            this.table = this.shadowRoot.getElementById('tbl1');
            this.chart = this.shadowRoot.getElementById('chart');
            this.backBt = this.shadowRoot.getElementById('back');
            this.backBt.addEventListener('mouseover',e=>{
                this.backBt.style.borderColor = '#42b983';
                this.backBt.style.color = '#42b983';
            });
            this.backBt.addEventListener('mouseout',e=>{
                this.backBt.style.borderColor = '#aaa';
                this.backBt.style.color = '#555';
            });
            this.chartMaxCount = 126;
            this.backBt.addEventListener('click',this.back.bind(this));
            this.chart.chartClickListener = (item) => {
                if (item && item.id !== -1) {
                    let ds = this.table.dataSource;
                    if (item.name.startsWith('Process')) {
                        let pName = item.name.slice(8);
                        if (!ds.find(item => item.key === 'Process')) {
                            ds.push({key:'Process',value:pName,time:item.time});
                        }
                        this.chart.title = 'Threads in process ' + pName;
                        let find = this.eventInfo.processes.find(process => item.id === process.pid);
                        this.clickProcess(find);
                    } else if (item.name.startsWith('Thread')) {
                        let tName = item.name.slice(7);
                        if (!ds.find(item => item.key === 'Thread')) {
                            ds.push({key:'Thread',value:tName,time:item.time});
                        }
                        this.chart.title = 'Libraries in thread ' + tName;
                        let find = this.clickProcessData.threads.find(thread => item.id === thread.tid);
                        this.clickThread(find);
                    } else if (item.name.startsWith('Library')) {
                        let libName = item.name.slice(8);
                        if (!ds.find(item => item.key === 'Library')) {
                            ds.push({key:'Library',value:libName,time:item.time});
                        }
                        this.chart.title = 'Function in library ' + libName;
                        let find = this.clickThreadData.libs.find(lib => item.id === lib.fileId);
                        this.clickLib(find);
                    }
                    this.table.dataSource = ds;
                }
            };
        }

        initChartData() {
            if (Array.isArray(this.eventInfo.processes)) {
                function compare(property) {
                    return function (a,b) {
                        return b[property] - a[property];
                    }
                }
                this.eventInfo.processes.sort(compare('eventCount'));
                let chartSource = [];
                let otherValue = 0;
                this.eventInfo.processes.forEach((process,index) => {
                    if (index < 40) {
                        chartSource.push({
                            id:process.pid,
                            name: this.getProcessName(process.pid),
                            value: (process.eventCount / this.eventInfo.eventCount).toFixed(3),
                            color: this.color[index],
                            time: this.getSampleWeight(process.eventCount)
                        });
                    } else {
                        otherValue += process.eventCount;
                    }
                });
                if (otherValue > 0) {
                    chartSource.push({
                        id : -1,
                        name: 'Other: Represents a collection of items which proporiton of count ranked very low',
                        value: (otherValue / this.eventInfo.eventCount).toFixed(3),
                        color: '#888888',
                        time: this.getSampleWeight(otherValue)
                    });
                }
                chartSource.sort((a, b) => { return b.time - a.time });
                this.processDs = chartSource;
                this.chart.dataSource = chartSource;
                this.chart.title = 'Processes in event type ' + this.eventInfo.eventConfigName;
            }
        }

        back() {
            if (this.currentLevel === 'Function in Library') {
                this.chart.title = 'Libraries in thread ' + this.getThreadName(this.clickThreadData.tid).slice(7);
                this.chart.dataSource = this.libDs;
                this.currentLevel = 'Library in Thread';
            } else if (this.currentLevel === 'Library in Thread') {
                this.chart.title = 'Threads in process ' + this.getProcessName(this.clickProcessData.pid).slice(8);
                this.chart.dataSource = this.threadDs;
                this.currentLevel = 'Thread in Process';
            } else {
                this.chart.title = 'Processes in event type ' + this.eventInfo.eventConfigName;
                this.chart.dataSource = this.processDs;
                this.backBt.style.display = 'none';
            }
            let row = this.table.dataSource;
            if (Array.isArray(row)) {
                row.pop();
                this.table.dataSource = row;
            }
        }

        /**
         * chart click process
         *
         * @param process
         */
        clickProcess(process)
        {
            if (process && process.threads) {
                this.backBt.style.display = 'flex';
                this.currentLevel = 'Thread in Process';
                this.clickProcessData = process;
                let chartSource = [];
                let chartTotal = 0;
                let count = 0;
                let filter = process.threads.filter(item => item.eventCount / process.eventCount > 0.001);
                let total = 0;
                filter.forEach(item=>{ total += item.eventCount });
                total = process.eventCount;
                for (let item of filter) {
                    if (count >= this.chartMaxCount) {
                        break;
                    }
                    if (item.isMergedThread === "true") {
                        continue;
                    }
                    chartSource.push({
                        id:item.tid,
                        name: this.getThreadName(item.tid),
                        value: (item.eventCount / total).toFixed(6),
                        color: this.color[count % this.color.length],
                        time: this.getSampleWeight(item.eventCount)
                    });
                    chartTotal += item.eventCount;
                    count++;
                }
                if (count < this.chartMaxCount && chartTotal < process.eventCount) {
                    chartSource.push({
                        id : -1,
                        name: 'Other: Represents a collection of items which proporiton of count less than 1% or ranked very low',
                        value: ((process.eventCount - chartTotal) / process.eventCount).toFixed(6),
                        color: '#888888',
                        time: this.getSampleWeight(process.eventCount - chartTotal)
                    });
                } else {
                    this.addOtherItem(count, total, chartTotal, chartSource);
                }
                chartSource.sort((a, b) => { return b.time - a.time });
                this.threadDs = chartSource;
                this.chart.dataSource = chartSource;
            }
        }

        /**
         * chart click thread
         * @param thread
         */
        clickThread(thread)
        {
            if (thread && thread.libs) {
                this.currentLevel = 'Library in Thread';
                let chartSource = [];
                let chartTotal = 0;
                let count = 0;
                this.clickThreadData = thread;
                let filter = thread.libs.filter(item => item.eventCount / thread.eventCount > 0.001);
                let total = 0;
                filter.forEach(item=>{ total += item.eventCount });
                total = thread.eventCount;
                for (let item of filter) {
                    if (count < this.chartMaxCount) {
                        chartSource.push({
                            id:item.fileId,
                            name: this.getLibName(item.fileId),
                            value: (item.eventCount / total).toFixed(6),
                            color: this.color[count % this.color.length],
                            time: this.getSampleWeight(item.eventCount)
                        });
                        chartTotal += item.eventCount;
                        count ++;
                    }
                    if (count >= this.chartMaxCount) {
                        break;
                    }
                }
                if (count < this.chartMaxCount && chartTotal < thread.eventCount) {
                    chartSource.push({
                        id : -1,
                        name: 'Other: Represents a collection of items which proporiton of count less than 1% or ranked very low',
                        value: ((thread.eventCount - chartTotal) / thread.eventCount).toFixed(6),
                        color: '#888888',
                        time: this.getSampleWeight(thread.eventCount - chartTotal)
                    });
                } else {
                    this.addOtherItem(count, total, chartTotal, chartSource);
                }
                chartSource.sort((a, b) => { return b.time - a.time })
                this.libDs = chartSource;
                this.chart.dataSource = chartSource;
            }
        }

        /**
         * chart click lib
         * @param lib
         */
        clickLib(lib) {
            if (lib && lib.functions) {
                this.currentLevel = 'Function in Library'
                let chartSource = [];
                let chartTotal = 0;
                let count = 0;
                let filter = lib.functions.filter(item => item.counts[1] / lib.eventCount > 0.001);
                let total = lib.eventCount;
                let countTotal = 0;
                filter.forEach(item=>{ countTotal += item.counts[1]});
                for (let item of filter) {
                    if (count < this.chartMaxCount) {
                        chartSource.push({
                            id:item.symbol,
                            name: this.getFuncName(item.symbol),
                            value: (item.counts[1] / total).toFixed(6),
                            color: this.color[count % this.color.length],
                            time: this.getSampleWeight(item.counts[1])
                        });
                        chartTotal += item.counts[1];
                        count++;
                    }
                    if (count >= this.chartMaxCount) {
                        break;
                    }
                }
                if (count < this.chartMaxCount && countTotal < lib.eventCount) {
                    chartSource.push({
                        id : -1,
                        name: 'Other: Represents a collection of items which proporiton of count less than 1% or ranked very low',
                        value: ((lib.eventCount - countTotal) / lib.eventCount).toFixed(6),
                        color: '#888888',
                        time: this.getSampleWeight(lib.eventCount - countTotal)
                    });
                } else {
                    this.addOtherItem(count,total,chartTotal,chartSource);
                }
                chartSource.sort((a, b) => { return b.time - a.time });
                this.chart.dataSource = chartSource;
            }
        }

        addOtherItem(count,total,chartTotal,chartSource) {
            if (count >= this.chartMaxCount && total > chartTotal) {
                chartSource.push({
                    id : -1,
                    name: 'Other: Represents a collection of items which proporiton of count less than 1% or ranked very low',
                    value: ((total - chartTotal) / total).toFixed(6),
                    color: '#888888',
                    time: this.getSampleWeight(total - chartTotal)
                });
            }
        }

        attributeChangedCallback(name, oldValue, newValue) {
            if (name === 'color' && this.loading) {
                this.loading.style.color = newValue;
            }
            if (name === 'size' && this.loading) {
                this.loading.style.fontSize = newValue + 'px';
            }
        }
    }
    if (!customElements.get('app-chart-statistics')) {
        customElements.define('app-chart-statistics', AppChartStatistics);
    }

    class AppFlameGraph extends HTMLElement {
        static get observedAttributes() {
            return ['color', 'size'];
        }

        constructor() {
            super();
            const shadowRoot = this.attachShadow({mode: 'open'});
            shadowRoot.innerHTML = `
        <style>
        :host{
            font-size:inherit;
            display:inline-flex;
            align-items: center;
            justify-content:center;
            width: 100%;
        }
        </style>
        <div style="width: 100%;display: flex;flex-direction: column">
            <lit-select id="typeSelect" default-value="1" mode="single" style="width:40vw;margin-bottom: 10px;align-self: flex-end">
                    <lit-select-option value="1">Show percentage of event count relative to the current thread</lit-select-option>
                    <lit-select-option value="2">Show percentage of event count relative to the current process</lit-select-option>
                    <lit-select-option value="3">Show percentage of event count relative to all process</lit-select-option>
                    <lit-select-option value="4">show event count</lit-select-option>
                    <lit-select-option value="5">show event count in milliseconds</lit-select-option>
            </lit-select>
            <div id="panel" style="width: 100%"></div>
        </div>
        <slot></slot>
        `;
        }

        get data() {
            return this._json || null;
        }

        set data(json) {
            // 如果已经给过值,不重新刷新
            if (this.isFinished) {
                return;
            }
            this._json = json;
            this.panel = this.shadowRoot.getElementById('panel');
            this.panel.innerHTML = '';
            let processes = json.recordSampleInfo[window.eventIndex].processes;
            processes.slice(0).forEach(it => {
                it.threads.sort((a, b) => { return b.eventCount - a.eventCount });
                it.threads.slice(0).forEach(th => {
                    let pid = it.pid;
                    let processName = json.processNameMap[it.pid];
                    let tid = th.tid;
                    let threadName = json.threadNameMap[th.tid];
                    let eventCount = th.eventCount;
                    let sampleCount = th.sampleCount;
                    let g = th.CallOrder;
                    let flame = document.createElement('app-chart-flame');
                    flame.style.width = '100%';
                    flame.style.height = 'auto';
                    flame.style.display = 'flex';
                    this.panel.appendChild(flame);
                    flame.data = {
                        type:this.type||1,
                        pid, processName, tid, threadName, eventCount, sampleCount, CallOrder:g
                    };
                })
            })
            this.isFinished = true;
        }

        connectedCallback() {
            this.isFinished = false;
            this.panel = this.shadowRoot.getElementById('panel');
            this.typeSelect = this.shadowRoot.getElementById('typeSelect');
            this.typeSelect.onchange = ev => {
                this.type = parseInt(ev.detail.value);
                this.isFinished = false;
                this.data = window.data;
            }
        }

        attributeChangedCallback(name, oldValue, newValue) {
            if (name === 'color' && this.loading) {
                this.loading.style.color = newValue;
            }
            if (name === 'size' && this.loading) {
                this.loading.style.fontSize = newValue + 'px';
            }
        }
    }
    if (!customElements.get('app-flame-graph')) {
        customElements.define('app-flame-graph', AppFlameGraph);
    }

    class AppFunction extends HTMLElement {
        static get observedAttributes() {
            return ['color', 'size'];
        }

        constructor() {
            super();
            const shadowRoot = this.attachShadow({mode: 'open'});
            shadowRoot.innerHTML = `
        <style>
        :host{
            font-size:inherit;
            display:inline-flex;
            align-items: center;
            justify-content:center;
            padding: 0;
            margin: 0;
            width: 100%;
        }
        </style>
        <div style="width: 100%;display: flex;flex-direction: column">
            <lit-table id="table" noheader style="width: 100%;">
                <lit-table-column title="key" data-index="key" width="200px" key="key" ></lit-table-column>
                <lit-table-column title="value" data-index="value" width="1fr" key="value"></lit-table-column>
            </lit-table>
            <lit-select id="typeSelect" default-value="1" mode="single" style="width:500px;margin-bottom: 10px;margin-top:10px;align-self: flex-end">
                    <lit-select-option value="1">Show percentage of event count relative to the current thread</lit-select-option>
                    <lit-select-option value="2">Show percentage of event count relative to the current process</lit-select-option>
                    <lit-select-option value="3">Show percentage of event count relative to all process</lit-select-option>
                    <lit-select-option value="4">show event count</lit-select-option>
                    <lit-select-option value="5">show event count in milliseconds</lit-select-option>
            </lit-select>
            <app-chart-flame id="flame1"></app-chart-flame>
            <app-chart-flame id="flame2"></app-chart-flame>
        </div>
        <slot></slot>
        `;
        }

        getNodesMatchingFuncId(root, funcId) {
            let nodes = [];

            function recursiveFn(node) {
                if (node.symbol === funcId) {
                    nodes.push(node);
                } else {
                    for (let child of node.callStack) {
                        recursiveFn(child);
                    }
                }
            }

            recursiveFn(root);
            return nodes;
        }

        get dataSource() {
            return this._dataSource;
        }

        getReverseData(rg, funId) {

        }

        set dataSource(val) {
            this._dataSource = val;
            this.table.dataSource = [
                {key: 'Event Type', value: data.recordSampleInfo[window.eventIndex].eventConfigName},
                {key: 'Process', value: val.process},
                {key: 'Thread', value: val.thread},
                {key: 'Library', value: val.library},
                {key: 'Function', value: val.fun}
            ];
            let filterProcess =
                data.recordSampleInfo[window.eventIndex].processes.filter(it => it.pid === val.processId);
            let filterThread = filterProcess[0].threads.filter(it => it.tid === val.threadId);
            let filterG = filterThread[0].CallOrder;
            let filterRG = filterThread[0].CalledOrder;
            let c;
            let rc;
            let findF = (obj) => {
                if (Array.isArray(obj)) {
                    obj.forEach(it => {
                        if (it.symbol === val.funId) {
                            c = it;
                            return;
                        } else {
                            if (it.callStack && it.callStack.length > 0) {
                                findF(it.callStack);
                            }
                        }
                    });
                } else {
                    findF(obj.callStack);
                }
            };
            // 合并倒树结构
            let mergeRc = (obj) => {
                let rc = {};
                let _rc = this.getNodesMatchingFuncId(obj, val.funId);// 将rg树中 为funId值的节点 形成一个数组
                let _sumCount = _rc.reduce((acc, cur) => acc + cur.subEvents, 0);// 计算eventCount值
                let splitChildrenForNodes = (nodes) => {
                    let map = new Map();
                    for (let node of nodes) {
                        if (node.callStack) {
                            for (let child of node.callStack) {
                                let subNodes = map.get(child.symbol);
                                if (subNodes) {
                                    subNodes.push(child);
                                } else {
                                    map.set(child.symbol, [child]);
                                }
                            }
                        }
                    }
                    let res = [];
                    for (let key of map.keys()) {
                        let subNodes = map.get(key);
                        res.push({
                            selfEvents: 0,
                            subEvents: subNodes.reduce((acc, cur) => acc + cur.subEvents, 0),
                            symbol: key,
                            callStack: splitChildrenForNodes(subNodes)
                        });
                    }
                    return res;
                };
                let children = splitChildrenForNodes(_rc);
                return {
                    selfEvents: 0,
                    subEvents: _sumCount,
                    symbol: val.funId,
                    callStack: children
                };
            }
            findF(filterG);
            rc = mergeRc(filterRG);
            c = mergeRc(filterG);
            this.flame1.data = {
                pid: val.processId,
                processName: val.processName,
                tid: val.threadId,
                threadName: val.threadName,
                eventCount: null,
                sampleCount: null,
                type: this.type || 1,
                funcName: `Functions called by ${val.fun}`,
                CallOrder: c
            };

            this.flame2.data = {
                pid: val.processId,
                processName: val.processName,
                tid: val.threadId,
                threadName: val.threadName,
                eventCount: null,
                sampleCount: null,
                reverse: true,
                type: this.type || 1,
                funcName: `Functions calling ${val.fun}`,
                CallOrder: rc
            };
        }

        connectedCallback() {
            this.table = this.shadowRoot.getElementById('table');
            this.flame1 = this.shadowRoot.getElementById('flame1');
            this.flame2 = this.shadowRoot.getElementById('flame2');
            this.typeSelect = this.shadowRoot.getElementById('typeSelect');
            this.typeSelect.onchange = (e) => {
                this.type = parseInt(e.detail.value);
                this.dataSource = this.dataSource;
            };
        }

        attributeChangedCallback(name, oldValue, newValue) {

        }
    }
    if (!customElements.get('app-function')) {
        customElements.define('app-function', AppFunction);
    }

    class AppSimpleTable extends HTMLElement {
        static get observedAttributes() {
            return ['color', 'size'];
        }

        constructor() {
            super();
            const shadowRoot = this.attachShadow({mode: 'open'});
            shadowRoot.innerHTML = `
        <style>
        :host{
            font-size:inherit;
            display:inline-flex;
            align-items: center;
            justify-content:center;
        }
        .loading{
            display: block;
            width: 1em;
            height: 1em;
            margin: auto;
            animation: rotate 1.4s linear infinite;
        }
        .circle {
            stroke: currentColor;
            animation:  progress 1.4s ease-in-out infinite;
            stroke-dasharray: 80px, 200px;
            stroke-dashoffset: 0px;
            transition:.3s;
        }
        :host(:not(:empty)) .loading{
            margin:.5em;
        }
        @keyframes rotate{
            to{
                transform: rotate(360deg);
            }
        }
        @keyframes progress {
            0% {
              stroke-dasharray: 1px, 200px;
              stroke-dashoffset: 0px;
            }
            50% {
              stroke-dasharray: 100px, 200px;
              stroke-dashoffset: -15px;
            }
            100% {
              stroke-dasharray: 100px, 200px;
              stroke-dashoffset: -125px;
            }
        }
        </style>
        <div style="width: 100%;height: auto;">
            <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>
            <div style="display: flex;flex-direction: column;align-items: flex-end;width: 100%;">
                <div style="display: flex;flex-direction: row;align-items: center;justify-content: space-between;width: 100%;margin-bottom: 10px">
                    <lit-input id="keyword" icon="search" placeholder="Please enter a keyword" style="width: 300px" allow-clear></lit-input>
                    <lit-select id="typeSelect" default-value="1" mode="single" style="width: 400px;margin-bottom: 10px">
                        <lit-select-option value="1">show percentage of event count</lit-select-option>
                        <lit-select-option value="2">show event count</lit-select-option>
                        <lit-select-option value="3">show event count in milliseconds</lit-select-option>
                    </lit-select>
                </div>
                <lit-table id="table" style="width: calc(100vw - 40px);">
                    <lit-table-column title="Total" data-index="total" width="100px" key="total" order></lit-table-column>
                    <lit-table-column title="Self" data-index="self" width="100px" key="self" order></lit-table-column>
                    <lit-table-column title="Samples" data-index="samples" width="100px" key="samples" order></lit-table-column>
                    <lit-table-column title="Process" data-index="process" width="250px" key="process" order></lit-table-column>
                    <lit-table-column title="Thread" data-index="thread" width="250px" key="thread" order></lit-table-column>
                    <lit-table-column title="Library" data-index="library" width="250px" key="library" order></lit-table-column>
                    <lit-table-column title="Function" data-index="fun" key="fun" order></lit-table-column>
                </lit-table>
                <div style="height: 140px">
                    <lit-pagination id="pagination" show-size-changer page-size="10" page-size-options="[20,50,200]" style="margin-top: 10px;">
    <!--                    <template slot="showTotal"><label>{{range[0]}}-{{range[1]}} of {{total}} items</label></template>-->
                    </lit-pagination>
                </div>
            </div>

        </div>
        <slot></slot>
        `;
        }

        set data(json) {
            if (json.recordSampleInfo && json.recordSampleInfo.length > 0) {
                this.processNameMap = json.processNameMap;
                this.threadNameMap = json.threadNameMap;
                this.symbolsFileList = json.symbolsFileList;
                this.SymbolMap = json.SymbolMap;
                this.eventInfo = json.recordSampleInfo[window.eventIndex];
                this.initTableData().then(() => {
                    this.loading.style.display = 'none';
                    this.pagination.current = 1;
                    this.pagination.total = this.source.length;
                    this.table.dataSource = this.paginationHandler(1,this.pagination.pageSize);
                });
            }
        }

        paginationHandler(page,pageSize,data) {
            let offset = (page - 1) * pageSize;
            let arr = [];
            if (this.searchKey && this.searchKey.length > 0 && data) {
                arr = (offset + pageSize >= data.length) ?
                      data.slice(offset, data.length) : data.slice(offset, offset + pageSize);
            } else {
                arr = (offset + pageSize >= this.source.length) ?
                      this.source.slice(offset, this.source.length) : this.source.slice(offset, offset + pageSize);
            }
            arr.forEach(item=>{
                item.total = this.getSampleWeight(item.totalCount);
                item.self = this.getSampleWeight(item.selfCount);
            })
            return arr;
        }

        async initTableData() {
            this.source = [];
            this.eventInfo.processes.forEach(process => {
                process.threads.forEach(thread => {
                    if (thread.isMergedThread === "true") {
                        return;
                    }
                    thread.libs.forEach(lib => {
                        lib.functions.forEach(fun => {
                            this.source.push({
                                process: this.getProcessName(process.pid),
                                processId:process.pid,
                                thread: this.getThreadName(thread.tid),
                                threadId:thread.tid,
                                library: this.getLibName(lib.fileId),
                                libraryId:lib.fileId,
                                fun: this.getFuncName(fun.symbol),
                                funId: fun.symbol,
                                totalCount: fun.counts[2],
                                selfCount: fun.counts[1],
                                samples: fun.counts[0],
                                total:this.getSampleWeight(fun.counts[2]),
                                self:this.getSampleWeight(fun.counts[1]),
                            });
                        });
                    });
                });
            });
            function compare(property) {
                return function (a, b) {
                    return b[property] - a[property];
                };
            }
            this.source.sort(compare('totalCount'));
        }

        getSampleWeight(count) {
            if (this.eventType.value === '1') {
                return (count * 100.0 / this.eventInfo.eventCount).toFixed(2) + '%';
            } else if (this.eventType.value === '2') {
                return count + '';
            } else {
                return (count / 1000000.0).toFixed(3);
            }
        }

        getProcessName(pid) {
            let name = this.processNameMap[pid];
            return name ? `${pid} (${name})` : pid.toString();
        }

        getThreadName(tid) {
            let name = this.threadNameMap[tid];
            return name ? `${tid} (${name})` : tid.toString();
        }

        getLibName(fileId) {
            return this.symbolsFileList[fileId];
        }

        getFuncName(funcId) {
            return this.SymbolMap[funcId].symbol;
        }

        get size() {
            return this.getAttribute('size') || '';
        }

        get color() {
            return this.getAttribute('color') || '';
        }

        set size(value) {
            this.setAttribute('size', value);
        }

        set color(value) {
            this.setAttribute('color', value);
        }

        connectedCallback() {
            this.suffix = '';
            this.loading = this.shadowRoot.getElementById('loading');
            this.keyword = this.shadowRoot.getElementById('keyword');
            this.eventType = this.shadowRoot.getElementById('typeSelect');
            this.pagination = this.shadowRoot.getElementById('pagination');
            this.table = this.shadowRoot.getElementById('table');
            this.eventType.addEventListener('change',this.updateTableSource.bind(this));
            this.pagination.addEventListener('onChange',this.updateTableSource.bind(this));
            this.pagination.addEventListener('onShowSizeChange',this.updateTableSource.bind(this));
            this.size && (this.size = this.size);
            this.color && (this.color = this.color);
            this.ds = [];
            this.keyword.addEventListener('input',e=>{
                if (this.searchKey !== this.keyword.value) {
                    this.searchKey = this.keyword.value;
                    this.pagination.current = 1;
                    this.ds = this.source.filter(item => item.process.indexOf(this.searchKey) !== -1
                        || item.thread.indexOf(this.searchKey) !== -1
                        || item.library.indexOf(this.searchKey) !== -1 || item.fun.indexOf(this.searchKey) !== -1);
                    this.pagination.total = this.ds.length;
                    this.table.dataSource =
                        this.paginationHandler(this.pagination.current,parseInt(this.pagination.pageSize),this.ds);
                }
            });
            this.keyword.addEventListener('onClear',e=>{
                this.searchKey = undefined;
                this.pagination.current = 1;
                this.pagination.total = this.source.length;
                this.table.dataSource =
                    this.paginationHandler(this.pagination.current,parseInt(this.pagination.pageSize));
            });
            this.table.addEventListener('ColumnClick',evt => {
                this.sortByColumn(evt.detail);
            });
        }

        sortByColumn(detail) {
            function compare(property,sort,type) {
                return function (a, b) {
                    if (type === 'number') {
                        return sort === 2 ? b[property] - a[property] : a[property] - b[property];
                    } else {
                        if (b[property] > a[property]) {
                            return  sort === 2 ? 1 : -1;
                        } else if (b[property] === a[property]) {
                            return 0;
                        } else {
                            return  sort === 2 ? -1 : 1;
                        }
                    }
                };
            }

            console.log(detail.key);
            if (detail.key === 'total') {
                this.ds.sort(compare('totalCount',detail.sort,'number'));
            } else if (detail.key === 'self') {
                this.ds.sort(compare('selfCount',detail.sort,'number'));
            } else if (detail.key === 'samples') {
                this.ds.sort(compare('samples',detail.sort,'number'));
            } else {
                this.ds.sort(compare(detail.key,detail.sort,'string'));
            }
            this.pagination.current = 1;
            this.pagination.total = this.ds.length;
            this.table.dataSource = this.paginationHandler(this.pagination.current,parseInt(this.pagination.pageSize),this.ds);
        }

        updateTableSource(e) {
            if (e.type === 'change') {
                this.eventType.value = e.detail.value;
                this.suffix = e.detail.value === '3' ? '(in ms)' : '';
            }
            if (this.ds.length !== 0) {
                this.pagination.total = this.ds.length;
                this.table.dataSource =
                    this.paginationHandler(this.pagination.current,parseInt(this.pagination.pageSize),this.ds);
            } else {
                this.table.dataSource =
                    this.paginationHandler(this.pagination.current,parseInt(this.pagination.pageSize));
            }
        }

        attributeChangedCallback(name, oldValue, newValue) {
            if (name === 'color' && this.loading) {
                this.loading.style.color = newValue;
            }
            if (name === 'size' && this.loading) {
                this.loading.style.fontSize = newValue + 'px';
            }
        }
    }
    if (!customElements.get('app-simple-table')) {
        customElements.define('app-simple-table', AppSimpleTable);
    }

    (function () {

        function createPromise(callback) {
            if (callback) {
                return new Promise((resolve, _) => callback(resolve));
            }
            return new Promise((resolve, _) => resolve());
        }

        function initGlobalObjects() {
            let recordData = document.querySelector('#record_data').textContent;
            if (recordData.trim().length>0) {
                return new Promise((resolve, reject) => {
                    resolve(JSON.parse(recordData));
                });
            } else {
                return fetch('data.json').then(response => response.json());
            }
        }
        function waitDocumentReady() {
            return createPromise((resolve) =>  document.addEventListener('DOMContentLoaded', resolve));
        }
        createPromise()
            .then(waitDocumentReady)
            .then(initGlobalObjects)
            .then((json) => {
                window.data = json;
                window.eventIndex = 0;
                let eventSelector = document.querySelector('#events');
                if (json.recordSampleInfo && json.recordSampleInfo.length > 0) {
                    let events = [];
                    json.recordSampleInfo.forEach((e, index) => {
                        events.push({key:index+'',val:e.eventConfigName})
                    });
                    eventSelector.dataSource = events;
                }
                let chart = document.querySelector('#chart-statistics');
                let loading = document.querySelector('#loading');
                let table = document.querySelector('#sample-table');
                let appFunc = document.querySelector('#function');
                let flame = document.querySelector('#flame-graph');
                let tabs = document.querySelector('#tabs')
                let pane4 = document.querySelector('#pane4')
                chart.data = json;
                table.data = json;
                table.addEventListener('onRowClick', e => {
                    pane4.hide = false;
                    tabs.activePane('4');
                    appFunc.dataSource = e.detail;
                });
                tabs.onTabClick = (e) => {
                    if (e.detail.key === '3') {
                        flame.isFinished = false;
                        flame.data = json;
                    }
                };
                eventSelector.addEventListener('change',(e)=>{
                    loading.style.display = 'flex';
                    pane4.hide = true;
                    window.eventIndex = parseInt( e.detail.value);
                    chart.data = json;
                    table.data = json;
                    flame.isFinished = false;
                    flame.data = json;
                    if (tabs.activekey === '4') {
                        tabs.activePane('1');
                    }
                    loading.style.display = 'none';
                });
            });
    }())
</script>
<div style="width: 100%;height: 100%">
    <div style="width: 100%;display: flex;flex-direction: column;align-items: center">
        <lit-loading id="loading" size="32" style="display: none"></lit-loading>
    </div>
    <div style="display: flex;flex-direction: row;align-items: center;padding: 15px">
            <span style="font-weight: bold;margin-right: 10px">Event Type :</span>
            <lit-select id="events" default-value="0" style="width: 400px"></lit-select>
    </div>
    <lit-tabs id='tabs' position="top-left" activekey="1" mode="flat">
        <lit-tabpane id="pane1" tab="Chart Statistics" key="1">
            <app-chart-statistics id="chart-statistics"></app-chart-statistics>
        </lit-tabpane>
        <lit-tabpane id="pane2" tab="Sample Table" key="2">
            <app-simple-table id="sample-table"></app-simple-table>
        </lit-tabpane>
        <lit-tabpane id="pane3" tab="Flame Graph" key="3">
            <app-flame-graph id="flame-graph"></app-flame-graph>
        </lit-tabpane>
        <lit-tabpane id="pane4" tab="Function" key="4" hide>
            <app-function id="function" style="width: 100%"></app-function>
        </lit-tabpane>
    </lit-tabs>
</div>
<script id="record_data" type="application/json">