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 { RangeSelectStruct, TraceRow } from './TraceRow'; 17import { Rect } from '../timer-shaft/Rect'; 18import { TimerShaftElement } from '../TimerShaftElement'; 19import { info } from '../../../../log/Log'; 20import './Extension'; 21import { SpSystemTrace } from '../../SpSystemTrace'; 22import {querySearchRowFuncData} from "../../../database/sql/Func.sql"; 23 24export class RangeSelect { 25 private rowsEL: HTMLDivElement | undefined | null; 26 private rowsPaneEL: HTMLDivElement | undefined | null; 27 isMouseDown: boolean = false; 28 public rangeTraceRow: Array<TraceRow<any>> | undefined; 29 public selectHandler: ((ds: Array<TraceRow<any>>, refreshCheckBox: boolean) => void) | undefined; 30 private startPageX: number = 0; 31 private startPageY: number = 0; 32 private endPageX: number = 0; 33 private endPageY: number = 0; 34 private timerShaftEL: TimerShaftElement | null | undefined; 35 private isHover: boolean = false; 36 private movingMark: string = ''; 37 private mark: { startMark: number; endMark: number } = { 38 startMark: 0, 39 endMark: 0, 40 }; 41 private trace: SpSystemTrace | null | undefined; 42 drag = false; 43 44 constructor(trace: SpSystemTrace | null | undefined) { 45 this.trace = trace; 46 this.timerShaftEL = trace?.timerShaftEL; 47 this.rowsEL = trace?.rowsEL; 48 this.rowsPaneEL = trace?.rowsPaneEL; 49 } 50 51 isInRowsEl(ev: MouseEvent): boolean { 52 return this.rowsPaneEL!.containPoint(ev, { left: 248 }); 53 } 54 55 isInSpacerEL(ev: MouseEvent): boolean { 56 return this.trace!.favoriteChartListEL!.containPoint(ev, { left: 248 }); 57 } 58 59 mouseDown(eventDown: MouseEvent): void { 60 this.startPageX = eventDown.pageX; 61 this.startPageY = eventDown.pageY; 62 if (this.isHover) { 63 this.isMouseDown = true; 64 return; 65 } 66 this.rangeTraceRow = []; 67 this.isMouseDown = true; 68 TraceRow.rangeSelectObject = undefined; 69 } 70 71 mouseUp(mouseEventUp: MouseEvent): void { 72 this.endPageX = mouseEventUp.pageX; 73 this.endPageY = mouseEventUp.pageY; 74 if (this.drag) { 75 if (this.selectHandler) { 76 this.selectHandler(this.rangeTraceRow || [], !this.isHover); 77 } 78 //如果只框选了一条泳道,查询H:RSMainThread::DoComposition数据 79 let docompositionData: Array<number> = []; 80 if (this.rangeTraceRow) { 81 this.rangeTraceRow.forEach((row) => { 82 row.docompositionList = []; 83 }); 84 docompositionData = []; 85 if ( 86 this.rangeTraceRow.length === 1 && 87 this.rangeTraceRow[0]?.getAttribute('row-type') === 'func' && 88 this.rangeTraceRow[0]?.getAttribute('name')?.startsWith('render_service') 89 ) { 90 querySearchRowFuncData( 91 'H:RSMainThread::DoComposition', 92 Number(this.rangeTraceRow[0]?.getAttribute('row-id')), 93 TraceRow.rangeSelectObject!.startNS!, 94 TraceRow.rangeSelectObject!.endNS! 95 ).then((res) => { 96 res.forEach((item) => { 97 docompositionData.push(item.startTime!); 98 }); 99 this.rangeTraceRow![0].docompositionList = docompositionData; 100 }); 101 } 102 } 103 } 104 this.isMouseDown = false; 105 } 106 107 isDrag(): boolean { 108 return this.startPageX !== this.endPageX; 109 } 110 111 isTouchMark(ev: MouseEvent): boolean { 112 let notTimeHeight: boolean = this.rowsPaneEL!.containPoint(ev, { 113 left: 248, 114 top: -45, 115 }); 116 if (!notTimeHeight) { 117 return false; 118 } 119 if ((this.rangeTraceRow?.isEmpty() ?? false) && !this.isMouseDown) { 120 this.isHover = false; 121 } 122 return notTimeHeight && (this.rangeTraceRow?.isNotEmpty() ?? false) && !this.isMouseDown; 123 } 124 125 mouseOut(mouseEventOut: MouseEvent): void { 126 this.endPageX = mouseEventOut.pageX; 127 this.endPageY = mouseEventOut.pageY; 128 if (this.drag) { 129 if (this.selectHandler && this.isMouseDown) { 130 this.selectHandler(this.rangeTraceRow || [], !this.isHover); 131 } 132 } 133 document.getSelection()?.removeAllRanges(); 134 this.isMouseDown = false; 135 } 136 137 mouseMove(rows: Array<TraceRow<any>>, ev: MouseEvent): void { 138 this.endPageX = ev.pageX; 139 this.endPageY = ev.pageY; 140 if (this.isTouchMark(ev) && TraceRow.rangeSelectObject) { 141 this.handleTouchMark(ev); 142 } else { 143 document.body.style.cursor = 'default'; 144 } 145 if (this.isHover && this.isMouseDown) { 146 this.handleRangeSelectAndDraw(rows, ev); 147 return; 148 } 149 if (!this.isMouseDown) { 150 this.handleDrawForNotMouseDown(); 151 return; 152 } 153 this.handleRangeSelect(rows); 154 this.timerShaftEL!.sportRuler!.isRangeSelect = this.rangeTraceRow!.length > 0; 155 this.timerShaftEL!.sportRuler!.draw(); 156 } 157 158 private handleRangeSelect(rows: Array<TraceRow<any>>): void { 159 let rangeSelect: RangeSelectStruct | undefined; 160 let favoriteRect = this.trace?.favoriteChartListEL?.getBoundingClientRect(); 161 let favoriteLimit = favoriteRect!.top + favoriteRect!.height; 162 this.rangeTraceRow = rows.filter((it) => { 163 let domRect = it.getBoundingClientRect(); 164 let itRect = {x: domRect.x, y: domRect.y, width: domRect.width, height: domRect.height}; 165 if (itRect.y < favoriteLimit && !it.collect) { 166 let offset = favoriteLimit - itRect.y; 167 itRect.y = itRect.y + offset; 168 itRect.height = itRect.height - offset; 169 } 170 if (it.sticky) { 171 itRect.y = 0; 172 itRect.height = 0; 173 } 174 if ( 175 Rect.intersect(itRect as Rect, { 176 x: Math.min(this.startPageX, this.endPageX), 177 y: Math.min(this.startPageY, this.endPageY), 178 width: Math.abs(this.startPageX - this.endPageX), 179 height: Math.abs(this.startPageY - this.endPageY), 180 } as Rect) 181 ) { 182 if (!rangeSelect) { 183 it.setTipLeft(0, null); 184 rangeSelect = new RangeSelectStruct(); 185 let startX = Math.min(this.startPageX, this.endPageX) - it.describeEl!.getBoundingClientRect().right; 186 let endX = Math.max(this.startPageX, this.endPageX) - it.describeEl!.getBoundingClientRect().right; 187 if (startX <= 0) startX = 0; 188 if (endX > it.frame.width) endX = it.frame.width; 189 rangeSelect.startX = startX; 190 rangeSelect.endX = endX; 191 rangeSelect.startNS = RangeSelect.SetNS(it, startX); 192 rangeSelect.endNS = RangeSelect.SetNS(it, endX); 193 } 194 TraceRow.rangeSelectObject = rangeSelect; 195 it.rangeSelect = true; 196 return true; 197 } else { 198 it.rangeSelect = false; 199 return false; 200 } 201 }); 202 if (this.rangeTraceRow && this.rangeTraceRow.length) { 203 this.rangeTraceRow!.forEach((row) => { 204 row.docompositionList = []; 205 }); 206 } 207 } 208 209 private handleDrawForNotMouseDown(): void { 210 this.timerShaftEL!.sportRuler!.isRangeSelect = this.rangeTraceRow?.isNotEmpty() ?? false; 211 this.timerShaftEL!.sportRuler!.draw(); 212 } 213 214 private handleRangeSelectAndDraw(rows: Array<TraceRow<any>>, ev: MouseEvent): void { 215 let rangeSelect: RangeSelectStruct | undefined; 216 this.rangeTraceRow = rows.filter((it) => { 217 if (it.rangeSelect) { 218 if (!rangeSelect) { 219 rangeSelect = new RangeSelectStruct(); 220 let mouseX = ev.pageX - this.rowsEL!.getBoundingClientRect().left - 248; 221 mouseX = mouseX < 0 ? 0 : mouseX; 222 let markA = this.movingMark == 'markA' ? mouseX : this.mark.startMark; 223 let markB = this.movingMark == 'markB' ? mouseX : this.mark.endMark; 224 let startX = markA < markB ? markA : markB; 225 let endX = markB < markA ? markA : markB; 226 rangeSelect.startX = startX; 227 rangeSelect.endX = endX; 228 rangeSelect.startNS = RangeSelect.SetNS(it, startX); 229 rangeSelect.endNS = RangeSelect.SetNS(it, endX); 230 if (rangeSelect.startNS <= TraceRow.range!.startNS) { 231 rangeSelect.startNS = TraceRow.range!.startNS; 232 } 233 if (rangeSelect.endNS >= TraceRow.range!.endNS) { 234 rangeSelect.endNS = TraceRow.range!.endNS; 235 } 236 if (startX < 0) { 237 rangeSelect.startNS = TraceRow.rangeSelectObject!.startNS!; 238 } 239 if (endX > it.frame.width) { 240 rangeSelect.endNS = TraceRow.rangeSelectObject!.endNS!; 241 } 242 } 243 TraceRow.rangeSelectObject = rangeSelect; 244 return true; 245 } 246 }); 247 this.timerShaftEL!.sportRuler!.isRangeSelect = (this.rangeTraceRow?.length || 0) > 0; 248 this.timerShaftEL!.sportRuler!.draw(); 249 } 250 251 private handleTouchMark(ev: MouseEvent): void { 252 info('isTouchMark'); 253 let x1 = 254 ((TraceRow.rangeSelectObject!.startNS! - TraceRow.range!.startNS) * 255 (this.timerShaftEL?.canvas?.clientWidth || 0)) / 256 (TraceRow.range!.endNS - TraceRow.range!.startNS); 257 let x2 = 258 ((TraceRow.rangeSelectObject!.endNS! - TraceRow.range!.startNS) * 259 (this.timerShaftEL?.canvas?.clientWidth || 0)) / 260 (TraceRow.range!.endNS - TraceRow.range!.startNS); 261 this.mark = {startMark: x1, endMark: x2}; 262 let mouseX = ev.pageX - this.rowsPaneEL!.getBoundingClientRect().left - 248; 263 if (mouseX > x1 - 5 && mouseX < x1 + 5) { 264 this.isHover = true; 265 document.body.style.cursor = 'ew-resize'; 266 this.movingMark = x1 < x2 ? 'markA' : 'markB'; 267 } else if (mouseX > x2 - 5 && mouseX < x2 + 5) { 268 this.isHover = true; 269 document.body.style.cursor = 'ew-resize'; 270 this.movingMark = x2 < x1 ? 'markA' : 'markB'; 271 } else { 272 this.isHover = false; 273 document.body.style.cursor = 'default'; 274 } 275 } 276 277 static SetNS(row: TraceRow<any>, num: number): number { 278 return Math.floor( 279 ((TraceRow.range!.endNS - TraceRow.range!.startNS) * num) / row.frame.width + TraceRow.range!.startNS! 280 ); 281 } 282} 283