1import {ns2s, Rect} from "./ProcedureWorkerCommon.js"; 2import {CpuStruct} from "../bean/CpuStruct.js"; 3import {ColorUtils} from "../component/trace/base/ColorUtils.js"; 4 5let timeRuler: TimeRuler | undefined; 6let rangeRuler: RangeRuler | undefined; 7let sportRuler: SportRuler | undefined; 8let offsetTop: number = 0; 9let offsetLeft: number = 0; 10 11// @ts-ignore 12export function timeline(canvas: OffscreenCanvas, ctx: OffscreenCanvasRenderingContext2D, startNS: number, 13 endNS: number, totalNS: number, frame: Rect, keyPressCode: any, keyUpCode: any, 14 mouseDown: any, mouseUp: any, mouseMove: any, mouseOut: any, 15 _offsetLeft: number, _offsetTop: number, changeHandler: Function) { 16 offsetLeft = _offsetLeft; 17 offsetTop = _offsetTop; 18 if (timeRuler == undefined) { 19 timeRuler = new TimeRuler(canvas, ctx, new Rect(0, 0, frame.width, 20), totalNS); 20 } 21 if (!sportRuler) { 22 sportRuler = new SportRuler(canvas, ctx, new Rect(0, 100.5, frame.width, frame.height - 100)); 23 } 24 if (!rangeRuler) { 25 rangeRuler = new RangeRuler(canvas, ctx!, new Rect(0, 25, frame.width, 75), { 26 startX: 0, 27 endX: frame.width, 28 startNS: 0, 29 endNS: totalNS, 30 totalNS: totalNS, 31 xs: [], 32 xsTxt: [] 33 }, (a) => { 34 if (sportRuler) { 35 sportRuler.range = a; 36 } 37 changeHandler(a); 38 }); 39 } 40 ; 41 rangeRuler.frame.width = frame.width; 42 sportRuler.frame.width = frame.width; 43 timeRuler.frame.width = frame.width; 44 if (keyPressCode) { 45 rangeRuler.keyPress(keyPressCode); 46 } else if (keyUpCode) { 47 rangeRuler.keyUp(keyUpCode); 48 } else if (mouseDown) { 49 rangeRuler.mouseDown(mouseDown); 50 } else if (mouseUp) { 51 rangeRuler.mouseUp(mouseUp); 52 } else if (mouseMove) { 53 rangeRuler.mouseMove(mouseMove); 54 } else if (mouseOut) { 55 rangeRuler.mouseOut(mouseOut); 56 } else { 57 timeRuler.draw(); 58 rangeRuler.draw(); 59 } 60} 61 62export abstract class Graph { 63 // @ts-ignore 64 c: OffscreenCanvasRenderingContext2D; 65 // @ts-ignore 66 canvas: OffscreenCanvas | undefined | null; 67 frame: Rect; 68 69 // @ts-ignore 70 protected constructor(canvas: OffscreenCanvas | undefined | null, c: OffscreenCanvasRenderingContext2D, frame: Rect) { 71 this.canvas = canvas; 72 this.frame = frame; 73 this.c = c; 74 } 75 76 abstract draw(): void; 77} 78 79export class TimeRuler extends Graph { 80 totalNS: number 81 private stepSmall: number; 82 private step: number; 83 private stepNS: number; 84 85 // @ts-ignore 86 constructor(canvas: OffscreenCanvas | undefined | null, c: OffscreenCanvasRenderingContext2D, frame: Rect, totalNS: number = 10_000_000_000) { 87 super(canvas, c, frame) 88 this.totalNS = totalNS; 89 this.step = this.frame.width / 10; 90 this.stepSmall = this.frame.width / 100; 91 this.stepNS = this.totalNS / 10; 92 } 93 94 draw() { 95 this.step = this.frame.width / 10; 96 this.stepSmall = this.frame.width / 100; 97 this.stepNS = this.totalNS / 10; 98 this.c.clearRect(this.frame.x, this.frame.y, this.frame.width, this.frame.height) 99 this.c.beginPath(); 100 this.c.strokeStyle = "#999" 101 this.c.lineWidth = 1; 102 for (let i = 0; i <= 10; i++) { 103 let x = Math.floor(i * this.step) + this.frame.x; 104 this.c.moveTo(x, 0); 105 this.c.lineTo(x, this.frame.height); 106 if (i == 10) break; 107 for (let j = 1; j < 10; j++) { 108 this.c.moveTo(x + Math.floor(j * this.stepSmall), 0); 109 this.c.lineTo(x + Math.floor(j * this.stepSmall), this.frame.height / 4); 110 } 111 this.c.fillStyle = '#999' 112 this.c.fillText(`${ns2s(i * this.stepNS)}`, x + 5, this.frame.height - 1) 113 } 114 this.c.stroke(); 115 this.c.closePath(); 116 } 117} 118 119/** 120 * SportRuler 121 */ 122export class SportRuler extends Graph { 123 private _range: TimeRange = {} as TimeRange; 124 private rangeFlag = new Flag(0, 0, 0, 0, 0); 125 public flagList: Array<Flag> = []; 126 private ruler_w = 1022; 127 public static rulerFlagObj: Flag | null = null; 128 129 public flagListIdx: number | null = null 130 131 public obj = [{x: 3}, {x: 2}]; 132 133 modifyFlagList(type: string, flag: any = {}) { 134 if (type == "amend") { 135 if (flag.text && this.flagListIdx !== null) { 136 this.flagList[this.flagListIdx].text = flag.text 137 } 138 if (flag.color && this.flagListIdx !== null) { 139 this.flagList[this.flagListIdx].color = flag.color 140 } 141 } else if (type == "remove") { 142 if (this.flagListIdx !== null) { 143 this.flagList.splice(this.flagListIdx, 1) 144 } 145 } 146 this.draw() 147 } 148 149 get range(): TimeRange { 150 return this._range; 151 } 152 153 set range(value: TimeRange) { 154 this._range = value; 155 this.draw() 156 } 157 158 lineColor: string | null = null; 159 160 // @ts-ignore 161 constructor(canvas: OffscreenCanvas | undefined | null, c: OffscreenCanvasRenderingContext2D, frame: Rect) { 162 super(canvas, c, frame) 163 } 164 165 draw(): void { 166 this.ruler_w = this.frame.width; 167 this.c.clearRect(this.frame.x, this.frame.y, this.frame.width, this.frame.height) 168 this.c.beginPath(); 169 this.lineColor = "#dadada";//window.getComputedStyle(this.canvas!, null).getPropertyValue("color"); 170 this.c.strokeStyle = this.lineColor //"#dadada" 171 this.c.lineWidth = 1; 172 this.c.moveTo(this.frame.x, this.frame.y) 173 this.c.lineTo(this.frame.x + this.frame.width, this.frame.y) 174 this.c.stroke(); 175 this.c.closePath(); 176 this.c.beginPath(); 177 this.c.lineWidth = 3; 178 this.c.strokeStyle = "#999999" 179 this.c.moveTo(this.frame.x, this.frame.y) 180 this.c.lineTo(this.frame.x, this.frame.y + this.frame.height) 181 this.c.stroke(); 182 this.c.closePath(); 183 this.c.beginPath(); 184 this.c.lineWidth = 1; 185 this.c.strokeStyle = this.lineColor;//"#999999" 186 this.c.fillStyle = '#999999' 187 this.c.font = '8px sans-serif' 188 this.range.xs?.forEach((it, i) => { 189 this.c.moveTo(it, this.frame.y) 190 this.c.lineTo(it, this.frame.y + this.frame.height) 191 this.c.fillText(`+${this.range.xsTxt[i]}`, it + 3, this.frame.y + 12) 192 }) 193 194 this.c.stroke(); 195 this.c.closePath(); 196 } 197 198 // drawTheFlag 199 drawTheFlag(x: number, color: string = "#999999", isFill: boolean = false, text: string = "") { 200 this.c.beginPath(); 201 this.c.fillStyle = color; 202 this.c.strokeStyle = color; 203 this.c.moveTo(x, 125); 204 this.c.lineTo(x + 10, 125); 205 this.c.lineTo(x + 10, 127); 206 this.c.lineTo(x + 18, 127); 207 this.c.lineTo(x + 18, 137); 208 this.c.lineTo(x + 10, 137); 209 this.c.lineTo(x + 10, 135); 210 this.c.lineTo(x + 2, 135); 211 this.c.lineTo(x + 2, 143); 212 this.c.lineTo(x, 143); 213 this.c.closePath() 214 if (isFill) { 215 this.c.fill() 216 } 217 this.c.stroke(); 218 219 220 if (text !== "") { 221 this.c.font = "10px Microsoft YaHei" 222 const {width} = this.c.measureText(text); 223 this.c.fillStyle = 'rgba(255, 255, 255, 0.8)'; // 224 this.c.fillRect(x + 21, 132, width + 4, 12); 225 this.c.fillStyle = "black"; 226 this.c.fillText(text, x + 23, 142); 227 this.c.stroke(); 228 } 229 } 230 231 randomRgbColor() { 232 const letters = '0123456789ABCDEF'; 233 let color = '#'; 234 for (let i = 0; i < 6; i++) { 235 color += letters[Math.floor(Math.random() * 16)] 236 } 237 return color; 238 } 239 240 mouseUp(ev: MouseEvent) { 241 } 242 243 onFlagRangeEvent(flagObj: Flag, idx: number) { 244 SportRuler.rulerFlagObj = flagObj; 245 this.flagListIdx = idx; 246 } 247 248 mouseMove(ev: MouseEvent) { 249 let x = ev.offsetX - (offsetLeft || 0) 250 let y = ev.offsetY - (offsetTop || 0) 251 if (y >= 50 && y < 200) { 252 this.draw() 253 if (y >= 123 && y < 142 && x > 0) { 254 let onFlagRange = this.flagList.findIndex((flagObj: Flag) => { 255 let flag_x = Math.round(this.ruler_w * (flagObj.time - this.range.startNS) / (this.range.endNS - this.range.startNS)); 256 return (x >= flag_x && x <= flag_x + 18) 257 }); 258 if (onFlagRange == -1) { 259 } else { 260 } 261 } else { 262 } 263 } 264 } 265} 266 267const markPadding = 5; 268 269export class Mark extends Graph { 270 name: string | undefined 271 inspectionFrame: Rect 272 private _isHover: boolean = false 273 274 get isHover(): boolean { 275 return this._isHover; 276 } 277 278 set isHover(value: boolean) { 279 this._isHover = value; 280 if (value) { 281 } else { 282 } 283 } 284 285 // @ts-ignore 286 constructor(canvas: OffscreenCanvas | undefined | null, name: string, c: OffscreenCanvasRenderingContext2D, frame: Rect) { 287 super(canvas, c, frame); 288 this.name = name; 289 this.inspectionFrame = new Rect(frame.x - markPadding, frame.y, frame.width + markPadding * 2, frame.height) 290 } 291 292 draw(): void { 293 this.c.beginPath(); 294 this.c.lineWidth = 7 295 this.c.strokeStyle = '#999999' 296 this.c.moveTo(this.frame.x, this.frame.y); 297 this.c.lineTo(this.frame.x, this.frame.y + this.frame.height / 3) 298 this.c.stroke(); 299 this.c.lineWidth = 1 300 this.c.strokeStyle = '#999999' 301 this.c.moveTo(this.frame.x, this.frame.y); 302 this.c.lineTo(this.frame.x, this.frame.y + this.frame.height) 303 this.c.stroke(); 304 this.c.closePath(); 305 } 306} 307 308export interface TimeRange { 309 totalNS: number 310 startX: number 311 endX: number 312 startNS: number 313 endNS: number 314 xs: Array<number> 315 xsTxt: Array<string> 316} 317 318export class RangeRuler extends Graph { 319 public rangeRect: Rect 320 public markA: Mark 321 public markB: Mark 322 public range: TimeRange; 323 mouseDownOffsetX = 0 324 mouseDownMovingMarkX = 0 325 movingMark: Mark | undefined | null; 326 isMouseDown: boolean = false; 327 isMovingRange: boolean = false; 328 isNewRange: boolean = false; 329 markAX: number = 0; 330 markBX: number = 0; 331 isPress: boolean = false 332 pressFrameId: number = -1 333 currentDuration: number = 0 334 centerXPercentage: number = 0; 335 animaStartTime: number | undefined 336 animTime: number = 100; 337 p: number = 800; 338 private readonly notifyHandler: (r: TimeRange) => void; 339 private scale: number = 0; 340 private scales: Array<number> = [50, 100, 200, 500, 1_000, 2_000, 5_000, 10_000, 20_000, 50_000, 100_000, 200_000, 500_000, 341 1_000_000, 2_000_000, 5_000_000, 10_000_000, 20_000_000, 50_000_000, 100_000_000, 200_000_000, 500_000_000, 342 1_000_000_000, 2_000_000_000, 5_000_000_000, 10_000_000_000, 20_000_000_000, 50_000_000_000, 343 100_000_000_000, 200_000_000_000, 500_000_000_000]; 344 345 // @ts-ignore 346 constructor(canvas: OffscreenCanvas | undefined | null, c: OffscreenCanvasRenderingContext2D, frame: Rect, range: TimeRange, notifyHandler: (r: TimeRange) => void) { 347 super(canvas, c, frame) 348 this.range = range; 349 this.notifyHandler = notifyHandler; 350 this.markA = new Mark(canvas, 'A', c, new Rect(range.startX, frame.y, 1, frame.height)) 351 this.markB = new Mark(canvas, 'B', c, new Rect(range.endX, frame.y, 1, frame.height)) 352 this.rangeRect = new Rect(range.startX, frame.y, range.endX - range.startX, frame.height) 353 } 354 355 private _cpuUsage: Array<{ cpu: number, ro: number, rate: number }> = [] 356 set cpuUsage(value: Array<{ cpu: number, ro: number, rate: number }>) { 357 this._cpuUsage = value 358 this.draw(); 359 } 360 361 drawCpuUsage() { 362 let maxNum = Math.round(this._cpuUsage.length / 100) 363 let miniHeight = Math.round(this.frame.height / CpuStruct.cpuCount);//每格高度 364 let miniWidth = Math.ceil(this.frame.width / 100);//每格宽度 365 for (let i = 0; i < this._cpuUsage.length; i++) { 366 //cpu: 0, ro: 0, rate: 0.987620037556431 367 let it = this._cpuUsage[i] 368 this.c.fillStyle = ColorUtils.MD_PALETTE[it.cpu] 369 this.c.globalAlpha = it.rate 370 this.c.fillRect(this.frame.x + miniWidth * it.ro, this.frame.y + it.cpu * miniHeight, miniWidth, miniHeight) 371 } 372 } 373 374 draw(discardNotify: boolean = false): void { 375 this.c.clearRect(this.frame.x - markPadding, this.frame.y, this.frame.width + markPadding * 2, this.frame.height) 376 this.c.beginPath(); 377 if (this._cpuUsage.length > 0) { 378 this.drawCpuUsage() 379 this.c.globalAlpha = 0; 380 } else { 381 this.c.globalAlpha = 1; 382 } 383 this.c.fillStyle = "#ffffff";//window.getComputedStyle(this.canvas!, null).getPropertyValue("background-color") 384 this.rangeRect.x = this.markA.frame.x < this.markB.frame.x ? this.markA.frame.x : this.markB.frame.x 385 this.rangeRect.width = Math.abs(this.markB.frame.x - this.markA.frame.x) 386 this.c.fillRect(this.rangeRect.x, this.rangeRect.y, this.rangeRect.width, this.rangeRect.height) 387 this.c.globalAlpha = 1; 388 this.c.globalAlpha = .5; 389 this.c.fillStyle = "#999999" 390 this.c.fillRect(this.frame.x, this.frame.y, this.rangeRect.x, this.rangeRect.height) 391 this.c.fillRect(this.rangeRect.x + this.rangeRect.width, this.frame.y, this.frame.width - this.rangeRect.width, this.rangeRect.height) 392 this.c.globalAlpha = 1; 393 this.c.closePath(); 394 this.markA.draw(); 395 this.markB.draw(); 396 if (this.notifyHandler) { 397 this.range.startX = this.rangeRect.x 398 this.range.endX = this.rangeRect.x + this.rangeRect.width 399 this.range.startNS = this.range.startX * this.range.totalNS / (this.frame.width || 0) 400 this.range.endNS = this.range.endX * this.range.totalNS / (this.frame.width || 0) 401 let l20 = (this.range.endNS - this.range.startNS) / 20; 402 let min = 0; 403 let max = 0; 404 let weight = 0; 405 for (let index = 0; index < this.scales.length; index++) { 406 if (this.scales[index] > l20) { 407 if (index > 0) { 408 min = this.scales[index - 1]; 409 } else { 410 min = 0; 411 } 412 max = this.scales[index]; 413 weight = (l20 - min) * 1.0 / (max - min); 414 if (weight > 0.243) { 415 this.scale = max; 416 } else { 417 this.scale = min; 418 } 419 break; 420 } 421 } 422 if (this.scale == 0) { 423 this.scale = this.scales[0]; 424 } 425 let tmpNs = 0; 426 let yu = this.range.startNS % this.scale; 427 let realW = (this.scale * this.frame.width) / (this.range.endNS - this.range.startNS); 428 let startX = 0; 429 if (this.range.xs) { 430 this.range.xs.length = 0 431 } else { 432 this.range.xs = [] 433 } 434 if (this.range.xsTxt) { 435 this.range.xsTxt.length = 0 436 } else { 437 this.range.xsTxt = [] 438 } 439 if (yu != 0) { 440 let firstNodeWidth = ((this.scale - yu) / this.scale * realW); 441 startX += firstNodeWidth; 442 tmpNs += yu; 443 this.range.xs.push(startX) 444 this.range.xsTxt.push(ns2s(tmpNs)) 445 } 446 while (tmpNs < this.range.endNS - this.range.startNS) { 447 startX += realW; 448 tmpNs += this.scale; 449 this.range.xs.push(startX) 450 this.range.xsTxt.push(ns2s(tmpNs)) 451 } 452 if (!discardNotify) { 453 this.notifyHandler(this.range) 454 } 455 } 456 } 457 458 mouseDown(ev: MouseEvent) { 459 let x = ev.offsetX - (offsetLeft || 0) 460 let y = ev.offsetY - (offsetTop || 0) 461 this.isMouseDown = true; 462 this.mouseDownOffsetX = x; 463 if (this.markA.isHover) { 464 this.movingMark = this.markA; 465 this.mouseDownMovingMarkX = this.movingMark.frame.x || 0 466 } else if (this.markB.isHover) { 467 this.movingMark = this.markB; 468 this.mouseDownMovingMarkX = this.movingMark.frame.x || 0 469 } else { 470 this.movingMark = null; 471 } 472 if (this.rangeRect.containsWithPadding(x, y, 5, 0)) { 473 this.isMovingRange = true; 474 this.markAX = this.markA.frame.x; 475 this.markBX = this.markB.frame.x; 476 } else if (this.frame.containsWithMargin(x, y, 20, 0, 0, 0) && !this.rangeRect.containsWithMargin(x, y, 0, markPadding, 0, markPadding)) { 477 this.isNewRange = true; 478 } 479 } 480 481 mouseUp(ev: MouseEvent) { 482 this.isMouseDown = false; 483 this.isMovingRange = false; 484 this.isNewRange = false; 485 this.movingMark = null; 486 } 487 488 mouseMove(ev: MouseEvent) { 489 let x = ev.offsetX - (offsetLeft || 0); 490 let y = ev.offsetY - (offsetTop || 0) 491 this.centerXPercentage = x / (this.frame.width || 0) 492 if (this.centerXPercentage <= 0) { 493 this.centerXPercentage = 0 494 } else if (this.centerXPercentage >= 1) { 495 this.centerXPercentage = 1 496 } 497 let maxX = this.frame.width || 0 498 if (this.markA.inspectionFrame.contains(x, y)) { 499 this.markA.isHover = true 500 } else if (this.markB.inspectionFrame.contains(x, y)) { 501 this.markB.isHover = true; 502 } else { 503 this.markA.isHover = false; 504 this.markB.isHover = false; 505 } 506 if (this.movingMark) { 507 let result = x - this.mouseDownOffsetX + this.mouseDownMovingMarkX; 508 if (result >= 0 && result <= maxX) { 509 this.movingMark.frame.x = result 510 } else if (result < 0) { 511 this.movingMark.frame.x = 0 512 } else { 513 this.movingMark.frame.x = maxX 514 } 515 this.movingMark.inspectionFrame.x = this.movingMark.frame.x - markPadding 516 requestAnimationFrame(() => this.draw()); 517 } else if (this.rangeRect.containsWithPadding(x, y, markPadding, 0)) { 518 } else if (this.frame.containsWithMargin(x, y, 20, 0, 0, 0) && !this.rangeRect.containsWithMargin(x, y, 0, markPadding, 0, markPadding)) { 519 } 520 if (this.isMovingRange && this.isMouseDown) { 521 let result = x - this.mouseDownOffsetX; 522 let mA = result + this.markAX 523 let mB = result + this.markBX 524 if (mA >= 0 && mA <= maxX) { 525 this.markA.frame.x = mA 526 } else if (mA < 0) { 527 this.markA.frame.x = 0 528 } else { 529 this.markA.frame.x = maxX 530 } 531 this.markA.inspectionFrame.x = this.markA.frame.x - markPadding 532 if (mB >= 0 && mB <= maxX) { 533 this.markB.frame.x = mB; 534 } else if (mB < 0) { 535 this.markB.frame.x = 0 536 } else { 537 this.markB.frame.x = maxX 538 } 539 this.markB.inspectionFrame.x = this.markB.frame.x - markPadding 540 requestAnimationFrame(() => this.draw()); 541 } else if (this.isNewRange) { 542 this.markA.frame.x = this.mouseDownOffsetX; 543 this.markA.inspectionFrame.x = this.mouseDownOffsetX - markPadding; 544 if (x >= 0 && x <= maxX) { 545 this.markB.frame.x = x; 546 } else if (x < 0) { 547 this.markB.frame.x = 0; 548 } else { 549 this.markB.frame.x = maxX; 550 } 551 this.markB.inspectionFrame.x = this.markB.frame.x - markPadding; 552 requestAnimationFrame(() => this.draw()); 553 } 554 } 555 556 mouseOut(ev: MouseEvent) { 557 this.movingMark = null; 558 } 559 560 561 fillX() { 562 if (this.range.startNS < 0) this.range.startNS = 0; 563 if (this.range.endNS < 0) this.range.endNS = 0; 564 if (this.range.endNS > this.range.totalNS) this.range.endNS = this.range.totalNS; 565 if (this.range.startNS > this.range.totalNS) this.range.startNS = this.range.totalNS; 566 this.range.startX = this.range.startNS * (this.frame.width || 0) / this.range.totalNS 567 this.range.endX = this.range.endNS * (this.frame.width || 0) / this.range.totalNS 568 this.markA.frame.x = this.range.startX 569 this.markA.inspectionFrame.x = this.markA.frame.x - markPadding 570 this.markB.frame.x = this.range.endX 571 this.markB.inspectionFrame.x = this.markB.frame.x - markPadding 572 } 573 574 keyPress(ev: KeyboardEvent) { 575 if (this.animaStartTime === undefined) { 576 this.animaStartTime = new Date().getTime(); 577 } 578 let startTime = new Date().getTime(); 579 let duration = (startTime - this.animaStartTime); 580 if (duration < this.animTime) duration = this.animTime 581 this.currentDuration = duration 582 if (this.isPress) return 583 this.isPress = true 584 switch (ev.key.toLocaleLowerCase()) { 585 case "w": 586 let animW = () => { 587 if (this.scale === 50) return; 588 this.range.startNS += (this.centerXPercentage * this.currentDuration * 2 * this.scale / this.p); 589 this.range.endNS -= ((1 - this.centerXPercentage) * this.currentDuration * 2 * this.scale / this.p); 590 this.fillX(); 591 this.draw(); 592 this.pressFrameId = requestAnimationFrame(animW) 593 } 594 this.pressFrameId = requestAnimationFrame(animW) 595 break; 596 case "s": 597 let animS = () => { 598 if (this.range.startNS <= 0 && this.range.endNS >= this.range.totalNS) return; 599 this.range.startNS -= (this.centerXPercentage * this.currentDuration * 2 * this.scale / this.p); 600 this.range.endNS += ((1 - this.centerXPercentage) * this.currentDuration * 2 * this.scale / this.p); 601 this.fillX(); 602 this.draw(); 603 this.pressFrameId = requestAnimationFrame(animS) 604 } 605 this.pressFrameId = requestAnimationFrame(animS) 606 break; 607 case "a": 608 let animA = () => { 609 if (this.range.startNS == 0) return; 610 let s = this.scale / this.p * this.currentDuration; 611 this.range.startNS -= s; 612 this.range.endNS -= s; 613 this.fillX(); 614 this.draw(); 615 this.pressFrameId = requestAnimationFrame(animA) 616 617 } 618 this.pressFrameId = requestAnimationFrame(animA) 619 break; 620 case "d": 621 let animD = () => { 622 if (this.range.endNS >= this.range.totalNS) return; 623 this.range.startNS += this.scale / this.p * this.currentDuration; 624 this.range.endNS += this.scale / this.p * this.currentDuration; 625 this.fillX(); 626 this.draw(); 627 this.pressFrameId = requestAnimationFrame(animD) 628 629 } 630 this.pressFrameId = requestAnimationFrame(animD) 631 break; 632 } 633 } 634 635 keyUp(ev: KeyboardEvent) { 636 this.animaStartTime = undefined; 637 this.isPress = false 638 if (this.pressFrameId != -1) { 639 cancelAnimationFrame(this.pressFrameId) 640 } 641 let startTime = new Date().getTime(); 642 switch (ev.key) { 643 case "w": 644 let animW = () => { 645 if (this.scale === 50) return; 646 let dur = (new Date().getTime() - startTime); 647 this.range.startNS += (this.centerXPercentage * 100 * this.scale / this.p); 648 this.range.endNS -= ((1 - this.centerXPercentage) * 100 * this.scale / this.p); 649 this.fillX(); 650 this.draw(); 651 if (dur < 300) { 652 requestAnimationFrame(animW) 653 } 654 } 655 requestAnimationFrame(animW) 656 break; 657 case "s": 658 let animS = () => { 659 if (this.range.startNS <= 0 && this.range.endNS >= this.range.totalNS) return; 660 let dur = (new Date().getTime() - startTime); 661 this.range.startNS -= (this.centerXPercentage * 100 * this.scale / this.p); 662 this.range.endNS += ((1 - this.centerXPercentage) * 100 * this.scale / this.p); 663 this.fillX(); 664 this.draw(); 665 if (dur < 300) { 666 requestAnimationFrame(animS) 667 } 668 } 669 requestAnimationFrame(animS) 670 break; 671 case "a": 672 let animA = () => { 673 if (this.range.startNS <= 0) return 674 let dur = (new Date().getTime() - startTime); 675 let s = this.scale * 80 / this.p; 676 this.range.startNS -= s; 677 this.range.endNS -= s; 678 this.fillX(); 679 this.draw(); 680 if (dur < 300) { 681 requestAnimationFrame(animA) 682 } 683 } 684 animA(); 685 break; 686 case "d": 687 let animD = () => { 688 if (this.range.endNS >= this.range.totalNS) return; 689 let dur = (new Date().getTime() - startTime); 690 let s = this.scale * 80 / this.p; 691 this.range.startNS += s; 692 this.range.endNS += s; 693 this.fillX(); 694 this.draw(); 695 if (dur < 300) { 696 requestAnimationFrame(animD) 697 } 698 } 699 animD(); 700 break; 701 } 702 } 703} 704 705export class Flag { 706 x: number = 0 707 y: number = 0 708 width: number = 0 709 height: number = 0 710 time: number = 0 711 color: string = "" 712 selected: boolean = false 713 text: string = "" 714 715 constructor(x: number, y: number, width: number, height: number, time: number, color: string = "#999999", selected = false) { 716 this.x = x; 717 this.y = y; 718 this.width = width; 719 this.height = height; 720 this.time = time; 721 this.color = color; 722 this.selected = selected; 723 } 724}