1/* 2 * Copyright (C) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import { BaseElement, element } from '../../../../base-ui/BaseElement'; 17import { LitTable } from '../../../../base-ui/table/lit-table'; 18import { MarkStruct } from '../../../bean/MarkStruct'; 19import { SpSystemTrace } from '../../SpSystemTrace'; 20import { getTimeString } from '../sheet/TabPaneCurrentSelection'; 21import { Flag } from './Flag'; 22 23@element('tabpane-flag') 24export class TabPaneFlag extends BaseElement { 25 private flag: Flag | null = null; 26 private flagList: Array<Flag> = []; 27 private systemTrace: SpSystemTrace | undefined | null; 28 private tableDataSource: Array<MarkStruct | unknown> = []; 29 private panelTable: LitTable | undefined | null; 30 31 initElements(): void { 32 this.systemTrace = document 33 .querySelector('body > sp-application') 34 ?.shadowRoot!.querySelector<SpSystemTrace>('#sp-system-trace'); 35 this.panelTable = this.shadowRoot!.querySelector<LitTable>('.notes-editor-panel'); 36 this.panelTable!.addEventListener('row-click', (evt: unknown) => { 37 // @ts-ignore 38 if (evt.detail.data.startTime === undefined) { 39 return; 40 } 41 this.flagList = this.systemTrace?.timerShaftEL!.sportRuler?.flagList || []; 42 // 点击表格某一行后,背景变色 43 // @ts-ignore 44 let data = evt.detail.data; 45 this.systemTrace!.flagList = this.flagList || []; 46 // 页面上对应的flag变为实心有旗杆 47 this.flagList.forEach((flag, index) => { 48 if (data.startTime === flag.time) { 49 flag.selected = true; 50 this.setTableSelection(index + 1); 51 } else { 52 flag.selected = false; 53 } 54 this.systemTrace?.timerShaftEL!.sportRuler!.drawTriangle(flag.time, flag.type); 55 }); 56 }); 57 // 当鼠标移出panel时重新加载备注信息 58 this.systemTrace?.shadowRoot?.querySelector('trace-sheet')?.addEventListener( 59 'mouseout', 60 (event: unknown) => { 61 if (this.flagList.length === 0) { 62 return; 63 } 64 // @ts-ignore 65 if ((window as unknown).flagInputFocus) { 66 return; 67 } 68 let tr = this.panelTable!.shadowRoot!.querySelectorAll('.tr') as NodeListOf<HTMLDivElement>; 69 // 第一个tr是移除全部,所以跳过,从第二个tr开始,和this.slicestimeList数组的第一个对应……,所以i从1开始,在this.slicestimeList数组中取值时用i-1 70 for (let i = 1; i < tr.length; i++) { 71 tr[i].querySelector<HTMLInputElement>('#text-input')!.value = this.flagList[i - 1].text; 72 } 73 // @ts-ignore 74 event.stopPropagation(); 75 }, 76 { capture: true } 77 ); 78 new ResizeObserver((entries) => { 79 if (this.parentElement!.style.display !== 'none') { 80 this.setTableData(); 81 } 82 }).observe(this); 83 } 84 85 public setCurrentFlag(flag: Flag): void { 86 this.flagList = this.systemTrace?.timerShaftEL!.sportRuler?.flagList || []; 87 this.flag = flag; 88 // 判断当前传入的旗子是否已经存在 89 let findFlag = this.flagList.find((it) => it.time === flag.time); 90 // 如果this.flagList为空,或者没有在同一位置绘制过,就将当前的flag放进数组 91 if (!findFlag || this.flagList.length === 0) { 92 this.flagList!.push(this.flag); 93 } 94 this.setTableData(); 95 } 96 97 /** 98 * 根据this.flagList设置表格数据 99 */ 100 private setTableData(): void { 101 this.flagList = this.systemTrace?.timerShaftEL!.sportRuler?.flagList || []; 102 this.tableDataSource = []; 103 // 按照时间进行排序,保证泳道图上的旗子和表格的顺序一致 104 this.flagList.sort(function (a, b) { 105 return a.time - b.time; 106 }); 107 108 for (let flag of this.flagList) { 109 let btn = document.createElement('button'); 110 btn.className = 'remove'; 111 let color = document.createElement('input'); 112 color.type = 'color'; 113 let text = document.createElement('input'); 114 text.type = 'text'; 115 color!.value = flag.color; 116 text!.value = flag.text; 117 let flagData = new MarkStruct(btn, color.value, text.value, getTimeString(flag.time), flag.time); 118 flag.selected === true ? (flagData.isSelected = true) : (flagData.isSelected = false); 119 this.systemTrace?.timerShaftEL!.sportRuler!.drawTriangle(flag.time, flag.type); 120 this.tableDataSource.push(flagData); 121 } 122 // 表格第一行只添加一个RemoveAll按钮 123 let removeAll = document.createElement('button'); 124 removeAll.className = 'removeAll'; 125 removeAll.innerHTML = 'RemoveAll'; 126 let flagData = new MarkStruct(removeAll); 127 this.tableDataSource.unshift(flagData); 128 129 // 当前点击了哪个旗子,就将对应的表格中的那行的背景变色 130 this.tableDataSource.forEach((data, index) => { 131 // @ts-ignore 132 if (data.time === this.flag?.time) { 133 this.setTableSelection(index); 134 } 135 }); 136 this.panelTable!.recycleDataSource = this.tableDataSource; 137 this.eventHandler(); 138 this.systemTrace!.flagList = this.flagList || []; 139 } 140 141 /** 142 * 修改旗子颜色事件和移除旗子的事件处理 143 */ 144 private eventHandler(): void { 145 let tr = this.panelTable!.shadowRoot!.querySelectorAll('.tr') as NodeListOf<HTMLDivElement>; 146 this.removeAllClickEventByFlag(tr[0]); 147 // 第一个tr是移除全部,所以跳过,从第二个tr开始,和this.flagList数组的第一个对应……,所以i从1开始,在this.flagList数组中取值时用i-1 148 for (let i = 1; i < tr.length; i++) { 149 tr[i].querySelector<HTMLInputElement>('#color-input')!.value = this.flagList[i - 1].color; 150 // 点击色块修改颜色 151 this.colorInputChangeEventByFlag(i, tr[i]); 152 // 修改备注 153 tr[i].querySelector<HTMLInputElement>('#text-input')!.value = this.flagList[i - 1].text; 154 this.textInputKeyUpEventByFlag(i, tr[i]); 155 this.textInputBlurEventByFlag(i, tr[i]); 156 this.textInputFocusEventByFlag(tr[i]); 157 // 点击remove按钮移除 158 this.removeClickEventByFlag(i, tr[i]); 159 } 160 } 161 162 private removeAllClickEventByFlag(tr: HTMLDivElement): void { 163 tr.querySelector('.removeAll')!.addEventListener('click', () => { 164 this.systemTrace!.flagList = []; 165 let flagList = [...this.flagList]; 166 for (let i = 0; i < flagList.length; i++) { 167 flagList[i].hidden = true; 168 document.dispatchEvent(new CustomEvent('flag-change', { detail: flagList[i] })); 169 } 170 this.flagList = []; 171 return; 172 }); 173 } 174 175 private colorInputChangeEventByFlag(index: number, tr: HTMLDivElement): void { 176 tr.querySelector<HTMLInputElement>('#color-input')?.addEventListener('change', (event: unknown) => { 177 // @ts-ignore 178 if (this.tableDataSource[index].startTime === this.flagList[index - 1].time) { 179 // @ts-ignore 180 this.flagList[index - 1].color = event?.target.value; 181 document.dispatchEvent(new CustomEvent('flag-change', { detail: this.flagList[index - 1] })); 182 // 旗子颜色改变时,重绘泳道图 183 this.systemTrace?.refreshCanvas(true); 184 } 185 // @ts-ignore 186 event.stopPropagation(); 187 }); 188 } 189 190 private textInputKeyUpEventByFlag(index: number, tr: HTMLDivElement): void { 191 tr.querySelector<HTMLInputElement>('#text-input')?.addEventListener('keyup', (event: unknown) => { 192 // @ts-ignore 193 if (this.tableDataSource[index].startTime === this.flagList[index - 1].time && event.code === 'Enter' || event.code === 'NumpadEnter') { 194 // @ts-ignore 195 this.flagList[index - 1].text = event?.target.value; 196 document.dispatchEvent(new CustomEvent('flag-change', { detail: this.flagList[index - 1] })); 197 // 旗子颜色改变时,重绘泳道图 198 this.systemTrace?.refreshCanvas(true); 199 } 200 // @ts-ignore 201 event.stopPropagation(); 202 }); 203 } 204 205 private textInputBlurEventByFlag(index: number, tr: HTMLDivElement): void { 206 tr.querySelector<HTMLInputElement>('#text-input')?.addEventListener('blur', (event: unknown) => { 207 // @ts-ignore 208 (window as unknown).flagInputFocus = false; 209 window.publish(window.SmartEvent.UI.KeyboardEnable, { 210 enable: true, 211 }); 212 // @ts-ignore 213 if (this.tableDataSource[index].startTime === this.flagList[index - 1].time) { 214 // @ts-ignore 215 this.flagList[index - 1].text = event?.target.value; 216 document.dispatchEvent(new CustomEvent('flag-change', { detail: this.flagList[index - 1] })); 217 this.setTableData(); 218 // 旗子颜色改变时,重绘泳道图 219 this.systemTrace?.refreshCanvas(true); 220 } 221 // @ts-ignore 222 event.stopPropagation(); 223 }); 224 } 225 226 private textInputFocusEventByFlag(tr: HTMLDivElement): void { 227 tr.querySelector<HTMLInputElement>('#text-input')?.addEventListener('focus', (event: unknown) => { 228 // @ts-ignore 229 (window as unknown).flagInputFocus = true; 230 window.publish(window.SmartEvent.UI.KeyboardEnable, { 231 enable: false, 232 }); 233 let tr = this.panelTable!.shadowRoot!.querySelectorAll('.tr') as NodeListOf<HTMLDivElement>; 234 // 第一个tr是移除全部,所以跳过,从第二个tr开始,和this.flagList数组的第一个对应……,所以i从1开始,在this.flagList数组中取值时用i-1 235 for (let i = 1; i < tr.length; i++) { 236 tr[i].querySelector<HTMLInputElement>('#text-input')!.value = this.flagList[i - 1].text; 237 } 238 }); 239 } 240 241 private removeClickEventByFlag(index: number, tr: HTMLDivElement): void { 242 tr!.querySelector('.remove')?.addEventListener('click', (event: unknown) => { 243 // @ts-ignore 244 if (this.tableDataSource[index].startTime === this.flagList[index - 1].time) { 245 this.flagList[index - 1].hidden = true; 246 this.systemTrace!.flagList = this.flagList || []; 247 document.dispatchEvent(new CustomEvent('flag-change', { detail: this.flagList[index - 1] })); 248 // 移除时更新表格内容 249 this.setTableData(); 250 } 251 // @ts-ignore 252 event.stopPropagation(); 253 }); 254 } 255 256 /** 257 * 修改表格指定行数的背景颜色 258 * @param line 要改变的表格行数 259 */ 260 public setTableSelection(line: unknown): void { 261 // @ts-ignore 262 this.tableDataSource[line].isSelected = true; 263 // @ts-ignore 264 this.panelTable?.clearAllSelection(this.tableDataSource[line]); 265 // @ts-ignore 266 this.panelTable?.setCurrentSelection(this.tableDataSource[line]); 267 } 268 269 initHtml(): string { 270 return ` 271 <style> 272 :host{ 273 display: flex; 274 flex-direction: column; 275 padding: 10px 10px; 276 } 277 </style> 278 <lit-table class="notes-editor-panel" style="height: auto"> 279 <lit-table-column width="20%" data-index="startTimeStr" key="startTimeStr" align="flex-start" title="TimeStamp"> 280 </lit-table-column> 281 <lit-table-column width="10%" data-index="color" key="color" align="flex-start" title="Color"> 282 <template> 283 <div style='width:50px; height: 21px; position: relative;overflow: hidden;'> 284 <input type="color" id="color-input" style=' 285 background: var(--dark-background5,#FFFFFF); 286 padding: 0px; 287 border: none; 288 width: 60px; 289 height: 31px; 290 position: absolute; 291 top: -5px; 292 left: -5px;'/> 293 </div> 294 </template> 295 </lit-table-column> 296 <lit-table-column width="40%" data-index="text" key="text" align="flex-start" title="Remarks"> 297 <template> 298 <input type="text" id="text-input" style="width: 100%; border: none" /> 299 </template> 300 </lit-table-column> 301 <lit-table-column width="10%" data-index="operate" key="operate" align="flex-start" title="Operate"> 302 <template> 303 <button class="remove" style=' 304 background: var(--dark-border1,#262f3c); 305 color: white; 306 border-radius: 10px; 307 font-size: 10px; 308 height: 21px; 309 line-height: 21px; 310 min-width: 7em; 311 border: none; 312 cursor: pointer; 313 outline: inherit; 314 '>Remove</button> 315 </template> 316 </lit-table-column> 317 </lit-table> 318 `; 319 } 320} 321