open-plant 1.2.1 → 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -1
- package/README.md +20 -2
- package/dist/assets/roi-clip-worker-DdVYCepx.js +2 -0
- package/dist/assets/roi-clip-worker-DdVYCepx.js.map +1 -0
- package/dist/index.cjs +7 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1336 -1265
- package/dist/index.js.map +1 -1
- package/dist/types/index.d.ts +9 -9
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/react/draw-layer.d.ts +10 -1
- package/dist/types/react/draw-layer.d.ts.map +1 -1
- package/dist/types/react/wsi-viewer-canvas.d.ts +24 -3
- package/dist/types/react/wsi-viewer-canvas.d.ts.map +1 -1
- package/dist/types/wsi/point-clip-worker-client.d.ts +5 -0
- package/dist/types/wsi/point-clip-worker-client.d.ts.map +1 -1
- package/dist/types/wsi/point-clip-worker-protocol.d.ts +17 -2
- package/dist/types/wsi/point-clip-worker-protocol.d.ts.map +1 -1
- package/dist/types/wsi/point-clip.d.ts +1 -0
- package/dist/types/wsi/point-clip.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/assets/roi-clip-worker-i1SE1Dpa.js +0 -2
- package/dist/assets/roi-clip-worker-i1SE1Dpa.js.map +0 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/core/gl-utils.ts","../src/core/ortho-camera.ts","../src/core/m1-tile-renderer.ts","../src/wsi/constants.ts","../src/wsi/utils.ts","../src/react/draw-layer.tsx","../src/wsi/image-info.ts","../src/react/overview-map.tsx","../src/react/tile-viewer-canvas.tsx","../src/wsi/point-clip.ts","../src/wsi/webgpu.ts","../src/wsi/point-clip-hybrid.ts","../src/wsi/point-clip-worker-client.ts","../src/wsi/roi-term-stats.ts","../src/wsi/tile-scheduler.ts","../src/wsi/wsi-tile-renderer.ts","../src/react/wsi-viewer-canvas.tsx"],"sourcesContent":["function compileShader(gl: WebGL2RenderingContext, type: number, source: string): WebGLShader {\n const shader = gl.createShader(type);\n if (!shader) {\n throw new Error(\"Failed to create shader.\");\n }\n\n gl.shaderSource(shader, source);\n gl.compileShader(shader);\n\n const ok = gl.getShaderParameter(shader, gl.COMPILE_STATUS);\n if (!ok) {\n const log = gl.getShaderInfoLog(shader) ?? \"unknown shader error\";\n gl.deleteShader(shader);\n throw new Error(log);\n }\n\n return shader;\n}\n\nexport function createProgram(gl: WebGL2RenderingContext, vertexSource: string, fragmentSource: string): WebGLProgram {\n const vertexShader = compileShader(gl, gl.VERTEX_SHADER, vertexSource);\n const fragmentShader = compileShader(gl, gl.FRAGMENT_SHADER, fragmentSource);\n\n const program = gl.createProgram();\n if (!program) {\n gl.deleteShader(vertexShader);\n gl.deleteShader(fragmentShader);\n throw new Error(\"Failed to create program.\");\n }\n\n gl.attachShader(program, vertexShader);\n gl.attachShader(program, fragmentShader);\n gl.linkProgram(program);\n\n gl.deleteShader(vertexShader);\n gl.deleteShader(fragmentShader);\n\n const ok = gl.getProgramParameter(program, gl.LINK_STATUS);\n if (!ok) {\n const log = gl.getProgramInfoLog(program) ?? \"unknown link error\";\n gl.deleteProgram(program);\n throw new Error(log);\n }\n\n return program;\n}\n\nexport function requireUniformLocation(\n gl: WebGL2RenderingContext,\n program: WebGLProgram,\n uniformName: string,\n): WebGLUniformLocation {\n const location = gl.getUniformLocation(program, uniformName);\n if (!location) {\n throw new Error(`Failed to get uniform location: ${uniformName}`);\n }\n return location;\n}\n\nexport function requireWebGL2(canvas: HTMLCanvasElement): WebGL2RenderingContext {\n const context = canvas.getContext(\"webgl2\", {\n alpha: false,\n antialias: false,\n depth: false,\n stencil: false,\n preserveDrawingBuffer: false,\n powerPreference: \"high-performance\",\n });\n\n if (!context) {\n throw new Error(\"WebGL2 is not available.\");\n }\n\n return context;\n}\n","export interface ViewState {\n offsetX: number;\n offsetY: number;\n zoom: number;\n}\n\nexport class OrthoCamera {\n private viewportWidth = 1;\n private viewportHeight = 1;\n\n private viewState: ViewState = {\n offsetX: 0,\n offsetY: 0,\n zoom: 1,\n };\n\n setViewport(width: number, height: number): void {\n this.viewportWidth = Math.max(1, width);\n this.viewportHeight = Math.max(1, height);\n }\n\n getViewportSize(): { width: number; height: number } {\n return {\n width: this.viewportWidth,\n height: this.viewportHeight,\n };\n }\n\n setViewState(next: Partial<ViewState>): void {\n if (next.offsetX !== undefined) {\n this.viewState.offsetX = next.offsetX;\n }\n\n if (next.offsetY !== undefined) {\n this.viewState.offsetY = next.offsetY;\n }\n\n if (next.zoom !== undefined) {\n this.viewState.zoom = Math.max(0.0001, next.zoom);\n }\n }\n\n getViewState(): ViewState {\n return { ...this.viewState };\n }\n\n getMatrix(): Float32Array {\n const viewWidth = this.viewportWidth / this.viewState.zoom;\n const viewHeight = this.viewportHeight / this.viewState.zoom;\n\n const sx = 2 / viewWidth;\n const sy = -2 / viewHeight;\n const tx = -1 - this.viewState.offsetX * sx;\n const ty = 1 - this.viewState.offsetY * sy;\n\n return new Float32Array([\n sx,\n 0,\n 0,\n 0,\n sy,\n 0,\n tx,\n ty,\n 1,\n ]);\n }\n}\n","import {\n\tcreateProgram,\n\trequireUniformLocation,\n\trequireWebGL2,\n} from \"./gl-utils\";\nimport { OrthoCamera, type ViewState } from \"./ortho-camera\";\nimport type { Bounds, TileDefinition } from \"./types\";\n\ninterface LoadedTile {\n\tid: string;\n\tbounds: Bounds;\n\ttexture: WebGLTexture;\n}\n\nexport interface M1TileRendererOptions {\n\tcanvas: HTMLCanvasElement;\n\timageWidth: number;\n\timageHeight: number;\n\tclearColor?: [number, number, number, number];\n\tinitialViewState?: Partial<ViewState>;\n}\n\nconst VERTEX_SHADER = `#version 300 es\nprecision highp float;\n\nin vec2 aUnit;\nin vec2 aUv;\n\nuniform mat3 uCamera;\nuniform vec4 uBounds;\n\nout vec2 vUv;\n\nvoid main() {\n vec2 world = vec2(\n mix(uBounds.x, uBounds.z, aUnit.x),\n mix(uBounds.y, uBounds.w, aUnit.y)\n );\n vec3 clip = uCamera * vec3(world, 1.0);\n gl_Position = vec4(clip.xy, 0.0, 1.0);\n vUv = aUv;\n}\n`;\n\nconst FRAGMENT_SHADER = `#version 300 es\nprecision highp float;\n\nin vec2 vUv;\nuniform sampler2D uTexture;\n\nout vec4 outColor;\n\nvoid main() {\n outColor = texture(uTexture, vUv);\n}\n`;\n\nexport class M1TileRenderer {\n\tprivate readonly canvas: HTMLCanvasElement;\n\tprivate readonly gl: WebGL2RenderingContext;\n\tprivate readonly camera = new OrthoCamera();\n\tprivate readonly imageWidth: number;\n\tprivate readonly imageHeight: number;\n\tprivate readonly clearColor: [number, number, number, number];\n\tprivate readonly program: WebGLProgram;\n\tprivate readonly vao: WebGLVertexArrayObject;\n\tprivate readonly quadBuffer: WebGLBuffer;\n\tprivate readonly uCameraLocation: WebGLUniformLocation;\n\tprivate readonly uBoundsLocation: WebGLUniformLocation;\n\tprivate readonly uTextureLocation: WebGLUniformLocation;\n\tprivate readonly resizeObserver: ResizeObserver;\n\n\tprivate tiles: LoadedTile[] = [];\n\tprivate frameId: number | null = null;\n\tprivate loadVersion = 0;\n\tprivate destroyed = false;\n\tprivate fitted = false;\n\tprivate controlledViewState = false;\n\n\tconstructor(options: M1TileRendererOptions) {\n\t\tthis.canvas = options.canvas;\n\t\tthis.imageWidth = Math.max(1, options.imageWidth);\n\t\tthis.imageHeight = Math.max(1, options.imageHeight);\n\t\tthis.clearColor = options.clearColor ?? [0.03, 0.05, 0.08, 1];\n\n\t\tthis.gl = requireWebGL2(this.canvas);\n\t\tthis.program = createProgram(this.gl, VERTEX_SHADER, FRAGMENT_SHADER);\n\n\t\tconst vao = this.gl.createVertexArray();\n\t\tconst quadBuffer = this.gl.createBuffer();\n\t\tif (!vao || !quadBuffer) {\n\t\t\tthrow new Error(\"Failed to create WebGL buffers.\");\n\t\t}\n\n\t\tthis.vao = vao;\n\t\tthis.quadBuffer = quadBuffer;\n\n\t\tthis.gl.bindVertexArray(this.vao);\n\t\tthis.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.quadBuffer);\n\n\t\tconst quadVertices = new Float32Array([\n\t\t\t0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1,\n\t\t]);\n\n\t\tthis.gl.bufferData(this.gl.ARRAY_BUFFER, quadVertices, this.gl.STATIC_DRAW);\n\n\t\tconst unitLocation = this.gl.getAttribLocation(this.program, \"aUnit\");\n\t\tconst uvLocation = this.gl.getAttribLocation(this.program, \"aUv\");\n\t\tif (unitLocation < 0 || uvLocation < 0) {\n\t\t\tthrow new Error(\"Failed to get attribute locations.\");\n\t\t}\n\n\t\tconst stride = 4 * Float32Array.BYTES_PER_ELEMENT;\n\t\tthis.gl.enableVertexAttribArray(unitLocation);\n\t\tthis.gl.vertexAttribPointer(\n\t\t\tunitLocation,\n\t\t\t2,\n\t\t\tthis.gl.FLOAT,\n\t\t\tfalse,\n\t\t\tstride,\n\t\t\t0,\n\t\t);\n\t\tthis.gl.enableVertexAttribArray(uvLocation);\n\t\tthis.gl.vertexAttribPointer(\n\t\t\tuvLocation,\n\t\t\t2,\n\t\t\tthis.gl.FLOAT,\n\t\t\tfalse,\n\t\t\tstride,\n\t\t\t2 * Float32Array.BYTES_PER_ELEMENT,\n\t\t);\n\n\t\tthis.gl.bindVertexArray(null);\n\t\tthis.gl.bindBuffer(this.gl.ARRAY_BUFFER, null);\n\n\t\tthis.uCameraLocation = requireUniformLocation(\n\t\t\tthis.gl,\n\t\t\tthis.program,\n\t\t\t\"uCamera\",\n\t\t);\n\t\tthis.uBoundsLocation = requireUniformLocation(\n\t\t\tthis.gl,\n\t\t\tthis.program,\n\t\t\t\"uBounds\",\n\t\t);\n\t\tthis.uTextureLocation = requireUniformLocation(\n\t\t\tthis.gl,\n\t\t\tthis.program,\n\t\t\t\"uTexture\",\n\t\t);\n\n\t\tif (options.initialViewState) {\n\t\t\tthis.controlledViewState = true;\n\t\t\tthis.camera.setViewState(options.initialViewState);\n\t\t}\n\n\t\tthis.resizeObserver = new ResizeObserver(() => {\n\t\t\tthis.resize();\n\t\t});\n\n\t\tthis.resizeObserver.observe(this.canvas);\n\t\tthis.resize();\n\t}\n\n\tasync setTiles(tiles: TileDefinition[]): Promise<void> {\n\t\tif (this.destroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst version = ++this.loadVersion;\n\n\t\tconst loaded = await Promise.all(\n\t\t\ttiles.map(async (tile) => {\n\t\t\t\tconst loadedTile = await this.loadTile(tile, version);\n\t\t\t\treturn loadedTile;\n\t\t\t}),\n\t\t);\n\n\t\tif (this.destroyed || version !== this.loadVersion) {\n\t\t\tfor (const tile of loaded) {\n\t\t\t\tif (tile) {\n\t\t\t\t\tthis.gl.deleteTexture(tile.texture);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tthis.disposeTiles(this.tiles);\n\t\tthis.tiles = loaded.filter((tile): tile is LoadedTile => tile !== null);\n\t\tthis.requestRender();\n\t}\n\n\tsetViewState(viewState: Partial<ViewState>): void {\n\t\tthis.controlledViewState = true;\n\t\tthis.camera.setViewState(viewState);\n\t\tthis.requestRender();\n\t}\n\n\tgetViewState(): ViewState {\n\t\treturn this.camera.getViewState();\n\t}\n\n\tdestroy(): void {\n\t\tif (this.destroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.destroyed = true;\n\t\tthis.loadVersion += 1;\n\n\t\tif (this.frameId !== null) {\n\t\t\tcancelAnimationFrame(this.frameId);\n\t\t\tthis.frameId = null;\n\t\t}\n\n\t\tthis.resizeObserver.disconnect();\n\t\tthis.disposeTiles(this.tiles);\n\t\tthis.tiles = [];\n\n\t\tthis.gl.deleteBuffer(this.quadBuffer);\n\t\tthis.gl.deleteVertexArray(this.vao);\n\t\tthis.gl.deleteProgram(this.program);\n\t}\n\n\tprivate async loadTile(\n\t\ttile: TileDefinition,\n\t\tversion: number,\n\t): Promise<LoadedTile | null> {\n\t\ttry {\n\t\t\tconst response = await fetch(tile.url);\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Tile fetch failed: ${response.status} ${response.statusText}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst blob = await response.blob();\n\t\t\tconst bitmap = await createImageBitmap(blob);\n\n\t\t\tif (this.destroyed || version !== this.loadVersion) {\n\t\t\t\tbitmap.close();\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst texture = this.gl.createTexture();\n\t\t\tif (!texture) {\n\t\t\t\tbitmap.close();\n\t\t\t\tthrow new Error(\"Failed to create tile texture.\");\n\t\t\t}\n\n\t\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, texture);\n\t\t\tthis.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, 1);\n\t\t\tthis.gl.texParameteri(\n\t\t\t\tthis.gl.TEXTURE_2D,\n\t\t\t\tthis.gl.TEXTURE_WRAP_S,\n\t\t\t\tthis.gl.CLAMP_TO_EDGE,\n\t\t\t);\n\t\t\tthis.gl.texParameteri(\n\t\t\t\tthis.gl.TEXTURE_2D,\n\t\t\t\tthis.gl.TEXTURE_WRAP_T,\n\t\t\t\tthis.gl.CLAMP_TO_EDGE,\n\t\t\t);\n\t\t\tthis.gl.texParameteri(\n\t\t\t\tthis.gl.TEXTURE_2D,\n\t\t\t\tthis.gl.TEXTURE_MIN_FILTER,\n\t\t\t\tthis.gl.LINEAR,\n\t\t\t);\n\t\t\tthis.gl.texParameteri(\n\t\t\t\tthis.gl.TEXTURE_2D,\n\t\t\t\tthis.gl.TEXTURE_MAG_FILTER,\n\t\t\t\tthis.gl.LINEAR,\n\t\t\t);\n\t\t\tthis.gl.texImage2D(\n\t\t\t\tthis.gl.TEXTURE_2D,\n\t\t\t\t0,\n\t\t\t\tthis.gl.RGBA,\n\t\t\t\tthis.gl.RGBA,\n\t\t\t\tthis.gl.UNSIGNED_BYTE,\n\t\t\t\tbitmap,\n\t\t\t);\n\t\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, null);\n\t\t\tbitmap.close();\n\n\t\t\treturn {\n\t\t\t\tid: tile.id,\n\t\t\t\tbounds: tile.bounds,\n\t\t\t\ttexture,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tconsole.error(`[M1TileRenderer] tile load failed: ${tile.id}`, error);\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate resize(): void {\n\t\tif (this.destroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst rect = this.canvas.getBoundingClientRect();\n\t\tconst cssWidth = Math.max(1, rect.width || this.canvas.clientWidth || 1);\n\t\tconst cssHeight = Math.max(1, rect.height || this.canvas.clientHeight || 1);\n\t\tconst dpr = Math.max(1, window.devicePixelRatio || 1);\n\n\t\tconst targetWidth = Math.max(1, Math.round(cssWidth * dpr));\n\t\tconst targetHeight = Math.max(1, Math.round(cssHeight * dpr));\n\n\t\tif (\n\t\t\tthis.canvas.width !== targetWidth ||\n\t\t\tthis.canvas.height !== targetHeight\n\t\t) {\n\t\t\tthis.canvas.width = targetWidth;\n\t\t\tthis.canvas.height = targetHeight;\n\t\t}\n\n\t\tthis.camera.setViewport(cssWidth, cssHeight);\n\t\tthis.gl.viewport(0, 0, this.canvas.width, this.canvas.height);\n\n\t\tif (!this.fitted && !this.controlledViewState) {\n\t\t\tthis.fitToImage();\n\t\t\tthis.fitted = true;\n\t\t}\n\n\t\tthis.requestRender();\n\t}\n\n\tprivate fitToImage(): void {\n\t\tconst viewport = this.camera.getViewportSize();\n\n\t\tconst zoom = Math.min(\n\t\t\tviewport.width / this.imageWidth,\n\t\t\tviewport.height / this.imageHeight,\n\t\t);\n\t\tconst safeZoom = Number.isFinite(zoom) && zoom > 0 ? zoom : 1;\n\n\t\tconst visibleWorldWidth = viewport.width / safeZoom;\n\t\tconst visibleWorldHeight = viewport.height / safeZoom;\n\n\t\tconst offsetX = (this.imageWidth - visibleWorldWidth) * 0.5;\n\t\tconst offsetY = (this.imageHeight - visibleWorldHeight) * 0.5;\n\n\t\tthis.camera.setViewState({\n\t\t\tzoom: safeZoom,\n\t\t\toffsetX,\n\t\t\toffsetY,\n\t\t});\n\t}\n\n\tprivate requestRender(): void {\n\t\tif (this.frameId !== null || this.destroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.frameId = requestAnimationFrame(() => {\n\t\t\tthis.frameId = null;\n\t\t\tthis.render();\n\t\t});\n\t}\n\n\tprivate render(): void {\n\t\tif (this.destroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.gl.clearColor(\n\t\t\tthis.clearColor[0],\n\t\t\tthis.clearColor[1],\n\t\t\tthis.clearColor[2],\n\t\t\tthis.clearColor[3],\n\t\t);\n\t\tthis.gl.clear(this.gl.COLOR_BUFFER_BIT);\n\n\t\tthis.gl.useProgram(this.program);\n\t\tthis.gl.bindVertexArray(this.vao);\n\t\tthis.gl.uniformMatrix3fv(\n\t\t\tthis.uCameraLocation,\n\t\t\tfalse,\n\t\t\tthis.camera.getMatrix(),\n\t\t);\n\t\tthis.gl.uniform1i(this.uTextureLocation, 0);\n\n\t\tfor (const tile of this.tiles) {\n\t\t\tthis.gl.activeTexture(this.gl.TEXTURE0);\n\t\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, tile.texture);\n\t\t\tthis.gl.uniform4f(\n\t\t\t\tthis.uBoundsLocation,\n\t\t\t\ttile.bounds[0],\n\t\t\t\ttile.bounds[1],\n\t\t\t\ttile.bounds[2],\n\t\t\t\ttile.bounds[3],\n\t\t\t);\n\t\t\tthis.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);\n\t\t}\n\n\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, null);\n\t\tthis.gl.bindVertexArray(null);\n\t}\n\n\tprivate disposeTiles(tiles: LoadedTile[]): void {\n\t\tfor (const tile of tiles) {\n\t\t\tthis.gl.deleteTexture(tile.texture);\n\t\t}\n\t}\n}\n","export const DEFAULT_POINT_COLOR: [number, number, number, number] = [\n\t160, 160, 160, 255,\n];\n","import { DEFAULT_POINT_COLOR } from \"./constants\";\nimport type { TermPalette, WsiViewState } from \"./types\";\n\nexport function clamp(value: number, min: number, max: number): number {\n\treturn Math.max(min, Math.min(max, value));\n}\n\nexport function calcScaleResolution(\n\timageMpp: number,\n\timageZoom: number,\n\tcurrentZoom: number,\n): number {\n\tconst mpp = Number(imageMpp);\n\tconst z0 = Number(imageZoom);\n\tconst z1 = Number(currentZoom);\n\tif (!Number.isFinite(mpp) || mpp <= 0) return 1;\n\tif (!Number.isFinite(z0) || !Number.isFinite(z1)) return mpp;\n\treturn Math.pow(2, z0 - z1) * mpp;\n}\n\nexport function calcScaleLength(\n\timageMpp: number,\n\timageZoom: number,\n\tcurrentZoom: number,\n): string {\n\tconst resolution = calcScaleResolution(imageMpp, imageZoom, currentZoom);\n\tlet length = 100 * resolution;\n\tif (Number(imageMpp)) {\n\t\tlet unit = \"μm\";\n\t\tif (length > 1000) {\n\t\t\tlength /= 1000;\n\t\t\tunit = \"mm\";\n\t\t}\n\t\treturn `${length.toPrecision(3)} ${unit}`;\n\t}\n\treturn `${Math.round(length * 1000) / 1000} pixels`;\n}\n\nexport function isSameViewState(\n\ta: Partial<WsiViewState> | null | undefined,\n\tb: Partial<WsiViewState> | null | undefined,\n): boolean {\n\tif (!a && !b) return true;\n\tif (!a || !b) return false;\n\treturn (\n\t\tMath.abs((a.zoom ?? 0) - (b.zoom ?? 0)) < 1e-6 &&\n\t\tMath.abs((a.offsetX ?? 0) - (b.offsetX ?? 0)) < 1e-6 &&\n\t\tMath.abs((a.offsetY ?? 0) - (b.offsetY ?? 0)) < 1e-6 &&\n\t\tMath.abs((a.rotationDeg ?? 0) - (b.rotationDeg ?? 0)) < 1e-6\n\t);\n}\n\nexport function toBearerToken(value: string | null | undefined): string {\n\tconst trimmed = String(value ?? \"\").trim();\n\tif (!trimmed) return \"\";\n\tif (/^bearer\\s+/i.test(trimmed)) {\n\t\tconst token = trimmed.replace(/^bearer\\s+/i, \"\").trim();\n\t\treturn token ? `Bearer ${token}` : \"\";\n\t}\n\treturn `Bearer ${trimmed}`;\n}\n\nexport function hexToRgba(\n\thex: string | null | undefined,\n): [number, number, number, number] {\n\tconst value = String(hex ?? \"\").trim();\n\tconst match = value.match(/^#?([0-9a-fA-F]{6})$/);\n\tif (!match) return [...DEFAULT_POINT_COLOR];\n\n\tconst n = Number.parseInt(match[1], 16);\n\treturn [(n >> 16) & 255, (n >> 8) & 255, n & 255, 255];\n}\n\nexport function buildTermPalette(\n\tterms:\n\t\t| Array<{ termId?: string | null; termColor?: string | null }>\n\t\t| null\n\t\t| undefined,\n): TermPalette {\n\tconst palette: Array<[number, number, number, number]> = [\n\t\t[...DEFAULT_POINT_COLOR],\n\t];\n\tconst termToPaletteIndex = new Map<string, number>();\n\n\tfor (const term of terms ?? []) {\n\t\tconst termId = String(term?.termId ?? \"\");\n\t\tif (!termId || termToPaletteIndex.has(termId)) continue;\n\n\t\ttermToPaletteIndex.set(termId, palette.length);\n\t\tpalette.push(hexToRgba(term?.termColor));\n\t}\n\n\tconst colors = new Uint8Array(palette.length * 4);\n\tfor (let i = 0; i < palette.length; i += 1) {\n\t\tcolors[i * 4] = palette[i][0];\n\t\tcolors[i * 4 + 1] = palette[i][1];\n\t\tcolors[i * 4 + 2] = palette[i][2];\n\t\tcolors[i * 4 + 3] = palette[i][3];\n\t}\n\n\treturn { colors, termToPaletteIndex };\n}\n\nexport function createProgram(\n\tgl: WebGL2RenderingContext,\n\tvertexSource: string,\n\tfragmentSource: string,\n): WebGLProgram {\n\tconst vs = gl.createShader(gl.VERTEX_SHADER);\n\tconst fs = gl.createShader(gl.FRAGMENT_SHADER);\n\tif (!vs || !fs) {\n\t\tthrow new Error(\"Shader allocation failed\");\n\t}\n\n\tgl.shaderSource(vs, vertexSource);\n\tgl.compileShader(vs);\n\tif (!gl.getShaderParameter(vs, gl.COMPILE_STATUS)) {\n\t\tthrow new Error(gl.getShaderInfoLog(vs) || \"vertex compile failed\");\n\t}\n\n\tgl.shaderSource(fs, fragmentSource);\n\tgl.compileShader(fs);\n\tif (!gl.getShaderParameter(fs, gl.COMPILE_STATUS)) {\n\t\tthrow new Error(gl.getShaderInfoLog(fs) || \"fragment compile failed\");\n\t}\n\n\tconst program = gl.createProgram();\n\tif (!program) {\n\t\tthrow new Error(\"Program allocation failed\");\n\t}\n\n\tgl.attachShader(program, vs);\n\tgl.attachShader(program, fs);\n\tgl.linkProgram(program);\n\n\tgl.deleteShader(vs);\n\tgl.deleteShader(fs);\n\n\tif (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n\t\tthrow new Error(gl.getProgramInfoLog(program) || \"program link failed\");\n\t}\n\n\treturn program;\n}\n","import {\n\ttype CSSProperties,\n\ttype MutableRefObject,\n\ttype PointerEvent as ReactPointerEvent,\n\ttype RefObject,\n\tuseCallback,\n\tuseEffect,\n\tuseMemo,\n\tuseRef,\n} from \"react\";\nimport { calcScaleResolution } from \"../wsi/utils\";\n\nexport type StampDrawTool =\n\t| \"stamp-rectangle\"\n\t| \"stamp-circle\"\n\t| \"stamp-rectangle-4096px\"\n\t| \"stamp-rectangle-2mm2\"\n\t| \"stamp-circle-2mm2\"\n\t| \"stamp-circle-hpf-0.2mm2\";\n\nexport type DrawTool =\n\t| \"cursor\"\n\t| \"freehand\"\n\t| \"rectangle\"\n\t| \"circular\"\n\t| StampDrawTool;\n\nexport type DrawCoordinate = [number, number];\n\nexport type DrawBounds = [number, number, number, number];\n\nexport interface DrawResult {\n\ttool: Exclude<DrawTool, \"cursor\">;\n\tcoordinates: DrawCoordinate[];\n\tbbox: DrawBounds;\n\tareaPx: number;\n}\n\nexport interface DrawRegion {\n\tid?: string | number;\n\tcoordinates: DrawCoordinate[];\n\tlabel?: string;\n}\n\nexport interface RegionStyleContext {\n\tregion: DrawRegion;\n\tregionId: string | number;\n\tregionIndex: number;\n\tstate: \"default\" | \"hover\" | \"active\";\n}\n\nexport type RegionStrokeStyleResolver = (\n\tcontext: RegionStyleContext,\n) => Partial<RegionStrokeStyle> | null | undefined;\n\nexport interface DrawOverlayShape {\n\tid?: string | number;\n\tcoordinates: DrawCoordinate[];\n\tclosed?: boolean;\n\tfill?: boolean;\n\tstrokeStyle?: Partial<RegionStrokeStyle>;\n}\n\nexport interface RegionStrokeStyle {\n\tcolor: string;\n\twidth: number;\n\tlineDash: number[];\n\tlineJoin: CanvasLineJoin;\n\tlineCap: CanvasLineCap;\n\tshadowColor: string;\n\tshadowBlur: number;\n\tshadowOffsetX: number;\n\tshadowOffsetY: number;\n}\n\nexport interface RegionLabelStyle {\n\tfontFamily: string;\n\tfontSize: number;\n\tfontWeight: string | number;\n\ttextColor: string;\n\tbackgroundColor: string;\n\tborderColor: string;\n\tborderWidth: number;\n\tpaddingX: number;\n\tpaddingY: number;\n\toffsetY: number;\n\tborderRadius: number;\n}\n\nexport interface DrawProjector {\n\tscreenToWorld(clientX: number, clientY: number): DrawCoordinate | number[];\n\tworldToScreen(worldX: number, worldY: number): DrawCoordinate | number[];\n\tgetViewState?: () => { zoom: number; rotationDeg?: number };\n}\n\nexport interface StampOptions {\n\trectangleAreaMm2?: number;\n\tcircleAreaMm2?: number;\n\trectanglePixelSize?: number;\n}\n\nexport interface DrawLayerProps {\n\ttool: DrawTool;\n\timageWidth: number;\n\timageHeight: number;\n\timageMpp?: number;\n\timageZoom?: number;\n\tstampOptions?: StampOptions;\n\tprojectorRef: RefObject<DrawProjector | null>;\n\tonDrawComplete?: (result: DrawResult) => void;\n\tenabled?: boolean;\n\tviewStateSignal?: unknown;\n\tpersistedRegions?: DrawRegion[];\n\tpersistedPolygons?: DrawCoordinate[][];\n\tregionStrokeStyle?: Partial<RegionStrokeStyle>;\n\tregionStrokeHoverStyle?: Partial<RegionStrokeStyle>;\n\tregionStrokeActiveStyle?: Partial<RegionStrokeStyle>;\n\tresolveRegionStrokeStyle?: RegionStrokeStyleResolver;\n\toverlayShapes?: DrawOverlayShape[];\n\thoveredRegionId?: string | number | null;\n\tactiveRegionId?: string | number | null;\n\tregionLabelStyle?: Partial<RegionLabelStyle>;\n\tinvalidateRef?: MutableRefObject<(() => void) | null>;\n\tclassName?: string;\n\tstyle?: CSSProperties;\n}\n\ninterface DrawSession {\n\tisDrawing: boolean;\n\tpointerId: number | null;\n\tstart: DrawCoordinate | null;\n\tcurrent: DrawCoordinate | null;\n\tpoints: DrawCoordinate[];\n\tstampCenter: DrawCoordinate | null;\n}\n\nconst DRAW_FILL = \"rgba(255, 77, 79, 0.16)\";\nconst FREEHAND_MIN_POINTS = 3;\nconst FREEHAND_SCREEN_STEP = 2;\nconst CIRCLE_SIDES = 96;\nconst MIN_AREA_PX = 1;\nconst EMPTY_REGIONS: DrawRegion[] = [];\nconst EMPTY_DASH: number[] = [];\nconst MICRONS_PER_MM = 1000;\nconst DEFAULT_STAMP_RECTANGLE_AREA_MM2 = 2;\nconst DEFAULT_STAMP_CIRCLE_AREA_MM2 = 2;\nconst DEFAULT_STAMP_RECTANGLE_PIXEL_SIZE = 4096;\nconst LEGACY_HPF_CIRCLE_AREA_MM2 = 0.2;\n\nconst DEFAULT_REGION_STROKE_STYLE: RegionStrokeStyle = {\n\tcolor: \"#ff4d4f\",\n\twidth: 2,\n\tlineDash: EMPTY_DASH,\n\tlineJoin: \"round\",\n\tlineCap: \"round\",\n\tshadowColor: \"rgba(0, 0, 0, 0)\",\n\tshadowBlur: 0,\n\tshadowOffsetX: 0,\n\tshadowOffsetY: 0,\n};\n\nconst DEFAULT_REGION_LABEL_STYLE: RegionLabelStyle = {\n\tfontFamily:\n\t\t\"ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace\",\n\tfontSize: 12,\n\tfontWeight: 500,\n\ttextColor: \"#ffffff\",\n\tbackgroundColor: \"rgba(8, 14, 22, 0.88)\",\n\tborderColor: \"rgba(255, 77, 79, 0.85)\",\n\tborderWidth: 1,\n\tpaddingX: 6,\n\tpaddingY: 4,\n\toffsetY: 10,\n\tborderRadius: 3,\n};\n\nfunction clamp(value: number, min: number, max: number): number {\n\treturn Math.max(min, Math.min(max, value));\n}\n\nfunction isStampTool(tool: DrawTool): tool is StampDrawTool {\n\treturn (\n\t\ttool === \"stamp-rectangle\" ||\n\t\ttool === \"stamp-circle\" ||\n\t\ttool === \"stamp-rectangle-4096px\" ||\n\t\ttool === \"stamp-rectangle-2mm2\" ||\n\t\ttool === \"stamp-circle-2mm2\" ||\n\t\ttool === \"stamp-circle-hpf-0.2mm2\"\n\t);\n}\n\nfunction clampPositiveOrFallback(\n\tvalue: number | undefined,\n\tfallback: number,\n): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value) || value <= 0) {\n\t\treturn fallback;\n\t}\n\treturn value;\n}\n\nfunction resolveStampOptions(options: StampOptions | undefined): Required<StampOptions> {\n\treturn {\n\t\trectangleAreaMm2: clampPositiveOrFallback(\n\t\t\toptions?.rectangleAreaMm2,\n\t\t\tDEFAULT_STAMP_RECTANGLE_AREA_MM2,\n\t\t),\n\t\tcircleAreaMm2: clampPositiveOrFallback(\n\t\t\toptions?.circleAreaMm2,\n\t\t\tDEFAULT_STAMP_CIRCLE_AREA_MM2,\n\t\t),\n\t\trectanglePixelSize: clampPositiveOrFallback(\n\t\t\toptions?.rectanglePixelSize,\n\t\t\tDEFAULT_STAMP_RECTANGLE_PIXEL_SIZE,\n\t\t),\n\t};\n}\n\nfunction mm2ToUm2(areaMm2: number): number {\n\treturn areaMm2 * MICRONS_PER_MM * MICRONS_PER_MM;\n}\n\nfunction createSquareFromCenter(\n\tcenter: DrawCoordinate | null,\n\thalfLength: number,\n): DrawCoordinate[] {\n\tif (!center || !Number.isFinite(halfLength) || halfLength <= 0) return [];\n\treturn closeRing([\n\t\t[center[0] - halfLength, center[1] - halfLength],\n\t\t[center[0] + halfLength, center[1] - halfLength],\n\t\t[center[0] + halfLength, center[1] + halfLength],\n\t\t[center[0] - halfLength, center[1] + halfLength],\n\t]);\n}\n\nfunction createCircleFromCenter(\n\tcenter: DrawCoordinate | null,\n\tradius: number,\n\tsides = CIRCLE_SIDES,\n): DrawCoordinate[] {\n\tif (!center || !Number.isFinite(radius) || radius <= 0) return [];\n\n\tconst coords: DrawCoordinate[] = [];\n\tfor (let i = 0; i <= sides; i += 1) {\n\t\tconst t = (i / sides) * Math.PI * 2;\n\t\tcoords.push([\n\t\t\tcenter[0] + Math.cos(t) * radius,\n\t\t\tcenter[1] + Math.sin(t) * radius,\n\t\t]);\n\t}\n\n\treturn closeRing(coords);\n}\n\nexport function closeRing(coords: DrawCoordinate[]): DrawCoordinate[] {\n\tif (!Array.isArray(coords) || coords.length < 3) return [];\n\n\tconst out = coords.map(([x, y]) => [x, y] as DrawCoordinate);\n\tconst first = out[0];\n\tconst last = out[out.length - 1];\n\tif (!first || !last) return [];\n\n\tif (first[0] !== last[0] || first[1] !== last[1]) {\n\t\tout.push([first[0], first[1]]);\n\t}\n\n\treturn out;\n}\n\nexport function createRectangle(\n\tstart: DrawCoordinate | null,\n\tend: DrawCoordinate | null,\n): DrawCoordinate[] {\n\tif (!start || !end) return [];\n\n\treturn closeRing([\n\t\t[start[0], start[1]],\n\t\t[end[0], start[1]],\n\t\t[end[0], end[1]],\n\t\t[start[0], end[1]],\n\t]);\n}\n\nexport function createCircle(\n\tstart: DrawCoordinate | null,\n\tend: DrawCoordinate | null,\n\tsides = CIRCLE_SIDES,\n): DrawCoordinate[] {\n\tif (!start || !end) return [];\n\n\tconst centerX = (start[0] + end[0]) * 0.5;\n\tconst centerY = (start[1] + end[1]) * 0.5;\n\tconst radius = Math.hypot(end[0] - start[0], end[1] - start[1]) * 0.5;\n\tif (radius < 1) return [];\n\n\tconst coords: DrawCoordinate[] = [];\n\tfor (let i = 0; i <= sides; i += 1) {\n\t\tconst t = (i / sides) * Math.PI * 2;\n\t\tcoords.push([\n\t\t\tcenterX + Math.cos(t) * radius,\n\t\t\tcenterY + Math.sin(t) * radius,\n\t\t]);\n\t}\n\n\treturn closeRing(coords);\n}\n\nfunction polygonArea(coords: DrawCoordinate[]): number {\n\tif (!Array.isArray(coords) || coords.length < 4) return 0;\n\n\tlet sum = 0;\n\tfor (let i = 0; i < coords.length - 1; i += 1) {\n\t\tconst a = coords[i];\n\t\tconst b = coords[i + 1];\n\t\tsum += a[0] * b[1] - b[0] * a[1];\n\t}\n\n\treturn Math.abs(sum * 0.5);\n}\n\nfunction computeBounds(coords: DrawCoordinate[]): DrawBounds {\n\tif (!Array.isArray(coords) || coords.length === 0) return [0, 0, 0, 0];\n\n\tlet minX = Infinity;\n\tlet minY = Infinity;\n\tlet maxX = -Infinity;\n\tlet maxY = -Infinity;\n\n\tfor (const [x, y] of coords) {\n\t\tif (x < minX) minX = x;\n\t\tif (x > maxX) maxX = x;\n\t\tif (y < minY) minY = y;\n\t\tif (y > maxY) maxY = y;\n\t}\n\n\treturn [minX, minY, maxX, maxY];\n}\n\nfunction isValidPolygon(coords: DrawCoordinate[]): boolean {\n\treturn (\n\t\tArray.isArray(coords) &&\n\t\tcoords.length >= 4 &&\n\t\tpolygonArea(coords) > MIN_AREA_PX\n\t);\n}\n\nfunction drawPath(\n\tctx: CanvasRenderingContext2D,\n\tpoints: DrawCoordinate[],\n\tstrokeStyle: RegionStrokeStyle,\n\tclose = false,\n\tfill = false,\n): void {\n\tif (points.length === 0) return;\n\n\tctx.beginPath();\n\tctx.moveTo(points[0][0], points[0][1]);\n\tfor (let i = 1; i < points.length; i += 1) {\n\t\tctx.lineTo(points[i][0], points[i][1]);\n\t}\n\n\tif (close) {\n\t\tctx.closePath();\n\t}\n\tif (fill && close) {\n\t\tctx.fillStyle = DRAW_FILL;\n\t\tctx.fill();\n\t}\n\n\tctx.strokeStyle = strokeStyle.color;\n\tctx.lineWidth = strokeStyle.width;\n\tctx.lineJoin = strokeStyle.lineJoin;\n\tctx.lineCap = strokeStyle.lineCap;\n\tctx.shadowColor = strokeStyle.shadowColor;\n\tctx.shadowBlur = strokeStyle.shadowBlur;\n\tctx.shadowOffsetX = strokeStyle.shadowOffsetX;\n\tctx.shadowOffsetY = strokeStyle.shadowOffsetY;\n\tctx.setLineDash(strokeStyle.lineDash);\n\tctx.stroke();\n\tctx.setLineDash(EMPTY_DASH);\n\tctx.shadowColor = \"rgba(0, 0, 0, 0)\";\n\tctx.shadowBlur = 0;\n\tctx.shadowOffsetX = 0;\n\tctx.shadowOffsetY = 0;\n}\n\nfunction resolveStrokeStyle(\n\tstyle: Partial<RegionStrokeStyle> | undefined,\n): RegionStrokeStyle {\n\tconst dash = Array.isArray(style?.lineDash)\n\t\t? style.lineDash.filter((value) => Number.isFinite(value) && value >= 0)\n\t\t: EMPTY_DASH;\n\tconst width =\n\t\ttypeof style?.width === \"number\" && Number.isFinite(style.width)\n\t\t\t? Math.max(0, style.width)\n\t\t\t: DEFAULT_REGION_STROKE_STYLE.width;\n\tconst shadowBlur =\n\t\ttypeof style?.shadowBlur === \"number\" && Number.isFinite(style.shadowBlur)\n\t\t\t? Math.max(0, style.shadowBlur)\n\t\t\t: DEFAULT_REGION_STROKE_STYLE.shadowBlur;\n\tconst shadowOffsetX =\n\t\ttypeof style?.shadowOffsetX === \"number\" &&\n\t\tNumber.isFinite(style.shadowOffsetX)\n\t\t\t? style.shadowOffsetX\n\t\t\t: DEFAULT_REGION_STROKE_STYLE.shadowOffsetX;\n\tconst shadowOffsetY =\n\t\ttypeof style?.shadowOffsetY === \"number\" &&\n\t\tNumber.isFinite(style.shadowOffsetY)\n\t\t\t? style.shadowOffsetY\n\t\t\t: DEFAULT_REGION_STROKE_STYLE.shadowOffsetY;\n\treturn {\n\t\tcolor: style?.color || DEFAULT_REGION_STROKE_STYLE.color,\n\t\twidth,\n\t\tlineDash: dash.length ? dash : EMPTY_DASH,\n\t\tlineJoin: style?.lineJoin || DEFAULT_REGION_STROKE_STYLE.lineJoin,\n\t\tlineCap: style?.lineCap || DEFAULT_REGION_STROKE_STYLE.lineCap,\n\t\tshadowColor: style?.shadowColor || DEFAULT_REGION_STROKE_STYLE.shadowColor,\n\t\tshadowBlur,\n\t\tshadowOffsetX,\n\t\tshadowOffsetY,\n\t};\n}\n\nfunction mergeStrokeStyle(\n\tbase: RegionStrokeStyle,\n\toverride: Partial<RegionStrokeStyle> | undefined,\n): RegionStrokeStyle {\n\tif (!override) return base;\n\treturn resolveStrokeStyle({\n\t\tcolor: override.color ?? base.color,\n\t\twidth: override.width ?? base.width,\n\t\tlineDash: override.lineDash ?? base.lineDash,\n\t\tlineJoin: override.lineJoin ?? base.lineJoin,\n\t\tlineCap: override.lineCap ?? base.lineCap,\n\t\tshadowColor: override.shadowColor ?? base.shadowColor,\n\t\tshadowBlur: override.shadowBlur ?? base.shadowBlur,\n\t\tshadowOffsetX: override.shadowOffsetX ?? base.shadowOffsetX,\n\t\tshadowOffsetY: override.shadowOffsetY ?? base.shadowOffsetY,\n\t});\n}\n\nfunction isSameRegionId(\n\ta: string | number | null | undefined,\n\tb: string | number | null | undefined,\n): boolean {\n\tif (a === null || a === undefined || b === null || b === undefined) {\n\t\treturn false;\n\t}\n\treturn String(a) === String(b);\n}\n\nfunction resolveLabelStyle(\n\tstyle: Partial<RegionLabelStyle> | undefined,\n): RegionLabelStyle {\n\tconst px =\n\t\ttypeof style?.paddingX === \"number\" && Number.isFinite(style.paddingX)\n\t\t\t? Math.max(0, style.paddingX)\n\t\t\t: DEFAULT_REGION_LABEL_STYLE.paddingX;\n\tconst py =\n\t\ttypeof style?.paddingY === \"number\" && Number.isFinite(style.paddingY)\n\t\t\t? Math.max(0, style.paddingY)\n\t\t\t: DEFAULT_REGION_LABEL_STYLE.paddingY;\n\tconst fs =\n\t\ttypeof style?.fontSize === \"number\" && Number.isFinite(style.fontSize)\n\t\t\t? Math.max(8, style.fontSize)\n\t\t\t: DEFAULT_REGION_LABEL_STYLE.fontSize;\n\tconst bw =\n\t\ttypeof style?.borderWidth === \"number\" && Number.isFinite(style.borderWidth)\n\t\t\t? Math.max(0, style.borderWidth)\n\t\t\t: DEFAULT_REGION_LABEL_STYLE.borderWidth;\n\tconst oy =\n\t\ttypeof style?.offsetY === \"number\" && Number.isFinite(style.offsetY)\n\t\t\t? style.offsetY\n\t\t\t: DEFAULT_REGION_LABEL_STYLE.offsetY;\n\tconst br =\n\t\ttypeof style?.borderRadius === \"number\" &&\n\t\tNumber.isFinite(style.borderRadius)\n\t\t\t? Math.max(0, style.borderRadius)\n\t\t\t: DEFAULT_REGION_LABEL_STYLE.borderRadius;\n\treturn {\n\t\tfontFamily: style?.fontFamily || DEFAULT_REGION_LABEL_STYLE.fontFamily,\n\t\tfontSize: fs,\n\t\tfontWeight: style?.fontWeight || DEFAULT_REGION_LABEL_STYLE.fontWeight,\n\t\ttextColor: style?.textColor || DEFAULT_REGION_LABEL_STYLE.textColor,\n\t\tbackgroundColor:\n\t\t\tstyle?.backgroundColor || DEFAULT_REGION_LABEL_STYLE.backgroundColor,\n\t\tborderColor: style?.borderColor || DEFAULT_REGION_LABEL_STYLE.borderColor,\n\t\tborderWidth: bw,\n\t\tpaddingX: px,\n\t\tpaddingY: py,\n\t\toffsetY: oy,\n\t\tborderRadius: br,\n\t};\n}\n\nfunction drawRoundedRect(\n\tctx: CanvasRenderingContext2D,\n\tx: number,\n\ty: number,\n\twidth: number,\n\theight: number,\n\tradius: number,\n): void {\n\tconst r = Math.max(0, Math.min(radius, width * 0.5, height * 0.5));\n\tctx.beginPath();\n\tctx.moveTo(x + r, y);\n\tctx.lineTo(x + width - r, y);\n\tctx.quadraticCurveTo(x + width, y, x + width, y + r);\n\tctx.lineTo(x + width, y + height - r);\n\tctx.quadraticCurveTo(x + width, y + height, x + width - r, y + height);\n\tctx.lineTo(x + r, y + height);\n\tctx.quadraticCurveTo(x, y + height, x, y + height - r);\n\tctx.lineTo(x, y + r);\n\tctx.quadraticCurveTo(x, y, x + r, y);\n\tctx.closePath();\n}\n\nfunction getTopAnchor(coords: DrawCoordinate[]): DrawCoordinate | null {\n\tif (!coords.length) return null;\n\n\tlet minY = Infinity;\n\tfor (const point of coords) {\n\t\tif (point[1] < minY) minY = point[1];\n\t}\n\tif (!Number.isFinite(minY)) return null;\n\n\tlet minX = Infinity;\n\tlet maxX = -Infinity;\n\tfor (const point of coords) {\n\t\tif (Math.abs(point[1] - minY) > 0.5) continue;\n\t\tif (point[0] < minX) minX = point[0];\n\t\tif (point[0] > maxX) maxX = point[0];\n\t}\n\n\tif (!Number.isFinite(minX) || !Number.isFinite(maxX)) return null;\n\treturn [(minX + maxX) * 0.5, minY];\n}\n\nfunction drawRegionLabel(\n\tctx: CanvasRenderingContext2D,\n\ttext: string,\n\tanchor: DrawCoordinate,\n\tcanvasWidth: number,\n\tcanvasHeight: number,\n\tlabelStyle: RegionLabelStyle,\n): void {\n\tconst label = text.trim();\n\tif (!label) return;\n\n\tctx.save();\n\tctx.font = `${labelStyle.fontWeight} ${labelStyle.fontSize}px ${labelStyle.fontFamily}`;\n\tctx.textAlign = \"center\";\n\tctx.textBaseline = \"middle\";\n\n\tconst textWidth = ctx.measureText(label).width;\n\tconst boxWidth = textWidth + labelStyle.paddingX * 2;\n\tconst boxHeight = labelStyle.fontSize + labelStyle.paddingY * 2;\n\n\tconst x = clamp(\n\t\tanchor[0],\n\t\tboxWidth * 0.5 + 1,\n\t\tcanvasWidth - boxWidth * 0.5 - 1,\n\t);\n\tconst y = clamp(\n\t\tanchor[1] - labelStyle.offsetY,\n\t\tboxHeight * 0.5 + 1,\n\t\tcanvasHeight - boxHeight * 0.5 - 1,\n\t);\n\tconst left = x - boxWidth * 0.5;\n\tconst top = y - boxHeight * 0.5;\n\n\tctx.fillStyle = labelStyle.backgroundColor;\n\tctx.strokeStyle = labelStyle.borderColor;\n\tctx.lineWidth = labelStyle.borderWidth;\n\tdrawRoundedRect(\n\t\tctx,\n\t\tleft,\n\t\ttop,\n\t\tboxWidth,\n\t\tboxHeight,\n\t\tlabelStyle.borderRadius,\n\t);\n\tctx.fill();\n\tif (labelStyle.borderWidth > 0) {\n\t\tctx.stroke();\n\t}\n\n\tctx.fillStyle = labelStyle.textColor;\n\tctx.fillText(label, x, y + 0.5);\n\tctx.restore();\n}\n\nfunction clampWorld(\n\tcoord: DrawCoordinate,\n\timageWidth: number,\n\timageHeight: number,\n): DrawCoordinate {\n\treturn [clamp(coord[0], 0, imageWidth), clamp(coord[1], 0, imageHeight)];\n}\n\nfunction toCoord(value: DrawCoordinate | number[]): DrawCoordinate | null {\n\tif (!Array.isArray(value) || value.length < 2) return null;\n\tconst x = Number(value[0]);\n\tconst y = Number(value[1]);\n\tif (!Number.isFinite(x) || !Number.isFinite(y)) return null;\n\treturn [x, y];\n}\n\nexport function DrawLayer({\n\ttool,\n\timageWidth,\n\timageHeight,\n\timageMpp,\n\timageZoom,\n\tstampOptions,\n\tprojectorRef,\n\tonDrawComplete,\n\tenabled,\n\tviewStateSignal,\n\tpersistedRegions,\n\tpersistedPolygons,\n\tregionStrokeStyle,\n\tregionStrokeHoverStyle,\n\tregionStrokeActiveStyle,\n\tresolveRegionStrokeStyle,\n\toverlayShapes,\n\thoveredRegionId = null,\n\tactiveRegionId = null,\n\tregionLabelStyle,\n\tinvalidateRef,\n\tclassName,\n\tstyle,\n}: DrawLayerProps): React.ReactElement {\n\tconst canvasRef = useRef<HTMLCanvasElement | null>(null);\n\tconst drawPendingRef = useRef(false);\n\tconst lastToolRef = useRef<DrawTool>(tool);\n\tconst sessionRef = useRef<DrawSession>({\n\t\tisDrawing: false,\n\t\tpointerId: null,\n\t\tstart: null,\n\t\tcurrent: null,\n\t\tpoints: [],\n\t\tstampCenter: null,\n\t});\n\n\tconst active = enabled ?? tool !== \"cursor\";\n\tconst mergedPersistedRegions = useMemo<DrawRegion[]>(() => {\n\t\tif (persistedRegions && persistedRegions.length > 0) {\n\t\t\treturn persistedRegions;\n\t\t}\n\t\tif (!persistedPolygons || persistedPolygons.length === 0) {\n\t\t\treturn EMPTY_REGIONS;\n\t\t}\n\t\treturn persistedPolygons.map((coordinates, index) => ({\n\t\t\tid: index,\n\t\t\tcoordinates,\n\t\t}));\n\t}, [persistedRegions, persistedPolygons]);\n\n\tconst resolvedStrokeStyle = useMemo(\n\t\t() => resolveStrokeStyle(regionStrokeStyle),\n\t\t[regionStrokeStyle],\n\t);\n\tconst resolvedHoverStrokeStyle = useMemo(\n\t\t() => mergeStrokeStyle(resolvedStrokeStyle, regionStrokeHoverStyle),\n\t\t[resolvedStrokeStyle, regionStrokeHoverStyle],\n\t);\n\tconst resolvedActiveStrokeStyle = useMemo(\n\t\t() => mergeStrokeStyle(resolvedStrokeStyle, regionStrokeActiveStyle),\n\t\t[resolvedStrokeStyle, regionStrokeActiveStyle],\n\t);\n\n\tconst resolvedLabelStyle = useMemo(\n\t\t() => resolveLabelStyle(regionLabelStyle),\n\t\t[regionLabelStyle],\n\t);\n\tconst resolvedStampOptions = useMemo(\n\t\t() => resolveStampOptions(stampOptions),\n\t\t[stampOptions],\n\t);\n\n\tconst mergedStyle = useMemo<CSSProperties>(\n\t\t() => ({\n\t\t\tposition: \"absolute\",\n\t\t\tinset: 0,\n\t\t\tzIndex: 2,\n\t\t\twidth: \"100%\",\n\t\t\theight: \"100%\",\n\t\t\tdisplay: \"block\",\n\t\t\ttouchAction: \"none\",\n\t\t\tpointerEvents: active ? \"auto\" : \"none\",\n\t\t\tcursor: active ? \"crosshair\" : \"default\",\n\t\t\t...style,\n\t\t}),\n\t\t[active, style],\n\t);\n\n\tconst resizeCanvas = useCallback(() => {\n\t\tconst canvas = canvasRef.current;\n\t\tif (!canvas) return;\n\n\t\tconst rect = canvas.getBoundingClientRect();\n\t\tconst dpr = Math.max(1, window.devicePixelRatio || 1);\n\t\tconst w = Math.max(1, Math.round(rect.width * dpr));\n\t\tconst h = Math.max(1, Math.round(rect.height * dpr));\n\n\t\tif (canvas.width !== w || canvas.height !== h) {\n\t\t\tcanvas.width = w;\n\t\t\tcanvas.height = h;\n\t\t}\n\t}, []);\n\n\tconst worldToScreenPoints = useCallback(\n\t\t(points: DrawCoordinate[]): DrawCoordinate[] => {\n\t\t\tconst projector = projectorRef.current;\n\t\t\tif (!projector || points.length === 0) return [];\n\n\t\t\tconst out = new Array<DrawCoordinate>(points.length);\n\t\t\tfor (let i = 0; i < points.length; i += 1) {\n\t\t\t\tconst coord = toCoord(\n\t\t\t\t\tprojector.worldToScreen(points[i][0], points[i][1]),\n\t\t\t\t);\n\t\t\t\tif (!coord) return [];\n\t\t\t\tout[i] = coord;\n\t\t\t}\n\t\t\treturn out;\n\t\t},\n\t\t[projectorRef],\n\t);\n\n\tconst micronsToWorldPixels = useCallback(\n\t\t(lengthUm: number): number => {\n\t\t\tif (!Number.isFinite(lengthUm) || lengthUm <= 0) return 0;\n\n\t\t\t// If mpp is missing, fall back to 1um/px assumption.\n\t\t\tconst mppValue =\n\t\t\t\ttypeof imageMpp === \"number\" && Number.isFinite(imageMpp) && imageMpp > 0\n\t\t\t\t\t? imageMpp\n\t\t\t\t\t: 1;\n\t\t\tconst imageZoomValue =\n\t\t\t\ttypeof imageZoom === \"number\" && Number.isFinite(imageZoom)\n\t\t\t\t\t? imageZoom\n\t\t\t\t\t: 0;\n\t\t\tconst viewZoomRaw = projectorRef.current?.getViewState?.().zoom;\n\t\t\tconst viewZoom =\n\t\t\t\ttypeof viewZoomRaw === \"number\" &&\n\t\t\t\tNumber.isFinite(viewZoomRaw) &&\n\t\t\t\tviewZoomRaw > 0\n\t\t\t\t\t? viewZoomRaw\n\t\t\t\t\t: 1;\n\t\t\tconst continuousZoom = imageZoomValue + Math.log2(viewZoom);\n\t\t\tconst umPerScreenPixel = Math.max(\n\t\t\t\t1e-9,\n\t\t\t\tcalcScaleResolution(mppValue, imageZoomValue, continuousZoom),\n\t\t\t);\n\t\t\tconst screenPixels = lengthUm / umPerScreenPixel;\n\t\t\treturn screenPixels / viewZoom;\n\t\t},\n\t\t[imageMpp, imageZoom, projectorRef],\n\t);\n\n\tconst buildStampCoords = useCallback(\n\t\t(stampTool: StampDrawTool, center: DrawCoordinate | null): DrawCoordinate[] => {\n\t\t\tif (!center) return [];\n\n\t\t\tlet areaMm2 = 0;\n\t\t\tif (stampTool === \"stamp-rectangle-4096px\") {\n\t\t\t\tconst halfLength = resolvedStampOptions.rectanglePixelSize * 0.5;\n\t\t\t\tconst fixed = createSquareFromCenter(center, halfLength);\n\t\t\t\treturn fixed.map((point) => clampWorld(point, imageWidth, imageHeight));\n\t\t\t}\n\n\t\t\tif (stampTool === \"stamp-rectangle\" || stampTool === \"stamp-rectangle-2mm2\") {\n\t\t\t\tareaMm2 =\n\t\t\t\t\tstampTool === \"stamp-rectangle-2mm2\"\n\t\t\t\t\t\t? DEFAULT_STAMP_RECTANGLE_AREA_MM2\n\t\t\t\t\t\t: resolvedStampOptions.rectangleAreaMm2;\n\t\t\t} else if (\n\t\t\t\tstampTool === \"stamp-circle\" ||\n\t\t\t\tstampTool === \"stamp-circle-2mm2\" ||\n\t\t\t\tstampTool === \"stamp-circle-hpf-0.2mm2\"\n\t\t\t) {\n\t\t\t\tareaMm2 =\n\t\t\t\t\tstampTool === \"stamp-circle-hpf-0.2mm2\"\n\t\t\t\t\t\t? LEGACY_HPF_CIRCLE_AREA_MM2\n\t\t\t\t\t\t: stampTool === \"stamp-circle-2mm2\"\n\t\t\t\t\t\t\t? DEFAULT_STAMP_CIRCLE_AREA_MM2\n\t\t\t\t\t\t\t: resolvedStampOptions.circleAreaMm2;\n\t\t\t}\n\t\t\tif (!Number.isFinite(areaMm2) || areaMm2 <= 0) return [];\n\n\t\t\tconst areaUm2 = mm2ToUm2(areaMm2);\n\t\t\tlet coords: DrawCoordinate[] = [];\n\t\t\tif (stampTool === \"stamp-rectangle\" || stampTool === \"stamp-rectangle-2mm2\") {\n\t\t\t\tconst halfLength = micronsToWorldPixels(Math.sqrt(areaUm2) * 0.5);\n\t\t\t\tcoords = createSquareFromCenter(center, halfLength);\n\t\t\t} else if (\n\t\t\t\tstampTool === \"stamp-circle\" ||\n\t\t\t\tstampTool === \"stamp-circle-2mm2\" ||\n\t\t\t\tstampTool === \"stamp-circle-hpf-0.2mm2\"\n\t\t\t) {\n\t\t\t\tconst radius = micronsToWorldPixels(Math.sqrt(areaUm2 / Math.PI));\n\t\t\t\tcoords = createCircleFromCenter(center, radius);\n\t\t\t}\n\n\t\t\tif (!coords.length) return [];\n\t\t\treturn coords.map((point) => clampWorld(point, imageWidth, imageHeight));\n\t\t},\n\t\t[micronsToWorldPixels, imageWidth, imageHeight, resolvedStampOptions],\n\t);\n\n\tconst buildPreviewCoords = useCallback((): DrawCoordinate[] => {\n\t\tconst session = sessionRef.current;\n\t\tif (isStampTool(tool)) {\n\t\t\treturn buildStampCoords(tool, session.stampCenter);\n\t\t}\n\t\tif (!session.isDrawing) return [];\n\n\t\tif (tool === \"freehand\") {\n\t\t\treturn session.points;\n\t\t}\n\t\tif (tool === \"rectangle\") {\n\t\t\treturn createRectangle(session.start, session.current);\n\t\t}\n\t\tif (tool === \"circular\") {\n\t\t\treturn createCircle(session.start, session.current);\n\t\t}\n\n\t\treturn [];\n\t}, [tool, buildStampCoords]);\n\n\tconst drawOverlay = useCallback(() => {\n\t\tresizeCanvas();\n\n\t\tconst canvas = canvasRef.current;\n\t\tif (!canvas) return;\n\n\t\tconst ctx = canvas.getContext(\"2d\");\n\t\tif (!ctx) return;\n\n\t\tconst dpr = Math.max(1, window.devicePixelRatio || 1);\n\t\tconst canvasWidth = canvas.width / dpr;\n\t\tconst canvasHeight = canvas.height / dpr;\n\t\tctx.setTransform(1, 0, 0, 1, 0, 0);\n\t\tctx.clearRect(0, 0, canvas.width, canvas.height);\n\t\tctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n\n\t\t// Persisted ROI outlines always remain visible.\n\t\tif (mergedPersistedRegions.length > 0) {\n\t\t\tfor (let i = 0; i < mergedPersistedRegions.length; i += 1) {\n\t\t\t\tconst region = mergedPersistedRegions[i];\n\t\t\t\tconst ring = region?.coordinates;\n\t\t\t\tif (!ring || ring.length < 3) continue;\n\t\t\t\tconst closed = closeRing(ring);\n\t\t\t\tconst screen = worldToScreenPoints(closed);\n\t\t\t\tif (screen.length >= 4) {\n\t\t\t\t\tconst regionKey = region.id ?? i;\n\t\t\t\t\tconst state: RegionStyleContext[\"state\"] = isSameRegionId(\n\t\t\t\t\t\tactiveRegionId,\n\t\t\t\t\t\tregionKey,\n\t\t\t\t\t)\n\t\t\t\t\t\t? \"active\"\n\t\t\t\t\t\t: isSameRegionId(hoveredRegionId, regionKey)\n\t\t\t\t\t\t\t? \"hover\"\n\t\t\t\t\t\t\t: \"default\";\n\t\t\t\t\tlet strokeStyle =\n\t\t\t\t\t\tstate === \"active\"\n\t\t\t\t\t\t\t? resolvedActiveStrokeStyle\n\t\t\t\t\t\t\t: state === \"hover\"\n\t\t\t\t\t\t\t\t? resolvedHoverStrokeStyle\n\t\t\t\t\t\t\t\t: resolvedStrokeStyle;\n\n\t\t\t\t\tif (resolveRegionStrokeStyle) {\n\t\t\t\t\t\tconst resolved = resolveRegionStrokeStyle({\n\t\t\t\t\t\t\tregion,\n\t\t\t\t\t\t\tregionId: regionKey,\n\t\t\t\t\t\t\tregionIndex: i,\n\t\t\t\t\t\t\tstate,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tstrokeStyle = mergeStrokeStyle(strokeStyle, resolved || undefined);\n\t\t\t\t\t}\n\t\t\t\t\tdrawPath(ctx, screen, strokeStyle, true, false);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (Array.isArray(overlayShapes) && overlayShapes.length > 0) {\n\t\t\tfor (let i = 0; i < overlayShapes.length; i += 1) {\n\t\t\t\tconst shape = overlayShapes[i];\n\t\t\t\tif (!shape?.coordinates?.length) continue;\n\t\t\t\tconst closed = shape.closed ?? false;\n\t\t\t\tconst points = closed ? closeRing(shape.coordinates) : shape.coordinates;\n\t\t\t\tconst screen = worldToScreenPoints(points);\n\t\t\t\tif (screen.length < 2) continue;\n\t\t\t\tconst strokeStyle = mergeStrokeStyle(\n\t\t\t\t\tresolvedStrokeStyle,\n\t\t\t\t\tshape.strokeStyle,\n\t\t\t\t);\n\t\t\t\tdrawPath(ctx, screen, strokeStyle, closed, shape.fill ?? false);\n\t\t\t}\n\t\t}\n\n\t\tif (active) {\n\t\t\tconst preview = buildPreviewCoords();\n\t\t\tif (preview.length > 0) {\n\t\t\t\tif (tool === \"freehand\") {\n\t\t\t\t\tconst line = worldToScreenPoints(preview);\n\t\t\t\t\tif (line.length >= 2) {\n\t\t\t\t\t\tdrawPath(ctx, line, resolvedStrokeStyle, false, false);\n\t\t\t\t\t}\n\t\t\t\t\tif (line.length >= 3) {\n\t\t\t\t\t\tdrawPath(\n\t\t\t\t\t\t\tctx,\n\t\t\t\t\t\t\tworldToScreenPoints(closeRing(preview)),\n\t\t\t\t\t\t\tresolvedStrokeStyle,\n\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tconst polygon = worldToScreenPoints(preview);\n\t\t\t\t\tif (polygon.length >= 4) {\n\t\t\t\t\t\tdrawPath(ctx, polygon, resolvedStrokeStyle, true, true);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Draw labels last so they stay visually on top.\n\t\tif (mergedPersistedRegions.length > 0) {\n\t\t\tfor (const region of mergedPersistedRegions) {\n\t\t\t\tif (!region.label) continue;\n\t\t\t\tconst ring = region?.coordinates;\n\t\t\t\tif (!ring || ring.length < 3) continue;\n\t\t\t\tconst closed = closeRing(ring);\n\t\t\t\tconst anchorWorld = getTopAnchor(closed);\n\t\t\t\tif (!anchorWorld) continue;\n\t\t\t\tconst anchorScreen = toCoord(\n\t\t\t\t\tprojectorRef.current?.worldToScreen(anchorWorld[0], anchorWorld[1]) ??\n\t\t\t\t\t\t[],\n\t\t\t\t);\n\t\t\t\tif (!anchorScreen) continue;\n\t\t\t\tdrawRegionLabel(\n\t\t\t\t\tctx,\n\t\t\t\t\tregion.label,\n\t\t\t\t\tanchorScreen,\n\t\t\t\t\tcanvasWidth,\n\t\t\t\t\tcanvasHeight,\n\t\t\t\t\tresolvedLabelStyle,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}, [\n\t\tactive,\n\t\ttool,\n\t\tbuildPreviewCoords,\n\t\tresizeCanvas,\n\t\tworldToScreenPoints,\n\t\tprojectorRef,\n\t\tmergedPersistedRegions,\n\t\toverlayShapes,\n\t\thoveredRegionId,\n\t\tactiveRegionId,\n\t\tresolvedStrokeStyle,\n\t\tresolvedHoverStrokeStyle,\n\t\tresolvedActiveStrokeStyle,\n\t\tresolveRegionStrokeStyle,\n\t\tresolvedLabelStyle,\n\t]);\n\n\tconst requestDraw = useCallback(() => {\n\t\tif (drawPendingRef.current) return;\n\t\tdrawPendingRef.current = true;\n\t\trequestAnimationFrame(() => {\n\t\t\tdrawPendingRef.current = false;\n\t\t\tdrawOverlay();\n\t\t});\n\t}, [drawOverlay]);\n\n\tconst resetSession = useCallback(() => {\n\t\tconst session = sessionRef.current;\n\t\tconst canvas = canvasRef.current;\n\n\t\tif (\n\t\t\tcanvas &&\n\t\t\tsession.pointerId !== null &&\n\t\t\tcanvas.hasPointerCapture(session.pointerId)\n\t\t) {\n\t\t\ttry {\n\t\t\t\tcanvas.releasePointerCapture(session.pointerId);\n\t\t\t} catch {\n\t\t\t\t// noop\n\t\t\t}\n\t\t}\n\n\t\tsession.isDrawing = false;\n\t\tsession.pointerId = null;\n\t\tsession.start = null;\n\t\tsession.current = null;\n\t\tsession.points = [];\n\t\tsession.stampCenter = null;\n\t}, []);\n\n\tconst toWorld = useCallback(\n\t\t(event: ReactPointerEvent<HTMLCanvasElement>): DrawCoordinate | null => {\n\t\t\tconst projector = projectorRef.current;\n\t\t\tif (!projector || imageWidth <= 0 || imageHeight <= 0) return null;\n\n\t\t\tconst raw = toCoord(\n\t\t\t\tprojector.screenToWorld(event.clientX, event.clientY),\n\t\t\t);\n\t\t\tif (!raw) return null;\n\t\t\treturn clampWorld(raw, imageWidth, imageHeight);\n\t\t},\n\t\t[projectorRef, imageWidth, imageHeight],\n\t);\n\n\tconst finishSession = useCallback(() => {\n\t\tconst session = sessionRef.current;\n\t\tif (!session.isDrawing) {\n\t\t\tresetSession();\n\t\t\trequestDraw();\n\t\t\treturn;\n\t\t}\n\n\t\tlet coordinates: DrawCoordinate[] = [];\n\t\tif (tool === \"freehand\") {\n\t\t\tif (session.points.length >= FREEHAND_MIN_POINTS) {\n\t\t\t\tcoordinates = closeRing(session.points);\n\t\t\t}\n\t\t} else if (tool === \"rectangle\") {\n\t\t\tcoordinates = createRectangle(session.start, session.current);\n\t\t} else if (tool === \"circular\") {\n\t\t\tcoordinates = createCircle(session.start, session.current);\n\t\t}\n\n\t\tif (\n\t\t\t(tool === \"freehand\" || tool === \"rectangle\" || tool === \"circular\") &&\n\t\t\tisValidPolygon(coordinates) &&\n\t\t\tonDrawComplete\n\t\t) {\n\t\t\tonDrawComplete({\n\t\t\t\ttool,\n\t\t\t\tcoordinates,\n\t\t\t\tbbox: computeBounds(coordinates),\n\t\t\t\tareaPx: polygonArea(coordinates),\n\t\t\t});\n\t\t}\n\n\t\tresetSession();\n\t\trequestDraw();\n\t}, [tool, onDrawComplete, resetSession, requestDraw]);\n\n\tconst handleStampAt = useCallback(\n\t\t(stampTool: StampDrawTool, center: DrawCoordinate): void => {\n\t\t\tconst coordinates = buildStampCoords(stampTool, center);\n\t\t\tif (!isValidPolygon(coordinates) || !onDrawComplete) return;\n\t\t\tonDrawComplete({\n\t\t\t\ttool: stampTool,\n\t\t\t\tcoordinates,\n\t\t\t\tbbox: computeBounds(coordinates),\n\t\t\t\tareaPx: polygonArea(coordinates),\n\t\t\t});\n\t\t},\n\t\t[buildStampCoords, onDrawComplete],\n\t);\n\n\tconst handlePointerDown = useCallback(\n\t\t(event: ReactPointerEvent<HTMLCanvasElement>) => {\n\t\t\tif (!active) return;\n\t\t\tif (tool === \"cursor\") return;\n\t\t\tif (event.button !== 0) return;\n\n\t\t\tconst world = toWorld(event);\n\t\t\tif (!world) return;\n\n\t\t\tevent.preventDefault();\n\t\t\tevent.stopPropagation();\n\n\t\t\tif (isStampTool(tool)) {\n\t\t\t\tconst session = sessionRef.current;\n\t\t\t\tsession.stampCenter = world;\n\t\t\t\thandleStampAt(tool, world);\n\t\t\t\trequestDraw();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst canvas = canvasRef.current;\n\t\t\tif (canvas) {\n\t\t\t\tcanvas.setPointerCapture(event.pointerId);\n\t\t\t}\n\n\t\t\tconst session = sessionRef.current;\n\t\t\tsession.isDrawing = true;\n\t\t\tsession.pointerId = event.pointerId;\n\t\t\tsession.start = world;\n\t\t\tsession.current = world;\n\t\t\tsession.points = tool === \"freehand\" ? [world] : [];\n\t\t\trequestDraw();\n\t\t},\n\t\t[active, tool, toWorld, handleStampAt, requestDraw],\n\t);\n\n\tconst handlePointerMove = useCallback(\n\t\t(event: ReactPointerEvent<HTMLCanvasElement>) => {\n\t\t\tif (!active) return;\n\t\t\tif (tool === \"cursor\") return;\n\n\t\t\tconst world = toWorld(event);\n\t\t\tif (!world) return;\n\n\t\t\tif (isStampTool(tool)) {\n\t\t\t\tconst session = sessionRef.current;\n\t\t\t\tsession.stampCenter = world;\n\t\t\t\tevent.preventDefault();\n\t\t\t\tevent.stopPropagation();\n\t\t\t\trequestDraw();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst session = sessionRef.current;\n\t\t\tif (!session.isDrawing || session.pointerId !== event.pointerId) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tevent.preventDefault();\n\t\t\tevent.stopPropagation();\n\n\t\t\tif (tool === \"freehand\") {\n\t\t\t\tconst projector = projectorRef.current;\n\t\t\t\tconst zoom = Math.max(1e-6, projector?.getViewState?.().zoom ?? 1);\n\t\t\t\tconst minWorldStep = FREEHAND_SCREEN_STEP / zoom;\n\t\t\t\tconst minWorldStep2 = minWorldStep * minWorldStep;\n\t\t\t\tconst prev = session.points[session.points.length - 1];\n\n\t\t\t\tif (!prev) {\n\t\t\t\t\tsession.points.push(world);\n\t\t\t\t} else {\n\t\t\t\t\tconst dx = world[0] - prev[0];\n\t\t\t\t\tconst dy = world[1] - prev[1];\n\t\t\t\t\tif (dx * dx + dy * dy >= minWorldStep2) {\n\t\t\t\t\t\tsession.points.push(world);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tsession.current = world;\n\t\t\t}\n\n\t\t\trequestDraw();\n\t\t},\n\t\t[active, tool, toWorld, requestDraw, projectorRef],\n\t);\n\n\tconst handlePointerUp = useCallback(\n\t\t(event: ReactPointerEvent<HTMLCanvasElement>) => {\n\t\t\tconst session = sessionRef.current;\n\t\t\tif (!session.isDrawing || session.pointerId !== event.pointerId) return;\n\n\t\t\tevent.preventDefault();\n\t\t\tevent.stopPropagation();\n\t\t\tconst canvas = canvasRef.current;\n\t\t\tif (canvas && canvas.hasPointerCapture(event.pointerId)) {\n\t\t\t\ttry {\n\t\t\t\t\tcanvas.releasePointerCapture(event.pointerId);\n\t\t\t\t} catch {\n\t\t\t\t\t// noop\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfinishSession();\n\t\t},\n\t\t[finishSession],\n\t);\n\n\tconst handlePointerLeave = useCallback(() => {\n\t\tif (!isStampTool(tool)) return;\n\t\tconst session = sessionRef.current;\n\t\tif (!session.stampCenter) return;\n\t\tsession.stampCenter = null;\n\t\trequestDraw();\n\t}, [tool, requestDraw]);\n\n\tuseEffect(() => {\n\t\tresizeCanvas();\n\t\trequestDraw();\n\n\t\tconst canvas = canvasRef.current;\n\t\tif (!canvas) return undefined;\n\n\t\tconst observer = new ResizeObserver(() => {\n\t\t\tresizeCanvas();\n\t\t\trequestDraw();\n\t\t});\n\t\tobserver.observe(canvas);\n\n\t\treturn () => {\n\t\t\tobserver.disconnect();\n\t\t};\n\t}, [resizeCanvas, requestDraw]);\n\n\tuseEffect(() => {\n\t\tif (!active) {\n\t\t\tresetSession();\n\t\t}\n\t\trequestDraw();\n\t}, [active, requestDraw, resetSession]);\n\n\tuseEffect(() => {\n\t\tif (lastToolRef.current === tool) {\n\t\t\treturn;\n\t\t}\n\t\tlastToolRef.current = tool;\n\t\tresetSession();\n\t\trequestDraw();\n\t}, [tool, resetSession, requestDraw]);\n\n\tuseEffect(() => {\n\t\trequestDraw();\n\t}, [viewStateSignal, mergedPersistedRegions, overlayShapes, requestDraw]);\n\n\tuseEffect(() => {\n\t\tif (!invalidateRef) return undefined;\n\t\tinvalidateRef.current = requestDraw;\n\t\treturn () => {\n\t\t\tif (invalidateRef.current === requestDraw) {\n\t\t\t\tinvalidateRef.current = null;\n\t\t\t}\n\t\t};\n\t}, [invalidateRef, requestDraw]);\n\n\tuseEffect(() => {\n\t\tif (!active) return undefined;\n\n\t\tconst onKeyDown = (event: KeyboardEvent): void => {\n\t\t\tif (event.key !== \"Escape\") return;\n\t\t\tresetSession();\n\t\t\trequestDraw();\n\t\t};\n\n\t\twindow.addEventListener(\"keydown\", onKeyDown);\n\t\treturn () => {\n\t\t\twindow.removeEventListener(\"keydown\", onKeyDown);\n\t\t};\n\t}, [active, resetSession, requestDraw]);\n\n\treturn (\n\t\t<canvas\n\t\t\tref={canvasRef}\n\t\t\tclassName={className}\n\t\t\tstyle={mergedStyle}\n\t\t\tonPointerDown={handlePointerDown}\n\t\t\tonPointerMove={handlePointerMove}\n\t\t\tonPointerUp={handlePointerUp}\n\t\t\tonPointerCancel={handlePointerUp}\n\t\t\tonPointerLeave={handlePointerLeave}\n\t\t\tonContextMenu={(event) => {\n\t\t\t\tif (active) event.preventDefault();\n\t\t\t}}\n\t\t\tonWheel={(event) => {\n\t\t\t\tif (active) event.preventDefault();\n\t\t\t}}\n\t\t/>\n\t);\n}\n","import type { WsiImageSource, WsiTerm } from \"./types\";\n\nfunction trimTrailingSlash(value: string): string {\n return String(value ?? \"\").replace(/\\/+$/, \"\");\n}\n\nfunction ensureLeadingSlash(value: string): string {\n const raw = String(value ?? \"\");\n return raw.startsWith(\"/\") ? raw : `/${raw}`;\n}\n\nfunction joinImsTileRoot(tileBaseUrl: string): string {\n const base = trimTrailingSlash(tileBaseUrl);\n if (!base) return \"\";\n\n // Explicit TileGroup path already provided.\n if (/\\/TileGroup\\d+$/i.test(base)) return base;\n\n let parsed: URL | null = null;\n try {\n parsed = new URL(base);\n } catch {\n parsed = null;\n }\n\n if (parsed) {\n const origin = `${parsed.protocol}//${parsed.host}`;\n const path = trimTrailingSlash(parsed.pathname || \"\");\n\n // If caller passes /ims, keep /ims and append image path directly:\n // /ims + /tiles/<hash> + /tier/y_x.webp\n if (/\\/ims$/i.test(path)) return `${origin}${path}`;\n if (/\\/tiles$/i.test(path)) return `${origin}${path}`;\n return `${origin}${path}/tiles`;\n }\n\n // Relative path mode\n if (/\\/ims$/i.test(base)) return `/ims`;\n if (/\\/tiles$/i.test(base)) return `${base}`;\n return `${base}/tiles`;\n}\n\nexport function normalizeImageInfo(raw: any, tileBaseUrl: string): WsiImageSource {\n const ims = raw?.imsInfo || {};\n const isIms = !!raw?.imsInfo;\n\n const width = Number(ims.width ?? raw?.width ?? 0);\n const height = Number(ims.height ?? raw?.height ?? 0);\n const tileSize = Number(ims.tileSize ?? raw?.tileSize ?? 0);\n const maxTierZoom = Number(ims.zoom ?? raw?.zoom ?? 0);\n const tilePath = String(ims.path ?? raw?.path ?? \"\");\n const mpp = Number(ims.mpp ?? raw?.mpp ?? 0);\n\n if (!width || !height || !tileSize || !tilePath) {\n throw new Error(\"이미지 메타데이터가 불완전합니다. width/height/tileSize/path 확인 필요\");\n }\n\n const terms: WsiTerm[] = Array.isArray(raw?.terms)\n ? raw.terms.map((term: any) => ({\n termId: String(term?.termId ?? \"\"),\n termName: String(term?.termName ?? \"\"),\n termColor: String(term?.termColor ?? \"\"),\n }))\n : [];\n\n const normalizedPath = ensureLeadingSlash(tilePath);\n const imsTileRoot = joinImsTileRoot(tileBaseUrl);\n const tileUrlBuilder = isIms ? (tier: number, x: number, y: number): string => `${imsTileRoot}${normalizedPath}/${tier}/${y}_${x}.webp` : undefined;\n\n return {\n id: raw?._id || \"unknown\",\n name: raw?.name || \"unknown\",\n width,\n height,\n mpp: Number.isFinite(mpp) && mpp > 0 ? mpp : undefined,\n tileSize,\n maxTierZoom: Number.isFinite(maxTierZoom) ? Math.max(0, Math.floor(maxTierZoom)) : 0,\n tilePath,\n tileBaseUrl,\n terms,\n tileUrlBuilder,\n };\n}\n\nexport function toTileUrl(source: Pick<WsiImageSource, \"tilePath\" | \"tileBaseUrl\" | \"tileUrlBuilder\">, tier: number, x: number, y: number): string {\n if (source.tileUrlBuilder) {\n return source.tileUrlBuilder(tier, x, y);\n }\n const normalizedPath = ensureLeadingSlash(source.tilePath);\n return `${source.tileBaseUrl}${normalizedPath}/${tier}/${y}_${x}.webp`;\n}\n","import {\n\ttype CSSProperties,\n\ttype MutableRefObject,\n\ttype PointerEvent as ReactPointerEvent,\n\ttype RefObject,\n\tuseCallback,\n\tuseEffect,\n\tuseMemo,\n\tuseRef,\n} from \"react\";\nimport { toTileUrl } from \"../wsi/image-info\";\nimport type { WsiImageSource, WsiViewState } from \"../wsi/types\";\nimport { clamp } from \"../wsi/utils\";\n\ntype Bounds = [number, number, number, number];\n\nexport interface OverviewMapProjector {\n\tgetViewState: () => WsiViewState;\n\tsetViewState: (next: Partial<WsiViewState>) => void;\n\tsetViewCenter?: (worldX: number, worldY: number) => void;\n\tgetViewBounds?: () => number[];\n\tgetViewCorners?: () => Array<[number, number]>;\n}\n\nexport type OverviewMapPosition =\n\t| \"bottom-right\"\n\t| \"bottom-left\"\n\t| \"top-right\"\n\t| \"top-left\";\n\nexport interface OverviewMapOptions {\n\twidth: number;\n\theight: number;\n\tmargin: number;\n\tposition: OverviewMapPosition;\n\tborderRadius: number;\n\tborderWidth: number;\n\tbackgroundColor: string;\n\tborderColor: string;\n\tviewportStrokeColor: string;\n\tviewportFillColor: string;\n\tinteractive: boolean;\n\tshowThumbnail: boolean;\n\tmaxThumbnailTiles: number;\n}\n\nexport interface OverviewMapProps {\n\tsource: WsiImageSource;\n\tprojectorRef: RefObject<OverviewMapProjector | null>;\n\tauthToken?: string;\n\toptions?: Partial<OverviewMapOptions>;\n\tinvalidateRef?: MutableRefObject<(() => void) | null>;\n\tclassName?: string;\n\tstyle?: CSSProperties;\n}\n\nconst DEFAULT_OVERVIEW_MAP_OPTIONS: OverviewMapOptions = {\n\twidth: 220,\n\theight: 140,\n\tmargin: 16,\n\tposition: \"bottom-right\",\n\tborderRadius: 10,\n\tborderWidth: 1.5,\n\tbackgroundColor: \"rgba(4, 10, 18, 0.88)\",\n\tborderColor: \"rgba(230, 244, 255, 0.35)\",\n\tviewportStrokeColor: \"rgba(255, 106, 61, 0.95)\",\n\tviewportFillColor: \"rgba(255, 106, 61, 0.2)\",\n\tinteractive: true,\n\tshowThumbnail: true,\n\tmaxThumbnailTiles: 16,\n};\n\nfunction toPositiveNumber(\n\tvalue: number | undefined,\n\tfallback: number,\n\tmin = 1,\n): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) return fallback;\n\treturn Math.max(min, value);\n}\n\nfunction isFiniteBounds(bounds: number[] | null | undefined): bounds is Bounds {\n\treturn (\n\t\tArray.isArray(bounds) &&\n\t\tbounds.length === 4 &&\n\t\tNumber.isFinite(bounds[0]) &&\n\t\tNumber.isFinite(bounds[1]) &&\n\t\tNumber.isFinite(bounds[2]) &&\n\t\tNumber.isFinite(bounds[3])\n\t);\n}\n\nexport function OverviewMap({\n\tsource,\n\tprojectorRef,\n\tauthToken = \"\",\n\toptions,\n\tinvalidateRef,\n\tclassName,\n\tstyle,\n}: OverviewMapProps): React.ReactElement {\n\tconst canvasRef = useRef<HTMLCanvasElement | null>(null);\n\tconst thumbnailRef = useRef<HTMLCanvasElement | null>(null);\n\tconst lastBoundsRef = useRef<Bounds | null>(null);\n\tconst draggingRef = useRef<{ active: boolean; pointerId: number | null }>({\n\t\tactive: false,\n\t\tpointerId: null,\n\t});\n\tconst rafRef = useRef<number | null>(null);\n\tconst drawPendingRef = useRef(false);\n\n\tconst width = toPositiveNumber(\n\t\toptions?.width,\n\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.width,\n\t\t64,\n\t);\n\tconst height = toPositiveNumber(\n\t\toptions?.height,\n\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.height,\n\t\t48,\n\t);\n\tconst margin = toPositiveNumber(\n\t\toptions?.margin,\n\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.margin,\n\t\t0,\n\t);\n\tconst borderRadius = toPositiveNumber(\n\t\toptions?.borderRadius,\n\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.borderRadius,\n\t\t0,\n\t);\n\tconst borderWidth = toPositiveNumber(\n\t\toptions?.borderWidth,\n\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.borderWidth,\n\t\t0,\n\t);\n\tconst maxThumbnailTiles = Math.max(\n\t\t1,\n\t\tMath.round(\n\t\t\ttoPositiveNumber(\n\t\t\t\toptions?.maxThumbnailTiles,\n\t\t\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.maxThumbnailTiles,\n\t\t\t\t1,\n\t\t\t),\n\t\t),\n\t);\n\n\tconst backgroundColor =\n\t\toptions?.backgroundColor || DEFAULT_OVERVIEW_MAP_OPTIONS.backgroundColor;\n\tconst borderColor =\n\t\toptions?.borderColor || DEFAULT_OVERVIEW_MAP_OPTIONS.borderColor;\n\tconst viewportStrokeColor =\n\t\toptions?.viewportStrokeColor ||\n\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.viewportStrokeColor;\n\tconst viewportFillColor =\n\t\toptions?.viewportFillColor ||\n\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.viewportFillColor;\n\tconst interactive =\n\t\toptions?.interactive ?? DEFAULT_OVERVIEW_MAP_OPTIONS.interactive;\n\tconst showThumbnail =\n\t\toptions?.showThumbnail ?? DEFAULT_OVERVIEW_MAP_OPTIONS.showThumbnail;\n\tconst position =\n\t\toptions?.position || DEFAULT_OVERVIEW_MAP_OPTIONS.position;\n\n\tconst mergedStyle = useMemo<CSSProperties>(() => {\n\t\tconst pos: CSSProperties = {};\n\t\tif (position === \"top-left\" || position === \"bottom-left\") pos.left = margin;\n\t\telse pos.right = margin;\n\t\tif (position === \"top-left\" || position === \"top-right\") pos.top = margin;\n\t\telse pos.bottom = margin;\n\n\t\treturn {\n\t\t\tposition: \"absolute\",\n\t\t\t...pos,\n\t\t\twidth,\n\t\t\theight,\n\t\t\tborderRadius,\n\t\t\toverflow: \"hidden\",\n\t\t\tzIndex: 4,\n\t\t\tpointerEvents: interactive ? \"auto\" : \"none\",\n\t\t\ttouchAction: \"none\",\n\t\t\tboxShadow: \"0 10px 22px rgba(0, 0, 0, 0.3)\",\n\t\t\t...style,\n\t\t};\n\t}, [margin, position, width, height, borderRadius, interactive, style]);\n\n\tconst draw = useCallback(() => {\n\t\tconst canvas = canvasRef.current;\n\t\tif (!canvas) return;\n\n\t\tconst ctx = canvas.getContext(\"2d\");\n\t\tif (!ctx) return;\n\n\t\tconst cssW = width;\n\t\tconst cssH = height;\n\t\tconst dpr = Math.max(1, window.devicePixelRatio || 1);\n\n\t\tconst pixelW = Math.max(1, Math.round(cssW * dpr));\n\t\tconst pixelH = Math.max(1, Math.round(cssH * dpr));\n\t\tif (canvas.width !== pixelW || canvas.height !== pixelH) {\n\t\t\tcanvas.width = pixelW;\n\t\t\tcanvas.height = pixelH;\n\t\t}\n\n\t\tctx.setTransform(1, 0, 0, 1, 0, 0);\n\t\tctx.clearRect(0, 0, canvas.width, canvas.height);\n\t\tctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n\n\t\tctx.fillStyle = backgroundColor;\n\t\tctx.fillRect(0, 0, cssW, cssH);\n\n\t\tconst preview = thumbnailRef.current;\n\t\tif (preview) {\n\t\t\tctx.drawImage(preview, 0, 0, cssW, cssH);\n\t\t}\n\n\t\tctx.strokeStyle = borderColor;\n\t\tctx.lineWidth = borderWidth;\n\t\tctx.strokeRect(\n\t\t\tborderWidth * 0.5,\n\t\t\tborderWidth * 0.5,\n\t\t\tcssW - borderWidth,\n\t\t\tcssH - borderWidth,\n\t\t);\n\n\t\tconst projector = projectorRef.current;\n\t\tconst bounds = projector?.getViewBounds?.();\n\t\tconst corners = projector?.getViewCorners?.();\n\t\tconst safeBounds = isFiniteBounds(bounds)\n\t\t\t? bounds\n\t\t\t: isFiniteBounds(lastBoundsRef.current)\n\t\t\t\t? lastBoundsRef.current\n\t\t\t\t: null;\n\t\tif (!safeBounds) return;\n\t\tlastBoundsRef.current = safeBounds;\n\n\t\tconst sx = cssW / Math.max(1, source.width);\n\t\tconst sy = cssH / Math.max(1, source.height);\n\n\t\tconst safeCorners =\n\t\t\tArray.isArray(corners) &&\n\t\t\tcorners.length >= 4 &&\n\t\t\tcorners.every(\n\t\t\t\t(point) =>\n\t\t\t\t\tArray.isArray(point) &&\n\t\t\t\t\tpoint.length >= 2 &&\n\t\t\t\t\tNumber.isFinite(point[0]) &&\n\t\t\t\t\tNumber.isFinite(point[1]),\n\t\t\t)\n\t\t\t\t? (corners as Array<[number, number]>)\n\t\t\t\t: null;\n\n\t\tif (safeCorners) {\n\t\t\tctx.beginPath();\n\t\t\tfor (let i = 0; i < safeCorners.length; i += 1) {\n\t\t\t\tconst point = safeCorners[i];\n\t\t\t\tconst x = clamp(point[0] * sx, 0, cssW);\n\t\t\t\tconst y = clamp(point[1] * sy, 0, cssH);\n\t\t\t\tif (i === 0) ctx.moveTo(x, y);\n\t\t\t\telse ctx.lineTo(x, y);\n\t\t\t}\n\t\t\tctx.closePath();\n\t\t\tctx.fillStyle = viewportFillColor;\n\t\t\tctx.fill();\n\t\t\tctx.strokeStyle = viewportStrokeColor;\n\t\t\tctx.lineWidth = 1.5;\n\t\t\tctx.stroke();\n\t\t\treturn;\n\t\t}\n\n\t\tconst left = clamp(safeBounds[0] * sx, 0, cssW);\n\t\tconst top = clamp(safeBounds[1] * sy, 0, cssH);\n\t\tconst right = clamp(safeBounds[2] * sx, 0, cssW);\n\t\tconst bottom = clamp(safeBounds[3] * sy, 0, cssH);\n\t\tconst rectW = Math.max(1, right - left);\n\t\tconst rectH = Math.max(1, bottom - top);\n\n\t\tctx.fillStyle = viewportFillColor;\n\t\tctx.fillRect(left, top, rectW, rectH);\n\n\t\tctx.strokeStyle = viewportStrokeColor;\n\t\tctx.lineWidth = 1.5;\n\t\tctx.strokeRect(\n\t\t\tleft + 0.5,\n\t\t\ttop + 0.5,\n\t\t\tMath.max(1, rectW - 1),\n\t\t\tMath.max(1, rectH - 1),\n\t\t);\n\t}, [\n\t\twidth,\n\t\theight,\n\t\tbackgroundColor,\n\t\tborderColor,\n\t\tborderWidth,\n\t\tprojectorRef,\n\t\tsource.width,\n\t\tsource.height,\n\t\tviewportFillColor,\n\t\tviewportStrokeColor,\n\t]);\n\n\tconst requestDraw = useCallback(() => {\n\t\tif (drawPendingRef.current) return;\n\t\tdrawPendingRef.current = true;\n\t\trafRef.current = requestAnimationFrame(() => {\n\t\t\tdrawPendingRef.current = false;\n\t\t\trafRef.current = null;\n\t\t\tdraw();\n\t\t});\n\t}, [draw]);\n\n\tconst toWorldFromClient = useCallback(\n\t\t(clientX: number, clientY: number): [number, number] | null => {\n\t\t\tconst canvas = canvasRef.current;\n\t\t\tif (!canvas) return null;\n\n\t\t\tconst rect = canvas.getBoundingClientRect();\n\t\t\tif (!rect.width || !rect.height) return null;\n\n\t\t\tconst nx = clamp((clientX - rect.left) / rect.width, 0, 1);\n\t\t\tconst ny = clamp((clientY - rect.top) / rect.height, 0, 1);\n\t\t\treturn [nx * source.width, ny * source.height];\n\t\t},\n\t\t[source.width, source.height],\n\t);\n\n\tconst recenterTo = useCallback(\n\t\t(worldX: number, worldY: number) => {\n\t\t\tconst projector = projectorRef.current;\n\t\t\tif (!projector) return;\n\n\t\t\tif (projector.setViewCenter) {\n\t\t\t\tprojector.setViewCenter(worldX, worldY);\n\t\t\t\trequestDraw();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst bounds = projector.getViewBounds?.();\n\t\t\tconst safeBounds = isFiniteBounds(bounds)\n\t\t\t\t? bounds\n\t\t\t\t: isFiniteBounds(lastBoundsRef.current)\n\t\t\t\t\t? lastBoundsRef.current\n\t\t\t\t\t: null;\n\t\t\tif (!safeBounds) return;\n\n\t\t\tconst visibleW = Math.max(1e-6, safeBounds[2] - safeBounds[0]);\n\t\t\tconst visibleH = Math.max(1e-6, safeBounds[3] - safeBounds[1]);\n\n\t\t\tprojector.setViewState({\n\t\t\t\toffsetX: worldX - visibleW * 0.5,\n\t\t\t\toffsetY: worldY - visibleH * 0.5,\n\t\t\t});\n\t\t\trequestDraw();\n\t\t},\n\t\t[projectorRef, requestDraw],\n\t);\n\n\tconst handlePointerDown = useCallback(\n\t\t(event: ReactPointerEvent<HTMLCanvasElement>) => {\n\t\t\tif (!interactive) return;\n\t\t\tif (event.button !== 0) return;\n\n\t\t\tconst canvas = canvasRef.current;\n\t\t\tif (!canvas) return;\n\n\t\t\tconst world = toWorldFromClient(event.clientX, event.clientY);\n\t\t\tif (!world) return;\n\n\t\t\tevent.preventDefault();\n\t\t\tevent.stopPropagation();\n\n\t\t\tcanvas.setPointerCapture(event.pointerId);\n\t\t\tdraggingRef.current = { active: true, pointerId: event.pointerId };\n\t\t\trecenterTo(world[0], world[1]);\n\t\t},\n\t\t[interactive, toWorldFromClient, recenterTo],\n\t);\n\n\tconst handlePointerMove = useCallback(\n\t\t(event: ReactPointerEvent<HTMLCanvasElement>) => {\n\t\t\tconst drag = draggingRef.current;\n\t\t\tif (!drag.active || drag.pointerId !== event.pointerId) return;\n\n\t\t\tconst world = toWorldFromClient(event.clientX, event.clientY);\n\t\t\tif (!world) return;\n\n\t\t\tevent.preventDefault();\n\t\t\tevent.stopPropagation();\n\t\t\trecenterTo(world[0], world[1]);\n\t\t},\n\t\t[toWorldFromClient, recenterTo],\n\t);\n\n\tconst handlePointerUp = useCallback(\n\t\t(event: ReactPointerEvent<HTMLCanvasElement>) => {\n\t\t\tconst drag = draggingRef.current;\n\t\t\tif (!drag.active || drag.pointerId !== event.pointerId) return;\n\n\t\t\tconst canvas = canvasRef.current;\n\t\t\tif (canvas && canvas.hasPointerCapture(event.pointerId)) {\n\t\t\t\ttry {\n\t\t\t\t\tcanvas.releasePointerCapture(event.pointerId);\n\t\t\t\t} catch {\n\t\t\t\t\t// noop\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdraggingRef.current = { active: false, pointerId: null };\n\t\t\trequestDraw();\n\t\t},\n\t\t[requestDraw],\n\t);\n\n\tuseEffect(() => {\n\t\tlet cancelled = false;\n\t\tthumbnailRef.current = null;\n\t\trequestDraw();\n\n\t\tconst tier = 0;\n\t\tconst levelScale = 2 ** (source.maxTierZoom - tier);\n\t\tconst levelWidth = Math.ceil(source.width / levelScale);\n\t\tconst levelHeight = Math.ceil(source.height / levelScale);\n\t\tconst tilesX = Math.max(1, Math.ceil(levelWidth / source.tileSize));\n\t\tconst tilesY = Math.max(1, Math.ceil(levelHeight / source.tileSize));\n\t\tconst tileCount = tilesX * tilesY;\n\n\t\tif (!showThumbnail || tileCount > maxThumbnailTiles) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst preview = document.createElement(\"canvas\");\n\t\tpreview.width = Math.max(1, Math.round(width));\n\t\tpreview.height = Math.max(1, Math.round(height));\n\t\tconst ctx = preview.getContext(\"2d\");\n\t\tif (!ctx) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tctx.fillStyle = backgroundColor;\n\t\tctx.fillRect(0, 0, preview.width, preview.height);\n\n\t\tconst requests: Array<{\n\t\t\turl: string;\n\t\t\tbounds: Bounds;\n\t\t}> = [];\n\n\t\tfor (let y = 0; y < tilesY; y += 1) {\n\t\t\tfor (let x = 0; x < tilesX; x += 1) {\n\t\t\t\tconst left = x * source.tileSize * levelScale;\n\t\t\t\tconst top = y * source.tileSize * levelScale;\n\t\t\t\tconst right =\n\t\t\t\t\tMath.min((x + 1) * source.tileSize, levelWidth) * levelScale;\n\t\t\t\tconst bottom =\n\t\t\t\t\tMath.min((y + 1) * source.tileSize, levelHeight) * levelScale;\n\t\t\t\trequests.push({\n\t\t\t\t\turl: toTileUrl(source, tier, x, y),\n\t\t\t\t\tbounds: [left, top, right, bottom],\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tvoid Promise.allSettled(\n\t\t\trequests.map(async (tile) => {\n\t\t\t\tconst useAuthHeader = !!authToken;\n\t\t\t\tconst response = await fetch(tile.url, {\n\t\t\t\t\theaders: useAuthHeader ? { Authorization: authToken } : undefined,\n\t\t\t\t});\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new Error(`HTTP ${response.status}`);\n\t\t\t\t}\n\t\t\t\tconst bitmap = await createImageBitmap(await response.blob());\n\t\t\t\treturn { tile, bitmap };\n\t\t\t}),\n\t\t).then((results) => {\n\t\t\tif (cancelled) {\n\t\t\t\tfor (const result of results) {\n\t\t\t\t\tif (result.status === \"fulfilled\") {\n\t\t\t\t\t\tresult.value.bitmap.close();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst sx = preview.width / Math.max(1, source.width);\n\t\t\tconst sy = preview.height / Math.max(1, source.height);\n\t\t\tfor (const result of results) {\n\t\t\t\tif (result.status !== \"fulfilled\") continue;\n\t\t\t\tconst {\n\t\t\t\t\ttile: { bounds },\n\t\t\t\t\tbitmap,\n\t\t\t\t} = result.value;\n\t\t\t\tconst dx = bounds[0] * sx;\n\t\t\t\tconst dy = bounds[1] * sy;\n\t\t\t\tconst dw = Math.max(1, (bounds[2] - bounds[0]) * sx);\n\t\t\t\tconst dh = Math.max(1, (bounds[3] - bounds[1]) * sy);\n\t\t\t\tctx.drawImage(bitmap, dx, dy, dw, dh);\n\t\t\t\tbitmap.close();\n\t\t\t}\n\n\t\t\tthumbnailRef.current = preview;\n\t\t\trequestDraw();\n\t\t});\n\n\t\treturn () => {\n\t\t\tcancelled = true;\n\t\t};\n\t}, [\n\t\tsource,\n\t\tauthToken,\n\t\twidth,\n\t\theight,\n\t\tbackgroundColor,\n\t\tshowThumbnail,\n\t\tmaxThumbnailTiles,\n\t\trequestDraw,\n\t]);\n\n\tuseEffect(() => {\n\t\trequestDraw();\n\t}, [requestDraw]);\n\n\tuseEffect(() => {\n\t\tif (!invalidateRef) return undefined;\n\t\tinvalidateRef.current = requestDraw;\n\t\treturn () => {\n\t\t\tif (invalidateRef.current === requestDraw) {\n\t\t\t\tinvalidateRef.current = null;\n\t\t\t}\n\t\t};\n\t}, [invalidateRef, requestDraw]);\n\n\tuseEffect(\n\t\t() => () => {\n\t\t\tdraggingRef.current = { active: false, pointerId: null };\n\t\t\tif (rafRef.current !== null) {\n\t\t\t\tcancelAnimationFrame(rafRef.current);\n\t\t\t\trafRef.current = null;\n\t\t\t}\n\t\t\tdrawPendingRef.current = false;\n\t\t},\n\t\t[],\n\t);\n\n\treturn (\n\t\t<canvas\n\t\t\tref={canvasRef}\n\t\t\tclassName={className}\n\t\t\tstyle={mergedStyle}\n\t\t\tonPointerDown={handlePointerDown}\n\t\t\tonPointerMove={handlePointerMove}\n\t\t\tonPointerUp={handlePointerUp}\n\t\t\tonPointerCancel={handlePointerUp}\n\t\t\tonContextMenu={(event) => {\n\t\t\t\tevent.preventDefault();\n\t\t\t}}\n\t\t\tonWheel={(event) => {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tevent.stopPropagation();\n\t\t\t}}\n\t\t/>\n\t);\n}\n","import { type CSSProperties, useEffect, useMemo, useRef } from \"react\";\nimport { M1TileRenderer } from \"../core/m1-tile-renderer\";\nimport type { ViewState } from \"../core/ortho-camera\";\nimport type { TileDefinition } from \"../core/types\";\n\nexport interface TileViewerCanvasProps {\n\timageWidth: number;\n\timageHeight: number;\n\ttiles: TileDefinition[];\n\tviewState?: Partial<ViewState>;\n\tclassName?: string;\n\tstyle?: CSSProperties;\n}\n\nexport function TileViewerCanvas({\n\timageWidth,\n\timageHeight,\n\ttiles,\n\tviewState,\n\tclassName,\n\tstyle,\n}: TileViewerCanvasProps): React.ReactElement {\n\tconst canvasRef = useRef<HTMLCanvasElement | null>(null);\n\tconst rendererRef = useRef<M1TileRenderer | null>(null);\n\tconst mergedStyle = useMemo(\n\t\t() => ({ width: \"100%\", height: \"100%\", display: \"block\", ...style }),\n\t\t[style],\n\t);\n\n\tuseEffect(() => {\n\t\tconst canvas = canvasRef.current;\n\t\tif (!canvas) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst renderer = new M1TileRenderer({\n\t\t\tcanvas,\n\t\t\timageWidth,\n\t\t\timageHeight,\n\t\t\tinitialViewState: viewState,\n\t\t});\n\n\t\trendererRef.current = renderer;\n\t\tvoid renderer.setTiles(tiles);\n\n\t\treturn () => {\n\t\t\trenderer.destroy();\n\t\t\trendererRef.current = null;\n\t\t};\n\t}, [imageWidth, imageHeight]);\n\n\tuseEffect(() => {\n\t\tconst renderer = rendererRef.current;\n\t\tif (!renderer) {\n\t\t\treturn;\n\t\t}\n\n\t\tvoid renderer.setTiles(tiles);\n\t}, [tiles]);\n\n\tuseEffect(() => {\n\t\tconst renderer = rendererRef.current;\n\t\tif (!renderer || !viewState) {\n\t\t\treturn;\n\t\t}\n\n\t\trenderer.setViewState(viewState);\n\t}, [viewState]);\n\n\treturn <canvas ref={canvasRef} className={className} style={mergedStyle} />;\n}\n","import type { WsiPointData } from \"./types\";\n\nexport type RoiCoordinate = [number, number];\nexport type RoiPolygon = RoiCoordinate[];\n\ninterface PreparedPolygon {\n\tring: RoiPolygon;\n\tminX: number;\n\tminY: number;\n\tmaxX: number;\n\tmaxY: number;\n}\n\nfunction closeRing(coords: RoiPolygon): RoiPolygon {\n\tif (!Array.isArray(coords) || coords.length < 3) return [];\n\tconst out = coords.map(([x, y]) => [x, y] as RoiCoordinate);\n\tconst first = out[0];\n\tconst last = out[out.length - 1];\n\tif (!first || !last) return [];\n\tif (first[0] !== last[0] || first[1] !== last[1]) {\n\t\tout.push([first[0], first[1]]);\n\t}\n\treturn out;\n}\n\nfunction preparePolygons(polygons: RoiPolygon[]): PreparedPolygon[] {\n\tconst prepared: PreparedPolygon[] = [];\n\tfor (const poly of polygons ?? []) {\n\t\tconst ring = closeRing(poly);\n\t\tif (ring.length < 4) continue;\n\t\tlet minX = Infinity;\n\t\tlet minY = Infinity;\n\t\tlet maxX = -Infinity;\n\t\tlet maxY = -Infinity;\n\t\tfor (const [x, y] of ring) {\n\t\t\tif (x < minX) minX = x;\n\t\t\tif (x > maxX) maxX = x;\n\t\t\tif (y < minY) minY = y;\n\t\t\tif (y > maxY) maxY = y;\n\t\t}\n\t\tif (!Number.isFinite(minX) || !Number.isFinite(minY)) continue;\n\t\tprepared.push({ ring, minX, minY, maxX, maxY });\n\t}\n\treturn prepared;\n}\n\nfunction isInsideRing(x: number, y: number, ring: RoiPolygon): boolean {\n\tlet inside = false;\n\tfor (let i = 0, j = ring.length - 1; i < ring.length; j = i, i += 1) {\n\t\tconst xi = ring[i][0];\n\t\tconst yi = ring[i][1];\n\t\tconst xj = ring[j][0];\n\t\tconst yj = ring[j][1];\n\t\tconst intersect =\n\t\t\tyi > y !== yj > y &&\n\t\t\tx < ((xj - xi) * (y - yi)) / ((yj - yi) || Number.EPSILON) + xi;\n\t\tif (intersect) inside = !inside;\n\t}\n\treturn inside;\n}\n\nfunction isInsideAnyPolygon(\n\tx: number,\n\ty: number,\n\tpolygons: PreparedPolygon[],\n): boolean {\n\tfor (const poly of polygons) {\n\t\tif (x < poly.minX || x > poly.maxX || y < poly.minY || y > poly.maxY) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (isInsideRing(x, y, poly.ring)) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\nexport function filterPointDataByPolygons(\n\tpointData: WsiPointData | null | undefined,\n\tpolygons: RoiPolygon[] | null | undefined,\n): WsiPointData | null {\n\tif (!pointData || !pointData.count || !pointData.positions || !pointData.paletteIndices) {\n\t\treturn null;\n\t}\n\n\tconst prepared = preparePolygons(polygons ?? []);\n\tif (prepared.length === 0) {\n\t\treturn {\n\t\t\tcount: 0,\n\t\t\tpositions: new Float32Array(0),\n\t\t\tpaletteIndices: new Uint16Array(0),\n\t\t};\n\t}\n\n\tconst count = pointData.count;\n\tconst positions = pointData.positions;\n\tconst terms = pointData.paletteIndices;\n\n\tconst nextPositions = new Float32Array(count * 2);\n\tconst nextTerms = new Uint16Array(count);\n\tlet cursor = 0;\n\n\tfor (let i = 0; i < count; i += 1) {\n\t\tconst x = positions[i * 2];\n\t\tconst y = positions[i * 2 + 1];\n\t\tif (!isInsideAnyPolygon(x, y, prepared)) continue;\n\t\tnextPositions[cursor * 2] = x;\n\t\tnextPositions[cursor * 2 + 1] = y;\n\t\tnextTerms[cursor] = terms[i];\n\t\tcursor += 1;\n\t}\n\n\treturn {\n\t\tcount: cursor,\n\t\tpositions: nextPositions.subarray(0, cursor * 2),\n\t\tpaletteIndices: nextTerms.subarray(0, cursor),\n\t};\n}\n","export interface WebGpuCapabilities {\n\tsupported: boolean;\n\tadapterName?: string;\n\tfeatures: string[];\n\tlimits?: {\n\t\tmaxStorageBufferBindingSize: number;\n\t\tmaxComputeInvocationsPerWorkgroup: number;\n\t\tmaxComputeWorkgroupSizeX: number;\n\t};\n}\n\ninterface NavigatorGpuLike {\n\trequestAdapter: () => Promise<GpuAdapterLike | null>;\n}\n\ninterface GpuAdapterLike {\n\tinfo?: {\n\t\tdescription?: string;\n\t\tvendor?: string;\n\t};\n\tfeatures: Iterable<string>;\n\tlimits: {\n\t\tmaxStorageBufferBindingSize: number;\n\t\tmaxComputeInvocationsPerWorkgroup: number;\n\t\tmaxComputeWorkgroupSizeX: number;\n\t};\n\trequestDevice: () => Promise<GpuDeviceLike>;\n}\n\ninterface GpuBufferLike {\n\tdestroy: () => void;\n\tmapAsync: (mode: number) => Promise<void>;\n\tgetMappedRange: () => ArrayBuffer;\n\tunmap: () => void;\n}\n\ninterface GpuComputePassLike {\n\tsetPipeline: (pipeline: GpuComputePipelineLike) => void;\n\tsetBindGroup: (index: number, bindGroup: unknown) => void;\n\tdispatchWorkgroups: (x: number, y?: number, z?: number) => void;\n\tend: () => void;\n}\n\ninterface GpuCommandEncoderLike {\n\tbeginComputePass: () => GpuComputePassLike;\n\tcopyBufferToBuffer: (\n\t\tsource: GpuBufferLike,\n\t\tsourceOffset: number,\n\t\tdestination: GpuBufferLike,\n\t\tdestinationOffset: number,\n\t\tsize: number,\n\t) => void;\n\tfinish: () => unknown;\n}\n\ninterface GpuQueueLike {\n\twriteBuffer: (\n\t\tbuffer: GpuBufferLike,\n\t\tbufferOffset: number,\n\t\tdata: ArrayBufferView | ArrayBufferLike,\n\t\tdataOffset?: number,\n\t\tsize?: number,\n\t) => void;\n\tsubmit: (commands: unknown[]) => void;\n}\n\ninterface GpuComputePipelineLike {\n\treadonly _brand?: \"GpuComputePipelineLike\";\n}\n\ninterface GpuBindGroupLayoutLike {\n\treadonly _brand?: \"GpuBindGroupLayoutLike\";\n}\n\ninterface GpuDeviceLike {\n\tlimits: {\n\t\tmaxStorageBufferBindingSize: number;\n\t};\n\tqueue: GpuQueueLike;\n\tcreateBindGroupLayout: (descriptor: unknown) => GpuBindGroupLayoutLike;\n\tcreatePipelineLayout: (descriptor: unknown) => unknown;\n\tcreateShaderModule: (descriptor: { code: string }) => unknown;\n\tcreateComputePipeline: (descriptor: unknown) => GpuComputePipelineLike;\n\tcreateBuffer: (descriptor: { size: number; usage: number }) => GpuBufferLike;\n\tcreateBindGroup: (descriptor: unknown) => unknown;\n\tcreateCommandEncoder: () => GpuCommandEncoderLike;\n}\n\ninterface WebGpuContext {\n\tdevice: GpuDeviceLike;\n\tpipeline: GpuComputePipelineLike;\n\tbindGroupLayout: GpuBindGroupLayoutLike;\n}\n\nlet contextPromise: Promise<WebGpuContext | null> | null = null;\n\nconst BBOX_PREFILTER_SHADER = `\nstruct Params {\n pointCount: u32,\n boundsCount: u32,\n _pad0: u32,\n _pad1: u32,\n};\n\n@group(0) @binding(0) var<storage, read> positions: array<vec2<f32>>;\n@group(0) @binding(1) var<storage, read> bounds: array<vec4<f32>>;\n@group(0) @binding(2) var<storage, read_write> outputMask: array<u32>;\n@group(0) @binding(3) var<uniform> params: Params;\n\n@compute @workgroup_size(256)\nfn main(@builtin(global_invocation_id) gid: vec3<u32>) {\n let i = gid.x;\n if (i >= params.pointCount) {\n return;\n }\n\n let p = positions[i];\n var inside: u32 = 0u;\n for (var bi: u32 = 0u; bi < params.boundsCount; bi = bi + 1u) {\n let b = bounds[bi];\n if (p.x >= b.x && p.x <= b.z && p.y >= b.y && p.y <= b.w) {\n inside = 1u;\n break;\n }\n }\n outputMask[i] = inside;\n}\n`;\n\nfunction hasWebGpu(): boolean {\n\tif (typeof navigator === \"undefined\") return false;\n\tconst nav = navigator as Navigator & { gpu?: unknown };\n\treturn typeof nav.gpu === \"object\" && nav.gpu !== null;\n}\n\nfunction getNavigatorGpu(): NavigatorGpuLike | null {\n\tif (!hasWebGpu()) return null;\n\tconst nav = navigator as Navigator & { gpu?: unknown };\n\tconst gpu = nav.gpu;\n\tif (!gpu || typeof gpu !== \"object\") return null;\n\tconst candidate = gpu as Partial<NavigatorGpuLike>;\n\tif (typeof candidate.requestAdapter !== \"function\") return null;\n\treturn candidate as NavigatorGpuLike;\n}\n\nconst GPU_SHADER_STAGE_COMPUTE =\n\t(globalThis as { GPUShaderStage?: { COMPUTE?: number } }).GPUShaderStage\n\t\t?.COMPUTE ?? 0x4;\nconst GPU_BUFFER_USAGE_STORAGE =\n\t(globalThis as { GPUBufferUsage?: { STORAGE?: number } }).GPUBufferUsage\n\t\t?.STORAGE ?? 0x80;\nconst GPU_BUFFER_USAGE_COPY_DST =\n\t(globalThis as { GPUBufferUsage?: { COPY_DST?: number } }).GPUBufferUsage\n\t\t?.COPY_DST ?? 0x08;\nconst GPU_BUFFER_USAGE_COPY_SRC =\n\t(globalThis as { GPUBufferUsage?: { COPY_SRC?: number } }).GPUBufferUsage\n\t\t?.COPY_SRC ?? 0x04;\nconst GPU_BUFFER_USAGE_UNIFORM =\n\t(globalThis as { GPUBufferUsage?: { UNIFORM?: number } }).GPUBufferUsage\n\t\t?.UNIFORM ?? 0x40;\nconst GPU_BUFFER_USAGE_MAP_READ =\n\t(globalThis as { GPUBufferUsage?: { MAP_READ?: number } }).GPUBufferUsage\n\t\t?.MAP_READ ?? 0x01;\nconst GPU_MAP_MODE_READ =\n\t(globalThis as { GPUMapMode?: { READ?: number } }).GPUMapMode?.READ ?? 0x01;\n\nexport async function getWebGpuCapabilities(): Promise<WebGpuCapabilities> {\n\tconst navGpu = getNavigatorGpu();\n\tif (!navGpu) {\n\t\treturn { supported: false, features: [] };\n\t}\n\tconst adapter = await navGpu.requestAdapter();\n\tif (!adapter) {\n\t\treturn { supported: false, features: [] };\n\t}\n\n\treturn {\n\t\tsupported: true,\n\t\tadapterName: adapter.info?.description ?? adapter.info?.vendor ?? \"unknown\",\n\t\tfeatures: Array.from(adapter.features),\n\t\tlimits: {\n\t\t\tmaxStorageBufferBindingSize: Number(\n\t\t\t\tadapter.limits.maxStorageBufferBindingSize,\n\t\t\t),\n\t\t\tmaxComputeInvocationsPerWorkgroup: Number(\n\t\t\t\tadapter.limits.maxComputeInvocationsPerWorkgroup,\n\t\t\t),\n\t\t\tmaxComputeWorkgroupSizeX: Number(adapter.limits.maxComputeWorkgroupSizeX),\n\t\t},\n\t};\n}\n\nasync function getContext(): Promise<WebGpuContext | null> {\n\tif (contextPromise) return contextPromise;\n\tcontextPromise = (async () => {\n\t\tconst navGpu = getNavigatorGpu();\n\t\tif (!navGpu) return null;\n\t\tconst adapter = await navGpu.requestAdapter();\n\t\tif (!adapter) return null;\n\t\tconst device = await adapter.requestDevice();\n\n\t\tconst bindGroupLayout = device.createBindGroupLayout({\n\t\t\tentries: [\n\t\t\t\t{\n\t\t\t\t\tbinding: 0,\n\t\t\t\t\tvisibility: GPU_SHADER_STAGE_COMPUTE,\n\t\t\t\t\tbuffer: { type: \"read-only-storage\" },\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tbinding: 1,\n\t\t\t\t\tvisibility: GPU_SHADER_STAGE_COMPUTE,\n\t\t\t\t\tbuffer: { type: \"read-only-storage\" },\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tbinding: 2,\n\t\t\t\t\tvisibility: GPU_SHADER_STAGE_COMPUTE,\n\t\t\t\t\tbuffer: { type: \"storage\" },\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tbinding: 3,\n\t\t\t\t\tvisibility: GPU_SHADER_STAGE_COMPUTE,\n\t\t\t\t\tbuffer: { type: \"uniform\" },\n\t\t\t\t},\n\t\t\t],\n\t\t});\n\n\t\tconst pipeline = device.createComputePipeline({\n\t\t\tlayout: device.createPipelineLayout({ bindGroupLayouts: [bindGroupLayout] }),\n\t\t\tcompute: {\n\t\t\t\tmodule: device.createShaderModule({ code: BBOX_PREFILTER_SHADER }),\n\t\t\t\tentryPoint: \"main\",\n\t\t\t},\n\t\t});\n\n\t\treturn { device, pipeline, bindGroupLayout };\n\t})();\n\n\treturn contextPromise;\n}\n\nfunction align(value: number, step: number): number {\n\treturn Math.ceil(value / step) * step;\n}\n\nexport async function prefilterPointsByBoundsWebGpu(\n\tpositions: Float32Array,\n\tpointCount: number,\n\tbounds: Float32Array,\n): Promise<Uint32Array | null> {\n\tconst ctx = await getContext();\n\tif (!ctx) return null;\n\n\tconst count = Math.max(0, Math.floor(pointCount));\n\tconst boundsCount = Math.max(0, Math.floor(bounds.length / 4));\n\tif (count === 0 || boundsCount === 0) {\n\t\treturn new Uint32Array(0);\n\t}\n\n\tconst safePointCount = Math.min(count, Math.floor(positions.length / 2));\n\tif (safePointCount === 0) {\n\t\treturn new Uint32Array(0);\n\t}\n\n\tconst positionBytes = safePointCount * 2 * Float32Array.BYTES_PER_ELEMENT;\n\tconst boundsBytes = boundsCount * 4 * Float32Array.BYTES_PER_ELEMENT;\n\tconst outputBytes = safePointCount * Uint32Array.BYTES_PER_ELEMENT;\n\n\tconst limit = Number(ctx.device.limits.maxStorageBufferBindingSize);\n\tif (positionBytes > limit || boundsBytes > limit || outputBytes > limit) {\n\t\treturn null;\n\t}\n\n\tconst positionsBuffer = ctx.device.createBuffer({\n\t\tsize: align(positionBytes, 4),\n\t\tusage: GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST,\n\t});\n\tconst boundsBuffer = ctx.device.createBuffer({\n\t\tsize: align(boundsBytes, 4),\n\t\tusage: GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST,\n\t});\n\tconst outputBuffer = ctx.device.createBuffer({\n\t\tsize: align(outputBytes, 4),\n\t\tusage: GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_SRC,\n\t});\n\tconst uniformBuffer = ctx.device.createBuffer({\n\t\tsize: 16,\n\t\tusage: GPU_BUFFER_USAGE_UNIFORM | GPU_BUFFER_USAGE_COPY_DST,\n\t});\n\tconst readBuffer = ctx.device.createBuffer({\n\t\tsize: align(outputBytes, 4),\n\t\tusage: GPU_BUFFER_USAGE_COPY_DST | GPU_BUFFER_USAGE_MAP_READ,\n\t});\n\n\tctx.device.queue.writeBuffer(\n\t\tpositionsBuffer,\n\t\t0,\n\t\tpositions.buffer,\n\t\tpositions.byteOffset,\n\t\tpositionBytes,\n\t);\n\tctx.device.queue.writeBuffer(\n\t\tboundsBuffer,\n\t\t0,\n\t\tbounds.buffer,\n\t\tbounds.byteOffset,\n\t\tboundsBytes,\n\t);\n\tctx.device.queue.writeBuffer(\n\t\tuniformBuffer,\n\t\t0,\n\t\tnew Uint32Array([safePointCount, boundsCount, 0, 0]),\n\t);\n\n\tconst bindGroup = ctx.device.createBindGroup({\n\t\tlayout: ctx.bindGroupLayout,\n\t\tentries: [\n\t\t\t{ binding: 0, resource: { buffer: positionsBuffer } },\n\t\t\t{ binding: 1, resource: { buffer: boundsBuffer } },\n\t\t\t{ binding: 2, resource: { buffer: outputBuffer } },\n\t\t\t{ binding: 3, resource: { buffer: uniformBuffer } },\n\t\t],\n\t});\n\n\tconst commandEncoder = ctx.device.createCommandEncoder();\n\tconst pass = commandEncoder.beginComputePass();\n\tpass.setPipeline(ctx.pipeline);\n\tpass.setBindGroup(0, bindGroup);\n\tpass.dispatchWorkgroups(Math.ceil(safePointCount / 256));\n\tpass.end();\n\n\tcommandEncoder.copyBufferToBuffer(outputBuffer, 0, readBuffer, 0, outputBytes);\n\tctx.device.queue.submit([commandEncoder.finish()]);\n\n\tawait readBuffer.mapAsync(GPU_MAP_MODE_READ);\n\tconst mapped = readBuffer.getMappedRange();\n\tconst out = new Uint32Array(mapped.slice(0));\n\treadBuffer.unmap();\n\n\tpositionsBuffer.destroy();\n\tboundsBuffer.destroy();\n\toutputBuffer.destroy();\n\tuniformBuffer.destroy();\n\treadBuffer.destroy();\n\n\treturn out;\n}\n","import { filterPointDataByPolygons, type RoiPolygon } from \"./point-clip\";\nimport type { WsiPointData } from \"./types\";\nimport { prefilterPointsByBoundsWebGpu } from \"./webgpu\";\n\ninterface PreparedPolygon {\n ring: RoiPolygon;\n minX: number;\n minY: number;\n maxX: number;\n maxY: number;\n}\n\nexport interface HybridPointClipOptions {\n bridgeToDraw?: boolean;\n}\n\nexport interface HybridPointClipResult {\n data: WsiPointData | null;\n meta: {\n mode: \"hybrid-webgpu\";\n durationMs: number;\n usedWebGpu: boolean;\n candidateCount: number;\n bridgedToDraw?: boolean;\n };\n}\n\nfunction nowMs(): number {\n if (typeof performance !== \"undefined\" && typeof performance.now === \"function\") {\n return performance.now();\n }\n return Date.now();\n}\n\nfunction closeRing(coords: RoiPolygon): RoiPolygon {\n if (!Array.isArray(coords) || coords.length < 3) return [];\n const out = coords.map(([x, y]) => [x, y] as [number, number]);\n const first = out[0];\n const last = out[out.length - 1];\n if (!first || !last) return [];\n if (first[0] !== last[0] || first[1] !== last[1]) {\n out.push([first[0], first[1]]);\n }\n return out;\n}\n\nfunction preparePolygons(polygons: RoiPolygon[]): PreparedPolygon[] {\n const prepared: PreparedPolygon[] = [];\n for (const poly of polygons ?? []) {\n const ring = closeRing(poly);\n if (ring.length < 4) continue;\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const [x, y] of ring) {\n if (x < minX) minX = x;\n if (x > maxX) maxX = x;\n if (y < minY) minY = y;\n if (y > maxY) maxY = y;\n }\n if (!Number.isFinite(minX) || !Number.isFinite(minY)) continue;\n prepared.push({ ring, minX, minY, maxX, maxY });\n }\n return prepared;\n}\n\nfunction isInsideRing(x: number, y: number, ring: RoiPolygon): boolean {\n let inside = false;\n for (let i = 0, j = ring.length - 1; i < ring.length; j = i, i += 1) {\n const xi = ring[i][0];\n const yi = ring[i][1];\n const xj = ring[j][0];\n const yj = ring[j][1];\n const intersect = yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi || Number.EPSILON) + xi;\n if (intersect) inside = !inside;\n }\n return inside;\n}\n\nfunction isInsideAnyPolygon(x: number, y: number, polygons: PreparedPolygon[]): boolean {\n for (const poly of polygons) {\n if (x < poly.minX || x > poly.maxX || y < poly.minY || y > poly.maxY) {\n continue;\n }\n if (isInsideRing(x, y, poly.ring)) {\n return true;\n }\n }\n return false;\n}\n\nexport async function filterPointDataByPolygonsHybrid(\n pointData: WsiPointData | null | undefined,\n polygons: RoiPolygon[] | null | undefined,\n options: HybridPointClipOptions = {}\n): Promise<HybridPointClipResult> {\n const start = nowMs();\n const bridgeToDraw = options.bridgeToDraw === true;\n if (!pointData || !pointData.count || !pointData.positions || !pointData.paletteIndices) {\n return {\n data: null,\n meta: {\n mode: \"hybrid-webgpu\",\n durationMs: nowMs() - start,\n usedWebGpu: false,\n candidateCount: 0,\n bridgedToDraw: false,\n },\n };\n }\n\n const prepared = preparePolygons(polygons ?? []);\n if (prepared.length === 0) {\n return {\n data: {\n count: 0,\n positions: new Float32Array(0),\n paletteIndices: new Uint16Array(0),\n },\n meta: {\n mode: \"hybrid-webgpu\",\n durationMs: nowMs() - start,\n usedWebGpu: false,\n candidateCount: 0,\n bridgedToDraw: false,\n },\n };\n }\n\n const safeCount = Math.max(0, Math.min(pointData.count, Math.floor(pointData.positions.length / 2), pointData.paletteIndices.length));\n if (safeCount === 0) {\n return {\n data: {\n count: 0,\n positions: new Float32Array(0),\n paletteIndices: new Uint16Array(0),\n },\n meta: {\n mode: \"hybrid-webgpu\",\n durationMs: nowMs() - start,\n usedWebGpu: false,\n candidateCount: 0,\n bridgedToDraw: false,\n },\n };\n }\n\n const bboxFlat = new Float32Array(prepared.length * 4);\n for (let i = 0; i < prepared.length; i += 1) {\n const base = i * 4;\n const poly = prepared[i];\n bboxFlat[base] = poly.minX;\n bboxFlat[base + 1] = poly.minY;\n bboxFlat[base + 2] = poly.maxX;\n bboxFlat[base + 3] = poly.maxY;\n }\n\n let candidateMask: Uint32Array | null = null;\n let usedWebGpu = false;\n try {\n candidateMask = await prefilterPointsByBoundsWebGpu(pointData.positions, safeCount, bboxFlat);\n usedWebGpu = !!candidateMask;\n } catch {\n candidateMask = null;\n usedWebGpu = false;\n }\n\n if (!candidateMask) {\n const fallback = filterPointDataByPolygons(pointData, polygons);\n return {\n data: fallback,\n meta: {\n mode: \"hybrid-webgpu\",\n durationMs: nowMs() - start,\n usedWebGpu: false,\n candidateCount: safeCount,\n bridgedToDraw: false,\n },\n };\n }\n\n let candidateCount = 0;\n for (let i = 0; i < safeCount; i += 1) {\n if (candidateMask[i] === 1) candidateCount += 1;\n }\n\n const candidateIndices = new Uint32Array(candidateCount);\n if (candidateCount > 0) {\n let candidateCursor = 0;\n for (let i = 0; i < safeCount; i += 1) {\n if (candidateMask[i] !== 1) continue;\n candidateIndices[candidateCursor] = i;\n candidateCursor += 1;\n }\n }\n\n if (candidateCount === 0) {\n if (bridgeToDraw) {\n return {\n data: {\n count: safeCount,\n positions: pointData.positions.subarray(0, safeCount * 2),\n paletteIndices: pointData.paletteIndices.subarray(0, safeCount),\n drawIndices: new Uint32Array(0),\n },\n meta: {\n mode: \"hybrid-webgpu\",\n durationMs: nowMs() - start,\n usedWebGpu: true,\n candidateCount: 0,\n bridgedToDraw: true,\n },\n };\n }\n\n return {\n data: {\n count: 0,\n positions: new Float32Array(0),\n paletteIndices: new Uint16Array(0),\n },\n meta: {\n mode: \"hybrid-webgpu\",\n durationMs: nowMs() - start,\n usedWebGpu: true,\n candidateCount: 0,\n bridgedToDraw: false,\n },\n };\n }\n\n if (bridgeToDraw) {\n const drawIndices = new Uint32Array(candidateCount);\n let visibleCount = 0;\n\n for (let i = 0; i < candidateCount; i += 1) {\n const pointIndex = candidateIndices[i] ?? 0;\n const x = pointData.positions[pointIndex * 2];\n const y = pointData.positions[pointIndex * 2 + 1];\n if (!isInsideAnyPolygon(x, y, prepared)) continue;\n drawIndices[visibleCount] = pointIndex;\n visibleCount += 1;\n }\n\n return {\n data: {\n count: safeCount,\n positions: pointData.positions.subarray(0, safeCount * 2),\n paletteIndices: pointData.paletteIndices.subarray(0, safeCount),\n drawIndices: drawIndices.subarray(0, visibleCount),\n },\n meta: {\n mode: \"hybrid-webgpu\",\n durationMs: nowMs() - start,\n usedWebGpu: true,\n candidateCount,\n bridgedToDraw: true,\n },\n };\n }\n\n const nextPositions = new Float32Array(candidateCount * 2);\n const nextTerms = new Uint16Array(candidateCount);\n let cursor = 0;\n\n for (let i = 0; i < candidateCount; i += 1) {\n const pointIndex = candidateIndices[i] ?? 0;\n const x = pointData.positions[pointIndex * 2];\n const y = pointData.positions[pointIndex * 2 + 1];\n if (!isInsideAnyPolygon(x, y, prepared)) continue;\n nextPositions[cursor * 2] = x;\n nextPositions[cursor * 2 + 1] = y;\n nextTerms[cursor] = pointData.paletteIndices[pointIndex];\n cursor += 1;\n }\n\n return {\n data: {\n count: cursor,\n positions: nextPositions.subarray(0, cursor * 2),\n paletteIndices: nextTerms.subarray(0, cursor),\n },\n meta: {\n mode: \"hybrid-webgpu\",\n durationMs: nowMs() - start,\n usedWebGpu: true,\n candidateCount,\n bridgedToDraw: false,\n },\n };\n}\n","import { filterPointDataByPolygons, type RoiPolygon } from \"./point-clip\";\nimport type { RoiClipWorkerRequest, RoiClipWorkerResponse } from \"./point-clip-worker-protocol\";\nimport type { WsiPointData } from \"./types\";\n\nexport type PointClipMode = \"sync\" | \"worker\" | \"hybrid-webgpu\";\n\nexport interface PointClipResultMeta {\n mode: PointClipMode;\n durationMs: number;\n}\n\nexport interface PointClipResult {\n data: WsiPointData | null;\n meta: PointClipResultMeta;\n}\n\ninterface PendingWorkerRequest {\n resolve: (result: PointClipResult) => void;\n reject: (reason?: unknown) => void;\n startMs: number;\n}\n\nlet workerInstance: Worker | null = null;\nlet workerSupported = true;\nlet requestId = 1;\nconst pendingById = new Map<number, PendingWorkerRequest>();\n\nfunction nowMs(): number {\n if (typeof performance !== \"undefined\" && typeof performance.now === \"function\") {\n return performance.now();\n }\n return Date.now();\n}\n\nfunction createWorker(): Worker | null {\n if (!workerSupported) return null;\n if (workerInstance) return workerInstance;\n try {\n const worker = new Worker(new URL(\"../workers/roi-clip-worker.ts\", import.meta.url), { type: \"module\" });\n worker.addEventListener(\"message\", handleWorkerMessage);\n worker.addEventListener(\"error\", handleWorkerError);\n workerInstance = worker;\n return worker;\n } catch {\n workerSupported = false;\n return null;\n }\n}\n\nfunction handleWorkerMessage(event: MessageEvent<RoiClipWorkerResponse>): void {\n const msg = event.data;\n if (!msg) return;\n const pending = pendingById.get(msg.id);\n if (!pending) return;\n pendingById.delete(msg.id);\n\n if (msg.type === \"roi-clip-failure\") {\n pending.reject(new Error(msg.error || \"worker clip failed\"));\n return;\n }\n\n const count = Math.max(0, Math.floor(msg.count));\n const positions = new Float32Array(msg.positions);\n const paletteIndices = new Uint16Array(msg.paletteIndices);\n const output: WsiPointData = {\n count,\n positions: positions.subarray(0, count * 2),\n paletteIndices: paletteIndices.subarray(0, count),\n };\n\n pending.resolve({\n data: output,\n meta: {\n mode: \"worker\",\n durationMs: Number.isFinite(msg.durationMs) ? msg.durationMs : nowMs() - pending.startMs,\n },\n });\n}\n\nfunction handleWorkerError(): void {\n workerSupported = false;\n if (workerInstance) {\n workerInstance.removeEventListener(\"message\", handleWorkerMessage);\n workerInstance.removeEventListener(\"error\", handleWorkerError);\n workerInstance.terminate();\n workerInstance = null;\n }\n for (const [, pending] of pendingById) {\n pending.reject(new Error(\"worker crashed\"));\n }\n pendingById.clear();\n}\n\nexport function terminateRoiClipWorker(): void {\n if (!workerInstance) return;\n workerInstance.removeEventListener(\"message\", handleWorkerMessage);\n workerInstance.removeEventListener(\"error\", handleWorkerError);\n workerInstance.terminate();\n workerInstance = null;\n for (const [, pending] of pendingById) {\n pending.reject(new Error(\"worker terminated\"));\n }\n pendingById.clear();\n}\n\nexport async function filterPointDataByPolygonsInWorker(pointData: WsiPointData | null | undefined, polygons: RoiPolygon[] | null | undefined): Promise<PointClipResult> {\n if (!pointData || !pointData.count || !pointData.positions || !pointData.paletteIndices) {\n return {\n data: null,\n meta: { mode: \"worker\", durationMs: 0 },\n };\n }\n\n const worker = createWorker();\n if (!worker) {\n const start = nowMs();\n return {\n data: filterPointDataByPolygons(pointData, polygons),\n meta: { mode: \"sync\", durationMs: nowMs() - start },\n };\n }\n\n const safeCount = Math.max(0, Math.min(pointData.count, Math.floor(pointData.positions.length / 2), pointData.paletteIndices.length));\n const positionsCopy = pointData.positions.slice(0, safeCount * 2);\n const termsCopy = pointData.paletteIndices.slice(0, safeCount);\n const id = requestId++;\n const startMs = nowMs();\n\n return new Promise<PointClipResult>((resolve, reject) => {\n pendingById.set(id, { resolve, reject, startMs });\n const msg: RoiClipWorkerRequest = {\n type: \"roi-clip-request\",\n id,\n count: safeCount,\n positions: positionsCopy.buffer,\n paletteIndices: termsCopy.buffer,\n polygons: polygons ?? [],\n };\n worker.postMessage(msg, [positionsCopy.buffer, termsCopy.buffer]);\n });\n}\n","import type { WsiPointData, WsiRegion } from \"./types\";\n\nexport interface RoiTermCount {\n\ttermId: string;\n\tpaletteIndex: number;\n\tcount: number;\n}\n\nexport interface RoiPointGroup {\n\tregionId: string | number;\n\tregionIndex: number;\n\ttotalCount: number;\n\ttermCounts: RoiTermCount[];\n}\n\nexport interface RoiPointGroupOptions {\n\tpaletteIndexToTermId?: ReadonlyMap<number, string> | readonly string[];\n\tincludeEmptyRegions?: boolean;\n}\n\nexport interface RoiPointGroupStats {\n\tgroups: RoiPointGroup[];\n\tinputPointCount: number;\n\tpointsInsideAnyRegion: number;\n\tunmatchedPointCount: number;\n}\n\ninterface PreparedRegion {\n\tregionId: string | number;\n\tregionIndex: number;\n\tring: Array<[number, number]>;\n\tminX: number;\n\tminY: number;\n\tmaxX: number;\n\tmaxY: number;\n\tarea: number;\n}\n\nfunction closeRing(\n\tcoordinates: readonly [number, number][],\n): Array<[number, number]> {\n\tif (!Array.isArray(coordinates) || coordinates.length < 3) return [];\n\tconst out = coordinates.map(\n\t\t(point): [number, number] => [Number(point[0]), Number(point[1])],\n\t);\n\tconst first = out[0];\n\tconst last = out[out.length - 1];\n\tif (!first || !last) return [];\n\tif (first[0] !== last[0] || first[1] !== last[1]) {\n\t\tout.push([first[0], first[1]]);\n\t}\n\treturn out;\n}\n\nfunction polygonArea(ring: Array<[number, number]>): number {\n\tlet sum = 0;\n\tfor (let i = 0; i < ring.length - 1; i += 1) {\n\t\tconst [ax, ay] = ring[i];\n\t\tconst [bx, by] = ring[i + 1];\n\t\tsum += ax * by - bx * ay;\n\t}\n\treturn Math.abs(sum * 0.5);\n}\n\nfunction prepareRegions(regions: readonly WsiRegion[]): PreparedRegion[] {\n\tconst prepared: PreparedRegion[] = [];\n\tfor (let i = 0; i < regions.length; i += 1) {\n\t\tconst region = regions[i];\n\t\tif (!region?.coordinates?.length) continue;\n\n\t\tconst ring = closeRing(region.coordinates);\n\t\tif (ring.length < 4) continue;\n\n\t\tlet minX = Infinity;\n\t\tlet minY = Infinity;\n\t\tlet maxX = -Infinity;\n\t\tlet maxY = -Infinity;\n\t\tfor (const [x, y] of ring) {\n\t\t\tif (x < minX) minX = x;\n\t\t\tif (x > maxX) maxX = x;\n\t\t\tif (y < minY) minY = y;\n\t\t\tif (y > maxY) maxY = y;\n\t\t}\n\t\tif (\n\t\t\t!Number.isFinite(minX) ||\n\t\t\t!Number.isFinite(minY) ||\n\t\t\t!Number.isFinite(maxX) ||\n\t\t\t!Number.isFinite(maxY)\n\t\t) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tprepared.push({\n\t\t\tregionId: region.id ?? i,\n\t\t\tregionIndex: i,\n\t\t\tring,\n\t\t\tminX,\n\t\t\tminY,\n\t\t\tmaxX,\n\t\t\tmaxY,\n\t\t\tarea: Math.max(1e-6, polygonArea(ring)),\n\t\t});\n\t}\n\treturn prepared;\n}\n\nfunction isInsideRing(x: number, y: number, ring: Array<[number, number]>): boolean {\n\tlet inside = false;\n\tfor (let i = 0, j = ring.length - 1; i < ring.length; j = i, i += 1) {\n\t\tconst xi = ring[i][0];\n\t\tconst yi = ring[i][1];\n\t\tconst xj = ring[j][0];\n\t\tconst yj = ring[j][1];\n\t\tconst intersect =\n\t\t\tyi > y !== yj > y &&\n\t\t\tx < ((xj - xi) * (y - yi)) / ((yj - yi) || Number.EPSILON) + xi;\n\t\tif (intersect) inside = !inside;\n\t}\n\treturn inside;\n}\n\nfunction resolveTermId(\n\tpaletteIndex: number,\n\tpaletteIndexToTermId: RoiPointGroupOptions[\"paletteIndexToTermId\"],\n): string {\n\tif (Array.isArray(paletteIndexToTermId)) {\n\t\tconst fromArray = paletteIndexToTermId[paletteIndex];\n\t\tif (typeof fromArray === \"string\" && fromArray.length > 0) return fromArray;\n\t}\n\tif (paletteIndexToTermId instanceof Map) {\n\t\tconst fromMap = paletteIndexToTermId.get(paletteIndex);\n\t\tif (typeof fromMap === \"string\" && fromMap.length > 0) return fromMap;\n\t}\n\treturn String(paletteIndex);\n}\n\nexport function computeRoiPointGroups(\n\tpointData: WsiPointData | null | undefined,\n\tregions: readonly WsiRegion[] | null | undefined,\n\toptions: RoiPointGroupOptions = {},\n): RoiPointGroupStats {\n\tconst baseCount = Math.max(\n\t\t0,\n\t\tMath.min(\n\t\t\tMath.floor(pointData?.count ?? 0),\n\t\t\tMath.floor((pointData?.positions?.length ?? 0) / 2),\n\t\t\tpointData?.paletteIndices?.length ?? 0,\n\t\t),\n\t);\n\n\tlet drawIndices: Uint32Array | null = null;\n\tif (pointData?.drawIndices instanceof Uint32Array) {\n\t\tconst source = pointData.drawIndices;\n\t\tlet valid = source.length;\n\t\tfor (let i = 0; i < source.length; i += 1) {\n\t\t\tconst idx = source[i];\n\t\t\tif (idx < baseCount) continue;\n\t\t\tvalid -= 1;\n\t\t}\n\t\tif (valid === source.length) {\n\t\t\tdrawIndices = source;\n\t\t} else if (valid > 0) {\n\t\t\tconst filtered = new Uint32Array(valid);\n\t\t\tlet cursor = 0;\n\t\t\tfor (let i = 0; i < source.length; i += 1) {\n\t\t\t\tconst idx = source[i];\n\t\t\t\tif (idx >= baseCount) continue;\n\t\t\t\tfiltered[cursor] = idx;\n\t\t\t\tcursor += 1;\n\t\t\t}\n\t\t\tdrawIndices = filtered;\n\t\t} else {\n\t\t\tdrawIndices = new Uint32Array(0);\n\t\t}\n\t}\n\n\tconst inputCount = drawIndices ? drawIndices.length : baseCount;\n\n\tconst preparedRegions = prepareRegions(regions ?? []);\n\tif (!pointData || inputCount === 0 || preparedRegions.length === 0) {\n\t\treturn {\n\t\t\tgroups: [],\n\t\t\tinputPointCount: inputCount,\n\t\t\tpointsInsideAnyRegion: 0,\n\t\t\tunmatchedPointCount: inputCount,\n\t\t};\n\t}\n\n\tconst regionTermCounters = new Map<number, Map<number, number>>();\n\tconst regionTotalCounters = new Map<number, number>();\n\tlet insideCount = 0;\n\n\tfor (let i = 0; i < inputCount; i += 1) {\n\t\tconst pointIndex = drawIndices ? drawIndices[i] : i;\n\t\tconst x = pointData.positions[pointIndex * 2];\n\t\tconst y = pointData.positions[pointIndex * 2 + 1];\n\t\tlet bestRegion: PreparedRegion | null = null;\n\n\t\tfor (const region of preparedRegions) {\n\t\t\tif (x < region.minX || x > region.maxX || y < region.minY || y > region.maxY) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (!isInsideRing(x, y, region.ring)) continue;\n\t\t\tif (!bestRegion || region.area < bestRegion.area) {\n\t\t\t\tbestRegion = region;\n\t\t\t}\n\t\t}\n\n\t\tif (!bestRegion) continue;\n\t\tinsideCount += 1;\n\n\t\tconst paletteIndex = pointData.paletteIndices[pointIndex] ?? 0;\n\t\tconst regionTermMap =\n\t\t\tregionTermCounters.get(bestRegion.regionIndex) ?? new Map<number, number>();\n\t\tregionTermMap.set(paletteIndex, (regionTermMap.get(paletteIndex) ?? 0) + 1);\n\t\tregionTermCounters.set(bestRegion.regionIndex, regionTermMap);\n\t\tregionTotalCounters.set(\n\t\t\tbestRegion.regionIndex,\n\t\t\t(regionTotalCounters.get(bestRegion.regionIndex) ?? 0) + 1,\n\t\t);\n\t}\n\n\tconst includeEmptyRegions = options.includeEmptyRegions ?? false;\n\tconst groups: RoiPointGroup[] = [];\n\tfor (const region of preparedRegions) {\n\t\tconst totalCount = regionTotalCounters.get(region.regionIndex) ?? 0;\n\t\tif (!includeEmptyRegions && totalCount <= 0) continue;\n\t\tconst termMap = regionTermCounters.get(region.regionIndex) ?? new Map();\n\t\tconst termCounts: RoiTermCount[] = Array.from(termMap.entries())\n\t\t\t.map(([paletteIndex, count]) => ({\n\t\t\t\ttermId: resolveTermId(paletteIndex, options.paletteIndexToTermId),\n\t\t\t\tpaletteIndex,\n\t\t\t\tcount,\n\t\t\t}))\n\t\t\t.sort((a, b) => b.count - a.count || a.paletteIndex - b.paletteIndex);\n\n\t\tgroups.push({\n\t\t\tregionId: region.regionId,\n\t\t\tregionIndex: region.regionIndex,\n\t\t\ttotalCount,\n\t\t\ttermCounts,\n\t\t});\n\t}\n\n\treturn {\n\t\tgroups,\n\t\tinputPointCount: inputCount,\n\t\tpointsInsideAnyRegion: insideCount,\n\t\tunmatchedPointCount: Math.max(0, inputCount - insideCount),\n\t};\n}\n","export type TileBounds = [number, number, number, number];\n\nexport interface ScheduledTile {\n\tkey: string;\n\ttier: number;\n\tx: number;\n\ty: number;\n\tbounds: TileBounds;\n\tdistance2: number;\n\turl: string;\n}\n\nexport interface TileSchedulerSnapshot {\n\tinflight: number;\n\tqueued: number;\n\taborted: number;\n\tretries: number;\n\tfailed: number;\n}\n\nexport interface TileSchedulerOptions {\n\tmaxConcurrency?: number;\n\tmaxRetries?: number;\n\tretryBaseDelayMs?: number;\n\tretryMaxDelayMs?: number;\n\tauthToken?: string;\n\tonTileLoad: (tile: ScheduledTile, bitmap: ImageBitmap) => void;\n\tonTileError?: (\n\t\ttile: ScheduledTile,\n\t\terror: unknown,\n\t\tattemptCount: number,\n\t) => void;\n\tonStateChange?: (snapshot: TileSchedulerSnapshot) => void;\n}\n\ninterface QueueItem {\n\ttile: ScheduledTile;\n\tattempt: number;\n\treadyAt: number;\n}\n\ninterface InflightItem {\n\ttile: ScheduledTile;\n\tattempt: number;\n\tcontroller: AbortController;\n}\n\nfunction nowMs(): number {\n\tif (typeof performance !== \"undefined\" && typeof performance.now === \"function\") {\n\t\treturn performance.now();\n\t}\n\treturn Date.now();\n}\n\nfunction shouldAttachAuthHeader(url: string, authToken: string): boolean {\n\tif (!authToken) return false;\n\ttry {\n\t\tconst parsed = new URL(url, typeof window !== \"undefined\" ? window.location.href : undefined);\n\t\tconst host = parsed.hostname.toLowerCase();\n\t\tconst isAwsS3 =\n\t\t\thost.includes(\"amazonaws.com\") || host.startsWith(\"s3.\") || host.includes(\".s3.\");\n\t\tif (isAwsS3) return false;\n\t} catch {\n\t\t// Fallback to attaching auth if URL parsing fails.\n\t}\n\treturn true;\n}\n\nexport class TileScheduler {\n\tprivate readonly maxConcurrency: number;\n\tprivate readonly maxRetries: number;\n\tprivate readonly retryBaseDelayMs: number;\n\tprivate readonly retryMaxDelayMs: number;\n\tprivate readonly onTileLoad: (tile: ScheduledTile, bitmap: ImageBitmap) => void;\n\tprivate readonly onTileError?:\n\t\t| ((tile: ScheduledTile, error: unknown, attemptCount: number) => void)\n\t\t| undefined;\n\tprivate readonly onStateChange?:\n\t\t| ((snapshot: TileSchedulerSnapshot) => void)\n\t\t| undefined;\n\n\tprivate authToken: string;\n\tprivate destroyed = false;\n\tprivate queue: QueueItem[] = [];\n\tprivate queuedByKey = new Map<string, QueueItem>();\n\tprivate inflight = new Map<string, InflightItem>();\n\tprivate visibleKeys = new Set<string>();\n\tprivate timerId: number | null = null;\n\tprivate abortedCount = 0;\n\tprivate retryCount = 0;\n\tprivate failedCount = 0;\n\n\tconstructor(options: TileSchedulerOptions) {\n\t\tthis.maxConcurrency = Math.max(1, Math.floor(options.maxConcurrency ?? 12));\n\t\tthis.maxRetries = Math.max(0, Math.floor(options.maxRetries ?? 2));\n\t\tthis.retryBaseDelayMs = Math.max(\n\t\t\t10,\n\t\t\tMath.floor(options.retryBaseDelayMs ?? 120),\n\t\t);\n\t\tthis.retryMaxDelayMs = Math.max(\n\t\t\tthis.retryBaseDelayMs,\n\t\t\tMath.floor(options.retryMaxDelayMs ?? 1200),\n\t\t);\n\t\tthis.authToken = options.authToken ?? \"\";\n\t\tthis.onTileLoad = options.onTileLoad;\n\t\tthis.onTileError = options.onTileError;\n\t\tthis.onStateChange = options.onStateChange;\n\t}\n\n\tsetAuthToken(token: string): void {\n\t\tthis.authToken = String(token ?? \"\");\n\t}\n\n\tschedule(tiles: readonly ScheduledTile[]): void {\n\t\tif (this.destroyed) return;\n\n\t\tconst nextVisibleKeys = new Set<string>();\n\t\tfor (const tile of tiles) {\n\t\t\tnextVisibleKeys.add(tile.key);\n\t\t}\n\t\tthis.visibleKeys = nextVisibleKeys;\n\n\t\tthis.dropInvisibleQueued(nextVisibleKeys);\n\t\tthis.abortInvisibleInflight(nextVisibleKeys);\n\n\t\tfor (const tile of tiles) {\n\t\t\tif (this.inflight.has(tile.key)) {\n\t\t\t\tconst inflight = this.inflight.get(tile.key);\n\t\t\t\tif (inflight) inflight.tile = tile;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst queued = this.queuedByKey.get(tile.key);\n\t\t\tif (queued) {\n\t\t\t\tqueued.tile = tile;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst item: QueueItem = {\n\t\t\t\ttile,\n\t\t\t\tattempt: 0,\n\t\t\t\treadyAt: nowMs(),\n\t\t\t};\n\t\t\tthis.queue.push(item);\n\t\t\tthis.queuedByKey.set(tile.key, item);\n\t\t}\n\n\t\tthis.sortQueue();\n\t\tthis.pump();\n\t\tthis.emitStateChange();\n\t}\n\n\tclear(): void {\n\t\tthis.clearPumpTimer();\n\t\tthis.visibleKeys.clear();\n\t\tthis.queue = [];\n\t\tthis.queuedByKey.clear();\n\n\t\tfor (const [, item] of this.inflight) {\n\t\t\titem.controller.abort();\n\t\t}\n\t\tthis.inflight.clear();\n\t\tthis.emitStateChange();\n\t}\n\n\tdestroy(): void {\n\t\tif (this.destroyed) return;\n\t\tthis.destroyed = true;\n\t\tthis.clear();\n\t}\n\n\tgetInflightCount(): number {\n\t\treturn this.inflight.size;\n\t}\n\n\tgetSnapshot(): TileSchedulerSnapshot {\n\t\treturn {\n\t\t\tinflight: this.inflight.size,\n\t\t\tqueued: this.queue.length,\n\t\t\taborted: this.abortedCount,\n\t\t\tretries: this.retryCount,\n\t\t\tfailed: this.failedCount,\n\t\t};\n\t}\n\n\tprivate dropInvisibleQueued(visibleKeys: Set<string>): void {\n\t\tif (this.queue.length === 0) return;\n\t\tconst nextQueue: QueueItem[] = [];\n\t\tfor (const item of this.queue) {\n\t\t\tif (!visibleKeys.has(item.tile.key)) {\n\t\t\t\tthis.queuedByKey.delete(item.tile.key);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tnextQueue.push(item);\n\t\t}\n\t\tthis.queue = nextQueue;\n\t}\n\n\tprivate abortInvisibleInflight(visibleKeys: Set<string>): void {\n\t\tfor (const [key, item] of this.inflight) {\n\t\t\tif (visibleKeys.has(key)) continue;\n\t\t\tthis.inflight.delete(key);\n\t\t\tthis.abortedCount += 1;\n\t\t\titem.controller.abort();\n\t\t}\n\t}\n\n\tprivate sortQueue(): void {\n\t\tthis.queue.sort((a, b) => {\n\t\t\tif (a.readyAt !== b.readyAt) return a.readyAt - b.readyAt;\n\t\t\tif (a.tile.distance2 !== b.tile.distance2) {\n\t\t\t\treturn a.tile.distance2 - b.tile.distance2;\n\t\t\t}\n\t\t\tif (a.tile.tier !== b.tile.tier) return b.tile.tier - a.tile.tier;\n\t\t\treturn a.tile.key.localeCompare(b.tile.key);\n\t\t});\n\t}\n\n\tprivate pump(): void {\n\t\tif (this.destroyed) return;\n\t\tthis.clearPumpTimer();\n\n\t\twhile (this.inflight.size < this.maxConcurrency) {\n\t\t\tconst next = this.takeNextReadyQueueItem();\n\t\t\tif (!next) break;\n\t\t\tthis.startFetch(next);\n\t\t}\n\n\t\tif (this.inflight.size >= this.maxConcurrency) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.queue.length === 0) return;\n\n\t\tconst earliestReadyAt = this.queue[0]?.readyAt;\n\t\tif (typeof earliestReadyAt !== \"number\") return;\n\t\tconst delay = Math.max(0, earliestReadyAt - nowMs());\n\t\tthis.timerId = window.setTimeout(() => {\n\t\t\tthis.timerId = null;\n\t\t\tthis.pump();\n\t\t}, delay);\n\t}\n\n\tprivate takeNextReadyQueueItem(): QueueItem | null {\n\t\tif (this.queue.length === 0) return null;\n\t\tconst now = nowMs();\n\t\tconst first = this.queue[0];\n\t\tif (!first || first.readyAt > now) return null;\n\n\t\tthis.queue.shift();\n\t\tthis.queuedByKey.delete(first.tile.key);\n\t\treturn first;\n\t}\n\n\tprivate startFetch(item: QueueItem): void {\n\t\tconst controller = new AbortController();\n\t\tconst inflightEntry: InflightItem = {\n\t\t\ttile: item.tile,\n\t\t\tattempt: item.attempt,\n\t\t\tcontroller,\n\t\t};\n\t\tthis.inflight.set(item.tile.key, inflightEntry);\n\t\tthis.emitStateChange();\n\n\t\tconst useAuthHeader = shouldAttachAuthHeader(item.tile.url, this.authToken);\n\t\tfetch(item.tile.url, {\n\t\t\tsignal: controller.signal,\n\t\t\theaders: useAuthHeader ? { Authorization: this.authToken } : undefined,\n\t\t})\n\t\t\t.then((response) => {\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new Error(`HTTP ${response.status}`);\n\t\t\t\t}\n\t\t\t\treturn response.blob();\n\t\t\t})\n\t\t\t.then((blob) => createImageBitmap(blob))\n\t\t\t.then((bitmap) => {\n\t\t\t\tif (this.destroyed || controller.signal.aborted) {\n\t\t\t\t\tbitmap.close();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (!this.visibleKeys.has(item.tile.key)) {\n\t\t\t\t\tbitmap.close();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis.onTileLoad(item.tile, bitmap);\n\t\t\t})\n\t\t\t.catch((error: unknown) => {\n\t\t\t\tif (controller.signal.aborted || this.destroyed) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst shouldRetry =\n\t\t\t\t\titem.attempt < this.maxRetries && this.visibleKeys.has(item.tile.key);\n\t\t\t\tif (shouldRetry) {\n\t\t\t\t\tthis.retryCount += 1;\n\t\t\t\t\tconst nextAttempt = item.attempt + 1;\n\t\t\t\t\tconst retryDelay = this.getRetryDelay(nextAttempt);\n\t\t\t\t\tconst queued: QueueItem = {\n\t\t\t\t\t\ttile: item.tile,\n\t\t\t\t\t\tattempt: nextAttempt,\n\t\t\t\t\t\treadyAt: nowMs() + retryDelay,\n\t\t\t\t\t};\n\t\t\t\t\tconst existing = this.queuedByKey.get(item.tile.key);\n\t\t\t\t\tif (existing) {\n\t\t\t\t\t\texisting.tile = queued.tile;\n\t\t\t\t\t\texisting.readyAt = Math.min(existing.readyAt, queued.readyAt);\n\t\t\t\t\t\texisting.attempt = Math.max(existing.attempt, queued.attempt);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.queue.push(queued);\n\t\t\t\t\t\tthis.queuedByKey.set(queued.tile.key, queued);\n\t\t\t\t\t}\n\t\t\t\t\tthis.sortQueue();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis.failedCount += 1;\n\t\t\t\tthis.onTileError?.(item.tile, error, item.attempt + 1);\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tthis.inflight.delete(item.tile.key);\n\t\t\t\tthis.pump();\n\t\t\t\tthis.emitStateChange();\n\t\t\t});\n\t}\n\n\tprivate getRetryDelay(attempt: number): number {\n\t\tconst exp = Math.max(0, attempt - 1);\n\t\tconst delay = Math.min(\n\t\t\tthis.retryMaxDelayMs,\n\t\t\tthis.retryBaseDelayMs * 2 ** exp,\n\t\t);\n\t\tconst jitter = 0.85 + Math.random() * 0.3;\n\t\treturn Math.round(delay * jitter);\n\t}\n\n\tprivate clearPumpTimer(): void {\n\t\tif (this.timerId === null) return;\n\t\twindow.clearTimeout(this.timerId);\n\t\tthis.timerId = null;\n\t}\n\n\tprivate emitStateChange(): void {\n\t\tthis.onStateChange?.(this.getSnapshot());\n\t}\n}\n","import { toTileUrl } from \"./image-info\";\nimport {\n\tTileScheduler,\n\ttype ScheduledTile,\n\ttype TileBounds,\n} from \"./tile-scheduler\";\nimport type {\n\tWsiImageSource,\n\tWsiPointData,\n\tWsiRenderStats,\n\tWsiViewState,\n} from \"./types\";\nimport { clamp, createProgram } from \"./utils\";\n\ntype Bounds = TileBounds;\n\ninterface CachedTile {\n\tkey: string;\n\ttexture: WebGLTexture;\n\tbounds: Bounds;\n\ttier: number;\n\tlastUsed: number;\n}\n\ninterface TileVertexProgram {\n\tprogram: WebGLProgram;\n\tvao: WebGLVertexArrayObject;\n\tvbo: WebGLBuffer;\n\tuCamera: WebGLUniformLocation;\n\tuBounds: WebGLUniformLocation;\n\tuTexture: WebGLUniformLocation;\n}\n\ninterface PointProgram {\n\tprogram: WebGLProgram;\n\tvao: WebGLVertexArrayObject;\n\tposBuffer: WebGLBuffer;\n\ttermBuffer: WebGLBuffer;\n\tindexBuffer: WebGLBuffer;\n\tpaletteTexture: WebGLTexture;\n\tuCamera: WebGLUniformLocation;\n\tuPointSize: WebGLUniformLocation;\n\tuPalette: WebGLUniformLocation;\n\tuPaletteSize: WebGLUniformLocation;\n}\n\ninterface OrthoViewport {\n\twidth: number;\n\theight: number;\n}\n\ntype WorldPoint = [number, number];\nconst DEFAULT_ROTATION_DRAG_SENSITIVITY = 0.35;\n\nexport interface WsiTileSchedulerConfig {\n\tmaxConcurrency?: number;\n\tmaxRetries?: number;\n\tretryBaseDelayMs?: number;\n\tretryMaxDelayMs?: number;\n}\n\nexport interface WsiTileRendererOptions {\n\tonViewStateChange?: (next: WsiViewState) => void;\n\tonStats?: (stats: WsiRenderStats) => void;\n\tauthToken?: string;\n\tmaxCacheTiles?: number;\n\tctrlDragRotate?: boolean;\n\trotationDragSensitivityDegPerPixel?: number;\n\ttileScheduler?: WsiTileSchedulerConfig;\n\tonTileError?: (event: WsiTileErrorEvent) => void;\n\tonContextLost?: () => void;\n\tonContextRestored?: () => void;\n}\n\nexport interface WsiTileErrorEvent {\n\ttile: ScheduledTile;\n\terror: unknown;\n\tattemptCount: number;\n}\n\nclass OrthoCamera {\n\tprivate viewportWidth = 1;\n\tprivate viewportHeight = 1;\n\tprivate viewState: WsiViewState = {\n\t\tzoom: 1,\n\t\toffsetX: 0,\n\t\toffsetY: 0,\n\t\trotationDeg: 0,\n\t};\n\n\tsetViewport(width: number, height: number): void {\n\t\tthis.viewportWidth = Math.max(1, width);\n\t\tthis.viewportHeight = Math.max(1, height);\n\t}\n\n\tgetViewport(): OrthoViewport {\n\t\treturn { width: this.viewportWidth, height: this.viewportHeight };\n\t}\n\n\tsetViewState(next: Partial<WsiViewState>): void {\n\t\tif (typeof next.zoom === \"number\") {\n\t\t\tthis.viewState.zoom = Math.max(0.0001, next.zoom);\n\t\t}\n\t\tif (typeof next.offsetX === \"number\") {\n\t\t\tthis.viewState.offsetX = next.offsetX;\n\t\t}\n\t\tif (typeof next.offsetY === \"number\") {\n\t\t\tthis.viewState.offsetY = next.offsetY;\n\t\t}\n\t\tif (typeof next.rotationDeg === \"number\" && Number.isFinite(next.rotationDeg)) {\n\t\t\tthis.viewState.rotationDeg = next.rotationDeg;\n\t\t}\n\t}\n\n\tgetViewState(): WsiViewState {\n\t\treturn { ...this.viewState };\n\t}\n\n\tgetCenter(): WorldPoint {\n\t\tconst zoom = Math.max(1e-6, this.viewState.zoom);\n\t\treturn [\n\t\t\tthis.viewState.offsetX + this.viewportWidth / (2 * zoom),\n\t\t\tthis.viewState.offsetY + this.viewportHeight / (2 * zoom),\n\t\t];\n\t}\n\n\tsetCenter(centerX: number, centerY: number): void {\n\t\tconst zoom = Math.max(1e-6, this.viewState.zoom);\n\t\tthis.viewState.offsetX = centerX - this.viewportWidth / (2 * zoom);\n\t\tthis.viewState.offsetY = centerY - this.viewportHeight / (2 * zoom);\n\t}\n\n\tscreenToWorld(screenX: number, screenY: number): WorldPoint {\n\t\tconst state = this.viewState;\n\t\tconst zoom = Math.max(1e-6, state.zoom);\n\t\tconst [centerX, centerY] = this.getCenter();\n\t\tconst dx = (screenX - this.viewportWidth * 0.5) / zoom;\n\t\tconst dy = (screenY - this.viewportHeight * 0.5) / zoom;\n\t\tconst rad = toRadians(state.rotationDeg);\n\t\tconst cos = Math.cos(rad);\n\t\tconst sin = Math.sin(rad);\n\t\treturn [centerX + dx * cos - dy * sin, centerY + dx * sin + dy * cos];\n\t}\n\n\tworldToScreen(worldX: number, worldY: number): WorldPoint {\n\t\tconst state = this.viewState;\n\t\tconst zoom = Math.max(1e-6, state.zoom);\n\t\tconst [centerX, centerY] = this.getCenter();\n\t\tconst dx = worldX - centerX;\n\t\tconst dy = worldY - centerY;\n\t\tconst rad = toRadians(state.rotationDeg);\n\t\tconst cos = Math.cos(rad);\n\t\tconst sin = Math.sin(rad);\n\t\tconst rx = dx * cos + dy * sin;\n\t\tconst ry = -dx * sin + dy * cos;\n\t\treturn [\n\t\t\tthis.viewportWidth * 0.5 + rx * zoom,\n\t\t\tthis.viewportHeight * 0.5 + ry * zoom,\n\t\t];\n\t}\n\n\tgetViewCorners(): [WorldPoint, WorldPoint, WorldPoint, WorldPoint] {\n\t\tconst w = this.viewportWidth;\n\t\tconst h = this.viewportHeight;\n\t\treturn [\n\t\t\tthis.screenToWorld(0, 0),\n\t\t\tthis.screenToWorld(w, 0),\n\t\t\tthis.screenToWorld(w, h),\n\t\t\tthis.screenToWorld(0, h),\n\t\t];\n\t}\n\n\tgetMatrix(): Float32Array {\n\t\tconst zoom = Math.max(1e-6, this.viewState.zoom);\n\t\tconst [centerX, centerY] = this.getCenter();\n\t\tconst rad = toRadians(this.viewState.rotationDeg);\n\t\tconst cos = Math.cos(rad);\n\t\tconst sin = Math.sin(rad);\n\n\t\tconst ax = (2 * zoom * cos) / this.viewportWidth;\n\t\tconst bx = (2 * zoom * sin) / this.viewportWidth;\n\t\tconst ay = (2 * zoom * sin) / this.viewportHeight;\n\t\tconst by = (-2 * zoom * cos) / this.viewportHeight;\n\t\tconst tx = -(ax * centerX + bx * centerY);\n\t\tconst ty = -(ay * centerX + by * centerY);\n\n\t\treturn new Float32Array([ax, ay, 0, bx, by, 0, tx, ty, 1]);\n\t}\n}\n\nfunction toRadians(deg: number): number {\n\treturn (deg * Math.PI) / 180;\n}\n\nfunction nowMs(): number {\n\tif (typeof performance !== \"undefined\" && typeof performance.now === \"function\") {\n\t\treturn performance.now();\n\t}\n\treturn Date.now();\n}\n\nfunction requireUniformLocation(\n\tgl: WebGL2RenderingContext,\n\tprogram: WebGLProgram,\n\tname: string,\n): WebGLUniformLocation {\n\tconst location = gl.getUniformLocation(program, name);\n\tif (!location) {\n\t\tthrow new Error(`uniform location lookup failed: ${name}`);\n\t}\n\treturn location;\n}\n\nfunction isSameArrayView(\n\ta: ArrayBufferView | null | undefined,\n\tb: ArrayBufferView | null | undefined,\n): boolean {\n\tif (!a || !b) return a === b;\n\treturn (\n\t\ta.buffer === b.buffer &&\n\t\ta.byteOffset === b.byteOffset &&\n\t\ta.byteLength === b.byteLength\n\t);\n}\n\nexport class WsiTileRenderer {\n\tprivate readonly canvas: HTMLCanvasElement;\n\tprivate readonly source: WsiImageSource;\n\tprivate readonly gl: WebGL2RenderingContext;\n\tprivate readonly camera = new OrthoCamera();\n\tprivate readonly onViewStateChange?: (next: WsiViewState) => void;\n\tprivate readonly onStats?: (stats: WsiRenderStats) => void;\n\tprivate readonly onTileError?: (event: WsiTileErrorEvent) => void;\n\tprivate readonly onContextLost?: () => void;\n\tprivate readonly onContextRestored?: () => void;\n\tprivate readonly resizeObserver: ResizeObserver;\n\tprivate tileProgram: TileVertexProgram;\n\tprivate pointProgram: PointProgram;\n\tprivate readonly tileScheduler: TileScheduler;\n\n\tprivate authToken: string;\n\tprivate destroyed = false;\n\tprivate contextLost = false;\n\tprivate frame: number | null = null;\n\tprivate frameSerial = 0;\n\tprivate dragging = false;\n\tprivate interactionMode: \"none\" | \"pan\" | \"rotate\" = \"none\";\n\tprivate rotateLastAngleRad: number | null = null;\n\tprivate pointerId: number | null = null;\n\tprivate lastPointerX = 0;\n\tprivate lastPointerY = 0;\n\tprivate interactionLocked = false;\n\tprivate ctrlDragRotate = true;\n\tprivate rotationDragSensitivityDegPerPixel = 0.35;\n\tprivate maxCacheTiles: number;\n\tprivate fitZoom = 1;\n\tprivate minZoom = 1e-6;\n\tprivate maxZoom = 1;\n\tprivate currentTier = 0;\n\tprivate pointCount = 0;\n\tprivate usePointIndices = false;\n\tprivate pointBuffersDirty = true;\n\tprivate pointPaletteSize = 1;\n\tprivate lastPointData: WsiPointData | null = null;\n\tprivate lastPointPalette: Uint8Array | null = null;\n\tprivate cache = new Map<string, CachedTile>();\n\n\tprivate readonly boundPointerDown: (event: PointerEvent) => void;\n\tprivate readonly boundPointerMove: (event: PointerEvent) => void;\n\tprivate readonly boundPointerUp: (event: PointerEvent) => void;\n\tprivate readonly boundWheel: (event: WheelEvent) => void;\n\tprivate readonly boundDoubleClick: (event: MouseEvent) => void;\n\tprivate readonly boundContextMenu: (event: MouseEvent) => void;\n\tprivate readonly boundContextLost: (event: Event) => void;\n\tprivate readonly boundContextRestored: (event: Event) => void;\n\n\tconstructor(\n\t\tcanvas: HTMLCanvasElement,\n\t\tsource: WsiImageSource,\n\t\toptions: WsiTileRendererOptions = {},\n\t) {\n\t\tthis.canvas = canvas;\n\t\tthis.source = source;\n\t\tthis.onViewStateChange = options.onViewStateChange;\n\t\tthis.onStats = options.onStats;\n\t\tthis.onTileError = options.onTileError;\n\t\tthis.onContextLost = options.onContextLost;\n\t\tthis.onContextRestored = options.onContextRestored;\n\t\tthis.authToken = options.authToken ?? \"\";\n\t\tthis.maxCacheTiles = Math.max(32, Math.floor(options.maxCacheTiles ?? 320));\n\t\tthis.ctrlDragRotate = options.ctrlDragRotate ?? true;\n\t\tthis.rotationDragSensitivityDegPerPixel =\n\t\t\ttypeof options.rotationDragSensitivityDegPerPixel === \"number\" &&\n\t\t\tNumber.isFinite(options.rotationDragSensitivityDegPerPixel)\n\t\t\t\t? Math.max(0, options.rotationDragSensitivityDegPerPixel)\n\t\t\t\t: DEFAULT_ROTATION_DRAG_SENSITIVITY;\n\n\t\tconst gl = canvas.getContext(\"webgl2\", {\n\t\t\talpha: false,\n\t\t\tantialias: false,\n\t\t\tdepth: false,\n\t\t\tstencil: false,\n\t\t\tpowerPreference: \"high-performance\",\n\t\t});\n\t\tif (!gl) {\n\t\t\tthrow new Error(\"WebGL2 not supported\");\n\t\t}\n\t\tthis.gl = gl;\n\n\t\tthis.tileProgram = this.initTileProgram();\n\t\tthis.pointProgram = this.initPointProgram();\n\t\tthis.tileScheduler = new TileScheduler({\n\t\t\tauthToken: this.authToken,\n\t\t\tmaxConcurrency: options.tileScheduler?.maxConcurrency ?? 12,\n\t\t\tmaxRetries: options.tileScheduler?.maxRetries ?? 2,\n\t\t\tretryBaseDelayMs: options.tileScheduler?.retryBaseDelayMs ?? 120,\n\t\t\tretryMaxDelayMs: options.tileScheduler?.retryMaxDelayMs ?? 1200,\n\t\t\tonTileLoad: (tile, bitmap) => this.handleTileLoaded(tile, bitmap),\n\t\t\tonTileError: (tile, error, attemptCount) => {\n\t\t\t\tthis.onTileError?.({ tile, error, attemptCount });\n\t\t\t\tconsole.warn(\"tile load failed\", tile.url, error);\n\t\t\t},\n\t\t});\n\n\t\tthis.resizeObserver = new ResizeObserver(() => this.resize());\n\t\tthis.resizeObserver.observe(canvas);\n\n\t\tthis.boundPointerDown = (event: PointerEvent) => this.onPointerDown(event);\n\t\tthis.boundPointerMove = (event: PointerEvent) => this.onPointerMove(event);\n\t\tthis.boundPointerUp = (event: PointerEvent) => this.onPointerUp(event);\n\t\tthis.boundWheel = (event: WheelEvent) => this.onWheel(event);\n\t\tthis.boundDoubleClick = (event: MouseEvent) => this.onDoubleClick(event);\n\t\tthis.boundContextMenu = (event: MouseEvent) => this.onContextMenu(event);\n\t\tthis.boundContextLost = (event: Event) => this.onWebGlContextLost(event);\n\t\tthis.boundContextRestored = (event: Event) =>\n\t\t\tthis.onWebGlContextRestored(event);\n\n\t\tcanvas.addEventListener(\"pointerdown\", this.boundPointerDown);\n\t\tcanvas.addEventListener(\"pointermove\", this.boundPointerMove);\n\t\tcanvas.addEventListener(\"pointerup\", this.boundPointerUp);\n\t\tcanvas.addEventListener(\"pointercancel\", this.boundPointerUp);\n\t\tcanvas.addEventListener(\"wheel\", this.boundWheel, { passive: false });\n\t\tcanvas.addEventListener(\"dblclick\", this.boundDoubleClick);\n\t\tcanvas.addEventListener(\"contextmenu\", this.boundContextMenu);\n\t\tcanvas.addEventListener(\"webglcontextlost\", this.boundContextLost);\n\t\tcanvas.addEventListener(\"webglcontextrestored\", this.boundContextRestored);\n\n\t\tthis.fitToImage();\n\t\tthis.resize();\n\t}\n\n\tsetAuthToken(token: string): void {\n\t\tthis.authToken = String(token ?? \"\");\n\t\tthis.tileScheduler.setAuthToken(this.authToken);\n\t}\n\n\tsetViewState(next: Partial<WsiViewState>): void {\n\t\tconst normalized: Partial<WsiViewState> = { ...next };\n\t\tif (typeof normalized.zoom === \"number\") {\n\t\t\tnormalized.zoom = clamp(normalized.zoom, this.minZoom, this.maxZoom);\n\t\t}\n\t\tthis.camera.setViewState(normalized);\n\t\tthis.clampViewState();\n\t\tthis.emitViewState();\n\t\tthis.requestRender();\n\t}\n\n\tgetViewState(): WsiViewState {\n\t\treturn this.camera.getViewState();\n\t}\n\n\tsetPointPalette(colors: Uint8Array | null | undefined): void {\n\t\tif (!colors || colors.length === 0) {\n\t\t\tthis.lastPointPalette = null;\n\t\t\treturn;\n\t\t}\n\t\tthis.lastPointPalette = new Uint8Array(colors);\n\t\tif (this.contextLost || this.gl.isContextLost()) return;\n\t\tconst gl = this.gl;\n\t\tconst paletteSize = Math.max(1, Math.floor(this.lastPointPalette.length / 4));\n\t\tthis.pointPaletteSize = paletteSize;\n\t\tgl.bindTexture(gl.TEXTURE_2D, this.pointProgram.paletteTexture);\n\t\tgl.texImage2D(\n\t\t\tgl.TEXTURE_2D,\n\t\t\t0,\n\t\t\tgl.RGBA,\n\t\t\tpaletteSize,\n\t\t\t1,\n\t\t\t0,\n\t\t\tgl.RGBA,\n\t\t\tgl.UNSIGNED_BYTE,\n\t\t\tthis.lastPointPalette,\n\t\t);\n\t\tgl.bindTexture(gl.TEXTURE_2D, null);\n\t\tthis.requestRender();\n\t}\n\n\tsetPointData(points: WsiPointData | null | undefined): void {\n\t\tif (!points || !points.count || !points.positions || !points.paletteIndices) {\n\t\t\tthis.lastPointData = null;\n\t\t\tthis.pointCount = 0;\n\t\t\tthis.usePointIndices = false;\n\t\t\tthis.requestRender();\n\t\t\treturn;\n\t\t}\n\n\t\tconst safeCount = Math.max(\n\t\t\t0,\n\t\t\tMath.min(\n\t\t\t\tpoints.count,\n\t\t\t\tMath.floor(points.positions.length / 2),\n\t\t\t\tpoints.paletteIndices.length,\n\t\t\t),\n\t\t);\n\t\tconst nextPositions = points.positions.subarray(0, safeCount * 2);\n\t\tconst nextPaletteIndices = points.paletteIndices.subarray(0, safeCount);\n\t\tconst hasDrawIndices = points.drawIndices instanceof Uint32Array;\n\t\tconst nextDrawIndices = hasDrawIndices\n\t\t\t? this.sanitizeDrawIndices(points.drawIndices as Uint32Array, safeCount)\n\t\t\t: null;\n\t\tconst prev = this.lastPointData;\n\t\tlet geometryChanged =\n\t\t\tthis.pointBuffersDirty ||\n\t\t\t!prev ||\n\t\t\tprev.count !== safeCount ||\n\t\t\t!isSameArrayView(prev.positions, nextPositions) ||\n\t\t\t!isSameArrayView(prev.paletteIndices, nextPaletteIndices);\n\t\tlet drawIndicesChanged =\n\t\t\tthis.pointBuffersDirty ||\n\t\t\t(hasDrawIndices &&\n\t\t\t\t(!prev?.drawIndices ||\n\t\t\t\t\t!isSameArrayView(prev.drawIndices, nextDrawIndices))) ||\n\t\t\t(!hasDrawIndices && !!prev?.drawIndices);\n\n\t\tthis.lastPointData = {\n\t\t\tcount: safeCount,\n\t\t\tpositions: nextPositions,\n\t\t\tpaletteIndices: nextPaletteIndices,\n\t\t\tdrawIndices: hasDrawIndices ? nextDrawIndices ?? undefined : undefined,\n\t\t};\n\t\tif (this.contextLost || this.gl.isContextLost()) return;\n\n\t\tconst gl = this.gl;\n\t\tif (geometryChanged) {\n\t\t\tgl.bindBuffer(gl.ARRAY_BUFFER, this.pointProgram.posBuffer);\n\t\t\tgl.bufferData(gl.ARRAY_BUFFER, this.lastPointData.positions, gl.STATIC_DRAW);\n\n\t\t\tgl.bindBuffer(gl.ARRAY_BUFFER, this.pointProgram.termBuffer);\n\t\t\tgl.bufferData(\n\t\t\t\tgl.ARRAY_BUFFER,\n\t\t\t\tthis.lastPointData.paletteIndices,\n\t\t\t\tgl.STATIC_DRAW,\n\t\t\t);\n\t\t\tgl.bindBuffer(gl.ARRAY_BUFFER, null);\n\t\t}\n\n\t\tif (hasDrawIndices && drawIndicesChanged) {\n\t\t\tgl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.pointProgram.indexBuffer);\n\t\t\tgl.bufferData(\n\t\t\t\tgl.ELEMENT_ARRAY_BUFFER,\n\t\t\t\tnextDrawIndices ?? new Uint32Array(0),\n\t\t\t\tgl.DYNAMIC_DRAW,\n\t\t\t);\n\t\t\tgl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);\n\t\t}\n\n\t\tthis.usePointIndices = hasDrawIndices;\n\t\tthis.pointCount = hasDrawIndices\n\t\t\t? (nextDrawIndices?.length ?? 0)\n\t\t\t: this.lastPointData.count;\n\t\tif (geometryChanged || drawIndicesChanged) {\n\t\t\tthis.pointBuffersDirty = false;\n\t\t}\n\t\tthis.requestRender();\n\t}\n\n\tprivate sanitizeDrawIndices(\n\t\tdrawIndices: Uint32Array,\n\t\tmaxExclusive: number,\n\t): Uint32Array {\n\t\tif (maxExclusive <= 0 || drawIndices.length === 0) {\n\t\t\treturn new Uint32Array(0);\n\t\t}\n\n\t\tlet validCount = drawIndices.length;\n\t\tfor (let i = 0; i < drawIndices.length; i += 1) {\n\t\t\tif (drawIndices[i] < maxExclusive) continue;\n\t\t\tvalidCount -= 1;\n\t\t}\n\t\tif (validCount === drawIndices.length) {\n\t\t\treturn drawIndices;\n\t\t}\n\t\tif (validCount <= 0) {\n\t\t\treturn new Uint32Array(0);\n\t\t}\n\n\t\tconst filtered = new Uint32Array(validCount);\n\t\tlet cursor = 0;\n\t\tfor (let i = 0; i < drawIndices.length; i += 1) {\n\t\t\tconst idx = drawIndices[i];\n\t\t\tif (idx >= maxExclusive) continue;\n\t\t\tfiltered[cursor] = idx;\n\t\t\tcursor += 1;\n\t\t}\n\t\treturn filtered;\n\t}\n\n\tsetInteractionLock(locked: boolean): void {\n\t\tconst next = Boolean(locked);\n\t\tif (this.interactionLocked === next) return;\n\t\tthis.interactionLocked = next;\n\t\tif (next) this.cancelDrag();\n\t}\n\n\tcancelDrag(): void {\n\t\tif (this.pointerId !== null && this.canvas.hasPointerCapture(this.pointerId)) {\n\t\t\ttry {\n\t\t\t\tthis.canvas.releasePointerCapture(this.pointerId);\n\t\t\t} catch {\n\t\t\t\t// noop\n\t\t\t}\n\t\t}\n\t\tthis.dragging = false;\n\t\tthis.interactionMode = \"none\";\n\t\tthis.rotateLastAngleRad = null;\n\t\tthis.pointerId = null;\n\t\tthis.canvas.classList.remove(\"dragging\");\n\t}\n\n\tprivate getPointerAngleRad(clientX: number, clientY: number): number {\n\t\tconst rect = this.canvas.getBoundingClientRect();\n\t\tconst x = clientX - rect.left - rect.width * 0.5;\n\t\tconst y = clientY - rect.top - rect.height * 0.5;\n\t\treturn Math.atan2(y, x);\n\t}\n\n\tscreenToWorld(clientX: number, clientY: number): [number, number] {\n\t\tconst rect = this.canvas.getBoundingClientRect();\n\t\tconst sx = clientX - rect.left;\n\t\tconst sy = clientY - rect.top;\n\t\treturn this.camera.screenToWorld(sx, sy);\n\t}\n\n\tworldToScreen(worldX: number, worldY: number): [number, number] {\n\t\treturn this.camera.worldToScreen(worldX, worldY);\n\t}\n\n\tsetViewCenter(worldX: number, worldY: number): void {\n\t\tif (!Number.isFinite(worldX) || !Number.isFinite(worldY)) return;\n\t\tthis.camera.setCenter(worldX, worldY);\n\t\tthis.clampViewState();\n\t\tthis.emitViewState();\n\t\tthis.requestRender();\n\t}\n\n\tgetViewCorners(): [WorldPoint, WorldPoint, WorldPoint, WorldPoint] {\n\t\treturn this.camera.getViewCorners();\n\t}\n\n\tresetRotation(): void {\n\t\tconst state = this.camera.getViewState();\n\t\tif (Math.abs(state.rotationDeg) < 1e-6) return;\n\t\tthis.camera.setViewState({ rotationDeg: 0 });\n\t\tthis.clampViewState();\n\t\tthis.emitViewState();\n\t\tthis.requestRender();\n\t}\n\n\tgetPointSizeByZoom(): number {\n\t\tconst zoom = Math.max(1e-6, this.camera.getViewState().zoom);\n\t\tconst continuousZoom = this.source.maxTierZoom + Math.log2(zoom);\n\t\tconst stops: [number, number][] = [\n\t\t\t[1, 2.6],\n\t\t\t[2, 3.1],\n\t\t\t[3, 3.8],\n\t\t\t[4, 4.8],\n\t\t\t[5, 6.1],\n\t\t\t[6, 7.4],\n\t\t\t[7, 8.4],\n\t\t\t[8, 9.0],\n\t\t\t[9, 11.5],\n\t\t\t[10, 14.5],\n\t\t\t[11, 18.0],\n\t\t\t[12, 22.0],\n\t\t];\n\t\tlet size = stops[0][1];\n\t\tfor (let i = 1; i < stops.length; i += 1) {\n\t\t\tconst [z0, s0] = stops[i - 1];\n\t\t\tconst [z1, s1] = stops[i];\n\t\t\tif (continuousZoom <= z0) break;\n\t\t\tconst t = clamp((continuousZoom - z0) / Math.max(1e-6, z1 - z0), 0, 1);\n\t\t\tsize = s0 + (s1 - s0) * t;\n\t\t}\n\n\t\tconst lastStop = stops[stops.length - 1];\n\t\tif (continuousZoom > lastStop[0]) {\n\t\t\tsize += (continuousZoom - lastStop[0]) * 4.0;\n\t\t}\n\n\t\treturn clamp(size, 2.2, 36.0);\n\t}\n\n\tfitToImage(): void {\n\t\tconst rect = this.canvas.getBoundingClientRect();\n\t\tconst vw = Math.max(1, rect.width || 1);\n\t\tconst vh = Math.max(1, rect.height || 1);\n\n\t\tconst zoom = Math.min(vw / this.source.width, vh / this.source.height);\n\t\tconst safeZoom = Number.isFinite(zoom) && zoom > 0 ? zoom : 1;\n\n\t\tthis.fitZoom = safeZoom;\n\t\tthis.minZoom = Math.max(this.fitZoom * 0.5, 1e-6);\n\t\tthis.maxZoom = Math.max(1, this.fitZoom * 8);\n\t\tif (this.minZoom > this.maxZoom) {\n\t\t\tthis.minZoom = this.maxZoom;\n\t\t}\n\n\t\tconst visibleWorldW = vw / safeZoom;\n\t\tconst visibleWorldH = vh / safeZoom;\n\n\t\tthis.camera.setViewState({\n\t\t\tzoom: clamp(safeZoom, this.minZoom, this.maxZoom),\n\t\t\toffsetX: (this.source.width - visibleWorldW) * 0.5,\n\t\t\toffsetY: (this.source.height - visibleWorldH) * 0.5,\n\t\t\trotationDeg: 0,\n\t\t});\n\n\t\tthis.clampViewState();\n\t\tthis.emitViewState();\n\t\tthis.requestRender();\n\t}\n\n\tzoomBy(factor: number, screenX: number, screenY: number): void {\n\t\tconst state = this.camera.getViewState();\n\t\tconst nextZoom = clamp(state.zoom * factor, this.minZoom, this.maxZoom);\n\t\tif (nextZoom === state.zoom) return;\n\n\t\tconst [worldX, worldY] = this.camera.screenToWorld(screenX, screenY);\n\n\t\tthis.camera.setViewState({ zoom: nextZoom });\n\n\t\tconst vp = this.camera.getViewport();\n\t\tconst dx = screenX - vp.width * 0.5;\n\t\tconst dy = screenY - vp.height * 0.5;\n\t\tconst rad = toRadians(this.camera.getViewState().rotationDeg);\n\t\tconst cos = Math.cos(rad);\n\t\tconst sin = Math.sin(rad);\n\t\tconst worldDx = (dx / nextZoom) * cos - (dy / nextZoom) * sin;\n\t\tconst worldDy = (dx / nextZoom) * sin + (dy / nextZoom) * cos;\n\t\tthis.camera.setCenter(worldX - worldDx, worldY - worldDy);\n\n\t\tthis.clampViewState();\n\t\tthis.emitViewState();\n\t\tthis.requestRender();\n\t}\n\n\tclampViewState(): void {\n\t\tconst bounds = this.getViewBounds();\n\t\tconst visibleW = Math.max(1e-6, bounds[2] - bounds[0]);\n\t\tconst visibleH = Math.max(1e-6, bounds[3] - bounds[1]);\n\t\tconst marginX = visibleW * 0.2;\n\t\tconst marginY = visibleH * 0.2;\n\n\t\tconst [centerX, centerY] = this.camera.getCenter();\n\t\tconst halfW = visibleW * 0.5;\n\t\tconst halfH = visibleH * 0.5;\n\n\t\tconst minCenterX = halfW - marginX;\n\t\tconst maxCenterX = this.source.width - halfW + marginX;\n\t\tconst minCenterY = halfH - marginY;\n\t\tconst maxCenterY = this.source.height - halfH + marginY;\n\n\t\tconst nextCenterX =\n\t\t\tminCenterX <= maxCenterX\n\t\t\t\t? clamp(centerX, minCenterX, maxCenterX)\n\t\t\t\t: this.source.width * 0.5;\n\t\tconst nextCenterY =\n\t\t\tminCenterY <= maxCenterY\n\t\t\t\t? clamp(centerY, minCenterY, maxCenterY)\n\t\t\t\t: this.source.height * 0.5;\n\n\t\tthis.camera.setCenter(nextCenterX, nextCenterY);\n\t}\n\n\temitViewState(): void {\n\t\tthis.onViewStateChange?.(this.camera.getViewState());\n\t}\n\n\tselectTier(): number {\n\t\tconst zoom = Math.max(1e-6, this.camera.getViewState().zoom);\n\t\tconst rawTier = this.source.maxTierZoom + Math.log2(zoom);\n\t\treturn clamp(Math.floor(rawTier), 0, this.source.maxTierZoom);\n\t}\n\n\tgetViewBounds(): Bounds {\n\t\tconst corners = this.camera.getViewCorners();\n\t\tlet minX = Infinity;\n\t\tlet minY = Infinity;\n\t\tlet maxX = -Infinity;\n\t\tlet maxY = -Infinity;\n\t\tfor (const [x, y] of corners) {\n\t\t\tif (x < minX) minX = x;\n\t\t\tif (x > maxX) maxX = x;\n\t\t\tif (y < minY) minY = y;\n\t\t\tif (y > maxY) maxY = y;\n\t\t}\n\t\treturn [minX, minY, maxX, maxY];\n\t}\n\n\tintersectsBounds(a: Bounds, b: Bounds): boolean {\n\t\treturn !(a[2] <= b[0] || a[0] >= b[2] || a[3] <= b[1] || a[1] >= b[3]);\n\t}\n\n\tgetVisibleTiles(): ScheduledTile[] {\n\t\tconst tier = this.selectTier();\n\t\tthis.currentTier = tier;\n\n\t\tconst viewBounds = this.getViewBounds();\n\n\t\tconst levelScale = Math.pow(2, this.source.maxTierZoom - tier);\n\t\tconst levelWidth = Math.ceil(this.source.width / levelScale);\n\t\tconst levelHeight = Math.ceil(this.source.height / levelScale);\n\n\t\tconst tilesX = Math.max(1, Math.ceil(levelWidth / this.source.tileSize));\n\t\tconst tilesY = Math.max(1, Math.ceil(levelHeight / this.source.tileSize));\n\n\t\tconst viewMinX = viewBounds[0];\n\t\tconst viewMinY = viewBounds[1];\n\t\tconst viewMaxX = viewBounds[2];\n\t\tconst viewMaxY = viewBounds[3];\n\n\t\tconst minTileX = clamp(\n\t\t\tMath.floor(viewMinX / levelScale / this.source.tileSize),\n\t\t\t0,\n\t\t\ttilesX - 1,\n\t\t);\n\t\tconst maxTileX = clamp(\n\t\t\tMath.floor((viewMaxX - 1) / levelScale / this.source.tileSize),\n\t\t\t0,\n\t\t\ttilesX - 1,\n\t\t);\n\t\tconst minTileY = clamp(\n\t\t\tMath.floor(viewMinY / levelScale / this.source.tileSize),\n\t\t\t0,\n\t\t\ttilesY - 1,\n\t\t);\n\t\tconst maxTileY = clamp(\n\t\t\tMath.floor((viewMaxY - 1) / levelScale / this.source.tileSize),\n\t\t\t0,\n\t\t\ttilesY - 1,\n\t\t);\n\n\t\tif (minTileX > maxTileX || minTileY > maxTileY) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst centerTileX = (viewMinX + viewMaxX) * 0.5 / levelScale / this.source.tileSize;\n\t\tconst centerTileY = (viewMinY + viewMaxY) * 0.5 / levelScale / this.source.tileSize;\n\n\t\tconst visible: ScheduledTile[] = [];\n\t\tfor (let y = minTileY; y <= maxTileY; y += 1) {\n\t\t\tfor (let x = minTileX; x <= maxTileX; x += 1) {\n\t\t\t\tconst left = x * this.source.tileSize * levelScale;\n\t\t\t\tconst top = y * this.source.tileSize * levelScale;\n\t\t\t\tconst right = Math.min((x + 1) * this.source.tileSize, levelWidth) * levelScale;\n\t\t\t\tconst bottom = Math.min((y + 1) * this.source.tileSize, levelHeight) * levelScale;\n\n\t\t\t\tconst dx = x - centerTileX;\n\t\t\t\tconst dy = y - centerTileY;\n\t\t\t\tvisible.push({\n\t\t\t\t\tkey: `${tier}/${x}/${y}`,\n\t\t\t\t\ttier,\n\t\t\t\t\tx,\n\t\t\t\t\ty,\n\t\t\t\t\tbounds: [left, top, right, bottom],\n\t\t\t\t\tdistance2: dx * dx + dy * dy,\n\t\t\t\t\turl: toTileUrl(this.source, tier, x, y),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tvisible.sort((a, b) => a.distance2 - b.distance2);\n\t\treturn visible;\n\t}\n\n\ttrimCache(): void {\n\t\tif (this.cache.size <= this.maxCacheTiles) return;\n\n\t\tconst entries = Array.from(this.cache.entries());\n\t\tentries.sort((a, b) => a[1].lastUsed - b[1].lastUsed);\n\n\t\tconst removeCount = this.cache.size - this.maxCacheTiles;\n\t\tfor (let i = 0; i < removeCount; i += 1) {\n\t\t\tconst [key, value] = entries[i];\n\t\t\tthis.gl.deleteTexture(value.texture);\n\t\t\tthis.cache.delete(key);\n\t\t}\n\t}\n\n\trender(): void {\n\t\tif (this.destroyed || this.contextLost || this.gl.isContextLost()) return;\n\t\tconst frameStartMs = nowMs();\n\t\tthis.frameSerial += 1;\n\n\t\tconst gl = this.gl;\n\t\tconst tileProgram = this.tileProgram;\n\t\tconst pointProgram = this.pointProgram;\n\n\t\tgl.clearColor(0.03, 0.06, 0.1, 1);\n\t\tgl.clear(gl.COLOR_BUFFER_BIT);\n\n\t\tconst visible = this.getVisibleTiles();\n\t\tconst viewBounds = this.getViewBounds();\n\t\tconst visibleKeys = new Set(visible.map((tile) => tile.key));\n\n\t\tgl.useProgram(tileProgram.program);\n\t\tgl.bindVertexArray(tileProgram.vao);\n\t\tgl.uniformMatrix3fv(tileProgram.uCamera, false, this.camera.getMatrix());\n\t\tgl.uniform1i(tileProgram.uTexture, 0);\n\n\t\tconst fallbackTiles: CachedTile[] = [];\n\t\tfor (const [, cached] of this.cache) {\n\t\t\tif (visibleKeys.has(cached.key)) continue;\n\t\t\tif (!this.intersectsBounds(cached.bounds, viewBounds)) continue;\n\t\t\tfallbackTiles.push(cached);\n\t\t}\n\n\t\tfallbackTiles.sort((a, b) => a.tier - b.tier);\n\t\tfor (const cached of fallbackTiles) {\n\t\t\tcached.lastUsed = this.frameSerial;\n\t\t\tgl.activeTexture(gl.TEXTURE0);\n\t\t\tgl.bindTexture(gl.TEXTURE_2D, cached.texture);\n\t\t\tgl.uniform4f(\n\t\t\t\ttileProgram.uBounds,\n\t\t\t\tcached.bounds[0],\n\t\t\t\tcached.bounds[1],\n\t\t\t\tcached.bounds[2],\n\t\t\t\tcached.bounds[3],\n\t\t\t);\n\t\t\tgl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);\n\t\t}\n\n\t\tlet renderedTiles = 0;\n\t\tconst missingTiles: ScheduledTile[] = [];\n\t\tfor (const tile of visible) {\n\t\t\tconst cached = this.cache.get(tile.key);\n\t\t\tif (!cached) {\n\t\t\t\tmissingTiles.push(tile);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tcached.lastUsed = this.frameSerial;\n\t\t\tgl.activeTexture(gl.TEXTURE0);\n\t\t\tgl.bindTexture(gl.TEXTURE_2D, cached.texture);\n\t\t\tgl.uniform4f(\n\t\t\t\ttileProgram.uBounds,\n\t\t\t\tcached.bounds[0],\n\t\t\t\tcached.bounds[1],\n\t\t\t\tcached.bounds[2],\n\t\t\t\tcached.bounds[3],\n\t\t\t);\n\t\t\tgl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);\n\t\t\trenderedTiles += 1;\n\t\t}\n\t\tthis.tileScheduler.schedule(missingTiles);\n\n\t\tgl.bindTexture(gl.TEXTURE_2D, null);\n\t\tgl.bindVertexArray(null);\n\n\t\tlet renderedPoints = 0;\n\t\tif (this.pointCount > 0) {\n\t\t\tgl.enable(gl.BLEND);\n\t\t\tgl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);\n\t\t\tgl.useProgram(pointProgram.program);\n\t\t\tgl.bindVertexArray(pointProgram.vao);\n\t\t\tgl.uniformMatrix3fv(pointProgram.uCamera, false, this.camera.getMatrix());\n\t\t\tgl.uniform1f(pointProgram.uPointSize, this.getPointSizeByZoom());\n\t\t\tgl.uniform1f(pointProgram.uPaletteSize, this.pointPaletteSize);\n\t\t\tgl.uniform1i(pointProgram.uPalette, 1);\n\t\t\tgl.activeTexture(gl.TEXTURE1);\n\t\t\tgl.bindTexture(gl.TEXTURE_2D, pointProgram.paletteTexture);\n\t\t\tif (this.usePointIndices) {\n\t\t\t\tgl.drawElements(gl.POINTS, this.pointCount, gl.UNSIGNED_INT, 0);\n\t\t\t} else {\n\t\t\t\tgl.drawArrays(gl.POINTS, 0, this.pointCount);\n\t\t\t}\n\t\t\tgl.bindTexture(gl.TEXTURE_2D, null);\n\t\t\tgl.bindVertexArray(null);\n\t\t\trenderedPoints = this.pointCount;\n\t\t}\n\n\t\tif (this.onStats) {\n\t\t\tconst schedulerStats = this.tileScheduler.getSnapshot();\n\t\t\tconst cacheHits = renderedTiles;\n\t\t\tconst cacheMisses = missingTiles.length;\n\t\t\tconst drawCalls =\n\t\t\t\tfallbackTiles.length + renderedTiles + (renderedPoints > 0 ? 1 : 0);\n\t\t\tthis.onStats({\n\t\t\t\ttier: this.currentTier,\n\t\t\t\tvisible: visible.length,\n\t\t\t\trendered: renderedTiles,\n\t\t\t\tpoints: renderedPoints,\n\t\t\t\tfallback: fallbackTiles.length,\n\t\t\t\tcache: this.cache.size,\n\t\t\t\tinflight: schedulerStats.inflight,\n\t\t\t\tqueued: schedulerStats.queued,\n\t\t\t\tretries: schedulerStats.retries,\n\t\t\t\tfailed: schedulerStats.failed,\n\t\t\t\taborted: schedulerStats.aborted,\n\t\t\t\tcacheHits,\n\t\t\t\tcacheMisses,\n\t\t\t\tdrawCalls,\n\t\t\t\tframeMs: nowMs() - frameStartMs,\n\t\t\t});\n\t\t}\n\t}\n\n\trequestRender(): void {\n\t\tif (\n\t\t\tthis.frame !== null ||\n\t\t\tthis.destroyed ||\n\t\t\tthis.contextLost ||\n\t\t\tthis.gl.isContextLost()\n\t\t)\n\t\t\treturn;\n\t\tthis.frame = requestAnimationFrame(() => {\n\t\t\tthis.frame = null;\n\t\t\tthis.render();\n\t\t});\n\t}\n\n\tresize(): void {\n\t\tconst rect = this.canvas.getBoundingClientRect();\n\t\tconst cssW = Math.max(1, rect.width || this.canvas.clientWidth || 1);\n\t\tconst cssH = Math.max(1, rect.height || this.canvas.clientHeight || 1);\n\t\tconst dpr = Math.max(1, window.devicePixelRatio || 1);\n\n\t\tconst pixelW = Math.max(1, Math.round(cssW * dpr));\n\t\tconst pixelH = Math.max(1, Math.round(cssH * dpr));\n\n\t\tif (this.canvas.width !== pixelW || this.canvas.height !== pixelH) {\n\t\t\tthis.canvas.width = pixelW;\n\t\t\tthis.canvas.height = pixelH;\n\t\t}\n\n\t\tthis.camera.setViewport(cssW, cssH);\n\t\tthis.gl.viewport(0, 0, pixelW, pixelH);\n\t\tthis.requestRender();\n\t}\n\n\tonPointerDown(event: PointerEvent): void {\n\t\tif (this.interactionLocked) return;\n\t\tconst wantsRotate = this.ctrlDragRotate && (event.ctrlKey || event.metaKey);\n\t\tconst allowButton = event.button === 0 || (wantsRotate && event.button === 2);\n\t\tif (!allowButton) return;\n\t\tif (wantsRotate) {\n\t\t\tevent.preventDefault();\n\t\t}\n\t\tthis.dragging = true;\n\t\tthis.interactionMode =\n\t\t\twantsRotate ? \"rotate\" : \"pan\";\n\t\tthis.pointerId = event.pointerId;\n\t\tthis.lastPointerX = event.clientX;\n\t\tthis.lastPointerY = event.clientY;\n\t\tthis.rotateLastAngleRad =\n\t\t\tthis.interactionMode === \"rotate\"\n\t\t\t\t? this.getPointerAngleRad(event.clientX, event.clientY)\n\t\t\t\t: null;\n\t\tthis.canvas.classList.add(\"dragging\");\n\t\tthis.canvas.setPointerCapture(event.pointerId);\n\t}\n\n\tonPointerMove(event: PointerEvent): void {\n\t\tif (this.interactionLocked) return;\n\t\tif (!this.dragging || event.pointerId !== this.pointerId) return;\n\n\t\tconst dx = event.clientX - this.lastPointerX;\n\t\tconst dy = event.clientY - this.lastPointerY;\n\t\tthis.lastPointerX = event.clientX;\n\t\tthis.lastPointerY = event.clientY;\n\n\t\tif (this.interactionMode === \"rotate\") {\n\t\t\tconst nextAngle = this.getPointerAngleRad(event.clientX, event.clientY);\n\t\t\tconst prevAngle = this.rotateLastAngleRad;\n\t\t\tthis.rotateLastAngleRad = nextAngle;\n\t\t\tif (prevAngle !== null) {\n\t\t\t\tconst rawDelta = nextAngle - prevAngle;\n\t\t\t\tconst delta = Math.atan2(Math.sin(rawDelta), Math.cos(rawDelta));\n\n\t\t\t\tconst sensitivityScale =\n\t\t\t\t\tDEFAULT_ROTATION_DRAG_SENSITIVITY > 0\n\t\t\t\t\t\t? this.rotationDragSensitivityDegPerPixel /\n\t\t\t\t\t\t\tDEFAULT_ROTATION_DRAG_SENSITIVITY\n\t\t\t\t\t\t: 1;\n\t\t\t\tconst state = this.camera.getViewState();\n\t\t\t\tthis.camera.setViewState({\n\t\t\t\t\trotationDeg:\n\t\t\t\t\t\tstate.rotationDeg - ((delta * 180) / Math.PI) * sensitivityScale,\n\t\t\t\t});\n\t\t\t}\n\t\t} else {\n\t\t\tconst state = this.camera.getViewState();\n\t\t\tconst zoom = Math.max(1e-6, state.zoom);\n\t\t\tconst rad = toRadians(state.rotationDeg);\n\t\t\tconst cos = Math.cos(rad);\n\t\t\tconst sin = Math.sin(rad);\n\t\t\tconst worldDx = (dx * cos - dy * sin) / zoom;\n\t\t\tconst worldDy = (dx * sin + dy * cos) / zoom;\n\t\t\tthis.camera.setViewState({\n\t\t\t\toffsetX: state.offsetX - worldDx,\n\t\t\t\toffsetY: state.offsetY - worldDy,\n\t\t\t});\n\t\t}\n\n\t\tthis.clampViewState();\n\t\tthis.emitViewState();\n\t\tthis.requestRender();\n\t}\n\n\tonPointerUp(event: PointerEvent): void {\n\t\tif (this.interactionLocked) return;\n\t\tif (event.pointerId !== this.pointerId) return;\n\t\tthis.cancelDrag();\n\t}\n\n\tonWheel(event: WheelEvent): void {\n\t\tif (this.interactionLocked) {\n\t\t\tevent.preventDefault();\n\t\t\treturn;\n\t\t}\n\n\t\tevent.preventDefault();\n\t\tconst rect = this.canvas.getBoundingClientRect();\n\t\tconst x = event.clientX - rect.left;\n\t\tconst y = event.clientY - rect.top;\n\t\tconst factor = event.deltaY < 0 ? 1.12 : 0.89;\n\t\tthis.zoomBy(factor, x, y);\n\t}\n\n\tonDoubleClick(event: MouseEvent): void {\n\t\tif (this.interactionLocked) return;\n\t\tconst rect = this.canvas.getBoundingClientRect();\n\t\tconst x = event.clientX - rect.left;\n\t\tconst y = event.clientY - rect.top;\n\t\tthis.zoomBy(event.shiftKey ? 0.8 : 1.25, x, y);\n\t}\n\n\tonContextMenu(event: MouseEvent): void {\n\t\tif (this.dragging || event.ctrlKey || event.metaKey) {\n\t\t\tevent.preventDefault();\n\t\t}\n\t}\n\n\tprivate onWebGlContextLost(event: Event): void {\n\t\tevent.preventDefault();\n\t\tif (this.destroyed || this.contextLost) return;\n\t\tthis.contextLost = true;\n\t\tthis.pointBuffersDirty = true;\n\n\t\tif (this.frame !== null) {\n\t\t\tcancelAnimationFrame(this.frame);\n\t\t\tthis.frame = null;\n\t\t}\n\n\t\tthis.cancelDrag();\n\t\tthis.tileScheduler.clear();\n\t\tthis.cache.clear();\n\t\tthis.onContextLost?.();\n\t}\n\n\tprivate onWebGlContextRestored(_event: Event): void {\n\t\tif (this.destroyed) return;\n\t\tthis.contextLost = false;\n\t\tthis.cache.clear();\n\n\t\tthis.tileProgram = this.initTileProgram();\n\t\tthis.pointProgram = this.initPointProgram();\n\t\tthis.pointBuffersDirty = true;\n\n\t\tif (this.lastPointPalette && this.lastPointPalette.length > 0) {\n\t\t\tthis.setPointPalette(this.lastPointPalette);\n\t\t}\n\t\tif (this.lastPointData) {\n\t\t\tthis.setPointData(this.lastPointData);\n\t\t} else {\n\t\t\tthis.pointCount = 0;\n\t\t}\n\n\t\tthis.resize();\n\t\tthis.requestRender();\n\t\tthis.onContextRestored?.();\n\t}\n\n\tdestroy(): void {\n\t\tif (this.destroyed) return;\n\t\tthis.destroyed = true;\n\n\t\tif (this.frame !== null) {\n\t\t\tcancelAnimationFrame(this.frame);\n\t\t\tthis.frame = null;\n\t\t}\n\n\t\tthis.resizeObserver.disconnect();\n\t\tthis.canvas.removeEventListener(\"pointerdown\", this.boundPointerDown);\n\t\tthis.canvas.removeEventListener(\"pointermove\", this.boundPointerMove);\n\t\tthis.canvas.removeEventListener(\"pointerup\", this.boundPointerUp);\n\t\tthis.canvas.removeEventListener(\"pointercancel\", this.boundPointerUp);\n\t\tthis.canvas.removeEventListener(\"wheel\", this.boundWheel);\n\t\tthis.canvas.removeEventListener(\"dblclick\", this.boundDoubleClick);\n\t\tthis.canvas.removeEventListener(\"contextmenu\", this.boundContextMenu);\n\t\tthis.canvas.removeEventListener(\"webglcontextlost\", this.boundContextLost);\n\t\tthis.canvas.removeEventListener(\n\t\t\t\"webglcontextrestored\",\n\t\t\tthis.boundContextRestored,\n\t\t);\n\t\tthis.cancelDrag();\n\t\tthis.tileScheduler.destroy();\n\n\t\tif (!this.contextLost && !this.gl.isContextLost()) {\n\t\t\tfor (const [, value] of this.cache) {\n\t\t\t\tthis.gl.deleteTexture(value.texture);\n\t\t\t}\n\t\t\tthis.gl.deleteBuffer(this.tileProgram.vbo);\n\t\t\tthis.gl.deleteVertexArray(this.tileProgram.vao);\n\t\t\tthis.gl.deleteProgram(this.tileProgram.program);\n\n\t\t\tthis.gl.deleteBuffer(this.pointProgram.posBuffer);\n\t\t\tthis.gl.deleteBuffer(this.pointProgram.termBuffer);\n\t\t\tthis.gl.deleteBuffer(this.pointProgram.indexBuffer);\n\t\t\tthis.gl.deleteTexture(this.pointProgram.paletteTexture);\n\t\t\tthis.gl.deleteVertexArray(this.pointProgram.vao);\n\t\t\tthis.gl.deleteProgram(this.pointProgram.program);\n\t\t}\n\t\tthis.cache.clear();\n\t}\n\n\tprivate initTileProgram(): TileVertexProgram {\n\t\tconst gl = this.gl;\n\n\t\tconst vertex = `#version 300 es\n precision highp float;\n in vec2 aUnit;\n in vec2 aUv;\n uniform mat3 uCamera;\n uniform vec4 uBounds;\n out vec2 vUv;\n void main() {\n vec2 world = vec2(\n mix(uBounds.x, uBounds.z, aUnit.x),\n mix(uBounds.y, uBounds.w, aUnit.y)\n );\n vec3 clip = uCamera * vec3(world, 1.0);\n gl_Position = vec4(clip.xy, 0.0, 1.0);\n vUv = aUv;\n }`;\n\n\t\tconst fragment = `#version 300 es\n precision highp float;\n in vec2 vUv;\n uniform sampler2D uTexture;\n out vec4 outColor;\n void main() {\n outColor = texture(uTexture, vUv);\n }`;\n\n\t\tconst program = createProgram(gl, vertex, fragment);\n\t\tconst uCamera = requireUniformLocation(gl, program, \"uCamera\");\n\t\tconst uBounds = requireUniformLocation(gl, program, \"uBounds\");\n\t\tconst uTexture = requireUniformLocation(gl, program, \"uTexture\");\n\n\t\tconst vao = gl.createVertexArray();\n\t\tconst vbo = gl.createBuffer();\n\t\tif (!vao || !vbo) {\n\t\t\tthrow new Error(\"buffer allocation failed\");\n\t\t}\n\n\t\tgl.bindVertexArray(vao);\n\t\tgl.bindBuffer(gl.ARRAY_BUFFER, vbo);\n\t\tgl.bufferData(\n\t\t\tgl.ARRAY_BUFFER,\n\t\t\tnew Float32Array([0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1]),\n\t\t\tgl.STATIC_DRAW,\n\t\t);\n\n\t\tconst aUnit = gl.getAttribLocation(program, \"aUnit\");\n\t\tconst aUv = gl.getAttribLocation(program, \"aUv\");\n\t\tif (aUnit < 0 || aUv < 0) {\n\t\t\tthrow new Error(\"tile attribute lookup failed\");\n\t\t}\n\t\tgl.enableVertexAttribArray(aUnit);\n\t\tgl.enableVertexAttribArray(aUv);\n\t\tgl.vertexAttribPointer(aUnit, 2, gl.FLOAT, false, 16, 0);\n\t\tgl.vertexAttribPointer(aUv, 2, gl.FLOAT, false, 16, 8);\n\n\t\tgl.bindVertexArray(null);\n\t\tgl.bindBuffer(gl.ARRAY_BUFFER, null);\n\n\t\treturn { program, vao, vbo, uCamera, uBounds, uTexture };\n\t}\n\n\tprivate initPointProgram(): PointProgram {\n\t\tconst gl = this.gl;\n\n\t\tconst pointVertex = `#version 300 es\n precision highp float;\n in vec2 aPosition;\n in uint aTerm;\n uniform mat3 uCamera;\n uniform float uPointSize;\n flat out uint vTerm;\n void main() {\n vec3 clip = uCamera * vec3(aPosition, 1.0);\n gl_Position = vec4(clip.xy, 0.0, 1.0);\n gl_PointSize = uPointSize;\n vTerm = aTerm;\n }`;\n\n\t\tconst pointFragment = `#version 300 es\n precision highp float;\n flat in uint vTerm;\n uniform sampler2D uPalette;\n uniform float uPaletteSize;\n uniform float uPointSize;\n out vec4 outColor;\n void main() {\n vec2 pc = gl_PointCoord * 2.0 - 1.0;\n float r = length(pc);\n if (r > 1.0) discard;\n\n float idx = clamp(float(vTerm), 0.0, max(0.0, uPaletteSize - 1.0));\n vec2 uv = vec2((idx + 0.5) / uPaletteSize, 0.5);\n vec4 color = texture(uPalette, uv);\n if (color.a <= 0.0) discard;\n\n float ringWidth = clamp(3.0 / max(1.0, uPointSize), 0.12, 0.62);\n float innerRadius = 1.0 - ringWidth;\n float aa = 1.5 / max(1.0, uPointSize);\n\n float outerMask = 1.0 - smoothstep(1.0 - aa, 1.0 + aa, r);\n float innerMask = smoothstep(innerRadius - aa, innerRadius + aa, r);\n float alpha = outerMask * innerMask * color.a;\n if (alpha <= 0.001) discard;\n\n outColor = vec4(color.rgb * alpha, alpha);\n }`;\n\n\t\tconst program = createProgram(gl, pointVertex, pointFragment);\n\t\tconst uCamera = requireUniformLocation(gl, program, \"uCamera\");\n\t\tconst uPointSize = requireUniformLocation(gl, program, \"uPointSize\");\n\t\tconst uPalette = requireUniformLocation(gl, program, \"uPalette\");\n\t\tconst uPaletteSize = requireUniformLocation(gl, program, \"uPaletteSize\");\n\n\t\tconst vao = gl.createVertexArray();\n\t\tconst posBuffer = gl.createBuffer();\n\t\tconst termBuffer = gl.createBuffer();\n\t\tconst indexBuffer = gl.createBuffer();\n\t\tconst paletteTexture = gl.createTexture();\n\t\tif (!vao || !posBuffer || !termBuffer || !indexBuffer || !paletteTexture) {\n\t\t\tthrow new Error(\"point buffer allocation failed\");\n\t\t}\n\n\t\tgl.bindVertexArray(vao);\n\n\t\tgl.bindBuffer(gl.ARRAY_BUFFER, posBuffer);\n\t\tgl.bufferData(gl.ARRAY_BUFFER, 0, gl.DYNAMIC_DRAW);\n\t\tconst posLoc = gl.getAttribLocation(program, \"aPosition\");\n\t\tif (posLoc < 0) {\n\t\t\tthrow new Error(\"point position attribute not found\");\n\t\t}\n\t\tgl.enableVertexAttribArray(posLoc);\n\t\tgl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, 0, 0);\n\n\t\tgl.bindBuffer(gl.ARRAY_BUFFER, termBuffer);\n\t\tgl.bufferData(gl.ARRAY_BUFFER, 0, gl.DYNAMIC_DRAW);\n\t\tconst termLoc = gl.getAttribLocation(program, \"aTerm\");\n\t\tif (termLoc < 0) {\n\t\t\tthrow new Error(\"point term attribute not found\");\n\t\t}\n\t\tgl.enableVertexAttribArray(termLoc);\n\t\tgl.vertexAttribIPointer(termLoc, 1, gl.UNSIGNED_SHORT, 0, 0);\n\n\t\tgl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);\n\t\tgl.bufferData(gl.ELEMENT_ARRAY_BUFFER, 0, gl.DYNAMIC_DRAW);\n\n\t\tgl.bindVertexArray(null);\n\t\tgl.bindBuffer(gl.ARRAY_BUFFER, null);\n\t\tgl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);\n\n\t\tgl.bindTexture(gl.TEXTURE_2D, paletteTexture);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n\t\tgl.texImage2D(\n\t\t\tgl.TEXTURE_2D,\n\t\t\t0,\n\t\t\tgl.RGBA,\n\t\t\t1,\n\t\t\t1,\n\t\t\t0,\n\t\t\tgl.RGBA,\n\t\t\tgl.UNSIGNED_BYTE,\n\t\t\tnew Uint8Array([160, 160, 160, 255]),\n\t\t);\n\t\tgl.bindTexture(gl.TEXTURE_2D, null);\n\n\t\treturn {\n\t\t\tprogram,\n\t\t\tvao,\n\t\t\tposBuffer,\n\t\t\ttermBuffer,\n\t\t\tindexBuffer,\n\t\t\tpaletteTexture,\n\t\t\tuCamera,\n\t\t\tuPointSize,\n\t\t\tuPalette,\n\t\t\tuPaletteSize,\n\t\t};\n\t}\n\n\tprivate handleTileLoaded(tile: ScheduledTile, bitmap: ImageBitmap): void {\n\t\tif (this.destroyed || this.contextLost || this.gl.isContextLost()) {\n\t\t\tbitmap.close();\n\t\t\treturn;\n\t\t}\n\t\tif (this.cache.has(tile.key)) {\n\t\t\tbitmap.close();\n\t\t\treturn;\n\t\t}\n\n\t\tconst texture = this.createTextureFromBitmap(bitmap);\n\t\tbitmap.close();\n\t\tif (!texture) return;\n\n\t\tthis.cache.set(tile.key, {\n\t\t\tkey: tile.key,\n\t\t\ttexture,\n\t\t\tbounds: tile.bounds,\n\t\t\ttier: tile.tier,\n\t\t\tlastUsed: this.frameSerial,\n\t\t});\n\t\tthis.trimCache();\n\t\tthis.requestRender();\n\t}\n\n\tprivate createTextureFromBitmap(bitmap: ImageBitmap): WebGLTexture | null {\n\t\tif (this.contextLost || this.gl.isContextLost()) return null;\n\t\tconst gl = this.gl;\n\t\tconst texture = gl.createTexture();\n\t\tif (!texture) return null;\n\n\t\tgl.bindTexture(gl.TEXTURE_2D, texture);\n\t\tgl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n\t\tgl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, bitmap);\n\t\tgl.bindTexture(gl.TEXTURE_2D, null);\n\t\treturn texture;\n\t}\n}\n","import { type CSSProperties, type MouseEvent as ReactMouseEvent, type PointerEvent as ReactPointerEvent, useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { filterPointDataByPolygons, type RoiPolygon } from \"../wsi/point-clip\";\nimport { filterPointDataByPolygonsHybrid } from \"../wsi/point-clip-hybrid\";\nimport { filterPointDataByPolygonsInWorker, type PointClipMode } from \"../wsi/point-clip-worker-client\";\nimport { computeRoiPointGroups, type RoiPointGroupStats } from \"../wsi/roi-term-stats\";\nimport type { WsiImageSource, WsiPointData, WsiRegion, WsiRenderStats, WsiViewState } from \"../wsi/types\";\nimport { type WsiTileErrorEvent, WsiTileRenderer } from \"../wsi/wsi-tile-renderer\";\nimport type { DrawCoordinate, DrawOverlayShape, DrawResult, DrawTool, RegionLabelStyle, RegionStrokeStyle, RegionStrokeStyleResolver, StampOptions } from \"./draw-layer\";\nimport { DrawLayer } from \"./draw-layer\";\nimport { OverviewMap, type OverviewMapOptions } from \"./overview-map\";\n\nconst EMPTY_ROI_REGIONS: WsiRegion[] = [];\nconst EMPTY_ROI_POLYGONS: DrawCoordinate[][] = [];\nconst EMPTY_CLIPPED_POINTS: WsiPointData = {\n count: 0,\n positions: new Float32Array(0),\n paletteIndices: new Uint16Array(0),\n};\n\nexport interface RegionHoverEvent {\n region: WsiRegion | null;\n regionId: string | number | null;\n regionIndex: number;\n coordinate: DrawCoordinate | null;\n}\n\nexport interface RegionClickEvent {\n region: WsiRegion;\n regionId: string | number;\n regionIndex: number;\n coordinate: DrawCoordinate;\n}\n\nexport interface PointClipStatsEvent {\n mode: PointClipMode;\n durationMs: number;\n inputCount: number;\n outputCount: number;\n polygonCount: number;\n usedWebGpu?: boolean;\n candidateCount?: number;\n bridgedToDraw?: boolean;\n}\n\nexport interface PointerWorldMoveEvent {\n coordinate: DrawCoordinate | null;\n clientX: number;\n clientY: number;\n insideImage: boolean;\n}\n\nfunction resolveRegionId(region: WsiRegion, index: number): string | number {\n return region.id ?? index;\n}\n\nfunction isPointInPolygon(point: DrawCoordinate, polygon: DrawCoordinate[]): boolean {\n if (!Array.isArray(polygon) || polygon.length < 3) return false;\n\n const [x, y] = point;\n let inside = false;\n\n for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {\n const [xi, yi] = polygon[i];\n const [xj, yj] = polygon[j];\n const intersect = yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / Math.max(1e-12, yj - yi) + xi;\n if (intersect) inside = !inside;\n }\n\n return inside;\n}\n\nfunction pickRegionAt(\n coord: DrawCoordinate,\n regions: WsiRegion[]\n): {\n region: WsiRegion;\n regionIndex: number;\n regionId: string | number;\n} | null {\n for (let i = regions.length - 1; i >= 0; i -= 1) {\n const region = regions[i];\n if (!region?.coordinates?.length) continue;\n if (!isPointInPolygon(coord, region.coordinates)) continue;\n return {\n region,\n regionIndex: i,\n regionId: resolveRegionId(region, i),\n };\n }\n return null;\n}\n\nexport interface WsiViewerCanvasProps {\n source: WsiImageSource | null;\n viewState?: Partial<WsiViewState> | null;\n onViewStateChange?: (next: WsiViewState) => void;\n onStats?: (stats: WsiRenderStats) => void;\n onTileError?: (event: WsiTileErrorEvent) => void;\n onContextLost?: () => void;\n onContextRestored?: () => void;\n debugOverlay?: boolean;\n debugOverlayStyle?: CSSProperties;\n fitNonce?: number;\n rotationResetNonce?: number;\n authToken?: string;\n ctrlDragRotate?: boolean;\n pointData?: WsiPointData | null;\n pointPalette?: Uint8Array | null;\n roiRegions?: WsiRegion[];\n roiPolygons?: DrawCoordinate[][];\n clipPointsToRois?: boolean;\n clipMode?: PointClipMode;\n onClipStats?: (event: PointClipStatsEvent) => void;\n onRoiPointGroups?: (stats: RoiPointGroupStats) => void;\n roiPaletteIndexToTermId?: ReadonlyMap<number, string> | readonly string[];\n interactionLock?: boolean;\n drawTool?: DrawTool;\n stampOptions?: StampOptions;\n regionStrokeStyle?: Partial<RegionStrokeStyle>;\n regionStrokeHoverStyle?: Partial<RegionStrokeStyle>;\n regionStrokeActiveStyle?: Partial<RegionStrokeStyle>;\n resolveRegionStrokeStyle?: RegionStrokeStyleResolver;\n overlayShapes?: DrawOverlayShape[];\n regionLabelStyle?: Partial<RegionLabelStyle>;\n onPointerWorldMove?: (event: PointerWorldMoveEvent) => void;\n onRegionHover?: (event: RegionHoverEvent) => void;\n onRegionClick?: (event: RegionClickEvent) => void;\n onActiveRegionChange?: (regionId: string | number | null) => void;\n onDrawComplete?: (result: DrawResult) => void;\n showOverviewMap?: boolean;\n overviewMapOptions?: Partial<OverviewMapOptions>;\n className?: string;\n style?: CSSProperties;\n}\n\nexport function WsiViewerCanvas({\n source,\n viewState,\n onViewStateChange,\n onStats,\n onTileError,\n onContextLost,\n onContextRestored,\n debugOverlay = false,\n debugOverlayStyle,\n fitNonce = 0,\n rotationResetNonce = 0,\n authToken = \"\",\n ctrlDragRotate = true,\n pointData = null,\n pointPalette = null,\n roiRegions,\n roiPolygons,\n clipPointsToRois = false,\n clipMode = \"worker\",\n onClipStats,\n onRoiPointGroups,\n roiPaletteIndexToTermId,\n interactionLock = false,\n drawTool = \"cursor\",\n stampOptions,\n regionStrokeStyle,\n regionStrokeHoverStyle,\n regionStrokeActiveStyle,\n resolveRegionStrokeStyle,\n overlayShapes,\n regionLabelStyle,\n onPointerWorldMove,\n onRegionHover,\n onRegionClick,\n onActiveRegionChange,\n onDrawComplete,\n showOverviewMap = false,\n overviewMapOptions,\n className,\n style,\n}: WsiViewerCanvasProps): React.ReactElement {\n const canvasRef = useRef<HTMLCanvasElement | null>(null);\n const rendererRef = useRef<WsiTileRenderer | null>(null);\n const drawInvalidateRef = useRef<(() => void) | null>(null);\n const overviewInvalidateRef = useRef<(() => void) | null>(null);\n const onViewStateChangeRef = useRef<typeof onViewStateChange>(onViewStateChange);\n const onStatsRef = useRef<typeof onStats>(onStats);\n const debugOverlayRef = useRef(debugOverlay);\n const [isOverviewOpen, setIsOverviewOpen] = useState(true);\n const [hoveredRegionId, setHoveredRegionId] = useState<string | number | null>(null);\n const [activeRegionId, setActiveRegionId] = useState<string | number | null>(null);\n const [debugStats, setDebugStats] = useState<WsiRenderStats | null>(null);\n const hoveredRegionIdRef = useRef<string | number | null>(null);\n const clipRunIdRef = useRef(0);\n const safeRoiRegions = roiRegions ?? EMPTY_ROI_REGIONS;\n const safeRoiPolygons = roiPolygons ?? EMPTY_ROI_POLYGONS;\n\n const mergedStyle = useMemo<CSSProperties>(() => ({ position: \"relative\", width: \"100%\", height: \"100%\", ...style }), [style]);\n const mergedDebugOverlayStyle = useMemo<CSSProperties>(\n () => ({\n position: \"absolute\",\n top: 8,\n left: 8,\n zIndex: 7,\n margin: 0,\n padding: \"8px 10px\",\n maxWidth: \"min(420px, 80%)\",\n pointerEvents: \"none\",\n whiteSpace: \"pre-wrap\",\n lineHeight: 1.35,\n fontFamily: \"ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace\",\n fontSize: 11,\n color: \"#cde6ff\",\n background: \"rgba(6, 12, 20, 0.82)\",\n border: \"1px solid rgba(173, 216, 255, 0.28)\",\n borderRadius: 8,\n boxShadow: \"0 8px 22px rgba(0,0,0,0.35)\",\n ...debugOverlayStyle,\n }),\n [debugOverlayStyle]\n );\n\n const effectiveRoiRegions = useMemo<WsiRegion[]>(() => {\n if (safeRoiRegions.length > 0) {\n return safeRoiRegions;\n }\n if (safeRoiPolygons.length === 0) {\n return EMPTY_ROI_REGIONS;\n }\n return safeRoiPolygons.map((coordinates, index) => ({\n id: index,\n coordinates,\n }));\n }, [safeRoiRegions, safeRoiPolygons]);\n\n const clipPolygons = useMemo(() => effectiveRoiRegions.map(region => region.coordinates), [effectiveRoiRegions]);\n\n const [renderPointData, setRenderPointData] = useState<WsiPointData | null>(pointData);\n\n useEffect(() => {\n const runId = ++clipRunIdRef.current;\n let cancelled = false;\n\n if (!clipPointsToRois) {\n setRenderPointData(pointData);\n return () => {\n cancelled = true;\n };\n }\n\n if (!pointData || !pointData.count || !pointData.positions || !pointData.paletteIndices) {\n setRenderPointData(null);\n return () => {\n cancelled = true;\n };\n }\n\n if (clipPolygons.length === 0) {\n setRenderPointData(EMPTY_CLIPPED_POINTS);\n onClipStats?.({\n mode: clipMode,\n durationMs: 0,\n inputCount: pointData.count,\n outputCount: 0,\n polygonCount: 0,\n });\n return () => {\n cancelled = true;\n };\n }\n\n const applyResult = (\n data: WsiPointData | null,\n stats: Omit<PointClipStatsEvent, \"inputCount\" | \"outputCount\" | \"polygonCount\">\n ) => {\n if (cancelled || runId !== clipRunIdRef.current) return;\n const outputCount = data?.drawIndices ? data.drawIndices.length : data?.count ?? 0;\n setRenderPointData(data);\n onClipStats?.({\n mode: stats.mode,\n durationMs: stats.durationMs,\n inputCount: pointData.count,\n outputCount,\n polygonCount: clipPolygons.length,\n usedWebGpu: stats.usedWebGpu,\n candidateCount: stats.candidateCount,\n bridgedToDraw: stats.bridgedToDraw,\n });\n };\n\n const run = async (): Promise<void> => {\n if (clipMode === \"sync\") {\n const start = performance.now();\n const data = filterPointDataByPolygons(pointData, clipPolygons);\n applyResult(data, {\n mode: \"sync\",\n durationMs: performance.now() - start,\n });\n return;\n }\n\n if (clipMode === \"hybrid-webgpu\") {\n const result = await filterPointDataByPolygonsHybrid(\n pointData,\n clipPolygons as RoiPolygon[],\n { bridgeToDraw: true }\n );\n applyResult(result.data, {\n mode: result.meta.mode,\n durationMs: result.meta.durationMs,\n usedWebGpu: result.meta.usedWebGpu,\n candidateCount: result.meta.candidateCount,\n bridgedToDraw: result.meta.bridgedToDraw,\n });\n return;\n }\n\n try {\n const result = await filterPointDataByPolygonsInWorker(pointData, clipPolygons as RoiPolygon[]);\n applyResult(result.data, {\n mode: result.meta.mode,\n durationMs: result.meta.durationMs,\n });\n } catch {\n const start = performance.now();\n const data = filterPointDataByPolygons(pointData, clipPolygons);\n applyResult(data, {\n mode: \"sync\",\n durationMs: performance.now() - start,\n });\n }\n };\n\n void run();\n return () => {\n cancelled = true;\n };\n }, [clipPointsToRois, clipMode, pointData, clipPolygons, onClipStats]);\n\n const overviewWidth = useMemo(() => {\n const value = Number(overviewMapOptions?.width ?? 220);\n return Number.isFinite(value) ? Math.max(64, value) : 220;\n }, [overviewMapOptions?.width]);\n const overviewHeight = useMemo(() => {\n const value = Number(overviewMapOptions?.height ?? 140);\n return Number.isFinite(value) ? Math.max(48, value) : 140;\n }, [overviewMapOptions?.height]);\n const overviewMargin = useMemo(() => {\n const value = Number(overviewMapOptions?.margin ?? 16);\n return Number.isFinite(value) ? Math.max(0, value) : 16;\n }, [overviewMapOptions?.margin]);\n const overviewPosition = overviewMapOptions?.position || \"bottom-right\";\n\n const commitActiveRegion = useCallback(\n (next: string | number | null) => {\n setActiveRegionId(prev => {\n if (String(prev) === String(next)) {\n return prev;\n }\n onActiveRegionChange?.(next);\n return next;\n });\n },\n [onActiveRegionChange]\n );\n\n useEffect(() => {\n onViewStateChangeRef.current = onViewStateChange;\n }, [onViewStateChange]);\n\n useEffect(() => {\n onStatsRef.current = onStats;\n }, [onStats]);\n\n useEffect(() => {\n debugOverlayRef.current = debugOverlay;\n if (!debugOverlay) setDebugStats(null);\n }, [debugOverlay]);\n\n const handleRendererStats = useCallback((stats: WsiRenderStats): void => {\n onStatsRef.current?.(stats);\n if (debugOverlayRef.current) {\n setDebugStats(stats);\n }\n }, []);\n\n const debugOverlayText = useMemo(() => {\n if (!debugStats) {\n return \"stats: waiting for first frame...\";\n }\n return [\n `tier ${debugStats.tier} | frame ${debugStats.frameMs?.toFixed(2) ?? \"-\"} ms | drawCalls ${debugStats.drawCalls ?? \"-\"}`,\n `tiles visible ${debugStats.visible} | rendered ${debugStats.rendered} | fallback ${debugStats.fallback}`,\n `cache size ${debugStats.cache} | hit ${debugStats.cacheHits ?? \"-\"} | miss ${debugStats.cacheMisses ?? \"-\"}`,\n `queue inflight ${debugStats.inflight} | queued ${debugStats.queued ?? \"-\"} | retries ${debugStats.retries ?? \"-\"} | failed ${debugStats.failed ?? \"-\"} | aborted ${debugStats.aborted ?? \"-\"}`,\n `points ${debugStats.points}`,\n ].join(\"\\n\");\n }, [debugStats]);\n\n useEffect(() => {\n const hasActive = activeRegionId === null ? true : effectiveRoiRegions.some((region, index) => String(resolveRegionId(region, index)) === String(activeRegionId));\n if (!hasActive && activeRegionId !== null) {\n commitActiveRegion(null);\n }\n\n const currentHover = hoveredRegionIdRef.current;\n const hasHover = currentHover === null ? true : effectiveRoiRegions.some((region, index) => String(resolveRegionId(region, index)) === String(currentHover));\n\n if (!hasHover && currentHover !== null) {\n hoveredRegionIdRef.current = null;\n setHoveredRegionId(null);\n onRegionHover?.({\n region: null,\n regionId: null,\n regionIndex: -1,\n coordinate: null,\n });\n }\n }, [effectiveRoiRegions, activeRegionId, onRegionHover, commitActiveRegion]);\n\n const emitViewStateChange = useCallback((next: WsiViewState): void => {\n const callback = onViewStateChangeRef.current;\n if (callback) {\n callback(next);\n }\n drawInvalidateRef.current?.();\n overviewInvalidateRef.current?.();\n }, []);\n\n useEffect(() => {\n if (!showOverviewMap) {\n setIsOverviewOpen(false);\n return;\n }\n setIsOverviewOpen(true);\n }, [showOverviewMap, source?.id]);\n\n useEffect(() => {\n if (drawTool === \"cursor\") return;\n if (hoveredRegionIdRef.current === null) return;\n hoveredRegionIdRef.current = null;\n setHoveredRegionId(null);\n onRegionHover?.({\n region: null,\n regionId: null,\n regionIndex: -1,\n coordinate: null,\n });\n }, [drawTool, onRegionHover]);\n\n const resolveWorldCoord = useCallback((clientX: number, clientY: number): DrawCoordinate | null => {\n const renderer = rendererRef.current;\n if (!renderer) return null;\n const raw = renderer.screenToWorld(clientX, clientY);\n if (!Array.isArray(raw) || raw.length < 2) return null;\n const x = Number(raw[0]);\n const y = Number(raw[1]);\n if (!Number.isFinite(x) || !Number.isFinite(y)) return null;\n return [x, y];\n }, []);\n\n const handleRegionPointerMove = useCallback(\n (event: ReactPointerEvent<HTMLDivElement>) => {\n const isCanvasEvent = event.target === canvasRef.current;\n const coord = resolveWorldCoord(event.clientX, event.clientY);\n if (onPointerWorldMove) {\n const insideImage = !!coord && coord[0] >= 0 && coord[1] >= 0 && !!source && coord[0] <= source.width && coord[1] <= source.height;\n onPointerWorldMove({\n coordinate: coord,\n clientX: event.clientX,\n clientY: event.clientY,\n insideImage,\n });\n }\n\n if (drawTool !== \"cursor\") return;\n if (!isCanvasEvent) {\n if (hoveredRegionIdRef.current !== null) {\n hoveredRegionIdRef.current = null;\n setHoveredRegionId(null);\n onRegionHover?.({\n region: null,\n regionId: null,\n regionIndex: -1,\n coordinate: null,\n });\n }\n return;\n }\n if (!coord) return;\n if (!effectiveRoiRegions.length) return;\n\n const hit = pickRegionAt(coord, effectiveRoiRegions);\n const nextHoverId = hit?.regionId ?? null;\n const prevHoverId = hoveredRegionIdRef.current;\n if (String(prevHoverId) === String(nextHoverId)) return;\n\n hoveredRegionIdRef.current = nextHoverId;\n setHoveredRegionId(nextHoverId);\n onRegionHover?.({\n region: hit?.region ?? null,\n regionId: nextHoverId,\n regionIndex: hit?.regionIndex ?? -1,\n coordinate: coord,\n });\n },\n [drawTool, effectiveRoiRegions, resolveWorldCoord, onRegionHover, onPointerWorldMove, source]\n );\n\n const handleRegionPointerLeave = useCallback(() => {\n onPointerWorldMove?.({\n coordinate: null,\n clientX: -1,\n clientY: -1,\n insideImage: false,\n });\n if (hoveredRegionIdRef.current === null) return;\n hoveredRegionIdRef.current = null;\n setHoveredRegionId(null);\n onRegionHover?.({\n region: null,\n regionId: null,\n regionIndex: -1,\n coordinate: null,\n });\n }, [onRegionHover, onPointerWorldMove]);\n\n const handleRegionClick = useCallback(\n (event: ReactMouseEvent<HTMLDivElement>) => {\n if (drawTool !== \"cursor\") return;\n if (event.target !== canvasRef.current) return;\n if (!effectiveRoiRegions.length) {\n commitActiveRegion(null);\n return;\n }\n\n const coord = resolveWorldCoord(event.clientX, event.clientY);\n if (!coord) return;\n\n const hit = pickRegionAt(coord, effectiveRoiRegions);\n if (!hit) {\n commitActiveRegion(null);\n return;\n }\n\n const nextActive: string | number | null = activeRegionId !== null && String(activeRegionId) === String(hit.regionId) ? null : hit.regionId;\n commitActiveRegion(nextActive);\n onRegionClick?.({\n region: hit.region,\n regionId: hit.regionId,\n regionIndex: hit.regionIndex,\n coordinate: coord,\n });\n },\n [drawTool, effectiveRoiRegions, resolveWorldCoord, onRegionClick, activeRegionId, commitActiveRegion]\n );\n\n useEffect(() => {\n const canvas = canvasRef.current;\n if (!canvas || !source) {\n return;\n }\n\n const renderer = new WsiTileRenderer(canvas, source, {\n onViewStateChange: emitViewStateChange,\n onStats: handleRendererStats,\n onTileError,\n onContextLost,\n onContextRestored,\n authToken,\n ctrlDragRotate,\n });\n\n rendererRef.current = renderer;\n if (viewState) {\n renderer.setViewState(viewState);\n }\n renderer.setInteractionLock(interactionLock);\n\n return () => {\n renderer.destroy();\n rendererRef.current = null;\n };\n }, [source, handleRendererStats, onTileError, onContextLost, onContextRestored, authToken, ctrlDragRotate, emitViewStateChange]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer || !viewState) {\n return;\n }\n renderer.setViewState(viewState);\n }, [viewState]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) {\n return;\n }\n renderer.fitToImage();\n }, [fitNonce]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) return;\n renderer.resetRotation();\n }, [rotationResetNonce]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer || !pointPalette) {\n return;\n }\n renderer.setPointPalette(pointPalette);\n }, [pointPalette]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) {\n return;\n }\n renderer.setPointData(renderPointData);\n }, [renderPointData]);\n\n useEffect(() => {\n if (!onRoiPointGroups) return;\n const sourcePoints = clipPointsToRois ? renderPointData : pointData;\n const stats = computeRoiPointGroups(sourcePoints, effectiveRoiRegions, {\n paletteIndexToTermId: roiPaletteIndexToTermId,\n includeEmptyRegions: true,\n });\n onRoiPointGroups(stats);\n }, [onRoiPointGroups, clipPointsToRois, pointData, renderPointData, effectiveRoiRegions, roiPaletteIndexToTermId]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) {\n return;\n }\n renderer.setInteractionLock(interactionLock);\n }, [interactionLock]);\n\n return (\n <div className={className} style={mergedStyle} onPointerMove={handleRegionPointerMove} onPointerLeave={handleRegionPointerLeave} onClick={handleRegionClick}>\n <canvas\n ref={canvasRef}\n className=\"wsi-render-canvas\"\n style={{\n position: \"absolute\",\n inset: 0,\n zIndex: 1,\n width: \"100%\",\n height: \"100%\",\n display: \"block\",\n touchAction: \"none\",\n cursor: drawTool === \"cursor\" && hoveredRegionId !== null ? \"pointer\" : interactionLock ? \"crosshair\" : \"grab\",\n }}\n />\n {source ? (\n <DrawLayer\n tool={drawTool}\n enabled={drawTool !== \"cursor\"}\n imageWidth={source.width}\n imageHeight={source.height}\n imageMpp={source.mpp}\n imageZoom={source.maxTierZoom}\n stampOptions={stampOptions}\n projectorRef={rendererRef}\n viewStateSignal={viewState}\n persistedRegions={effectiveRoiRegions}\n regionStrokeStyle={regionStrokeStyle}\n regionStrokeHoverStyle={regionStrokeHoverStyle}\n regionStrokeActiveStyle={regionStrokeActiveStyle}\n resolveRegionStrokeStyle={resolveRegionStrokeStyle}\n overlayShapes={overlayShapes}\n hoveredRegionId={hoveredRegionId}\n activeRegionId={activeRegionId}\n regionLabelStyle={regionLabelStyle}\n invalidateRef={drawInvalidateRef}\n onDrawComplete={onDrawComplete}\n />\n ) : null}\n {debugOverlay ? (\n <pre data-open-plant-debug-overlay style={mergedDebugOverlayStyle}>\n {debugOverlayText}\n </pre>\n ) : null}\n {source && showOverviewMap ? (\n isOverviewOpen ? (\n <>\n <OverviewMap source={source} projectorRef={rendererRef} authToken={authToken} options={overviewMapOptions} invalidateRef={overviewInvalidateRef} />\n <button\n type=\"button\"\n aria-label=\"Hide overview map\"\n onClick={() => setIsOverviewOpen(false)}\n style={{\n position: \"absolute\",\n zIndex: 6,\n ...(overviewPosition.includes(\"left\") ? { left: overviewMargin } : { right: overviewMargin }),\n ...(overviewPosition.includes(\"top\") ? { top: overviewMargin + overviewHeight + 8 } : { bottom: overviewMargin + overviewHeight + 8 }),\n width: 20,\n height: 20,\n borderRadius: 999,\n border: \"1px solid rgba(255,255,255,0.4)\",\n background: \"rgba(8, 14, 22, 0.9)\",\n color: \"#fff\",\n fontSize: 13,\n lineHeight: 1,\n cursor: \"pointer\",\n padding: 0,\n }}\n >\n ×\n </button>\n </>\n ) : (\n <button\n type=\"button\"\n aria-label=\"Show overview map\"\n onClick={() => setIsOverviewOpen(true)}\n style={{\n position: \"absolute\",\n zIndex: 6,\n ...(overviewPosition.includes(\"left\") ? { left: overviewMargin } : { right: overviewMargin }),\n ...(overviewPosition.includes(\"top\") ? { top: overviewMargin } : { bottom: overviewMargin }),\n height: 24,\n minWidth: 40,\n borderRadius: 999,\n border: \"1px solid rgba(255,255,255,0.45)\",\n background: \"rgba(8, 14, 22, 0.9)\",\n color: \"#dff8ff\",\n fontSize: 11,\n fontWeight: 700,\n cursor: \"pointer\",\n padding: \"0 8px\",\n }}\n >\n Map\n </button>\n )\n ) : null}\n </div>\n );\n}\n"],"names":["compileShader","gl","type","source","shader","log","createProgram","vertexSource","fragmentSource","vertexShader","fragmentShader","program","requireUniformLocation","uniformName","location","requireWebGL2","canvas","context","OrthoCamera$1","__publicField","width","height","next","viewWidth","viewHeight","sx","sy","tx","ty","VERTEX_SHADER","FRAGMENT_SHADER","M1TileRenderer","options","OrthoCamera","vao","quadBuffer","quadVertices","unitLocation","uvLocation","stride","tiles","version","loaded","tile","viewState","response","blob","bitmap","texture","error","rect","cssWidth","cssHeight","dpr","targetWidth","targetHeight","viewport","zoom","safeZoom","visibleWorldWidth","visibleWorldHeight","offsetX","offsetY","DEFAULT_POINT_COLOR","clamp","value","min","max","calcScaleResolution","imageMpp","imageZoom","currentZoom","mpp","z0","z1","calcScaleLength","length","unit","isSameViewState","a","b","toBearerToken","trimmed","token","hexToRgba","hex","match","n","buildTermPalette","terms","palette","termToPaletteIndex","term","termId","colors","vs","fs","DRAW_FILL","FREEHAND_MIN_POINTS","FREEHAND_SCREEN_STEP","CIRCLE_SIDES","MIN_AREA_PX","EMPTY_REGIONS","EMPTY_DASH","MICRONS_PER_MM","DEFAULT_STAMP_RECTANGLE_AREA_MM2","DEFAULT_STAMP_CIRCLE_AREA_MM2","DEFAULT_STAMP_RECTANGLE_PIXEL_SIZE","LEGACY_HPF_CIRCLE_AREA_MM2","DEFAULT_REGION_STROKE_STYLE","DEFAULT_REGION_LABEL_STYLE","isStampTool","tool","clampPositiveOrFallback","fallback","resolveStampOptions","mm2ToUm2","areaMm2","createSquareFromCenter","center","halfLength","closeRing","createCircleFromCenter","radius","sides","coords","t","out","x","y","first","last","createRectangle","start","end","createCircle","centerX","centerY","i","polygonArea","sum","computeBounds","minX","minY","maxX","maxY","isValidPolygon","drawPath","ctx","points","strokeStyle","close","fill","resolveStrokeStyle","style","dash","shadowBlur","shadowOffsetX","shadowOffsetY","mergeStrokeStyle","base","override","isSameRegionId","resolveLabelStyle","px","py","bw","oy","br","drawRoundedRect","r","getTopAnchor","point","drawRegionLabel","text","anchor","canvasWidth","canvasHeight","labelStyle","label","boxWidth","boxHeight","left","top","clampWorld","coord","imageWidth","imageHeight","toCoord","DrawLayer","stampOptions","projectorRef","onDrawComplete","enabled","viewStateSignal","persistedRegions","persistedPolygons","regionStrokeStyle","regionStrokeHoverStyle","regionStrokeActiveStyle","resolveRegionStrokeStyle","overlayShapes","hoveredRegionId","activeRegionId","regionLabelStyle","invalidateRef","className","canvasRef","useRef","drawPendingRef","lastToolRef","sessionRef","active","mergedPersistedRegions","useMemo","coordinates","index","resolvedStrokeStyle","resolvedHoverStrokeStyle","resolvedActiveStrokeStyle","resolvedLabelStyle","resolvedStampOptions","mergedStyle","resizeCanvas","useCallback","w","h","worldToScreenPoints","projector","micronsToWorldPixels","lengthUm","mppValue","imageZoomValue","viewZoomRaw","viewZoom","continuousZoom","umPerScreenPixel","buildStampCoords","stampTool","areaUm2","buildPreviewCoords","session","drawOverlay","region","ring","closed","screen","regionKey","state","resolved","shape","preview","line","polygon","anchorWorld","anchorScreen","requestDraw","resetSession","toWorld","event","raw","finishSession","handleStampAt","handlePointerDown","world","handlePointerMove","minWorldStep","minWorldStep2","prev","dx","dy","handlePointerUp","handlePointerLeave","useEffect","observer","onKeyDown","jsx","trimTrailingSlash","ensureLeadingSlash","joinImsTileRoot","tileBaseUrl","parsed","origin","path","normalizeImageInfo","ims","isIms","tileSize","maxTierZoom","tilePath","normalizedPath","imsTileRoot","tileUrlBuilder","tier","toTileUrl","DEFAULT_OVERVIEW_MAP_OPTIONS","toPositiveNumber","isFiniteBounds","bounds","OverviewMap","authToken","thumbnailRef","lastBoundsRef","draggingRef","rafRef","margin","borderRadius","borderWidth","maxThumbnailTiles","backgroundColor","borderColor","viewportStrokeColor","viewportFillColor","interactive","showThumbnail","position","pos","draw","cssW","cssH","pixelW","pixelH","corners","safeBounds","safeCorners","right","bottom","rectW","rectH","toWorldFromClient","clientX","clientY","nx","ny","recenterTo","worldX","worldY","visibleW","visibleH","drag","cancelled","levelScale","levelWidth","levelHeight","tilesX","tilesY","tileCount","requests","useAuthHeader","results","result","dw","dh","TileViewerCanvas","rendererRef","renderer","preparePolygons","polygons","prepared","poly","isInsideRing","inside","j","xi","yi","xj","yj","isInsideAnyPolygon","filterPointDataByPolygons","pointData","count","positions","nextPositions","nextTerms","cursor","contextPromise","BBOX_PREFILTER_SHADER","hasWebGpu","nav","getNavigatorGpu","gpu","candidate","GPU_SHADER_STAGE_COMPUTE","GPU_BUFFER_USAGE_STORAGE","GPU_BUFFER_USAGE_COPY_DST","GPU_BUFFER_USAGE_COPY_SRC","GPU_BUFFER_USAGE_UNIFORM","GPU_BUFFER_USAGE_MAP_READ","GPU_MAP_MODE_READ","getWebGpuCapabilities","navGpu","adapter","getContext","device","bindGroupLayout","pipeline","align","step","prefilterPointsByBoundsWebGpu","pointCount","boundsCount","safePointCount","positionBytes","boundsBytes","outputBytes","limit","positionsBuffer","boundsBuffer","outputBuffer","uniformBuffer","readBuffer","bindGroup","commandEncoder","pass","mapped","nowMs","filterPointDataByPolygonsHybrid","bridgeToDraw","safeCount","bboxFlat","candidateMask","usedWebGpu","candidateCount","candidateIndices","candidateCursor","drawIndices","visibleCount","pointIndex","workerInstance","workerSupported","requestId","pendingById","createWorker","worker","handleWorkerMessage","handleWorkerError","msg","pending","paletteIndices","output","terminateRoiClipWorker","filterPointDataByPolygonsInWorker","positionsCopy","termsCopy","id","startMs","resolve","reject","ax","ay","bx","by","prepareRegions","regions","resolveTermId","paletteIndex","paletteIndexToTermId","fromArray","fromMap","computeRoiPointGroups","baseCount","valid","filtered","idx","inputCount","preparedRegions","regionTermCounters","regionTotalCounters","insideCount","bestRegion","regionTermMap","includeEmptyRegions","groups","totalCount","termMap","termCounts","shouldAttachAuthHeader","url","host","TileScheduler","nextVisibleKeys","inflight","queued","item","visibleKeys","nextQueue","key","earliestReadyAt","delay","now","controller","inflightEntry","nextAttempt","retryDelay","existing","attempt","exp","jitter","DEFAULT_ROTATION_DRAG_SENSITIVITY","screenX","screenY","rad","toRadians","cos","sin","rx","ry","deg","name","isSameArrayView","WsiTileRenderer","attemptCount","normalized","paletteSize","nextPaletteIndices","hasDrawIndices","nextDrawIndices","geometryChanged","drawIndicesChanged","maxExclusive","validCount","locked","stops","size","s0","s1","lastStop","vw","vh","visibleWorldW","visibleWorldH","factor","nextZoom","vp","worldDx","worldDy","marginX","marginY","halfW","halfH","minCenterX","maxCenterX","minCenterY","maxCenterY","nextCenterX","nextCenterY","rawTier","viewBounds","viewMinX","viewMinY","viewMaxX","viewMaxY","minTileX","maxTileX","minTileY","maxTileY","centerTileX","centerTileY","visible","entries","removeCount","frameStartMs","tileProgram","pointProgram","fallbackTiles","cached","renderedTiles","missingTiles","renderedPoints","schedulerStats","cacheHits","cacheMisses","drawCalls","wantsRotate","nextAngle","prevAngle","rawDelta","delta","sensitivityScale","_event","uCamera","uBounds","uTexture","vbo","aUnit","aUv","uPointSize","uPalette","uPaletteSize","posBuffer","termBuffer","indexBuffer","paletteTexture","posLoc","termLoc","EMPTY_ROI_REGIONS","EMPTY_ROI_POLYGONS","EMPTY_CLIPPED_POINTS","resolveRegionId","isPointInPolygon","pickRegionAt","WsiViewerCanvas","onViewStateChange","onStats","onTileError","onContextLost","onContextRestored","debugOverlay","debugOverlayStyle","fitNonce","rotationResetNonce","ctrlDragRotate","pointPalette","roiRegions","roiPolygons","clipPointsToRois","clipMode","onClipStats","onRoiPointGroups","roiPaletteIndexToTermId","interactionLock","drawTool","onPointerWorldMove","onRegionHover","onRegionClick","onActiveRegionChange","showOverviewMap","overviewMapOptions","drawInvalidateRef","overviewInvalidateRef","onViewStateChangeRef","onStatsRef","debugOverlayRef","isOverviewOpen","setIsOverviewOpen","useState","setHoveredRegionId","setActiveRegionId","debugStats","setDebugStats","hoveredRegionIdRef","clipRunIdRef","safeRoiRegions","safeRoiPolygons","mergedDebugOverlayStyle","effectiveRoiRegions","clipPolygons","renderPointData","setRenderPointData","runId","applyResult","data","stats","outputCount","overviewHeight","overviewMargin","overviewPosition","commitActiveRegion","handleRendererStats","debugOverlayText","currentHover","emitViewStateChange","callback","resolveWorldCoord","handleRegionPointerMove","isCanvasEvent","insideImage","hit","nextHoverId","prevHoverId","handleRegionPointerLeave","handleRegionClick","nextActive","jsxs","Fragment"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/core/gl-utils.ts","../src/core/ortho-camera.ts","../src/core/m1-tile-renderer.ts","../src/wsi/constants.ts","../src/wsi/utils.ts","../src/react/draw-layer.tsx","../src/wsi/image-info.ts","../src/react/overview-map.tsx","../src/react/tile-viewer-canvas.tsx","../src/wsi/point-clip.ts","../src/wsi/webgpu.ts","../src/wsi/point-clip-hybrid.ts","../src/wsi/point-clip-worker-client.ts","../src/wsi/roi-term-stats.ts","../src/wsi/tile-scheduler.ts","../src/wsi/wsi-tile-renderer.ts","../src/react/wsi-viewer-canvas.tsx"],"sourcesContent":["function compileShader(gl: WebGL2RenderingContext, type: number, source: string): WebGLShader {\n const shader = gl.createShader(type);\n if (!shader) {\n throw new Error(\"Failed to create shader.\");\n }\n\n gl.shaderSource(shader, source);\n gl.compileShader(shader);\n\n const ok = gl.getShaderParameter(shader, gl.COMPILE_STATUS);\n if (!ok) {\n const log = gl.getShaderInfoLog(shader) ?? \"unknown shader error\";\n gl.deleteShader(shader);\n throw new Error(log);\n }\n\n return shader;\n}\n\nexport function createProgram(gl: WebGL2RenderingContext, vertexSource: string, fragmentSource: string): WebGLProgram {\n const vertexShader = compileShader(gl, gl.VERTEX_SHADER, vertexSource);\n const fragmentShader = compileShader(gl, gl.FRAGMENT_SHADER, fragmentSource);\n\n const program = gl.createProgram();\n if (!program) {\n gl.deleteShader(vertexShader);\n gl.deleteShader(fragmentShader);\n throw new Error(\"Failed to create program.\");\n }\n\n gl.attachShader(program, vertexShader);\n gl.attachShader(program, fragmentShader);\n gl.linkProgram(program);\n\n gl.deleteShader(vertexShader);\n gl.deleteShader(fragmentShader);\n\n const ok = gl.getProgramParameter(program, gl.LINK_STATUS);\n if (!ok) {\n const log = gl.getProgramInfoLog(program) ?? \"unknown link error\";\n gl.deleteProgram(program);\n throw new Error(log);\n }\n\n return program;\n}\n\nexport function requireUniformLocation(\n gl: WebGL2RenderingContext,\n program: WebGLProgram,\n uniformName: string,\n): WebGLUniformLocation {\n const location = gl.getUniformLocation(program, uniformName);\n if (!location) {\n throw new Error(`Failed to get uniform location: ${uniformName}`);\n }\n return location;\n}\n\nexport function requireWebGL2(canvas: HTMLCanvasElement): WebGL2RenderingContext {\n const context = canvas.getContext(\"webgl2\", {\n alpha: false,\n antialias: false,\n depth: false,\n stencil: false,\n preserveDrawingBuffer: false,\n powerPreference: \"high-performance\",\n });\n\n if (!context) {\n throw new Error(\"WebGL2 is not available.\");\n }\n\n return context;\n}\n","export interface ViewState {\n offsetX: number;\n offsetY: number;\n zoom: number;\n}\n\nexport class OrthoCamera {\n private viewportWidth = 1;\n private viewportHeight = 1;\n\n private viewState: ViewState = {\n offsetX: 0,\n offsetY: 0,\n zoom: 1,\n };\n\n setViewport(width: number, height: number): void {\n this.viewportWidth = Math.max(1, width);\n this.viewportHeight = Math.max(1, height);\n }\n\n getViewportSize(): { width: number; height: number } {\n return {\n width: this.viewportWidth,\n height: this.viewportHeight,\n };\n }\n\n setViewState(next: Partial<ViewState>): void {\n if (next.offsetX !== undefined) {\n this.viewState.offsetX = next.offsetX;\n }\n\n if (next.offsetY !== undefined) {\n this.viewState.offsetY = next.offsetY;\n }\n\n if (next.zoom !== undefined) {\n this.viewState.zoom = Math.max(0.0001, next.zoom);\n }\n }\n\n getViewState(): ViewState {\n return { ...this.viewState };\n }\n\n getMatrix(): Float32Array {\n const viewWidth = this.viewportWidth / this.viewState.zoom;\n const viewHeight = this.viewportHeight / this.viewState.zoom;\n\n const sx = 2 / viewWidth;\n const sy = -2 / viewHeight;\n const tx = -1 - this.viewState.offsetX * sx;\n const ty = 1 - this.viewState.offsetY * sy;\n\n return new Float32Array([\n sx,\n 0,\n 0,\n 0,\n sy,\n 0,\n tx,\n ty,\n 1,\n ]);\n }\n}\n","import {\n\tcreateProgram,\n\trequireUniformLocation,\n\trequireWebGL2,\n} from \"./gl-utils\";\nimport { OrthoCamera, type ViewState } from \"./ortho-camera\";\nimport type { Bounds, TileDefinition } from \"./types\";\n\ninterface LoadedTile {\n\tid: string;\n\tbounds: Bounds;\n\ttexture: WebGLTexture;\n}\n\nexport interface M1TileRendererOptions {\n\tcanvas: HTMLCanvasElement;\n\timageWidth: number;\n\timageHeight: number;\n\tclearColor?: [number, number, number, number];\n\tinitialViewState?: Partial<ViewState>;\n}\n\nconst VERTEX_SHADER = `#version 300 es\nprecision highp float;\n\nin vec2 aUnit;\nin vec2 aUv;\n\nuniform mat3 uCamera;\nuniform vec4 uBounds;\n\nout vec2 vUv;\n\nvoid main() {\n vec2 world = vec2(\n mix(uBounds.x, uBounds.z, aUnit.x),\n mix(uBounds.y, uBounds.w, aUnit.y)\n );\n vec3 clip = uCamera * vec3(world, 1.0);\n gl_Position = vec4(clip.xy, 0.0, 1.0);\n vUv = aUv;\n}\n`;\n\nconst FRAGMENT_SHADER = `#version 300 es\nprecision highp float;\n\nin vec2 vUv;\nuniform sampler2D uTexture;\n\nout vec4 outColor;\n\nvoid main() {\n outColor = texture(uTexture, vUv);\n}\n`;\n\nexport class M1TileRenderer {\n\tprivate readonly canvas: HTMLCanvasElement;\n\tprivate readonly gl: WebGL2RenderingContext;\n\tprivate readonly camera = new OrthoCamera();\n\tprivate readonly imageWidth: number;\n\tprivate readonly imageHeight: number;\n\tprivate readonly clearColor: [number, number, number, number];\n\tprivate readonly program: WebGLProgram;\n\tprivate readonly vao: WebGLVertexArrayObject;\n\tprivate readonly quadBuffer: WebGLBuffer;\n\tprivate readonly uCameraLocation: WebGLUniformLocation;\n\tprivate readonly uBoundsLocation: WebGLUniformLocation;\n\tprivate readonly uTextureLocation: WebGLUniformLocation;\n\tprivate readonly resizeObserver: ResizeObserver;\n\n\tprivate tiles: LoadedTile[] = [];\n\tprivate frameId: number | null = null;\n\tprivate loadVersion = 0;\n\tprivate destroyed = false;\n\tprivate fitted = false;\n\tprivate controlledViewState = false;\n\n\tconstructor(options: M1TileRendererOptions) {\n\t\tthis.canvas = options.canvas;\n\t\tthis.imageWidth = Math.max(1, options.imageWidth);\n\t\tthis.imageHeight = Math.max(1, options.imageHeight);\n\t\tthis.clearColor = options.clearColor ?? [0.03, 0.05, 0.08, 1];\n\n\t\tthis.gl = requireWebGL2(this.canvas);\n\t\tthis.program = createProgram(this.gl, VERTEX_SHADER, FRAGMENT_SHADER);\n\n\t\tconst vao = this.gl.createVertexArray();\n\t\tconst quadBuffer = this.gl.createBuffer();\n\t\tif (!vao || !quadBuffer) {\n\t\t\tthrow new Error(\"Failed to create WebGL buffers.\");\n\t\t}\n\n\t\tthis.vao = vao;\n\t\tthis.quadBuffer = quadBuffer;\n\n\t\tthis.gl.bindVertexArray(this.vao);\n\t\tthis.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.quadBuffer);\n\n\t\tconst quadVertices = new Float32Array([\n\t\t\t0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1,\n\t\t]);\n\n\t\tthis.gl.bufferData(this.gl.ARRAY_BUFFER, quadVertices, this.gl.STATIC_DRAW);\n\n\t\tconst unitLocation = this.gl.getAttribLocation(this.program, \"aUnit\");\n\t\tconst uvLocation = this.gl.getAttribLocation(this.program, \"aUv\");\n\t\tif (unitLocation < 0 || uvLocation < 0) {\n\t\t\tthrow new Error(\"Failed to get attribute locations.\");\n\t\t}\n\n\t\tconst stride = 4 * Float32Array.BYTES_PER_ELEMENT;\n\t\tthis.gl.enableVertexAttribArray(unitLocation);\n\t\tthis.gl.vertexAttribPointer(\n\t\t\tunitLocation,\n\t\t\t2,\n\t\t\tthis.gl.FLOAT,\n\t\t\tfalse,\n\t\t\tstride,\n\t\t\t0,\n\t\t);\n\t\tthis.gl.enableVertexAttribArray(uvLocation);\n\t\tthis.gl.vertexAttribPointer(\n\t\t\tuvLocation,\n\t\t\t2,\n\t\t\tthis.gl.FLOAT,\n\t\t\tfalse,\n\t\t\tstride,\n\t\t\t2 * Float32Array.BYTES_PER_ELEMENT,\n\t\t);\n\n\t\tthis.gl.bindVertexArray(null);\n\t\tthis.gl.bindBuffer(this.gl.ARRAY_BUFFER, null);\n\n\t\tthis.uCameraLocation = requireUniformLocation(\n\t\t\tthis.gl,\n\t\t\tthis.program,\n\t\t\t\"uCamera\",\n\t\t);\n\t\tthis.uBoundsLocation = requireUniformLocation(\n\t\t\tthis.gl,\n\t\t\tthis.program,\n\t\t\t\"uBounds\",\n\t\t);\n\t\tthis.uTextureLocation = requireUniformLocation(\n\t\t\tthis.gl,\n\t\t\tthis.program,\n\t\t\t\"uTexture\",\n\t\t);\n\n\t\tif (options.initialViewState) {\n\t\t\tthis.controlledViewState = true;\n\t\t\tthis.camera.setViewState(options.initialViewState);\n\t\t}\n\n\t\tthis.resizeObserver = new ResizeObserver(() => {\n\t\t\tthis.resize();\n\t\t});\n\n\t\tthis.resizeObserver.observe(this.canvas);\n\t\tthis.resize();\n\t}\n\n\tasync setTiles(tiles: TileDefinition[]): Promise<void> {\n\t\tif (this.destroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst version = ++this.loadVersion;\n\n\t\tconst loaded = await Promise.all(\n\t\t\ttiles.map(async (tile) => {\n\t\t\t\tconst loadedTile = await this.loadTile(tile, version);\n\t\t\t\treturn loadedTile;\n\t\t\t}),\n\t\t);\n\n\t\tif (this.destroyed || version !== this.loadVersion) {\n\t\t\tfor (const tile of loaded) {\n\t\t\t\tif (tile) {\n\t\t\t\t\tthis.gl.deleteTexture(tile.texture);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tthis.disposeTiles(this.tiles);\n\t\tthis.tiles = loaded.filter((tile): tile is LoadedTile => tile !== null);\n\t\tthis.requestRender();\n\t}\n\n\tsetViewState(viewState: Partial<ViewState>): void {\n\t\tthis.controlledViewState = true;\n\t\tthis.camera.setViewState(viewState);\n\t\tthis.requestRender();\n\t}\n\n\tgetViewState(): ViewState {\n\t\treturn this.camera.getViewState();\n\t}\n\n\tdestroy(): void {\n\t\tif (this.destroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.destroyed = true;\n\t\tthis.loadVersion += 1;\n\n\t\tif (this.frameId !== null) {\n\t\t\tcancelAnimationFrame(this.frameId);\n\t\t\tthis.frameId = null;\n\t\t}\n\n\t\tthis.resizeObserver.disconnect();\n\t\tthis.disposeTiles(this.tiles);\n\t\tthis.tiles = [];\n\n\t\tthis.gl.deleteBuffer(this.quadBuffer);\n\t\tthis.gl.deleteVertexArray(this.vao);\n\t\tthis.gl.deleteProgram(this.program);\n\t}\n\n\tprivate async loadTile(\n\t\ttile: TileDefinition,\n\t\tversion: number,\n\t): Promise<LoadedTile | null> {\n\t\ttry {\n\t\t\tconst response = await fetch(tile.url);\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Tile fetch failed: ${response.status} ${response.statusText}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst blob = await response.blob();\n\t\t\tconst bitmap = await createImageBitmap(blob);\n\n\t\t\tif (this.destroyed || version !== this.loadVersion) {\n\t\t\t\tbitmap.close();\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst texture = this.gl.createTexture();\n\t\t\tif (!texture) {\n\t\t\t\tbitmap.close();\n\t\t\t\tthrow new Error(\"Failed to create tile texture.\");\n\t\t\t}\n\n\t\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, texture);\n\t\t\tthis.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, 1);\n\t\t\tthis.gl.texParameteri(\n\t\t\t\tthis.gl.TEXTURE_2D,\n\t\t\t\tthis.gl.TEXTURE_WRAP_S,\n\t\t\t\tthis.gl.CLAMP_TO_EDGE,\n\t\t\t);\n\t\t\tthis.gl.texParameteri(\n\t\t\t\tthis.gl.TEXTURE_2D,\n\t\t\t\tthis.gl.TEXTURE_WRAP_T,\n\t\t\t\tthis.gl.CLAMP_TO_EDGE,\n\t\t\t);\n\t\t\tthis.gl.texParameteri(\n\t\t\t\tthis.gl.TEXTURE_2D,\n\t\t\t\tthis.gl.TEXTURE_MIN_FILTER,\n\t\t\t\tthis.gl.LINEAR,\n\t\t\t);\n\t\t\tthis.gl.texParameteri(\n\t\t\t\tthis.gl.TEXTURE_2D,\n\t\t\t\tthis.gl.TEXTURE_MAG_FILTER,\n\t\t\t\tthis.gl.LINEAR,\n\t\t\t);\n\t\t\tthis.gl.texImage2D(\n\t\t\t\tthis.gl.TEXTURE_2D,\n\t\t\t\t0,\n\t\t\t\tthis.gl.RGBA,\n\t\t\t\tthis.gl.RGBA,\n\t\t\t\tthis.gl.UNSIGNED_BYTE,\n\t\t\t\tbitmap,\n\t\t\t);\n\t\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, null);\n\t\t\tbitmap.close();\n\n\t\t\treturn {\n\t\t\t\tid: tile.id,\n\t\t\t\tbounds: tile.bounds,\n\t\t\t\ttexture,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tconsole.error(`[M1TileRenderer] tile load failed: ${tile.id}`, error);\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate resize(): void {\n\t\tif (this.destroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst rect = this.canvas.getBoundingClientRect();\n\t\tconst cssWidth = Math.max(1, rect.width || this.canvas.clientWidth || 1);\n\t\tconst cssHeight = Math.max(1, rect.height || this.canvas.clientHeight || 1);\n\t\tconst dpr = Math.max(1, window.devicePixelRatio || 1);\n\n\t\tconst targetWidth = Math.max(1, Math.round(cssWidth * dpr));\n\t\tconst targetHeight = Math.max(1, Math.round(cssHeight * dpr));\n\n\t\tif (\n\t\t\tthis.canvas.width !== targetWidth ||\n\t\t\tthis.canvas.height !== targetHeight\n\t\t) {\n\t\t\tthis.canvas.width = targetWidth;\n\t\t\tthis.canvas.height = targetHeight;\n\t\t}\n\n\t\tthis.camera.setViewport(cssWidth, cssHeight);\n\t\tthis.gl.viewport(0, 0, this.canvas.width, this.canvas.height);\n\n\t\tif (!this.fitted && !this.controlledViewState) {\n\t\t\tthis.fitToImage();\n\t\t\tthis.fitted = true;\n\t\t}\n\n\t\tthis.requestRender();\n\t}\n\n\tprivate fitToImage(): void {\n\t\tconst viewport = this.camera.getViewportSize();\n\n\t\tconst zoom = Math.min(\n\t\t\tviewport.width / this.imageWidth,\n\t\t\tviewport.height / this.imageHeight,\n\t\t);\n\t\tconst safeZoom = Number.isFinite(zoom) && zoom > 0 ? zoom : 1;\n\n\t\tconst visibleWorldWidth = viewport.width / safeZoom;\n\t\tconst visibleWorldHeight = viewport.height / safeZoom;\n\n\t\tconst offsetX = (this.imageWidth - visibleWorldWidth) * 0.5;\n\t\tconst offsetY = (this.imageHeight - visibleWorldHeight) * 0.5;\n\n\t\tthis.camera.setViewState({\n\t\t\tzoom: safeZoom,\n\t\t\toffsetX,\n\t\t\toffsetY,\n\t\t});\n\t}\n\n\tprivate requestRender(): void {\n\t\tif (this.frameId !== null || this.destroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.frameId = requestAnimationFrame(() => {\n\t\t\tthis.frameId = null;\n\t\t\tthis.render();\n\t\t});\n\t}\n\n\tprivate render(): void {\n\t\tif (this.destroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.gl.clearColor(\n\t\t\tthis.clearColor[0],\n\t\t\tthis.clearColor[1],\n\t\t\tthis.clearColor[2],\n\t\t\tthis.clearColor[3],\n\t\t);\n\t\tthis.gl.clear(this.gl.COLOR_BUFFER_BIT);\n\n\t\tthis.gl.useProgram(this.program);\n\t\tthis.gl.bindVertexArray(this.vao);\n\t\tthis.gl.uniformMatrix3fv(\n\t\t\tthis.uCameraLocation,\n\t\t\tfalse,\n\t\t\tthis.camera.getMatrix(),\n\t\t);\n\t\tthis.gl.uniform1i(this.uTextureLocation, 0);\n\n\t\tfor (const tile of this.tiles) {\n\t\t\tthis.gl.activeTexture(this.gl.TEXTURE0);\n\t\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, tile.texture);\n\t\t\tthis.gl.uniform4f(\n\t\t\t\tthis.uBoundsLocation,\n\t\t\t\ttile.bounds[0],\n\t\t\t\ttile.bounds[1],\n\t\t\t\ttile.bounds[2],\n\t\t\t\ttile.bounds[3],\n\t\t\t);\n\t\t\tthis.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);\n\t\t}\n\n\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, null);\n\t\tthis.gl.bindVertexArray(null);\n\t}\n\n\tprivate disposeTiles(tiles: LoadedTile[]): void {\n\t\tfor (const tile of tiles) {\n\t\t\tthis.gl.deleteTexture(tile.texture);\n\t\t}\n\t}\n}\n","export const DEFAULT_POINT_COLOR: [number, number, number, number] = [\n\t160, 160, 160, 255,\n];\n","import { DEFAULT_POINT_COLOR } from \"./constants\";\nimport type { TermPalette, WsiViewState } from \"./types\";\n\nexport function clamp(value: number, min: number, max: number): number {\n\treturn Math.max(min, Math.min(max, value));\n}\n\nexport function calcScaleResolution(\n\timageMpp: number,\n\timageZoom: number,\n\tcurrentZoom: number,\n): number {\n\tconst mpp = Number(imageMpp);\n\tconst z0 = Number(imageZoom);\n\tconst z1 = Number(currentZoom);\n\tif (!Number.isFinite(mpp) || mpp <= 0) return 1;\n\tif (!Number.isFinite(z0) || !Number.isFinite(z1)) return mpp;\n\treturn Math.pow(2, z0 - z1) * mpp;\n}\n\nexport function calcScaleLength(\n\timageMpp: number,\n\timageZoom: number,\n\tcurrentZoom: number,\n): string {\n\tconst resolution = calcScaleResolution(imageMpp, imageZoom, currentZoom);\n\tlet length = 100 * resolution;\n\tif (Number(imageMpp)) {\n\t\tlet unit = \"μm\";\n\t\tif (length > 1000) {\n\t\t\tlength /= 1000;\n\t\t\tunit = \"mm\";\n\t\t}\n\t\treturn `${length.toPrecision(3)} ${unit}`;\n\t}\n\treturn `${Math.round(length * 1000) / 1000} pixels`;\n}\n\nexport function isSameViewState(\n\ta: Partial<WsiViewState> | null | undefined,\n\tb: Partial<WsiViewState> | null | undefined,\n): boolean {\n\tif (!a && !b) return true;\n\tif (!a || !b) return false;\n\treturn (\n\t\tMath.abs((a.zoom ?? 0) - (b.zoom ?? 0)) < 1e-6 &&\n\t\tMath.abs((a.offsetX ?? 0) - (b.offsetX ?? 0)) < 1e-6 &&\n\t\tMath.abs((a.offsetY ?? 0) - (b.offsetY ?? 0)) < 1e-6 &&\n\t\tMath.abs((a.rotationDeg ?? 0) - (b.rotationDeg ?? 0)) < 1e-6\n\t);\n}\n\nexport function toBearerToken(value: string | null | undefined): string {\n\tconst trimmed = String(value ?? \"\").trim();\n\tif (!trimmed) return \"\";\n\tif (/^bearer\\s+/i.test(trimmed)) {\n\t\tconst token = trimmed.replace(/^bearer\\s+/i, \"\").trim();\n\t\treturn token ? `Bearer ${token}` : \"\";\n\t}\n\treturn `Bearer ${trimmed}`;\n}\n\nexport function hexToRgba(\n\thex: string | null | undefined,\n): [number, number, number, number] {\n\tconst value = String(hex ?? \"\").trim();\n\tconst match = value.match(/^#?([0-9a-fA-F]{6})$/);\n\tif (!match) return [...DEFAULT_POINT_COLOR];\n\n\tconst n = Number.parseInt(match[1], 16);\n\treturn [(n >> 16) & 255, (n >> 8) & 255, n & 255, 255];\n}\n\nexport function buildTermPalette(\n\tterms:\n\t\t| Array<{ termId?: string | null; termColor?: string | null }>\n\t\t| null\n\t\t| undefined,\n): TermPalette {\n\tconst palette: Array<[number, number, number, number]> = [\n\t\t[...DEFAULT_POINT_COLOR],\n\t];\n\tconst termToPaletteIndex = new Map<string, number>();\n\n\tfor (const term of terms ?? []) {\n\t\tconst termId = String(term?.termId ?? \"\");\n\t\tif (!termId || termToPaletteIndex.has(termId)) continue;\n\n\t\ttermToPaletteIndex.set(termId, palette.length);\n\t\tpalette.push(hexToRgba(term?.termColor));\n\t}\n\n\tconst colors = new Uint8Array(palette.length * 4);\n\tfor (let i = 0; i < palette.length; i += 1) {\n\t\tcolors[i * 4] = palette[i][0];\n\t\tcolors[i * 4 + 1] = palette[i][1];\n\t\tcolors[i * 4 + 2] = palette[i][2];\n\t\tcolors[i * 4 + 3] = palette[i][3];\n\t}\n\n\treturn { colors, termToPaletteIndex };\n}\n\nexport function createProgram(\n\tgl: WebGL2RenderingContext,\n\tvertexSource: string,\n\tfragmentSource: string,\n): WebGLProgram {\n\tconst vs = gl.createShader(gl.VERTEX_SHADER);\n\tconst fs = gl.createShader(gl.FRAGMENT_SHADER);\n\tif (!vs || !fs) {\n\t\tthrow new Error(\"Shader allocation failed\");\n\t}\n\n\tgl.shaderSource(vs, vertexSource);\n\tgl.compileShader(vs);\n\tif (!gl.getShaderParameter(vs, gl.COMPILE_STATUS)) {\n\t\tthrow new Error(gl.getShaderInfoLog(vs) || \"vertex compile failed\");\n\t}\n\n\tgl.shaderSource(fs, fragmentSource);\n\tgl.compileShader(fs);\n\tif (!gl.getShaderParameter(fs, gl.COMPILE_STATUS)) {\n\t\tthrow new Error(gl.getShaderInfoLog(fs) || \"fragment compile failed\");\n\t}\n\n\tconst program = gl.createProgram();\n\tif (!program) {\n\t\tthrow new Error(\"Program allocation failed\");\n\t}\n\n\tgl.attachShader(program, vs);\n\tgl.attachShader(program, fs);\n\tgl.linkProgram(program);\n\n\tgl.deleteShader(vs);\n\tgl.deleteShader(fs);\n\n\tif (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n\t\tthrow new Error(gl.getProgramInfoLog(program) || \"program link failed\");\n\t}\n\n\treturn program;\n}\n","import { type CSSProperties, type MutableRefObject, type PointerEvent as ReactPointerEvent, type RefObject, useCallback, useEffect, useMemo, useRef } from \"react\";\nimport { calcScaleResolution } from \"../wsi/utils\";\n\nexport type StampDrawTool = \"stamp-rectangle\" | \"stamp-circle\" | \"stamp-rectangle-4096px\" | \"stamp-rectangle-2mm2\" | \"stamp-circle-2mm2\" | \"stamp-circle-hpf-0.2mm2\";\n\nexport type DrawTool = \"cursor\" | \"freehand\" | \"rectangle\" | \"circular\" | StampDrawTool;\n\nexport type DrawCoordinate = [number, number];\n\nexport type DrawBounds = [number, number, number, number];\n\nexport type DrawIntent = \"roi\" | \"patch\";\n\nexport interface DrawResult {\n tool: Exclude<DrawTool, \"cursor\">;\n intent: DrawIntent;\n coordinates: DrawCoordinate[];\n bbox: DrawBounds;\n areaPx: number;\n}\n\nexport type PatchDrawResult = DrawResult & {\n tool: \"stamp-rectangle-4096px\";\n intent: \"patch\";\n};\n\nexport interface DrawRegion {\n id?: string | number;\n coordinates: DrawCoordinate[];\n label?: string;\n}\n\nexport interface RegionStyleContext {\n region: DrawRegion;\n regionId: string | number;\n regionIndex: number;\n state: \"default\" | \"hover\" | \"active\";\n}\n\nexport type RegionStrokeStyleResolver = (context: RegionStyleContext) => Partial<RegionStrokeStyle> | null | undefined;\n\nexport interface DrawOverlayShape {\n id?: string | number;\n coordinates: DrawCoordinate[];\n closed?: boolean;\n fill?: boolean;\n strokeStyle?: Partial<RegionStrokeStyle>;\n}\n\nexport interface RegionStrokeStyle {\n color: string;\n width: number;\n lineDash: number[];\n lineJoin: CanvasLineJoin;\n lineCap: CanvasLineCap;\n shadowColor: string;\n shadowBlur: number;\n shadowOffsetX: number;\n shadowOffsetY: number;\n}\n\nexport interface RegionLabelStyle {\n fontFamily: string;\n fontSize: number;\n fontWeight: string | number;\n textColor: string;\n backgroundColor: string;\n borderColor: string;\n borderWidth: number;\n paddingX: number;\n paddingY: number;\n offsetY: number;\n borderRadius: number;\n}\n\nexport interface DrawProjector {\n screenToWorld(clientX: number, clientY: number): DrawCoordinate | number[];\n worldToScreen(worldX: number, worldY: number): DrawCoordinate | number[];\n getViewState?: () => { zoom: number; rotationDeg?: number };\n}\n\nexport interface StampOptions {\n rectangleAreaMm2?: number;\n circleAreaMm2?: number;\n rectanglePixelSize?: number;\n}\n\nexport interface DrawLayerProps {\n tool: DrawTool;\n imageWidth: number;\n imageHeight: number;\n imageMpp?: number;\n imageZoom?: number;\n stampOptions?: StampOptions;\n projectorRef: RefObject<DrawProjector | null>;\n onDrawComplete?: (result: DrawResult) => void;\n onPatchComplete?: (result: PatchDrawResult) => void;\n enabled?: boolean;\n viewStateSignal?: unknown;\n persistedRegions?: DrawRegion[];\n patchRegions?: DrawRegion[];\n persistedPolygons?: DrawCoordinate[][];\n regionStrokeStyle?: Partial<RegionStrokeStyle>;\n regionStrokeHoverStyle?: Partial<RegionStrokeStyle>;\n regionStrokeActiveStyle?: Partial<RegionStrokeStyle>;\n patchStrokeStyle?: Partial<RegionStrokeStyle>;\n resolveRegionStrokeStyle?: RegionStrokeStyleResolver;\n overlayShapes?: DrawOverlayShape[];\n hoveredRegionId?: string | number | null;\n activeRegionId?: string | number | null;\n regionLabelStyle?: Partial<RegionLabelStyle>;\n invalidateRef?: MutableRefObject<(() => void) | null>;\n className?: string;\n style?: CSSProperties;\n}\n\ninterface DrawSession {\n isDrawing: boolean;\n pointerId: number | null;\n start: DrawCoordinate | null;\n current: DrawCoordinate | null;\n points: DrawCoordinate[];\n stampCenter: DrawCoordinate | null;\n}\n\nconst DRAW_FILL = \"rgba(255, 77, 79, 0.16)\";\nconst FREEHAND_MIN_POINTS = 3;\nconst FREEHAND_SCREEN_STEP = 2;\nconst CIRCLE_SIDES = 96;\nconst MIN_AREA_PX = 1;\nconst EMPTY_REGIONS: DrawRegion[] = [];\nconst EMPTY_DASH: number[] = [];\nconst MICRONS_PER_MM = 1000;\nconst DEFAULT_STAMP_RECTANGLE_AREA_MM2 = 2;\nconst DEFAULT_STAMP_CIRCLE_AREA_MM2 = 2;\nconst DEFAULT_STAMP_RECTANGLE_PIXEL_SIZE = 4096;\nconst LEGACY_HPF_CIRCLE_AREA_MM2 = 0.2;\n\nconst DEFAULT_REGION_STROKE_STYLE: RegionStrokeStyle = {\n color: \"#ff4d4f\",\n width: 2,\n lineDash: EMPTY_DASH,\n lineJoin: \"round\",\n lineCap: \"round\",\n shadowColor: \"rgba(0, 0, 0, 0)\",\n shadowBlur: 0,\n shadowOffsetX: 0,\n shadowOffsetY: 0,\n};\n\nconst DEFAULT_PATCH_STROKE_STYLE: RegionStrokeStyle = {\n color: \"#4cc9f0\",\n width: 2,\n lineDash: [10, 8],\n lineJoin: \"round\",\n lineCap: \"round\",\n shadowColor: \"rgba(0, 0, 0, 0)\",\n shadowBlur: 0,\n shadowOffsetX: 0,\n shadowOffsetY: 0,\n};\n\nconst DEFAULT_REGION_LABEL_STYLE: RegionLabelStyle = {\n fontFamily: \"ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace\",\n fontSize: 12,\n fontWeight: 500,\n textColor: \"#ffffff\",\n backgroundColor: \"rgba(8, 14, 22, 0.88)\",\n borderColor: \"rgba(255, 77, 79, 0.85)\",\n borderWidth: 1,\n paddingX: 6,\n paddingY: 4,\n offsetY: 10,\n borderRadius: 3,\n};\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, value));\n}\n\nfunction isStampTool(tool: DrawTool): tool is StampDrawTool {\n return (\n tool === \"stamp-rectangle\" || tool === \"stamp-circle\" || tool === \"stamp-rectangle-4096px\" || tool === \"stamp-rectangle-2mm2\" || tool === \"stamp-circle-2mm2\" || tool === \"stamp-circle-hpf-0.2mm2\"\n );\n}\n\nfunction clampPositiveOrFallback(value: number | undefined, fallback: number): number {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value <= 0) {\n return fallback;\n }\n return value;\n}\n\nfunction resolveStampOptions(options: StampOptions | undefined): Required<StampOptions> {\n return {\n rectangleAreaMm2: clampPositiveOrFallback(options?.rectangleAreaMm2, DEFAULT_STAMP_RECTANGLE_AREA_MM2),\n circleAreaMm2: clampPositiveOrFallback(options?.circleAreaMm2, DEFAULT_STAMP_CIRCLE_AREA_MM2),\n rectanglePixelSize: clampPositiveOrFallback(options?.rectanglePixelSize, DEFAULT_STAMP_RECTANGLE_PIXEL_SIZE),\n };\n}\n\nfunction mm2ToUm2(areaMm2: number): number {\n return areaMm2 * MICRONS_PER_MM * MICRONS_PER_MM;\n}\n\nfunction createSquareFromCenter(center: DrawCoordinate | null, halfLength: number): DrawCoordinate[] {\n if (!center || !Number.isFinite(halfLength) || halfLength <= 0) return [];\n return closeRing([\n [center[0] - halfLength, center[1] - halfLength],\n [center[0] + halfLength, center[1] - halfLength],\n [center[0] + halfLength, center[1] + halfLength],\n [center[0] - halfLength, center[1] + halfLength],\n ]);\n}\n\nfunction createCircleFromCenter(center: DrawCoordinate | null, radius: number, sides = CIRCLE_SIDES): DrawCoordinate[] {\n if (!center || !Number.isFinite(radius) || radius <= 0) return [];\n\n const coords: DrawCoordinate[] = [];\n for (let i = 0; i <= sides; i += 1) {\n const t = (i / sides) * Math.PI * 2;\n coords.push([center[0] + Math.cos(t) * radius, center[1] + Math.sin(t) * radius]);\n }\n\n return closeRing(coords);\n}\n\nexport function closeRing(coords: DrawCoordinate[]): DrawCoordinate[] {\n if (!Array.isArray(coords) || coords.length < 3) return [];\n\n const out = coords.map(([x, y]) => [x, y] as DrawCoordinate);\n const first = out[0];\n const last = out[out.length - 1];\n if (!first || !last) return [];\n\n if (first[0] !== last[0] || first[1] !== last[1]) {\n out.push([first[0], first[1]]);\n }\n\n return out;\n}\n\nexport function createRectangle(start: DrawCoordinate | null, end: DrawCoordinate | null): DrawCoordinate[] {\n if (!start || !end) return [];\n\n return closeRing([\n [start[0], start[1]],\n [end[0], start[1]],\n [end[0], end[1]],\n [start[0], end[1]],\n ]);\n}\n\nexport function createCircle(start: DrawCoordinate | null, end: DrawCoordinate | null, sides = CIRCLE_SIDES): DrawCoordinate[] {\n if (!start || !end) return [];\n\n const centerX = (start[0] + end[0]) * 0.5;\n const centerY = (start[1] + end[1]) * 0.5;\n const radius = Math.hypot(end[0] - start[0], end[1] - start[1]) * 0.5;\n if (radius < 1) return [];\n\n const coords: DrawCoordinate[] = [];\n for (let i = 0; i <= sides; i += 1) {\n const t = (i / sides) * Math.PI * 2;\n coords.push([centerX + Math.cos(t) * radius, centerY + Math.sin(t) * radius]);\n }\n\n return closeRing(coords);\n}\n\nfunction polygonArea(coords: DrawCoordinate[]): number {\n if (!Array.isArray(coords) || coords.length < 4) return 0;\n\n let sum = 0;\n for (let i = 0; i < coords.length - 1; i += 1) {\n const a = coords[i];\n const b = coords[i + 1];\n sum += a[0] * b[1] - b[0] * a[1];\n }\n\n return Math.abs(sum * 0.5);\n}\n\nfunction computeBounds(coords: DrawCoordinate[]): DrawBounds {\n if (!Array.isArray(coords) || coords.length === 0) return [0, 0, 0, 0];\n\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n\n for (const [x, y] of coords) {\n if (x < minX) minX = x;\n if (x > maxX) maxX = x;\n if (y < minY) minY = y;\n if (y > maxY) maxY = y;\n }\n\n return [minX, minY, maxX, maxY];\n}\n\nfunction isValidPolygon(coords: DrawCoordinate[]): boolean {\n return Array.isArray(coords) && coords.length >= 4 && polygonArea(coords) > MIN_AREA_PX;\n}\n\nfunction drawPath(ctx: CanvasRenderingContext2D, points: DrawCoordinate[], strokeStyle: RegionStrokeStyle, close = false, fill = false): void {\n if (points.length === 0) return;\n\n ctx.beginPath();\n ctx.moveTo(points[0][0], points[0][1]);\n for (let i = 1; i < points.length; i += 1) {\n ctx.lineTo(points[i][0], points[i][1]);\n }\n\n if (close) {\n ctx.closePath();\n }\n if (fill && close) {\n ctx.fillStyle = DRAW_FILL;\n ctx.fill();\n }\n\n ctx.strokeStyle = strokeStyle.color;\n ctx.lineWidth = strokeStyle.width;\n ctx.lineJoin = strokeStyle.lineJoin;\n ctx.lineCap = strokeStyle.lineCap;\n ctx.shadowColor = strokeStyle.shadowColor;\n ctx.shadowBlur = strokeStyle.shadowBlur;\n ctx.shadowOffsetX = strokeStyle.shadowOffsetX;\n ctx.shadowOffsetY = strokeStyle.shadowOffsetY;\n ctx.setLineDash(strokeStyle.lineDash);\n ctx.stroke();\n ctx.setLineDash(EMPTY_DASH);\n ctx.shadowColor = \"rgba(0, 0, 0, 0)\";\n ctx.shadowBlur = 0;\n ctx.shadowOffsetX = 0;\n ctx.shadowOffsetY = 0;\n}\n\nfunction resolveStrokeStyle(style: Partial<RegionStrokeStyle> | undefined): RegionStrokeStyle {\n const dash = Array.isArray(style?.lineDash) ? style.lineDash.filter(value => Number.isFinite(value) && value >= 0) : EMPTY_DASH;\n const width = typeof style?.width === \"number\" && Number.isFinite(style.width) ? Math.max(0, style.width) : DEFAULT_REGION_STROKE_STYLE.width;\n const shadowBlur = typeof style?.shadowBlur === \"number\" && Number.isFinite(style.shadowBlur) ? Math.max(0, style.shadowBlur) : DEFAULT_REGION_STROKE_STYLE.shadowBlur;\n const shadowOffsetX = typeof style?.shadowOffsetX === \"number\" && Number.isFinite(style.shadowOffsetX) ? style.shadowOffsetX : DEFAULT_REGION_STROKE_STYLE.shadowOffsetX;\n const shadowOffsetY = typeof style?.shadowOffsetY === \"number\" && Number.isFinite(style.shadowOffsetY) ? style.shadowOffsetY : DEFAULT_REGION_STROKE_STYLE.shadowOffsetY;\n return {\n color: style?.color || DEFAULT_REGION_STROKE_STYLE.color,\n width,\n lineDash: dash.length ? dash : EMPTY_DASH,\n lineJoin: style?.lineJoin || DEFAULT_REGION_STROKE_STYLE.lineJoin,\n lineCap: style?.lineCap || DEFAULT_REGION_STROKE_STYLE.lineCap,\n shadowColor: style?.shadowColor || DEFAULT_REGION_STROKE_STYLE.shadowColor,\n shadowBlur,\n shadowOffsetX,\n shadowOffsetY,\n };\n}\n\nfunction mergeStrokeStyle(base: RegionStrokeStyle, override: Partial<RegionStrokeStyle> | undefined): RegionStrokeStyle {\n if (!override) return base;\n return resolveStrokeStyle({\n color: override.color ?? base.color,\n width: override.width ?? base.width,\n lineDash: override.lineDash ?? base.lineDash,\n lineJoin: override.lineJoin ?? base.lineJoin,\n lineCap: override.lineCap ?? base.lineCap,\n shadowColor: override.shadowColor ?? base.shadowColor,\n shadowBlur: override.shadowBlur ?? base.shadowBlur,\n shadowOffsetX: override.shadowOffsetX ?? base.shadowOffsetX,\n shadowOffsetY: override.shadowOffsetY ?? base.shadowOffsetY,\n });\n}\n\nfunction isSameRegionId(a: string | number | null | undefined, b: string | number | null | undefined): boolean {\n if (a === null || a === undefined || b === null || b === undefined) {\n return false;\n }\n return String(a) === String(b);\n}\n\nfunction resolveLabelStyle(style: Partial<RegionLabelStyle> | undefined): RegionLabelStyle {\n const px = typeof style?.paddingX === \"number\" && Number.isFinite(style.paddingX) ? Math.max(0, style.paddingX) : DEFAULT_REGION_LABEL_STYLE.paddingX;\n const py = typeof style?.paddingY === \"number\" && Number.isFinite(style.paddingY) ? Math.max(0, style.paddingY) : DEFAULT_REGION_LABEL_STYLE.paddingY;\n const fs = typeof style?.fontSize === \"number\" && Number.isFinite(style.fontSize) ? Math.max(8, style.fontSize) : DEFAULT_REGION_LABEL_STYLE.fontSize;\n const bw = typeof style?.borderWidth === \"number\" && Number.isFinite(style.borderWidth) ? Math.max(0, style.borderWidth) : DEFAULT_REGION_LABEL_STYLE.borderWidth;\n const oy = typeof style?.offsetY === \"number\" && Number.isFinite(style.offsetY) ? style.offsetY : DEFAULT_REGION_LABEL_STYLE.offsetY;\n const br = typeof style?.borderRadius === \"number\" && Number.isFinite(style.borderRadius) ? Math.max(0, style.borderRadius) : DEFAULT_REGION_LABEL_STYLE.borderRadius;\n return {\n fontFamily: style?.fontFamily || DEFAULT_REGION_LABEL_STYLE.fontFamily,\n fontSize: fs,\n fontWeight: style?.fontWeight || DEFAULT_REGION_LABEL_STYLE.fontWeight,\n textColor: style?.textColor || DEFAULT_REGION_LABEL_STYLE.textColor,\n backgroundColor: style?.backgroundColor || DEFAULT_REGION_LABEL_STYLE.backgroundColor,\n borderColor: style?.borderColor || DEFAULT_REGION_LABEL_STYLE.borderColor,\n borderWidth: bw,\n paddingX: px,\n paddingY: py,\n offsetY: oy,\n borderRadius: br,\n };\n}\n\nfunction drawRoundedRect(ctx: CanvasRenderingContext2D, x: number, y: number, width: number, height: number, radius: number): void {\n const r = Math.max(0, Math.min(radius, width * 0.5, height * 0.5));\n ctx.beginPath();\n ctx.moveTo(x + r, y);\n ctx.lineTo(x + width - r, y);\n ctx.quadraticCurveTo(x + width, y, x + width, y + r);\n ctx.lineTo(x + width, y + height - r);\n ctx.quadraticCurveTo(x + width, y + height, x + width - r, y + height);\n ctx.lineTo(x + r, y + height);\n ctx.quadraticCurveTo(x, y + height, x, y + height - r);\n ctx.lineTo(x, y + r);\n ctx.quadraticCurveTo(x, y, x + r, y);\n ctx.closePath();\n}\n\nfunction getTopAnchor(coords: DrawCoordinate[]): DrawCoordinate | null {\n if (!coords.length) return null;\n\n let minY = Infinity;\n for (const point of coords) {\n if (point[1] < minY) minY = point[1];\n }\n if (!Number.isFinite(minY)) return null;\n\n let minX = Infinity;\n let maxX = -Infinity;\n for (const point of coords) {\n if (Math.abs(point[1] - minY) > 0.5) continue;\n if (point[0] < minX) minX = point[0];\n if (point[0] > maxX) maxX = point[0];\n }\n\n if (!Number.isFinite(minX) || !Number.isFinite(maxX)) return null;\n return [(minX + maxX) * 0.5, minY];\n}\n\nfunction drawRegionLabel(ctx: CanvasRenderingContext2D, text: string, anchor: DrawCoordinate, canvasWidth: number, canvasHeight: number, labelStyle: RegionLabelStyle): void {\n const label = text.trim();\n if (!label) return;\n\n ctx.save();\n ctx.font = `${labelStyle.fontWeight} ${labelStyle.fontSize}px ${labelStyle.fontFamily}`;\n ctx.textAlign = \"center\";\n ctx.textBaseline = \"middle\";\n\n const textWidth = ctx.measureText(label).width;\n const boxWidth = textWidth + labelStyle.paddingX * 2;\n const boxHeight = labelStyle.fontSize + labelStyle.paddingY * 2;\n\n const x = clamp(anchor[0], boxWidth * 0.5 + 1, canvasWidth - boxWidth * 0.5 - 1);\n const y = clamp(anchor[1] - labelStyle.offsetY, boxHeight * 0.5 + 1, canvasHeight - boxHeight * 0.5 - 1);\n const left = x - boxWidth * 0.5;\n const top = y - boxHeight * 0.5;\n\n ctx.fillStyle = labelStyle.backgroundColor;\n ctx.strokeStyle = labelStyle.borderColor;\n ctx.lineWidth = labelStyle.borderWidth;\n drawRoundedRect(ctx, left, top, boxWidth, boxHeight, labelStyle.borderRadius);\n ctx.fill();\n if (labelStyle.borderWidth > 0) {\n ctx.stroke();\n }\n\n ctx.fillStyle = labelStyle.textColor;\n ctx.fillText(label, x, y + 0.5);\n ctx.restore();\n}\n\nfunction clampWorld(coord: DrawCoordinate, imageWidth: number, imageHeight: number): DrawCoordinate {\n return [clamp(coord[0], 0, imageWidth), clamp(coord[1], 0, imageHeight)];\n}\n\nfunction toCoord(value: DrawCoordinate | number[]): DrawCoordinate | null {\n if (!Array.isArray(value) || value.length < 2) return null;\n const x = Number(value[0]);\n const y = Number(value[1]);\n if (!Number.isFinite(x) || !Number.isFinite(y)) return null;\n return [x, y];\n}\n\nexport function DrawLayer({\n tool,\n imageWidth,\n imageHeight,\n imageMpp,\n imageZoom,\n stampOptions,\n projectorRef,\n onDrawComplete,\n onPatchComplete,\n enabled,\n viewStateSignal,\n persistedRegions,\n patchRegions,\n persistedPolygons,\n regionStrokeStyle,\n regionStrokeHoverStyle,\n regionStrokeActiveStyle,\n patchStrokeStyle,\n resolveRegionStrokeStyle,\n overlayShapes,\n hoveredRegionId = null,\n activeRegionId = null,\n regionLabelStyle,\n invalidateRef,\n className,\n style,\n}: DrawLayerProps): React.ReactElement {\n const canvasRef = useRef<HTMLCanvasElement | null>(null);\n const drawPendingRef = useRef(false);\n const lastToolRef = useRef<DrawTool>(tool);\n const sessionRef = useRef<DrawSession>({\n isDrawing: false,\n pointerId: null,\n start: null,\n current: null,\n points: [],\n stampCenter: null,\n });\n\n const active = enabled ?? tool !== \"cursor\";\n const mergedPersistedRegions = useMemo<DrawRegion[]>(() => {\n if (persistedRegions && persistedRegions.length > 0) {\n return persistedRegions;\n }\n if (!persistedPolygons || persistedPolygons.length === 0) {\n return EMPTY_REGIONS;\n }\n return persistedPolygons.map((coordinates, index) => ({\n id: index,\n coordinates,\n }));\n }, [persistedRegions, persistedPolygons]);\n const mergedPatchRegions = useMemo<DrawRegion[]>(() => patchRegions ?? EMPTY_REGIONS, [patchRegions]);\n\n const resolvedStrokeStyle = useMemo(() => resolveStrokeStyle(regionStrokeStyle), [regionStrokeStyle]);\n const resolvedHoverStrokeStyle = useMemo(() => mergeStrokeStyle(resolvedStrokeStyle, regionStrokeHoverStyle), [resolvedStrokeStyle, regionStrokeHoverStyle]);\n const resolvedActiveStrokeStyle = useMemo(() => mergeStrokeStyle(resolvedStrokeStyle, regionStrokeActiveStyle), [resolvedStrokeStyle, regionStrokeActiveStyle]);\n const resolvedPatchStrokeStyle = useMemo(() => mergeStrokeStyle(DEFAULT_PATCH_STROKE_STYLE, patchStrokeStyle), [patchStrokeStyle]);\n\n const resolvedLabelStyle = useMemo(() => resolveLabelStyle(regionLabelStyle), [regionLabelStyle]);\n const resolvedStampOptions = useMemo(() => resolveStampOptions(stampOptions), [stampOptions]);\n\n const mergedStyle = useMemo<CSSProperties>(\n () => ({\n position: \"absolute\",\n inset: 0,\n zIndex: 2,\n width: \"100%\",\n height: \"100%\",\n display: \"block\",\n touchAction: \"none\",\n pointerEvents: active ? \"auto\" : \"none\",\n cursor: active ? \"crosshair\" : \"default\",\n ...style,\n }),\n [active, style]\n );\n\n const resizeCanvas = useCallback(() => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n\n const rect = canvas.getBoundingClientRect();\n const dpr = Math.max(1, window.devicePixelRatio || 1);\n const w = Math.max(1, Math.round(rect.width * dpr));\n const h = Math.max(1, Math.round(rect.height * dpr));\n\n if (canvas.width !== w || canvas.height !== h) {\n canvas.width = w;\n canvas.height = h;\n }\n }, []);\n\n const worldToScreenPoints = useCallback(\n (points: DrawCoordinate[]): DrawCoordinate[] => {\n const projector = projectorRef.current;\n if (!projector || points.length === 0) return [];\n\n const out = new Array<DrawCoordinate>(points.length);\n for (let i = 0; i < points.length; i += 1) {\n const coord = toCoord(projector.worldToScreen(points[i][0], points[i][1]));\n if (!coord) return [];\n out[i] = coord;\n }\n return out;\n },\n [projectorRef]\n );\n\n const micronsToWorldPixels = useCallback(\n (lengthUm: number): number => {\n if (!Number.isFinite(lengthUm) || lengthUm <= 0) return 0;\n\n // If mpp is missing, fall back to 1um/px assumption.\n const mppValue = typeof imageMpp === \"number\" && Number.isFinite(imageMpp) && imageMpp > 0 ? imageMpp : 1;\n const imageZoomValue = typeof imageZoom === \"number\" && Number.isFinite(imageZoom) ? imageZoom : 0;\n const viewZoomRaw = projectorRef.current?.getViewState?.().zoom;\n const viewZoom = typeof viewZoomRaw === \"number\" && Number.isFinite(viewZoomRaw) && viewZoomRaw > 0 ? viewZoomRaw : 1;\n const continuousZoom = imageZoomValue + Math.log2(viewZoom);\n const umPerScreenPixel = Math.max(1e-9, calcScaleResolution(mppValue, imageZoomValue, continuousZoom));\n const screenPixels = lengthUm / umPerScreenPixel;\n return screenPixels / viewZoom;\n },\n [imageMpp, imageZoom, projectorRef]\n );\n\n const buildStampCoords = useCallback(\n (stampTool: StampDrawTool, center: DrawCoordinate | null): DrawCoordinate[] => {\n if (!center) return [];\n\n let areaMm2 = 0;\n if (stampTool === \"stamp-rectangle-4096px\") {\n const halfLength = resolvedStampOptions.rectanglePixelSize * 0.5;\n const fixed = createSquareFromCenter(center, halfLength);\n return fixed.map(point => clampWorld(point, imageWidth, imageHeight));\n }\n\n if (stampTool === \"stamp-rectangle\" || stampTool === \"stamp-rectangle-2mm2\") {\n areaMm2 = stampTool === \"stamp-rectangle-2mm2\" ? DEFAULT_STAMP_RECTANGLE_AREA_MM2 : resolvedStampOptions.rectangleAreaMm2;\n } else if (stampTool === \"stamp-circle\" || stampTool === \"stamp-circle-2mm2\" || stampTool === \"stamp-circle-hpf-0.2mm2\") {\n areaMm2 = stampTool === \"stamp-circle-hpf-0.2mm2\" ? LEGACY_HPF_CIRCLE_AREA_MM2 : stampTool === \"stamp-circle-2mm2\" ? DEFAULT_STAMP_CIRCLE_AREA_MM2 : resolvedStampOptions.circleAreaMm2;\n }\n if (!Number.isFinite(areaMm2) || areaMm2 <= 0) return [];\n\n const areaUm2 = mm2ToUm2(areaMm2);\n let coords: DrawCoordinate[] = [];\n if (stampTool === \"stamp-rectangle\" || stampTool === \"stamp-rectangle-2mm2\") {\n const halfLength = micronsToWorldPixels(Math.sqrt(areaUm2) * 0.5);\n coords = createSquareFromCenter(center, halfLength);\n } else if (stampTool === \"stamp-circle\" || stampTool === \"stamp-circle-2mm2\" || stampTool === \"stamp-circle-hpf-0.2mm2\") {\n const radius = micronsToWorldPixels(Math.sqrt(areaUm2 / Math.PI));\n coords = createCircleFromCenter(center, radius);\n }\n\n if (!coords.length) return [];\n return coords.map(point => clampWorld(point, imageWidth, imageHeight));\n },\n [micronsToWorldPixels, imageWidth, imageHeight, resolvedStampOptions]\n );\n\n const buildPreviewCoords = useCallback((): DrawCoordinate[] => {\n const session = sessionRef.current;\n if (isStampTool(tool)) {\n return buildStampCoords(tool, session.stampCenter);\n }\n if (!session.isDrawing) return [];\n\n if (tool === \"freehand\") {\n return session.points;\n }\n if (tool === \"rectangle\") {\n return createRectangle(session.start, session.current);\n }\n if (tool === \"circular\") {\n return createCircle(session.start, session.current);\n }\n\n return [];\n }, [tool, buildStampCoords]);\n\n const drawOverlay = useCallback(() => {\n resizeCanvas();\n\n const canvas = canvasRef.current;\n if (!canvas) return;\n\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return;\n\n const dpr = Math.max(1, window.devicePixelRatio || 1);\n const canvasWidth = canvas.width / dpr;\n const canvasHeight = canvas.height / dpr;\n ctx.setTransform(1, 0, 0, 1, 0, 0);\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n\n // Persisted ROI outlines always remain visible.\n if (mergedPersistedRegions.length > 0) {\n for (let i = 0; i < mergedPersistedRegions.length; i += 1) {\n const region = mergedPersistedRegions[i];\n const ring = region?.coordinates;\n if (!ring || ring.length < 3) continue;\n const closed = closeRing(ring);\n const screen = worldToScreenPoints(closed);\n if (screen.length >= 4) {\n const regionKey = region.id ?? i;\n const state: RegionStyleContext[\"state\"] = isSameRegionId(activeRegionId, regionKey) ? \"active\" : isSameRegionId(hoveredRegionId, regionKey) ? \"hover\" : \"default\";\n let strokeStyle = state === \"active\" ? resolvedActiveStrokeStyle : state === \"hover\" ? resolvedHoverStrokeStyle : resolvedStrokeStyle;\n\n if (resolveRegionStrokeStyle) {\n const resolved = resolveRegionStrokeStyle({\n region,\n regionId: regionKey,\n regionIndex: i,\n state,\n });\n strokeStyle = mergeStrokeStyle(strokeStyle, resolved || undefined);\n }\n drawPath(ctx, screen, strokeStyle, true, false);\n }\n }\n }\n\n if (mergedPatchRegions.length > 0) {\n for (let i = 0; i < mergedPatchRegions.length; i += 1) {\n const region = mergedPatchRegions[i];\n const ring = region?.coordinates;\n if (!ring || ring.length < 3) continue;\n const closed = closeRing(ring);\n const screen = worldToScreenPoints(closed);\n if (screen.length < 4) continue;\n drawPath(ctx, screen, resolvedPatchStrokeStyle, true, false);\n }\n }\n\n if (Array.isArray(overlayShapes) && overlayShapes.length > 0) {\n for (let i = 0; i < overlayShapes.length; i += 1) {\n const shape = overlayShapes[i];\n if (!shape?.coordinates?.length) continue;\n const closed = shape.closed ?? false;\n const points = closed ? closeRing(shape.coordinates) : shape.coordinates;\n const screen = worldToScreenPoints(points);\n if (screen.length < 2) continue;\n const strokeStyle = mergeStrokeStyle(resolvedStrokeStyle, shape.strokeStyle);\n drawPath(ctx, screen, strokeStyle, closed, shape.fill ?? false);\n }\n }\n\n if (active) {\n const preview = buildPreviewCoords();\n if (preview.length > 0) {\n if (tool === \"freehand\") {\n const line = worldToScreenPoints(preview);\n if (line.length >= 2) {\n drawPath(ctx, line, resolvedStrokeStyle, false, false);\n }\n if (line.length >= 3) {\n drawPath(ctx, worldToScreenPoints(closeRing(preview)), resolvedStrokeStyle, true, true);\n }\n } else {\n const polygon = worldToScreenPoints(preview);\n if (polygon.length >= 4) {\n drawPath(ctx, polygon, resolvedStrokeStyle, true, true);\n }\n }\n }\n }\n\n // Draw labels last so they stay visually on top.\n if (mergedPersistedRegions.length > 0) {\n for (const region of mergedPersistedRegions) {\n if (!region.label) continue;\n const ring = region?.coordinates;\n if (!ring || ring.length < 3) continue;\n const closed = closeRing(ring);\n const anchorWorld = getTopAnchor(closed);\n if (!anchorWorld) continue;\n const anchorScreen = toCoord(projectorRef.current?.worldToScreen(anchorWorld[0], anchorWorld[1]) ?? []);\n if (!anchorScreen) continue;\n drawRegionLabel(ctx, region.label, anchorScreen, canvasWidth, canvasHeight, resolvedLabelStyle);\n }\n }\n }, [\n active,\n tool,\n buildPreviewCoords,\n resizeCanvas,\n worldToScreenPoints,\n projectorRef,\n mergedPersistedRegions,\n overlayShapes,\n hoveredRegionId,\n activeRegionId,\n resolvedStrokeStyle,\n resolvedHoverStrokeStyle,\n resolvedActiveStrokeStyle,\n mergedPatchRegions,\n resolvedPatchStrokeStyle,\n resolveRegionStrokeStyle,\n resolvedLabelStyle,\n ]);\n\n const requestDraw = useCallback(() => {\n if (drawPendingRef.current) return;\n drawPendingRef.current = true;\n requestAnimationFrame(() => {\n drawPendingRef.current = false;\n drawOverlay();\n });\n }, [drawOverlay]);\n\n const resetSession = useCallback(() => {\n const session = sessionRef.current;\n const canvas = canvasRef.current;\n\n if (canvas && session.pointerId !== null && canvas.hasPointerCapture(session.pointerId)) {\n try {\n canvas.releasePointerCapture(session.pointerId);\n } catch {\n // noop\n }\n }\n\n session.isDrawing = false;\n session.pointerId = null;\n session.start = null;\n session.current = null;\n session.points = [];\n session.stampCenter = null;\n }, []);\n\n const toWorld = useCallback(\n (event: ReactPointerEvent<HTMLCanvasElement>): DrawCoordinate | null => {\n const projector = projectorRef.current;\n if (!projector || imageWidth <= 0 || imageHeight <= 0) return null;\n\n const raw = toCoord(projector.screenToWorld(event.clientX, event.clientY));\n if (!raw) return null;\n return clampWorld(raw, imageWidth, imageHeight);\n },\n [projectorRef, imageWidth, imageHeight]\n );\n\n const finishSession = useCallback(() => {\n const session = sessionRef.current;\n if (!session.isDrawing) {\n resetSession();\n requestDraw();\n return;\n }\n\n let coordinates: DrawCoordinate[] = [];\n if (tool === \"freehand\") {\n if (session.points.length >= FREEHAND_MIN_POINTS) {\n coordinates = closeRing(session.points);\n }\n } else if (tool === \"rectangle\") {\n coordinates = createRectangle(session.start, session.current);\n } else if (tool === \"circular\") {\n coordinates = createCircle(session.start, session.current);\n }\n\n if ((tool === \"freehand\" || tool === \"rectangle\" || tool === \"circular\") && isValidPolygon(coordinates) && onDrawComplete) {\n onDrawComplete({\n tool,\n intent: \"roi\",\n coordinates,\n bbox: computeBounds(coordinates),\n areaPx: polygonArea(coordinates),\n });\n }\n\n resetSession();\n requestDraw();\n }, [tool, onDrawComplete, resetSession, requestDraw]);\n\n const handleStampAt = useCallback(\n (stampTool: StampDrawTool, center: DrawCoordinate): void => {\n const coordinates = buildStampCoords(stampTool, center);\n if (!isValidPolygon(coordinates)) return;\n const intent: DrawIntent = stampTool === \"stamp-rectangle-4096px\" ? \"patch\" : \"roi\";\n const result: DrawResult = {\n tool: stampTool,\n intent,\n coordinates,\n bbox: computeBounds(coordinates),\n areaPx: polygonArea(coordinates),\n };\n onDrawComplete?.(result);\n if (intent === \"patch\" && onPatchComplete) {\n onPatchComplete(result as PatchDrawResult);\n }\n },\n [buildStampCoords, onDrawComplete, onPatchComplete]\n );\n\n const handlePointerDown = useCallback(\n (event: ReactPointerEvent<HTMLCanvasElement>) => {\n if (!active) return;\n if (tool === \"cursor\") return;\n if (event.button !== 0) return;\n\n const world = toWorld(event);\n if (!world) return;\n\n event.preventDefault();\n event.stopPropagation();\n\n if (isStampTool(tool)) {\n const session = sessionRef.current;\n session.stampCenter = world;\n handleStampAt(tool, world);\n requestDraw();\n return;\n }\n\n const canvas = canvasRef.current;\n if (canvas) {\n canvas.setPointerCapture(event.pointerId);\n }\n\n const session = sessionRef.current;\n session.isDrawing = true;\n session.pointerId = event.pointerId;\n session.start = world;\n session.current = world;\n session.points = tool === \"freehand\" ? [world] : [];\n requestDraw();\n },\n [active, tool, toWorld, handleStampAt, requestDraw]\n );\n\n const handlePointerMove = useCallback(\n (event: ReactPointerEvent<HTMLCanvasElement>) => {\n if (!active) return;\n if (tool === \"cursor\") return;\n\n const world = toWorld(event);\n if (!world) return;\n\n if (isStampTool(tool)) {\n const session = sessionRef.current;\n session.stampCenter = world;\n event.preventDefault();\n event.stopPropagation();\n requestDraw();\n return;\n }\n\n const session = sessionRef.current;\n if (!session.isDrawing || session.pointerId !== event.pointerId) {\n return;\n }\n event.preventDefault();\n event.stopPropagation();\n\n if (tool === \"freehand\") {\n const projector = projectorRef.current;\n const zoom = Math.max(1e-6, projector?.getViewState?.().zoom ?? 1);\n const minWorldStep = FREEHAND_SCREEN_STEP / zoom;\n const minWorldStep2 = minWorldStep * minWorldStep;\n const prev = session.points[session.points.length - 1];\n\n if (!prev) {\n session.points.push(world);\n } else {\n const dx = world[0] - prev[0];\n const dy = world[1] - prev[1];\n if (dx * dx + dy * dy >= minWorldStep2) {\n session.points.push(world);\n }\n }\n } else {\n session.current = world;\n }\n\n requestDraw();\n },\n [active, tool, toWorld, requestDraw, projectorRef]\n );\n\n const handlePointerUp = useCallback(\n (event: ReactPointerEvent<HTMLCanvasElement>) => {\n const session = sessionRef.current;\n if (!session.isDrawing || session.pointerId !== event.pointerId) return;\n\n event.preventDefault();\n event.stopPropagation();\n const canvas = canvasRef.current;\n if (canvas && canvas.hasPointerCapture(event.pointerId)) {\n try {\n canvas.releasePointerCapture(event.pointerId);\n } catch {\n // noop\n }\n }\n\n finishSession();\n },\n [finishSession]\n );\n\n const handlePointerLeave = useCallback(() => {\n if (!isStampTool(tool)) return;\n const session = sessionRef.current;\n if (!session.stampCenter) return;\n session.stampCenter = null;\n requestDraw();\n }, [tool, requestDraw]);\n\n useEffect(() => {\n resizeCanvas();\n requestDraw();\n\n const canvas = canvasRef.current;\n if (!canvas) return undefined;\n\n const observer = new ResizeObserver(() => {\n resizeCanvas();\n requestDraw();\n });\n observer.observe(canvas);\n\n return () => {\n observer.disconnect();\n };\n }, [resizeCanvas, requestDraw]);\n\n useEffect(() => {\n if (!active) {\n resetSession();\n }\n requestDraw();\n }, [active, requestDraw, resetSession]);\n\n useEffect(() => {\n if (lastToolRef.current === tool) {\n return;\n }\n lastToolRef.current = tool;\n resetSession();\n requestDraw();\n }, [tool, resetSession, requestDraw]);\n\n useEffect(() => {\n requestDraw();\n }, [viewStateSignal, mergedPersistedRegions, overlayShapes, requestDraw]);\n\n useEffect(() => {\n if (!invalidateRef) return undefined;\n invalidateRef.current = requestDraw;\n return () => {\n if (invalidateRef.current === requestDraw) {\n invalidateRef.current = null;\n }\n };\n }, [invalidateRef, requestDraw]);\n\n useEffect(() => {\n if (!active) return undefined;\n\n const onKeyDown = (event: KeyboardEvent): void => {\n if (event.key !== \"Escape\") return;\n resetSession();\n requestDraw();\n };\n\n window.addEventListener(\"keydown\", onKeyDown);\n return () => {\n window.removeEventListener(\"keydown\", onKeyDown);\n };\n }, [active, resetSession, requestDraw]);\n\n return (\n <canvas\n ref={canvasRef}\n className={className}\n style={mergedStyle}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n onPointerCancel={handlePointerUp}\n onPointerLeave={handlePointerLeave}\n onContextMenu={event => {\n if (active) event.preventDefault();\n }}\n onWheel={event => {\n if (active) event.preventDefault();\n }}\n />\n );\n}\n","import type { WsiImageSource, WsiTerm } from \"./types\";\n\nfunction trimTrailingSlash(value: string): string {\n return String(value ?? \"\").replace(/\\/+$/, \"\");\n}\n\nfunction ensureLeadingSlash(value: string): string {\n const raw = String(value ?? \"\");\n return raw.startsWith(\"/\") ? raw : `/${raw}`;\n}\n\nfunction joinImsTileRoot(tileBaseUrl: string): string {\n const base = trimTrailingSlash(tileBaseUrl);\n if (!base) return \"\";\n\n // Explicit TileGroup path already provided.\n if (/\\/TileGroup\\d+$/i.test(base)) return base;\n\n let parsed: URL | null = null;\n try {\n parsed = new URL(base);\n } catch {\n parsed = null;\n }\n\n if (parsed) {\n const origin = `${parsed.protocol}//${parsed.host}`;\n const path = trimTrailingSlash(parsed.pathname || \"\");\n\n // If caller passes /ims, keep /ims and append image path directly:\n // /ims + /tiles/<hash> + /tier/y_x.webp\n if (/\\/ims$/i.test(path)) return `${origin}${path}`;\n if (/\\/tiles$/i.test(path)) return `${origin}${path}`;\n return `${origin}${path}/tiles`;\n }\n\n // Relative path mode\n if (/\\/ims$/i.test(base)) return `/ims`;\n if (/\\/tiles$/i.test(base)) return `${base}`;\n return `${base}/tiles`;\n}\n\nexport function normalizeImageInfo(raw: any, tileBaseUrl: string): WsiImageSource {\n const ims = raw?.imsInfo || {};\n const isIms = !!raw?.imsInfo;\n\n const width = Number(ims.width ?? raw?.width ?? 0);\n const height = Number(ims.height ?? raw?.height ?? 0);\n const tileSize = Number(ims.tileSize ?? raw?.tileSize ?? 0);\n const maxTierZoom = Number(ims.zoom ?? raw?.zoom ?? 0);\n const tilePath = String(ims.path ?? raw?.path ?? \"\");\n const mpp = Number(ims.mpp ?? raw?.mpp ?? 0);\n\n if (!width || !height || !tileSize || !tilePath) {\n throw new Error(\"이미지 메타데이터가 불완전합니다. width/height/tileSize/path 확인 필요\");\n }\n\n const terms: WsiTerm[] = Array.isArray(raw?.terms)\n ? raw.terms.map((term: any) => ({\n termId: String(term?.termId ?? \"\"),\n termName: String(term?.termName ?? \"\"),\n termColor: String(term?.termColor ?? \"\"),\n }))\n : [];\n\n const normalizedPath = ensureLeadingSlash(tilePath);\n const imsTileRoot = joinImsTileRoot(tileBaseUrl);\n const tileUrlBuilder = isIms ? (tier: number, x: number, y: number): string => `${imsTileRoot}${normalizedPath}/${tier}/${y}_${x}.webp` : undefined;\n\n return {\n id: raw?._id || \"unknown\",\n name: raw?.name || \"unknown\",\n width,\n height,\n mpp: Number.isFinite(mpp) && mpp > 0 ? mpp : undefined,\n tileSize,\n maxTierZoom: Number.isFinite(maxTierZoom) ? Math.max(0, Math.floor(maxTierZoom)) : 0,\n tilePath,\n tileBaseUrl,\n terms,\n tileUrlBuilder,\n };\n}\n\nexport function toTileUrl(source: Pick<WsiImageSource, \"tilePath\" | \"tileBaseUrl\" | \"tileUrlBuilder\">, tier: number, x: number, y: number): string {\n if (source.tileUrlBuilder) {\n return source.tileUrlBuilder(tier, x, y);\n }\n const normalizedPath = ensureLeadingSlash(source.tilePath);\n return `${source.tileBaseUrl}${normalizedPath}/${tier}/${y}_${x}.webp`;\n}\n","import {\n\ttype CSSProperties,\n\ttype MutableRefObject,\n\ttype PointerEvent as ReactPointerEvent,\n\ttype RefObject,\n\tuseCallback,\n\tuseEffect,\n\tuseMemo,\n\tuseRef,\n} from \"react\";\nimport { toTileUrl } from \"../wsi/image-info\";\nimport type { WsiImageSource, WsiViewState } from \"../wsi/types\";\nimport { clamp } from \"../wsi/utils\";\n\ntype Bounds = [number, number, number, number];\n\nexport interface OverviewMapProjector {\n\tgetViewState: () => WsiViewState;\n\tsetViewState: (next: Partial<WsiViewState>) => void;\n\tsetViewCenter?: (worldX: number, worldY: number) => void;\n\tgetViewBounds?: () => number[];\n\tgetViewCorners?: () => Array<[number, number]>;\n}\n\nexport type OverviewMapPosition =\n\t| \"bottom-right\"\n\t| \"bottom-left\"\n\t| \"top-right\"\n\t| \"top-left\";\n\nexport interface OverviewMapOptions {\n\twidth: number;\n\theight: number;\n\tmargin: number;\n\tposition: OverviewMapPosition;\n\tborderRadius: number;\n\tborderWidth: number;\n\tbackgroundColor: string;\n\tborderColor: string;\n\tviewportStrokeColor: string;\n\tviewportFillColor: string;\n\tinteractive: boolean;\n\tshowThumbnail: boolean;\n\tmaxThumbnailTiles: number;\n}\n\nexport interface OverviewMapProps {\n\tsource: WsiImageSource;\n\tprojectorRef: RefObject<OverviewMapProjector | null>;\n\tauthToken?: string;\n\toptions?: Partial<OverviewMapOptions>;\n\tinvalidateRef?: MutableRefObject<(() => void) | null>;\n\tclassName?: string;\n\tstyle?: CSSProperties;\n}\n\nconst DEFAULT_OVERVIEW_MAP_OPTIONS: OverviewMapOptions = {\n\twidth: 220,\n\theight: 140,\n\tmargin: 16,\n\tposition: \"bottom-right\",\n\tborderRadius: 10,\n\tborderWidth: 1.5,\n\tbackgroundColor: \"rgba(4, 10, 18, 0.88)\",\n\tborderColor: \"rgba(230, 244, 255, 0.35)\",\n\tviewportStrokeColor: \"rgba(255, 106, 61, 0.95)\",\n\tviewportFillColor: \"rgba(255, 106, 61, 0.2)\",\n\tinteractive: true,\n\tshowThumbnail: true,\n\tmaxThumbnailTiles: 16,\n};\n\nfunction toPositiveNumber(\n\tvalue: number | undefined,\n\tfallback: number,\n\tmin = 1,\n): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) return fallback;\n\treturn Math.max(min, value);\n}\n\nfunction isFiniteBounds(bounds: number[] | null | undefined): bounds is Bounds {\n\treturn (\n\t\tArray.isArray(bounds) &&\n\t\tbounds.length === 4 &&\n\t\tNumber.isFinite(bounds[0]) &&\n\t\tNumber.isFinite(bounds[1]) &&\n\t\tNumber.isFinite(bounds[2]) &&\n\t\tNumber.isFinite(bounds[3])\n\t);\n}\n\nexport function OverviewMap({\n\tsource,\n\tprojectorRef,\n\tauthToken = \"\",\n\toptions,\n\tinvalidateRef,\n\tclassName,\n\tstyle,\n}: OverviewMapProps): React.ReactElement {\n\tconst canvasRef = useRef<HTMLCanvasElement | null>(null);\n\tconst thumbnailRef = useRef<HTMLCanvasElement | null>(null);\n\tconst lastBoundsRef = useRef<Bounds | null>(null);\n\tconst draggingRef = useRef<{ active: boolean; pointerId: number | null }>({\n\t\tactive: false,\n\t\tpointerId: null,\n\t});\n\tconst rafRef = useRef<number | null>(null);\n\tconst drawPendingRef = useRef(false);\n\n\tconst width = toPositiveNumber(\n\t\toptions?.width,\n\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.width,\n\t\t64,\n\t);\n\tconst height = toPositiveNumber(\n\t\toptions?.height,\n\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.height,\n\t\t48,\n\t);\n\tconst margin = toPositiveNumber(\n\t\toptions?.margin,\n\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.margin,\n\t\t0,\n\t);\n\tconst borderRadius = toPositiveNumber(\n\t\toptions?.borderRadius,\n\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.borderRadius,\n\t\t0,\n\t);\n\tconst borderWidth = toPositiveNumber(\n\t\toptions?.borderWidth,\n\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.borderWidth,\n\t\t0,\n\t);\n\tconst maxThumbnailTiles = Math.max(\n\t\t1,\n\t\tMath.round(\n\t\t\ttoPositiveNumber(\n\t\t\t\toptions?.maxThumbnailTiles,\n\t\t\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.maxThumbnailTiles,\n\t\t\t\t1,\n\t\t\t),\n\t\t),\n\t);\n\n\tconst backgroundColor =\n\t\toptions?.backgroundColor || DEFAULT_OVERVIEW_MAP_OPTIONS.backgroundColor;\n\tconst borderColor =\n\t\toptions?.borderColor || DEFAULT_OVERVIEW_MAP_OPTIONS.borderColor;\n\tconst viewportStrokeColor =\n\t\toptions?.viewportStrokeColor ||\n\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.viewportStrokeColor;\n\tconst viewportFillColor =\n\t\toptions?.viewportFillColor ||\n\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.viewportFillColor;\n\tconst interactive =\n\t\toptions?.interactive ?? DEFAULT_OVERVIEW_MAP_OPTIONS.interactive;\n\tconst showThumbnail =\n\t\toptions?.showThumbnail ?? DEFAULT_OVERVIEW_MAP_OPTIONS.showThumbnail;\n\tconst position =\n\t\toptions?.position || DEFAULT_OVERVIEW_MAP_OPTIONS.position;\n\n\tconst mergedStyle = useMemo<CSSProperties>(() => {\n\t\tconst pos: CSSProperties = {};\n\t\tif (position === \"top-left\" || position === \"bottom-left\") pos.left = margin;\n\t\telse pos.right = margin;\n\t\tif (position === \"top-left\" || position === \"top-right\") pos.top = margin;\n\t\telse pos.bottom = margin;\n\n\t\treturn {\n\t\t\tposition: \"absolute\",\n\t\t\t...pos,\n\t\t\twidth,\n\t\t\theight,\n\t\t\tborderRadius,\n\t\t\toverflow: \"hidden\",\n\t\t\tzIndex: 4,\n\t\t\tpointerEvents: interactive ? \"auto\" : \"none\",\n\t\t\ttouchAction: \"none\",\n\t\t\tboxShadow: \"0 10px 22px rgba(0, 0, 0, 0.3)\",\n\t\t\t...style,\n\t\t};\n\t}, [margin, position, width, height, borderRadius, interactive, style]);\n\n\tconst draw = useCallback(() => {\n\t\tconst canvas = canvasRef.current;\n\t\tif (!canvas) return;\n\n\t\tconst ctx = canvas.getContext(\"2d\");\n\t\tif (!ctx) return;\n\n\t\tconst cssW = width;\n\t\tconst cssH = height;\n\t\tconst dpr = Math.max(1, window.devicePixelRatio || 1);\n\n\t\tconst pixelW = Math.max(1, Math.round(cssW * dpr));\n\t\tconst pixelH = Math.max(1, Math.round(cssH * dpr));\n\t\tif (canvas.width !== pixelW || canvas.height !== pixelH) {\n\t\t\tcanvas.width = pixelW;\n\t\t\tcanvas.height = pixelH;\n\t\t}\n\n\t\tctx.setTransform(1, 0, 0, 1, 0, 0);\n\t\tctx.clearRect(0, 0, canvas.width, canvas.height);\n\t\tctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n\n\t\tctx.fillStyle = backgroundColor;\n\t\tctx.fillRect(0, 0, cssW, cssH);\n\n\t\tconst preview = thumbnailRef.current;\n\t\tif (preview) {\n\t\t\tctx.drawImage(preview, 0, 0, cssW, cssH);\n\t\t}\n\n\t\tctx.strokeStyle = borderColor;\n\t\tctx.lineWidth = borderWidth;\n\t\tctx.strokeRect(\n\t\t\tborderWidth * 0.5,\n\t\t\tborderWidth * 0.5,\n\t\t\tcssW - borderWidth,\n\t\t\tcssH - borderWidth,\n\t\t);\n\n\t\tconst projector = projectorRef.current;\n\t\tconst bounds = projector?.getViewBounds?.();\n\t\tconst corners = projector?.getViewCorners?.();\n\t\tconst safeBounds = isFiniteBounds(bounds)\n\t\t\t? bounds\n\t\t\t: isFiniteBounds(lastBoundsRef.current)\n\t\t\t\t? lastBoundsRef.current\n\t\t\t\t: null;\n\t\tif (!safeBounds) return;\n\t\tlastBoundsRef.current = safeBounds;\n\n\t\tconst sx = cssW / Math.max(1, source.width);\n\t\tconst sy = cssH / Math.max(1, source.height);\n\n\t\tconst safeCorners =\n\t\t\tArray.isArray(corners) &&\n\t\t\tcorners.length >= 4 &&\n\t\t\tcorners.every(\n\t\t\t\t(point) =>\n\t\t\t\t\tArray.isArray(point) &&\n\t\t\t\t\tpoint.length >= 2 &&\n\t\t\t\t\tNumber.isFinite(point[0]) &&\n\t\t\t\t\tNumber.isFinite(point[1]),\n\t\t\t)\n\t\t\t\t? (corners as Array<[number, number]>)\n\t\t\t\t: null;\n\n\t\tif (safeCorners) {\n\t\t\tctx.beginPath();\n\t\t\tfor (let i = 0; i < safeCorners.length; i += 1) {\n\t\t\t\tconst point = safeCorners[i];\n\t\t\t\tconst x = clamp(point[0] * sx, 0, cssW);\n\t\t\t\tconst y = clamp(point[1] * sy, 0, cssH);\n\t\t\t\tif (i === 0) ctx.moveTo(x, y);\n\t\t\t\telse ctx.lineTo(x, y);\n\t\t\t}\n\t\t\tctx.closePath();\n\t\t\tctx.fillStyle = viewportFillColor;\n\t\t\tctx.fill();\n\t\t\tctx.strokeStyle = viewportStrokeColor;\n\t\t\tctx.lineWidth = 1.5;\n\t\t\tctx.stroke();\n\t\t\treturn;\n\t\t}\n\n\t\tconst left = clamp(safeBounds[0] * sx, 0, cssW);\n\t\tconst top = clamp(safeBounds[1] * sy, 0, cssH);\n\t\tconst right = clamp(safeBounds[2] * sx, 0, cssW);\n\t\tconst bottom = clamp(safeBounds[3] * sy, 0, cssH);\n\t\tconst rectW = Math.max(1, right - left);\n\t\tconst rectH = Math.max(1, bottom - top);\n\n\t\tctx.fillStyle = viewportFillColor;\n\t\tctx.fillRect(left, top, rectW, rectH);\n\n\t\tctx.strokeStyle = viewportStrokeColor;\n\t\tctx.lineWidth = 1.5;\n\t\tctx.strokeRect(\n\t\t\tleft + 0.5,\n\t\t\ttop + 0.5,\n\t\t\tMath.max(1, rectW - 1),\n\t\t\tMath.max(1, rectH - 1),\n\t\t);\n\t}, [\n\t\twidth,\n\t\theight,\n\t\tbackgroundColor,\n\t\tborderColor,\n\t\tborderWidth,\n\t\tprojectorRef,\n\t\tsource.width,\n\t\tsource.height,\n\t\tviewportFillColor,\n\t\tviewportStrokeColor,\n\t]);\n\n\tconst requestDraw = useCallback(() => {\n\t\tif (drawPendingRef.current) return;\n\t\tdrawPendingRef.current = true;\n\t\trafRef.current = requestAnimationFrame(() => {\n\t\t\tdrawPendingRef.current = false;\n\t\t\trafRef.current = null;\n\t\t\tdraw();\n\t\t});\n\t}, [draw]);\n\n\tconst toWorldFromClient = useCallback(\n\t\t(clientX: number, clientY: number): [number, number] | null => {\n\t\t\tconst canvas = canvasRef.current;\n\t\t\tif (!canvas) return null;\n\n\t\t\tconst rect = canvas.getBoundingClientRect();\n\t\t\tif (!rect.width || !rect.height) return null;\n\n\t\t\tconst nx = clamp((clientX - rect.left) / rect.width, 0, 1);\n\t\t\tconst ny = clamp((clientY - rect.top) / rect.height, 0, 1);\n\t\t\treturn [nx * source.width, ny * source.height];\n\t\t},\n\t\t[source.width, source.height],\n\t);\n\n\tconst recenterTo = useCallback(\n\t\t(worldX: number, worldY: number) => {\n\t\t\tconst projector = projectorRef.current;\n\t\t\tif (!projector) return;\n\n\t\t\tif (projector.setViewCenter) {\n\t\t\t\tprojector.setViewCenter(worldX, worldY);\n\t\t\t\trequestDraw();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst bounds = projector.getViewBounds?.();\n\t\t\tconst safeBounds = isFiniteBounds(bounds)\n\t\t\t\t? bounds\n\t\t\t\t: isFiniteBounds(lastBoundsRef.current)\n\t\t\t\t\t? lastBoundsRef.current\n\t\t\t\t\t: null;\n\t\t\tif (!safeBounds) return;\n\n\t\t\tconst visibleW = Math.max(1e-6, safeBounds[2] - safeBounds[0]);\n\t\t\tconst visibleH = Math.max(1e-6, safeBounds[3] - safeBounds[1]);\n\n\t\t\tprojector.setViewState({\n\t\t\t\toffsetX: worldX - visibleW * 0.5,\n\t\t\t\toffsetY: worldY - visibleH * 0.5,\n\t\t\t});\n\t\t\trequestDraw();\n\t\t},\n\t\t[projectorRef, requestDraw],\n\t);\n\n\tconst handlePointerDown = useCallback(\n\t\t(event: ReactPointerEvent<HTMLCanvasElement>) => {\n\t\t\tif (!interactive) return;\n\t\t\tif (event.button !== 0) return;\n\n\t\t\tconst canvas = canvasRef.current;\n\t\t\tif (!canvas) return;\n\n\t\t\tconst world = toWorldFromClient(event.clientX, event.clientY);\n\t\t\tif (!world) return;\n\n\t\t\tevent.preventDefault();\n\t\t\tevent.stopPropagation();\n\n\t\t\tcanvas.setPointerCapture(event.pointerId);\n\t\t\tdraggingRef.current = { active: true, pointerId: event.pointerId };\n\t\t\trecenterTo(world[0], world[1]);\n\t\t},\n\t\t[interactive, toWorldFromClient, recenterTo],\n\t);\n\n\tconst handlePointerMove = useCallback(\n\t\t(event: ReactPointerEvent<HTMLCanvasElement>) => {\n\t\t\tconst drag = draggingRef.current;\n\t\t\tif (!drag.active || drag.pointerId !== event.pointerId) return;\n\n\t\t\tconst world = toWorldFromClient(event.clientX, event.clientY);\n\t\t\tif (!world) return;\n\n\t\t\tevent.preventDefault();\n\t\t\tevent.stopPropagation();\n\t\t\trecenterTo(world[0], world[1]);\n\t\t},\n\t\t[toWorldFromClient, recenterTo],\n\t);\n\n\tconst handlePointerUp = useCallback(\n\t\t(event: ReactPointerEvent<HTMLCanvasElement>) => {\n\t\t\tconst drag = draggingRef.current;\n\t\t\tif (!drag.active || drag.pointerId !== event.pointerId) return;\n\n\t\t\tconst canvas = canvasRef.current;\n\t\t\tif (canvas && canvas.hasPointerCapture(event.pointerId)) {\n\t\t\t\ttry {\n\t\t\t\t\tcanvas.releasePointerCapture(event.pointerId);\n\t\t\t\t} catch {\n\t\t\t\t\t// noop\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdraggingRef.current = { active: false, pointerId: null };\n\t\t\trequestDraw();\n\t\t},\n\t\t[requestDraw],\n\t);\n\n\tuseEffect(() => {\n\t\tlet cancelled = false;\n\t\tthumbnailRef.current = null;\n\t\trequestDraw();\n\n\t\tconst tier = 0;\n\t\tconst levelScale = 2 ** (source.maxTierZoom - tier);\n\t\tconst levelWidth = Math.ceil(source.width / levelScale);\n\t\tconst levelHeight = Math.ceil(source.height / levelScale);\n\t\tconst tilesX = Math.max(1, Math.ceil(levelWidth / source.tileSize));\n\t\tconst tilesY = Math.max(1, Math.ceil(levelHeight / source.tileSize));\n\t\tconst tileCount = tilesX * tilesY;\n\n\t\tif (!showThumbnail || tileCount > maxThumbnailTiles) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst preview = document.createElement(\"canvas\");\n\t\tpreview.width = Math.max(1, Math.round(width));\n\t\tpreview.height = Math.max(1, Math.round(height));\n\t\tconst ctx = preview.getContext(\"2d\");\n\t\tif (!ctx) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tctx.fillStyle = backgroundColor;\n\t\tctx.fillRect(0, 0, preview.width, preview.height);\n\n\t\tconst requests: Array<{\n\t\t\turl: string;\n\t\t\tbounds: Bounds;\n\t\t}> = [];\n\n\t\tfor (let y = 0; y < tilesY; y += 1) {\n\t\t\tfor (let x = 0; x < tilesX; x += 1) {\n\t\t\t\tconst left = x * source.tileSize * levelScale;\n\t\t\t\tconst top = y * source.tileSize * levelScale;\n\t\t\t\tconst right =\n\t\t\t\t\tMath.min((x + 1) * source.tileSize, levelWidth) * levelScale;\n\t\t\t\tconst bottom =\n\t\t\t\t\tMath.min((y + 1) * source.tileSize, levelHeight) * levelScale;\n\t\t\t\trequests.push({\n\t\t\t\t\turl: toTileUrl(source, tier, x, y),\n\t\t\t\t\tbounds: [left, top, right, bottom],\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tvoid Promise.allSettled(\n\t\t\trequests.map(async (tile) => {\n\t\t\t\tconst useAuthHeader = !!authToken;\n\t\t\t\tconst response = await fetch(tile.url, {\n\t\t\t\t\theaders: useAuthHeader ? { Authorization: authToken } : undefined,\n\t\t\t\t});\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new Error(`HTTP ${response.status}`);\n\t\t\t\t}\n\t\t\t\tconst bitmap = await createImageBitmap(await response.blob());\n\t\t\t\treturn { tile, bitmap };\n\t\t\t}),\n\t\t).then((results) => {\n\t\t\tif (cancelled) {\n\t\t\t\tfor (const result of results) {\n\t\t\t\t\tif (result.status === \"fulfilled\") {\n\t\t\t\t\t\tresult.value.bitmap.close();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst sx = preview.width / Math.max(1, source.width);\n\t\t\tconst sy = preview.height / Math.max(1, source.height);\n\t\t\tfor (const result of results) {\n\t\t\t\tif (result.status !== \"fulfilled\") continue;\n\t\t\t\tconst {\n\t\t\t\t\ttile: { bounds },\n\t\t\t\t\tbitmap,\n\t\t\t\t} = result.value;\n\t\t\t\tconst dx = bounds[0] * sx;\n\t\t\t\tconst dy = bounds[1] * sy;\n\t\t\t\tconst dw = Math.max(1, (bounds[2] - bounds[0]) * sx);\n\t\t\t\tconst dh = Math.max(1, (bounds[3] - bounds[1]) * sy);\n\t\t\t\tctx.drawImage(bitmap, dx, dy, dw, dh);\n\t\t\t\tbitmap.close();\n\t\t\t}\n\n\t\t\tthumbnailRef.current = preview;\n\t\t\trequestDraw();\n\t\t});\n\n\t\treturn () => {\n\t\t\tcancelled = true;\n\t\t};\n\t}, [\n\t\tsource,\n\t\tauthToken,\n\t\twidth,\n\t\theight,\n\t\tbackgroundColor,\n\t\tshowThumbnail,\n\t\tmaxThumbnailTiles,\n\t\trequestDraw,\n\t]);\n\n\tuseEffect(() => {\n\t\trequestDraw();\n\t}, [requestDraw]);\n\n\tuseEffect(() => {\n\t\tif (!invalidateRef) return undefined;\n\t\tinvalidateRef.current = requestDraw;\n\t\treturn () => {\n\t\t\tif (invalidateRef.current === requestDraw) {\n\t\t\t\tinvalidateRef.current = null;\n\t\t\t}\n\t\t};\n\t}, [invalidateRef, requestDraw]);\n\n\tuseEffect(\n\t\t() => () => {\n\t\t\tdraggingRef.current = { active: false, pointerId: null };\n\t\t\tif (rafRef.current !== null) {\n\t\t\t\tcancelAnimationFrame(rafRef.current);\n\t\t\t\trafRef.current = null;\n\t\t\t}\n\t\t\tdrawPendingRef.current = false;\n\t\t},\n\t\t[],\n\t);\n\n\treturn (\n\t\t<canvas\n\t\t\tref={canvasRef}\n\t\t\tclassName={className}\n\t\t\tstyle={mergedStyle}\n\t\t\tonPointerDown={handlePointerDown}\n\t\t\tonPointerMove={handlePointerMove}\n\t\t\tonPointerUp={handlePointerUp}\n\t\t\tonPointerCancel={handlePointerUp}\n\t\t\tonContextMenu={(event) => {\n\t\t\t\tevent.preventDefault();\n\t\t\t}}\n\t\t\tonWheel={(event) => {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tevent.stopPropagation();\n\t\t\t}}\n\t\t/>\n\t);\n}\n","import { type CSSProperties, useEffect, useMemo, useRef } from \"react\";\nimport { M1TileRenderer } from \"../core/m1-tile-renderer\";\nimport type { ViewState } from \"../core/ortho-camera\";\nimport type { TileDefinition } from \"../core/types\";\n\nexport interface TileViewerCanvasProps {\n\timageWidth: number;\n\timageHeight: number;\n\ttiles: TileDefinition[];\n\tviewState?: Partial<ViewState>;\n\tclassName?: string;\n\tstyle?: CSSProperties;\n}\n\nexport function TileViewerCanvas({\n\timageWidth,\n\timageHeight,\n\ttiles,\n\tviewState,\n\tclassName,\n\tstyle,\n}: TileViewerCanvasProps): React.ReactElement {\n\tconst canvasRef = useRef<HTMLCanvasElement | null>(null);\n\tconst rendererRef = useRef<M1TileRenderer | null>(null);\n\tconst mergedStyle = useMemo(\n\t\t() => ({ width: \"100%\", height: \"100%\", display: \"block\", ...style }),\n\t\t[style],\n\t);\n\n\tuseEffect(() => {\n\t\tconst canvas = canvasRef.current;\n\t\tif (!canvas) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst renderer = new M1TileRenderer({\n\t\t\tcanvas,\n\t\t\timageWidth,\n\t\t\timageHeight,\n\t\t\tinitialViewState: viewState,\n\t\t});\n\n\t\trendererRef.current = renderer;\n\t\tvoid renderer.setTiles(tiles);\n\n\t\treturn () => {\n\t\t\trenderer.destroy();\n\t\t\trendererRef.current = null;\n\t\t};\n\t}, [imageWidth, imageHeight]);\n\n\tuseEffect(() => {\n\t\tconst renderer = rendererRef.current;\n\t\tif (!renderer) {\n\t\t\treturn;\n\t\t}\n\n\t\tvoid renderer.setTiles(tiles);\n\t}, [tiles]);\n\n\tuseEffect(() => {\n\t\tconst renderer = rendererRef.current;\n\t\tif (!renderer || !viewState) {\n\t\t\treturn;\n\t\t}\n\n\t\trenderer.setViewState(viewState);\n\t}, [viewState]);\n\n\treturn <canvas ref={canvasRef} className={className} style={mergedStyle} />;\n}\n","import type { WsiPointData } from \"./types\";\n\nexport type RoiCoordinate = [number, number];\nexport type RoiPolygon = RoiCoordinate[];\n\ninterface PreparedPolygon {\n\tring: RoiPolygon;\n\tminX: number;\n\tminY: number;\n\tmaxX: number;\n\tmaxY: number;\n}\n\nfunction sanitizePointCount(pointData: WsiPointData): number {\n\treturn Math.max(\n\t\t0,\n\t\tMath.min(\n\t\t\tMath.floor(pointData.count ?? 0),\n\t\t\tMath.floor((pointData.positions?.length ?? 0) / 2),\n\t\t\tpointData.paletteIndices?.length ?? 0,\n\t\t),\n\t);\n}\n\nfunction closeRing(coords: RoiPolygon): RoiPolygon {\n\tif (!Array.isArray(coords) || coords.length < 3) return [];\n\tconst out = coords.map(([x, y]) => [x, y] as RoiCoordinate);\n\tconst first = out[0];\n\tconst last = out[out.length - 1];\n\tif (!first || !last) return [];\n\tif (first[0] !== last[0] || first[1] !== last[1]) {\n\t\tout.push([first[0], first[1]]);\n\t}\n\treturn out;\n}\n\nfunction preparePolygons(polygons: RoiPolygon[]): PreparedPolygon[] {\n\tconst prepared: PreparedPolygon[] = [];\n\tfor (const poly of polygons ?? []) {\n\t\tconst ring = closeRing(poly);\n\t\tif (ring.length < 4) continue;\n\t\tlet minX = Infinity;\n\t\tlet minY = Infinity;\n\t\tlet maxX = -Infinity;\n\t\tlet maxY = -Infinity;\n\t\tfor (const [x, y] of ring) {\n\t\t\tif (x < minX) minX = x;\n\t\t\tif (x > maxX) maxX = x;\n\t\t\tif (y < minY) minY = y;\n\t\t\tif (y > maxY) maxY = y;\n\t\t}\n\t\tif (!Number.isFinite(minX) || !Number.isFinite(minY)) continue;\n\t\tprepared.push({ ring, minX, minY, maxX, maxY });\n\t}\n\treturn prepared;\n}\n\nfunction isInsideRing(x: number, y: number, ring: RoiPolygon): boolean {\n\tlet inside = false;\n\tfor (let i = 0, j = ring.length - 1; i < ring.length; j = i, i += 1) {\n\t\tconst xi = ring[i][0];\n\t\tconst yi = ring[i][1];\n\t\tconst xj = ring[j][0];\n\t\tconst yj = ring[j][1];\n\t\tconst intersect =\n\t\t\tyi > y !== yj > y &&\n\t\t\tx < ((xj - xi) * (y - yi)) / ((yj - yi) || Number.EPSILON) + xi;\n\t\tif (intersect) inside = !inside;\n\t}\n\treturn inside;\n}\n\nfunction isInsideAnyPolygon(\n\tx: number,\n\ty: number,\n\tpolygons: PreparedPolygon[],\n): boolean {\n\tfor (const poly of polygons) {\n\t\tif (x < poly.minX || x > poly.maxX || y < poly.minY || y > poly.maxY) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (isInsideRing(x, y, poly.ring)) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\nexport function filterPointDataByPolygons(\n\tpointData: WsiPointData | null | undefined,\n\tpolygons: RoiPolygon[] | null | undefined,\n): WsiPointData | null {\n\tif (!pointData || !pointData.count || !pointData.positions || !pointData.paletteIndices) {\n\t\treturn null;\n\t}\n\n\tconst prepared = preparePolygons(polygons ?? []);\n\tif (prepared.length === 0) {\n\t\treturn {\n\t\t\tcount: 0,\n\t\t\tpositions: new Float32Array(0),\n\t\t\tpaletteIndices: new Uint16Array(0),\n\t\t};\n\t}\n\n\tconst count = sanitizePointCount(pointData);\n\tconst positions = pointData.positions;\n\tconst terms = pointData.paletteIndices;\n\n\tconst nextPositions = new Float32Array(count * 2);\n\tconst nextTerms = new Uint16Array(count);\n\tlet cursor = 0;\n\n\tfor (let i = 0; i < count; i += 1) {\n\t\tconst x = positions[i * 2];\n\t\tconst y = positions[i * 2 + 1];\n\t\tif (!isInsideAnyPolygon(x, y, prepared)) continue;\n\t\tnextPositions[cursor * 2] = x;\n\t\tnextPositions[cursor * 2 + 1] = y;\n\t\tnextTerms[cursor] = terms[i];\n\t\tcursor += 1;\n\t}\n\n\treturn {\n\t\tcount: cursor,\n\t\tpositions: nextPositions.subarray(0, cursor * 2),\n\t\tpaletteIndices: nextTerms.subarray(0, cursor),\n\t};\n}\n\nexport function filterPointIndicesByPolygons(\n\tpointData: WsiPointData | null | undefined,\n\tpolygons: RoiPolygon[] | null | undefined,\n): Uint32Array {\n\tif (!pointData || !pointData.count || !pointData.positions || !pointData.paletteIndices) {\n\t\treturn new Uint32Array(0);\n\t}\n\n\tconst prepared = preparePolygons(polygons ?? []);\n\tif (prepared.length === 0) {\n\t\treturn new Uint32Array(0);\n\t}\n\n\tconst count = sanitizePointCount(pointData);\n\tif (count === 0) {\n\t\treturn new Uint32Array(0);\n\t}\n\n\tconst positions = pointData.positions;\n\tconst out = new Uint32Array(count);\n\tlet cursor = 0;\n\n\tfor (let i = 0; i < count; i += 1) {\n\t\tconst x = positions[i * 2];\n\t\tconst y = positions[i * 2 + 1];\n\t\tif (!isInsideAnyPolygon(x, y, prepared)) continue;\n\t\tout[cursor] = i;\n\t\tcursor += 1;\n\t}\n\n\treturn out.subarray(0, cursor);\n}\n","export interface WebGpuCapabilities {\n\tsupported: boolean;\n\tadapterName?: string;\n\tfeatures: string[];\n\tlimits?: {\n\t\tmaxStorageBufferBindingSize: number;\n\t\tmaxComputeInvocationsPerWorkgroup: number;\n\t\tmaxComputeWorkgroupSizeX: number;\n\t};\n}\n\ninterface NavigatorGpuLike {\n\trequestAdapter: () => Promise<GpuAdapterLike | null>;\n}\n\ninterface GpuAdapterLike {\n\tinfo?: {\n\t\tdescription?: string;\n\t\tvendor?: string;\n\t};\n\tfeatures: Iterable<string>;\n\tlimits: {\n\t\tmaxStorageBufferBindingSize: number;\n\t\tmaxComputeInvocationsPerWorkgroup: number;\n\t\tmaxComputeWorkgroupSizeX: number;\n\t};\n\trequestDevice: () => Promise<GpuDeviceLike>;\n}\n\ninterface GpuBufferLike {\n\tdestroy: () => void;\n\tmapAsync: (mode: number) => Promise<void>;\n\tgetMappedRange: () => ArrayBuffer;\n\tunmap: () => void;\n}\n\ninterface GpuComputePassLike {\n\tsetPipeline: (pipeline: GpuComputePipelineLike) => void;\n\tsetBindGroup: (index: number, bindGroup: unknown) => void;\n\tdispatchWorkgroups: (x: number, y?: number, z?: number) => void;\n\tend: () => void;\n}\n\ninterface GpuCommandEncoderLike {\n\tbeginComputePass: () => GpuComputePassLike;\n\tcopyBufferToBuffer: (\n\t\tsource: GpuBufferLike,\n\t\tsourceOffset: number,\n\t\tdestination: GpuBufferLike,\n\t\tdestinationOffset: number,\n\t\tsize: number,\n\t) => void;\n\tfinish: () => unknown;\n}\n\ninterface GpuQueueLike {\n\twriteBuffer: (\n\t\tbuffer: GpuBufferLike,\n\t\tbufferOffset: number,\n\t\tdata: ArrayBufferView | ArrayBufferLike,\n\t\tdataOffset?: number,\n\t\tsize?: number,\n\t) => void;\n\tsubmit: (commands: unknown[]) => void;\n}\n\ninterface GpuComputePipelineLike {\n\treadonly _brand?: \"GpuComputePipelineLike\";\n}\n\ninterface GpuBindGroupLayoutLike {\n\treadonly _brand?: \"GpuBindGroupLayoutLike\";\n}\n\ninterface GpuDeviceLike {\n\tlimits: {\n\t\tmaxStorageBufferBindingSize: number;\n\t};\n\tqueue: GpuQueueLike;\n\tcreateBindGroupLayout: (descriptor: unknown) => GpuBindGroupLayoutLike;\n\tcreatePipelineLayout: (descriptor: unknown) => unknown;\n\tcreateShaderModule: (descriptor: { code: string }) => unknown;\n\tcreateComputePipeline: (descriptor: unknown) => GpuComputePipelineLike;\n\tcreateBuffer: (descriptor: { size: number; usage: number }) => GpuBufferLike;\n\tcreateBindGroup: (descriptor: unknown) => unknown;\n\tcreateCommandEncoder: () => GpuCommandEncoderLike;\n}\n\ninterface WebGpuContext {\n\tdevice: GpuDeviceLike;\n\tpipeline: GpuComputePipelineLike;\n\tbindGroupLayout: GpuBindGroupLayoutLike;\n}\n\nlet contextPromise: Promise<WebGpuContext | null> | null = null;\n\nconst BBOX_PREFILTER_SHADER = `\nstruct Params {\n pointCount: u32,\n boundsCount: u32,\n _pad0: u32,\n _pad1: u32,\n};\n\n@group(0) @binding(0) var<storage, read> positions: array<vec2<f32>>;\n@group(0) @binding(1) var<storage, read> bounds: array<vec4<f32>>;\n@group(0) @binding(2) var<storage, read_write> outputMask: array<u32>;\n@group(0) @binding(3) var<uniform> params: Params;\n\n@compute @workgroup_size(256)\nfn main(@builtin(global_invocation_id) gid: vec3<u32>) {\n let i = gid.x;\n if (i >= params.pointCount) {\n return;\n }\n\n let p = positions[i];\n var inside: u32 = 0u;\n for (var bi: u32 = 0u; bi < params.boundsCount; bi = bi + 1u) {\n let b = bounds[bi];\n if (p.x >= b.x && p.x <= b.z && p.y >= b.y && p.y <= b.w) {\n inside = 1u;\n break;\n }\n }\n outputMask[i] = inside;\n}\n`;\n\nfunction hasWebGpu(): boolean {\n\tif (typeof navigator === \"undefined\") return false;\n\tconst nav = navigator as Navigator & { gpu?: unknown };\n\treturn typeof nav.gpu === \"object\" && nav.gpu !== null;\n}\n\nfunction getNavigatorGpu(): NavigatorGpuLike | null {\n\tif (!hasWebGpu()) return null;\n\tconst nav = navigator as Navigator & { gpu?: unknown };\n\tconst gpu = nav.gpu;\n\tif (!gpu || typeof gpu !== \"object\") return null;\n\tconst candidate = gpu as Partial<NavigatorGpuLike>;\n\tif (typeof candidate.requestAdapter !== \"function\") return null;\n\treturn candidate as NavigatorGpuLike;\n}\n\nconst GPU_SHADER_STAGE_COMPUTE =\n\t(globalThis as { GPUShaderStage?: { COMPUTE?: number } }).GPUShaderStage\n\t\t?.COMPUTE ?? 0x4;\nconst GPU_BUFFER_USAGE_STORAGE =\n\t(globalThis as { GPUBufferUsage?: { STORAGE?: number } }).GPUBufferUsage\n\t\t?.STORAGE ?? 0x80;\nconst GPU_BUFFER_USAGE_COPY_DST =\n\t(globalThis as { GPUBufferUsage?: { COPY_DST?: number } }).GPUBufferUsage\n\t\t?.COPY_DST ?? 0x08;\nconst GPU_BUFFER_USAGE_COPY_SRC =\n\t(globalThis as { GPUBufferUsage?: { COPY_SRC?: number } }).GPUBufferUsage\n\t\t?.COPY_SRC ?? 0x04;\nconst GPU_BUFFER_USAGE_UNIFORM =\n\t(globalThis as { GPUBufferUsage?: { UNIFORM?: number } }).GPUBufferUsage\n\t\t?.UNIFORM ?? 0x40;\nconst GPU_BUFFER_USAGE_MAP_READ =\n\t(globalThis as { GPUBufferUsage?: { MAP_READ?: number } }).GPUBufferUsage\n\t\t?.MAP_READ ?? 0x01;\nconst GPU_MAP_MODE_READ =\n\t(globalThis as { GPUMapMode?: { READ?: number } }).GPUMapMode?.READ ?? 0x01;\n\nexport async function getWebGpuCapabilities(): Promise<WebGpuCapabilities> {\n\tconst navGpu = getNavigatorGpu();\n\tif (!navGpu) {\n\t\treturn { supported: false, features: [] };\n\t}\n\tconst adapter = await navGpu.requestAdapter();\n\tif (!adapter) {\n\t\treturn { supported: false, features: [] };\n\t}\n\n\treturn {\n\t\tsupported: true,\n\t\tadapterName: adapter.info?.description ?? adapter.info?.vendor ?? \"unknown\",\n\t\tfeatures: Array.from(adapter.features),\n\t\tlimits: {\n\t\t\tmaxStorageBufferBindingSize: Number(\n\t\t\t\tadapter.limits.maxStorageBufferBindingSize,\n\t\t\t),\n\t\t\tmaxComputeInvocationsPerWorkgroup: Number(\n\t\t\t\tadapter.limits.maxComputeInvocationsPerWorkgroup,\n\t\t\t),\n\t\t\tmaxComputeWorkgroupSizeX: Number(adapter.limits.maxComputeWorkgroupSizeX),\n\t\t},\n\t};\n}\n\nasync function getContext(): Promise<WebGpuContext | null> {\n\tif (contextPromise) return contextPromise;\n\tcontextPromise = (async () => {\n\t\tconst navGpu = getNavigatorGpu();\n\t\tif (!navGpu) return null;\n\t\tconst adapter = await navGpu.requestAdapter();\n\t\tif (!adapter) return null;\n\t\tconst device = await adapter.requestDevice();\n\n\t\tconst bindGroupLayout = device.createBindGroupLayout({\n\t\t\tentries: [\n\t\t\t\t{\n\t\t\t\t\tbinding: 0,\n\t\t\t\t\tvisibility: GPU_SHADER_STAGE_COMPUTE,\n\t\t\t\t\tbuffer: { type: \"read-only-storage\" },\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tbinding: 1,\n\t\t\t\t\tvisibility: GPU_SHADER_STAGE_COMPUTE,\n\t\t\t\t\tbuffer: { type: \"read-only-storage\" },\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tbinding: 2,\n\t\t\t\t\tvisibility: GPU_SHADER_STAGE_COMPUTE,\n\t\t\t\t\tbuffer: { type: \"storage\" },\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tbinding: 3,\n\t\t\t\t\tvisibility: GPU_SHADER_STAGE_COMPUTE,\n\t\t\t\t\tbuffer: { type: \"uniform\" },\n\t\t\t\t},\n\t\t\t],\n\t\t});\n\n\t\tconst pipeline = device.createComputePipeline({\n\t\t\tlayout: device.createPipelineLayout({ bindGroupLayouts: [bindGroupLayout] }),\n\t\t\tcompute: {\n\t\t\t\tmodule: device.createShaderModule({ code: BBOX_PREFILTER_SHADER }),\n\t\t\t\tentryPoint: \"main\",\n\t\t\t},\n\t\t});\n\n\t\treturn { device, pipeline, bindGroupLayout };\n\t})();\n\n\treturn contextPromise;\n}\n\nfunction align(value: number, step: number): number {\n\treturn Math.ceil(value / step) * step;\n}\n\nexport async function prefilterPointsByBoundsWebGpu(\n\tpositions: Float32Array,\n\tpointCount: number,\n\tbounds: Float32Array,\n): Promise<Uint32Array | null> {\n\tconst ctx = await getContext();\n\tif (!ctx) return null;\n\n\tconst count = Math.max(0, Math.floor(pointCount));\n\tconst boundsCount = Math.max(0, Math.floor(bounds.length / 4));\n\tif (count === 0 || boundsCount === 0) {\n\t\treturn new Uint32Array(0);\n\t}\n\n\tconst safePointCount = Math.min(count, Math.floor(positions.length / 2));\n\tif (safePointCount === 0) {\n\t\treturn new Uint32Array(0);\n\t}\n\n\tconst positionBytes = safePointCount * 2 * Float32Array.BYTES_PER_ELEMENT;\n\tconst boundsBytes = boundsCount * 4 * Float32Array.BYTES_PER_ELEMENT;\n\tconst outputBytes = safePointCount * Uint32Array.BYTES_PER_ELEMENT;\n\n\tconst limit = Number(ctx.device.limits.maxStorageBufferBindingSize);\n\tif (positionBytes > limit || boundsBytes > limit || outputBytes > limit) {\n\t\treturn null;\n\t}\n\n\tconst positionsBuffer = ctx.device.createBuffer({\n\t\tsize: align(positionBytes, 4),\n\t\tusage: GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST,\n\t});\n\tconst boundsBuffer = ctx.device.createBuffer({\n\t\tsize: align(boundsBytes, 4),\n\t\tusage: GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST,\n\t});\n\tconst outputBuffer = ctx.device.createBuffer({\n\t\tsize: align(outputBytes, 4),\n\t\tusage: GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_SRC,\n\t});\n\tconst uniformBuffer = ctx.device.createBuffer({\n\t\tsize: 16,\n\t\tusage: GPU_BUFFER_USAGE_UNIFORM | GPU_BUFFER_USAGE_COPY_DST,\n\t});\n\tconst readBuffer = ctx.device.createBuffer({\n\t\tsize: align(outputBytes, 4),\n\t\tusage: GPU_BUFFER_USAGE_COPY_DST | GPU_BUFFER_USAGE_MAP_READ,\n\t});\n\n\tctx.device.queue.writeBuffer(\n\t\tpositionsBuffer,\n\t\t0,\n\t\tpositions.buffer,\n\t\tpositions.byteOffset,\n\t\tpositionBytes,\n\t);\n\tctx.device.queue.writeBuffer(\n\t\tboundsBuffer,\n\t\t0,\n\t\tbounds.buffer,\n\t\tbounds.byteOffset,\n\t\tboundsBytes,\n\t);\n\tctx.device.queue.writeBuffer(\n\t\tuniformBuffer,\n\t\t0,\n\t\tnew Uint32Array([safePointCount, boundsCount, 0, 0]),\n\t);\n\n\tconst bindGroup = ctx.device.createBindGroup({\n\t\tlayout: ctx.bindGroupLayout,\n\t\tentries: [\n\t\t\t{ binding: 0, resource: { buffer: positionsBuffer } },\n\t\t\t{ binding: 1, resource: { buffer: boundsBuffer } },\n\t\t\t{ binding: 2, resource: { buffer: outputBuffer } },\n\t\t\t{ binding: 3, resource: { buffer: uniformBuffer } },\n\t\t],\n\t});\n\n\tconst commandEncoder = ctx.device.createCommandEncoder();\n\tconst pass = commandEncoder.beginComputePass();\n\tpass.setPipeline(ctx.pipeline);\n\tpass.setBindGroup(0, bindGroup);\n\tpass.dispatchWorkgroups(Math.ceil(safePointCount / 256));\n\tpass.end();\n\n\tcommandEncoder.copyBufferToBuffer(outputBuffer, 0, readBuffer, 0, outputBytes);\n\tctx.device.queue.submit([commandEncoder.finish()]);\n\n\tawait readBuffer.mapAsync(GPU_MAP_MODE_READ);\n\tconst mapped = readBuffer.getMappedRange();\n\tconst out = new Uint32Array(mapped.slice(0));\n\treadBuffer.unmap();\n\n\tpositionsBuffer.destroy();\n\tboundsBuffer.destroy();\n\toutputBuffer.destroy();\n\tuniformBuffer.destroy();\n\treadBuffer.destroy();\n\n\treturn out;\n}\n","import { filterPointDataByPolygons, type RoiPolygon } from \"./point-clip\";\nimport type { WsiPointData } from \"./types\";\nimport { prefilterPointsByBoundsWebGpu } from \"./webgpu\";\n\ninterface PreparedPolygon {\n ring: RoiPolygon;\n minX: number;\n minY: number;\n maxX: number;\n maxY: number;\n}\n\nexport interface HybridPointClipOptions {\n bridgeToDraw?: boolean;\n}\n\nexport interface HybridPointClipResult {\n data: WsiPointData | null;\n meta: {\n mode: \"hybrid-webgpu\";\n durationMs: number;\n usedWebGpu: boolean;\n candidateCount: number;\n bridgedToDraw?: boolean;\n };\n}\n\nfunction nowMs(): number {\n if (typeof performance !== \"undefined\" && typeof performance.now === \"function\") {\n return performance.now();\n }\n return Date.now();\n}\n\nfunction closeRing(coords: RoiPolygon): RoiPolygon {\n if (!Array.isArray(coords) || coords.length < 3) return [];\n const out = coords.map(([x, y]) => [x, y] as [number, number]);\n const first = out[0];\n const last = out[out.length - 1];\n if (!first || !last) return [];\n if (first[0] !== last[0] || first[1] !== last[1]) {\n out.push([first[0], first[1]]);\n }\n return out;\n}\n\nfunction preparePolygons(polygons: RoiPolygon[]): PreparedPolygon[] {\n const prepared: PreparedPolygon[] = [];\n for (const poly of polygons ?? []) {\n const ring = closeRing(poly);\n if (ring.length < 4) continue;\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const [x, y] of ring) {\n if (x < minX) minX = x;\n if (x > maxX) maxX = x;\n if (y < minY) minY = y;\n if (y > maxY) maxY = y;\n }\n if (!Number.isFinite(minX) || !Number.isFinite(minY)) continue;\n prepared.push({ ring, minX, minY, maxX, maxY });\n }\n return prepared;\n}\n\nfunction isInsideRing(x: number, y: number, ring: RoiPolygon): boolean {\n let inside = false;\n for (let i = 0, j = ring.length - 1; i < ring.length; j = i, i += 1) {\n const xi = ring[i][0];\n const yi = ring[i][1];\n const xj = ring[j][0];\n const yj = ring[j][1];\n const intersect = yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi || Number.EPSILON) + xi;\n if (intersect) inside = !inside;\n }\n return inside;\n}\n\nfunction isInsideAnyPolygon(x: number, y: number, polygons: PreparedPolygon[]): boolean {\n for (const poly of polygons) {\n if (x < poly.minX || x > poly.maxX || y < poly.minY || y > poly.maxY) {\n continue;\n }\n if (isInsideRing(x, y, poly.ring)) {\n return true;\n }\n }\n return false;\n}\n\nexport async function filterPointDataByPolygonsHybrid(\n pointData: WsiPointData | null | undefined,\n polygons: RoiPolygon[] | null | undefined,\n options: HybridPointClipOptions = {}\n): Promise<HybridPointClipResult> {\n const start = nowMs();\n const bridgeToDraw = options.bridgeToDraw === true;\n if (!pointData || !pointData.count || !pointData.positions || !pointData.paletteIndices) {\n return {\n data: null,\n meta: {\n mode: \"hybrid-webgpu\",\n durationMs: nowMs() - start,\n usedWebGpu: false,\n candidateCount: 0,\n bridgedToDraw: false,\n },\n };\n }\n\n const prepared = preparePolygons(polygons ?? []);\n if (prepared.length === 0) {\n return {\n data: {\n count: 0,\n positions: new Float32Array(0),\n paletteIndices: new Uint16Array(0),\n },\n meta: {\n mode: \"hybrid-webgpu\",\n durationMs: nowMs() - start,\n usedWebGpu: false,\n candidateCount: 0,\n bridgedToDraw: false,\n },\n };\n }\n\n const safeCount = Math.max(0, Math.min(pointData.count, Math.floor(pointData.positions.length / 2), pointData.paletteIndices.length));\n if (safeCount === 0) {\n return {\n data: {\n count: 0,\n positions: new Float32Array(0),\n paletteIndices: new Uint16Array(0),\n },\n meta: {\n mode: \"hybrid-webgpu\",\n durationMs: nowMs() - start,\n usedWebGpu: false,\n candidateCount: 0,\n bridgedToDraw: false,\n },\n };\n }\n\n const bboxFlat = new Float32Array(prepared.length * 4);\n for (let i = 0; i < prepared.length; i += 1) {\n const base = i * 4;\n const poly = prepared[i];\n bboxFlat[base] = poly.minX;\n bboxFlat[base + 1] = poly.minY;\n bboxFlat[base + 2] = poly.maxX;\n bboxFlat[base + 3] = poly.maxY;\n }\n\n let candidateMask: Uint32Array | null = null;\n let usedWebGpu = false;\n try {\n candidateMask = await prefilterPointsByBoundsWebGpu(pointData.positions, safeCount, bboxFlat);\n usedWebGpu = !!candidateMask;\n } catch {\n candidateMask = null;\n usedWebGpu = false;\n }\n\n if (!candidateMask) {\n const fallback = filterPointDataByPolygons(pointData, polygons);\n return {\n data: fallback,\n meta: {\n mode: \"hybrid-webgpu\",\n durationMs: nowMs() - start,\n usedWebGpu: false,\n candidateCount: safeCount,\n bridgedToDraw: false,\n },\n };\n }\n\n let candidateCount = 0;\n for (let i = 0; i < safeCount; i += 1) {\n if (candidateMask[i] === 1) candidateCount += 1;\n }\n\n const candidateIndices = new Uint32Array(candidateCount);\n if (candidateCount > 0) {\n let candidateCursor = 0;\n for (let i = 0; i < safeCount; i += 1) {\n if (candidateMask[i] !== 1) continue;\n candidateIndices[candidateCursor] = i;\n candidateCursor += 1;\n }\n }\n\n if (candidateCount === 0) {\n if (bridgeToDraw) {\n return {\n data: {\n count: safeCount,\n positions: pointData.positions.subarray(0, safeCount * 2),\n paletteIndices: pointData.paletteIndices.subarray(0, safeCount),\n drawIndices: new Uint32Array(0),\n },\n meta: {\n mode: \"hybrid-webgpu\",\n durationMs: nowMs() - start,\n usedWebGpu: true,\n candidateCount: 0,\n bridgedToDraw: true,\n },\n };\n }\n\n return {\n data: {\n count: 0,\n positions: new Float32Array(0),\n paletteIndices: new Uint16Array(0),\n },\n meta: {\n mode: \"hybrid-webgpu\",\n durationMs: nowMs() - start,\n usedWebGpu: true,\n candidateCount: 0,\n bridgedToDraw: false,\n },\n };\n }\n\n if (bridgeToDraw) {\n const drawIndices = new Uint32Array(candidateCount);\n let visibleCount = 0;\n\n for (let i = 0; i < candidateCount; i += 1) {\n const pointIndex = candidateIndices[i] ?? 0;\n const x = pointData.positions[pointIndex * 2];\n const y = pointData.positions[pointIndex * 2 + 1];\n if (!isInsideAnyPolygon(x, y, prepared)) continue;\n drawIndices[visibleCount] = pointIndex;\n visibleCount += 1;\n }\n\n return {\n data: {\n count: safeCount,\n positions: pointData.positions.subarray(0, safeCount * 2),\n paletteIndices: pointData.paletteIndices.subarray(0, safeCount),\n drawIndices: drawIndices.subarray(0, visibleCount),\n },\n meta: {\n mode: \"hybrid-webgpu\",\n durationMs: nowMs() - start,\n usedWebGpu: true,\n candidateCount,\n bridgedToDraw: true,\n },\n };\n }\n\n const nextPositions = new Float32Array(candidateCount * 2);\n const nextTerms = new Uint16Array(candidateCount);\n let cursor = 0;\n\n for (let i = 0; i < candidateCount; i += 1) {\n const pointIndex = candidateIndices[i] ?? 0;\n const x = pointData.positions[pointIndex * 2];\n const y = pointData.positions[pointIndex * 2 + 1];\n if (!isInsideAnyPolygon(x, y, prepared)) continue;\n nextPositions[cursor * 2] = x;\n nextPositions[cursor * 2 + 1] = y;\n nextTerms[cursor] = pointData.paletteIndices[pointIndex];\n cursor += 1;\n }\n\n return {\n data: {\n count: cursor,\n positions: nextPositions.subarray(0, cursor * 2),\n paletteIndices: nextTerms.subarray(0, cursor),\n },\n meta: {\n mode: \"hybrid-webgpu\",\n durationMs: nowMs() - start,\n usedWebGpu: true,\n candidateCount,\n bridgedToDraw: false,\n },\n };\n}\n","import { filterPointDataByPolygons, filterPointIndicesByPolygons, type RoiPolygon } from \"./point-clip\";\nimport type { RoiClipWorkerRequest, RoiClipWorkerResponse } from \"./point-clip-worker-protocol\";\nimport type { WsiPointData } from \"./types\";\n\nexport type PointClipMode = \"sync\" | \"worker\" | \"hybrid-webgpu\";\n\nexport interface PointClipResultMeta {\n mode: PointClipMode;\n durationMs: number;\n}\n\nexport interface PointClipResult {\n data: WsiPointData | null;\n meta: PointClipResultMeta;\n}\n\nexport interface PointClipIndexResult {\n indices: Uint32Array;\n meta: PointClipResultMeta;\n}\n\ninterface PendingDataWorkerRequest {\n kind: \"data\";\n resolve: (result: PointClipResult) => void;\n reject: (reason?: unknown) => void;\n startMs: number;\n}\n\ninterface PendingIndexWorkerRequest {\n kind: \"index\";\n resolve: (result: PointClipIndexResult) => void;\n reject: (reason?: unknown) => void;\n startMs: number;\n}\n\ntype PendingWorkerRequest = PendingDataWorkerRequest | PendingIndexWorkerRequest;\n\nlet workerInstance: Worker | null = null;\nlet workerSupported = true;\nlet requestId = 1;\nconst pendingById = new Map<number, PendingWorkerRequest>();\n\nfunction nowMs(): number {\n if (typeof performance !== \"undefined\" && typeof performance.now === \"function\") {\n return performance.now();\n }\n return Date.now();\n}\n\nfunction createWorker(): Worker | null {\n if (!workerSupported) return null;\n if (workerInstance) return workerInstance;\n try {\n const worker = new Worker(new URL(\"../workers/roi-clip-worker.ts\", import.meta.url), { type: \"module\" });\n worker.addEventListener(\"message\", handleWorkerMessage);\n worker.addEventListener(\"error\", handleWorkerError);\n workerInstance = worker;\n return worker;\n } catch {\n workerSupported = false;\n return null;\n }\n}\n\nfunction handleWorkerMessage(event: MessageEvent<RoiClipWorkerResponse>): void {\n const msg = event.data;\n if (!msg) return;\n const pending = pendingById.get(msg.id);\n if (!pending) return;\n pendingById.delete(msg.id);\n\n if (msg.type === \"roi-clip-failure\") {\n pending.reject(new Error(msg.error || \"worker clip failed\"));\n return;\n }\n\n if (msg.type === \"roi-clip-index-success\") {\n if (pending.kind !== \"index\") {\n pending.reject(new Error(\"worker response mismatch: expected point data result\"));\n return;\n }\n const count = Math.max(0, Math.floor(msg.count));\n const indices = new Uint32Array(msg.indices).subarray(0, count);\n pending.resolve({\n indices,\n meta: {\n mode: \"worker\",\n durationMs: Number.isFinite(msg.durationMs) ? msg.durationMs : nowMs() - pending.startMs,\n },\n });\n return;\n }\n\n if (pending.kind !== \"data\") {\n pending.reject(new Error(\"worker response mismatch: expected index result\"));\n return;\n }\n\n const count = Math.max(0, Math.floor(msg.count));\n const positions = new Float32Array(msg.positions);\n const paletteIndices = new Uint16Array(msg.paletteIndices);\n const output: WsiPointData = {\n count,\n positions: positions.subarray(0, count * 2),\n paletteIndices: paletteIndices.subarray(0, count),\n };\n\n pending.resolve({\n data: output,\n meta: {\n mode: \"worker\",\n durationMs: Number.isFinite(msg.durationMs) ? msg.durationMs : nowMs() - pending.startMs,\n },\n });\n}\n\nfunction handleWorkerError(): void {\n workerSupported = false;\n if (workerInstance) {\n workerInstance.removeEventListener(\"message\", handleWorkerMessage);\n workerInstance.removeEventListener(\"error\", handleWorkerError);\n workerInstance.terminate();\n workerInstance = null;\n }\n for (const [, pending] of pendingById) {\n pending.reject(new Error(\"worker crashed\"));\n }\n pendingById.clear();\n}\n\nexport function terminateRoiClipWorker(): void {\n if (!workerInstance) return;\n workerInstance.removeEventListener(\"message\", handleWorkerMessage);\n workerInstance.removeEventListener(\"error\", handleWorkerError);\n workerInstance.terminate();\n workerInstance = null;\n for (const [, pending] of pendingById) {\n pending.reject(new Error(\"worker terminated\"));\n }\n pendingById.clear();\n}\n\nexport async function filterPointDataByPolygonsInWorker(pointData: WsiPointData | null | undefined, polygons: RoiPolygon[] | null | undefined): Promise<PointClipResult> {\n if (!pointData || !pointData.count || !pointData.positions || !pointData.paletteIndices) {\n return {\n data: null,\n meta: { mode: \"worker\", durationMs: 0 },\n };\n }\n\n const worker = createWorker();\n if (!worker) {\n const start = nowMs();\n return {\n data: filterPointDataByPolygons(pointData, polygons),\n meta: { mode: \"sync\", durationMs: nowMs() - start },\n };\n }\n\n const safeCount = Math.max(0, Math.min(pointData.count, Math.floor(pointData.positions.length / 2), pointData.paletteIndices.length));\n const positionsCopy = pointData.positions.slice(0, safeCount * 2);\n const termsCopy = pointData.paletteIndices.slice(0, safeCount);\n const id = requestId++;\n const startMs = nowMs();\n\n return new Promise<PointClipResult>((resolve, reject) => {\n pendingById.set(id, { kind: \"data\", resolve, reject, startMs });\n const msg: RoiClipWorkerRequest = {\n type: \"roi-clip-request\",\n id,\n count: safeCount,\n positions: positionsCopy.buffer,\n paletteIndices: termsCopy.buffer,\n polygons: polygons ?? [],\n };\n worker.postMessage(msg, [positionsCopy.buffer, termsCopy.buffer]);\n });\n}\n\nexport async function filterPointIndicesByPolygonsInWorker(pointData: WsiPointData | null | undefined, polygons: RoiPolygon[] | null | undefined): Promise<PointClipIndexResult> {\n if (!pointData || !pointData.count || !pointData.positions || !pointData.paletteIndices) {\n return {\n indices: new Uint32Array(0),\n meta: { mode: \"worker\", durationMs: 0 },\n };\n }\n\n const worker = createWorker();\n if (!worker) {\n const start = nowMs();\n return {\n indices: filterPointIndicesByPolygons(pointData, polygons),\n meta: { mode: \"sync\", durationMs: nowMs() - start },\n };\n }\n\n const safeCount = Math.max(0, Math.min(pointData.count, Math.floor(pointData.positions.length / 2), pointData.paletteIndices.length));\n const positionsCopy = pointData.positions.slice(0, safeCount * 2);\n const id = requestId++;\n const startMs = nowMs();\n\n return new Promise<PointClipIndexResult>((resolve, reject) => {\n pendingById.set(id, { kind: \"index\", resolve, reject, startMs });\n const msg: RoiClipWorkerRequest = {\n type: \"roi-clip-index-request\",\n id,\n count: safeCount,\n positions: positionsCopy.buffer,\n polygons: polygons ?? [],\n };\n worker.postMessage(msg, [positionsCopy.buffer]);\n });\n}\n","import type { WsiPointData, WsiRegion } from \"./types\";\n\nexport interface RoiTermCount {\n\ttermId: string;\n\tpaletteIndex: number;\n\tcount: number;\n}\n\nexport interface RoiPointGroup {\n\tregionId: string | number;\n\tregionIndex: number;\n\ttotalCount: number;\n\ttermCounts: RoiTermCount[];\n}\n\nexport interface RoiPointGroupOptions {\n\tpaletteIndexToTermId?: ReadonlyMap<number, string> | readonly string[];\n\tincludeEmptyRegions?: boolean;\n}\n\nexport interface RoiPointGroupStats {\n\tgroups: RoiPointGroup[];\n\tinputPointCount: number;\n\tpointsInsideAnyRegion: number;\n\tunmatchedPointCount: number;\n}\n\ninterface PreparedRegion {\n\tregionId: string | number;\n\tregionIndex: number;\n\tring: Array<[number, number]>;\n\tminX: number;\n\tminY: number;\n\tmaxX: number;\n\tmaxY: number;\n\tarea: number;\n}\n\nfunction closeRing(\n\tcoordinates: readonly [number, number][],\n): Array<[number, number]> {\n\tif (!Array.isArray(coordinates) || coordinates.length < 3) return [];\n\tconst out = coordinates.map(\n\t\t(point): [number, number] => [Number(point[0]), Number(point[1])],\n\t);\n\tconst first = out[0];\n\tconst last = out[out.length - 1];\n\tif (!first || !last) return [];\n\tif (first[0] !== last[0] || first[1] !== last[1]) {\n\t\tout.push([first[0], first[1]]);\n\t}\n\treturn out;\n}\n\nfunction polygonArea(ring: Array<[number, number]>): number {\n\tlet sum = 0;\n\tfor (let i = 0; i < ring.length - 1; i += 1) {\n\t\tconst [ax, ay] = ring[i];\n\t\tconst [bx, by] = ring[i + 1];\n\t\tsum += ax * by - bx * ay;\n\t}\n\treturn Math.abs(sum * 0.5);\n}\n\nfunction prepareRegions(regions: readonly WsiRegion[]): PreparedRegion[] {\n\tconst prepared: PreparedRegion[] = [];\n\tfor (let i = 0; i < regions.length; i += 1) {\n\t\tconst region = regions[i];\n\t\tif (!region?.coordinates?.length) continue;\n\n\t\tconst ring = closeRing(region.coordinates);\n\t\tif (ring.length < 4) continue;\n\n\t\tlet minX = Infinity;\n\t\tlet minY = Infinity;\n\t\tlet maxX = -Infinity;\n\t\tlet maxY = -Infinity;\n\t\tfor (const [x, y] of ring) {\n\t\t\tif (x < minX) minX = x;\n\t\t\tif (x > maxX) maxX = x;\n\t\t\tif (y < minY) minY = y;\n\t\t\tif (y > maxY) maxY = y;\n\t\t}\n\t\tif (\n\t\t\t!Number.isFinite(minX) ||\n\t\t\t!Number.isFinite(minY) ||\n\t\t\t!Number.isFinite(maxX) ||\n\t\t\t!Number.isFinite(maxY)\n\t\t) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tprepared.push({\n\t\t\tregionId: region.id ?? i,\n\t\t\tregionIndex: i,\n\t\t\tring,\n\t\t\tminX,\n\t\t\tminY,\n\t\t\tmaxX,\n\t\t\tmaxY,\n\t\t\tarea: Math.max(1e-6, polygonArea(ring)),\n\t\t});\n\t}\n\treturn prepared;\n}\n\nfunction isInsideRing(x: number, y: number, ring: Array<[number, number]>): boolean {\n\tlet inside = false;\n\tfor (let i = 0, j = ring.length - 1; i < ring.length; j = i, i += 1) {\n\t\tconst xi = ring[i][0];\n\t\tconst yi = ring[i][1];\n\t\tconst xj = ring[j][0];\n\t\tconst yj = ring[j][1];\n\t\tconst intersect =\n\t\t\tyi > y !== yj > y &&\n\t\t\tx < ((xj - xi) * (y - yi)) / ((yj - yi) || Number.EPSILON) + xi;\n\t\tif (intersect) inside = !inside;\n\t}\n\treturn inside;\n}\n\nfunction resolveTermId(\n\tpaletteIndex: number,\n\tpaletteIndexToTermId: RoiPointGroupOptions[\"paletteIndexToTermId\"],\n): string {\n\tif (Array.isArray(paletteIndexToTermId)) {\n\t\tconst fromArray = paletteIndexToTermId[paletteIndex];\n\t\tif (typeof fromArray === \"string\" && fromArray.length > 0) return fromArray;\n\t}\n\tif (paletteIndexToTermId instanceof Map) {\n\t\tconst fromMap = paletteIndexToTermId.get(paletteIndex);\n\t\tif (typeof fromMap === \"string\" && fromMap.length > 0) return fromMap;\n\t}\n\treturn String(paletteIndex);\n}\n\nexport function computeRoiPointGroups(\n\tpointData: WsiPointData | null | undefined,\n\tregions: readonly WsiRegion[] | null | undefined,\n\toptions: RoiPointGroupOptions = {},\n): RoiPointGroupStats {\n\tconst baseCount = Math.max(\n\t\t0,\n\t\tMath.min(\n\t\t\tMath.floor(pointData?.count ?? 0),\n\t\t\tMath.floor((pointData?.positions?.length ?? 0) / 2),\n\t\t\tpointData?.paletteIndices?.length ?? 0,\n\t\t),\n\t);\n\n\tlet drawIndices: Uint32Array | null = null;\n\tif (pointData?.drawIndices instanceof Uint32Array) {\n\t\tconst source = pointData.drawIndices;\n\t\tlet valid = source.length;\n\t\tfor (let i = 0; i < source.length; i += 1) {\n\t\t\tconst idx = source[i];\n\t\t\tif (idx < baseCount) continue;\n\t\t\tvalid -= 1;\n\t\t}\n\t\tif (valid === source.length) {\n\t\t\tdrawIndices = source;\n\t\t} else if (valid > 0) {\n\t\t\tconst filtered = new Uint32Array(valid);\n\t\t\tlet cursor = 0;\n\t\t\tfor (let i = 0; i < source.length; i += 1) {\n\t\t\t\tconst idx = source[i];\n\t\t\t\tif (idx >= baseCount) continue;\n\t\t\t\tfiltered[cursor] = idx;\n\t\t\t\tcursor += 1;\n\t\t\t}\n\t\t\tdrawIndices = filtered;\n\t\t} else {\n\t\t\tdrawIndices = new Uint32Array(0);\n\t\t}\n\t}\n\n\tconst inputCount = drawIndices ? drawIndices.length : baseCount;\n\n\tconst preparedRegions = prepareRegions(regions ?? []);\n\tif (!pointData || inputCount === 0 || preparedRegions.length === 0) {\n\t\treturn {\n\t\t\tgroups: [],\n\t\t\tinputPointCount: inputCount,\n\t\t\tpointsInsideAnyRegion: 0,\n\t\t\tunmatchedPointCount: inputCount,\n\t\t};\n\t}\n\n\tconst regionTermCounters = new Map<number, Map<number, number>>();\n\tconst regionTotalCounters = new Map<number, number>();\n\tlet insideCount = 0;\n\n\tfor (let i = 0; i < inputCount; i += 1) {\n\t\tconst pointIndex = drawIndices ? drawIndices[i] : i;\n\t\tconst x = pointData.positions[pointIndex * 2];\n\t\tconst y = pointData.positions[pointIndex * 2 + 1];\n\t\tlet bestRegion: PreparedRegion | null = null;\n\n\t\tfor (const region of preparedRegions) {\n\t\t\tif (x < region.minX || x > region.maxX || y < region.minY || y > region.maxY) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (!isInsideRing(x, y, region.ring)) continue;\n\t\t\tif (!bestRegion || region.area < bestRegion.area) {\n\t\t\t\tbestRegion = region;\n\t\t\t}\n\t\t}\n\n\t\tif (!bestRegion) continue;\n\t\tinsideCount += 1;\n\n\t\tconst paletteIndex = pointData.paletteIndices[pointIndex] ?? 0;\n\t\tconst regionTermMap =\n\t\t\tregionTermCounters.get(bestRegion.regionIndex) ?? new Map<number, number>();\n\t\tregionTermMap.set(paletteIndex, (regionTermMap.get(paletteIndex) ?? 0) + 1);\n\t\tregionTermCounters.set(bestRegion.regionIndex, regionTermMap);\n\t\tregionTotalCounters.set(\n\t\t\tbestRegion.regionIndex,\n\t\t\t(regionTotalCounters.get(bestRegion.regionIndex) ?? 0) + 1,\n\t\t);\n\t}\n\n\tconst includeEmptyRegions = options.includeEmptyRegions ?? false;\n\tconst groups: RoiPointGroup[] = [];\n\tfor (const region of preparedRegions) {\n\t\tconst totalCount = regionTotalCounters.get(region.regionIndex) ?? 0;\n\t\tif (!includeEmptyRegions && totalCount <= 0) continue;\n\t\tconst termMap = regionTermCounters.get(region.regionIndex) ?? new Map();\n\t\tconst termCounts: RoiTermCount[] = Array.from(termMap.entries())\n\t\t\t.map(([paletteIndex, count]) => ({\n\t\t\t\ttermId: resolveTermId(paletteIndex, options.paletteIndexToTermId),\n\t\t\t\tpaletteIndex,\n\t\t\t\tcount,\n\t\t\t}))\n\t\t\t.sort((a, b) => b.count - a.count || a.paletteIndex - b.paletteIndex);\n\n\t\tgroups.push({\n\t\t\tregionId: region.regionId,\n\t\t\tregionIndex: region.regionIndex,\n\t\t\ttotalCount,\n\t\t\ttermCounts,\n\t\t});\n\t}\n\n\treturn {\n\t\tgroups,\n\t\tinputPointCount: inputCount,\n\t\tpointsInsideAnyRegion: insideCount,\n\t\tunmatchedPointCount: Math.max(0, inputCount - insideCount),\n\t};\n}\n","export type TileBounds = [number, number, number, number];\n\nexport interface ScheduledTile {\n\tkey: string;\n\ttier: number;\n\tx: number;\n\ty: number;\n\tbounds: TileBounds;\n\tdistance2: number;\n\turl: string;\n}\n\nexport interface TileSchedulerSnapshot {\n\tinflight: number;\n\tqueued: number;\n\taborted: number;\n\tretries: number;\n\tfailed: number;\n}\n\nexport interface TileSchedulerOptions {\n\tmaxConcurrency?: number;\n\tmaxRetries?: number;\n\tretryBaseDelayMs?: number;\n\tretryMaxDelayMs?: number;\n\tauthToken?: string;\n\tonTileLoad: (tile: ScheduledTile, bitmap: ImageBitmap) => void;\n\tonTileError?: (\n\t\ttile: ScheduledTile,\n\t\terror: unknown,\n\t\tattemptCount: number,\n\t) => void;\n\tonStateChange?: (snapshot: TileSchedulerSnapshot) => void;\n}\n\ninterface QueueItem {\n\ttile: ScheduledTile;\n\tattempt: number;\n\treadyAt: number;\n}\n\ninterface InflightItem {\n\ttile: ScheduledTile;\n\tattempt: number;\n\tcontroller: AbortController;\n}\n\nfunction nowMs(): number {\n\tif (typeof performance !== \"undefined\" && typeof performance.now === \"function\") {\n\t\treturn performance.now();\n\t}\n\treturn Date.now();\n}\n\nfunction shouldAttachAuthHeader(url: string, authToken: string): boolean {\n\tif (!authToken) return false;\n\ttry {\n\t\tconst parsed = new URL(url, typeof window !== \"undefined\" ? window.location.href : undefined);\n\t\tconst host = parsed.hostname.toLowerCase();\n\t\tconst isAwsS3 =\n\t\t\thost.includes(\"amazonaws.com\") || host.startsWith(\"s3.\") || host.includes(\".s3.\");\n\t\tif (isAwsS3) return false;\n\t} catch {\n\t\t// Fallback to attaching auth if URL parsing fails.\n\t}\n\treturn true;\n}\n\nexport class TileScheduler {\n\tprivate readonly maxConcurrency: number;\n\tprivate readonly maxRetries: number;\n\tprivate readonly retryBaseDelayMs: number;\n\tprivate readonly retryMaxDelayMs: number;\n\tprivate readonly onTileLoad: (tile: ScheduledTile, bitmap: ImageBitmap) => void;\n\tprivate readonly onTileError?:\n\t\t| ((tile: ScheduledTile, error: unknown, attemptCount: number) => void)\n\t\t| undefined;\n\tprivate readonly onStateChange?:\n\t\t| ((snapshot: TileSchedulerSnapshot) => void)\n\t\t| undefined;\n\n\tprivate authToken: string;\n\tprivate destroyed = false;\n\tprivate queue: QueueItem[] = [];\n\tprivate queuedByKey = new Map<string, QueueItem>();\n\tprivate inflight = new Map<string, InflightItem>();\n\tprivate visibleKeys = new Set<string>();\n\tprivate timerId: number | null = null;\n\tprivate abortedCount = 0;\n\tprivate retryCount = 0;\n\tprivate failedCount = 0;\n\n\tconstructor(options: TileSchedulerOptions) {\n\t\tthis.maxConcurrency = Math.max(1, Math.floor(options.maxConcurrency ?? 12));\n\t\tthis.maxRetries = Math.max(0, Math.floor(options.maxRetries ?? 2));\n\t\tthis.retryBaseDelayMs = Math.max(\n\t\t\t10,\n\t\t\tMath.floor(options.retryBaseDelayMs ?? 120),\n\t\t);\n\t\tthis.retryMaxDelayMs = Math.max(\n\t\t\tthis.retryBaseDelayMs,\n\t\t\tMath.floor(options.retryMaxDelayMs ?? 1200),\n\t\t);\n\t\tthis.authToken = options.authToken ?? \"\";\n\t\tthis.onTileLoad = options.onTileLoad;\n\t\tthis.onTileError = options.onTileError;\n\t\tthis.onStateChange = options.onStateChange;\n\t}\n\n\tsetAuthToken(token: string): void {\n\t\tthis.authToken = String(token ?? \"\");\n\t}\n\n\tschedule(tiles: readonly ScheduledTile[]): void {\n\t\tif (this.destroyed) return;\n\n\t\tconst nextVisibleKeys = new Set<string>();\n\t\tfor (const tile of tiles) {\n\t\t\tnextVisibleKeys.add(tile.key);\n\t\t}\n\t\tthis.visibleKeys = nextVisibleKeys;\n\n\t\tthis.dropInvisibleQueued(nextVisibleKeys);\n\t\tthis.abortInvisibleInflight(nextVisibleKeys);\n\n\t\tfor (const tile of tiles) {\n\t\t\tif (this.inflight.has(tile.key)) {\n\t\t\t\tconst inflight = this.inflight.get(tile.key);\n\t\t\t\tif (inflight) inflight.tile = tile;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst queued = this.queuedByKey.get(tile.key);\n\t\t\tif (queued) {\n\t\t\t\tqueued.tile = tile;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst item: QueueItem = {\n\t\t\t\ttile,\n\t\t\t\tattempt: 0,\n\t\t\t\treadyAt: nowMs(),\n\t\t\t};\n\t\t\tthis.queue.push(item);\n\t\t\tthis.queuedByKey.set(tile.key, item);\n\t\t}\n\n\t\tthis.sortQueue();\n\t\tthis.pump();\n\t\tthis.emitStateChange();\n\t}\n\n\tclear(): void {\n\t\tthis.clearPumpTimer();\n\t\tthis.visibleKeys.clear();\n\t\tthis.queue = [];\n\t\tthis.queuedByKey.clear();\n\n\t\tfor (const [, item] of this.inflight) {\n\t\t\titem.controller.abort();\n\t\t}\n\t\tthis.inflight.clear();\n\t\tthis.emitStateChange();\n\t}\n\n\tdestroy(): void {\n\t\tif (this.destroyed) return;\n\t\tthis.destroyed = true;\n\t\tthis.clear();\n\t}\n\n\tgetInflightCount(): number {\n\t\treturn this.inflight.size;\n\t}\n\n\tgetSnapshot(): TileSchedulerSnapshot {\n\t\treturn {\n\t\t\tinflight: this.inflight.size,\n\t\t\tqueued: this.queue.length,\n\t\t\taborted: this.abortedCount,\n\t\t\tretries: this.retryCount,\n\t\t\tfailed: this.failedCount,\n\t\t};\n\t}\n\n\tprivate dropInvisibleQueued(visibleKeys: Set<string>): void {\n\t\tif (this.queue.length === 0) return;\n\t\tconst nextQueue: QueueItem[] = [];\n\t\tfor (const item of this.queue) {\n\t\t\tif (!visibleKeys.has(item.tile.key)) {\n\t\t\t\tthis.queuedByKey.delete(item.tile.key);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tnextQueue.push(item);\n\t\t}\n\t\tthis.queue = nextQueue;\n\t}\n\n\tprivate abortInvisibleInflight(visibleKeys: Set<string>): void {\n\t\tfor (const [key, item] of this.inflight) {\n\t\t\tif (visibleKeys.has(key)) continue;\n\t\t\tthis.inflight.delete(key);\n\t\t\tthis.abortedCount += 1;\n\t\t\titem.controller.abort();\n\t\t}\n\t}\n\n\tprivate sortQueue(): void {\n\t\tthis.queue.sort((a, b) => {\n\t\t\tif (a.readyAt !== b.readyAt) return a.readyAt - b.readyAt;\n\t\t\tif (a.tile.distance2 !== b.tile.distance2) {\n\t\t\t\treturn a.tile.distance2 - b.tile.distance2;\n\t\t\t}\n\t\t\tif (a.tile.tier !== b.tile.tier) return b.tile.tier - a.tile.tier;\n\t\t\treturn a.tile.key.localeCompare(b.tile.key);\n\t\t});\n\t}\n\n\tprivate pump(): void {\n\t\tif (this.destroyed) return;\n\t\tthis.clearPumpTimer();\n\n\t\twhile (this.inflight.size < this.maxConcurrency) {\n\t\t\tconst next = this.takeNextReadyQueueItem();\n\t\t\tif (!next) break;\n\t\t\tthis.startFetch(next);\n\t\t}\n\n\t\tif (this.inflight.size >= this.maxConcurrency) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.queue.length === 0) return;\n\n\t\tconst earliestReadyAt = this.queue[0]?.readyAt;\n\t\tif (typeof earliestReadyAt !== \"number\") return;\n\t\tconst delay = Math.max(0, earliestReadyAt - nowMs());\n\t\tthis.timerId = window.setTimeout(() => {\n\t\t\tthis.timerId = null;\n\t\t\tthis.pump();\n\t\t}, delay);\n\t}\n\n\tprivate takeNextReadyQueueItem(): QueueItem | null {\n\t\tif (this.queue.length === 0) return null;\n\t\tconst now = nowMs();\n\t\tconst first = this.queue[0];\n\t\tif (!first || first.readyAt > now) return null;\n\n\t\tthis.queue.shift();\n\t\tthis.queuedByKey.delete(first.tile.key);\n\t\treturn first;\n\t}\n\n\tprivate startFetch(item: QueueItem): void {\n\t\tconst controller = new AbortController();\n\t\tconst inflightEntry: InflightItem = {\n\t\t\ttile: item.tile,\n\t\t\tattempt: item.attempt,\n\t\t\tcontroller,\n\t\t};\n\t\tthis.inflight.set(item.tile.key, inflightEntry);\n\t\tthis.emitStateChange();\n\n\t\tconst useAuthHeader = shouldAttachAuthHeader(item.tile.url, this.authToken);\n\t\tfetch(item.tile.url, {\n\t\t\tsignal: controller.signal,\n\t\t\theaders: useAuthHeader ? { Authorization: this.authToken } : undefined,\n\t\t})\n\t\t\t.then((response) => {\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new Error(`HTTP ${response.status}`);\n\t\t\t\t}\n\t\t\t\treturn response.blob();\n\t\t\t})\n\t\t\t.then((blob) => createImageBitmap(blob))\n\t\t\t.then((bitmap) => {\n\t\t\t\tif (this.destroyed || controller.signal.aborted) {\n\t\t\t\t\tbitmap.close();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (!this.visibleKeys.has(item.tile.key)) {\n\t\t\t\t\tbitmap.close();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis.onTileLoad(item.tile, bitmap);\n\t\t\t})\n\t\t\t.catch((error: unknown) => {\n\t\t\t\tif (controller.signal.aborted || this.destroyed) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst shouldRetry =\n\t\t\t\t\titem.attempt < this.maxRetries && this.visibleKeys.has(item.tile.key);\n\t\t\t\tif (shouldRetry) {\n\t\t\t\t\tthis.retryCount += 1;\n\t\t\t\t\tconst nextAttempt = item.attempt + 1;\n\t\t\t\t\tconst retryDelay = this.getRetryDelay(nextAttempt);\n\t\t\t\t\tconst queued: QueueItem = {\n\t\t\t\t\t\ttile: item.tile,\n\t\t\t\t\t\tattempt: nextAttempt,\n\t\t\t\t\t\treadyAt: nowMs() + retryDelay,\n\t\t\t\t\t};\n\t\t\t\t\tconst existing = this.queuedByKey.get(item.tile.key);\n\t\t\t\t\tif (existing) {\n\t\t\t\t\t\texisting.tile = queued.tile;\n\t\t\t\t\t\texisting.readyAt = Math.min(existing.readyAt, queued.readyAt);\n\t\t\t\t\t\texisting.attempt = Math.max(existing.attempt, queued.attempt);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.queue.push(queued);\n\t\t\t\t\t\tthis.queuedByKey.set(queued.tile.key, queued);\n\t\t\t\t\t}\n\t\t\t\t\tthis.sortQueue();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis.failedCount += 1;\n\t\t\t\tthis.onTileError?.(item.tile, error, item.attempt + 1);\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tthis.inflight.delete(item.tile.key);\n\t\t\t\tthis.pump();\n\t\t\t\tthis.emitStateChange();\n\t\t\t});\n\t}\n\n\tprivate getRetryDelay(attempt: number): number {\n\t\tconst exp = Math.max(0, attempt - 1);\n\t\tconst delay = Math.min(\n\t\t\tthis.retryMaxDelayMs,\n\t\t\tthis.retryBaseDelayMs * 2 ** exp,\n\t\t);\n\t\tconst jitter = 0.85 + Math.random() * 0.3;\n\t\treturn Math.round(delay * jitter);\n\t}\n\n\tprivate clearPumpTimer(): void {\n\t\tif (this.timerId === null) return;\n\t\twindow.clearTimeout(this.timerId);\n\t\tthis.timerId = null;\n\t}\n\n\tprivate emitStateChange(): void {\n\t\tthis.onStateChange?.(this.getSnapshot());\n\t}\n}\n","import { toTileUrl } from \"./image-info\";\nimport {\n\tTileScheduler,\n\ttype ScheduledTile,\n\ttype TileBounds,\n} from \"./tile-scheduler\";\nimport type {\n\tWsiImageSource,\n\tWsiPointData,\n\tWsiRenderStats,\n\tWsiViewState,\n} from \"./types\";\nimport { clamp, createProgram } from \"./utils\";\n\ntype Bounds = TileBounds;\n\ninterface CachedTile {\n\tkey: string;\n\ttexture: WebGLTexture;\n\tbounds: Bounds;\n\ttier: number;\n\tlastUsed: number;\n}\n\ninterface TileVertexProgram {\n\tprogram: WebGLProgram;\n\tvao: WebGLVertexArrayObject;\n\tvbo: WebGLBuffer;\n\tuCamera: WebGLUniformLocation;\n\tuBounds: WebGLUniformLocation;\n\tuTexture: WebGLUniformLocation;\n}\n\ninterface PointProgram {\n\tprogram: WebGLProgram;\n\tvao: WebGLVertexArrayObject;\n\tposBuffer: WebGLBuffer;\n\ttermBuffer: WebGLBuffer;\n\tindexBuffer: WebGLBuffer;\n\tpaletteTexture: WebGLTexture;\n\tuCamera: WebGLUniformLocation;\n\tuPointSize: WebGLUniformLocation;\n\tuPalette: WebGLUniformLocation;\n\tuPaletteSize: WebGLUniformLocation;\n}\n\ninterface OrthoViewport {\n\twidth: number;\n\theight: number;\n}\n\ntype WorldPoint = [number, number];\nconst DEFAULT_ROTATION_DRAG_SENSITIVITY = 0.35;\n\nexport interface WsiTileSchedulerConfig {\n\tmaxConcurrency?: number;\n\tmaxRetries?: number;\n\tretryBaseDelayMs?: number;\n\tretryMaxDelayMs?: number;\n}\n\nexport interface WsiTileRendererOptions {\n\tonViewStateChange?: (next: WsiViewState) => void;\n\tonStats?: (stats: WsiRenderStats) => void;\n\tauthToken?: string;\n\tmaxCacheTiles?: number;\n\tctrlDragRotate?: boolean;\n\trotationDragSensitivityDegPerPixel?: number;\n\ttileScheduler?: WsiTileSchedulerConfig;\n\tonTileError?: (event: WsiTileErrorEvent) => void;\n\tonContextLost?: () => void;\n\tonContextRestored?: () => void;\n}\n\nexport interface WsiTileErrorEvent {\n\ttile: ScheduledTile;\n\terror: unknown;\n\tattemptCount: number;\n}\n\nclass OrthoCamera {\n\tprivate viewportWidth = 1;\n\tprivate viewportHeight = 1;\n\tprivate viewState: WsiViewState = {\n\t\tzoom: 1,\n\t\toffsetX: 0,\n\t\toffsetY: 0,\n\t\trotationDeg: 0,\n\t};\n\n\tsetViewport(width: number, height: number): void {\n\t\tthis.viewportWidth = Math.max(1, width);\n\t\tthis.viewportHeight = Math.max(1, height);\n\t}\n\n\tgetViewport(): OrthoViewport {\n\t\treturn { width: this.viewportWidth, height: this.viewportHeight };\n\t}\n\n\tsetViewState(next: Partial<WsiViewState>): void {\n\t\tif (typeof next.zoom === \"number\") {\n\t\t\tthis.viewState.zoom = Math.max(0.0001, next.zoom);\n\t\t}\n\t\tif (typeof next.offsetX === \"number\") {\n\t\t\tthis.viewState.offsetX = next.offsetX;\n\t\t}\n\t\tif (typeof next.offsetY === \"number\") {\n\t\t\tthis.viewState.offsetY = next.offsetY;\n\t\t}\n\t\tif (typeof next.rotationDeg === \"number\" && Number.isFinite(next.rotationDeg)) {\n\t\t\tthis.viewState.rotationDeg = next.rotationDeg;\n\t\t}\n\t}\n\n\tgetViewState(): WsiViewState {\n\t\treturn { ...this.viewState };\n\t}\n\n\tgetCenter(): WorldPoint {\n\t\tconst zoom = Math.max(1e-6, this.viewState.zoom);\n\t\treturn [\n\t\t\tthis.viewState.offsetX + this.viewportWidth / (2 * zoom),\n\t\t\tthis.viewState.offsetY + this.viewportHeight / (2 * zoom),\n\t\t];\n\t}\n\n\tsetCenter(centerX: number, centerY: number): void {\n\t\tconst zoom = Math.max(1e-6, this.viewState.zoom);\n\t\tthis.viewState.offsetX = centerX - this.viewportWidth / (2 * zoom);\n\t\tthis.viewState.offsetY = centerY - this.viewportHeight / (2 * zoom);\n\t}\n\n\tscreenToWorld(screenX: number, screenY: number): WorldPoint {\n\t\tconst state = this.viewState;\n\t\tconst zoom = Math.max(1e-6, state.zoom);\n\t\tconst [centerX, centerY] = this.getCenter();\n\t\tconst dx = (screenX - this.viewportWidth * 0.5) / zoom;\n\t\tconst dy = (screenY - this.viewportHeight * 0.5) / zoom;\n\t\tconst rad = toRadians(state.rotationDeg);\n\t\tconst cos = Math.cos(rad);\n\t\tconst sin = Math.sin(rad);\n\t\treturn [centerX + dx * cos - dy * sin, centerY + dx * sin + dy * cos];\n\t}\n\n\tworldToScreen(worldX: number, worldY: number): WorldPoint {\n\t\tconst state = this.viewState;\n\t\tconst zoom = Math.max(1e-6, state.zoom);\n\t\tconst [centerX, centerY] = this.getCenter();\n\t\tconst dx = worldX - centerX;\n\t\tconst dy = worldY - centerY;\n\t\tconst rad = toRadians(state.rotationDeg);\n\t\tconst cos = Math.cos(rad);\n\t\tconst sin = Math.sin(rad);\n\t\tconst rx = dx * cos + dy * sin;\n\t\tconst ry = -dx * sin + dy * cos;\n\t\treturn [\n\t\t\tthis.viewportWidth * 0.5 + rx * zoom,\n\t\t\tthis.viewportHeight * 0.5 + ry * zoom,\n\t\t];\n\t}\n\n\tgetViewCorners(): [WorldPoint, WorldPoint, WorldPoint, WorldPoint] {\n\t\tconst w = this.viewportWidth;\n\t\tconst h = this.viewportHeight;\n\t\treturn [\n\t\t\tthis.screenToWorld(0, 0),\n\t\t\tthis.screenToWorld(w, 0),\n\t\t\tthis.screenToWorld(w, h),\n\t\t\tthis.screenToWorld(0, h),\n\t\t];\n\t}\n\n\tgetMatrix(): Float32Array {\n\t\tconst zoom = Math.max(1e-6, this.viewState.zoom);\n\t\tconst [centerX, centerY] = this.getCenter();\n\t\tconst rad = toRadians(this.viewState.rotationDeg);\n\t\tconst cos = Math.cos(rad);\n\t\tconst sin = Math.sin(rad);\n\n\t\tconst ax = (2 * zoom * cos) / this.viewportWidth;\n\t\tconst bx = (2 * zoom * sin) / this.viewportWidth;\n\t\tconst ay = (2 * zoom * sin) / this.viewportHeight;\n\t\tconst by = (-2 * zoom * cos) / this.viewportHeight;\n\t\tconst tx = -(ax * centerX + bx * centerY);\n\t\tconst ty = -(ay * centerX + by * centerY);\n\n\t\treturn new Float32Array([ax, ay, 0, bx, by, 0, tx, ty, 1]);\n\t}\n}\n\nfunction toRadians(deg: number): number {\n\treturn (deg * Math.PI) / 180;\n}\n\nfunction nowMs(): number {\n\tif (typeof performance !== \"undefined\" && typeof performance.now === \"function\") {\n\t\treturn performance.now();\n\t}\n\treturn Date.now();\n}\n\nfunction requireUniformLocation(\n\tgl: WebGL2RenderingContext,\n\tprogram: WebGLProgram,\n\tname: string,\n): WebGLUniformLocation {\n\tconst location = gl.getUniformLocation(program, name);\n\tif (!location) {\n\t\tthrow new Error(`uniform location lookup failed: ${name}`);\n\t}\n\treturn location;\n}\n\nfunction isSameArrayView(\n\ta: ArrayBufferView | null | undefined,\n\tb: ArrayBufferView | null | undefined,\n): boolean {\n\tif (!a || !b) return a === b;\n\treturn (\n\t\ta.buffer === b.buffer &&\n\t\ta.byteOffset === b.byteOffset &&\n\t\ta.byteLength === b.byteLength\n\t);\n}\n\nexport class WsiTileRenderer {\n\tprivate readonly canvas: HTMLCanvasElement;\n\tprivate readonly source: WsiImageSource;\n\tprivate readonly gl: WebGL2RenderingContext;\n\tprivate readonly camera = new OrthoCamera();\n\tprivate readonly onViewStateChange?: (next: WsiViewState) => void;\n\tprivate readonly onStats?: (stats: WsiRenderStats) => void;\n\tprivate readonly onTileError?: (event: WsiTileErrorEvent) => void;\n\tprivate readonly onContextLost?: () => void;\n\tprivate readonly onContextRestored?: () => void;\n\tprivate readonly resizeObserver: ResizeObserver;\n\tprivate tileProgram: TileVertexProgram;\n\tprivate pointProgram: PointProgram;\n\tprivate readonly tileScheduler: TileScheduler;\n\n\tprivate authToken: string;\n\tprivate destroyed = false;\n\tprivate contextLost = false;\n\tprivate frame: number | null = null;\n\tprivate frameSerial = 0;\n\tprivate dragging = false;\n\tprivate interactionMode: \"none\" | \"pan\" | \"rotate\" = \"none\";\n\tprivate rotateLastAngleRad: number | null = null;\n\tprivate pointerId: number | null = null;\n\tprivate lastPointerX = 0;\n\tprivate lastPointerY = 0;\n\tprivate interactionLocked = false;\n\tprivate ctrlDragRotate = true;\n\tprivate rotationDragSensitivityDegPerPixel = 0.35;\n\tprivate maxCacheTiles: number;\n\tprivate fitZoom = 1;\n\tprivate minZoom = 1e-6;\n\tprivate maxZoom = 1;\n\tprivate currentTier = 0;\n\tprivate pointCount = 0;\n\tprivate usePointIndices = false;\n\tprivate pointBuffersDirty = true;\n\tprivate pointPaletteSize = 1;\n\tprivate lastPointData: WsiPointData | null = null;\n\tprivate lastPointPalette: Uint8Array | null = null;\n\tprivate cache = new Map<string, CachedTile>();\n\n\tprivate readonly boundPointerDown: (event: PointerEvent) => void;\n\tprivate readonly boundPointerMove: (event: PointerEvent) => void;\n\tprivate readonly boundPointerUp: (event: PointerEvent) => void;\n\tprivate readonly boundWheel: (event: WheelEvent) => void;\n\tprivate readonly boundDoubleClick: (event: MouseEvent) => void;\n\tprivate readonly boundContextMenu: (event: MouseEvent) => void;\n\tprivate readonly boundContextLost: (event: Event) => void;\n\tprivate readonly boundContextRestored: (event: Event) => void;\n\n\tconstructor(\n\t\tcanvas: HTMLCanvasElement,\n\t\tsource: WsiImageSource,\n\t\toptions: WsiTileRendererOptions = {},\n\t) {\n\t\tthis.canvas = canvas;\n\t\tthis.source = source;\n\t\tthis.onViewStateChange = options.onViewStateChange;\n\t\tthis.onStats = options.onStats;\n\t\tthis.onTileError = options.onTileError;\n\t\tthis.onContextLost = options.onContextLost;\n\t\tthis.onContextRestored = options.onContextRestored;\n\t\tthis.authToken = options.authToken ?? \"\";\n\t\tthis.maxCacheTiles = Math.max(32, Math.floor(options.maxCacheTiles ?? 320));\n\t\tthis.ctrlDragRotate = options.ctrlDragRotate ?? true;\n\t\tthis.rotationDragSensitivityDegPerPixel =\n\t\t\ttypeof options.rotationDragSensitivityDegPerPixel === \"number\" &&\n\t\t\tNumber.isFinite(options.rotationDragSensitivityDegPerPixel)\n\t\t\t\t? Math.max(0, options.rotationDragSensitivityDegPerPixel)\n\t\t\t\t: DEFAULT_ROTATION_DRAG_SENSITIVITY;\n\n\t\tconst gl = canvas.getContext(\"webgl2\", {\n\t\t\talpha: false,\n\t\t\tantialias: false,\n\t\t\tdepth: false,\n\t\t\tstencil: false,\n\t\t\tpowerPreference: \"high-performance\",\n\t\t});\n\t\tif (!gl) {\n\t\t\tthrow new Error(\"WebGL2 not supported\");\n\t\t}\n\t\tthis.gl = gl;\n\n\t\tthis.tileProgram = this.initTileProgram();\n\t\tthis.pointProgram = this.initPointProgram();\n\t\tthis.tileScheduler = new TileScheduler({\n\t\t\tauthToken: this.authToken,\n\t\t\tmaxConcurrency: options.tileScheduler?.maxConcurrency ?? 12,\n\t\t\tmaxRetries: options.tileScheduler?.maxRetries ?? 2,\n\t\t\tretryBaseDelayMs: options.tileScheduler?.retryBaseDelayMs ?? 120,\n\t\t\tretryMaxDelayMs: options.tileScheduler?.retryMaxDelayMs ?? 1200,\n\t\t\tonTileLoad: (tile, bitmap) => this.handleTileLoaded(tile, bitmap),\n\t\t\tonTileError: (tile, error, attemptCount) => {\n\t\t\t\tthis.onTileError?.({ tile, error, attemptCount });\n\t\t\t\tconsole.warn(\"tile load failed\", tile.url, error);\n\t\t\t},\n\t\t});\n\n\t\tthis.resizeObserver = new ResizeObserver(() => this.resize());\n\t\tthis.resizeObserver.observe(canvas);\n\n\t\tthis.boundPointerDown = (event: PointerEvent) => this.onPointerDown(event);\n\t\tthis.boundPointerMove = (event: PointerEvent) => this.onPointerMove(event);\n\t\tthis.boundPointerUp = (event: PointerEvent) => this.onPointerUp(event);\n\t\tthis.boundWheel = (event: WheelEvent) => this.onWheel(event);\n\t\tthis.boundDoubleClick = (event: MouseEvent) => this.onDoubleClick(event);\n\t\tthis.boundContextMenu = (event: MouseEvent) => this.onContextMenu(event);\n\t\tthis.boundContextLost = (event: Event) => this.onWebGlContextLost(event);\n\t\tthis.boundContextRestored = (event: Event) =>\n\t\t\tthis.onWebGlContextRestored(event);\n\n\t\tcanvas.addEventListener(\"pointerdown\", this.boundPointerDown);\n\t\tcanvas.addEventListener(\"pointermove\", this.boundPointerMove);\n\t\tcanvas.addEventListener(\"pointerup\", this.boundPointerUp);\n\t\tcanvas.addEventListener(\"pointercancel\", this.boundPointerUp);\n\t\tcanvas.addEventListener(\"wheel\", this.boundWheel, { passive: false });\n\t\tcanvas.addEventListener(\"dblclick\", this.boundDoubleClick);\n\t\tcanvas.addEventListener(\"contextmenu\", this.boundContextMenu);\n\t\tcanvas.addEventListener(\"webglcontextlost\", this.boundContextLost);\n\t\tcanvas.addEventListener(\"webglcontextrestored\", this.boundContextRestored);\n\n\t\tthis.fitToImage();\n\t\tthis.resize();\n\t}\n\n\tsetAuthToken(token: string): void {\n\t\tthis.authToken = String(token ?? \"\");\n\t\tthis.tileScheduler.setAuthToken(this.authToken);\n\t}\n\n\tsetViewState(next: Partial<WsiViewState>): void {\n\t\tconst normalized: Partial<WsiViewState> = { ...next };\n\t\tif (typeof normalized.zoom === \"number\") {\n\t\t\tnormalized.zoom = clamp(normalized.zoom, this.minZoom, this.maxZoom);\n\t\t}\n\t\tthis.camera.setViewState(normalized);\n\t\tthis.clampViewState();\n\t\tthis.emitViewState();\n\t\tthis.requestRender();\n\t}\n\n\tgetViewState(): WsiViewState {\n\t\treturn this.camera.getViewState();\n\t}\n\n\tsetPointPalette(colors: Uint8Array | null | undefined): void {\n\t\tif (!colors || colors.length === 0) {\n\t\t\tthis.lastPointPalette = null;\n\t\t\treturn;\n\t\t}\n\t\tthis.lastPointPalette = new Uint8Array(colors);\n\t\tif (this.contextLost || this.gl.isContextLost()) return;\n\t\tconst gl = this.gl;\n\t\tconst paletteSize = Math.max(1, Math.floor(this.lastPointPalette.length / 4));\n\t\tthis.pointPaletteSize = paletteSize;\n\t\tgl.bindTexture(gl.TEXTURE_2D, this.pointProgram.paletteTexture);\n\t\tgl.texImage2D(\n\t\t\tgl.TEXTURE_2D,\n\t\t\t0,\n\t\t\tgl.RGBA,\n\t\t\tpaletteSize,\n\t\t\t1,\n\t\t\t0,\n\t\t\tgl.RGBA,\n\t\t\tgl.UNSIGNED_BYTE,\n\t\t\tthis.lastPointPalette,\n\t\t);\n\t\tgl.bindTexture(gl.TEXTURE_2D, null);\n\t\tthis.requestRender();\n\t}\n\n\tsetPointData(points: WsiPointData | null | undefined): void {\n\t\tif (!points || !points.count || !points.positions || !points.paletteIndices) {\n\t\t\tthis.lastPointData = null;\n\t\t\tthis.pointCount = 0;\n\t\t\tthis.usePointIndices = false;\n\t\t\tthis.requestRender();\n\t\t\treturn;\n\t\t}\n\n\t\tconst safeCount = Math.max(\n\t\t\t0,\n\t\t\tMath.min(\n\t\t\t\tpoints.count,\n\t\t\t\tMath.floor(points.positions.length / 2),\n\t\t\t\tpoints.paletteIndices.length,\n\t\t\t),\n\t\t);\n\t\tconst nextPositions = points.positions.subarray(0, safeCount * 2);\n\t\tconst nextPaletteIndices = points.paletteIndices.subarray(0, safeCount);\n\t\tconst hasDrawIndices = points.drawIndices instanceof Uint32Array;\n\t\tconst nextDrawIndices = hasDrawIndices\n\t\t\t? this.sanitizeDrawIndices(points.drawIndices as Uint32Array, safeCount)\n\t\t\t: null;\n\t\tconst prev = this.lastPointData;\n\t\tlet geometryChanged =\n\t\t\tthis.pointBuffersDirty ||\n\t\t\t!prev ||\n\t\t\tprev.count !== safeCount ||\n\t\t\t!isSameArrayView(prev.positions, nextPositions) ||\n\t\t\t!isSameArrayView(prev.paletteIndices, nextPaletteIndices);\n\t\tlet drawIndicesChanged =\n\t\t\tthis.pointBuffersDirty ||\n\t\t\t(hasDrawIndices &&\n\t\t\t\t(!prev?.drawIndices ||\n\t\t\t\t\t!isSameArrayView(prev.drawIndices, nextDrawIndices))) ||\n\t\t\t(!hasDrawIndices && !!prev?.drawIndices);\n\n\t\tthis.lastPointData = {\n\t\t\tcount: safeCount,\n\t\t\tpositions: nextPositions,\n\t\t\tpaletteIndices: nextPaletteIndices,\n\t\t\tdrawIndices: hasDrawIndices ? nextDrawIndices ?? undefined : undefined,\n\t\t};\n\t\tif (this.contextLost || this.gl.isContextLost()) return;\n\n\t\tconst gl = this.gl;\n\t\tif (geometryChanged) {\n\t\t\tgl.bindBuffer(gl.ARRAY_BUFFER, this.pointProgram.posBuffer);\n\t\t\tgl.bufferData(gl.ARRAY_BUFFER, this.lastPointData.positions, gl.STATIC_DRAW);\n\n\t\t\tgl.bindBuffer(gl.ARRAY_BUFFER, this.pointProgram.termBuffer);\n\t\t\tgl.bufferData(\n\t\t\t\tgl.ARRAY_BUFFER,\n\t\t\t\tthis.lastPointData.paletteIndices,\n\t\t\t\tgl.STATIC_DRAW,\n\t\t\t);\n\t\t\tgl.bindBuffer(gl.ARRAY_BUFFER, null);\n\t\t}\n\n\t\tif (hasDrawIndices && drawIndicesChanged) {\n\t\t\tgl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.pointProgram.indexBuffer);\n\t\t\tgl.bufferData(\n\t\t\t\tgl.ELEMENT_ARRAY_BUFFER,\n\t\t\t\tnextDrawIndices ?? new Uint32Array(0),\n\t\t\t\tgl.DYNAMIC_DRAW,\n\t\t\t);\n\t\t\tgl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);\n\t\t}\n\n\t\tthis.usePointIndices = hasDrawIndices;\n\t\tthis.pointCount = hasDrawIndices\n\t\t\t? (nextDrawIndices?.length ?? 0)\n\t\t\t: this.lastPointData.count;\n\t\tif (geometryChanged || drawIndicesChanged) {\n\t\t\tthis.pointBuffersDirty = false;\n\t\t}\n\t\tthis.requestRender();\n\t}\n\n\tprivate sanitizeDrawIndices(\n\t\tdrawIndices: Uint32Array,\n\t\tmaxExclusive: number,\n\t): Uint32Array {\n\t\tif (maxExclusive <= 0 || drawIndices.length === 0) {\n\t\t\treturn new Uint32Array(0);\n\t\t}\n\n\t\tlet validCount = drawIndices.length;\n\t\tfor (let i = 0; i < drawIndices.length; i += 1) {\n\t\t\tif (drawIndices[i] < maxExclusive) continue;\n\t\t\tvalidCount -= 1;\n\t\t}\n\t\tif (validCount === drawIndices.length) {\n\t\t\treturn drawIndices;\n\t\t}\n\t\tif (validCount <= 0) {\n\t\t\treturn new Uint32Array(0);\n\t\t}\n\n\t\tconst filtered = new Uint32Array(validCount);\n\t\tlet cursor = 0;\n\t\tfor (let i = 0; i < drawIndices.length; i += 1) {\n\t\t\tconst idx = drawIndices[i];\n\t\t\tif (idx >= maxExclusive) continue;\n\t\t\tfiltered[cursor] = idx;\n\t\t\tcursor += 1;\n\t\t}\n\t\treturn filtered;\n\t}\n\n\tsetInteractionLock(locked: boolean): void {\n\t\tconst next = Boolean(locked);\n\t\tif (this.interactionLocked === next) return;\n\t\tthis.interactionLocked = next;\n\t\tif (next) this.cancelDrag();\n\t}\n\n\tcancelDrag(): void {\n\t\tif (this.pointerId !== null && this.canvas.hasPointerCapture(this.pointerId)) {\n\t\t\ttry {\n\t\t\t\tthis.canvas.releasePointerCapture(this.pointerId);\n\t\t\t} catch {\n\t\t\t\t// noop\n\t\t\t}\n\t\t}\n\t\tthis.dragging = false;\n\t\tthis.interactionMode = \"none\";\n\t\tthis.rotateLastAngleRad = null;\n\t\tthis.pointerId = null;\n\t\tthis.canvas.classList.remove(\"dragging\");\n\t}\n\n\tprivate getPointerAngleRad(clientX: number, clientY: number): number {\n\t\tconst rect = this.canvas.getBoundingClientRect();\n\t\tconst x = clientX - rect.left - rect.width * 0.5;\n\t\tconst y = clientY - rect.top - rect.height * 0.5;\n\t\treturn Math.atan2(y, x);\n\t}\n\n\tscreenToWorld(clientX: number, clientY: number): [number, number] {\n\t\tconst rect = this.canvas.getBoundingClientRect();\n\t\tconst sx = clientX - rect.left;\n\t\tconst sy = clientY - rect.top;\n\t\treturn this.camera.screenToWorld(sx, sy);\n\t}\n\n\tworldToScreen(worldX: number, worldY: number): [number, number] {\n\t\treturn this.camera.worldToScreen(worldX, worldY);\n\t}\n\n\tsetViewCenter(worldX: number, worldY: number): void {\n\t\tif (!Number.isFinite(worldX) || !Number.isFinite(worldY)) return;\n\t\tthis.camera.setCenter(worldX, worldY);\n\t\tthis.clampViewState();\n\t\tthis.emitViewState();\n\t\tthis.requestRender();\n\t}\n\n\tgetViewCorners(): [WorldPoint, WorldPoint, WorldPoint, WorldPoint] {\n\t\treturn this.camera.getViewCorners();\n\t}\n\n\tresetRotation(): void {\n\t\tconst state = this.camera.getViewState();\n\t\tif (Math.abs(state.rotationDeg) < 1e-6) return;\n\t\tthis.camera.setViewState({ rotationDeg: 0 });\n\t\tthis.clampViewState();\n\t\tthis.emitViewState();\n\t\tthis.requestRender();\n\t}\n\n\tgetPointSizeByZoom(): number {\n\t\tconst zoom = Math.max(1e-6, this.camera.getViewState().zoom);\n\t\tconst continuousZoom = this.source.maxTierZoom + Math.log2(zoom);\n\t\tconst stops: [number, number][] = [\n\t\t\t[1, 2.6],\n\t\t\t[2, 3.1],\n\t\t\t[3, 3.8],\n\t\t\t[4, 4.8],\n\t\t\t[5, 6.1],\n\t\t\t[6, 7.4],\n\t\t\t[7, 8.4],\n\t\t\t[8, 9.0],\n\t\t\t[9, 11.5],\n\t\t\t[10, 14.5],\n\t\t\t[11, 18.0],\n\t\t\t[12, 22.0],\n\t\t];\n\t\tlet size = stops[0][1];\n\t\tfor (let i = 1; i < stops.length; i += 1) {\n\t\t\tconst [z0, s0] = stops[i - 1];\n\t\t\tconst [z1, s1] = stops[i];\n\t\t\tif (continuousZoom <= z0) break;\n\t\t\tconst t = clamp((continuousZoom - z0) / Math.max(1e-6, z1 - z0), 0, 1);\n\t\t\tsize = s0 + (s1 - s0) * t;\n\t\t}\n\n\t\tconst lastStop = stops[stops.length - 1];\n\t\tif (continuousZoom > lastStop[0]) {\n\t\t\tsize += (continuousZoom - lastStop[0]) * 4.0;\n\t\t}\n\n\t\treturn clamp(size, 2.2, 36.0);\n\t}\n\n\tfitToImage(): void {\n\t\tconst rect = this.canvas.getBoundingClientRect();\n\t\tconst vw = Math.max(1, rect.width || 1);\n\t\tconst vh = Math.max(1, rect.height || 1);\n\n\t\tconst zoom = Math.min(vw / this.source.width, vh / this.source.height);\n\t\tconst safeZoom = Number.isFinite(zoom) && zoom > 0 ? zoom : 1;\n\n\t\tthis.fitZoom = safeZoom;\n\t\tthis.minZoom = Math.max(this.fitZoom * 0.5, 1e-6);\n\t\tthis.maxZoom = Math.max(1, this.fitZoom * 8);\n\t\tif (this.minZoom > this.maxZoom) {\n\t\t\tthis.minZoom = this.maxZoom;\n\t\t}\n\n\t\tconst visibleWorldW = vw / safeZoom;\n\t\tconst visibleWorldH = vh / safeZoom;\n\n\t\tthis.camera.setViewState({\n\t\t\tzoom: clamp(safeZoom, this.minZoom, this.maxZoom),\n\t\t\toffsetX: (this.source.width - visibleWorldW) * 0.5,\n\t\t\toffsetY: (this.source.height - visibleWorldH) * 0.5,\n\t\t\trotationDeg: 0,\n\t\t});\n\n\t\tthis.clampViewState();\n\t\tthis.emitViewState();\n\t\tthis.requestRender();\n\t}\n\n\tzoomBy(factor: number, screenX: number, screenY: number): void {\n\t\tconst state = this.camera.getViewState();\n\t\tconst nextZoom = clamp(state.zoom * factor, this.minZoom, this.maxZoom);\n\t\tif (nextZoom === state.zoom) return;\n\n\t\tconst [worldX, worldY] = this.camera.screenToWorld(screenX, screenY);\n\n\t\tthis.camera.setViewState({ zoom: nextZoom });\n\n\t\tconst vp = this.camera.getViewport();\n\t\tconst dx = screenX - vp.width * 0.5;\n\t\tconst dy = screenY - vp.height * 0.5;\n\t\tconst rad = toRadians(this.camera.getViewState().rotationDeg);\n\t\tconst cos = Math.cos(rad);\n\t\tconst sin = Math.sin(rad);\n\t\tconst worldDx = (dx / nextZoom) * cos - (dy / nextZoom) * sin;\n\t\tconst worldDy = (dx / nextZoom) * sin + (dy / nextZoom) * cos;\n\t\tthis.camera.setCenter(worldX - worldDx, worldY - worldDy);\n\n\t\tthis.clampViewState();\n\t\tthis.emitViewState();\n\t\tthis.requestRender();\n\t}\n\n\tclampViewState(): void {\n\t\tconst bounds = this.getViewBounds();\n\t\tconst visibleW = Math.max(1e-6, bounds[2] - bounds[0]);\n\t\tconst visibleH = Math.max(1e-6, bounds[3] - bounds[1]);\n\t\tconst marginX = visibleW * 0.2;\n\t\tconst marginY = visibleH * 0.2;\n\n\t\tconst [centerX, centerY] = this.camera.getCenter();\n\t\tconst halfW = visibleW * 0.5;\n\t\tconst halfH = visibleH * 0.5;\n\n\t\tconst minCenterX = halfW - marginX;\n\t\tconst maxCenterX = this.source.width - halfW + marginX;\n\t\tconst minCenterY = halfH - marginY;\n\t\tconst maxCenterY = this.source.height - halfH + marginY;\n\n\t\tconst nextCenterX =\n\t\t\tminCenterX <= maxCenterX\n\t\t\t\t? clamp(centerX, minCenterX, maxCenterX)\n\t\t\t\t: this.source.width * 0.5;\n\t\tconst nextCenterY =\n\t\t\tminCenterY <= maxCenterY\n\t\t\t\t? clamp(centerY, minCenterY, maxCenterY)\n\t\t\t\t: this.source.height * 0.5;\n\n\t\tthis.camera.setCenter(nextCenterX, nextCenterY);\n\t}\n\n\temitViewState(): void {\n\t\tthis.onViewStateChange?.(this.camera.getViewState());\n\t}\n\n\tselectTier(): number {\n\t\tconst zoom = Math.max(1e-6, this.camera.getViewState().zoom);\n\t\tconst rawTier = this.source.maxTierZoom + Math.log2(zoom);\n\t\treturn clamp(Math.floor(rawTier), 0, this.source.maxTierZoom);\n\t}\n\n\tgetViewBounds(): Bounds {\n\t\tconst corners = this.camera.getViewCorners();\n\t\tlet minX = Infinity;\n\t\tlet minY = Infinity;\n\t\tlet maxX = -Infinity;\n\t\tlet maxY = -Infinity;\n\t\tfor (const [x, y] of corners) {\n\t\t\tif (x < minX) minX = x;\n\t\t\tif (x > maxX) maxX = x;\n\t\t\tif (y < minY) minY = y;\n\t\t\tif (y > maxY) maxY = y;\n\t\t}\n\t\treturn [minX, minY, maxX, maxY];\n\t}\n\n\tintersectsBounds(a: Bounds, b: Bounds): boolean {\n\t\treturn !(a[2] <= b[0] || a[0] >= b[2] || a[3] <= b[1] || a[1] >= b[3]);\n\t}\n\n\tgetVisibleTiles(): ScheduledTile[] {\n\t\tconst tier = this.selectTier();\n\t\tthis.currentTier = tier;\n\n\t\tconst viewBounds = this.getViewBounds();\n\n\t\tconst levelScale = Math.pow(2, this.source.maxTierZoom - tier);\n\t\tconst levelWidth = Math.ceil(this.source.width / levelScale);\n\t\tconst levelHeight = Math.ceil(this.source.height / levelScale);\n\n\t\tconst tilesX = Math.max(1, Math.ceil(levelWidth / this.source.tileSize));\n\t\tconst tilesY = Math.max(1, Math.ceil(levelHeight / this.source.tileSize));\n\n\t\tconst viewMinX = viewBounds[0];\n\t\tconst viewMinY = viewBounds[1];\n\t\tconst viewMaxX = viewBounds[2];\n\t\tconst viewMaxY = viewBounds[3];\n\n\t\tconst minTileX = clamp(\n\t\t\tMath.floor(viewMinX / levelScale / this.source.tileSize),\n\t\t\t0,\n\t\t\ttilesX - 1,\n\t\t);\n\t\tconst maxTileX = clamp(\n\t\t\tMath.floor((viewMaxX - 1) / levelScale / this.source.tileSize),\n\t\t\t0,\n\t\t\ttilesX - 1,\n\t\t);\n\t\tconst minTileY = clamp(\n\t\t\tMath.floor(viewMinY / levelScale / this.source.tileSize),\n\t\t\t0,\n\t\t\ttilesY - 1,\n\t\t);\n\t\tconst maxTileY = clamp(\n\t\t\tMath.floor((viewMaxY - 1) / levelScale / this.source.tileSize),\n\t\t\t0,\n\t\t\ttilesY - 1,\n\t\t);\n\n\t\tif (minTileX > maxTileX || minTileY > maxTileY) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst centerTileX = (viewMinX + viewMaxX) * 0.5 / levelScale / this.source.tileSize;\n\t\tconst centerTileY = (viewMinY + viewMaxY) * 0.5 / levelScale / this.source.tileSize;\n\n\t\tconst visible: ScheduledTile[] = [];\n\t\tfor (let y = minTileY; y <= maxTileY; y += 1) {\n\t\t\tfor (let x = minTileX; x <= maxTileX; x += 1) {\n\t\t\t\tconst left = x * this.source.tileSize * levelScale;\n\t\t\t\tconst top = y * this.source.tileSize * levelScale;\n\t\t\t\tconst right = Math.min((x + 1) * this.source.tileSize, levelWidth) * levelScale;\n\t\t\t\tconst bottom = Math.min((y + 1) * this.source.tileSize, levelHeight) * levelScale;\n\n\t\t\t\tconst dx = x - centerTileX;\n\t\t\t\tconst dy = y - centerTileY;\n\t\t\t\tvisible.push({\n\t\t\t\t\tkey: `${tier}/${x}/${y}`,\n\t\t\t\t\ttier,\n\t\t\t\t\tx,\n\t\t\t\t\ty,\n\t\t\t\t\tbounds: [left, top, right, bottom],\n\t\t\t\t\tdistance2: dx * dx + dy * dy,\n\t\t\t\t\turl: toTileUrl(this.source, tier, x, y),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tvisible.sort((a, b) => a.distance2 - b.distance2);\n\t\treturn visible;\n\t}\n\n\ttrimCache(): void {\n\t\tif (this.cache.size <= this.maxCacheTiles) return;\n\n\t\tconst entries = Array.from(this.cache.entries());\n\t\tentries.sort((a, b) => a[1].lastUsed - b[1].lastUsed);\n\n\t\tconst removeCount = this.cache.size - this.maxCacheTiles;\n\t\tfor (let i = 0; i < removeCount; i += 1) {\n\t\t\tconst [key, value] = entries[i];\n\t\t\tthis.gl.deleteTexture(value.texture);\n\t\t\tthis.cache.delete(key);\n\t\t}\n\t}\n\n\trender(): void {\n\t\tif (this.destroyed || this.contextLost || this.gl.isContextLost()) return;\n\t\tconst frameStartMs = nowMs();\n\t\tthis.frameSerial += 1;\n\n\t\tconst gl = this.gl;\n\t\tconst tileProgram = this.tileProgram;\n\t\tconst pointProgram = this.pointProgram;\n\n\t\tgl.clearColor(0.03, 0.06, 0.1, 1);\n\t\tgl.clear(gl.COLOR_BUFFER_BIT);\n\n\t\tconst visible = this.getVisibleTiles();\n\t\tconst viewBounds = this.getViewBounds();\n\t\tconst visibleKeys = new Set(visible.map((tile) => tile.key));\n\n\t\tgl.useProgram(tileProgram.program);\n\t\tgl.bindVertexArray(tileProgram.vao);\n\t\tgl.uniformMatrix3fv(tileProgram.uCamera, false, this.camera.getMatrix());\n\t\tgl.uniform1i(tileProgram.uTexture, 0);\n\n\t\tconst fallbackTiles: CachedTile[] = [];\n\t\tfor (const [, cached] of this.cache) {\n\t\t\tif (visibleKeys.has(cached.key)) continue;\n\t\t\tif (!this.intersectsBounds(cached.bounds, viewBounds)) continue;\n\t\t\tfallbackTiles.push(cached);\n\t\t}\n\n\t\tfallbackTiles.sort((a, b) => a.tier - b.tier);\n\t\tfor (const cached of fallbackTiles) {\n\t\t\tcached.lastUsed = this.frameSerial;\n\t\t\tgl.activeTexture(gl.TEXTURE0);\n\t\t\tgl.bindTexture(gl.TEXTURE_2D, cached.texture);\n\t\t\tgl.uniform4f(\n\t\t\t\ttileProgram.uBounds,\n\t\t\t\tcached.bounds[0],\n\t\t\t\tcached.bounds[1],\n\t\t\t\tcached.bounds[2],\n\t\t\t\tcached.bounds[3],\n\t\t\t);\n\t\t\tgl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);\n\t\t}\n\n\t\tlet renderedTiles = 0;\n\t\tconst missingTiles: ScheduledTile[] = [];\n\t\tfor (const tile of visible) {\n\t\t\tconst cached = this.cache.get(tile.key);\n\t\t\tif (!cached) {\n\t\t\t\tmissingTiles.push(tile);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tcached.lastUsed = this.frameSerial;\n\t\t\tgl.activeTexture(gl.TEXTURE0);\n\t\t\tgl.bindTexture(gl.TEXTURE_2D, cached.texture);\n\t\t\tgl.uniform4f(\n\t\t\t\ttileProgram.uBounds,\n\t\t\t\tcached.bounds[0],\n\t\t\t\tcached.bounds[1],\n\t\t\t\tcached.bounds[2],\n\t\t\t\tcached.bounds[3],\n\t\t\t);\n\t\t\tgl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);\n\t\t\trenderedTiles += 1;\n\t\t}\n\t\tthis.tileScheduler.schedule(missingTiles);\n\n\t\tgl.bindTexture(gl.TEXTURE_2D, null);\n\t\tgl.bindVertexArray(null);\n\n\t\tlet renderedPoints = 0;\n\t\tif (this.pointCount > 0) {\n\t\t\tgl.enable(gl.BLEND);\n\t\t\tgl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);\n\t\t\tgl.useProgram(pointProgram.program);\n\t\t\tgl.bindVertexArray(pointProgram.vao);\n\t\t\tgl.uniformMatrix3fv(pointProgram.uCamera, false, this.camera.getMatrix());\n\t\t\tgl.uniform1f(pointProgram.uPointSize, this.getPointSizeByZoom());\n\t\t\tgl.uniform1f(pointProgram.uPaletteSize, this.pointPaletteSize);\n\t\t\tgl.uniform1i(pointProgram.uPalette, 1);\n\t\t\tgl.activeTexture(gl.TEXTURE1);\n\t\t\tgl.bindTexture(gl.TEXTURE_2D, pointProgram.paletteTexture);\n\t\t\tif (this.usePointIndices) {\n\t\t\t\tgl.drawElements(gl.POINTS, this.pointCount, gl.UNSIGNED_INT, 0);\n\t\t\t} else {\n\t\t\t\tgl.drawArrays(gl.POINTS, 0, this.pointCount);\n\t\t\t}\n\t\t\tgl.bindTexture(gl.TEXTURE_2D, null);\n\t\t\tgl.bindVertexArray(null);\n\t\t\trenderedPoints = this.pointCount;\n\t\t}\n\n\t\tif (this.onStats) {\n\t\t\tconst schedulerStats = this.tileScheduler.getSnapshot();\n\t\t\tconst cacheHits = renderedTiles;\n\t\t\tconst cacheMisses = missingTiles.length;\n\t\t\tconst drawCalls =\n\t\t\t\tfallbackTiles.length + renderedTiles + (renderedPoints > 0 ? 1 : 0);\n\t\t\tthis.onStats({\n\t\t\t\ttier: this.currentTier,\n\t\t\t\tvisible: visible.length,\n\t\t\t\trendered: renderedTiles,\n\t\t\t\tpoints: renderedPoints,\n\t\t\t\tfallback: fallbackTiles.length,\n\t\t\t\tcache: this.cache.size,\n\t\t\t\tinflight: schedulerStats.inflight,\n\t\t\t\tqueued: schedulerStats.queued,\n\t\t\t\tretries: schedulerStats.retries,\n\t\t\t\tfailed: schedulerStats.failed,\n\t\t\t\taborted: schedulerStats.aborted,\n\t\t\t\tcacheHits,\n\t\t\t\tcacheMisses,\n\t\t\t\tdrawCalls,\n\t\t\t\tframeMs: nowMs() - frameStartMs,\n\t\t\t});\n\t\t}\n\t}\n\n\trequestRender(): void {\n\t\tif (\n\t\t\tthis.frame !== null ||\n\t\t\tthis.destroyed ||\n\t\t\tthis.contextLost ||\n\t\t\tthis.gl.isContextLost()\n\t\t)\n\t\t\treturn;\n\t\tthis.frame = requestAnimationFrame(() => {\n\t\t\tthis.frame = null;\n\t\t\tthis.render();\n\t\t});\n\t}\n\n\tresize(): void {\n\t\tconst rect = this.canvas.getBoundingClientRect();\n\t\tconst cssW = Math.max(1, rect.width || this.canvas.clientWidth || 1);\n\t\tconst cssH = Math.max(1, rect.height || this.canvas.clientHeight || 1);\n\t\tconst dpr = Math.max(1, window.devicePixelRatio || 1);\n\n\t\tconst pixelW = Math.max(1, Math.round(cssW * dpr));\n\t\tconst pixelH = Math.max(1, Math.round(cssH * dpr));\n\n\t\tif (this.canvas.width !== pixelW || this.canvas.height !== pixelH) {\n\t\t\tthis.canvas.width = pixelW;\n\t\t\tthis.canvas.height = pixelH;\n\t\t}\n\n\t\tthis.camera.setViewport(cssW, cssH);\n\t\tthis.gl.viewport(0, 0, pixelW, pixelH);\n\t\tthis.requestRender();\n\t}\n\n\tonPointerDown(event: PointerEvent): void {\n\t\tif (this.interactionLocked) return;\n\t\tconst wantsRotate = this.ctrlDragRotate && (event.ctrlKey || event.metaKey);\n\t\tconst allowButton = event.button === 0 || (wantsRotate && event.button === 2);\n\t\tif (!allowButton) return;\n\t\tif (wantsRotate) {\n\t\t\tevent.preventDefault();\n\t\t}\n\t\tthis.dragging = true;\n\t\tthis.interactionMode =\n\t\t\twantsRotate ? \"rotate\" : \"pan\";\n\t\tthis.pointerId = event.pointerId;\n\t\tthis.lastPointerX = event.clientX;\n\t\tthis.lastPointerY = event.clientY;\n\t\tthis.rotateLastAngleRad =\n\t\t\tthis.interactionMode === \"rotate\"\n\t\t\t\t? this.getPointerAngleRad(event.clientX, event.clientY)\n\t\t\t\t: null;\n\t\tthis.canvas.classList.add(\"dragging\");\n\t\tthis.canvas.setPointerCapture(event.pointerId);\n\t}\n\n\tonPointerMove(event: PointerEvent): void {\n\t\tif (this.interactionLocked) return;\n\t\tif (!this.dragging || event.pointerId !== this.pointerId) return;\n\n\t\tconst dx = event.clientX - this.lastPointerX;\n\t\tconst dy = event.clientY - this.lastPointerY;\n\t\tthis.lastPointerX = event.clientX;\n\t\tthis.lastPointerY = event.clientY;\n\n\t\tif (this.interactionMode === \"rotate\") {\n\t\t\tconst nextAngle = this.getPointerAngleRad(event.clientX, event.clientY);\n\t\t\tconst prevAngle = this.rotateLastAngleRad;\n\t\t\tthis.rotateLastAngleRad = nextAngle;\n\t\t\tif (prevAngle !== null) {\n\t\t\t\tconst rawDelta = nextAngle - prevAngle;\n\t\t\t\tconst delta = Math.atan2(Math.sin(rawDelta), Math.cos(rawDelta));\n\n\t\t\t\tconst sensitivityScale =\n\t\t\t\t\tDEFAULT_ROTATION_DRAG_SENSITIVITY > 0\n\t\t\t\t\t\t? this.rotationDragSensitivityDegPerPixel /\n\t\t\t\t\t\t\tDEFAULT_ROTATION_DRAG_SENSITIVITY\n\t\t\t\t\t\t: 1;\n\t\t\t\tconst state = this.camera.getViewState();\n\t\t\t\tthis.camera.setViewState({\n\t\t\t\t\trotationDeg:\n\t\t\t\t\t\tstate.rotationDeg - ((delta * 180) / Math.PI) * sensitivityScale,\n\t\t\t\t});\n\t\t\t}\n\t\t} else {\n\t\t\tconst state = this.camera.getViewState();\n\t\t\tconst zoom = Math.max(1e-6, state.zoom);\n\t\t\tconst rad = toRadians(state.rotationDeg);\n\t\t\tconst cos = Math.cos(rad);\n\t\t\tconst sin = Math.sin(rad);\n\t\t\tconst worldDx = (dx * cos - dy * sin) / zoom;\n\t\t\tconst worldDy = (dx * sin + dy * cos) / zoom;\n\t\t\tthis.camera.setViewState({\n\t\t\t\toffsetX: state.offsetX - worldDx,\n\t\t\t\toffsetY: state.offsetY - worldDy,\n\t\t\t});\n\t\t}\n\n\t\tthis.clampViewState();\n\t\tthis.emitViewState();\n\t\tthis.requestRender();\n\t}\n\n\tonPointerUp(event: PointerEvent): void {\n\t\tif (this.interactionLocked) return;\n\t\tif (event.pointerId !== this.pointerId) return;\n\t\tthis.cancelDrag();\n\t}\n\n\tonWheel(event: WheelEvent): void {\n\t\tif (this.interactionLocked) {\n\t\t\tevent.preventDefault();\n\t\t\treturn;\n\t\t}\n\n\t\tevent.preventDefault();\n\t\tconst rect = this.canvas.getBoundingClientRect();\n\t\tconst x = event.clientX - rect.left;\n\t\tconst y = event.clientY - rect.top;\n\t\tconst factor = event.deltaY < 0 ? 1.12 : 0.89;\n\t\tthis.zoomBy(factor, x, y);\n\t}\n\n\tonDoubleClick(event: MouseEvent): void {\n\t\tif (this.interactionLocked) return;\n\t\tconst rect = this.canvas.getBoundingClientRect();\n\t\tconst x = event.clientX - rect.left;\n\t\tconst y = event.clientY - rect.top;\n\t\tthis.zoomBy(event.shiftKey ? 0.8 : 1.25, x, y);\n\t}\n\n\tonContextMenu(event: MouseEvent): void {\n\t\tif (this.dragging || event.ctrlKey || event.metaKey) {\n\t\t\tevent.preventDefault();\n\t\t}\n\t}\n\n\tprivate onWebGlContextLost(event: Event): void {\n\t\tevent.preventDefault();\n\t\tif (this.destroyed || this.contextLost) return;\n\t\tthis.contextLost = true;\n\t\tthis.pointBuffersDirty = true;\n\n\t\tif (this.frame !== null) {\n\t\t\tcancelAnimationFrame(this.frame);\n\t\t\tthis.frame = null;\n\t\t}\n\n\t\tthis.cancelDrag();\n\t\tthis.tileScheduler.clear();\n\t\tthis.cache.clear();\n\t\tthis.onContextLost?.();\n\t}\n\n\tprivate onWebGlContextRestored(_event: Event): void {\n\t\tif (this.destroyed) return;\n\t\tthis.contextLost = false;\n\t\tthis.cache.clear();\n\n\t\tthis.tileProgram = this.initTileProgram();\n\t\tthis.pointProgram = this.initPointProgram();\n\t\tthis.pointBuffersDirty = true;\n\n\t\tif (this.lastPointPalette && this.lastPointPalette.length > 0) {\n\t\t\tthis.setPointPalette(this.lastPointPalette);\n\t\t}\n\t\tif (this.lastPointData) {\n\t\t\tthis.setPointData(this.lastPointData);\n\t\t} else {\n\t\t\tthis.pointCount = 0;\n\t\t}\n\n\t\tthis.resize();\n\t\tthis.requestRender();\n\t\tthis.onContextRestored?.();\n\t}\n\n\tdestroy(): void {\n\t\tif (this.destroyed) return;\n\t\tthis.destroyed = true;\n\n\t\tif (this.frame !== null) {\n\t\t\tcancelAnimationFrame(this.frame);\n\t\t\tthis.frame = null;\n\t\t}\n\n\t\tthis.resizeObserver.disconnect();\n\t\tthis.canvas.removeEventListener(\"pointerdown\", this.boundPointerDown);\n\t\tthis.canvas.removeEventListener(\"pointermove\", this.boundPointerMove);\n\t\tthis.canvas.removeEventListener(\"pointerup\", this.boundPointerUp);\n\t\tthis.canvas.removeEventListener(\"pointercancel\", this.boundPointerUp);\n\t\tthis.canvas.removeEventListener(\"wheel\", this.boundWheel);\n\t\tthis.canvas.removeEventListener(\"dblclick\", this.boundDoubleClick);\n\t\tthis.canvas.removeEventListener(\"contextmenu\", this.boundContextMenu);\n\t\tthis.canvas.removeEventListener(\"webglcontextlost\", this.boundContextLost);\n\t\tthis.canvas.removeEventListener(\n\t\t\t\"webglcontextrestored\",\n\t\t\tthis.boundContextRestored,\n\t\t);\n\t\tthis.cancelDrag();\n\t\tthis.tileScheduler.destroy();\n\n\t\tif (!this.contextLost && !this.gl.isContextLost()) {\n\t\t\tfor (const [, value] of this.cache) {\n\t\t\t\tthis.gl.deleteTexture(value.texture);\n\t\t\t}\n\t\t\tthis.gl.deleteBuffer(this.tileProgram.vbo);\n\t\t\tthis.gl.deleteVertexArray(this.tileProgram.vao);\n\t\t\tthis.gl.deleteProgram(this.tileProgram.program);\n\n\t\t\tthis.gl.deleteBuffer(this.pointProgram.posBuffer);\n\t\t\tthis.gl.deleteBuffer(this.pointProgram.termBuffer);\n\t\t\tthis.gl.deleteBuffer(this.pointProgram.indexBuffer);\n\t\t\tthis.gl.deleteTexture(this.pointProgram.paletteTexture);\n\t\t\tthis.gl.deleteVertexArray(this.pointProgram.vao);\n\t\t\tthis.gl.deleteProgram(this.pointProgram.program);\n\t\t}\n\t\tthis.cache.clear();\n\t}\n\n\tprivate initTileProgram(): TileVertexProgram {\n\t\tconst gl = this.gl;\n\n\t\tconst vertex = `#version 300 es\n precision highp float;\n in vec2 aUnit;\n in vec2 aUv;\n uniform mat3 uCamera;\n uniform vec4 uBounds;\n out vec2 vUv;\n void main() {\n vec2 world = vec2(\n mix(uBounds.x, uBounds.z, aUnit.x),\n mix(uBounds.y, uBounds.w, aUnit.y)\n );\n vec3 clip = uCamera * vec3(world, 1.0);\n gl_Position = vec4(clip.xy, 0.0, 1.0);\n vUv = aUv;\n }`;\n\n\t\tconst fragment = `#version 300 es\n precision highp float;\n in vec2 vUv;\n uniform sampler2D uTexture;\n out vec4 outColor;\n void main() {\n outColor = texture(uTexture, vUv);\n }`;\n\n\t\tconst program = createProgram(gl, vertex, fragment);\n\t\tconst uCamera = requireUniformLocation(gl, program, \"uCamera\");\n\t\tconst uBounds = requireUniformLocation(gl, program, \"uBounds\");\n\t\tconst uTexture = requireUniformLocation(gl, program, \"uTexture\");\n\n\t\tconst vao = gl.createVertexArray();\n\t\tconst vbo = gl.createBuffer();\n\t\tif (!vao || !vbo) {\n\t\t\tthrow new Error(\"buffer allocation failed\");\n\t\t}\n\n\t\tgl.bindVertexArray(vao);\n\t\tgl.bindBuffer(gl.ARRAY_BUFFER, vbo);\n\t\tgl.bufferData(\n\t\t\tgl.ARRAY_BUFFER,\n\t\t\tnew Float32Array([0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1]),\n\t\t\tgl.STATIC_DRAW,\n\t\t);\n\n\t\tconst aUnit = gl.getAttribLocation(program, \"aUnit\");\n\t\tconst aUv = gl.getAttribLocation(program, \"aUv\");\n\t\tif (aUnit < 0 || aUv < 0) {\n\t\t\tthrow new Error(\"tile attribute lookup failed\");\n\t\t}\n\t\tgl.enableVertexAttribArray(aUnit);\n\t\tgl.enableVertexAttribArray(aUv);\n\t\tgl.vertexAttribPointer(aUnit, 2, gl.FLOAT, false, 16, 0);\n\t\tgl.vertexAttribPointer(aUv, 2, gl.FLOAT, false, 16, 8);\n\n\t\tgl.bindVertexArray(null);\n\t\tgl.bindBuffer(gl.ARRAY_BUFFER, null);\n\n\t\treturn { program, vao, vbo, uCamera, uBounds, uTexture };\n\t}\n\n\tprivate initPointProgram(): PointProgram {\n\t\tconst gl = this.gl;\n\n\t\tconst pointVertex = `#version 300 es\n precision highp float;\n in vec2 aPosition;\n in uint aTerm;\n uniform mat3 uCamera;\n uniform float uPointSize;\n flat out uint vTerm;\n void main() {\n vec3 clip = uCamera * vec3(aPosition, 1.0);\n gl_Position = vec4(clip.xy, 0.0, 1.0);\n gl_PointSize = uPointSize;\n vTerm = aTerm;\n }`;\n\n\t\tconst pointFragment = `#version 300 es\n precision highp float;\n flat in uint vTerm;\n uniform sampler2D uPalette;\n uniform float uPaletteSize;\n uniform float uPointSize;\n out vec4 outColor;\n void main() {\n vec2 pc = gl_PointCoord * 2.0 - 1.0;\n float r = length(pc);\n if (r > 1.0) discard;\n\n float idx = clamp(float(vTerm), 0.0, max(0.0, uPaletteSize - 1.0));\n vec2 uv = vec2((idx + 0.5) / uPaletteSize, 0.5);\n vec4 color = texture(uPalette, uv);\n if (color.a <= 0.0) discard;\n\n float ringWidth = clamp(3.0 / max(1.0, uPointSize), 0.12, 0.62);\n float innerRadius = 1.0 - ringWidth;\n float aa = 1.5 / max(1.0, uPointSize);\n\n float outerMask = 1.0 - smoothstep(1.0 - aa, 1.0 + aa, r);\n float innerMask = smoothstep(innerRadius - aa, innerRadius + aa, r);\n float alpha = outerMask * innerMask * color.a;\n if (alpha <= 0.001) discard;\n\n outColor = vec4(color.rgb * alpha, alpha);\n }`;\n\n\t\tconst program = createProgram(gl, pointVertex, pointFragment);\n\t\tconst uCamera = requireUniformLocation(gl, program, \"uCamera\");\n\t\tconst uPointSize = requireUniformLocation(gl, program, \"uPointSize\");\n\t\tconst uPalette = requireUniformLocation(gl, program, \"uPalette\");\n\t\tconst uPaletteSize = requireUniformLocation(gl, program, \"uPaletteSize\");\n\n\t\tconst vao = gl.createVertexArray();\n\t\tconst posBuffer = gl.createBuffer();\n\t\tconst termBuffer = gl.createBuffer();\n\t\tconst indexBuffer = gl.createBuffer();\n\t\tconst paletteTexture = gl.createTexture();\n\t\tif (!vao || !posBuffer || !termBuffer || !indexBuffer || !paletteTexture) {\n\t\t\tthrow new Error(\"point buffer allocation failed\");\n\t\t}\n\n\t\tgl.bindVertexArray(vao);\n\n\t\tgl.bindBuffer(gl.ARRAY_BUFFER, posBuffer);\n\t\tgl.bufferData(gl.ARRAY_BUFFER, 0, gl.DYNAMIC_DRAW);\n\t\tconst posLoc = gl.getAttribLocation(program, \"aPosition\");\n\t\tif (posLoc < 0) {\n\t\t\tthrow new Error(\"point position attribute not found\");\n\t\t}\n\t\tgl.enableVertexAttribArray(posLoc);\n\t\tgl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, 0, 0);\n\n\t\tgl.bindBuffer(gl.ARRAY_BUFFER, termBuffer);\n\t\tgl.bufferData(gl.ARRAY_BUFFER, 0, gl.DYNAMIC_DRAW);\n\t\tconst termLoc = gl.getAttribLocation(program, \"aTerm\");\n\t\tif (termLoc < 0) {\n\t\t\tthrow new Error(\"point term attribute not found\");\n\t\t}\n\t\tgl.enableVertexAttribArray(termLoc);\n\t\tgl.vertexAttribIPointer(termLoc, 1, gl.UNSIGNED_SHORT, 0, 0);\n\n\t\tgl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);\n\t\tgl.bufferData(gl.ELEMENT_ARRAY_BUFFER, 0, gl.DYNAMIC_DRAW);\n\n\t\tgl.bindVertexArray(null);\n\t\tgl.bindBuffer(gl.ARRAY_BUFFER, null);\n\t\tgl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);\n\n\t\tgl.bindTexture(gl.TEXTURE_2D, paletteTexture);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n\t\tgl.texImage2D(\n\t\t\tgl.TEXTURE_2D,\n\t\t\t0,\n\t\t\tgl.RGBA,\n\t\t\t1,\n\t\t\t1,\n\t\t\t0,\n\t\t\tgl.RGBA,\n\t\t\tgl.UNSIGNED_BYTE,\n\t\t\tnew Uint8Array([160, 160, 160, 255]),\n\t\t);\n\t\tgl.bindTexture(gl.TEXTURE_2D, null);\n\n\t\treturn {\n\t\t\tprogram,\n\t\t\tvao,\n\t\t\tposBuffer,\n\t\t\ttermBuffer,\n\t\t\tindexBuffer,\n\t\t\tpaletteTexture,\n\t\t\tuCamera,\n\t\t\tuPointSize,\n\t\t\tuPalette,\n\t\t\tuPaletteSize,\n\t\t};\n\t}\n\n\tprivate handleTileLoaded(tile: ScheduledTile, bitmap: ImageBitmap): void {\n\t\tif (this.destroyed || this.contextLost || this.gl.isContextLost()) {\n\t\t\tbitmap.close();\n\t\t\treturn;\n\t\t}\n\t\tif (this.cache.has(tile.key)) {\n\t\t\tbitmap.close();\n\t\t\treturn;\n\t\t}\n\n\t\tconst texture = this.createTextureFromBitmap(bitmap);\n\t\tbitmap.close();\n\t\tif (!texture) return;\n\n\t\tthis.cache.set(tile.key, {\n\t\t\tkey: tile.key,\n\t\t\ttexture,\n\t\t\tbounds: tile.bounds,\n\t\t\ttier: tile.tier,\n\t\t\tlastUsed: this.frameSerial,\n\t\t});\n\t\tthis.trimCache();\n\t\tthis.requestRender();\n\t}\n\n\tprivate createTextureFromBitmap(bitmap: ImageBitmap): WebGLTexture | null {\n\t\tif (this.contextLost || this.gl.isContextLost()) return null;\n\t\tconst gl = this.gl;\n\t\tconst texture = gl.createTexture();\n\t\tif (!texture) return null;\n\n\t\tgl.bindTexture(gl.TEXTURE_2D, texture);\n\t\tgl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n\t\tgl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, bitmap);\n\t\tgl.bindTexture(gl.TEXTURE_2D, null);\n\t\treturn texture;\n\t}\n}\n","import { type CSSProperties, type MouseEvent as ReactMouseEvent, type ReactNode, type PointerEvent as ReactPointerEvent, useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { filterPointDataByPolygons, type RoiPolygon } from \"../wsi/point-clip\";\nimport { filterPointDataByPolygonsHybrid } from \"../wsi/point-clip-hybrid\";\nimport { filterPointDataByPolygonsInWorker, type PointClipMode } from \"../wsi/point-clip-worker-client\";\nimport { computeRoiPointGroups, type RoiPointGroupStats } from \"../wsi/roi-term-stats\";\nimport type { WsiImageSource, WsiPointData, WsiRegion, WsiRenderStats, WsiViewState } from \"../wsi/types\";\nimport { type WsiTileErrorEvent, WsiTileRenderer } from \"../wsi/wsi-tile-renderer\";\nimport type { DrawCoordinate, DrawOverlayShape, DrawResult, DrawTool, PatchDrawResult, RegionLabelStyle, RegionStrokeStyle, RegionStrokeStyleResolver, StampOptions } from \"./draw-layer\";\nimport { DrawLayer } from \"./draw-layer\";\nimport { OverviewMap, type OverviewMapOptions } from \"./overview-map\";\n\nconst EMPTY_ROI_REGIONS: WsiRegion[] = [];\nconst EMPTY_ROI_POLYGONS: DrawCoordinate[][] = [];\nconst EMPTY_CLIPPED_POINTS: WsiPointData = {\n count: 0,\n positions: new Float32Array(0),\n paletteIndices: new Uint16Array(0),\n};\n\nexport interface RegionHoverEvent {\n region: WsiRegion | null;\n regionId: string | number | null;\n regionIndex: number;\n coordinate: DrawCoordinate | null;\n}\n\nexport interface RegionClickEvent {\n region: WsiRegion;\n regionId: string | number;\n regionIndex: number;\n coordinate: DrawCoordinate;\n}\n\nexport interface PointClipStatsEvent {\n mode: PointClipMode;\n durationMs: number;\n inputCount: number;\n outputCount: number;\n polygonCount: number;\n usedWebGpu?: boolean;\n candidateCount?: number;\n bridgedToDraw?: boolean;\n}\n\nexport interface PointerWorldMoveEvent {\n coordinate: DrawCoordinate | null;\n clientX: number;\n clientY: number;\n insideImage: boolean;\n}\n\nexport interface WsiCustomLayerContext {\n source: WsiImageSource;\n viewState: WsiViewState;\n drawTool: DrawTool;\n interactionLock: boolean;\n worldToScreen: (worldX: number, worldY: number) => DrawCoordinate | null;\n screenToWorld: (clientX: number, clientY: number) => DrawCoordinate | null;\n requestRedraw: () => void;\n}\n\nexport interface WsiCustomLayer {\n id?: string | number;\n zIndex?: number;\n pointerEvents?: CSSProperties[\"pointerEvents\"];\n className?: string;\n style?: CSSProperties;\n render: (context: WsiCustomLayerContext) => ReactNode;\n}\n\nfunction resolveRegionId(region: WsiRegion, index: number): string | number {\n return region.id ?? index;\n}\n\nfunction isPointInPolygon(point: DrawCoordinate, polygon: DrawCoordinate[]): boolean {\n if (!Array.isArray(polygon) || polygon.length < 3) return false;\n\n const [x, y] = point;\n let inside = false;\n\n for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {\n const [xi, yi] = polygon[i];\n const [xj, yj] = polygon[j];\n const intersect = yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / Math.max(1e-12, yj - yi) + xi;\n if (intersect) inside = !inside;\n }\n\n return inside;\n}\n\nfunction pickRegionAt(\n coord: DrawCoordinate,\n regions: WsiRegion[]\n): {\n region: WsiRegion;\n regionIndex: number;\n regionId: string | number;\n} | null {\n for (let i = regions.length - 1; i >= 0; i -= 1) {\n const region = regions[i];\n if (!region?.coordinates?.length) continue;\n if (!isPointInPolygon(coord, region.coordinates)) continue;\n return {\n region,\n regionIndex: i,\n regionId: resolveRegionId(region, i),\n };\n }\n return null;\n}\n\nexport interface WsiViewerCanvasProps {\n source: WsiImageSource | null;\n viewState?: Partial<WsiViewState> | null;\n onViewStateChange?: (next: WsiViewState) => void;\n onStats?: (stats: WsiRenderStats) => void;\n onTileError?: (event: WsiTileErrorEvent) => void;\n onContextLost?: () => void;\n onContextRestored?: () => void;\n debugOverlay?: boolean;\n debugOverlayStyle?: CSSProperties;\n fitNonce?: number;\n rotationResetNonce?: number;\n authToken?: string;\n ctrlDragRotate?: boolean;\n pointData?: WsiPointData | null;\n pointPalette?: Uint8Array | null;\n roiRegions?: WsiRegion[];\n roiPolygons?: DrawCoordinate[][];\n clipPointsToRois?: boolean;\n clipMode?: PointClipMode;\n onClipStats?: (event: PointClipStatsEvent) => void;\n onRoiPointGroups?: (stats: RoiPointGroupStats) => void;\n roiPaletteIndexToTermId?: ReadonlyMap<number, string> | readonly string[];\n interactionLock?: boolean;\n drawTool?: DrawTool;\n stampOptions?: StampOptions;\n regionStrokeStyle?: Partial<RegionStrokeStyle>;\n regionStrokeHoverStyle?: Partial<RegionStrokeStyle>;\n regionStrokeActiveStyle?: Partial<RegionStrokeStyle>;\n patchStrokeStyle?: Partial<RegionStrokeStyle>;\n resolveRegionStrokeStyle?: RegionStrokeStyleResolver;\n overlayShapes?: DrawOverlayShape[];\n customLayers?: WsiCustomLayer[];\n patchRegions?: WsiRegion[];\n regionLabelStyle?: Partial<RegionLabelStyle>;\n onPointerWorldMove?: (event: PointerWorldMoveEvent) => void;\n onRegionHover?: (event: RegionHoverEvent) => void;\n onRegionClick?: (event: RegionClickEvent) => void;\n onActiveRegionChange?: (regionId: string | number | null) => void;\n onDrawComplete?: (result: DrawResult) => void;\n onPatchComplete?: (result: PatchDrawResult) => void;\n showOverviewMap?: boolean;\n overviewMapOptions?: Partial<OverviewMapOptions>;\n className?: string;\n style?: CSSProperties;\n}\n\nexport function WsiViewerCanvas({\n source,\n viewState,\n onViewStateChange,\n onStats,\n onTileError,\n onContextLost,\n onContextRestored,\n debugOverlay = false,\n debugOverlayStyle,\n fitNonce = 0,\n rotationResetNonce = 0,\n authToken = \"\",\n ctrlDragRotate = true,\n pointData = null,\n pointPalette = null,\n roiRegions,\n roiPolygons,\n clipPointsToRois = false,\n clipMode = \"worker\",\n onClipStats,\n onRoiPointGroups,\n roiPaletteIndexToTermId,\n interactionLock = false,\n drawTool = \"cursor\",\n stampOptions,\n regionStrokeStyle,\n regionStrokeHoverStyle,\n regionStrokeActiveStyle,\n patchStrokeStyle,\n resolveRegionStrokeStyle,\n overlayShapes,\n customLayers,\n patchRegions,\n regionLabelStyle,\n onPointerWorldMove,\n onRegionHover,\n onRegionClick,\n onActiveRegionChange,\n onDrawComplete,\n onPatchComplete,\n showOverviewMap = false,\n overviewMapOptions,\n className,\n style,\n}: WsiViewerCanvasProps): React.ReactElement {\n const canvasRef = useRef<HTMLCanvasElement | null>(null);\n const rendererRef = useRef<WsiTileRenderer | null>(null);\n const drawInvalidateRef = useRef<(() => void) | null>(null);\n const overviewInvalidateRef = useRef<(() => void) | null>(null);\n const onViewStateChangeRef = useRef<typeof onViewStateChange>(onViewStateChange);\n const onStatsRef = useRef<typeof onStats>(onStats);\n const debugOverlayRef = useRef(debugOverlay);\n const [isOverviewOpen, setIsOverviewOpen] = useState(true);\n const [hoveredRegionId, setHoveredRegionId] = useState<string | number | null>(null);\n const [activeRegionId, setActiveRegionId] = useState<string | number | null>(null);\n const [customLayerViewState, setCustomLayerViewState] = useState<WsiViewState | null>(null);\n const [debugStats, setDebugStats] = useState<WsiRenderStats | null>(null);\n const hoveredRegionIdRef = useRef<string | number | null>(null);\n const clipRunIdRef = useRef(0);\n const safeRoiRegions = roiRegions ?? EMPTY_ROI_REGIONS;\n const safePatchRegions = patchRegions ?? EMPTY_ROI_REGIONS;\n const safeRoiPolygons = roiPolygons ?? EMPTY_ROI_POLYGONS;\n const shouldTrackCustomLayerViewState = (customLayers?.length ?? 0) > 0;\n\n const mergedStyle = useMemo<CSSProperties>(() => ({ position: \"relative\", width: \"100%\", height: \"100%\", ...style }), [style]);\n const mergedDebugOverlayStyle = useMemo<CSSProperties>(\n () => ({\n position: \"absolute\",\n top: 8,\n left: 8,\n zIndex: 7,\n margin: 0,\n padding: \"8px 10px\",\n maxWidth: \"min(420px, 80%)\",\n pointerEvents: \"none\",\n whiteSpace: \"pre-wrap\",\n lineHeight: 1.35,\n fontFamily: \"ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace\",\n fontSize: 11,\n color: \"#cde6ff\",\n background: \"rgba(6, 12, 20, 0.82)\",\n border: \"1px solid rgba(173, 216, 255, 0.28)\",\n borderRadius: 8,\n boxShadow: \"0 8px 22px rgba(0,0,0,0.35)\",\n ...debugOverlayStyle,\n }),\n [debugOverlayStyle]\n );\n\n const effectiveRoiRegions = useMemo<WsiRegion[]>(() => {\n if (safeRoiRegions.length > 0) {\n return safeRoiRegions;\n }\n if (safeRoiPolygons.length === 0) {\n return EMPTY_ROI_REGIONS;\n }\n return safeRoiPolygons.map((coordinates, index) => ({\n id: index,\n coordinates,\n }));\n }, [safeRoiRegions, safeRoiPolygons]);\n\n const clipPolygons = useMemo(() => effectiveRoiRegions.map(region => region.coordinates), [effectiveRoiRegions]);\n\n const [renderPointData, setRenderPointData] = useState<WsiPointData | null>(pointData);\n\n useEffect(() => {\n const runId = ++clipRunIdRef.current;\n let cancelled = false;\n\n if (!clipPointsToRois) {\n setRenderPointData(pointData);\n return () => {\n cancelled = true;\n };\n }\n\n if (!pointData || !pointData.count || !pointData.positions || !pointData.paletteIndices) {\n setRenderPointData(null);\n return () => {\n cancelled = true;\n };\n }\n\n if (clipPolygons.length === 0) {\n setRenderPointData(EMPTY_CLIPPED_POINTS);\n onClipStats?.({\n mode: clipMode,\n durationMs: 0,\n inputCount: pointData.count,\n outputCount: 0,\n polygonCount: 0,\n });\n return () => {\n cancelled = true;\n };\n }\n\n const applyResult = (data: WsiPointData | null, stats: Omit<PointClipStatsEvent, \"inputCount\" | \"outputCount\" | \"polygonCount\">) => {\n if (cancelled || runId !== clipRunIdRef.current) return;\n const outputCount = data?.drawIndices ? data.drawIndices.length : (data?.count ?? 0);\n setRenderPointData(data);\n onClipStats?.({\n mode: stats.mode,\n durationMs: stats.durationMs,\n inputCount: pointData.count,\n outputCount,\n polygonCount: clipPolygons.length,\n usedWebGpu: stats.usedWebGpu,\n candidateCount: stats.candidateCount,\n bridgedToDraw: stats.bridgedToDraw,\n });\n };\n\n const run = async (): Promise<void> => {\n if (clipMode === \"sync\") {\n const start = performance.now();\n const data = filterPointDataByPolygons(pointData, clipPolygons);\n applyResult(data, {\n mode: \"sync\",\n durationMs: performance.now() - start,\n });\n return;\n }\n\n if (clipMode === \"hybrid-webgpu\") {\n const result = await filterPointDataByPolygonsHybrid(pointData, clipPolygons as RoiPolygon[], { bridgeToDraw: true });\n applyResult(result.data, {\n mode: result.meta.mode,\n durationMs: result.meta.durationMs,\n usedWebGpu: result.meta.usedWebGpu,\n candidateCount: result.meta.candidateCount,\n bridgedToDraw: result.meta.bridgedToDraw,\n });\n return;\n }\n\n try {\n const result = await filterPointDataByPolygonsInWorker(pointData, clipPolygons as RoiPolygon[]);\n applyResult(result.data, {\n mode: result.meta.mode,\n durationMs: result.meta.durationMs,\n });\n } catch {\n const start = performance.now();\n const data = filterPointDataByPolygons(pointData, clipPolygons);\n applyResult(data, {\n mode: \"sync\",\n durationMs: performance.now() - start,\n });\n }\n };\n\n void run();\n return () => {\n cancelled = true;\n };\n }, [clipPointsToRois, clipMode, pointData, clipPolygons, onClipStats]);\n\n const overviewWidth = useMemo(() => {\n const value = Number(overviewMapOptions?.width ?? 220);\n return Number.isFinite(value) ? Math.max(64, value) : 220;\n }, [overviewMapOptions?.width]);\n const overviewHeight = useMemo(() => {\n const value = Number(overviewMapOptions?.height ?? 140);\n return Number.isFinite(value) ? Math.max(48, value) : 140;\n }, [overviewMapOptions?.height]);\n const overviewMargin = useMemo(() => {\n const value = Number(overviewMapOptions?.margin ?? 16);\n return Number.isFinite(value) ? Math.max(0, value) : 16;\n }, [overviewMapOptions?.margin]);\n const overviewPosition = overviewMapOptions?.position || \"bottom-right\";\n\n const commitActiveRegion = useCallback(\n (next: string | number | null) => {\n setActiveRegionId(prev => {\n if (String(prev) === String(next)) {\n return prev;\n }\n onActiveRegionChange?.(next);\n return next;\n });\n },\n [onActiveRegionChange]\n );\n\n useEffect(() => {\n onViewStateChangeRef.current = onViewStateChange;\n }, [onViewStateChange]);\n\n useEffect(() => {\n onStatsRef.current = onStats;\n }, [onStats]);\n\n useEffect(() => {\n debugOverlayRef.current = debugOverlay;\n if (!debugOverlay) setDebugStats(null);\n }, [debugOverlay]);\n\n const handleRendererStats = useCallback((stats: WsiRenderStats): void => {\n onStatsRef.current?.(stats);\n if (debugOverlayRef.current) {\n setDebugStats(stats);\n }\n }, []);\n\n const debugOverlayText = useMemo(() => {\n if (!debugStats) {\n return \"stats: waiting for first frame...\";\n }\n return [\n `tier ${debugStats.tier} | frame ${debugStats.frameMs?.toFixed(2) ?? \"-\"} ms | drawCalls ${debugStats.drawCalls ?? \"-\"}`,\n `tiles visible ${debugStats.visible} | rendered ${debugStats.rendered} | fallback ${debugStats.fallback}`,\n `cache size ${debugStats.cache} | hit ${debugStats.cacheHits ?? \"-\"} | miss ${debugStats.cacheMisses ?? \"-\"}`,\n `queue inflight ${debugStats.inflight} | queued ${debugStats.queued ?? \"-\"} | retries ${debugStats.retries ?? \"-\"} | failed ${debugStats.failed ?? \"-\"} | aborted ${debugStats.aborted ?? \"-\"}`,\n `points ${debugStats.points}`,\n ].join(\"\\n\");\n }, [debugStats]);\n\n useEffect(() => {\n const hasActive = activeRegionId === null ? true : effectiveRoiRegions.some((region, index) => String(resolveRegionId(region, index)) === String(activeRegionId));\n if (!hasActive && activeRegionId !== null) {\n commitActiveRegion(null);\n }\n\n const currentHover = hoveredRegionIdRef.current;\n const hasHover = currentHover === null ? true : effectiveRoiRegions.some((region, index) => String(resolveRegionId(region, index)) === String(currentHover));\n\n if (!hasHover && currentHover !== null) {\n hoveredRegionIdRef.current = null;\n setHoveredRegionId(null);\n onRegionHover?.({\n region: null,\n regionId: null,\n regionIndex: -1,\n coordinate: null,\n });\n }\n }, [effectiveRoiRegions, activeRegionId, onRegionHover, commitActiveRegion]);\n\n const emitViewStateChange = useCallback(\n (next: WsiViewState): void => {\n if (shouldTrackCustomLayerViewState) {\n setCustomLayerViewState(next);\n }\n const callback = onViewStateChangeRef.current;\n if (callback) {\n callback(next);\n }\n drawInvalidateRef.current?.();\n overviewInvalidateRef.current?.();\n },\n [shouldTrackCustomLayerViewState]\n );\n\n useEffect(() => {\n if (!showOverviewMap) {\n setIsOverviewOpen(false);\n return;\n }\n setIsOverviewOpen(true);\n }, [showOverviewMap, source?.id]);\n\n useEffect(() => {\n if (drawTool === \"cursor\") return;\n if (hoveredRegionIdRef.current === null) return;\n hoveredRegionIdRef.current = null;\n setHoveredRegionId(null);\n onRegionHover?.({\n region: null,\n regionId: null,\n regionIndex: -1,\n coordinate: null,\n });\n }, [drawTool, onRegionHover]);\n\n const resolveWorldCoord = useCallback((clientX: number, clientY: number): DrawCoordinate | null => {\n const renderer = rendererRef.current;\n if (!renderer) return null;\n const raw = renderer.screenToWorld(clientX, clientY);\n if (!Array.isArray(raw) || raw.length < 2) return null;\n const x = Number(raw[0]);\n const y = Number(raw[1]);\n if (!Number.isFinite(x) || !Number.isFinite(y)) return null;\n return [x, y];\n }, []);\n\n const resolveScreenCoord = useCallback((worldX: number, worldY: number): DrawCoordinate | null => {\n const renderer = rendererRef.current;\n if (!renderer) return null;\n const raw = renderer.worldToScreen(worldX, worldY);\n if (!Array.isArray(raw) || raw.length < 2) return null;\n const x = Number(raw[0]);\n const y = Number(raw[1]);\n if (!Number.isFinite(x) || !Number.isFinite(y)) return null;\n return [x, y];\n }, []);\n\n const requestCustomLayerRedraw = useCallback(() => {\n rendererRef.current?.requestRender();\n drawInvalidateRef.current?.();\n overviewInvalidateRef.current?.();\n }, []);\n\n const effectiveCustomLayerViewState = useMemo<WsiViewState | null>(() => {\n return customLayerViewState ?? rendererRef.current?.getViewState() ?? null;\n }, [customLayerViewState]);\n\n const customLayerContext = useMemo<WsiCustomLayerContext | null>(() => {\n if (!source) return null;\n const viewStateForLayer = effectiveCustomLayerViewState;\n if (!viewStateForLayer) return null;\n return {\n source,\n viewState: viewStateForLayer,\n drawTool,\n interactionLock,\n worldToScreen: resolveScreenCoord,\n screenToWorld: resolveWorldCoord,\n requestRedraw: requestCustomLayerRedraw,\n };\n }, [source, effectiveCustomLayerViewState, drawTool, interactionLock, resolveScreenCoord, resolveWorldCoord, requestCustomLayerRedraw]);\n\n const handleRegionPointerMove = useCallback(\n (event: ReactPointerEvent<HTMLDivElement>) => {\n const isCanvasEvent = event.target === canvasRef.current;\n const coord = resolveWorldCoord(event.clientX, event.clientY);\n if (onPointerWorldMove) {\n const insideImage = !!coord && coord[0] >= 0 && coord[1] >= 0 && !!source && coord[0] <= source.width && coord[1] <= source.height;\n onPointerWorldMove({\n coordinate: coord,\n clientX: event.clientX,\n clientY: event.clientY,\n insideImage,\n });\n }\n\n if (drawTool !== \"cursor\") return;\n if (!isCanvasEvent) {\n if (hoveredRegionIdRef.current !== null) {\n hoveredRegionIdRef.current = null;\n setHoveredRegionId(null);\n onRegionHover?.({\n region: null,\n regionId: null,\n regionIndex: -1,\n coordinate: null,\n });\n }\n return;\n }\n if (!coord) return;\n if (!effectiveRoiRegions.length) return;\n\n const hit = pickRegionAt(coord, effectiveRoiRegions);\n const nextHoverId = hit?.regionId ?? null;\n const prevHoverId = hoveredRegionIdRef.current;\n if (String(prevHoverId) === String(nextHoverId)) return;\n\n hoveredRegionIdRef.current = nextHoverId;\n setHoveredRegionId(nextHoverId);\n onRegionHover?.({\n region: hit?.region ?? null,\n regionId: nextHoverId,\n regionIndex: hit?.regionIndex ?? -1,\n coordinate: coord,\n });\n },\n [drawTool, effectiveRoiRegions, resolveWorldCoord, onRegionHover, onPointerWorldMove, source]\n );\n\n const handleRegionPointerLeave = useCallback(() => {\n onPointerWorldMove?.({\n coordinate: null,\n clientX: -1,\n clientY: -1,\n insideImage: false,\n });\n if (hoveredRegionIdRef.current === null) return;\n hoveredRegionIdRef.current = null;\n setHoveredRegionId(null);\n onRegionHover?.({\n region: null,\n regionId: null,\n regionIndex: -1,\n coordinate: null,\n });\n }, [onRegionHover, onPointerWorldMove]);\n\n const handleRegionClick = useCallback(\n (event: ReactMouseEvent<HTMLDivElement>) => {\n if (drawTool !== \"cursor\") return;\n if (event.target !== canvasRef.current) return;\n if (!effectiveRoiRegions.length) {\n commitActiveRegion(null);\n return;\n }\n\n const coord = resolveWorldCoord(event.clientX, event.clientY);\n if (!coord) return;\n\n const hit = pickRegionAt(coord, effectiveRoiRegions);\n if (!hit) {\n commitActiveRegion(null);\n return;\n }\n\n const nextActive: string | number | null = activeRegionId !== null && String(activeRegionId) === String(hit.regionId) ? null : hit.regionId;\n commitActiveRegion(nextActive);\n onRegionClick?.({\n region: hit.region,\n regionId: hit.regionId,\n regionIndex: hit.regionIndex,\n coordinate: coord,\n });\n },\n [drawTool, effectiveRoiRegions, resolveWorldCoord, onRegionClick, activeRegionId, commitActiveRegion]\n );\n\n useEffect(() => {\n const canvas = canvasRef.current;\n if (!canvas || !source) {\n return;\n }\n\n const renderer = new WsiTileRenderer(canvas, source, {\n onViewStateChange: emitViewStateChange,\n onStats: handleRendererStats,\n onTileError,\n onContextLost,\n onContextRestored,\n authToken,\n ctrlDragRotate,\n });\n\n rendererRef.current = renderer;\n if (viewState) {\n renderer.setViewState(viewState);\n }\n renderer.setInteractionLock(interactionLock);\n if (shouldTrackCustomLayerViewState) {\n setCustomLayerViewState(renderer.getViewState());\n }\n\n return () => {\n renderer.destroy();\n rendererRef.current = null;\n };\n }, [source, handleRendererStats, onTileError, onContextLost, onContextRestored, authToken, ctrlDragRotate, emitViewStateChange, shouldTrackCustomLayerViewState]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer || !viewState) {\n return;\n }\n renderer.setViewState(viewState);\n }, [viewState]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) {\n return;\n }\n renderer.fitToImage();\n }, [fitNonce]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) return;\n renderer.resetRotation();\n }, [rotationResetNonce]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer || !pointPalette) {\n return;\n }\n renderer.setPointPalette(pointPalette);\n }, [pointPalette]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) {\n return;\n }\n renderer.setPointData(renderPointData);\n }, [renderPointData]);\n\n useEffect(() => {\n if (!onRoiPointGroups) return;\n const sourcePoints = clipPointsToRois ? renderPointData : pointData;\n const stats = computeRoiPointGroups(sourcePoints, effectiveRoiRegions, {\n paletteIndexToTermId: roiPaletteIndexToTermId,\n includeEmptyRegions: true,\n });\n onRoiPointGroups(stats);\n }, [onRoiPointGroups, clipPointsToRois, pointData, renderPointData, effectiveRoiRegions, roiPaletteIndexToTermId]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) {\n return;\n }\n renderer.setInteractionLock(interactionLock);\n }, [interactionLock]);\n\n return (\n <div className={className} style={mergedStyle} onPointerMove={handleRegionPointerMove} onPointerLeave={handleRegionPointerLeave} onClick={handleRegionClick}>\n <canvas\n ref={canvasRef}\n className=\"wsi-render-canvas\"\n style={{\n position: \"absolute\",\n inset: 0,\n zIndex: 1,\n width: \"100%\",\n height: \"100%\",\n display: \"block\",\n touchAction: \"none\",\n cursor: drawTool === \"cursor\" && hoveredRegionId !== null ? \"pointer\" : interactionLock ? \"crosshair\" : \"grab\",\n }}\n />\n {source && customLayerContext && Array.isArray(customLayers) && customLayers.length > 0\n ? customLayers.map((layer, index) => (\n <div\n key={layer.id ?? index}\n className={layer.className}\n style={{\n position: \"absolute\",\n inset: 0,\n zIndex: layer.zIndex ?? 3,\n pointerEvents: layer.pointerEvents ?? \"none\",\n ...layer.style,\n }}\n >\n {layer.render(customLayerContext)}\n </div>\n ))\n : null}\n {source ? (\n <DrawLayer\n tool={drawTool}\n enabled={drawTool !== \"cursor\"}\n imageWidth={source.width}\n imageHeight={source.height}\n imageMpp={source.mpp}\n imageZoom={source.maxTierZoom}\n stampOptions={stampOptions}\n projectorRef={rendererRef}\n viewStateSignal={viewState}\n persistedRegions={effectiveRoiRegions}\n patchRegions={safePatchRegions}\n regionStrokeStyle={regionStrokeStyle}\n regionStrokeHoverStyle={regionStrokeHoverStyle}\n regionStrokeActiveStyle={regionStrokeActiveStyle}\n patchStrokeStyle={patchStrokeStyle}\n resolveRegionStrokeStyle={resolveRegionStrokeStyle}\n overlayShapes={overlayShapes}\n hoveredRegionId={hoveredRegionId}\n activeRegionId={activeRegionId}\n regionLabelStyle={regionLabelStyle}\n invalidateRef={drawInvalidateRef}\n onDrawComplete={onDrawComplete}\n onPatchComplete={onPatchComplete}\n />\n ) : null}\n {debugOverlay ? (\n <pre data-open-plant-debug-overlay style={mergedDebugOverlayStyle}>\n {debugOverlayText}\n </pre>\n ) : null}\n {source && showOverviewMap ? (\n isOverviewOpen ? (\n <>\n <OverviewMap source={source} projectorRef={rendererRef} authToken={authToken} options={overviewMapOptions} invalidateRef={overviewInvalidateRef} />\n <button\n type=\"button\"\n aria-label=\"Hide overview map\"\n onClick={() => setIsOverviewOpen(false)}\n style={{\n position: \"absolute\",\n zIndex: 6,\n ...(overviewPosition.includes(\"left\") ? { left: overviewMargin } : { right: overviewMargin }),\n ...(overviewPosition.includes(\"top\") ? { top: overviewMargin + overviewHeight + 8 } : { bottom: overviewMargin + overviewHeight + 8 }),\n width: 20,\n height: 20,\n borderRadius: 999,\n border: \"1px solid rgba(255,255,255,0.4)\",\n background: \"rgba(8, 14, 22, 0.9)\",\n color: \"#fff\",\n fontSize: 13,\n lineHeight: 1,\n cursor: \"pointer\",\n padding: 0,\n }}\n >\n ×\n </button>\n </>\n ) : (\n <button\n type=\"button\"\n aria-label=\"Show overview map\"\n onClick={() => setIsOverviewOpen(true)}\n style={{\n position: \"absolute\",\n zIndex: 6,\n ...(overviewPosition.includes(\"left\") ? { left: overviewMargin } : { right: overviewMargin }),\n ...(overviewPosition.includes(\"top\") ? { top: overviewMargin } : { bottom: overviewMargin }),\n height: 24,\n minWidth: 40,\n borderRadius: 999,\n border: \"1px solid rgba(255,255,255,0.45)\",\n background: \"rgba(8, 14, 22, 0.9)\",\n color: \"#dff8ff\",\n fontSize: 11,\n fontWeight: 700,\n cursor: \"pointer\",\n padding: \"0 8px\",\n }}\n >\n Map\n </button>\n )\n ) : null}\n </div>\n );\n}\n"],"names":["compileShader","gl","type","source","shader","log","createProgram","vertexSource","fragmentSource","vertexShader","fragmentShader","program","requireUniformLocation","uniformName","location","requireWebGL2","canvas","context","OrthoCamera$1","__publicField","width","height","next","viewWidth","viewHeight","sx","sy","tx","ty","VERTEX_SHADER","FRAGMENT_SHADER","M1TileRenderer","options","OrthoCamera","vao","quadBuffer","quadVertices","unitLocation","uvLocation","stride","tiles","version","loaded","tile","viewState","response","blob","bitmap","texture","error","rect","cssWidth","cssHeight","dpr","targetWidth","targetHeight","viewport","zoom","safeZoom","visibleWorldWidth","visibleWorldHeight","offsetX","offsetY","DEFAULT_POINT_COLOR","clamp","value","min","max","calcScaleResolution","imageMpp","imageZoom","currentZoom","mpp","z0","z1","calcScaleLength","length","unit","isSameViewState","a","b","toBearerToken","trimmed","token","hexToRgba","hex","match","n","buildTermPalette","terms","palette","termToPaletteIndex","term","termId","colors","vs","fs","DRAW_FILL","FREEHAND_MIN_POINTS","FREEHAND_SCREEN_STEP","CIRCLE_SIDES","MIN_AREA_PX","EMPTY_REGIONS","EMPTY_DASH","MICRONS_PER_MM","DEFAULT_STAMP_RECTANGLE_AREA_MM2","DEFAULT_STAMP_CIRCLE_AREA_MM2","DEFAULT_STAMP_RECTANGLE_PIXEL_SIZE","LEGACY_HPF_CIRCLE_AREA_MM2","DEFAULT_REGION_STROKE_STYLE","DEFAULT_PATCH_STROKE_STYLE","DEFAULT_REGION_LABEL_STYLE","isStampTool","tool","clampPositiveOrFallback","fallback","resolveStampOptions","mm2ToUm2","areaMm2","createSquareFromCenter","center","halfLength","closeRing","createCircleFromCenter","radius","sides","coords","t","out","x","y","first","last","createRectangle","start","end","createCircle","centerX","centerY","i","polygonArea","sum","computeBounds","minX","minY","maxX","maxY","isValidPolygon","drawPath","ctx","points","strokeStyle","close","fill","resolveStrokeStyle","style","dash","shadowBlur","shadowOffsetX","shadowOffsetY","mergeStrokeStyle","base","override","isSameRegionId","resolveLabelStyle","px","py","bw","oy","br","drawRoundedRect","r","getTopAnchor","point","drawRegionLabel","text","anchor","canvasWidth","canvasHeight","labelStyle","label","boxWidth","boxHeight","left","top","clampWorld","coord","imageWidth","imageHeight","toCoord","DrawLayer","stampOptions","projectorRef","onDrawComplete","onPatchComplete","enabled","viewStateSignal","persistedRegions","patchRegions","persistedPolygons","regionStrokeStyle","regionStrokeHoverStyle","regionStrokeActiveStyle","patchStrokeStyle","resolveRegionStrokeStyle","overlayShapes","hoveredRegionId","activeRegionId","regionLabelStyle","invalidateRef","className","canvasRef","useRef","drawPendingRef","lastToolRef","sessionRef","active","mergedPersistedRegions","useMemo","coordinates","index","mergedPatchRegions","resolvedStrokeStyle","resolvedHoverStrokeStyle","resolvedActiveStrokeStyle","resolvedPatchStrokeStyle","resolvedLabelStyle","resolvedStampOptions","mergedStyle","resizeCanvas","useCallback","w","h","worldToScreenPoints","projector","micronsToWorldPixels","lengthUm","mppValue","imageZoomValue","viewZoomRaw","viewZoom","continuousZoom","umPerScreenPixel","buildStampCoords","stampTool","areaUm2","buildPreviewCoords","session","drawOverlay","region","ring","closed","screen","regionKey","state","resolved","shape","preview","line","polygon","anchorWorld","anchorScreen","requestDraw","resetSession","toWorld","event","raw","finishSession","handleStampAt","intent","result","handlePointerDown","world","handlePointerMove","minWorldStep","minWorldStep2","prev","dx","dy","handlePointerUp","handlePointerLeave","useEffect","observer","onKeyDown","jsx","trimTrailingSlash","ensureLeadingSlash","joinImsTileRoot","tileBaseUrl","parsed","origin","path","normalizeImageInfo","ims","isIms","tileSize","maxTierZoom","tilePath","normalizedPath","imsTileRoot","tileUrlBuilder","tier","toTileUrl","DEFAULT_OVERVIEW_MAP_OPTIONS","toPositiveNumber","isFiniteBounds","bounds","OverviewMap","authToken","thumbnailRef","lastBoundsRef","draggingRef","rafRef","margin","borderRadius","borderWidth","maxThumbnailTiles","backgroundColor","borderColor","viewportStrokeColor","viewportFillColor","interactive","showThumbnail","position","pos","draw","cssW","cssH","pixelW","pixelH","corners","safeBounds","safeCorners","right","bottom","rectW","rectH","toWorldFromClient","clientX","clientY","nx","ny","recenterTo","worldX","worldY","visibleW","visibleH","drag","cancelled","levelScale","levelWidth","levelHeight","tilesX","tilesY","tileCount","requests","useAuthHeader","results","dw","dh","TileViewerCanvas","rendererRef","renderer","sanitizePointCount","pointData","preparePolygons","polygons","prepared","poly","isInsideRing","inside","j","xi","yi","xj","yj","isInsideAnyPolygon","filterPointDataByPolygons","count","positions","nextPositions","nextTerms","cursor","filterPointIndicesByPolygons","contextPromise","BBOX_PREFILTER_SHADER","hasWebGpu","nav","getNavigatorGpu","gpu","candidate","GPU_SHADER_STAGE_COMPUTE","GPU_BUFFER_USAGE_STORAGE","GPU_BUFFER_USAGE_COPY_DST","GPU_BUFFER_USAGE_COPY_SRC","GPU_BUFFER_USAGE_UNIFORM","GPU_BUFFER_USAGE_MAP_READ","GPU_MAP_MODE_READ","getWebGpuCapabilities","navGpu","adapter","getContext","device","bindGroupLayout","pipeline","align","step","prefilterPointsByBoundsWebGpu","pointCount","boundsCount","safePointCount","positionBytes","boundsBytes","outputBytes","limit","positionsBuffer","boundsBuffer","outputBuffer","uniformBuffer","readBuffer","bindGroup","commandEncoder","pass","mapped","nowMs","filterPointDataByPolygonsHybrid","bridgeToDraw","safeCount","bboxFlat","candidateMask","usedWebGpu","candidateCount","candidateIndices","candidateCursor","drawIndices","visibleCount","pointIndex","workerInstance","workerSupported","requestId","pendingById","createWorker","worker","handleWorkerMessage","handleWorkerError","msg","pending","indices","paletteIndices","output","terminateRoiClipWorker","filterPointDataByPolygonsInWorker","positionsCopy","termsCopy","id","startMs","resolve","reject","filterPointIndicesByPolygonsInWorker","ax","ay","bx","by","prepareRegions","regions","resolveTermId","paletteIndex","paletteIndexToTermId","fromArray","fromMap","computeRoiPointGroups","baseCount","valid","filtered","idx","inputCount","preparedRegions","regionTermCounters","regionTotalCounters","insideCount","bestRegion","regionTermMap","includeEmptyRegions","groups","totalCount","termMap","termCounts","shouldAttachAuthHeader","url","host","TileScheduler","nextVisibleKeys","inflight","queued","item","visibleKeys","nextQueue","key","earliestReadyAt","delay","now","controller","inflightEntry","nextAttempt","retryDelay","existing","attempt","exp","jitter","DEFAULT_ROTATION_DRAG_SENSITIVITY","screenX","screenY","rad","toRadians","cos","sin","rx","ry","deg","name","isSameArrayView","WsiTileRenderer","attemptCount","normalized","paletteSize","nextPaletteIndices","hasDrawIndices","nextDrawIndices","geometryChanged","drawIndicesChanged","maxExclusive","validCount","locked","stops","size","s0","s1","lastStop","vw","vh","visibleWorldW","visibleWorldH","factor","nextZoom","vp","worldDx","worldDy","marginX","marginY","halfW","halfH","minCenterX","maxCenterX","minCenterY","maxCenterY","nextCenterX","nextCenterY","rawTier","viewBounds","viewMinX","viewMinY","viewMaxX","viewMaxY","minTileX","maxTileX","minTileY","maxTileY","centerTileX","centerTileY","visible","entries","removeCount","frameStartMs","tileProgram","pointProgram","fallbackTiles","cached","renderedTiles","missingTiles","renderedPoints","schedulerStats","cacheHits","cacheMisses","drawCalls","wantsRotate","nextAngle","prevAngle","rawDelta","delta","sensitivityScale","_event","uCamera","uBounds","uTexture","vbo","aUnit","aUv","uPointSize","uPalette","uPaletteSize","posBuffer","termBuffer","indexBuffer","paletteTexture","posLoc","termLoc","EMPTY_ROI_REGIONS","EMPTY_ROI_POLYGONS","EMPTY_CLIPPED_POINTS","resolveRegionId","isPointInPolygon","pickRegionAt","WsiViewerCanvas","onViewStateChange","onStats","onTileError","onContextLost","onContextRestored","debugOverlay","debugOverlayStyle","fitNonce","rotationResetNonce","ctrlDragRotate","pointPalette","roiRegions","roiPolygons","clipPointsToRois","clipMode","onClipStats","onRoiPointGroups","roiPaletteIndexToTermId","interactionLock","drawTool","customLayers","onPointerWorldMove","onRegionHover","onRegionClick","onActiveRegionChange","showOverviewMap","overviewMapOptions","drawInvalidateRef","overviewInvalidateRef","onViewStateChangeRef","onStatsRef","debugOverlayRef","isOverviewOpen","setIsOverviewOpen","useState","setHoveredRegionId","setActiveRegionId","customLayerViewState","setCustomLayerViewState","debugStats","setDebugStats","hoveredRegionIdRef","clipRunIdRef","safeRoiRegions","safePatchRegions","safeRoiPolygons","shouldTrackCustomLayerViewState","mergedDebugOverlayStyle","effectiveRoiRegions","clipPolygons","renderPointData","setRenderPointData","runId","applyResult","data","stats","outputCount","overviewHeight","overviewMargin","overviewPosition","commitActiveRegion","handleRendererStats","debugOverlayText","currentHover","emitViewStateChange","callback","resolveWorldCoord","resolveScreenCoord","requestCustomLayerRedraw","effectiveCustomLayerViewState","customLayerContext","viewStateForLayer","handleRegionPointerMove","isCanvasEvent","insideImage","hit","nextHoverId","prevHoverId","handleRegionPointerLeave","handleRegionClick","nextActive","jsxs","layer","Fragment"],"mappings":"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"}
|