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.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","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","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","_documentCurrentScript","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.cjs","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","_documentCurrentScript","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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"}
|