image cache on cloudflare r2

feat: fix double click

dunkirk.sh ed6afa8b 2038f615

verified
Changed files
+35 -11
src
+35 -11
src/dashboard.ts
··· 86 86 private lodCache: Partial<Record<Granularity, LodCacheEntry>> = {}; 87 87 private activeGranularity: Granularity | null = null; 88 88 private isLoading = false; 89 - private dblClickHandler: (() => void) | null = null; 90 89 91 90 private readonly totalHitsEl = document.getElementById( 92 91 "total-hits", ··· 299 298 this.originalRange = { start: first, end: last }; 300 299 this.renderCurrentViewport({ min: first, max: last }); 301 300 } else { 302 - this.renderCurrentViewport(); 301 + this.renderCurrentViewport({ 302 + min: this.currentRange.start, 303 + max: this.currentRange.end, 304 + }); 303 305 } 304 306 } 305 307 ··· 368 370 private handleSelect(u: uPlot) { 369 371 if (u.select.width <= 10) return; 370 372 371 - const min = Math.floor(u.posToVal(u.select.left, "x")); 372 - const max = Math.floor(u.posToVal(u.select.left + u.select.width, "x")); 373 + let min = Math.floor(u.posToVal(u.select.left, "x")); 374 + let max = Math.floor(u.posToVal(u.select.left + u.select.width, "x")); 373 375 374 376 u.setSelect({ left: 0, top: 0, width: 0, height: 0 }, false); 375 377 378 + const minSpan = 1.5 * 86400; 379 + const span = max - min; 380 + if (span < minSpan) { 381 + const center = (min + max) / 2; 382 + min = Math.floor(center - minSpan / 2); 383 + max = Math.floor(center + minSpan / 2); 384 + } 385 + 376 386 this.currentRange = { start: min, end: max }; 377 387 378 388 const bestCache = this.getBestCacheForRange(min, max); ··· 396 406 max: this.originalRange.end, 397 407 }); 398 408 this.renderCurrentViewport(); 409 + this.fetchData(); 399 410 } 400 411 } 401 412 ··· 414 425 height: 0, 415 426 }, 416 427 scales: { 417 - x: { time: true }, 428 + x: { 429 + time: true, 430 + range: (u, dataMin, dataMax) => { 431 + let min = dataMin; 432 + let max = dataMax; 433 + const minSpan = 1.5 * 86400; 434 + const span = max - min; 435 + if (span < minSpan) { 436 + const center = (min + max) / 2; 437 + min = center - minSpan / 2; 438 + max = center + minSpan / 2; 439 + } 440 + return [min, max]; 441 + }, 442 + }, 418 443 y: { auto: true }, 419 444 }, 420 445 axes: [ ··· 441 466 ], 442 467 hooks: { 443 468 setSelect: [(u) => this.handleSelect(u)], 469 + ready: [ 470 + (u) => { 471 + u.over.addEventListener("dblclick", () => this.resetZoom()); 472 + }, 473 + ], 444 474 }, 445 475 }; 446 476 447 477 this.chartEl.innerHTML = ""; 448 478 this.chart = new uPlot(opts, [timestamps, hits], this.chartEl); 449 - 450 - if (this.dblClickHandler) { 451 - this.chartEl.removeEventListener("dblclick", this.dblClickHandler); 452 - } 453 - this.dblClickHandler = () => this.resetZoom(); 454 - this.chartEl.addEventListener("dblclick", this.dblClickHandler); 455 479 } 456 480 457 481 private handleResize = () => {