<!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');
}
}
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);
}
disconnectedCallback() {
}
adoptedCallback() {
console.log('Custom square element moved to new page.');
}
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',
'bordered',
'allow-clear',
'rows',
'maxlength',
'type',
'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>
`;
}
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));
};
}
}
disconnectedCallback() {
}
adoptedCallback() {
console.log('Custom square element moved to new page.');
}
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',
'show-quick-jumper',
'page-size-options',
'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>
`;
}
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`;
}
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) {
}
}
}
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');
}
disconnectedCallback() {
}
adoptedCallback() {
}
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) {
}
getMousePost(event) {
const { clientX, clientY } = event;
const { top, left } = this.chartView.getBoundingClientRect();
const x = (clientX - left);
const y = (clientY - top);
return { x, y };
}
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;
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;
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',
'disabled',
'loading',
'allow-clear',
'show-search',
'list-height',
'border',
'mode',
];
}
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;
}
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');
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}));
}
this.initOptions();
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;
}
this.inputElement.onfocus = ev => {
if (this.hasAttribute('disabled')) return;
if (this.inputElement.value.length > 0) {
this.inputElement.placeholder = this.inputElement.value;
this.inputElement.value = '';
}
if (this.hasAttribute('show-search')) {
this.searchElement.style.display = 'flex';
this.iconElement.style.display = 'none';
}
this.querySelectorAll('lit-select-option').forEach(a => {
a.style.display = 'flex';
})
}
this.inputElement.onblur = ev => {
if (this.hasAttribute('disabled')) return;
if (this.isMultiple()) {
if (this.hasAttribute('show-search')) {
this.searchElement.style.display = 'none';
this.iconElement.style.display = 'flex';
}
} else {
if (this.inputElement.placeholder !== this.defaultPlaceholder) {
this.inputElement.value = this.inputElement.placeholder;
this.inputElement.placeholder = this.defaultPlaceholder;
}
if (this.hasAttribute('show-search')) {
this.searchElement.style.display = 'none';
this.iconElement.style.display = 'flex';
}
}
}
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';
}
})
}
}
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
}
}));
}
}
};
}
initOptions() {
this.querySelectorAll('lit-select-option').forEach(a => {
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', '');
}
}
a.addEventListener('onSelected', (e) => {
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;
}
if (a.hasAttribute('selected')) {
a.removeAttribute('selected');
} else {
a.setAttribute('selected', '');
}
this.dispatchEvent(new CustomEvent('change', {detail: e.detail}));
});
});
}
clear() {
this.inputElement.value = '';
this.inputElement.placeholder = this.defaultPlaceholder;
}
reset() {
this.querySelectorAll('lit-select-option').forEach(a => {
[...this.querySelectorAll('lit-select-option')].forEach(a => a.removeAttribute('selected'));
if (a.getAttribute('value') === this.defaultValue) {
this.inputElement.value = a.textContent;
a.setAttribute('selected', '');
}
});
}
disconnectedCallback() {
}
adoptedCallback() {
console.log('Custom square element moved to new page.');
}
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>
`;
}
connectedCallback() {
}
disconnectedCallback() {
}
adoptedCallback() {
console.log('Custom square element moved to new page.');
}
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>
`;
}
connectedCallback() {
if (!this.hasAttribute('disabled')) {
this.onclick=ev => {
this.dispatchEvent(new CustomEvent('onSelected', {
detail: {
selected:true,
value: this.getAttribute('value'),
text: this.textContent
}
}));
};
}
}
disconnectedCallback() {
}
adoptedCallback() {
console.log('Custom square element moved to new page.');
}
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>
`;
}
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(' ');
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(' ');
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();
}
});
});
}
disconnectedCallback() {
}
adoptedCallback() {
console.log('Custom square element moved to new page.');
}
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 = [];
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');
}
};
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) {
rowElement.style.gridTemplateColumns = '60px ' + gridTemplateColumns.join(' ');
} else {
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 = '';
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) {
rowElement.style.gridTemplateColumns = '60px ' + gridTemplateColumns.join(' ');
} else {
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>
`;
}
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];
}
})
}
disconnectedCallback() {
}
adoptedCallback() {
console.log('Custom square element moved to new page.');
}
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>
`;
}
connectedCallback() {
}
disconnectedCallback() {
}
adoptedCallback() {
console.log('Custom square element moved to new page.');
}
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);
}
}
connectedCallback() {}
disconnectedCallback() {}
adoptedCallback() {}
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() {
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%)`;
}
}
}
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;
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';
}
})
}
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;
}
}
disconnectedCallback() {
}
adoptedCallback() {
console.log('Custom square element moved to new page.');
}
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;
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);
requestAnimationFrame(this.draw);
}
get c() {
return this._c;
}
zoomOut(value) {
this._c = value;
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;
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;
count = c.subEvents;
count = `${count}`;
return count;
}
getStatistics(c) {
let statistics;
switch (this.type) {
case 1:
statistics = c.subEvents * 100 / this.eventCountCurrentThread;
statistics = statistics.toFixed(2);
statistics = `${statistics}%`;
break;
case 2:
statistics = c.subEvents * 100 / this.eventCountCurrentProcess;
statistics = statistics.toFixed(2);
statistics = `${statistics}%`;
break;
case 3:
statistics = c.subEvents * 100 / this.eventCountAllProcess;
statistics = statistics.toFixed(2);
statistics = `${statistics}%`;
break;
case 4:
statistics = c.subEvents;
statistics = `${statistics}`;
break;
case 5:
statistics = c.subEvents / 1000000;
statistics = statistics.toFixed(3);
statistics = `${statistics} ms`;
break;
default:
statistics = c.subEvents * 100 / this.eventCountCurrentThread;
statistics = statistics.toFixed(2);
statistics = `${statistics}%`;
break;
}
return statistics;
}
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;
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',
'#ff9201',
'#008078',
'#0094c6',
'#ff7500',
'#2db3aa',
'#0076ff',
'#66adff',
'#73e6de',
'#535da6',
'#ffab40',
'#38428c',
'#7cdeff',
'#fbbf00',
'#2db4e2',
'#ffd44a',
'#7a84cc',
'#ffe593'
];
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);
let _sumCount = _rc.reduce((acc, cur) => acc + cur.subEvents, 0);
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">