open-plant 1.2.7 → 1.2.8
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/dist/index.cjs +5 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +342 -339
- package/dist/index.js.map +1 -1
- package/dist/types/react/draw-layer.d.ts.map +1 -1
- package/package.json +1 -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/brush-stroke.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 type BrushStrokeCoordinate = [number, number];\nexport type BrushStrokeBounds = [number, number, number, number];\n\nexport interface BrushStrokePolygonOptions {\n\tradius: number;\n\tclipBounds?: BrushStrokeBounds;\n\tminRasterStep?: number;\n\tmaxRasterPixels?: number;\n\tmaxRasterSize?: number;\n\tsimplifyTolerance?: number;\n\tcircleSides?: number;\n}\n\ninterface RasterConfig {\n\tminX: number;\n\tminY: number;\n\tstep: number;\n\tpadding: number;\n\twidth: number;\n\theight: number;\n}\n\ninterface BoundaryEdge {\n\tstart: number;\n\tend: number;\n\tdir: 0 | 1 | 2 | 3;\n}\n\nconst DEFAULT_MIN_RASTER_STEP = 0.1;\nconst DEFAULT_MAX_RASTER_PIXELS = 4_000_000;\nconst DEFAULT_MAX_RASTER_SIZE = 4096;\nconst DEFAULT_CIRCLE_SIDES = 64;\nconst MIN_RADIUS = 1e-6;\nconst ALPHA_THRESHOLD = 24;\n\nfunction clamp(value: number, min: number, max: number): number {\n\treturn Math.max(min, Math.min(max, value));\n}\n\nfunction closeRing(\n\tcoordinates: BrushStrokeCoordinate[],\n): BrushStrokeCoordinate[] {\n\tif (!Array.isArray(coordinates) || coordinates.length < 3) return [];\n\tconst out = coordinates.map(([x, y]) => [x, y] as BrushStrokeCoordinate);\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 sanitizePath(\n\tpoints: BrushStrokeCoordinate[],\n): BrushStrokeCoordinate[] {\n\tif (!Array.isArray(points) || points.length === 0) return [];\n\tconst out: BrushStrokeCoordinate[] = [];\n\tfor (const point of points) {\n\t\tif (!Array.isArray(point) || point.length < 2) continue;\n\t\tconst x = Number(point[0]);\n\t\tconst y = Number(point[1]);\n\t\tif (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n\t\tconst prev = out[out.length - 1];\n\t\tif (prev && Math.abs(prev[0] - x) < 1e-9 && Math.abs(prev[1] - y) < 1e-9) {\n\t\t\tcontinue;\n\t\t}\n\t\tout.push([x, y]);\n\t}\n\treturn out;\n}\n\nfunction createCirclePolygon(\n\tcenter: BrushStrokeCoordinate,\n\tradius: number,\n\tsides: number,\n): BrushStrokeCoordinate[] {\n\tif (radius <= MIN_RADIUS || sides < 8) return [];\n\tconst ring: BrushStrokeCoordinate[] = [];\n\tfor (let i = 0; i <= sides; i += 1) {\n\t\tconst t = (i / sides) * Math.PI * 2;\n\t\tring.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\treturn closeRing(ring);\n}\n\nfunction createBoundsFallback(\n\tpoints: BrushStrokeCoordinate[],\n\tradius: number,\n): BrushStrokeCoordinate[] {\n\tif (!points.length) return [];\n\tlet minX = Infinity;\n\tlet minY = Infinity;\n\tlet maxX = -Infinity;\n\tlet maxY = -Infinity;\n\tfor (const [x, y] of points) {\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\tif (!Number.isFinite(minX) || !Number.isFinite(minY)) return [];\n\tconst pad = Math.max(radius, 1);\n\treturn closeRing([\n\t\t[minX - pad, minY - pad],\n\t\t[maxX + pad, minY - pad],\n\t\t[maxX + pad, maxY + pad],\n\t\t[minX - pad, maxY + pad],\n\t]);\n}\n\nfunction computeExpandedBounds(\n\tpoints: BrushStrokeCoordinate[],\n\tradius: number,\n): BrushStrokeBounds {\n\tlet minX = Infinity;\n\tlet minY = Infinity;\n\tlet maxX = -Infinity;\n\tlet maxY = -Infinity;\n\tfor (const [x, y] of points) {\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\tconst pad = Math.max(radius, 1);\n\treturn [minX - pad, minY - pad, maxX + pad, maxY + pad];\n}\n\nfunction resolveRasterConfig(\n\tbounds: BrushStrokeBounds,\n\tradius: number,\n\toptions: BrushStrokePolygonOptions,\n): RasterConfig {\n\tconst minRasterStep = Math.max(\n\t\tDEFAULT_MIN_RASTER_STEP,\n\t\tNumber(options.minRasterStep) || 0,\n\t);\n\tconst maxRasterPixels = Math.max(\n\t\t32_768,\n\t\tMath.floor(options.maxRasterPixels || DEFAULT_MAX_RASTER_PIXELS),\n\t);\n\tconst maxRasterSize = Math.max(\n\t\t256,\n\t\tMath.floor(options.maxRasterSize || DEFAULT_MAX_RASTER_SIZE),\n\t);\n\n\tconst widthWorld = Math.max(1e-3, bounds[2] - bounds[0]);\n\tconst heightWorld = Math.max(1e-3, bounds[3] - bounds[1]);\n\tlet step = Math.max(minRasterStep, Number.EPSILON);\n\tlet padding = 3;\n\tlet width = Math.ceil(widthWorld / step) + padding * 2 + 1;\n\tlet height = Math.ceil(heightWorld / step) + padding * 2 + 1;\n\n\twhile (\n\t\twidth > maxRasterSize ||\n\t\theight > maxRasterSize ||\n\t\twidth * height > maxRasterPixels\n\t) {\n\t\tstep *= 1.15;\n\t\twidth = Math.ceil(widthWorld / step) + padding * 2 + 1;\n\t\theight = Math.ceil(heightWorld / step) + padding * 2 + 1;\n\t\tif (step > Math.max(widthWorld, heightWorld)) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\twidth = Math.max(8, width);\n\theight = Math.max(8, height);\n\n\treturn {\n\t\tminX: bounds[0],\n\t\tminY: bounds[1],\n\t\tstep,\n\t\tpadding,\n\t\twidth,\n\t\theight,\n\t};\n}\n\ntype AnyCanvas2DContext =\n\t| CanvasRenderingContext2D\n\t| OffscreenCanvasRenderingContext2D;\n\nfunction createRasterContext(\n\twidth: number,\n\theight: number,\n): AnyCanvas2DContext | null {\n\tif (typeof OffscreenCanvas !== \"undefined\") {\n\t\tconst canvas = new OffscreenCanvas(width, height);\n\t\tconst context = canvas.getContext(\"2d\", { willReadFrequently: true });\n\t\tif (context) return context;\n\t}\n\tif (typeof document !== \"undefined\") {\n\t\tconst canvas = document.createElement(\"canvas\");\n\t\tcanvas.width = width;\n\t\tcanvas.height = height;\n\t\treturn canvas.getContext(\"2d\", { willReadFrequently: true });\n\t}\n\treturn null;\n}\n\nfunction worldToRaster(\n\tpoint: BrushStrokeCoordinate,\n\tconfig: RasterConfig,\n): BrushStrokeCoordinate {\n\treturn [\n\t\t(point[0] - config.minX) / config.step + config.padding,\n\t\t(point[1] - config.minY) / config.step + config.padding,\n\t];\n}\n\nfunction rasterizeStrokeMask(\n\tpath: BrushStrokeCoordinate[],\n\tradius: number,\n\tconfig: RasterConfig,\n): Uint8Array {\n\tconst context = createRasterContext(config.width, config.height);\n\tif (!context) return new Uint8Array(0);\n\n\tcontext.clearRect(0, 0, config.width, config.height);\n\tcontext.fillStyle = \"#ffffff\";\n\tcontext.strokeStyle = \"#ffffff\";\n\tcontext.lineCap = \"round\";\n\tcontext.lineJoin = \"round\";\n\tcontext.lineWidth = (radius * 2) / config.step;\n\n\tconst points = path.map(point => worldToRaster(point, config));\n\tif (points.length <= 1) {\n\t\tconst p = points[0];\n\t\tif (!p) return new Uint8Array(0);\n\t\tcontext.beginPath();\n\t\tcontext.arc(p[0], p[1], radius / config.step, 0, Math.PI * 2);\n\t\tcontext.fill();\n\t} else {\n\t\tcontext.beginPath();\n\t\tcontext.moveTo(points[0][0], points[0][1]);\n\t\tfor (let i = 1; i < points.length; i += 1) {\n\t\t\tcontext.lineTo(points[i][0], points[i][1]);\n\t\t}\n\t\tcontext.stroke();\n\t}\n\n\tconst image = context.getImageData(0, 0, config.width, config.height);\n\tconst out = new Uint8Array(config.width * config.height);\n\tfor (let i = 0; i < out.length; i += 1) {\n\t\tout[i] = image.data[i * 4 + 3] >= ALPHA_THRESHOLD ? 1 : 0;\n\t}\n\treturn out;\n}\n\nfunction buildBoundaryEdges(mask: Uint8Array, width: number, height: number): BoundaryEdge[] {\n\tconst edges: BoundaryEdge[] = [];\n\tconst stride = width + 1;\n\tconst vertex = (x: number, y: number): number => y * stride + x;\n\tconst at = (x: number, y: number): boolean =>\n\t\tx >= 0 && y >= 0 && x < width && y < height && mask[y * width + x] > 0;\n\n\tfor (let y = 0; y < height; y += 1) {\n\t\tfor (let x = 0; x < width; x += 1) {\n\t\t\tif (!at(x, y)) continue;\n\t\t\tif (!at(x, y - 1)) {\n\t\t\t\tedges.push({\n\t\t\t\t\tstart: vertex(x, y),\n\t\t\t\t\tend: vertex(x + 1, y),\n\t\t\t\t\tdir: 0,\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (!at(x + 1, y)) {\n\t\t\t\tedges.push({\n\t\t\t\t\tstart: vertex(x + 1, y),\n\t\t\t\t\tend: vertex(x + 1, y + 1),\n\t\t\t\t\tdir: 1,\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (!at(x, y + 1)) {\n\t\t\t\tedges.push({\n\t\t\t\t\tstart: vertex(x + 1, y + 1),\n\t\t\t\t\tend: vertex(x, y + 1),\n\t\t\t\t\tdir: 2,\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (!at(x - 1, y)) {\n\t\t\t\tedges.push({\n\t\t\t\t\tstart: vertex(x, y + 1),\n\t\t\t\t\tend: vertex(x, y),\n\t\t\t\t\tdir: 3,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn edges;\n}\n\nfunction turnPriority(fromDir: number, toDir: number): number {\n\tconst delta = (toDir - fromDir + 4) % 4;\n\tif (delta === 1) return 0; // right\n\tif (delta === 0) return 1; // straight\n\tif (delta === 3) return 2; // left\n\treturn 3; // reverse\n}\n\nfunction traceLoops(edges: BoundaryEdge[]): number[][] {\n\tif (!edges.length) return [];\n\n\tconst outgoing = new Map<number, number[]>();\n\tfor (let i = 0; i < edges.length; i += 1) {\n\t\tconst entry = outgoing.get(edges[i].start);\n\t\tif (entry) {\n\t\t\tentry.push(i);\n\t\t} else {\n\t\t\toutgoing.set(edges[i].start, [i]);\n\t\t}\n\t}\n\n\tconst used = new Uint8Array(edges.length);\n\tconst loops: number[][] = [];\n\n\tfor (let i = 0; i < edges.length; i += 1) {\n\t\tif (used[i]) continue;\n\n\t\tconst first = edges[i];\n\t\tconst startVertex = first.start;\n\t\tlet currentVertex = first.end;\n\t\tlet currentDir = first.dir;\n\t\tconst loop: number[] = [first.start, first.end];\n\t\tused[i] = 1;\n\n\t\tlet guard = 0;\n\t\tconst guardLimit = edges.length * 3;\n\t\twhile (currentVertex !== startVertex && guard < guardLimit) {\n\t\t\tconst candidates = outgoing.get(currentVertex);\n\t\t\tif (!candidates || candidates.length === 0) break;\n\n\t\t\tlet bestIndex = -1;\n\t\t\tlet bestPriority = Infinity;\n\t\t\tfor (const edgeIndex of candidates) {\n\t\t\t\tif (used[edgeIndex]) continue;\n\t\t\t\tconst candidate = edges[edgeIndex];\n\t\t\t\tconst priority = turnPriority(currentDir, candidate.dir);\n\t\t\t\tif (priority < bestPriority) {\n\t\t\t\t\tbestPriority = priority;\n\t\t\t\t\tbestIndex = edgeIndex;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (bestIndex < 0) break;\n\t\t\tused[bestIndex] = 1;\n\t\t\tconst next = edges[bestIndex];\n\t\t\tcurrentVertex = next.end;\n\t\t\tcurrentDir = next.dir;\n\t\t\tloop.push(currentVertex);\n\t\t\tguard += 1;\n\t\t}\n\n\t\tif (\n\t\t\tloop.length >= 4 &&\n\t\t\tloop[0] === loop[loop.length - 1]\n\t\t) {\n\t\t\tloops.push(loop);\n\t\t}\n\t}\n\n\treturn loops;\n}\n\nfunction toWorldRing(\n\tvertexLoop: number[],\n\twidth: number,\n\tconfig: RasterConfig,\n): BrushStrokeCoordinate[] {\n\tconst stride = width + 1;\n\tconst ring: BrushStrokeCoordinate[] = [];\n\tfor (const id of vertexLoop) {\n\t\tconst x = id % stride;\n\t\tconst y = Math.floor(id / stride);\n\t\tring.push([\n\t\t\tconfig.minX + (x - config.padding) * config.step,\n\t\t\tconfig.minY + (y - config.padding) * config.step,\n\t\t]);\n\t}\n\treturn closeRing(ring);\n}\n\nfunction polygonSignedArea(ring: BrushStrokeCoordinate[]): number {\n\tif (ring.length < 4) return 0;\n\tlet sum = 0;\n\tfor (let i = 0; i < ring.length - 1; i += 1) {\n\t\tconst a = ring[i];\n\t\tconst b = ring[i + 1];\n\t\tsum += a[0] * b[1] - b[0] * a[1];\n\t}\n\treturn sum * 0.5;\n}\n\nfunction removeCollinearVertices(\n\tring: BrushStrokeCoordinate[],\n\tepsilon = 1e-9,\n): BrushStrokeCoordinate[] {\n\tconst closed = closeRing(ring);\n\tif (closed.length < 5) return closed;\n\tconst out: BrushStrokeCoordinate[] = [closed[0]];\n\tfor (let i = 1; i < closed.length - 1; i += 1) {\n\t\tconst prev = out[out.length - 1];\n\t\tconst curr = closed[i];\n\t\tconst next = closed[i + 1];\n\t\tconst cross =\n\t\t\t(curr[0] - prev[0]) * (next[1] - curr[1]) -\n\t\t\t(curr[1] - prev[1]) * (next[0] - curr[0]);\n\t\tif (Math.abs(cross) <= epsilon) continue;\n\t\tout.push(curr);\n\t}\n\tout.push(out[0]);\n\treturn closeRing(out);\n}\n\nfunction pointLineDistanceSquared(\n\tp: BrushStrokeCoordinate,\n\ta: BrushStrokeCoordinate,\n\tb: BrushStrokeCoordinate,\n): number {\n\tconst abx = b[0] - a[0];\n\tconst aby = b[1] - a[1];\n\tconst len2 = abx * abx + aby * aby;\n\tif (len2 <= 1e-12) {\n\t\tconst dx = p[0] - a[0];\n\t\tconst dy = p[1] - a[1];\n\t\treturn dx * dx + dy * dy;\n\t}\n\tconst t = clamp(\n\t\t((p[0] - a[0]) * abx + (p[1] - a[1]) * aby) / len2,\n\t\t0,\n\t\t1,\n\t);\n\tconst x = a[0] + abx * t;\n\tconst y = a[1] + aby * t;\n\tconst dx = p[0] - x;\n\tconst dy = p[1] - y;\n\treturn dx * dx + dy * dy;\n}\n\nfunction simplifyRdp(\n\tpoints: BrushStrokeCoordinate[],\n\ttolerance: number,\n): BrushStrokeCoordinate[] {\n\tif (points.length <= 2 || tolerance <= 0) return points.slice();\n\n\tconst keep = new Uint8Array(points.length);\n\tkeep[0] = 1;\n\tkeep[points.length - 1] = 1;\n\tconst tolerance2 = tolerance * tolerance;\n\tconst stack: Array<[number, number]> = [[0, points.length - 1]];\n\n\twhile (stack.length > 0) {\n\t\tconst next = stack.pop();\n\t\tif (!next) break;\n\t\tconst [start, end] = next;\n\t\tif (end - start <= 1) continue;\n\n\t\tlet maxDist2 = 0;\n\t\tlet split = -1;\n\t\tfor (let i = start + 1; i < end; i += 1) {\n\t\t\tconst dist2 = pointLineDistanceSquared(points[i], points[start], points[end]);\n\t\t\tif (dist2 > maxDist2) {\n\t\t\t\tmaxDist2 = dist2;\n\t\t\t\tsplit = i;\n\t\t\t}\n\t\t}\n\n\t\tif (split >= 0 && maxDist2 > tolerance2) {\n\t\t\tkeep[split] = 1;\n\t\t\tstack.push([start, split], [split, end]);\n\t\t}\n\t}\n\n\tconst out: BrushStrokeCoordinate[] = [];\n\tfor (let i = 0; i < points.length; i += 1) {\n\t\tif (keep[i]) out.push(points[i]);\n\t}\n\treturn out;\n}\n\nfunction simplifyClosedRing(\n\tring: BrushStrokeCoordinate[],\n\ttolerance: number,\n): BrushStrokeCoordinate[] {\n\tconst closed = closeRing(ring);\n\tif (closed.length < 5 || tolerance <= 0) return closed;\n\tconst open = closed.slice(0, -1);\n\tconst simplified = simplifyRdp(open, tolerance);\n\tif (simplified.length < 3) return closed;\n\treturn closeRing(simplified);\n}\n\nfunction clampRingToBounds(\n\tring: BrushStrokeCoordinate[],\n\tbounds: BrushStrokeBounds | undefined,\n): BrushStrokeCoordinate[] {\n\tif (!bounds) return ring;\n\treturn closeRing(\n\t\tring.map(([x, y]) => [\n\t\t\tclamp(x, bounds[0], bounds[2]),\n\t\t\tclamp(y, bounds[1], bounds[3]),\n\t\t] as BrushStrokeCoordinate),\n\t);\n}\n\nexport function buildBrushStrokePolygon(\n\tpath: BrushStrokeCoordinate[],\n\toptions: BrushStrokePolygonOptions,\n): BrushStrokeCoordinate[] {\n\tconst points = sanitizePath(path);\n\tconst radius = Math.max(MIN_RADIUS, Number(options.radius) || 0);\n\tif (points.length === 0 || !Number.isFinite(radius)) return [];\n\n\tconst circleSides = Math.max(12, Math.floor(options.circleSides || DEFAULT_CIRCLE_SIDES));\n\tif (points.length === 1) {\n\t\treturn clampRingToBounds(\n\t\t\tcreateCirclePolygon(points[0], radius, circleSides),\n\t\t\toptions.clipBounds,\n\t\t);\n\t}\n\n\tconst bounds = computeExpandedBounds(points, radius);\n\tconst raster = resolveRasterConfig(bounds, radius, options);\n\tconst mask = rasterizeStrokeMask(points, radius, raster);\n\tif (!mask.length) {\n\t\treturn clampRingToBounds(createBoundsFallback(points, radius), options.clipBounds);\n\t}\n\n\tconst edges = buildBoundaryEdges(mask, raster.width, raster.height);\n\tconst loops = traceLoops(edges);\n\tif (!loops.length) {\n\t\treturn clampRingToBounds(createBoundsFallback(points, radius), options.clipBounds);\n\t}\n\n\tlet bestRing: BrushStrokeCoordinate[] = [];\n\tlet bestArea = 0;\n\tfor (const loop of loops) {\n\t\tconst ring = toWorldRing(loop, raster.width, raster);\n\t\tconst area = Math.abs(polygonSignedArea(ring));\n\t\tif (area <= bestArea) continue;\n\t\tbestArea = area;\n\t\tbestRing = ring;\n\t}\n\n\tif (!bestRing.length) {\n\t\treturn clampRingToBounds(createBoundsFallback(points, radius), options.clipBounds);\n\t}\n\n\tconst tolerance =\n\t\ttypeof options.simplifyTolerance === \"number\" && Number.isFinite(options.simplifyTolerance)\n\t\t\t? Math.max(0, options.simplifyTolerance)\n\t\t\t: raster.step * 0.2;\n\tconst simplified = simplifyClosedRing(\n\t\tremoveCollinearVertices(bestRing, raster.step * 1e-3),\n\t\ttolerance,\n\t);\n\treturn clampRingToBounds(simplified, options.clipBounds);\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 { buildBrushStrokePolygon } from \"../wsi/brush-stroke\";\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\" | \"brush\" | StampDrawTool;\n\nexport type DrawCoordinate = [number, number];\n\nexport type DrawBounds = [number, number, number, number];\n\nexport type DrawIntent = \"roi\" | \"patch\" | \"brush\";\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 type DrawOverlayCoordinates = DrawCoordinate[] | DrawCoordinate[][] | DrawCoordinate[][][];\n\nexport interface DrawOverlayShape {\n id?: string | number;\n coordinates: DrawOverlayCoordinates;\n closed?: boolean;\n fill?: boolean;\n stroke?: Partial<RegionStrokeStyle>;\n strokeStyle?: Partial<RegionStrokeStyle>;\n invertedFill?: DrawOverlayInvertedFillStyle;\n visible?: boolean;\n}\n\nexport interface DrawOverlayInvertedFillStyle {\n fillColor: string;\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 zoomBy?: (factor: number, screenX: number, screenY: number) => void;\n}\n\nexport interface StampOptions {\n rectangleAreaMm2?: number;\n circleAreaMm2?: number;\n rectanglePixelSize?: number;\n}\n\nexport interface BrushOptions {\n radius: number;\n /**\n * Brush edge detail factor. Higher values create rounder/finer edges.\n * Range: 0.25 ~ 4. Default: 1.\n */\n edgeDetail?: number;\n /**\n * When true, a brush \"tap\" (click without drag) on ROI selects that ROI\n * instead of creating a brush stroke.\n */\n clickSelectRoi?: boolean;\n fillColor?: string;\n fillOpacity?: number;\n cursorColor?: string;\n cursorActiveColor?: string;\n cursorLineWidth?: number;\n cursorLineDash?: 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 brushOptions?: BrushOptions;\n projectorRef: RefObject<DrawProjector | null>;\n onBrushTap?: (coordinate: DrawCoordinate) => boolean;\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 cursor: DrawCoordinate | null;\n points: DrawCoordinate[];\n stampCenter: DrawCoordinate | null;\n}\n\ninterface ResolvedBrushOptions {\n radius: number;\n edgeDetail: number;\n clickSelectRoi: boolean;\n fillColor: string;\n fillOpacity: number;\n cursorColor: string;\n cursorActiveColor: string;\n cursorLineWidth: number;\n cursorLineDash: number[];\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;\nconst WHEEL_ZOOM_IN_FACTOR = 1.12;\nconst WHEEL_ZOOM_OUT_FACTOR = 0.89;\nconst DEFAULT_BRUSH_RADIUS = 32;\nconst DEFAULT_BRUSH_FILL_COLOR = \"#000000\";\nconst DEFAULT_BRUSH_FILL_OPACITY = 0.1;\nconst DEFAULT_BRUSH_CURSOR_COLOR = \"#FFCF00\";\nconst DEFAULT_BRUSH_CURSOR_ACTIVE_COLOR = \"#FF0000\";\nconst DEFAULT_BRUSH_CURSOR_LINE_WIDTH = 1.5;\nconst DEFAULT_BRUSH_CURSOR_DASH = [2, 2];\nconst DEFAULT_BRUSH_EDGE_DETAIL = 1;\nconst MIN_BRUSH_EDGE_DETAIL = 0.25;\nconst MAX_BRUSH_EDGE_DETAIL = 4;\nconst BRUSH_SCREEN_STEP = 1.5;\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 clampUnitOpacity(value: number | undefined, fallback: number): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return fallback;\n return clamp(value, 0, 1);\n}\n\nfunction sanitizeBrushLineDash(value: number[] | undefined): number[] {\n if (!Array.isArray(value)) return DEFAULT_BRUSH_CURSOR_DASH;\n const out = value.filter(item => Number.isFinite(item) && item >= 0);\n return out.length > 0 ? out : DEFAULT_BRUSH_CURSOR_DASH;\n}\n\nfunction resolveBrushEdgeDetail(value: number | undefined): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return DEFAULT_BRUSH_EDGE_DETAIL;\n return clamp(value, MIN_BRUSH_EDGE_DETAIL, MAX_BRUSH_EDGE_DETAIL);\n}\n\nfunction resolveBrushOptions(options: BrushOptions | undefined): ResolvedBrushOptions {\n const radius = clampPositiveOrFallback(options?.radius, DEFAULT_BRUSH_RADIUS);\n const cursorLineWidth = clampPositiveOrFallback(options?.cursorLineWidth, DEFAULT_BRUSH_CURSOR_LINE_WIDTH);\n const edgeDetail = resolveBrushEdgeDetail(options?.edgeDetail);\n return {\n radius,\n edgeDetail,\n clickSelectRoi: options?.clickSelectRoi === true,\n fillColor: options?.fillColor || DEFAULT_BRUSH_FILL_COLOR,\n fillOpacity: clampUnitOpacity(options?.fillOpacity, DEFAULT_BRUSH_FILL_OPACITY),\n cursorColor: options?.cursorColor || DEFAULT_BRUSH_CURSOR_COLOR,\n cursorActiveColor: options?.cursorActiveColor || DEFAULT_BRUSH_CURSOR_ACTIVE_COLOR,\n cursorLineWidth,\n cursorLineDash: sanitizeBrushLineDash(options?.cursorLineDash),\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 tracePath(ctx: CanvasRenderingContext2D, points: DrawCoordinate[], close = false): void {\n if (points.length === 0) return;\n\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}\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 tracePath(ctx, points, close);\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 isNestedRingCoordinates(coordinates: DrawOverlayCoordinates): boolean {\n const first = coordinates[0];\n return Array.isArray(first) && Array.isArray(first[0]);\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value);\n}\n\nfunction isCoordinatePair(value: unknown): value is [number, number] {\n return Array.isArray(value) && value.length >= 2 && isFiniteNumber(value[0]) && isFiniteNumber(value[1]);\n}\n\nfunction isCoordinateRing(value: unknown): value is DrawCoordinate[] {\n return Array.isArray(value) && value.length >= 2 && value.every(point => isCoordinatePair(point));\n}\n\nfunction collectOverlayRings(value: unknown, out: DrawCoordinate[][]): void {\n if (!Array.isArray(value) || value.length === 0) return;\n if (isCoordinateRing(value)) {\n out.push(value.map(([x, y]) => [x, y] as DrawCoordinate));\n return;\n }\n for (const item of value) {\n collectOverlayRings(item, out);\n }\n}\n\nfunction normalizeOverlayRings(coordinates: DrawOverlayCoordinates, close: boolean): DrawCoordinate[][] {\n const sourceRings: DrawCoordinate[][] = [];\n collectOverlayRings(coordinates, sourceRings);\n const out: DrawCoordinate[][] = [];\n for (const ring of sourceRings) {\n if (ring.length < 2) continue;\n const normalized = close ? closeRing(ring) : ring;\n if (normalized.length >= (close ? 4 : 2)) {\n out.push(normalized);\n }\n }\n return out;\n}\n\nfunction drawInvertedFillMask(ctx: CanvasRenderingContext2D, outerRing: DrawCoordinate[], holeRings: DrawCoordinate[][], fillColor: string): void {\n if (outerRing.length < 4 || holeRings.length === 0) return;\n ctx.save();\n ctx.beginPath();\n tracePath(ctx, outerRing, true);\n for (const ring of holeRings) {\n if (ring.length < 4) continue;\n tracePath(ctx, ring, true);\n }\n ctx.fillStyle = fillColor;\n ctx.fill(\"evenodd\");\n ctx.restore();\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 brushOptions,\n projectorRef,\n onBrushTap,\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 overlayDebugSnapshotRef = useRef<Map<string, string>>(new Map());\n const lastToolRef = useRef<DrawTool>(tool);\n const sessionRef = useRef<DrawSession>({\n isDrawing: false,\n pointerId: null,\n start: null,\n current: null,\n cursor: 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 const resolvedBrushOptions = useMemo(() => resolveBrushOptions(brushOptions), [brushOptions]);\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 ? (tool === \"brush\" ? \"none\" : \"crosshair\") : \"default\",\n ...style,\n }),\n [active, tool, 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 worldRadiusToScreenPixels = useCallback(\n (center: DrawCoordinate, worldRadius: number): number => {\n if (!Number.isFinite(worldRadius) || worldRadius <= 0) return 0;\n const projector = projectorRef.current;\n if (!projector) return 0;\n const a = toCoord(projector.worldToScreen(center[0], center[1]));\n const b = toCoord(projector.worldToScreen(center[0] + worldRadius, center[1]));\n if (!a || !b) return 0;\n return Math.hypot(b[0] - a[0], b[1] - a[1]);\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 (tool === \"brush\") {\n return [];\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 drawBrushStrokePreview = useCallback(\n (ctx: CanvasRenderingContext2D): void => {\n const session = sessionRef.current;\n if (!session.isDrawing || session.points.length === 0) return;\n\n const screenPoints = worldToScreenPoints(session.points);\n if (screenPoints.length === 0) return;\n const anchor = session.points[session.points.length - 1] ?? session.points[0];\n const radiusPx = worldRadiusToScreenPixels(anchor, resolvedBrushOptions.radius);\n if (!Number.isFinite(radiusPx) || radiusPx <= 0) return;\n\n ctx.save();\n ctx.globalAlpha = resolvedBrushOptions.fillOpacity;\n ctx.fillStyle = resolvedBrushOptions.fillColor;\n ctx.strokeStyle = resolvedBrushOptions.fillColor;\n ctx.lineCap = \"round\";\n ctx.lineJoin = \"round\";\n ctx.lineWidth = radiusPx * 2;\n if (screenPoints.length === 1) {\n ctx.beginPath();\n ctx.arc(screenPoints[0][0], screenPoints[0][1], radiusPx, 0, Math.PI * 2);\n ctx.fill();\n } else {\n ctx.beginPath();\n ctx.moveTo(screenPoints[0][0], screenPoints[0][1]);\n for (let i = 1; i < screenPoints.length; i += 1) {\n ctx.lineTo(screenPoints[i][0], screenPoints[i][1]);\n }\n ctx.stroke();\n }\n ctx.restore();\n },\n [worldToScreenPoints, worldRadiusToScreenPixels, resolvedBrushOptions]\n );\n\n const drawBrushCursor = useCallback(\n (ctx: CanvasRenderingContext2D): void => {\n const session = sessionRef.current;\n const cursor = session.cursor;\n if (!cursor) return;\n const screen = toCoord(projectorRef.current?.worldToScreen(cursor[0], cursor[1]) ?? []);\n if (!screen) return;\n const radiusPx = worldRadiusToScreenPixels(cursor, resolvedBrushOptions.radius);\n if (!Number.isFinite(radiusPx) || radiusPx <= 0) return;\n\n ctx.save();\n ctx.beginPath();\n ctx.arc(screen[0], screen[1], radiusPx, 0, Math.PI * 2);\n ctx.strokeStyle = session.isDrawing ? resolvedBrushOptions.cursorActiveColor : resolvedBrushOptions.cursorColor;\n ctx.lineWidth = resolvedBrushOptions.cursorLineWidth;\n ctx.setLineDash(resolvedBrushOptions.cursorLineDash);\n ctx.stroke();\n ctx.setLineDash(EMPTY_DASH);\n ctx.restore();\n },\n [projectorRef, worldRadiusToScreenPixels, resolvedBrushOptions]\n );\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 const debugOverlay = Boolean((globalThis as { __OPEN_PLANT_DEBUG_OVERLAY__?: boolean }).__OPEN_PLANT_DEBUG_OVERLAY__);\n const imageOuterRing = worldToScreenPoints(\n closeRing([\n [0, 0],\n [imageWidth, 0],\n [imageWidth, imageHeight],\n [0, imageHeight],\n ])\n );\n for (let i = 0; i < overlayShapes.length; i += 1) {\n const shape = overlayShapes[i];\n if (!shape?.coordinates?.length || shape.visible === false) continue;\n\n const closed = shape.closed ?? isNestedRingCoordinates(shape.coordinates);\n const renderRings = normalizeOverlayRings(shape.coordinates, closed);\n\n if (shape.invertedFill?.fillColor) {\n const holeRings: DrawCoordinate[][] = [];\n const closedRings = normalizeOverlayRings(shape.coordinates, true);\n for (const ring of closedRings) {\n const screen = worldToScreenPoints(ring);\n if (screen.length >= 4) {\n holeRings.push(screen);\n }\n }\n if (debugOverlay) {\n const debugKey = String(shape.id ?? i);\n const debugSignature = `${imageOuterRing.length}|${closedRings.length}|${holeRings.length}|${shape.invertedFill.fillColor}`;\n if (overlayDebugSnapshotRef.current.get(debugKey) !== debugSignature) {\n overlayDebugSnapshotRef.current.set(debugKey, debugSignature);\n console.debug(\"[open-plant] invertedFill\", {\n id: shape.id ?? i,\n outerRingPoints: imageOuterRing.length,\n sourceRingCount: closedRings.length,\n holeRingCount: holeRings.length,\n fillColor: shape.invertedFill.fillColor,\n });\n }\n }\n drawInvertedFillMask(ctx, imageOuterRing, holeRings, shape.invertedFill.fillColor);\n }\n\n if (renderRings.length === 0) continue;\n const strokeStyle = mergeStrokeStyle(resolvedStrokeStyle, shape.stroke ?? shape.strokeStyle);\n for (const ring of renderRings) {\n const screen = worldToScreenPoints(ring);\n if (screen.length < 2) continue;\n drawPath(ctx, screen, strokeStyle, closed, shape.fill ?? false);\n }\n }\n }\n\n if (active) {\n if (tool === \"brush\") {\n drawBrushStrokePreview(ctx);\n drawBrushCursor(ctx);\n } else {\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\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 drawBrushStrokePreview,\n drawBrushCursor,\n resizeCanvas,\n worldToScreenPoints,\n imageWidth,\n imageHeight,\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((preserveCursor = false) => {\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 if (!preserveCursor) {\n session.cursor = null;\n }\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(true);\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 } else if (tool === \"brush\") {\n const tapPoint = session.points[session.points.length - 1] ?? session.current ?? session.start;\n if (resolvedBrushOptions.clickSelectRoi && tapPoint && session.points.length <= 1 && onBrushTap?.(tapPoint)) {\n resetSession(true);\n requestDraw();\n return;\n }\n const zoom = Math.max(1e-6, projectorRef.current?.getViewState?.().zoom ?? 1);\n const edgeDetail = resolvedBrushOptions.edgeDetail;\n const minRasterStep = 0.75 / (zoom * edgeDetail);\n coordinates = buildBrushStrokePolygon(session.points, {\n radius: resolvedBrushOptions.radius,\n clipBounds: [0, 0, imageWidth, imageHeight],\n minRasterStep,\n circleSides: Math.max(24, Math.round(64 * edgeDetail)),\n simplifyTolerance: minRasterStep * 0.4,\n }) as DrawCoordinate[];\n }\n\n if ((tool === \"freehand\" || tool === \"rectangle\" || tool === \"circular\" || tool === \"brush\") && isValidPolygon(coordinates) && onDrawComplete) {\n const intent: DrawIntent = tool === \"brush\" ? \"brush\" : \"roi\";\n onDrawComplete({\n tool,\n intent,\n coordinates,\n bbox: computeBounds(coordinates),\n areaPx: polygonArea(coordinates),\n });\n }\n\n resetSession(true);\n requestDraw();\n }, [tool, onDrawComplete, resetSession, requestDraw, resolvedBrushOptions.radius, resolvedBrushOptions.edgeDetail, resolvedBrushOptions.clickSelectRoi, imageWidth, imageHeight, projectorRef, onBrushTap]);\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 appendBrushPoint = useCallback(\n (session: DrawSession, world: DrawCoordinate): void => {\n const projector = projectorRef.current;\n const zoom = Math.max(1e-6, projector?.getViewState?.().zoom ?? 1);\n const minWorldStep = BRUSH_SCREEN_STEP / zoom;\n const minWorldStep2 = minWorldStep * minWorldStep;\n const prev = session.points[session.points.length - 1];\n if (!prev) {\n session.points.push(world);\n session.current = world;\n return;\n }\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 } else {\n session.points[session.points.length - 1] = world;\n }\n session.current = world;\n },\n [projectorRef]\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.cursor = world;\n session.points = tool === \"freehand\" || tool === \"brush\" ? [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 (tool === \"brush\") {\n session.cursor = world;\n if (!session.isDrawing || session.pointerId !== event.pointerId) {\n requestDraw();\n return;\n }\n event.preventDefault();\n event.stopPropagation();\n appendBrushPoint(session, world);\n requestDraw();\n return;\n }\n\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, appendBrushPoint]\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 world = toWorld(event);\n if (world) {\n session.cursor = world;\n if (tool === \"brush\") {\n appendBrushPoint(session, world);\n } else {\n session.current = world;\n }\n }\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, toWorld, tool, appendBrushPoint]\n );\n\n const handlePointerLeave = useCallback(() => {\n const session = sessionRef.current;\n let changed = false;\n if (tool === \"brush\" && !session.isDrawing && session.cursor) {\n session.cursor = null;\n changed = true;\n }\n if (isStampTool(tool) && session.stampCenter) {\n session.stampCenter = null;\n changed = true;\n }\n if (changed) {\n requestDraw();\n }\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) return;\n const canvas = canvasRef.current;\n const projector = projectorRef.current;\n if (!canvas || typeof projector?.zoomBy !== \"function\") return;\n event.preventDefault();\n event.stopPropagation();\n const rect = canvas.getBoundingClientRect();\n const screenX = event.clientX - rect.left;\n const screenY = event.clientY - rect.top;\n projector.zoomBy(event.deltaY < 0 ? WHEEL_ZOOM_IN_FACTOR : WHEEL_ZOOM_OUT_FACTOR, screenX, screenY);\n requestDraw();\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\tconst pointIds =\n\t\tpointData.ids instanceof Uint32Array && pointData.ids.length >= count\n\t\t\t? pointData.ids\n\t\t\t: null;\n\n\tconst nextPositions = new Float32Array(count * 2);\n\tconst nextTerms = new Uint16Array(count);\n\tconst nextIds = pointIds ? new Uint32Array(count) : null;\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\tif (nextIds) {\n\t\t\tnextIds[cursor] = pointIds![i];\n\t\t}\n\t\tcursor += 1;\n\t}\n\n\tconst output: WsiPointData = {\n\t\tcount: cursor,\n\t\tpositions: nextPositions.subarray(0, cursor * 2),\n\t\tpaletteIndices: nextTerms.subarray(0, cursor),\n\t};\n\tif (nextIds) {\n\t\toutput.ids = nextIds.subarray(0, cursor);\n\t}\n\treturn output;\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 const pointIds = pointData.ids instanceof Uint32Array && pointData.ids.length >= safeCount ? pointData.ids : null;\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 const data: WsiPointData = {\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 if (pointIds) {\n data.ids = pointIds.subarray(0, safeCount);\n }\n return {\n data,\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 ...(pointIds ? { ids: new Uint32Array(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 const data: WsiPointData = {\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 if (pointIds) {\n data.ids = pointIds.subarray(0, safeCount);\n }\n\n return {\n data,\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 const nextIds = pointIds ? new Uint32Array(candidateCount) : null;\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 if (nextIds) {\n nextIds[cursor] = pointIds![pointIndex];\n }\n cursor += 1;\n }\n\n const compactData: WsiPointData = {\n count: cursor,\n positions: nextPositions.subarray(0, cursor * 2),\n paletteIndices: nextTerms.subarray(0, cursor),\n };\n if (nextIds) {\n compactData.ids = nextIds.subarray(0, cursor);\n }\n\n return {\n data: compactData,\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 ids = msg.ids ? new Uint32Array(msg.ids) : null;\n const output: WsiPointData = {\n count,\n positions: positions.subarray(0, count * 2),\n paletteIndices: paletteIndices.subarray(0, count),\n };\n if (ids) {\n output.ids = ids.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 idsCopy = pointData.ids instanceof Uint32Array && pointData.ids.length >= safeCount ? pointData.ids.slice(0, safeCount) : null;\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 ids: idsCopy?.buffer,\n polygons: polygons ?? [],\n };\n const transfer: Transferable[] = [positionsCopy.buffer, termsCopy.buffer];\n if (idsCopy) {\n transfer.push(idsCopy.buffer);\n }\n worker.postMessage(msg, transfer);\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;\nconst MIN_POINT_SIZE_PX = 0.5;\nconst MAX_POINT_SIZE_PX = 256;\n\ninterface PointSizeStop {\n\tzoom: number;\n\tsize: number;\n}\n\nconst DEFAULT_POINT_SIZE_STOPS: readonly PointSizeStop[] = [\n\t{ zoom: 1, size: 2.8 },\n\t{ zoom: 2, size: 3.4 },\n\t{ zoom: 3, size: 4.2 },\n\t{ zoom: 4, size: 5.3 },\n\t{ zoom: 5, size: 6.8 },\n\t{ zoom: 6, size: 8.4 },\n\t{ zoom: 7, size: 9.8 },\n\t{ zoom: 8, size: 11.2 },\n\t{ zoom: 9, size: 14.0 },\n\t{ zoom: 10, size: 17.5 },\n\t{ zoom: 11, size: 22.0 },\n\t{ zoom: 12, size: 28.0 },\n];\n\nexport type PointSizeByZoom = Readonly<Record<number, number>>;\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\tpointSizeByZoom?: PointSizeByZoom;\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\nfunction clonePointSizeStops(stops: readonly PointSizeStop[]): PointSizeStop[] {\n\treturn stops.map(stop => ({ zoom: stop.zoom, size: stop.size }));\n}\n\nfunction normalizePointSizeStops(pointSizeByZoom: PointSizeByZoom | null | undefined): PointSizeStop[] {\n\tif (!pointSizeByZoom) return clonePointSizeStops(DEFAULT_POINT_SIZE_STOPS);\n\n\tconst parsed = new Map<number, number>();\n\tfor (const [zoomKey, rawSize] of Object.entries(pointSizeByZoom)) {\n\t\tconst zoom = Number(zoomKey);\n\t\tconst size = Number(rawSize);\n\t\tif (!Number.isFinite(zoom) || !Number.isFinite(size) || size <= 0) continue;\n\t\tparsed.set(zoom, size);\n\t}\n\n\tif (parsed.size === 0) {\n\t\treturn clonePointSizeStops(DEFAULT_POINT_SIZE_STOPS);\n\t}\n\n\treturn Array.from(parsed.entries())\n\t\t.sort((a, b) => a[0] - b[0])\n\t\t.map(([zoom, size]) => ({ zoom, size }));\n}\n\nfunction arePointSizeStopsEqual(a: readonly PointSizeStop[], b: readonly PointSizeStop[]): boolean {\n\tif (a === b) return true;\n\tif (a.length !== b.length) return false;\n\tfor (let i = 0; i < a.length; i += 1) {\n\t\tif (a[i].zoom !== b[i].zoom || a[i].size !== b[i].size) {\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n\nfunction resolvePointSizeByZoomStops(continuousZoom: number, stops: readonly PointSizeStop[]): number {\n\tif (!Number.isFinite(continuousZoom)) return stops[0]?.size ?? MIN_POINT_SIZE_PX;\n\tif (stops.length === 0) return MIN_POINT_SIZE_PX;\n\tif (stops.length === 1) return stops[0].size;\n\tif (continuousZoom <= stops[0].zoom) return stops[0].size;\n\n\tfor (let i = 1; i < stops.length; i += 1) {\n\t\tconst prev = stops[i - 1];\n\t\tconst next = stops[i];\n\t\tif (continuousZoom > next.zoom) continue;\n\t\tconst span = Math.max(1e-6, next.zoom - prev.zoom);\n\t\tconst t = clamp((continuousZoom - prev.zoom) / span, 0, 1);\n\t\treturn prev.size + (next.size - prev.size) * t;\n\t}\n\n\tconst last = stops[stops.length - 1];\n\tconst prev = stops[stops.length - 2];\n\tconst span = Math.max(1e-6, last.zoom - prev.zoom);\n\tconst slope = (last.size - prev.size) / span;\n\treturn last.size + (continuousZoom - last.zoom) * slope;\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 pointSizeStops: PointSizeStop[] = clonePointSizeStops(DEFAULT_POINT_SIZE_STOPS);\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\t\tthis.pointSizeStops = normalizePointSizeStops(options.pointSizeByZoom);\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\tsetPointSizeByZoom(pointSizeByZoom: PointSizeByZoom | null | undefined): void {\n\t\tconst nextStops = normalizePointSizeStops(pointSizeByZoom);\n\t\tif (arePointSizeStopsEqual(this.pointSizeStops, nextStops)) return;\n\t\tthis.pointSizeStops = nextStops;\n\t\tthis.requestRender();\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 size = resolvePointSizeByZoomStops(continuousZoom, this.pointSizeStops);\n\t\treturn clamp(size, MIN_POINT_SIZE_PX, MAX_POINT_SIZE_PX);\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 MutableRefObject, 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 PointSizeByZoom, type WsiTileErrorEvent, WsiTileRenderer } from \"../wsi/wsi-tile-renderer\";\nimport type { BrushOptions, 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};\nconst POINT_HIT_RADIUS_SCALE = 0.65;\nconst MIN_POINT_HIT_RADIUS_PX = 4;\nconst MIN_POINT_HIT_GRID_SIZE = 24;\nconst MAX_POINT_HIT_GRID_SIZE = 1024;\nconst POINT_HIT_GRID_DENSITY_SCALE = 4;\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 PointHitEvent {\n index: number;\n id: number | null;\n coordinate: DrawCoordinate;\n pointCoordinate: DrawCoordinate;\n}\n\nexport interface PointClickEvent extends PointHitEvent {\n button: number;\n}\n\nexport interface PointHoverEvent {\n index: number | null;\n id: number | null;\n coordinate: DrawCoordinate | null;\n pointCoordinate: DrawCoordinate | null;\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\ninterface PointSpatialIndex {\n cellSize: number;\n safeCount: number;\n positions: Float32Array;\n ids: Uint32Array | null;\n buckets: Map<number, Map<number, number[]>>;\n}\n\nfunction sanitizePointCount(pointData: WsiPointData): number {\n return Math.max(0, Math.min(Math.floor(pointData.count ?? 0), Math.floor((pointData.positions?.length ?? 0) / 2), pointData.paletteIndices?.length ?? 0));\n}\n\nfunction sanitizeDrawIndices(drawIndices: Uint32Array | undefined, maxExclusive: number): Uint32Array | null {\n if (!(drawIndices instanceof Uint32Array) || maxExclusive <= 0 || drawIndices.length === 0) {\n return null;\n }\n\n let invalidFound = false;\n for (let i = 0; i < drawIndices.length; i += 1) {\n if (drawIndices[i] < maxExclusive) continue;\n invalidFound = true;\n break;\n }\n if (!invalidFound) {\n return drawIndices;\n }\n\n const out = new Uint32Array(drawIndices.length);\n let cursor = 0;\n for (let i = 0; i < drawIndices.length; i += 1) {\n const idx = drawIndices[i];\n if (idx >= maxExclusive) continue;\n out[cursor] = idx;\n cursor += 1;\n }\n return out.subarray(0, cursor);\n}\n\nfunction resolvePointHitGridSize(source: WsiImageSource | null, visibleCount: number): number {\n if (!source || visibleCount <= 0) return 256;\n const area = Math.max(1, source.width * source.height);\n const avgSpacing = Math.sqrt(area / Math.max(1, visibleCount));\n const raw = avgSpacing * POINT_HIT_GRID_DENSITY_SCALE;\n return Math.max(MIN_POINT_HIT_GRID_SIZE, Math.min(MAX_POINT_HIT_GRID_SIZE, raw));\n}\n\nfunction buildPointSpatialIndex(pointData: WsiPointData | null | undefined, source: WsiImageSource | null): PointSpatialIndex | null {\n if (!pointData || !pointData.positions || !pointData.paletteIndices) {\n return null;\n }\n\n const safeCount = sanitizePointCount(pointData);\n if (safeCount <= 0) {\n return null;\n }\n\n const positions = pointData.positions.subarray(0, safeCount * 2);\n const ids = pointData.ids instanceof Uint32Array && pointData.ids.length >= safeCount ? pointData.ids.subarray(0, safeCount) : null;\n const drawIndices = sanitizeDrawIndices(pointData.drawIndices, safeCount);\n const visibleCount = drawIndices ? drawIndices.length : safeCount;\n if (visibleCount === 0) {\n return null;\n }\n\n const cellSize = resolvePointHitGridSize(source, visibleCount);\n const buckets = new Map<number, Map<number, number[]>>();\n\n const pushBucket = (pointIndex: number): void => {\n const px = positions[pointIndex * 2];\n const py = positions[pointIndex * 2 + 1];\n if (!Number.isFinite(px) || !Number.isFinite(py)) return;\n\n const cellX = Math.floor(px / cellSize);\n const cellY = Math.floor(py / cellSize);\n let column = buckets.get(cellX);\n if (!column) {\n column = new Map<number, number[]>();\n buckets.set(cellX, column);\n }\n const bucket = column.get(cellY);\n if (bucket) {\n bucket.push(pointIndex);\n } else {\n column.set(cellY, [pointIndex]);\n }\n };\n\n if (drawIndices) {\n for (let i = 0; i < drawIndices.length; i += 1) {\n pushBucket(drawIndices[i] ?? 0);\n }\n } else {\n for (let i = 0; i < safeCount; i += 1) {\n pushBucket(i);\n }\n }\n\n if (buckets.size === 0) {\n return null;\n }\n\n return {\n cellSize,\n safeCount,\n positions,\n ids,\n buckets,\n };\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 pointSizeByZoom?: PointSizeByZoom;\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 brushOptions?: BrushOptions;\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 onPointHover?: (event: PointHoverEvent) => void;\n onPointClick?: (event: PointClickEvent) => void;\n onRegionHover?: (event: RegionHoverEvent) => void;\n onRegionClick?: (event: RegionClickEvent) => void;\n onActiveRegionChange?: (regionId: string | number | null) => void;\n getCellByCoordinatesRef?: MutableRefObject<((coordinate: DrawCoordinate) => PointHitEvent | null) | null>;\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 pointSizeByZoom,\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 brushOptions,\n regionStrokeStyle,\n regionStrokeHoverStyle,\n regionStrokeActiveStyle,\n patchStrokeStyle,\n resolveRegionStrokeStyle,\n overlayShapes,\n customLayers,\n patchRegions,\n regionLabelStyle,\n onPointerWorldMove,\n onPointHover,\n onPointClick,\n onRegionHover,\n onRegionClick,\n onActiveRegionChange,\n getCellByCoordinatesRef,\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 hoveredPointIndexRef = useRef<number | null>(null);\n const hoveredPointIdRef = useRef<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 shouldEnablePointHitTest = Boolean(onPointHover || onPointClick || getCellByCoordinatesRef);\n const pointSpatialIndex = useMemo(() => {\n if (!shouldEnablePointHitTest) return null;\n return buildPointSpatialIndex(renderPointData, source);\n }, [shouldEnablePointHitTest, renderPointData, source]);\n\n const getCellByCoordinates = useCallback(\n (coordinate: DrawCoordinate): PointHitEvent | null => {\n const renderer = rendererRef.current;\n if (!renderer || !pointSpatialIndex) return null;\n\n const x = Number(coordinate[0]);\n const y = Number(coordinate[1]);\n if (!Number.isFinite(x) || !Number.isFinite(y)) return null;\n\n const zoom = Math.max(1e-6, renderer.getViewState().zoom);\n const pointSizePx = renderer.getPointSizeByZoom();\n const hitRadiusPx = Math.max(MIN_POINT_HIT_RADIUS_PX, pointSizePx * POINT_HIT_RADIUS_SCALE);\n const hitRadiusWorld = hitRadiusPx / zoom;\n if (!Number.isFinite(hitRadiusWorld) || hitRadiusWorld <= 0) return null;\n\n const cellSize = pointSpatialIndex.cellSize;\n const baseCellX = Math.floor(x / cellSize);\n const baseCellY = Math.floor(y / cellSize);\n const cellRadius = Math.max(1, Math.ceil(hitRadiusWorld / cellSize));\n const maxDist2 = hitRadiusWorld * hitRadiusWorld;\n\n let nearestIndex = -1;\n let nearestDist2 = maxDist2;\n let nearestX = 0;\n let nearestY = 0;\n\n for (let cx = baseCellX - cellRadius; cx <= baseCellX + cellRadius; cx += 1) {\n const column = pointSpatialIndex.buckets.get(cx);\n if (!column) continue;\n\n for (let cy = baseCellY - cellRadius; cy <= baseCellY + cellRadius; cy += 1) {\n const bucket = column.get(cy);\n if (!bucket || bucket.length === 0) continue;\n\n for (let i = 0; i < bucket.length; i += 1) {\n const pointIndex = bucket[i];\n if (pointIndex >= pointSpatialIndex.safeCount) continue;\n\n const px = pointSpatialIndex.positions[pointIndex * 2];\n const py = pointSpatialIndex.positions[pointIndex * 2 + 1];\n const dx = px - x;\n const dy = py - y;\n const dist2 = dx * dx + dy * dy;\n if (dist2 > nearestDist2) continue;\n\n nearestDist2 = dist2;\n nearestIndex = pointIndex;\n nearestX = px;\n nearestY = py;\n }\n }\n }\n\n if (nearestIndex < 0) return null;\n const pointId = pointSpatialIndex.ids ? Number(pointSpatialIndex.ids[nearestIndex]) : null;\n return {\n index: nearestIndex,\n id: pointId,\n coordinate: [x, y],\n pointCoordinate: [nearestX, nearestY],\n };\n },\n [pointSpatialIndex]\n );\n\n const emitPointHover = useCallback(\n (hit: PointHitEvent | null, coordinate: DrawCoordinate | null) => {\n if (!onPointHover) return;\n const nextIndex = hit?.index ?? null;\n const nextId = hit?.id ?? null;\n if (hoveredPointIndexRef.current === nextIndex && hoveredPointIdRef.current === nextId) return;\n hoveredPointIndexRef.current = nextIndex;\n hoveredPointIdRef.current = nextId;\n onPointHover({\n index: nextIndex,\n id: nextId,\n coordinate,\n pointCoordinate: hit?.pointCoordinate ?? null,\n });\n },\n [onPointHover]\n );\n\n const emitPointClick = useCallback(\n (coordinate: DrawCoordinate, button: number) => {\n if (!onPointClick) return;\n const hit = getCellByCoordinates(coordinate);\n if (!hit) return;\n onPointClick({\n ...hit,\n button,\n });\n },\n [onPointClick, getCellByCoordinates]\n );\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 useEffect(() => {\n if (!getCellByCoordinatesRef) return;\n getCellByCoordinatesRef.current = getCellByCoordinates;\n return () => {\n if (getCellByCoordinatesRef.current === getCellByCoordinates) {\n getCellByCoordinatesRef.current = null;\n }\n };\n }, [getCellByCoordinatesRef, getCellByCoordinates]);\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 useEffect(() => {\n const hoveredPointIndex = hoveredPointIndexRef.current;\n if (hoveredPointIndex === null) return;\n if (pointSpatialIndex && hoveredPointIndex < pointSpatialIndex.safeCount) return;\n hoveredPointIndexRef.current = null;\n hoveredPointIdRef.current = null;\n onPointHover?.({\n index: null,\n id: null,\n coordinate: null,\n pointCoordinate: null,\n });\n }, [pointSpatialIndex, onPointHover]);\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 useEffect(() => {\n if (drawTool === \"cursor\") return;\n if (hoveredPointIndexRef.current === null) return;\n hoveredPointIndexRef.current = null;\n hoveredPointIdRef.current = null;\n onPointHover?.({\n index: null,\n id: null,\n coordinate: null,\n pointCoordinate: null,\n });\n }, [drawTool, onPointHover]);\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 emitPointHover(null, null);\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) {\n emitPointHover(null, null);\n return;\n }\n\n if (onPointHover) {\n emitPointHover(getCellByCoordinates(coord), coord);\n }\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, emitPointHover, getCellByCoordinates, onPointHover]\n );\n\n const handleRegionPointerLeave = useCallback(() => {\n onPointerWorldMove?.({\n coordinate: null,\n clientX: -1,\n clientY: -1,\n insideImage: false,\n });\n emitPointHover(null, null);\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, emitPointHover]);\n\n const handleRegionClick = useCallback(\n (event: ReactMouseEvent<HTMLDivElement>) => {\n if (drawTool !== \"cursor\") return;\n if (event.target !== canvasRef.current) return;\n\n const coord = resolveWorldCoord(event.clientX, event.clientY);\n if (!coord) return;\n emitPointClick(coord, event.button);\n\n if (!effectiveRoiRegions.length) {\n commitActiveRegion(null);\n return;\n }\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, emitPointClick]\n );\n\n const handleBrushTap = useCallback(\n (coord: DrawCoordinate): boolean => {\n if (drawTool !== \"brush\") return false;\n if (brushOptions?.clickSelectRoi !== true) return false;\n if (!effectiveRoiRegions.length) return false;\n\n const hit = pickRegionAt(coord, effectiveRoiRegions);\n if (!hit) return false;\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 return true;\n },\n [drawTool, brushOptions?.clickSelectRoi, effectiveRoiRegions, activeRegionId, commitActiveRegion, onRegionClick]\n );\n\n const handleRegionContextMenu = useCallback(\n (event: ReactMouseEvent<HTMLDivElement>) => {\n if (!onPointClick) return;\n if (drawTool !== \"cursor\") return;\n if (event.target !== canvasRef.current) return;\n event.preventDefault();\n const coord = resolveWorldCoord(event.clientX, event.clientY);\n if (!coord) return;\n emitPointClick(coord, event.button);\n },\n [drawTool, resolveWorldCoord, emitPointClick, onPointClick]\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 pointSizeByZoom,\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, pointSizeByZoom, 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.setPointSizeByZoom(pointSizeByZoom);\n }, [pointSizeByZoom]);\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} onContextMenu={handleRegionContextMenu}>\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 brushOptions={brushOptions}\n projectorRef={rendererRef}\n onBrushTap={handleBrushTap}\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_MIN_RASTER_STEP","DEFAULT_MAX_RASTER_PIXELS","DEFAULT_MAX_RASTER_SIZE","DEFAULT_CIRCLE_SIDES","MIN_RADIUS","ALPHA_THRESHOLD","clamp","value","min","max","closeRing","coordinates","out","x","y","first","last","sanitizePath","points","point","prev","createCirclePolygon","center","radius","sides","ring","t","createBoundsFallback","minX","minY","maxX","maxY","pad","computeExpandedBounds","resolveRasterConfig","bounds","minRasterStep","maxRasterPixels","maxRasterSize","widthWorld","heightWorld","step","padding","createRasterContext","worldToRaster","config","rasterizeStrokeMask","path","p","i","image","buildBoundaryEdges","mask","edges","vertex","at","turnPriority","fromDir","toDir","delta","traceLoops","outgoing","entry","used","loops","startVertex","currentVertex","currentDir","loop","guard","guardLimit","candidates","bestIndex","bestPriority","edgeIndex","candidate","priority","toWorldRing","vertexLoop","id","polygonSignedArea","sum","a","b","removeCollinearVertices","epsilon","closed","curr","cross","pointLineDistanceSquared","abx","aby","len2","dx","dy","simplifyRdp","tolerance","keep","tolerance2","stack","start","end","maxDist2","split","dist2","simplifyClosedRing","open","simplified","clampRingToBounds","buildBrushStrokePolygon","circleSides","raster","bestRing","bestArea","area","DEFAULT_POINT_COLOR","calcScaleResolution","imageMpp","imageZoom","currentZoom","mpp","z0","z1","calcScaleLength","length","unit","isSameViewState","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","WHEEL_ZOOM_IN_FACTOR","WHEEL_ZOOM_OUT_FACTOR","DEFAULT_BRUSH_RADIUS","DEFAULT_BRUSH_FILL_COLOR","DEFAULT_BRUSH_FILL_OPACITY","DEFAULT_BRUSH_CURSOR_COLOR","DEFAULT_BRUSH_CURSOR_ACTIVE_COLOR","DEFAULT_BRUSH_CURSOR_LINE_WIDTH","DEFAULT_BRUSH_CURSOR_DASH","DEFAULT_BRUSH_EDGE_DETAIL","MIN_BRUSH_EDGE_DETAIL","MAX_BRUSH_EDGE_DETAIL","BRUSH_SCREEN_STEP","DEFAULT_REGION_STROKE_STYLE","DEFAULT_PATCH_STROKE_STYLE","DEFAULT_REGION_LABEL_STYLE","isStampTool","tool","clampPositiveOrFallback","fallback","resolveStampOptions","clampUnitOpacity","sanitizeBrushLineDash","item","resolveBrushEdgeDetail","resolveBrushOptions","cursorLineWidth","edgeDetail","mm2ToUm2","areaMm2","createSquareFromCenter","halfLength","createCircleFromCenter","coords","createRectangle","createCircle","centerX","centerY","polygonArea","computeBounds","isValidPolygon","tracePath","ctx","close","drawPath","strokeStyle","fill","resolveStrokeStyle","style","dash","shadowBlur","shadowOffsetX","shadowOffsetY","mergeStrokeStyle","base","override","isSameRegionId","isNestedRingCoordinates","isFiniteNumber","isCoordinatePair","isCoordinateRing","collectOverlayRings","normalizeOverlayRings","sourceRings","normalized","drawInvertedFillMask","outerRing","holeRings","fillColor","resolveLabelStyle","px","py","bw","oy","br","drawRoundedRect","r","getTopAnchor","drawRegionLabel","text","anchor","canvasWidth","canvasHeight","labelStyle","label","boxWidth","boxHeight","left","top","clampWorld","coord","imageWidth","imageHeight","toCoord","DrawLayer","stampOptions","brushOptions","projectorRef","onBrushTap","onDrawComplete","onPatchComplete","enabled","viewStateSignal","persistedRegions","patchRegions","persistedPolygons","regionStrokeStyle","regionStrokeHoverStyle","regionStrokeActiveStyle","patchStrokeStyle","resolveRegionStrokeStyle","overlayShapes","hoveredRegionId","activeRegionId","regionLabelStyle","invalidateRef","className","canvasRef","useRef","drawPendingRef","overlayDebugSnapshotRef","lastToolRef","sessionRef","active","mergedPersistedRegions","useMemo","index","mergedPatchRegions","resolvedStrokeStyle","resolvedHoverStrokeStyle","resolvedActiveStrokeStyle","resolvedPatchStrokeStyle","resolvedLabelStyle","resolvedStampOptions","resolvedBrushOptions","mergedStyle","resizeCanvas","useCallback","w","h","worldToScreenPoints","projector","worldRadiusToScreenPixels","worldRadius","micronsToWorldPixels","lengthUm","mppValue","imageZoomValue","viewZoomRaw","viewZoom","continuousZoom","umPerScreenPixel","buildStampCoords","stampTool","areaUm2","buildPreviewCoords","session","drawBrushStrokePreview","screenPoints","radiusPx","drawBrushCursor","cursor","screen","drawOverlay","region","regionKey","state","resolved","debugOverlay","imageOuterRing","shape","renderRings","closedRings","debugKey","debugSignature","preview","line","polygon","anchorWorld","anchorScreen","requestDraw","resetSession","preserveCursor","toWorld","event","raw","finishSession","tapPoint","handleStampAt","intent","result","appendBrushPoint","world","minWorldStep","minWorldStep2","handlePointerDown","handlePointerMove","handlePointerUp","handlePointerLeave","changed","useEffect","observer","onKeyDown","jsx","screenX","screenY","trimTrailingSlash","ensureLeadingSlash","joinImsTileRoot","tileBaseUrl","parsed","origin","normalizeImageInfo","ims","isIms","tileSize","maxTierZoom","tilePath","normalizedPath","imsTileRoot","tileUrlBuilder","tier","toTileUrl","DEFAULT_OVERVIEW_MAP_OPTIONS","toPositiveNumber","isFiniteBounds","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","pointIds","nextPositions","nextTerms","nextIds","output","filterPointIndicesByPolygons","contextPromise","BBOX_PREFILTER_SHADER","hasWebGpu","nav","getNavigatorGpu","gpu","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","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","data","drawIndices","visibleCount","pointIndex","compactData","workerInstance","workerSupported","requestId","pendingById","createWorker","worker","_documentCurrentScript","handleWorkerMessage","handleWorkerError","msg","pending","indices","paletteIndices","ids","terminateRoiClipWorker","filterPointDataByPolygonsInWorker","positionsCopy","termsCopy","idsCopy","startMs","resolve","reject","transfer","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","visibleKeys","nextQueue","key","earliestReadyAt","delay","now","controller","inflightEntry","nextAttempt","retryDelay","existing","attempt","exp","jitter","DEFAULT_ROTATION_DRAG_SENSITIVITY","MIN_POINT_SIZE_PX","MAX_POINT_SIZE_PX","DEFAULT_POINT_SIZE_STOPS","rad","toRadians","cos","sin","rx","ry","deg","name","isSameArrayView","clonePointSizeStops","stops","stop","normalizePointSizeStops","pointSizeByZoom","zoomKey","rawSize","size","arePointSizeStopsEqual","resolvePointSizeByZoomStops","span","slope","WsiTileRenderer","attemptCount","paletteSize","nextPaletteIndices","hasDrawIndices","nextDrawIndices","geometryChanged","drawIndicesChanged","maxExclusive","validCount","locked","nextStops","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","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","POINT_HIT_RADIUS_SCALE","MIN_POINT_HIT_RADIUS_PX","MIN_POINT_HIT_GRID_SIZE","MAX_POINT_HIT_GRID_SIZE","POINT_HIT_GRID_DENSITY_SCALE","sanitizeDrawIndices","invalidFound","resolvePointHitGridSize","buildPointSpatialIndex","cellSize","buckets","pushBucket","cellX","cellY","column","bucket","resolveRegionId","isPointInPolygon","pickRegionAt","WsiViewerCanvas","onViewStateChange","onStats","onTileError","onContextLost","onContextRestored","debugOverlayStyle","fitNonce","rotationResetNonce","ctrlDragRotate","pointPalette","roiRegions","roiPolygons","clipPointsToRois","clipMode","onClipStats","onRoiPointGroups","roiPaletteIndexToTermId","interactionLock","drawTool","customLayers","onPointerWorldMove","onPointHover","onPointClick","onRegionHover","onRegionClick","onActiveRegionChange","getCellByCoordinatesRef","showOverviewMap","overviewMapOptions","drawInvalidateRef","overviewInvalidateRef","onViewStateChangeRef","onStatsRef","debugOverlayRef","isOverviewOpen","setIsOverviewOpen","useState","setHoveredRegionId","setActiveRegionId","customLayerViewState","setCustomLayerViewState","debugStats","setDebugStats","hoveredRegionIdRef","hoveredPointIndexRef","hoveredPointIdRef","clipRunIdRef","safeRoiRegions","safePatchRegions","safeRoiPolygons","shouldTrackCustomLayerViewState","mergedDebugOverlayStyle","effectiveRoiRegions","clipPolygons","renderPointData","setRenderPointData","runId","applyResult","stats","outputCount","shouldEnablePointHitTest","pointSpatialIndex","getCellByCoordinates","coordinate","pointSizePx","hitRadiusWorld","baseCellX","baseCellY","cellRadius","nearestIndex","nearestDist2","nearestX","nearestY","cx","cy","pointId","emitPointHover","hit","nextIndex","nextId","emitPointClick","button","overviewHeight","overviewMargin","overviewPosition","commitActiveRegion","handleRendererStats","debugOverlayText","currentHover","hoveredPointIndex","emitViewStateChange","callback","resolveWorldCoord","resolveScreenCoord","requestCustomLayerRedraw","effectiveCustomLayerViewState","customLayerContext","viewStateForLayer","handleRegionPointerMove","isCanvasEvent","insideImage","nextHoverId","prevHoverId","handleRegionPointerLeave","handleRegionClick","nextActive","handleBrushTap","handleRegionContextMenu","jsxs","layer","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/brush-stroke.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 type BrushStrokeCoordinate = [number, number];\nexport type BrushStrokeBounds = [number, number, number, number];\n\nexport interface BrushStrokePolygonOptions {\n\tradius: number;\n\tclipBounds?: BrushStrokeBounds;\n\tminRasterStep?: number;\n\tmaxRasterPixels?: number;\n\tmaxRasterSize?: number;\n\tsimplifyTolerance?: number;\n\tcircleSides?: number;\n}\n\ninterface RasterConfig {\n\tminX: number;\n\tminY: number;\n\tstep: number;\n\tpadding: number;\n\twidth: number;\n\theight: number;\n}\n\ninterface BoundaryEdge {\n\tstart: number;\n\tend: number;\n\tdir: 0 | 1 | 2 | 3;\n}\n\nconst DEFAULT_MIN_RASTER_STEP = 0.1;\nconst DEFAULT_MAX_RASTER_PIXELS = 4_000_000;\nconst DEFAULT_MAX_RASTER_SIZE = 4096;\nconst DEFAULT_CIRCLE_SIDES = 64;\nconst MIN_RADIUS = 1e-6;\nconst ALPHA_THRESHOLD = 24;\n\nfunction clamp(value: number, min: number, max: number): number {\n\treturn Math.max(min, Math.min(max, value));\n}\n\nfunction closeRing(\n\tcoordinates: BrushStrokeCoordinate[],\n): BrushStrokeCoordinate[] {\n\tif (!Array.isArray(coordinates) || coordinates.length < 3) return [];\n\tconst out = coordinates.map(([x, y]) => [x, y] as BrushStrokeCoordinate);\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 sanitizePath(\n\tpoints: BrushStrokeCoordinate[],\n): BrushStrokeCoordinate[] {\n\tif (!Array.isArray(points) || points.length === 0) return [];\n\tconst out: BrushStrokeCoordinate[] = [];\n\tfor (const point of points) {\n\t\tif (!Array.isArray(point) || point.length < 2) continue;\n\t\tconst x = Number(point[0]);\n\t\tconst y = Number(point[1]);\n\t\tif (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n\t\tconst prev = out[out.length - 1];\n\t\tif (prev && Math.abs(prev[0] - x) < 1e-9 && Math.abs(prev[1] - y) < 1e-9) {\n\t\t\tcontinue;\n\t\t}\n\t\tout.push([x, y]);\n\t}\n\treturn out;\n}\n\nfunction createCirclePolygon(\n\tcenter: BrushStrokeCoordinate,\n\tradius: number,\n\tsides: number,\n): BrushStrokeCoordinate[] {\n\tif (radius <= MIN_RADIUS || sides < 8) return [];\n\tconst ring: BrushStrokeCoordinate[] = [];\n\tfor (let i = 0; i <= sides; i += 1) {\n\t\tconst t = (i / sides) * Math.PI * 2;\n\t\tring.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\treturn closeRing(ring);\n}\n\nfunction createBoundsFallback(\n\tpoints: BrushStrokeCoordinate[],\n\tradius: number,\n): BrushStrokeCoordinate[] {\n\tif (!points.length) return [];\n\tlet minX = Infinity;\n\tlet minY = Infinity;\n\tlet maxX = -Infinity;\n\tlet maxY = -Infinity;\n\tfor (const [x, y] of points) {\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\tif (!Number.isFinite(minX) || !Number.isFinite(minY)) return [];\n\tconst pad = Math.max(radius, 1);\n\treturn closeRing([\n\t\t[minX - pad, minY - pad],\n\t\t[maxX + pad, minY - pad],\n\t\t[maxX + pad, maxY + pad],\n\t\t[minX - pad, maxY + pad],\n\t]);\n}\n\nfunction computeExpandedBounds(\n\tpoints: BrushStrokeCoordinate[],\n\tradius: number,\n): BrushStrokeBounds {\n\tlet minX = Infinity;\n\tlet minY = Infinity;\n\tlet maxX = -Infinity;\n\tlet maxY = -Infinity;\n\tfor (const [x, y] of points) {\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\tconst pad = Math.max(radius, 1);\n\treturn [minX - pad, minY - pad, maxX + pad, maxY + pad];\n}\n\nfunction resolveRasterConfig(\n\tbounds: BrushStrokeBounds,\n\tradius: number,\n\toptions: BrushStrokePolygonOptions,\n): RasterConfig {\n\tconst minRasterStep = Math.max(\n\t\tDEFAULT_MIN_RASTER_STEP,\n\t\tNumber(options.minRasterStep) || 0,\n\t);\n\tconst maxRasterPixels = Math.max(\n\t\t32_768,\n\t\tMath.floor(options.maxRasterPixels || DEFAULT_MAX_RASTER_PIXELS),\n\t);\n\tconst maxRasterSize = Math.max(\n\t\t256,\n\t\tMath.floor(options.maxRasterSize || DEFAULT_MAX_RASTER_SIZE),\n\t);\n\n\tconst widthWorld = Math.max(1e-3, bounds[2] - bounds[0]);\n\tconst heightWorld = Math.max(1e-3, bounds[3] - bounds[1]);\n\tlet step = Math.max(minRasterStep, Number.EPSILON);\n\tlet padding = 3;\n\tlet width = Math.ceil(widthWorld / step) + padding * 2 + 1;\n\tlet height = Math.ceil(heightWorld / step) + padding * 2 + 1;\n\n\twhile (\n\t\twidth > maxRasterSize ||\n\t\theight > maxRasterSize ||\n\t\twidth * height > maxRasterPixels\n\t) {\n\t\tstep *= 1.15;\n\t\twidth = Math.ceil(widthWorld / step) + padding * 2 + 1;\n\t\theight = Math.ceil(heightWorld / step) + padding * 2 + 1;\n\t\tif (step > Math.max(widthWorld, heightWorld)) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\twidth = Math.max(8, width);\n\theight = Math.max(8, height);\n\n\treturn {\n\t\tminX: bounds[0],\n\t\tminY: bounds[1],\n\t\tstep,\n\t\tpadding,\n\t\twidth,\n\t\theight,\n\t};\n}\n\ntype AnyCanvas2DContext =\n\t| CanvasRenderingContext2D\n\t| OffscreenCanvasRenderingContext2D;\n\nfunction createRasterContext(\n\twidth: number,\n\theight: number,\n): AnyCanvas2DContext | null {\n\tif (typeof OffscreenCanvas !== \"undefined\") {\n\t\tconst canvas = new OffscreenCanvas(width, height);\n\t\tconst context = canvas.getContext(\"2d\", { willReadFrequently: true });\n\t\tif (context) return context;\n\t}\n\tif (typeof document !== \"undefined\") {\n\t\tconst canvas = document.createElement(\"canvas\");\n\t\tcanvas.width = width;\n\t\tcanvas.height = height;\n\t\treturn canvas.getContext(\"2d\", { willReadFrequently: true });\n\t}\n\treturn null;\n}\n\nfunction worldToRaster(\n\tpoint: BrushStrokeCoordinate,\n\tconfig: RasterConfig,\n): BrushStrokeCoordinate {\n\treturn [\n\t\t(point[0] - config.minX) / config.step + config.padding,\n\t\t(point[1] - config.minY) / config.step + config.padding,\n\t];\n}\n\nfunction rasterizeStrokeMask(\n\tpath: BrushStrokeCoordinate[],\n\tradius: number,\n\tconfig: RasterConfig,\n): Uint8Array {\n\tconst context = createRasterContext(config.width, config.height);\n\tif (!context) return new Uint8Array(0);\n\n\tcontext.clearRect(0, 0, config.width, config.height);\n\tcontext.fillStyle = \"#ffffff\";\n\tcontext.strokeStyle = \"#ffffff\";\n\tcontext.lineCap = \"round\";\n\tcontext.lineJoin = \"round\";\n\tcontext.lineWidth = (radius * 2) / config.step;\n\n\tconst points = path.map(point => worldToRaster(point, config));\n\tif (points.length <= 1) {\n\t\tconst p = points[0];\n\t\tif (!p) return new Uint8Array(0);\n\t\tcontext.beginPath();\n\t\tcontext.arc(p[0], p[1], radius / config.step, 0, Math.PI * 2);\n\t\tcontext.fill();\n\t} else {\n\t\tcontext.beginPath();\n\t\tcontext.moveTo(points[0][0], points[0][1]);\n\t\tfor (let i = 1; i < points.length; i += 1) {\n\t\t\tcontext.lineTo(points[i][0], points[i][1]);\n\t\t}\n\t\tcontext.stroke();\n\t}\n\n\tconst image = context.getImageData(0, 0, config.width, config.height);\n\tconst out = new Uint8Array(config.width * config.height);\n\tfor (let i = 0; i < out.length; i += 1) {\n\t\tout[i] = image.data[i * 4 + 3] >= ALPHA_THRESHOLD ? 1 : 0;\n\t}\n\treturn out;\n}\n\nfunction buildBoundaryEdges(mask: Uint8Array, width: number, height: number): BoundaryEdge[] {\n\tconst edges: BoundaryEdge[] = [];\n\tconst stride = width + 1;\n\tconst vertex = (x: number, y: number): number => y * stride + x;\n\tconst at = (x: number, y: number): boolean =>\n\t\tx >= 0 && y >= 0 && x < width && y < height && mask[y * width + x] > 0;\n\n\tfor (let y = 0; y < height; y += 1) {\n\t\tfor (let x = 0; x < width; x += 1) {\n\t\t\tif (!at(x, y)) continue;\n\t\t\tif (!at(x, y - 1)) {\n\t\t\t\tedges.push({\n\t\t\t\t\tstart: vertex(x, y),\n\t\t\t\t\tend: vertex(x + 1, y),\n\t\t\t\t\tdir: 0,\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (!at(x + 1, y)) {\n\t\t\t\tedges.push({\n\t\t\t\t\tstart: vertex(x + 1, y),\n\t\t\t\t\tend: vertex(x + 1, y + 1),\n\t\t\t\t\tdir: 1,\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (!at(x, y + 1)) {\n\t\t\t\tedges.push({\n\t\t\t\t\tstart: vertex(x + 1, y + 1),\n\t\t\t\t\tend: vertex(x, y + 1),\n\t\t\t\t\tdir: 2,\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (!at(x - 1, y)) {\n\t\t\t\tedges.push({\n\t\t\t\t\tstart: vertex(x, y + 1),\n\t\t\t\t\tend: vertex(x, y),\n\t\t\t\t\tdir: 3,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn edges;\n}\n\nfunction turnPriority(fromDir: number, toDir: number): number {\n\tconst delta = (toDir - fromDir + 4) % 4;\n\tif (delta === 1) return 0; // right\n\tif (delta === 0) return 1; // straight\n\tif (delta === 3) return 2; // left\n\treturn 3; // reverse\n}\n\nfunction traceLoops(edges: BoundaryEdge[]): number[][] {\n\tif (!edges.length) return [];\n\n\tconst outgoing = new Map<number, number[]>();\n\tfor (let i = 0; i < edges.length; i += 1) {\n\t\tconst entry = outgoing.get(edges[i].start);\n\t\tif (entry) {\n\t\t\tentry.push(i);\n\t\t} else {\n\t\t\toutgoing.set(edges[i].start, [i]);\n\t\t}\n\t}\n\n\tconst used = new Uint8Array(edges.length);\n\tconst loops: number[][] = [];\n\n\tfor (let i = 0; i < edges.length; i += 1) {\n\t\tif (used[i]) continue;\n\n\t\tconst first = edges[i];\n\t\tconst startVertex = first.start;\n\t\tlet currentVertex = first.end;\n\t\tlet currentDir = first.dir;\n\t\tconst loop: number[] = [first.start, first.end];\n\t\tused[i] = 1;\n\n\t\tlet guard = 0;\n\t\tconst guardLimit = edges.length * 3;\n\t\twhile (currentVertex !== startVertex && guard < guardLimit) {\n\t\t\tconst candidates = outgoing.get(currentVertex);\n\t\t\tif (!candidates || candidates.length === 0) break;\n\n\t\t\tlet bestIndex = -1;\n\t\t\tlet bestPriority = Infinity;\n\t\t\tfor (const edgeIndex of candidates) {\n\t\t\t\tif (used[edgeIndex]) continue;\n\t\t\t\tconst candidate = edges[edgeIndex];\n\t\t\t\tconst priority = turnPriority(currentDir, candidate.dir);\n\t\t\t\tif (priority < bestPriority) {\n\t\t\t\t\tbestPriority = priority;\n\t\t\t\t\tbestIndex = edgeIndex;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (bestIndex < 0) break;\n\t\t\tused[bestIndex] = 1;\n\t\t\tconst next = edges[bestIndex];\n\t\t\tcurrentVertex = next.end;\n\t\t\tcurrentDir = next.dir;\n\t\t\tloop.push(currentVertex);\n\t\t\tguard += 1;\n\t\t}\n\n\t\tif (\n\t\t\tloop.length >= 4 &&\n\t\t\tloop[0] === loop[loop.length - 1]\n\t\t) {\n\t\t\tloops.push(loop);\n\t\t}\n\t}\n\n\treturn loops;\n}\n\nfunction toWorldRing(\n\tvertexLoop: number[],\n\twidth: number,\n\tconfig: RasterConfig,\n): BrushStrokeCoordinate[] {\n\tconst stride = width + 1;\n\tconst ring: BrushStrokeCoordinate[] = [];\n\tfor (const id of vertexLoop) {\n\t\tconst x = id % stride;\n\t\tconst y = Math.floor(id / stride);\n\t\tring.push([\n\t\t\tconfig.minX + (x - config.padding) * config.step,\n\t\t\tconfig.minY + (y - config.padding) * config.step,\n\t\t]);\n\t}\n\treturn closeRing(ring);\n}\n\nfunction polygonSignedArea(ring: BrushStrokeCoordinate[]): number {\n\tif (ring.length < 4) return 0;\n\tlet sum = 0;\n\tfor (let i = 0; i < ring.length - 1; i += 1) {\n\t\tconst a = ring[i];\n\t\tconst b = ring[i + 1];\n\t\tsum += a[0] * b[1] - b[0] * a[1];\n\t}\n\treturn sum * 0.5;\n}\n\nfunction removeCollinearVertices(\n\tring: BrushStrokeCoordinate[],\n\tepsilon = 1e-9,\n): BrushStrokeCoordinate[] {\n\tconst closed = closeRing(ring);\n\tif (closed.length < 5) return closed;\n\tconst out: BrushStrokeCoordinate[] = [closed[0]];\n\tfor (let i = 1; i < closed.length - 1; i += 1) {\n\t\tconst prev = out[out.length - 1];\n\t\tconst curr = closed[i];\n\t\tconst next = closed[i + 1];\n\t\tconst cross =\n\t\t\t(curr[0] - prev[0]) * (next[1] - curr[1]) -\n\t\t\t(curr[1] - prev[1]) * (next[0] - curr[0]);\n\t\tif (Math.abs(cross) <= epsilon) continue;\n\t\tout.push(curr);\n\t}\n\tout.push(out[0]);\n\treturn closeRing(out);\n}\n\nfunction pointLineDistanceSquared(\n\tp: BrushStrokeCoordinate,\n\ta: BrushStrokeCoordinate,\n\tb: BrushStrokeCoordinate,\n): number {\n\tconst abx = b[0] - a[0];\n\tconst aby = b[1] - a[1];\n\tconst len2 = abx * abx + aby * aby;\n\tif (len2 <= 1e-12) {\n\t\tconst dx = p[0] - a[0];\n\t\tconst dy = p[1] - a[1];\n\t\treturn dx * dx + dy * dy;\n\t}\n\tconst t = clamp(\n\t\t((p[0] - a[0]) * abx + (p[1] - a[1]) * aby) / len2,\n\t\t0,\n\t\t1,\n\t);\n\tconst x = a[0] + abx * t;\n\tconst y = a[1] + aby * t;\n\tconst dx = p[0] - x;\n\tconst dy = p[1] - y;\n\treturn dx * dx + dy * dy;\n}\n\nfunction simplifyRdp(\n\tpoints: BrushStrokeCoordinate[],\n\ttolerance: number,\n): BrushStrokeCoordinate[] {\n\tif (points.length <= 2 || tolerance <= 0) return points.slice();\n\n\tconst keep = new Uint8Array(points.length);\n\tkeep[0] = 1;\n\tkeep[points.length - 1] = 1;\n\tconst tolerance2 = tolerance * tolerance;\n\tconst stack: Array<[number, number]> = [[0, points.length - 1]];\n\n\twhile (stack.length > 0) {\n\t\tconst next = stack.pop();\n\t\tif (!next) break;\n\t\tconst [start, end] = next;\n\t\tif (end - start <= 1) continue;\n\n\t\tlet maxDist2 = 0;\n\t\tlet split = -1;\n\t\tfor (let i = start + 1; i < end; i += 1) {\n\t\t\tconst dist2 = pointLineDistanceSquared(points[i], points[start], points[end]);\n\t\t\tif (dist2 > maxDist2) {\n\t\t\t\tmaxDist2 = dist2;\n\t\t\t\tsplit = i;\n\t\t\t}\n\t\t}\n\n\t\tif (split >= 0 && maxDist2 > tolerance2) {\n\t\t\tkeep[split] = 1;\n\t\t\tstack.push([start, split], [split, end]);\n\t\t}\n\t}\n\n\tconst out: BrushStrokeCoordinate[] = [];\n\tfor (let i = 0; i < points.length; i += 1) {\n\t\tif (keep[i]) out.push(points[i]);\n\t}\n\treturn out;\n}\n\nfunction simplifyClosedRing(\n\tring: BrushStrokeCoordinate[],\n\ttolerance: number,\n): BrushStrokeCoordinate[] {\n\tconst closed = closeRing(ring);\n\tif (closed.length < 5 || tolerance <= 0) return closed;\n\tconst open = closed.slice(0, -1);\n\tconst simplified = simplifyRdp(open, tolerance);\n\tif (simplified.length < 3) return closed;\n\treturn closeRing(simplified);\n}\n\nfunction clampRingToBounds(\n\tring: BrushStrokeCoordinate[],\n\tbounds: BrushStrokeBounds | undefined,\n): BrushStrokeCoordinate[] {\n\tif (!bounds) return ring;\n\treturn closeRing(\n\t\tring.map(([x, y]) => [\n\t\t\tclamp(x, bounds[0], bounds[2]),\n\t\t\tclamp(y, bounds[1], bounds[3]),\n\t\t] as BrushStrokeCoordinate),\n\t);\n}\n\nexport function buildBrushStrokePolygon(\n\tpath: BrushStrokeCoordinate[],\n\toptions: BrushStrokePolygonOptions,\n): BrushStrokeCoordinate[] {\n\tconst points = sanitizePath(path);\n\tconst radius = Math.max(MIN_RADIUS, Number(options.radius) || 0);\n\tif (points.length === 0 || !Number.isFinite(radius)) return [];\n\n\tconst circleSides = Math.max(12, Math.floor(options.circleSides || DEFAULT_CIRCLE_SIDES));\n\tif (points.length === 1) {\n\t\treturn clampRingToBounds(\n\t\t\tcreateCirclePolygon(points[0], radius, circleSides),\n\t\t\toptions.clipBounds,\n\t\t);\n\t}\n\n\tconst bounds = computeExpandedBounds(points, radius);\n\tconst raster = resolveRasterConfig(bounds, radius, options);\n\tconst mask = rasterizeStrokeMask(points, radius, raster);\n\tif (!mask.length) {\n\t\treturn clampRingToBounds(createBoundsFallback(points, radius), options.clipBounds);\n\t}\n\n\tconst edges = buildBoundaryEdges(mask, raster.width, raster.height);\n\tconst loops = traceLoops(edges);\n\tif (!loops.length) {\n\t\treturn clampRingToBounds(createBoundsFallback(points, radius), options.clipBounds);\n\t}\n\n\tlet bestRing: BrushStrokeCoordinate[] = [];\n\tlet bestArea = 0;\n\tfor (const loop of loops) {\n\t\tconst ring = toWorldRing(loop, raster.width, raster);\n\t\tconst area = Math.abs(polygonSignedArea(ring));\n\t\tif (area <= bestArea) continue;\n\t\tbestArea = area;\n\t\tbestRing = ring;\n\t}\n\n\tif (!bestRing.length) {\n\t\treturn clampRingToBounds(createBoundsFallback(points, radius), options.clipBounds);\n\t}\n\n\tconst tolerance =\n\t\ttypeof options.simplifyTolerance === \"number\" && Number.isFinite(options.simplifyTolerance)\n\t\t\t? Math.max(0, options.simplifyTolerance)\n\t\t\t: raster.step * 0.2;\n\tconst simplified = simplifyClosedRing(\n\t\tremoveCollinearVertices(bestRing, raster.step * 1e-3),\n\t\ttolerance,\n\t);\n\treturn clampRingToBounds(simplified, options.clipBounds);\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 { buildBrushStrokePolygon } from \"../wsi/brush-stroke\";\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\" | \"brush\" | StampDrawTool;\n\nexport type DrawCoordinate = [number, number];\n\nexport type DrawBounds = [number, number, number, number];\n\nexport type DrawIntent = \"roi\" | \"patch\" | \"brush\";\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 type DrawOverlayCoordinates = DrawCoordinate[] | DrawCoordinate[][] | DrawCoordinate[][][];\n\nexport interface DrawOverlayShape {\n id?: string | number;\n coordinates: DrawOverlayCoordinates;\n closed?: boolean;\n fill?: boolean;\n stroke?: Partial<RegionStrokeStyle>;\n strokeStyle?: Partial<RegionStrokeStyle>;\n invertedFill?: DrawOverlayInvertedFillStyle;\n visible?: boolean;\n}\n\nexport interface DrawOverlayInvertedFillStyle {\n fillColor: string;\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 zoomBy?: (factor: number, screenX: number, screenY: number) => void;\n}\n\nexport interface StampOptions {\n rectangleAreaMm2?: number;\n circleAreaMm2?: number;\n rectanglePixelSize?: number;\n}\n\nexport interface BrushOptions {\n radius: number;\n /**\n * Brush edge detail factor. Higher values create rounder/finer edges.\n * Range: 0.25 ~ 4. Default: 1.\n */\n edgeDetail?: number;\n /**\n * When true, a brush \"tap\" (click without drag) on ROI selects that ROI\n * instead of creating a brush stroke.\n */\n clickSelectRoi?: boolean;\n fillColor?: string;\n fillOpacity?: number;\n cursorColor?: string;\n cursorActiveColor?: string;\n cursorLineWidth?: number;\n cursorLineDash?: 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 brushOptions?: BrushOptions;\n projectorRef: RefObject<DrawProjector | null>;\n onBrushTap?: (coordinate: DrawCoordinate) => boolean;\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 cursor: DrawCoordinate | null;\n points: DrawCoordinate[];\n stampCenter: DrawCoordinate | null;\n}\n\ninterface ResolvedBrushOptions {\n radius: number;\n edgeDetail: number;\n clickSelectRoi: boolean;\n fillColor: string;\n fillOpacity: number;\n cursorColor: string;\n cursorActiveColor: string;\n cursorLineWidth: number;\n cursorLineDash: number[];\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;\nconst WHEEL_ZOOM_IN_FACTOR = 1.12;\nconst WHEEL_ZOOM_OUT_FACTOR = 0.89;\nconst DEFAULT_BRUSH_RADIUS = 32;\nconst DEFAULT_BRUSH_FILL_COLOR = \"#000000\";\nconst DEFAULT_BRUSH_FILL_OPACITY = 0.1;\nconst DEFAULT_BRUSH_CURSOR_COLOR = \"#FFCF00\";\nconst DEFAULT_BRUSH_CURSOR_ACTIVE_COLOR = \"#FF0000\";\nconst DEFAULT_BRUSH_CURSOR_LINE_WIDTH = 1.5;\nconst DEFAULT_BRUSH_CURSOR_DASH = [2, 2];\nconst DEFAULT_BRUSH_EDGE_DETAIL = 1;\nconst MIN_BRUSH_EDGE_DETAIL = 0.25;\nconst MAX_BRUSH_EDGE_DETAIL = 4;\nconst MIN_BRUSH_RASTER_STEP = 0.1;\nconst BRUSH_RASTER_DIAMETER_SAMPLES = 96;\nconst BRUSH_SCREEN_STEP = 1.5;\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 clampUnitOpacity(value: number | undefined, fallback: number): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return fallback;\n return clamp(value, 0, 1);\n}\n\nfunction sanitizeBrushLineDash(value: number[] | undefined): number[] {\n if (!Array.isArray(value)) return DEFAULT_BRUSH_CURSOR_DASH;\n const out = value.filter(item => Number.isFinite(item) && item >= 0);\n return out.length > 0 ? out : DEFAULT_BRUSH_CURSOR_DASH;\n}\n\nfunction resolveBrushEdgeDetail(value: number | undefined): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return DEFAULT_BRUSH_EDGE_DETAIL;\n return clamp(value, MIN_BRUSH_EDGE_DETAIL, MAX_BRUSH_EDGE_DETAIL);\n}\n\nfunction resolveBrushOptions(options: BrushOptions | undefined): ResolvedBrushOptions {\n const radius = clampPositiveOrFallback(options?.radius, DEFAULT_BRUSH_RADIUS);\n const cursorLineWidth = clampPositiveOrFallback(options?.cursorLineWidth, DEFAULT_BRUSH_CURSOR_LINE_WIDTH);\n const edgeDetail = resolveBrushEdgeDetail(options?.edgeDetail);\n return {\n radius,\n edgeDetail,\n clickSelectRoi: options?.clickSelectRoi === true,\n fillColor: options?.fillColor || DEFAULT_BRUSH_FILL_COLOR,\n fillOpacity: clampUnitOpacity(options?.fillOpacity, DEFAULT_BRUSH_FILL_OPACITY),\n cursorColor: options?.cursorColor || DEFAULT_BRUSH_CURSOR_COLOR,\n cursorActiveColor: options?.cursorActiveColor || DEFAULT_BRUSH_CURSOR_ACTIVE_COLOR,\n cursorLineWidth,\n cursorLineDash: sanitizeBrushLineDash(options?.cursorLineDash),\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 tracePath(ctx: CanvasRenderingContext2D, points: DrawCoordinate[], close = false): void {\n if (points.length === 0) return;\n\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}\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 tracePath(ctx, points, close);\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 isNestedRingCoordinates(coordinates: DrawOverlayCoordinates): boolean {\n const first = coordinates[0];\n return Array.isArray(first) && Array.isArray(first[0]);\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value);\n}\n\nfunction isCoordinatePair(value: unknown): value is [number, number] {\n return Array.isArray(value) && value.length >= 2 && isFiniteNumber(value[0]) && isFiniteNumber(value[1]);\n}\n\nfunction isCoordinateRing(value: unknown): value is DrawCoordinate[] {\n return Array.isArray(value) && value.length >= 2 && value.every(point => isCoordinatePair(point));\n}\n\nfunction collectOverlayRings(value: unknown, out: DrawCoordinate[][]): void {\n if (!Array.isArray(value) || value.length === 0) return;\n if (isCoordinateRing(value)) {\n out.push(value.map(([x, y]) => [x, y] as DrawCoordinate));\n return;\n }\n for (const item of value) {\n collectOverlayRings(item, out);\n }\n}\n\nfunction normalizeOverlayRings(coordinates: DrawOverlayCoordinates, close: boolean): DrawCoordinate[][] {\n const sourceRings: DrawCoordinate[][] = [];\n collectOverlayRings(coordinates, sourceRings);\n const out: DrawCoordinate[][] = [];\n for (const ring of sourceRings) {\n if (ring.length < 2) continue;\n const normalized = close ? closeRing(ring) : ring;\n if (normalized.length >= (close ? 4 : 2)) {\n out.push(normalized);\n }\n }\n return out;\n}\n\nfunction drawInvertedFillMask(ctx: CanvasRenderingContext2D, outerRing: DrawCoordinate[], holeRings: DrawCoordinate[][], fillColor: string): void {\n if (outerRing.length < 4 || holeRings.length === 0) return;\n ctx.save();\n ctx.beginPath();\n tracePath(ctx, outerRing, true);\n for (const ring of holeRings) {\n if (ring.length < 4) continue;\n tracePath(ctx, ring, true);\n }\n ctx.fillStyle = fillColor;\n ctx.fill(\"evenodd\");\n ctx.restore();\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 brushOptions,\n projectorRef,\n onBrushTap,\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 overlayDebugSnapshotRef = useRef<Map<string, string>>(new Map());\n const lastToolRef = useRef<DrawTool>(tool);\n const sessionRef = useRef<DrawSession>({\n isDrawing: false,\n pointerId: null,\n start: null,\n current: null,\n cursor: 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 const resolvedBrushOptions = useMemo(() => resolveBrushOptions(brushOptions), [brushOptions]);\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 ? (tool === \"brush\" ? \"none\" : \"crosshair\") : \"default\",\n ...style,\n }),\n [active, tool, 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 worldRadiusToScreenPixels = useCallback(\n (center: DrawCoordinate, worldRadius: number): number => {\n if (!Number.isFinite(worldRadius) || worldRadius <= 0) return 0;\n const projector = projectorRef.current;\n if (!projector) return 0;\n const a = toCoord(projector.worldToScreen(center[0], center[1]));\n const b = toCoord(projector.worldToScreen(center[0] + worldRadius, center[1]));\n if (!a || !b) return 0;\n return Math.hypot(b[0] - a[0], b[1] - a[1]);\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 (tool === \"brush\") {\n return [];\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 drawBrushStrokePreview = useCallback(\n (ctx: CanvasRenderingContext2D): void => {\n const session = sessionRef.current;\n if (!session.isDrawing || session.points.length === 0) return;\n\n const screenPoints = worldToScreenPoints(session.points);\n if (screenPoints.length === 0) return;\n const anchor = session.points[session.points.length - 1] ?? session.points[0];\n const radiusPx = worldRadiusToScreenPixels(anchor, resolvedBrushOptions.radius);\n if (!Number.isFinite(radiusPx) || radiusPx <= 0) return;\n\n ctx.save();\n ctx.globalAlpha = resolvedBrushOptions.fillOpacity;\n ctx.fillStyle = resolvedBrushOptions.fillColor;\n ctx.strokeStyle = resolvedBrushOptions.fillColor;\n ctx.lineCap = \"round\";\n ctx.lineJoin = \"round\";\n ctx.lineWidth = radiusPx * 2;\n if (screenPoints.length === 1) {\n ctx.beginPath();\n ctx.arc(screenPoints[0][0], screenPoints[0][1], radiusPx, 0, Math.PI * 2);\n ctx.fill();\n } else {\n ctx.beginPath();\n ctx.moveTo(screenPoints[0][0], screenPoints[0][1]);\n for (let i = 1; i < screenPoints.length; i += 1) {\n ctx.lineTo(screenPoints[i][0], screenPoints[i][1]);\n }\n ctx.stroke();\n }\n ctx.restore();\n },\n [worldToScreenPoints, worldRadiusToScreenPixels, resolvedBrushOptions]\n );\n\n const drawBrushCursor = useCallback(\n (ctx: CanvasRenderingContext2D): void => {\n const session = sessionRef.current;\n const cursor = session.cursor;\n if (!cursor) return;\n const screen = toCoord(projectorRef.current?.worldToScreen(cursor[0], cursor[1]) ?? []);\n if (!screen) return;\n const radiusPx = worldRadiusToScreenPixels(cursor, resolvedBrushOptions.radius);\n if (!Number.isFinite(radiusPx) || radiusPx <= 0) return;\n\n ctx.save();\n ctx.beginPath();\n ctx.arc(screen[0], screen[1], radiusPx, 0, Math.PI * 2);\n ctx.strokeStyle = session.isDrawing ? resolvedBrushOptions.cursorActiveColor : resolvedBrushOptions.cursorColor;\n ctx.lineWidth = resolvedBrushOptions.cursorLineWidth;\n ctx.setLineDash(resolvedBrushOptions.cursorLineDash);\n ctx.stroke();\n ctx.setLineDash(EMPTY_DASH);\n ctx.restore();\n },\n [projectorRef, worldRadiusToScreenPixels, resolvedBrushOptions]\n );\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 const debugOverlay = Boolean((globalThis as { __OPEN_PLANT_DEBUG_OVERLAY__?: boolean }).__OPEN_PLANT_DEBUG_OVERLAY__);\n const imageOuterRing = worldToScreenPoints(\n closeRing([\n [0, 0],\n [imageWidth, 0],\n [imageWidth, imageHeight],\n [0, imageHeight],\n ])\n );\n for (let i = 0; i < overlayShapes.length; i += 1) {\n const shape = overlayShapes[i];\n if (!shape?.coordinates?.length || shape.visible === false) continue;\n\n const closed = shape.closed ?? isNestedRingCoordinates(shape.coordinates);\n const renderRings = normalizeOverlayRings(shape.coordinates, closed);\n\n if (shape.invertedFill?.fillColor) {\n const holeRings: DrawCoordinate[][] = [];\n const closedRings = normalizeOverlayRings(shape.coordinates, true);\n for (const ring of closedRings) {\n const screen = worldToScreenPoints(ring);\n if (screen.length >= 4) {\n holeRings.push(screen);\n }\n }\n if (debugOverlay) {\n const debugKey = String(shape.id ?? i);\n const debugSignature = `${imageOuterRing.length}|${closedRings.length}|${holeRings.length}|${shape.invertedFill.fillColor}`;\n if (overlayDebugSnapshotRef.current.get(debugKey) !== debugSignature) {\n overlayDebugSnapshotRef.current.set(debugKey, debugSignature);\n console.debug(\"[open-plant] invertedFill\", {\n id: shape.id ?? i,\n outerRingPoints: imageOuterRing.length,\n sourceRingCount: closedRings.length,\n holeRingCount: holeRings.length,\n fillColor: shape.invertedFill.fillColor,\n });\n }\n }\n drawInvertedFillMask(ctx, imageOuterRing, holeRings, shape.invertedFill.fillColor);\n }\n\n if (renderRings.length === 0) continue;\n const strokeStyle = mergeStrokeStyle(resolvedStrokeStyle, shape.stroke ?? shape.strokeStyle);\n for (const ring of renderRings) {\n const screen = worldToScreenPoints(ring);\n if (screen.length < 2) continue;\n drawPath(ctx, screen, strokeStyle, closed, shape.fill ?? false);\n }\n }\n }\n\n if (active) {\n if (tool === \"brush\") {\n drawBrushStrokePreview(ctx);\n drawBrushCursor(ctx);\n } else {\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\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 drawBrushStrokePreview,\n drawBrushCursor,\n resizeCanvas,\n worldToScreenPoints,\n imageWidth,\n imageHeight,\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((preserveCursor = false) => {\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 if (!preserveCursor) {\n session.cursor = null;\n }\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(true);\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 } else if (tool === \"brush\") {\n const tapPoint = session.points[session.points.length - 1] ?? session.current ?? session.start;\n if (resolvedBrushOptions.clickSelectRoi && tapPoint && session.points.length <= 1 && onBrushTap?.(tapPoint)) {\n resetSession(true);\n requestDraw();\n return;\n }\n const edgeDetail = resolvedBrushOptions.edgeDetail;\n const minRasterStep = Math.max(\n MIN_BRUSH_RASTER_STEP,\n (resolvedBrushOptions.radius * 2) / (BRUSH_RASTER_DIAMETER_SAMPLES * edgeDetail),\n );\n coordinates = buildBrushStrokePolygon(session.points, {\n radius: resolvedBrushOptions.radius,\n clipBounds: [0, 0, imageWidth, imageHeight],\n minRasterStep,\n circleSides: Math.max(24, Math.round(64 * edgeDetail)),\n simplifyTolerance: minRasterStep * 0.4,\n }) as DrawCoordinate[];\n }\n\n if ((tool === \"freehand\" || tool === \"rectangle\" || tool === \"circular\" || tool === \"brush\") && isValidPolygon(coordinates) && onDrawComplete) {\n const intent: DrawIntent = tool === \"brush\" ? \"brush\" : \"roi\";\n onDrawComplete({\n tool,\n intent,\n coordinates,\n bbox: computeBounds(coordinates),\n areaPx: polygonArea(coordinates),\n });\n }\n\n resetSession(true);\n requestDraw();\n }, [tool, onDrawComplete, resetSession, requestDraw, resolvedBrushOptions.radius, resolvedBrushOptions.edgeDetail, resolvedBrushOptions.clickSelectRoi, imageWidth, imageHeight, onBrushTap]);\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 appendBrushPoint = useCallback(\n (session: DrawSession, world: DrawCoordinate): void => {\n const projector = projectorRef.current;\n const zoom = Math.max(1e-6, projector?.getViewState?.().zoom ?? 1);\n const minWorldStep = BRUSH_SCREEN_STEP / zoom;\n const minWorldStep2 = minWorldStep * minWorldStep;\n const prev = session.points[session.points.length - 1];\n if (!prev) {\n session.points.push(world);\n session.current = world;\n return;\n }\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 } else {\n session.points[session.points.length - 1] = world;\n }\n session.current = world;\n },\n [projectorRef]\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.cursor = world;\n session.points = tool === \"freehand\" || tool === \"brush\" ? [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 (tool === \"brush\") {\n session.cursor = world;\n if (!session.isDrawing || session.pointerId !== event.pointerId) {\n requestDraw();\n return;\n }\n event.preventDefault();\n event.stopPropagation();\n appendBrushPoint(session, world);\n requestDraw();\n return;\n }\n\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, appendBrushPoint]\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 world = toWorld(event);\n if (world) {\n session.cursor = world;\n if (tool === \"brush\") {\n appendBrushPoint(session, world);\n } else {\n session.current = world;\n }\n }\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, toWorld, tool, appendBrushPoint]\n );\n\n const handlePointerLeave = useCallback(() => {\n const session = sessionRef.current;\n let changed = false;\n if (tool === \"brush\" && !session.isDrawing && session.cursor) {\n session.cursor = null;\n changed = true;\n }\n if (isStampTool(tool) && session.stampCenter) {\n session.stampCenter = null;\n changed = true;\n }\n if (changed) {\n requestDraw();\n }\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) return;\n const canvas = canvasRef.current;\n const projector = projectorRef.current;\n if (!canvas || typeof projector?.zoomBy !== \"function\") return;\n event.preventDefault();\n event.stopPropagation();\n const rect = canvas.getBoundingClientRect();\n const screenX = event.clientX - rect.left;\n const screenY = event.clientY - rect.top;\n projector.zoomBy(event.deltaY < 0 ? WHEEL_ZOOM_IN_FACTOR : WHEEL_ZOOM_OUT_FACTOR, screenX, screenY);\n requestDraw();\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\tconst pointIds =\n\t\tpointData.ids instanceof Uint32Array && pointData.ids.length >= count\n\t\t\t? pointData.ids\n\t\t\t: null;\n\n\tconst nextPositions = new Float32Array(count * 2);\n\tconst nextTerms = new Uint16Array(count);\n\tconst nextIds = pointIds ? new Uint32Array(count) : null;\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\tif (nextIds) {\n\t\t\tnextIds[cursor] = pointIds![i];\n\t\t}\n\t\tcursor += 1;\n\t}\n\n\tconst output: WsiPointData = {\n\t\tcount: cursor,\n\t\tpositions: nextPositions.subarray(0, cursor * 2),\n\t\tpaletteIndices: nextTerms.subarray(0, cursor),\n\t};\n\tif (nextIds) {\n\t\toutput.ids = nextIds.subarray(0, cursor);\n\t}\n\treturn output;\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 const pointIds = pointData.ids instanceof Uint32Array && pointData.ids.length >= safeCount ? pointData.ids : null;\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 const data: WsiPointData = {\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 if (pointIds) {\n data.ids = pointIds.subarray(0, safeCount);\n }\n return {\n data,\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 ...(pointIds ? { ids: new Uint32Array(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 const data: WsiPointData = {\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 if (pointIds) {\n data.ids = pointIds.subarray(0, safeCount);\n }\n\n return {\n data,\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 const nextIds = pointIds ? new Uint32Array(candidateCount) : null;\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 if (nextIds) {\n nextIds[cursor] = pointIds![pointIndex];\n }\n cursor += 1;\n }\n\n const compactData: WsiPointData = {\n count: cursor,\n positions: nextPositions.subarray(0, cursor * 2),\n paletteIndices: nextTerms.subarray(0, cursor),\n };\n if (nextIds) {\n compactData.ids = nextIds.subarray(0, cursor);\n }\n\n return {\n data: compactData,\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 ids = msg.ids ? new Uint32Array(msg.ids) : null;\n const output: WsiPointData = {\n count,\n positions: positions.subarray(0, count * 2),\n paletteIndices: paletteIndices.subarray(0, count),\n };\n if (ids) {\n output.ids = ids.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 idsCopy = pointData.ids instanceof Uint32Array && pointData.ids.length >= safeCount ? pointData.ids.slice(0, safeCount) : null;\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 ids: idsCopy?.buffer,\n polygons: polygons ?? [],\n };\n const transfer: Transferable[] = [positionsCopy.buffer, termsCopy.buffer];\n if (idsCopy) {\n transfer.push(idsCopy.buffer);\n }\n worker.postMessage(msg, transfer);\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;\nconst MIN_POINT_SIZE_PX = 0.5;\nconst MAX_POINT_SIZE_PX = 256;\n\ninterface PointSizeStop {\n\tzoom: number;\n\tsize: number;\n}\n\nconst DEFAULT_POINT_SIZE_STOPS: readonly PointSizeStop[] = [\n\t{ zoom: 1, size: 2.8 },\n\t{ zoom: 2, size: 3.4 },\n\t{ zoom: 3, size: 4.2 },\n\t{ zoom: 4, size: 5.3 },\n\t{ zoom: 5, size: 6.8 },\n\t{ zoom: 6, size: 8.4 },\n\t{ zoom: 7, size: 9.8 },\n\t{ zoom: 8, size: 11.2 },\n\t{ zoom: 9, size: 14.0 },\n\t{ zoom: 10, size: 17.5 },\n\t{ zoom: 11, size: 22.0 },\n\t{ zoom: 12, size: 28.0 },\n];\n\nexport type PointSizeByZoom = Readonly<Record<number, number>>;\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\tpointSizeByZoom?: PointSizeByZoom;\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\nfunction clonePointSizeStops(stops: readonly PointSizeStop[]): PointSizeStop[] {\n\treturn stops.map(stop => ({ zoom: stop.zoom, size: stop.size }));\n}\n\nfunction normalizePointSizeStops(pointSizeByZoom: PointSizeByZoom | null | undefined): PointSizeStop[] {\n\tif (!pointSizeByZoom) return clonePointSizeStops(DEFAULT_POINT_SIZE_STOPS);\n\n\tconst parsed = new Map<number, number>();\n\tfor (const [zoomKey, rawSize] of Object.entries(pointSizeByZoom)) {\n\t\tconst zoom = Number(zoomKey);\n\t\tconst size = Number(rawSize);\n\t\tif (!Number.isFinite(zoom) || !Number.isFinite(size) || size <= 0) continue;\n\t\tparsed.set(zoom, size);\n\t}\n\n\tif (parsed.size === 0) {\n\t\treturn clonePointSizeStops(DEFAULT_POINT_SIZE_STOPS);\n\t}\n\n\treturn Array.from(parsed.entries())\n\t\t.sort((a, b) => a[0] - b[0])\n\t\t.map(([zoom, size]) => ({ zoom, size }));\n}\n\nfunction arePointSizeStopsEqual(a: readonly PointSizeStop[], b: readonly PointSizeStop[]): boolean {\n\tif (a === b) return true;\n\tif (a.length !== b.length) return false;\n\tfor (let i = 0; i < a.length; i += 1) {\n\t\tif (a[i].zoom !== b[i].zoom || a[i].size !== b[i].size) {\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n\nfunction resolvePointSizeByZoomStops(continuousZoom: number, stops: readonly PointSizeStop[]): number {\n\tif (!Number.isFinite(continuousZoom)) return stops[0]?.size ?? MIN_POINT_SIZE_PX;\n\tif (stops.length === 0) return MIN_POINT_SIZE_PX;\n\tif (stops.length === 1) return stops[0].size;\n\tif (continuousZoom <= stops[0].zoom) return stops[0].size;\n\n\tfor (let i = 1; i < stops.length; i += 1) {\n\t\tconst prev = stops[i - 1];\n\t\tconst next = stops[i];\n\t\tif (continuousZoom > next.zoom) continue;\n\t\tconst span = Math.max(1e-6, next.zoom - prev.zoom);\n\t\tconst t = clamp((continuousZoom - prev.zoom) / span, 0, 1);\n\t\treturn prev.size + (next.size - prev.size) * t;\n\t}\n\n\tconst last = stops[stops.length - 1];\n\tconst prev = stops[stops.length - 2];\n\tconst span = Math.max(1e-6, last.zoom - prev.zoom);\n\tconst slope = (last.size - prev.size) / span;\n\treturn last.size + (continuousZoom - last.zoom) * slope;\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 pointSizeStops: PointSizeStop[] = clonePointSizeStops(DEFAULT_POINT_SIZE_STOPS);\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\t\tthis.pointSizeStops = normalizePointSizeStops(options.pointSizeByZoom);\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\tsetPointSizeByZoom(pointSizeByZoom: PointSizeByZoom | null | undefined): void {\n\t\tconst nextStops = normalizePointSizeStops(pointSizeByZoom);\n\t\tif (arePointSizeStopsEqual(this.pointSizeStops, nextStops)) return;\n\t\tthis.pointSizeStops = nextStops;\n\t\tthis.requestRender();\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 size = resolvePointSizeByZoomStops(continuousZoom, this.pointSizeStops);\n\t\treturn clamp(size, MIN_POINT_SIZE_PX, MAX_POINT_SIZE_PX);\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 MutableRefObject, 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 PointSizeByZoom, type WsiTileErrorEvent, WsiTileRenderer } from \"../wsi/wsi-tile-renderer\";\nimport type { BrushOptions, 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};\nconst POINT_HIT_RADIUS_SCALE = 0.65;\nconst MIN_POINT_HIT_RADIUS_PX = 4;\nconst MIN_POINT_HIT_GRID_SIZE = 24;\nconst MAX_POINT_HIT_GRID_SIZE = 1024;\nconst POINT_HIT_GRID_DENSITY_SCALE = 4;\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 PointHitEvent {\n index: number;\n id: number | null;\n coordinate: DrawCoordinate;\n pointCoordinate: DrawCoordinate;\n}\n\nexport interface PointClickEvent extends PointHitEvent {\n button: number;\n}\n\nexport interface PointHoverEvent {\n index: number | null;\n id: number | null;\n coordinate: DrawCoordinate | null;\n pointCoordinate: DrawCoordinate | null;\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\ninterface PointSpatialIndex {\n cellSize: number;\n safeCount: number;\n positions: Float32Array;\n ids: Uint32Array | null;\n buckets: Map<number, Map<number, number[]>>;\n}\n\nfunction sanitizePointCount(pointData: WsiPointData): number {\n return Math.max(0, Math.min(Math.floor(pointData.count ?? 0), Math.floor((pointData.positions?.length ?? 0) / 2), pointData.paletteIndices?.length ?? 0));\n}\n\nfunction sanitizeDrawIndices(drawIndices: Uint32Array | undefined, maxExclusive: number): Uint32Array | null {\n if (!(drawIndices instanceof Uint32Array) || maxExclusive <= 0 || drawIndices.length === 0) {\n return null;\n }\n\n let invalidFound = false;\n for (let i = 0; i < drawIndices.length; i += 1) {\n if (drawIndices[i] < maxExclusive) continue;\n invalidFound = true;\n break;\n }\n if (!invalidFound) {\n return drawIndices;\n }\n\n const out = new Uint32Array(drawIndices.length);\n let cursor = 0;\n for (let i = 0; i < drawIndices.length; i += 1) {\n const idx = drawIndices[i];\n if (idx >= maxExclusive) continue;\n out[cursor] = idx;\n cursor += 1;\n }\n return out.subarray(0, cursor);\n}\n\nfunction resolvePointHitGridSize(source: WsiImageSource | null, visibleCount: number): number {\n if (!source || visibleCount <= 0) return 256;\n const area = Math.max(1, source.width * source.height);\n const avgSpacing = Math.sqrt(area / Math.max(1, visibleCount));\n const raw = avgSpacing * POINT_HIT_GRID_DENSITY_SCALE;\n return Math.max(MIN_POINT_HIT_GRID_SIZE, Math.min(MAX_POINT_HIT_GRID_SIZE, raw));\n}\n\nfunction buildPointSpatialIndex(pointData: WsiPointData | null | undefined, source: WsiImageSource | null): PointSpatialIndex | null {\n if (!pointData || !pointData.positions || !pointData.paletteIndices) {\n return null;\n }\n\n const safeCount = sanitizePointCount(pointData);\n if (safeCount <= 0) {\n return null;\n }\n\n const positions = pointData.positions.subarray(0, safeCount * 2);\n const ids = pointData.ids instanceof Uint32Array && pointData.ids.length >= safeCount ? pointData.ids.subarray(0, safeCount) : null;\n const drawIndices = sanitizeDrawIndices(pointData.drawIndices, safeCount);\n const visibleCount = drawIndices ? drawIndices.length : safeCount;\n if (visibleCount === 0) {\n return null;\n }\n\n const cellSize = resolvePointHitGridSize(source, visibleCount);\n const buckets = new Map<number, Map<number, number[]>>();\n\n const pushBucket = (pointIndex: number): void => {\n const px = positions[pointIndex * 2];\n const py = positions[pointIndex * 2 + 1];\n if (!Number.isFinite(px) || !Number.isFinite(py)) return;\n\n const cellX = Math.floor(px / cellSize);\n const cellY = Math.floor(py / cellSize);\n let column = buckets.get(cellX);\n if (!column) {\n column = new Map<number, number[]>();\n buckets.set(cellX, column);\n }\n const bucket = column.get(cellY);\n if (bucket) {\n bucket.push(pointIndex);\n } else {\n column.set(cellY, [pointIndex]);\n }\n };\n\n if (drawIndices) {\n for (let i = 0; i < drawIndices.length; i += 1) {\n pushBucket(drawIndices[i] ?? 0);\n }\n } else {\n for (let i = 0; i < safeCount; i += 1) {\n pushBucket(i);\n }\n }\n\n if (buckets.size === 0) {\n return null;\n }\n\n return {\n cellSize,\n safeCount,\n positions,\n ids,\n buckets,\n };\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 pointSizeByZoom?: PointSizeByZoom;\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 brushOptions?: BrushOptions;\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 onPointHover?: (event: PointHoverEvent) => void;\n onPointClick?: (event: PointClickEvent) => void;\n onRegionHover?: (event: RegionHoverEvent) => void;\n onRegionClick?: (event: RegionClickEvent) => void;\n onActiveRegionChange?: (regionId: string | number | null) => void;\n getCellByCoordinatesRef?: MutableRefObject<((coordinate: DrawCoordinate) => PointHitEvent | null) | null>;\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 pointSizeByZoom,\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 brushOptions,\n regionStrokeStyle,\n regionStrokeHoverStyle,\n regionStrokeActiveStyle,\n patchStrokeStyle,\n resolveRegionStrokeStyle,\n overlayShapes,\n customLayers,\n patchRegions,\n regionLabelStyle,\n onPointerWorldMove,\n onPointHover,\n onPointClick,\n onRegionHover,\n onRegionClick,\n onActiveRegionChange,\n getCellByCoordinatesRef,\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 hoveredPointIndexRef = useRef<number | null>(null);\n const hoveredPointIdRef = useRef<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 shouldEnablePointHitTest = Boolean(onPointHover || onPointClick || getCellByCoordinatesRef);\n const pointSpatialIndex = useMemo(() => {\n if (!shouldEnablePointHitTest) return null;\n return buildPointSpatialIndex(renderPointData, source);\n }, [shouldEnablePointHitTest, renderPointData, source]);\n\n const getCellByCoordinates = useCallback(\n (coordinate: DrawCoordinate): PointHitEvent | null => {\n const renderer = rendererRef.current;\n if (!renderer || !pointSpatialIndex) return null;\n\n const x = Number(coordinate[0]);\n const y = Number(coordinate[1]);\n if (!Number.isFinite(x) || !Number.isFinite(y)) return null;\n\n const zoom = Math.max(1e-6, renderer.getViewState().zoom);\n const pointSizePx = renderer.getPointSizeByZoom();\n const hitRadiusPx = Math.max(MIN_POINT_HIT_RADIUS_PX, pointSizePx * POINT_HIT_RADIUS_SCALE);\n const hitRadiusWorld = hitRadiusPx / zoom;\n if (!Number.isFinite(hitRadiusWorld) || hitRadiusWorld <= 0) return null;\n\n const cellSize = pointSpatialIndex.cellSize;\n const baseCellX = Math.floor(x / cellSize);\n const baseCellY = Math.floor(y / cellSize);\n const cellRadius = Math.max(1, Math.ceil(hitRadiusWorld / cellSize));\n const maxDist2 = hitRadiusWorld * hitRadiusWorld;\n\n let nearestIndex = -1;\n let nearestDist2 = maxDist2;\n let nearestX = 0;\n let nearestY = 0;\n\n for (let cx = baseCellX - cellRadius; cx <= baseCellX + cellRadius; cx += 1) {\n const column = pointSpatialIndex.buckets.get(cx);\n if (!column) continue;\n\n for (let cy = baseCellY - cellRadius; cy <= baseCellY + cellRadius; cy += 1) {\n const bucket = column.get(cy);\n if (!bucket || bucket.length === 0) continue;\n\n for (let i = 0; i < bucket.length; i += 1) {\n const pointIndex = bucket[i];\n if (pointIndex >= pointSpatialIndex.safeCount) continue;\n\n const px = pointSpatialIndex.positions[pointIndex * 2];\n const py = pointSpatialIndex.positions[pointIndex * 2 + 1];\n const dx = px - x;\n const dy = py - y;\n const dist2 = dx * dx + dy * dy;\n if (dist2 > nearestDist2) continue;\n\n nearestDist2 = dist2;\n nearestIndex = pointIndex;\n nearestX = px;\n nearestY = py;\n }\n }\n }\n\n if (nearestIndex < 0) return null;\n const pointId = pointSpatialIndex.ids ? Number(pointSpatialIndex.ids[nearestIndex]) : null;\n return {\n index: nearestIndex,\n id: pointId,\n coordinate: [x, y],\n pointCoordinate: [nearestX, nearestY],\n };\n },\n [pointSpatialIndex]\n );\n\n const emitPointHover = useCallback(\n (hit: PointHitEvent | null, coordinate: DrawCoordinate | null) => {\n if (!onPointHover) return;\n const nextIndex = hit?.index ?? null;\n const nextId = hit?.id ?? null;\n if (hoveredPointIndexRef.current === nextIndex && hoveredPointIdRef.current === nextId) return;\n hoveredPointIndexRef.current = nextIndex;\n hoveredPointIdRef.current = nextId;\n onPointHover({\n index: nextIndex,\n id: nextId,\n coordinate,\n pointCoordinate: hit?.pointCoordinate ?? null,\n });\n },\n [onPointHover]\n );\n\n const emitPointClick = useCallback(\n (coordinate: DrawCoordinate, button: number) => {\n if (!onPointClick) return;\n const hit = getCellByCoordinates(coordinate);\n if (!hit) return;\n onPointClick({\n ...hit,\n button,\n });\n },\n [onPointClick, getCellByCoordinates]\n );\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 useEffect(() => {\n if (!getCellByCoordinatesRef) return;\n getCellByCoordinatesRef.current = getCellByCoordinates;\n return () => {\n if (getCellByCoordinatesRef.current === getCellByCoordinates) {\n getCellByCoordinatesRef.current = null;\n }\n };\n }, [getCellByCoordinatesRef, getCellByCoordinates]);\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 useEffect(() => {\n const hoveredPointIndex = hoveredPointIndexRef.current;\n if (hoveredPointIndex === null) return;\n if (pointSpatialIndex && hoveredPointIndex < pointSpatialIndex.safeCount) return;\n hoveredPointIndexRef.current = null;\n hoveredPointIdRef.current = null;\n onPointHover?.({\n index: null,\n id: null,\n coordinate: null,\n pointCoordinate: null,\n });\n }, [pointSpatialIndex, onPointHover]);\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 useEffect(() => {\n if (drawTool === \"cursor\") return;\n if (hoveredPointIndexRef.current === null) return;\n hoveredPointIndexRef.current = null;\n hoveredPointIdRef.current = null;\n onPointHover?.({\n index: null,\n id: null,\n coordinate: null,\n pointCoordinate: null,\n });\n }, [drawTool, onPointHover]);\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 emitPointHover(null, null);\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) {\n emitPointHover(null, null);\n return;\n }\n\n if (onPointHover) {\n emitPointHover(getCellByCoordinates(coord), coord);\n }\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, emitPointHover, getCellByCoordinates, onPointHover]\n );\n\n const handleRegionPointerLeave = useCallback(() => {\n onPointerWorldMove?.({\n coordinate: null,\n clientX: -1,\n clientY: -1,\n insideImage: false,\n });\n emitPointHover(null, null);\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, emitPointHover]);\n\n const handleRegionClick = useCallback(\n (event: ReactMouseEvent<HTMLDivElement>) => {\n if (drawTool !== \"cursor\") return;\n if (event.target !== canvasRef.current) return;\n\n const coord = resolveWorldCoord(event.clientX, event.clientY);\n if (!coord) return;\n emitPointClick(coord, event.button);\n\n if (!effectiveRoiRegions.length) {\n commitActiveRegion(null);\n return;\n }\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, emitPointClick]\n );\n\n const handleBrushTap = useCallback(\n (coord: DrawCoordinate): boolean => {\n if (drawTool !== \"brush\") return false;\n if (brushOptions?.clickSelectRoi !== true) return false;\n if (!effectiveRoiRegions.length) return false;\n\n const hit = pickRegionAt(coord, effectiveRoiRegions);\n if (!hit) return false;\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 return true;\n },\n [drawTool, brushOptions?.clickSelectRoi, effectiveRoiRegions, activeRegionId, commitActiveRegion, onRegionClick]\n );\n\n const handleRegionContextMenu = useCallback(\n (event: ReactMouseEvent<HTMLDivElement>) => {\n if (!onPointClick) return;\n if (drawTool !== \"cursor\") return;\n if (event.target !== canvasRef.current) return;\n event.preventDefault();\n const coord = resolveWorldCoord(event.clientX, event.clientY);\n if (!coord) return;\n emitPointClick(coord, event.button);\n },\n [drawTool, resolveWorldCoord, emitPointClick, onPointClick]\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 pointSizeByZoom,\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, pointSizeByZoom, 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.setPointSizeByZoom(pointSizeByZoom);\n }, [pointSizeByZoom]);\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} onContextMenu={handleRegionContextMenu}>\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 brushOptions={brushOptions}\n projectorRef={rendererRef}\n onBrushTap={handleBrushTap}\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_MIN_RASTER_STEP","DEFAULT_MAX_RASTER_PIXELS","DEFAULT_MAX_RASTER_SIZE","DEFAULT_CIRCLE_SIDES","MIN_RADIUS","ALPHA_THRESHOLD","clamp","value","min","max","closeRing","coordinates","out","x","y","first","last","sanitizePath","points","point","prev","createCirclePolygon","center","radius","sides","ring","t","createBoundsFallback","minX","minY","maxX","maxY","pad","computeExpandedBounds","resolveRasterConfig","bounds","minRasterStep","maxRasterPixels","maxRasterSize","widthWorld","heightWorld","step","padding","createRasterContext","worldToRaster","config","rasterizeStrokeMask","path","p","i","image","buildBoundaryEdges","mask","edges","vertex","at","turnPriority","fromDir","toDir","delta","traceLoops","outgoing","entry","used","loops","startVertex","currentVertex","currentDir","loop","guard","guardLimit","candidates","bestIndex","bestPriority","edgeIndex","candidate","priority","toWorldRing","vertexLoop","id","polygonSignedArea","sum","a","b","removeCollinearVertices","epsilon","closed","curr","cross","pointLineDistanceSquared","abx","aby","len2","dx","dy","simplifyRdp","tolerance","keep","tolerance2","stack","start","end","maxDist2","split","dist2","simplifyClosedRing","open","simplified","clampRingToBounds","buildBrushStrokePolygon","circleSides","raster","bestRing","bestArea","area","DEFAULT_POINT_COLOR","calcScaleResolution","imageMpp","imageZoom","currentZoom","mpp","z0","z1","calcScaleLength","length","unit","isSameViewState","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","WHEEL_ZOOM_IN_FACTOR","WHEEL_ZOOM_OUT_FACTOR","DEFAULT_BRUSH_RADIUS","DEFAULT_BRUSH_FILL_COLOR","DEFAULT_BRUSH_FILL_OPACITY","DEFAULT_BRUSH_CURSOR_COLOR","DEFAULT_BRUSH_CURSOR_ACTIVE_COLOR","DEFAULT_BRUSH_CURSOR_LINE_WIDTH","DEFAULT_BRUSH_CURSOR_DASH","DEFAULT_BRUSH_EDGE_DETAIL","MIN_BRUSH_EDGE_DETAIL","MAX_BRUSH_EDGE_DETAIL","MIN_BRUSH_RASTER_STEP","BRUSH_RASTER_DIAMETER_SAMPLES","BRUSH_SCREEN_STEP","DEFAULT_REGION_STROKE_STYLE","DEFAULT_PATCH_STROKE_STYLE","DEFAULT_REGION_LABEL_STYLE","isStampTool","tool","clampPositiveOrFallback","fallback","resolveStampOptions","clampUnitOpacity","sanitizeBrushLineDash","item","resolveBrushEdgeDetail","resolveBrushOptions","cursorLineWidth","edgeDetail","mm2ToUm2","areaMm2","createSquareFromCenter","halfLength","createCircleFromCenter","coords","createRectangle","createCircle","centerX","centerY","polygonArea","computeBounds","isValidPolygon","tracePath","ctx","close","drawPath","strokeStyle","fill","resolveStrokeStyle","style","dash","shadowBlur","shadowOffsetX","shadowOffsetY","mergeStrokeStyle","base","override","isSameRegionId","isNestedRingCoordinates","isFiniteNumber","isCoordinatePair","isCoordinateRing","collectOverlayRings","normalizeOverlayRings","sourceRings","normalized","drawInvertedFillMask","outerRing","holeRings","fillColor","resolveLabelStyle","px","py","bw","oy","br","drawRoundedRect","r","getTopAnchor","drawRegionLabel","text","anchor","canvasWidth","canvasHeight","labelStyle","label","boxWidth","boxHeight","left","top","clampWorld","coord","imageWidth","imageHeight","toCoord","DrawLayer","stampOptions","brushOptions","projectorRef","onBrushTap","onDrawComplete","onPatchComplete","enabled","viewStateSignal","persistedRegions","patchRegions","persistedPolygons","regionStrokeStyle","regionStrokeHoverStyle","regionStrokeActiveStyle","patchStrokeStyle","resolveRegionStrokeStyle","overlayShapes","hoveredRegionId","activeRegionId","regionLabelStyle","invalidateRef","className","canvasRef","useRef","drawPendingRef","overlayDebugSnapshotRef","lastToolRef","sessionRef","active","mergedPersistedRegions","useMemo","index","mergedPatchRegions","resolvedStrokeStyle","resolvedHoverStrokeStyle","resolvedActiveStrokeStyle","resolvedPatchStrokeStyle","resolvedLabelStyle","resolvedStampOptions","resolvedBrushOptions","mergedStyle","resizeCanvas","useCallback","w","h","worldToScreenPoints","projector","worldRadiusToScreenPixels","worldRadius","micronsToWorldPixels","lengthUm","mppValue","imageZoomValue","viewZoomRaw","viewZoom","continuousZoom","umPerScreenPixel","buildStampCoords","stampTool","areaUm2","buildPreviewCoords","session","drawBrushStrokePreview","screenPoints","radiusPx","drawBrushCursor","cursor","screen","drawOverlay","region","regionKey","state","resolved","debugOverlay","imageOuterRing","shape","renderRings","closedRings","debugKey","debugSignature","preview","line","polygon","anchorWorld","anchorScreen","requestDraw","resetSession","preserveCursor","toWorld","event","raw","finishSession","tapPoint","handleStampAt","intent","result","appendBrushPoint","world","minWorldStep","minWorldStep2","handlePointerDown","handlePointerMove","handlePointerUp","handlePointerLeave","changed","useEffect","observer","onKeyDown","jsx","screenX","screenY","trimTrailingSlash","ensureLeadingSlash","joinImsTileRoot","tileBaseUrl","parsed","origin","normalizeImageInfo","ims","isIms","tileSize","maxTierZoom","tilePath","normalizedPath","imsTileRoot","tileUrlBuilder","tier","toTileUrl","DEFAULT_OVERVIEW_MAP_OPTIONS","toPositiveNumber","isFiniteBounds","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","pointIds","nextPositions","nextTerms","nextIds","output","filterPointIndicesByPolygons","contextPromise","BBOX_PREFILTER_SHADER","hasWebGpu","nav","getNavigatorGpu","gpu","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","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","data","drawIndices","visibleCount","pointIndex","compactData","workerInstance","workerSupported","requestId","pendingById","createWorker","worker","_documentCurrentScript","handleWorkerMessage","handleWorkerError","msg","pending","indices","paletteIndices","ids","terminateRoiClipWorker","filterPointDataByPolygonsInWorker","positionsCopy","termsCopy","idsCopy","startMs","resolve","reject","transfer","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","visibleKeys","nextQueue","key","earliestReadyAt","delay","now","controller","inflightEntry","nextAttempt","retryDelay","existing","attempt","exp","jitter","DEFAULT_ROTATION_DRAG_SENSITIVITY","MIN_POINT_SIZE_PX","MAX_POINT_SIZE_PX","DEFAULT_POINT_SIZE_STOPS","rad","toRadians","cos","sin","rx","ry","deg","name","isSameArrayView","clonePointSizeStops","stops","stop","normalizePointSizeStops","pointSizeByZoom","zoomKey","rawSize","size","arePointSizeStopsEqual","resolvePointSizeByZoomStops","span","slope","WsiTileRenderer","attemptCount","paletteSize","nextPaletteIndices","hasDrawIndices","nextDrawIndices","geometryChanged","drawIndicesChanged","maxExclusive","validCount","locked","nextStops","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","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","POINT_HIT_RADIUS_SCALE","MIN_POINT_HIT_RADIUS_PX","MIN_POINT_HIT_GRID_SIZE","MAX_POINT_HIT_GRID_SIZE","POINT_HIT_GRID_DENSITY_SCALE","sanitizeDrawIndices","invalidFound","resolvePointHitGridSize","buildPointSpatialIndex","cellSize","buckets","pushBucket","cellX","cellY","column","bucket","resolveRegionId","isPointInPolygon","pickRegionAt","WsiViewerCanvas","onViewStateChange","onStats","onTileError","onContextLost","onContextRestored","debugOverlayStyle","fitNonce","rotationResetNonce","ctrlDragRotate","pointPalette","roiRegions","roiPolygons","clipPointsToRois","clipMode","onClipStats","onRoiPointGroups","roiPaletteIndexToTermId","interactionLock","drawTool","customLayers","onPointerWorldMove","onPointHover","onPointClick","onRegionHover","onRegionClick","onActiveRegionChange","getCellByCoordinatesRef","showOverviewMap","overviewMapOptions","drawInvalidateRef","overviewInvalidateRef","onViewStateChangeRef","onStatsRef","debugOverlayRef","isOverviewOpen","setIsOverviewOpen","useState","setHoveredRegionId","setActiveRegionId","customLayerViewState","setCustomLayerViewState","debugStats","setDebugStats","hoveredRegionIdRef","hoveredPointIndexRef","hoveredPointIdRef","clipRunIdRef","safeRoiRegions","safePatchRegions","safeRoiPolygons","shouldTrackCustomLayerViewState","mergedDebugOverlayStyle","effectiveRoiRegions","clipPolygons","renderPointData","setRenderPointData","runId","applyResult","stats","outputCount","shouldEnablePointHitTest","pointSpatialIndex","getCellByCoordinates","coordinate","pointSizePx","hitRadiusWorld","baseCellX","baseCellY","cellRadius","nearestIndex","nearestDist2","nearestX","nearestY","cx","cy","pointId","emitPointHover","hit","nextIndex","nextId","emitPointClick","button","overviewHeight","overviewMargin","overviewPosition","commitActiveRegion","handleRendererStats","debugOverlayText","currentHover","hoveredPointIndex","emitViewStateChange","callback","resolveWorldCoord","resolveScreenCoord","requestCustomLayerRedraw","effectiveCustomLayerViewState","customLayerContext","viewStateForLayer","handleRegionPointerMove","isCanvasEvent","insideImage","nextHoverId","prevHoverId","handleRegionPointerLeave","handleRegionClick","nextActive","handleBrushTap","handleRegionContextMenu","jsxs","layer","Fragment"],"mappings":"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"}
|