open-plant 1.2.20 → 1.2.21
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 +4 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +483 -488
- package/dist/index.js.map +1 -1
- package/dist/types/react/overview-map.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/roi-geometry.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\tsmoothingPasses?: 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 DEFAULT_SMOOTHING_PASSES = 1;\nconst MAX_SMOOTHING_PASSES = 4;\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 smoothClosedRingChaikin(\n\tring: BrushStrokeCoordinate[],\n\titerations: number,\n): BrushStrokeCoordinate[] {\n\tlet out = closeRing(ring);\n\tif (iterations <= 0 || out.length < 5) return out;\n\n\tfor (let pass = 0; pass < iterations; pass += 1) {\n\t\tconst open = out.slice(0, -1);\n\t\tif (open.length < 3) break;\n\t\tconst next: BrushStrokeCoordinate[] = [];\n\t\tfor (let i = 0; i < open.length; i += 1) {\n\t\t\tconst a = open[i];\n\t\t\tconst b = open[(i + 1) % open.length];\n\t\t\tnext.push(\n\t\t\t\t[a[0] * 0.75 + b[0] * 0.25, a[1] * 0.75 + b[1] * 0.25],\n\t\t\t\t[a[0] * 0.25 + b[0] * 0.75, a[1] * 0.25 + b[1] * 0.75],\n\t\t\t);\n\t\t}\n\t\tout = closeRing(next);\n\t}\n\treturn out;\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 smoothingPasses =\n\t\ttypeof options.smoothingPasses === \"number\" && Number.isFinite(options.smoothingPasses)\n\t\t\t? Math.round(clamp(options.smoothingPasses, 0, MAX_SMOOTHING_PASSES))\n\t\t\t: DEFAULT_SMOOTHING_PASSES;\n\tconst simplified = simplifyClosedRing(\n\t\tsmoothClosedRingChaikin(\n\t\t\tremoveCollinearVertices(bestRing, raster.step * 1e-3),\n\t\t\tsmoothingPasses,\n\t\t),\n\t\ttolerance,\n\t);\n\treturn clampRingToBounds(simplified, options.clipBounds);\n}\n","export type RoiCoordinate = [number, number];\nexport type RoiLinearRing = RoiCoordinate[];\nexport type RoiPolygonRings = RoiLinearRing[];\nexport type RoiMultiPolygon = RoiPolygonRings[];\nexport type RoiGeometry = RoiLinearRing | RoiPolygonRings | RoiMultiPolygon;\n\nexport interface PreparedRoiPolygon {\n\touter: RoiLinearRing;\n\tholes: RoiLinearRing[];\n\tminX: number;\n\tminY: number;\n\tmaxX: number;\n\tmaxY: number;\n\tarea: number;\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n\treturn typeof value === \"number\" && Number.isFinite(value);\n}\n\nfunction isCoordinatePair(value: unknown): value is RoiCoordinate {\n\treturn (\n\t\tArray.isArray(value) &&\n\t\tvalue.length >= 2 &&\n\t\tisFiniteNumber(value[0]) &&\n\t\tisFiniteNumber(value[1])\n\t);\n}\n\nfunction isLinearRing(value: unknown): value is RoiLinearRing {\n\treturn Array.isArray(value) && value.length > 0 && value.every(point => isCoordinatePair(point));\n}\n\nfunction isPolygonRings(value: unknown): value is RoiPolygonRings {\n\treturn Array.isArray(value) && value.length > 0 && value.every(ring => isLinearRing(ring));\n}\n\nfunction isMultiPolygon(value: unknown): value is RoiMultiPolygon {\n\treturn Array.isArray(value) && value.length > 0 && value.every(polygon => isPolygonRings(polygon));\n}\n\nexport function closeRoiRing(coordinates: readonly RoiCoordinate[]): RoiLinearRing {\n\tif (!Array.isArray(coordinates) || coordinates.length < 3) return [];\n\tconst out: RoiLinearRing = [];\n\tfor (const point of coordinates) {\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 && prev[0] === x && prev[1] === y) continue;\n\t\tout.push([x, y]);\n\t}\n\tif (out.length < 3) return [];\n\tconst first = out[0];\n\tconst last = out[out.length - 1];\n\tif (first[0] !== last[0] || first[1] !== last[1]) {\n\t\tout.push([first[0], first[1]]);\n\t}\n\treturn out.length >= 4 ? out : [];\n}\n\nexport function polygonSignedArea(ring: RoiLinearRing): number {\n\tif (!Array.isArray(ring) || 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 normalizePolygonRings(rings: RoiPolygonRings): RoiPolygonRings {\n\tif (!Array.isArray(rings) || rings.length === 0) return [];\n\tconst normalized: RoiLinearRing[] = [];\n\tfor (const ring of rings) {\n\t\tconst closed = closeRoiRing(ring);\n\t\tif (closed.length >= 4) normalized.push(closed);\n\t}\n\tif (normalized.length === 0) return [];\n\tif (normalized.length === 1) return [normalized[0]];\n\n\tlet outerIndex = 0;\n\tlet outerArea = 0;\n\tfor (let i = 0; i < normalized.length; i += 1) {\n\t\tconst area = Math.abs(polygonSignedArea(normalized[i]));\n\t\tif (area <= outerArea) continue;\n\t\touterArea = area;\n\t\touterIndex = i;\n\t}\n\n\tconst out: RoiPolygonRings = [normalized[outerIndex]];\n\tfor (let i = 0; i < normalized.length; i += 1) {\n\t\tif (i === outerIndex) continue;\n\t\tout.push(normalized[i]);\n\t}\n\treturn out;\n}\n\nexport function normalizeRoiGeometry(geometry: RoiGeometry | null | undefined): RoiMultiPolygon {\n\tif (!geometry) return [];\n\n\tif (isLinearRing(geometry)) {\n\t\tconst polygon = normalizePolygonRings([geometry]);\n\t\treturn polygon.length > 0 ? [polygon] : [];\n\t}\n\n\tif (isPolygonRings(geometry)) {\n\t\tconst polygon = normalizePolygonRings(geometry);\n\t\treturn polygon.length > 0 ? [polygon] : [];\n\t}\n\n\tif (isMultiPolygon(geometry)) {\n\t\tconst out: RoiMultiPolygon = [];\n\t\tfor (const polygon of geometry) {\n\t\t\tconst normalized = normalizePolygonRings(polygon);\n\t\t\tif (normalized.length > 0) out.push(normalized);\n\t\t}\n\t\treturn out;\n\t}\n\n\treturn [];\n}\n\nexport function pointInRing(x: number, y: number, ring: RoiLinearRing): 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\nexport function pointInPolygonWithHoles(\n\tx: number,\n\ty: number,\n\tpolygon: RoiPolygonRings,\n): boolean {\n\tif (!Array.isArray(polygon) || polygon.length === 0) return false;\n\tconst outer = polygon[0];\n\tif (!outer || outer.length < 4) return false;\n\tif (!pointInRing(x, y, outer)) return false;\n\tfor (let i = 1; i < polygon.length; i += 1) {\n\t\tconst hole = polygon[i];\n\t\tif (!hole || hole.length < 4) continue;\n\t\tif (pointInRing(x, y, hole)) return false;\n\t}\n\treturn true;\n}\n\nexport function prepareRoiPolygons(\n\tgeometries: readonly (RoiGeometry | null | undefined)[] | null | undefined,\n): PreparedRoiPolygon[] {\n\tconst prepared: PreparedRoiPolygon[] = [];\n\tfor (const geometry of geometries ?? []) {\n\t\tconst multipolygon = normalizeRoiGeometry(geometry);\n\t\tfor (const polygon of multipolygon) {\n\t\t\tconst outer = polygon[0];\n\t\t\tif (!outer || outer.length < 4) continue;\n\t\t\tlet minX = Infinity;\n\t\t\tlet minY = Infinity;\n\t\t\tlet maxX = -Infinity;\n\t\t\tlet maxY = -Infinity;\n\t\t\tfor (const [x, y] of outer) {\n\t\t\t\tif (x < minX) minX = x;\n\t\t\t\tif (x > maxX) maxX = x;\n\t\t\t\tif (y < minY) minY = y;\n\t\t\t\tif (y > maxY) maxY = y;\n\t\t\t}\n\t\t\tif (\n\t\t\t\t!Number.isFinite(minX) ||\n\t\t\t\t!Number.isFinite(minY) ||\n\t\t\t\t!Number.isFinite(maxX) ||\n\t\t\t\t!Number.isFinite(maxY)\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlet area = Math.abs(polygonSignedArea(outer));\n\t\t\tfor (let i = 1; i < polygon.length; i += 1) {\n\t\t\t\tarea -= Math.abs(polygonSignedArea(polygon[i]));\n\t\t\t}\n\t\t\tprepared.push({\n\t\t\t\touter,\n\t\t\t\tholes: polygon.slice(1),\n\t\t\t\tminX,\n\t\t\t\tminY,\n\t\t\t\tmaxX,\n\t\t\t\tmaxY,\n\t\t\t\tarea: Math.max(1e-6, area),\n\t\t\t});\n\t\t}\n\t}\n\treturn prepared;\n}\n\nexport function pointInPreparedPolygon(\n\tx: number,\n\ty: number,\n\tpolygon: PreparedRoiPolygon,\n): boolean {\n\tif (x < polygon.minX || x > polygon.maxX || y < polygon.minY || y > polygon.maxY) {\n\t\treturn false;\n\t}\n\tif (!pointInRing(x, y, polygon.outer)) return false;\n\tfor (const hole of polygon.holes) {\n\t\tif (pointInRing(x, y, hole)) return false;\n\t}\n\treturn true;\n}\n\nexport function pointInAnyPreparedPolygon(\n\tx: number,\n\ty: number,\n\tpolygons: readonly PreparedRoiPolygon[],\n): boolean {\n\tfor (const polygon of polygons) {\n\t\tif (!pointInPreparedPolygon(x, y, polygon)) continue;\n\t\treturn true;\n\t}\n\treturn false;\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 { normalizeRoiGeometry, type RoiGeometry } from \"../wsi/roi-geometry\";\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];\nexport type DrawRegionCoordinates = DrawCoordinate[] | DrawCoordinate[][] | DrawCoordinate[][][];\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: DrawRegionCoordinates;\n label?: string;\n}\n\nexport interface RegionStyleContext {\n region: DrawRegion;\n regionId: string | number;\n regionIndex: number;\n state: \"default\" | \"hover\" | \"active\";\n}\n\nexport type RegionStrokeStyleResolver = (context: RegionStyleContext) => Partial<RegionStrokeStyle> | null | undefined;\n\nexport interface RegionLabelStyleContext {\n region: DrawRegion;\n regionId: string | number;\n regionIndex: number;\n zoom: number;\n}\n\nexport type RegionLabelStyleResolver = (context: RegionLabelStyleContext) => Partial<RegionLabelStyle> | 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 DrawAreaTooltipStyle {\n fontFamily: string;\n fontSize: number;\n fontWeight: string | number;\n textColor: string;\n backgroundColor: string;\n borderRadius: number;\n paddingX: number;\n paddingY: number;\n}\n\nexport interface DrawAreaTooltipOptions {\n enabled?: boolean;\n format?: (areaMm2: number) => string;\n style?: Partial<DrawAreaTooltipStyle>;\n cursorOffset?: {\n x: number;\n y: number;\n };\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 getZoomRange?: () => { minZoom: number; maxZoom: 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 /**\n * Brush radius in HTML/CSS pixels (px).\n * This value is zoom-invariant: the on-screen brush size stays fixed.\n */\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 * Post-smoothing passes for brush outline to reduce stair-stepping.\n * Range: 0 ~ 4. Default: 1.\n */\n edgeSmoothing?: 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?: DrawRegionCoordinates[];\n drawFillColor?: string;\n regionStrokeStyle?: Partial<RegionStrokeStyle>;\n regionStrokeHoverStyle?: Partial<RegionStrokeStyle>;\n regionStrokeActiveStyle?: Partial<RegionStrokeStyle>;\n patchStrokeStyle?: Partial<RegionStrokeStyle>;\n resolveRegionStrokeStyle?: RegionStrokeStyleResolver;\n resolveRegionLabelStyle?: RegionLabelStyleResolver;\n overlayShapes?: DrawOverlayShape[];\n hoveredRegionId?: string | number | null;\n activeRegionId?: string | number | null;\n regionLabelStyle?: Partial<RegionLabelStyle>;\n drawAreaTooltip?: DrawAreaTooltipOptions;\n autoLiftRegionLabelAtMaxZoom?: boolean;\n regionLabelAutoLiftOffsetPx?: number;\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 cursorScreen: DrawCoordinate | null;\n points: DrawCoordinate[];\n screenPoints: DrawCoordinate[];\n stampCenter: DrawCoordinate | null;\n}\n\ninterface NormalizedDrawRegionPolygon {\n outer: DrawCoordinate[];\n holes: DrawCoordinate[][];\n}\n\ninterface PreparedRenderedRegion {\n region: DrawRegion;\n regionIndex: number;\n regionKey: string | number;\n polygons: NormalizedDrawRegionPolygon[];\n}\n\ninterface ResolvedBrushOptions {\n radius: number;\n edgeDetail: number;\n edgeSmoothing: number;\n clickSelectRoi: boolean;\n fillColor: string;\n fillOpacity: number;\n cursorColor: string;\n cursorActiveColor: string;\n cursorLineWidth: number;\n cursorLineDash: number[];\n}\n\ninterface ResolvedDrawAreaTooltipOptions {\n enabled: boolean;\n format: (areaMm2: number) => string;\n style: DrawAreaTooltipStyle;\n cursorOffsetX: number;\n cursorOffsetY: number;\n}\n\nconst DRAW_FILL = \"rgba(255, 77, 79, 0.16)\";\nconst DEFAULT_DRAW_PREVIEW_FILL = \"transparent\";\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 DEFAULT_BRUSH_EDGE_SMOOTHING = 1;\nconst MIN_BRUSH_EDGE_SMOOTHING = 0;\nconst MAX_BRUSH_EDGE_SMOOTHING = 4;\nconst MIN_BRUSH_RASTER_STEP = 0.05;\nconst BRUSH_RASTER_DIAMETER_SAMPLES = 256;\nconst BRUSH_SCREEN_STEP = 1.5; // CSS px\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 REGION_INTERACTION_SHADOW_COLOR = \"rgba(23, 23, 25, 0.1)\";\nconst REGION_INTERACTION_SHADOW_WIDTH = 6;\n\nconst DEFAULT_REGION_LABEL_STYLE: RegionLabelStyle = {\n fontFamily: \"Pretendard, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\",\n fontSize: 11,\n fontWeight: 600,\n textColor: \"#171719\",\n backgroundColor: \"#FFCC00\",\n borderColor: \"rgba(0, 0, 0, 0)\",\n borderWidth: 0,\n paddingX: 8,\n paddingY: 4,\n offsetY: 10,\n borderRadius: 4,\n};\n\nconst DEFAULT_DRAW_AREA_TOOLTIP_STYLE: DrawAreaTooltipStyle = {\n fontFamily: \"Pretendard, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\",\n fontSize: 13,\n fontWeight: 500,\n textColor: \"#FFFFFF\",\n backgroundColor: \"rgba(23, 23, 25, 0.5)\",\n borderRadius: 4,\n paddingX: 6,\n paddingY: 3,\n};\n\nconst DEFAULT_DRAW_AREA_TOOLTIP_OFFSET = {\n x: 16,\n y: -24,\n} as const;\nconst REGION_LABEL_AUTO_LIFT_MAX_OFFSET_PX = 20;\nconst REGION_LABEL_AUTO_LIFT_MAX_EPSILON = 1e-6;\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, value));\n}\n\nexport function resolveRegionLabelAutoLiftOffsetPx(\n enabled: boolean | undefined,\n zoom: number,\n zoomRange: { minZoom: number; maxZoom: number } | null | undefined\n): number {\n if (!enabled) return 0;\n if (!zoomRange) return 0;\n\n const minZoom = Number(zoomRange.minZoom);\n const maxZoom = Number(zoomRange.maxZoom);\n if (!Number.isFinite(minZoom) || !Number.isFinite(maxZoom)) return 0;\n\n if (maxZoom - minZoom <= REGION_LABEL_AUTO_LIFT_MAX_EPSILON) return 0;\n if (!Number.isFinite(zoom)) return 0;\n return zoom >= maxZoom - REGION_LABEL_AUTO_LIFT_MAX_EPSILON ? REGION_LABEL_AUTO_LIFT_MAX_OFFSET_PX : 0;\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 resolveBrushEdgeSmoothing(value: number | undefined): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return DEFAULT_BRUSH_EDGE_SMOOTHING;\n return Math.round(clamp(value, MIN_BRUSH_EDGE_SMOOTHING, MAX_BRUSH_EDGE_SMOOTHING));\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 const edgeSmoothing = resolveBrushEdgeSmoothing(options?.edgeSmoothing);\n return {\n radius,\n edgeDetail,\n edgeSmoothing,\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(\n center: DrawCoordinate | null,\n halfLength: number,\n projection?: {\n worldToScreen: (x: number, y: number) => DrawCoordinate | null;\n screenToWorld: (screen: DrawCoordinate) => DrawCoordinate | null;\n },\n): DrawCoordinate[] {\n if (!center || !Number.isFinite(halfLength) || halfLength <= 0) return [];\n\n if (projection) {\n const screenCenter = projection.worldToScreen(center[0], center[1]);\n const screenEdge = projection.worldToScreen(center[0] + halfLength, center[1]);\n if (screenCenter && screenEdge) {\n const screenHL = Math.hypot(screenEdge[0] - screenCenter[0], screenEdge[1] - screenCenter[1]);\n const screenCorners: DrawCoordinate[] = [\n [screenCenter[0] - screenHL, screenCenter[1] - screenHL],\n [screenCenter[0] + screenHL, screenCenter[1] - screenHL],\n [screenCenter[0] + screenHL, screenCenter[1] + screenHL],\n [screenCenter[0] - screenHL, screenCenter[1] + screenHL],\n ];\n const worldCorners: DrawCoordinate[] = [];\n for (const corner of screenCorners) {\n const world = projection.screenToWorld(corner);\n if (!world) throw new Error(\"Failed to create rectangle\");\n worldCorners.push(world);\n }\n return closeRing(worldCorners);\n }\n }\n\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(\n start: DrawCoordinate | null,\n end: DrawCoordinate | null,\n projection?: {\n worldToScreen: (x: number, y: number) => DrawCoordinate | null;\n screenToWorld: (screen: DrawCoordinate) => DrawCoordinate | null;\n },\n): DrawCoordinate[] {\n if (!start || !end) return [];\n\n if (projection) {\n const startScreen = projection.worldToScreen(start[0], start[1]);\n const endScreen = projection.worldToScreen(end[0], end[1]);\n\n if (startScreen && endScreen) {\n const screenCorners: DrawCoordinate[] = [\n [startScreen[0], startScreen[1]],\n [endScreen[0], startScreen[1]],\n [endScreen[0], endScreen[1]],\n [startScreen[0], endScreen[1]],\n ];\n const worldCorners: DrawCoordinate[] = [];\n for (const corner of screenCorners) {\n const world = projection.screenToWorld(corner);\n if (!world) return createRectangle(start, end);\n worldCorners.push(world);\n }\n return closeRing(worldCorners);\n }\n }\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(\n ctx: CanvasRenderingContext2D,\n points: DrawCoordinate[],\n strokeStyle: RegionStrokeStyle,\n close = false,\n fill = false,\n fillColor = DRAW_FILL\n): void {\n if (points.length === 0) return;\n\n ctx.beginPath();\n tracePath(ctx, points, close);\n if (fill && close) {\n ctx.fillStyle = fillColor;\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 resolveDrawPreviewFillColor(value: string | undefined): string {\n if (typeof value !== \"string\") return DEFAULT_DRAW_PREVIEW_FILL;\n const next = value.trim();\n return next.length > 0 ? next : DEFAULT_DRAW_PREVIEW_FILL;\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\nexport function resolveRegionLabelStyle(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\nexport function mergeRegionLabelStyle(base: RegionLabelStyle, override: Partial<RegionLabelStyle> | null | undefined): RegionLabelStyle {\n if (!override) return base;\n return resolveRegionLabelStyle({\n fontFamily: override.fontFamily ?? base.fontFamily,\n fontSize: override.fontSize ?? base.fontSize,\n fontWeight: override.fontWeight ?? base.fontWeight,\n textColor: override.textColor ?? base.textColor,\n backgroundColor: override.backgroundColor ?? base.backgroundColor,\n borderColor: override.borderColor ?? base.borderColor,\n borderWidth: override.borderWidth ?? base.borderWidth,\n paddingX: override.paddingX ?? base.paddingX,\n paddingY: override.paddingY ?? base.paddingY,\n offsetY: override.offsetY ?? base.offsetY,\n borderRadius: override.borderRadius ?? base.borderRadius,\n });\n}\n\nfunction resolveDrawAreaTooltipStyle(style: Partial<DrawAreaTooltipStyle> | undefined): DrawAreaTooltipStyle {\n const fontSize = typeof style?.fontSize === \"number\" && Number.isFinite(style.fontSize) ? Math.max(8, style.fontSize) : DEFAULT_DRAW_AREA_TOOLTIP_STYLE.fontSize;\n const borderRadius = typeof style?.borderRadius === \"number\" && Number.isFinite(style.borderRadius) ? Math.max(0, style.borderRadius) : DEFAULT_DRAW_AREA_TOOLTIP_STYLE.borderRadius;\n const paddingX = typeof style?.paddingX === \"number\" && Number.isFinite(style.paddingX) ? Math.max(0, style.paddingX) : DEFAULT_DRAW_AREA_TOOLTIP_STYLE.paddingX;\n const paddingY = typeof style?.paddingY === \"number\" && Number.isFinite(style.paddingY) ? Math.max(0, style.paddingY) : DEFAULT_DRAW_AREA_TOOLTIP_STYLE.paddingY;\n return {\n fontFamily: style?.fontFamily || DEFAULT_DRAW_AREA_TOOLTIP_STYLE.fontFamily,\n fontSize,\n fontWeight: style?.fontWeight || DEFAULT_DRAW_AREA_TOOLTIP_STYLE.fontWeight,\n textColor: style?.textColor || DEFAULT_DRAW_AREA_TOOLTIP_STYLE.textColor,\n backgroundColor: style?.backgroundColor || DEFAULT_DRAW_AREA_TOOLTIP_STYLE.backgroundColor,\n borderRadius,\n paddingX,\n paddingY,\n };\n}\n\nfunction resolveTooltipCursorOffset(value: DrawAreaTooltipOptions[\"cursorOffset\"]): { x: number; y: number } {\n const x = typeof value?.x === \"number\" && Number.isFinite(value.x) ? value.x : DEFAULT_DRAW_AREA_TOOLTIP_OFFSET.x;\n const y = typeof value?.y === \"number\" && Number.isFinite(value.y) ? value.y : DEFAULT_DRAW_AREA_TOOLTIP_OFFSET.y;\n return { x, y };\n}\n\nfunction defaultDrawAreaTooltipFormatter(areaMm2: number): string {\n if (!Number.isFinite(areaMm2)) return \"0.000 mm²\";\n return `${Math.max(0, areaMm2).toFixed(3)} mm²`;\n}\n\nfunction resolveDrawAreaTooltipOptions(options: DrawAreaTooltipOptions | undefined): ResolvedDrawAreaTooltipOptions {\n const format = typeof options?.format === \"function\" ? options.format : defaultDrawAreaTooltipFormatter;\n const cursorOffset = resolveTooltipCursorOffset(options?.cursorOffset);\n return {\n enabled: options?.enabled === true,\n format,\n style: resolveDrawAreaTooltipStyle(options?.style),\n cursorOffsetX: cursorOffset.x,\n cursorOffsetY: cursorOffset.y,\n };\n}\n\nfunction resolveRegionInteractionShadowStyle(strokeStyle: RegionStrokeStyle): RegionStrokeStyle {\n return {\n color: REGION_INTERACTION_SHADOW_COLOR,\n width: REGION_INTERACTION_SHADOW_WIDTH,\n lineDash: EMPTY_DASH,\n lineJoin: strokeStyle.lineJoin,\n lineCap: strokeStyle.lineCap,\n shadowColor: \"rgba(0, 0, 0, 0)\",\n shadowBlur: 0,\n shadowOffsetX: 0,\n shadowOffsetY: 0,\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 getTopAnchorFromPolygons(polygons: NormalizedDrawRegionPolygon[]): DrawCoordinate | null {\n let best: DrawCoordinate | null = null;\n for (const polygon of polygons) {\n const anchor = getTopAnchor(polygon.outer);\n if (!anchor) continue;\n if (!best || anchor[1] < best[1] || (anchor[1] === best[1] && anchor[0] < best[0])) {\n best = anchor;\n }\n }\n return best;\n}\n\nfunction normalizeDrawRegionPolygons(coordinates: DrawRegionCoordinates): NormalizedDrawRegionPolygon[] {\n const multipolygon = normalizeRoiGeometry(coordinates as RoiGeometry);\n if (multipolygon.length === 0) return [];\n\n const out: NormalizedDrawRegionPolygon[] = [];\n for (const polygon of multipolygon) {\n const outer = polygon[0];\n if (!outer || outer.length < 4) continue;\n const normalizedOuter = outer.map(([x, y]) => [x, y] as DrawCoordinate);\n const holes: DrawCoordinate[][] = [];\n for (let i = 1; i < polygon.length; i += 1) {\n const hole = polygon[i];\n if (!hole || hole.length < 4) continue;\n holes.push(hole.map(([x, y]) => [x, y] as DrawCoordinate));\n }\n out.push({\n outer: normalizedOuter,\n holes,\n });\n }\n return out;\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 drawAreaTooltipBox(\n ctx: CanvasRenderingContext2D,\n text: string,\n cursorScreen: DrawCoordinate,\n canvasWidth: number,\n canvasHeight: number,\n style: DrawAreaTooltipStyle,\n offsetX: number,\n offsetY: number\n): void {\n const label = text.trim();\n if (!label) return;\n\n ctx.save();\n ctx.font = `${style.fontWeight} ${style.fontSize}px ${style.fontFamily}`;\n ctx.textAlign = \"center\";\n ctx.textBaseline = \"middle\";\n\n const textWidth = ctx.measureText(label).width;\n const boxWidth = textWidth + style.paddingX * 2;\n const boxHeight = style.fontSize + style.paddingY * 2;\n\n const x = clamp(cursorScreen[0] + offsetX, boxWidth * 0.5 + 1, canvasWidth - boxWidth * 0.5 - 1);\n const y = clamp(cursorScreen[1] + 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 = style.backgroundColor;\n drawRoundedRect(ctx, left, top, boxWidth, boxHeight, style.borderRadius);\n ctx.fill();\n\n ctx.fillStyle = style.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 drawFillColor,\n regionStrokeStyle,\n regionStrokeHoverStyle,\n regionStrokeActiveStyle,\n patchStrokeStyle,\n resolveRegionStrokeStyle,\n resolveRegionLabelStyle: resolveRegionLabelStyleProp,\n overlayShapes,\n hoveredRegionId = null,\n activeRegionId = null,\n regionLabelStyle,\n drawAreaTooltip,\n autoLiftRegionLabelAtMaxZoom = false,\n regionLabelAutoLiftOffsetPx,\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 cursorScreen: null,\n points: [],\n screenPoints: [],\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 const preparedPersistedRegions = useMemo<PreparedRenderedRegion[]>(() => {\n const out: PreparedRenderedRegion[] = [];\n for (let i = 0; i < mergedPersistedRegions.length; i += 1) {\n const region = mergedPersistedRegions[i];\n const polygons = normalizeDrawRegionPolygons(region.coordinates);\n if (polygons.length === 0) continue;\n out.push({\n region,\n regionIndex: i,\n regionKey: region.id ?? i,\n polygons,\n });\n }\n return out;\n }, [mergedPersistedRegions]);\n const preparedPatchRegions = useMemo<PreparedRenderedRegion[]>(() => {\n const out: PreparedRenderedRegion[] = [];\n for (let i = 0; i < mergedPatchRegions.length; i += 1) {\n const region = mergedPatchRegions[i];\n const polygons = normalizeDrawRegionPolygons(region.coordinates);\n if (polygons.length === 0) continue;\n out.push({\n region,\n regionIndex: i,\n regionKey: region.id ?? i,\n polygons,\n });\n }\n return out;\n }, [mergedPatchRegions]);\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 const resolvedDrawPreviewFillColor = useMemo(() => resolveDrawPreviewFillColor(drawFillColor), [drawFillColor]);\n\n const resolvedLabelStyle = useMemo(() => resolveRegionLabelStyle(regionLabelStyle), [regionLabelStyle]);\n const resolvedDrawAreaTooltipOptions = useMemo(() => resolveDrawAreaTooltipOptions(drawAreaTooltip), [drawAreaTooltip]);\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 localScreenToWorld = useCallback(\n (screen: DrawCoordinate): DrawCoordinate | null => {\n const projector = projectorRef.current;\n const canvas = canvasRef.current;\n if (!projector || !canvas) return null;\n const rect = canvas.getBoundingClientRect();\n const raw = toCoord(projector.screenToWorld(rect.left + screen[0], rect.top + screen[1]));\n if (!raw) return null;\n return clampWorld(raw, imageWidth, imageHeight);\n },\n [projectorRef, imageWidth, imageHeight]\n );\n\n const getRectangleProjection = useCallback(() => {\n const projector = projectorRef.current;\n const rotationDeg = projector?.getViewState?.().rotationDeg ?? 0;\n if (Math.abs(rotationDeg % 360) < 0.01 || !projector) return undefined;\n\n return {\n worldToScreen: (x: number, y: number): DrawCoordinate | null =>\n toCoord(projector.worldToScreen(x, y)),\n screenToWorld: localScreenToWorld,\n };\n }, [projectorRef, localScreenToWorld]);\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 return createSquareFromCenter(center, halfLength, getRectangleProjection()).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, getRectangleProjection());\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, getRectangleProjection]\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, getRectangleProjection());\n }\n if (tool === \"circular\") {\n return createCircle(session.start, session.current);\n }\n\n return [];\n }, [tool, buildStampCoords, getRectangleProjection]);\n\n const drawBrushStrokePreview = useCallback(\n (ctx: CanvasRenderingContext2D): void => {\n const session = sessionRef.current;\n if (!session.isDrawing || session.screenPoints.length === 0) return;\n const screenPoints = session.screenPoints;\n if (screenPoints.length === 0) return;\n const radiusPx = 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 [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 =\n session.cursorScreen ??\n toCoord(projectorRef.current?.worldToScreen(cursor[0], cursor[1]) ?? []);\n if (!screen) return;\n const radiusPx = 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, 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 (preparedPersistedRegions.length > 0) {\n for (const entry of preparedPersistedRegions) {\n const { region, polygons, regionIndex, regionKey } = entry;\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,\n state,\n });\n strokeStyle = mergeStrokeStyle(strokeStyle, resolved || undefined);\n }\n const interactionShadowStyle = state === \"default\" ? null : resolveRegionInteractionShadowStyle(strokeStyle);\n\n for (const polygon of polygons) {\n const screenOuter = worldToScreenPoints(polygon.outer);\n if (screenOuter.length >= 4) {\n if (interactionShadowStyle) {\n drawPath(ctx, screenOuter, interactionShadowStyle, true, false);\n }\n drawPath(ctx, screenOuter, strokeStyle, true, false);\n }\n for (const hole of polygon.holes) {\n const screenHole = worldToScreenPoints(hole);\n if (screenHole.length >= 4) {\n if (interactionShadowStyle) {\n drawPath(ctx, screenHole, interactionShadowStyle, true, false);\n }\n drawPath(ctx, screenHole, strokeStyle, true, false);\n }\n }\n }\n }\n }\n\n if (preparedPatchRegions.length > 0) {\n for (const entry of preparedPatchRegions) {\n for (const polygon of entry.polygons) {\n const screenOuter = worldToScreenPoints(polygon.outer);\n if (screenOuter.length >= 4) {\n drawPath(ctx, screenOuter, resolvedPatchStrokeStyle, true, false);\n }\n for (const hole of polygon.holes) {\n const screenHole = worldToScreenPoints(hole);\n if (screenHole.length >= 4) {\n drawPath(ctx, screenHole, resolvedPatchStrokeStyle, true, false);\n }\n }\n }\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 const preview = buildPreviewCoords();\n\n if (active) {\n if (tool === \"brush\") {\n drawBrushStrokePreview(ctx);\n drawBrushCursor(ctx);\n } else 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, resolvedDrawPreviewFillColor);\n }\n } else {\n const polygon = worldToScreenPoints(preview);\n if (polygon.length >= 4) {\n drawPath(ctx, polygon, resolvedStrokeStyle, true, true, resolvedDrawPreviewFillColor);\n }\n }\n }\n }\n\n // Draw labels last so they stay visually on top.\n if (preparedPersistedRegions.length > 0) {\n const zoom = Math.max(1e-6, projectorRef.current?.getViewState?.().zoom ?? 1);\n const labelAutoLiftOffset =\n typeof regionLabelAutoLiftOffsetPx === \"number\" && Number.isFinite(regionLabelAutoLiftOffsetPx)\n ? Math.max(0, regionLabelAutoLiftOffsetPx)\n : resolveRegionLabelAutoLiftOffsetPx(autoLiftRegionLabelAtMaxZoom, zoom, projectorRef.current?.getZoomRange?.());\n for (const entry of preparedPersistedRegions) {\n if (!entry.region.label) continue;\n const anchorWorld = getTopAnchorFromPolygons(entry.polygons);\n if (!anchorWorld) continue;\n const anchorScreen = toCoord(projectorRef.current?.worldToScreen(anchorWorld[0], anchorWorld[1]) ?? []);\n if (!anchorScreen) continue;\n let dynamicLabelStyle = mergeRegionLabelStyle(\n resolvedLabelStyle,\n resolveRegionLabelStyleProp?.({\n region: entry.region,\n regionId: entry.regionKey,\n regionIndex: entry.regionIndex,\n zoom,\n })\n );\n if (labelAutoLiftOffset > 0) {\n dynamicLabelStyle = {\n ...dynamicLabelStyle,\n offsetY: dynamicLabelStyle.offsetY + labelAutoLiftOffset,\n };\n }\n drawRegionLabel(ctx, entry.region.label, anchorScreen, canvasWidth, canvasHeight, dynamicLabelStyle);\n }\n }\n\n if (resolvedDrawAreaTooltipOptions.enabled && active && (tool === \"freehand\" || tool === \"rectangle\" || tool === \"circular\")) {\n const session = sessionRef.current;\n if (session.isDrawing) {\n const areaCoords = tool === \"freehand\" ? closeRing(preview) : preview;\n if (areaCoords.length >= 4) {\n const areaPx = polygonArea(areaCoords);\n const mpp = typeof imageMpp === \"number\" && Number.isFinite(imageMpp) && imageMpp > 0 ? imageMpp : 0;\n const areaMm2 = mpp > 0 ? (areaPx * mpp * mpp) / (MICRONS_PER_MM * MICRONS_PER_MM) : 0;\n let text = defaultDrawAreaTooltipFormatter(areaMm2);\n try {\n text = resolvedDrawAreaTooltipOptions.format(areaMm2);\n } catch {\n text = defaultDrawAreaTooltipFormatter(areaMm2);\n }\n\n const cursor =\n session.cursorScreen ??\n (session.current ? toCoord(projectorRef.current?.worldToScreen(session.current[0], session.current[1]) ?? []) : null);\n if (cursor) {\n drawAreaTooltipBox(\n ctx,\n text,\n cursor,\n canvasWidth,\n canvasHeight,\n resolvedDrawAreaTooltipOptions.style,\n resolvedDrawAreaTooltipOptions.cursorOffsetX,\n resolvedDrawAreaTooltipOptions.cursorOffsetY\n );\n }\n }\n }\n }\n }, [\n active,\n tool,\n buildPreviewCoords,\n drawBrushStrokePreview,\n drawBrushCursor,\n resizeCanvas,\n worldToScreenPoints,\n imageWidth,\n imageHeight,\n projectorRef,\n preparedPersistedRegions,\n overlayShapes,\n hoveredRegionId,\n activeRegionId,\n resolvedStrokeStyle,\n resolvedHoverStrokeStyle,\n resolvedActiveStrokeStyle,\n resolvedDrawPreviewFillColor,\n preparedPatchRegions,\n resolvedPatchStrokeStyle,\n resolveRegionStrokeStyle,\n resolveRegionLabelStyleProp,\n resolvedLabelStyle,\n resolvedDrawAreaTooltipOptions,\n autoLiftRegionLabelAtMaxZoom,\n regionLabelAutoLiftOffsetPx,\n imageMpp,\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.screenPoints = [];\n session.stampCenter = null;\n if (!preserveCursor) {\n session.cursor = null;\n session.cursorScreen = 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 toLocalScreen = useCallback((event: ReactPointerEvent<HTMLCanvasElement>): DrawCoordinate | null => {\n const canvas = canvasRef.current;\n if (!canvas) return null;\n const rect = canvas.getBoundingClientRect();\n const x = clamp(event.clientX - rect.left, 0, rect.width);\n const y = clamp(event.clientY - rect.top, 0, rect.height);\n if (!Number.isFinite(x) || !Number.isFinite(y)) return null;\n return [x, y];\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, getRectangleProjection());\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 const screenPath =\n session.screenPoints.length > 0\n ? session.screenPoints\n : worldToScreenPoints(session.points);\n const screenPolygon = buildBrushStrokePolygon(screenPath, {\n radius: resolvedBrushOptions.radius,\n minRasterStep,\n circleSides: Math.max(24, Math.round(64 * edgeDetail)),\n simplifyTolerance: minRasterStep * 0.25,\n smoothingPasses: resolvedBrushOptions.edgeSmoothing,\n }) as DrawCoordinate[];\n const worldPolygon: DrawCoordinate[] = [];\n for (const point of screenPolygon) {\n const world = localScreenToWorld(point);\n if (!world) continue;\n worldPolygon.push(world);\n }\n coordinates = closeRing(worldPolygon);\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, worldToScreenPoints, localScreenToWorld, getRectangleProjection, resolvedBrushOptions.radius, resolvedBrushOptions.edgeDetail, resolvedBrushOptions.edgeSmoothing, resolvedBrushOptions.clickSelectRoi, 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, screen: DrawCoordinate): void => {\n const minScreenStep2 = BRUSH_SCREEN_STEP * BRUSH_SCREEN_STEP;\n const prevScreen = session.screenPoints[session.screenPoints.length - 1];\n if (!prevScreen) {\n session.points.push(world);\n session.screenPoints.push(screen);\n session.current = world;\n return;\n }\n const dx = screen[0] - prevScreen[0];\n const dy = screen[1] - prevScreen[1];\n if (dx * dx + dy * dy >= minScreenStep2) {\n session.points.push(world);\n session.screenPoints.push(screen);\n } else {\n session.points[session.points.length - 1] = world;\n session.screenPoints[session.screenPoints.length - 1] = screen;\n }\n session.current = world;\n },\n []\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 const screen = toLocalScreen(event);\n if (!screen) 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.cursorScreen = screen;\n session.points = tool === \"freehand\" || tool === \"brush\" ? [world] : [];\n session.screenPoints = tool === \"brush\" ? [screen] : [];\n requestDraw();\n },\n [active, tool, toWorld, toLocalScreen, 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 const screen = toLocalScreen(event);\n if (!screen) return;\n\n const session = sessionRef.current;\n session.cursor = world;\n session.cursorScreen = screen;\n\n if (isStampTool(tool)) {\n session.stampCenter = world;\n event.preventDefault();\n event.stopPropagation();\n requestDraw();\n return;\n }\n\n if (tool === \"brush\") {\n if (!session.isDrawing || session.pointerId !== event.pointerId) {\n requestDraw();\n return;\n }\n event.preventDefault();\n event.stopPropagation();\n appendBrushPoint(session, world, screen);\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, toLocalScreen, 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 const screen = toLocalScreen(event);\n if (world) {\n session.cursor = world;\n if (screen) {\n session.cursorScreen = screen;\n }\n if (tool === \"brush\") {\n if (screen) {\n appendBrushPoint(session, world, screen);\n }\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, toLocalScreen, 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 session.cursorScreen = 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 ReactNode,\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 type ViewportBorderStyle = \"stroke\" | \"dash\";\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\tviewportBorderColor: string;\n\tviewportBorderStyle: ViewportBorderStyle;\n\tviewportFillColor: string;\n\tinteractive: boolean;\n\tshowThumbnail: boolean;\n\tmaxThumbnailTiles: number;\n\tonClose?: () => void;\n\tcloseIcon?: ReactNode;\n\tcloseButtonStyle?: CSSProperties;\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: 200,\n\theight: 125,\n\tmargin: 16,\n\tposition: \"bottom-right\",\n\tborderRadius: 6,\n\tborderWidth: 0,\n\tbackgroundColor: \"rgba(4, 10, 18, 0.88)\",\n\tborderColor: \"rgba(230, 244, 255, 0.35)\",\n\tviewportBorderColor: \"#171719\",\n\tviewportBorderStyle: \"dash\",\n\tviewportFillColor: \"transparent\",\n\tinteractive: true,\n\tshowThumbnail: true,\n\tmaxThumbnailTiles: 16,\n};\n\nfunction strokeSymmetricDashedPolygon(\n\tctx: CanvasRenderingContext2D,\n\tpoints: Array<[number, number]>,\n\tdashLen: number,\n\tgapLen: number,\n): void {\n\tconst len = points.length;\n\tif (len !== 4) return;\n\tif (dashLen <= 0 || gapLen <= 0) return;\n\n\tfor (let i = 0; i < len; i += 1) {\n\t\tconst from = points[i];\n\t\tconst to = points[(i + 1) % len];\n\t\tconst sideLen = Math.hypot(to[0] - from[0], to[1] - from[1]);\n\t\tif (sideLen < 1e-6) continue;\n\n\t\tconst n = Math.max(1, Math.round((sideLen + gapLen) / (dashLen + gapLen)));\n\t\tconst fittedLen = n * dashLen + (n - 1) * gapLen;\n\t\tconst scale = sideLen / Math.max(1e-6, fittedLen);\n\t\tconst adjDash = dashLen * scale;\n\t\tconst adjGap = gapLen * scale;\n\n\t\tctx.beginPath();\n\t\tctx.moveTo(from[0], from[1]);\n\t\tctx.lineTo(to[0], to[1]);\n\t\tctx.setLineDash([adjDash, adjGap]);\n\t\tctx.lineDashOffset = 0;\n\t\tctx.stroke();\n\t}\n\n\tctx.setLineDash([]);\n\tctx.lineDashOffset = 0;\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\nconst DEFAULT_CLOSE_BUTTON_STYLE: CSSProperties = {\n\tposition: \"absolute\",\n\ttop: 4,\n\tright: 4,\n\tzIndex: 1,\n\twidth: 18,\n\theight: 18,\n\tborderRadius: 999,\n\tborder: \"1px solid rgba(255,255,255,0.4)\",\n\tbackground: \"rgba(16, 17, 19, 0.85)\",\n\tcolor: \"#fff\",\n\tfontSize: 12,\n\tlineHeight: 1,\n\tcursor: \"pointer\",\n\tpadding: 0,\n\tdisplay: \"flex\",\n\talignItems: \"center\",\n\tjustifyContent: \"center\",\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\n\tconst contentRect = useMemo(() => {\n\t\tconst imgW = Math.max(1, source.width);\n\t\tconst imgH = Math.max(1, source.height);\n\t\tconst imageAspect = imgW / imgH;\n\t\tconst boxAspect = width / height;\n\n\t\tlet cw: number;\n\t\tlet ch: number;\n\t\tif (imageAspect > boxAspect) {\n\t\t\tcw = width;\n\t\t\tch = width / imageAspect;\n\t\t} else {\n\t\t\tch = height;\n\t\t\tcw = height * imageAspect;\n\t\t}\n\n\t\treturn {\n\t\t\tx: (width - cw) / 2,\n\t\t\ty: (height - ch) / 2,\n\t\t\tw: cw,\n\t\t\th: ch,\n\t\t};\n\t}, [source.width, source.height, width, height]);\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 viewportBorderColor =\n\t\toptions?.viewportBorderColor ||\n\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.viewportBorderColor;\n\tconst viewportBorderStyle =\n\t\toptions?.viewportBorderStyle === \"stroke\" || options?.viewportBorderStyle === \"dash\"\n\t\t\t? options.viewportBorderStyle\n\t\t\t: DEFAULT_OVERVIEW_MAP_OPTIONS.viewportBorderStyle;\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\tconst onClose = options?.onClose;\n\tconst closeIcon = options?.closeIcon;\n\tconst closeButtonStyle = options?.closeButtonStyle;\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 { x: cx, y: cy, w: cw, h: ch } = contentRect;\n\n\t\tconst preview = thumbnailRef.current;\n\t\tif (preview) {\n\t\t\tctx.drawImage(preview, cx, cy, cw, ch);\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 = cw / Math.max(1, source.width);\n\t\tconst sy = ch / 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\tconst isDash = viewportBorderStyle === \"dash\";\n\n\t\tif (safeCorners) {\n\t\t\tconst screenCorners: Array<[number, number]> = [];\n\t\t\tfor (let i = 0; i < safeCorners.length; i += 1) {\n\t\t\t\tconst point = safeCorners[i];\n\t\t\t\tscreenCorners.push([\n\t\t\t\t\tclamp(cx + point[0] * sx, cx, cx + cw),\n\t\t\t\t\tclamp(cy + point[1] * sy, cy, cy + ch),\n\t\t\t\t]);\n\t\t\t}\n\n\t\t\tctx.beginPath();\n\t\t\tfor (let i = 0; i < screenCorners.length; i += 1) {\n\t\t\t\tif (i === 0) ctx.moveTo(screenCorners[i][0], screenCorners[i][1]);\n\t\t\t\telse ctx.lineTo(screenCorners[i][0], screenCorners[i][1]);\n\t\t\t}\n\t\t\tctx.closePath();\n\t\t\tctx.fillStyle = viewportFillColor;\n\t\t\tctx.fill();\n\n\t\t\tctx.strokeStyle = viewportBorderColor;\n\t\t\tctx.lineWidth = 2.25;\n\t\t\tif (isDash) {\n\t\t\t\tstrokeSymmetricDashedPolygon(ctx, screenCorners, 4, 3);\n\t\t\t} else {\n\t\t\t\tctx.stroke();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tconst left = clamp(cx + safeBounds[0] * sx, cx, cx + cw);\n\t\tconst top = clamp(cy + safeBounds[1] * sy, cy, cy + ch);\n\t\tconst right = clamp(cx + safeBounds[2] * sx, cx, cx + cw);\n\t\tconst bottom = clamp(cy + safeBounds[3] * sy, cy, cy + ch);\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 = viewportBorderColor;\n\t\tctx.lineWidth = 2.25;\n\t\tif (isDash) {\n\t\t\tconst rectCorners: Array<[number, number]> = [\n\t\t\t\t[left + 0.5, top + 0.5],\n\t\t\t\t[left + 0.5 + Math.max(1, rectW - 1), top + 0.5],\n\t\t\t\t[left + 0.5 + Math.max(1, rectW - 1), top + 0.5 + Math.max(1, rectH - 1)],\n\t\t\t\t[left + 0.5, top + 0.5 + Math.max(1, rectH - 1)],\n\t\t\t];\n\t\t\tstrokeSymmetricDashedPolygon(ctx, rectCorners, 4, 3);\n\t\t} else {\n\t\t\tctx.strokeRect(\n\t\t\t\tleft + 0.5,\n\t\t\t\ttop + 0.5,\n\t\t\t\tMath.max(1, rectW - 1),\n\t\t\t\tMath.max(1, rectH - 1),\n\t\t\t);\n\t\t}\n\t}, [\n\t\twidth,\n\t\theight,\n\t\tcontentRect,\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\tviewportBorderColor,\n\t\tviewportBorderStyle,\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 scaleX = rect.width / width;\n\t\t\tconst scaleY = rect.height / height;\n\t\t\tconst cxPx = contentRect.x * scaleX;\n\t\t\tconst cyPx = contentRect.y * scaleY;\n\t\t\tconst cwPx = contentRect.w * scaleX;\n\t\t\tconst chPx = contentRect.h * scaleY;\n\n\t\t\tconst nx = clamp((clientX - rect.left - cxPx) / cwPx, 0, 1);\n\t\t\tconst ny = clamp((clientY - rect.top - cyPx) / chPx, 0, 1);\n\t\t\treturn [nx * source.width, ny * source.height];\n\t\t},\n\t\t[source.width, source.height, width, height, contentRect],\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(contentRect.w));\n\t\tpreview.height = Math.max(1, Math.round(contentRect.h));\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\tcontentRect,\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<div className={className} style={mergedStyle}>\n\t\t\t<canvas\n\t\t\t\tref={canvasRef}\n\t\t\t\tstyle={{\n\t\t\t\t\twidth: \"100%\",\n\t\t\t\t\theight: \"100%\",\n\t\t\t\t\tdisplay: \"block\",\n\t\t\t\t\tborderRadius: \"inherit\",\n\t\t\t\t}}\n\t\t\t\tonPointerDown={handlePointerDown}\n\t\t\t\tonPointerMove={handlePointerMove}\n\t\t\t\tonPointerUp={handlePointerUp}\n\t\t\t\tonPointerCancel={handlePointerUp}\n\t\t\t\tonContextMenu={(event) => {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}}\n\t\t\t\tonWheel={(event) => {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t}}\n\t\t\t/>\n\t\t\t{onClose && (\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\taria-label=\"Hide overview map\"\n\t\t\t\t\tonClick={(event) => {\n\t\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\t\tonClose();\n\t\t\t\t\t}}\n\t\t\t\t\tstyle={closeButtonStyle\n\t\t\t\t\t\t? {...closeButtonStyle as CSSProperties}\n\t\t\t\t\t\t: { ...DEFAULT_CLOSE_BUTTON_STYLE as CSSProperties }\n\t\t\t\t\t}\n\t\t\t\t>\n\t\t\t\t\t{closeIcon ?? \"×\"}\n\t\t\t\t</button>\n\t\t\t)}\n\t\t</div>\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\";\nimport {\n\tpointInAnyPreparedPolygon,\n\tprepareRoiPolygons,\n\ttype RoiCoordinate,\n\ttype RoiGeometry,\n} from \"./roi-geometry\";\n\nexport type { RoiCoordinate };\nexport type RoiPolygon = RoiGeometry;\n\nfunction sanitizePointCount(pointData: WsiPointData): number {\n\tconst fillModesLength =\n\t\tpointData.fillModes instanceof Uint8Array\n\t\t\t? pointData.fillModes.length\n\t\t\t: Number.MAX_SAFE_INTEGER;\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\tfillModesLength,\n\t\t),\n\t);\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 = prepareRoiPolygons(polygons ?? []);\n\tif (prepared.length === 0) {\n\t\tconst empty: WsiPointData = {\n\t\t\tcount: 0,\n\t\t\tpositions: new Float32Array(0),\n\t\t\tpaletteIndices: new Uint16Array(0),\n\t\t};\n\t\tif (pointData.fillModes instanceof Uint8Array) {\n\t\t\tempty.fillModes = new Uint8Array(0);\n\t\t}\n\t\tif (pointData.ids instanceof Uint32Array) {\n\t\t\tempty.ids = new Uint32Array(0);\n\t\t}\n\t\treturn empty;\n\t}\n\n\tconst count = sanitizePointCount(pointData);\n\tconst positions = pointData.positions;\n\tconst terms = pointData.paletteIndices;\n\tconst fillModes =\n\t\tpointData.fillModes instanceof Uint8Array && pointData.fillModes.length >= count\n\t\t\t? pointData.fillModes\n\t\t\t: null;\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 nextFillModes = fillModes ? new Uint8Array(count) : null;\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 (!pointInAnyPreparedPolygon(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 (nextFillModes) {\n\t\t\tnextFillModes[cursor] = fillModes![i];\n\t\t}\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 (nextFillModes) {\n\t\toutput.fillModes = nextFillModes.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 = prepareRoiPolygons(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 (!pointInAnyPreparedPolygon(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 {\n pointInAnyPreparedPolygon,\n prepareRoiPolygons,\n} from \"./roi-geometry\";\nimport type { WsiPointData } from \"./types\";\nimport { prefilterPointsByBoundsWebGpu } from \"./webgpu\";\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\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 = prepareRoiPolygons(polygons ?? []);\n if (prepared.length === 0) {\n const data: WsiPointData = {\n count: 0,\n positions: new Float32Array(0),\n paletteIndices: new Uint16Array(0),\n };\n if (pointData.fillModes instanceof Uint8Array) {\n data.fillModes = new Uint8Array(0);\n }\n if (pointData.ids instanceof Uint32Array) {\n data.ids = new Uint32Array(0);\n }\n return {\n data,\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 fillModesLength =\n pointData.fillModes instanceof Uint8Array ? pointData.fillModes.length : Number.MAX_SAFE_INTEGER;\n const safeCount = Math.max(0, Math.min(pointData.count, Math.floor(pointData.positions.length / 2), pointData.paletteIndices.length, fillModesLength));\n const pointFillModes = pointData.fillModes instanceof Uint8Array && pointData.fillModes.length >= safeCount ? pointData.fillModes : null;\n const pointIds = pointData.ids instanceof Uint32Array && pointData.ids.length >= safeCount ? pointData.ids : null;\n if (safeCount === 0) {\n const data: WsiPointData = {\n count: 0,\n positions: new Float32Array(0),\n paletteIndices: new Uint16Array(0),\n };\n if (pointFillModes) {\n data.fillModes = new Uint8Array(0);\n }\n if (pointIds) {\n data.ids = new Uint32Array(0);\n }\n return {\n data,\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 polygon = prepared[i];\n bboxFlat[base] = polygon.minX;\n bboxFlat[base + 1] = polygon.minY;\n bboxFlat[base + 2] = polygon.maxX;\n bboxFlat[base + 3] = polygon.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 (pointFillModes) {\n data.fillModes = pointFillModes.subarray(0, safeCount);\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 const data: WsiPointData = {\n count: 0,\n positions: new Float32Array(0),\n paletteIndices: new Uint16Array(0),\n };\n if (pointFillModes) {\n data.fillModes = new Uint8Array(0);\n }\n if (pointIds) {\n data.ids = new Uint32Array(0);\n }\n return {\n data,\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 (!pointInAnyPreparedPolygon(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 (pointFillModes) {\n data.fillModes = pointFillModes.subarray(0, safeCount);\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 nextFillModes = pointFillModes ? new Uint8Array(candidateCount) : null;\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 (!pointInAnyPreparedPolygon(x, y, prepared)) continue;\n nextPositions[cursor * 2] = x;\n nextPositions[cursor * 2 + 1] = y;\n nextTerms[cursor] = pointData.paletteIndices[pointIndex];\n if (nextFillModes) {\n nextFillModes[cursor] = pointFillModes![pointIndex];\n }\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 (nextFillModes) {\n compactData.fillModes = nextFillModes.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 fillModes = msg.fillModes ? new Uint8Array(msg.fillModes) : null;\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 (fillModes) {\n output.fillModes = fillModes.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 fillModesLength = pointData.fillModes instanceof Uint8Array ? pointData.fillModes.length : Number.MAX_SAFE_INTEGER;\n const safeCount = Math.max(0, Math.min(pointData.count, Math.floor(pointData.positions.length / 2), pointData.paletteIndices.length, fillModesLength));\n const positionsCopy = pointData.positions.slice(0, safeCount * 2);\n const termsCopy = pointData.paletteIndices.slice(0, safeCount);\n const fillModesCopy = pointData.fillModes instanceof Uint8Array && pointData.fillModes.length >= safeCount ? pointData.fillModes.slice(0, safeCount) : null;\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 fillModes: fillModesCopy?.buffer,\n ids: idsCopy?.buffer,\n polygons: polygons ?? [],\n };\n const transfer: Transferable[] = [positionsCopy.buffer, termsCopy.buffer];\n if (fillModesCopy) {\n transfer.push(fillModesCopy.buffer);\n }\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 fillModesLength = pointData.fillModes instanceof Uint8Array ? pointData.fillModes.length : Number.MAX_SAFE_INTEGER;\n const safeCount = Math.max(0, Math.min(pointData.count, Math.floor(pointData.positions.length / 2), pointData.paletteIndices.length, fillModesLength));\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\";\nimport {\n\tpointInPreparedPolygon,\n\tprepareRoiPolygons,\n\ttype PreparedRoiPolygon,\n\ttype RoiGeometry,\n} from \"./roi-geometry\";\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\tpolygons: PreparedRoiPolygon[];\n\tarea: number;\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\tconst polygons = prepareRoiPolygons([region?.coordinates as RoiGeometry | null | undefined]);\n\t\tif (polygons.length === 0) continue;\n\n\t\tlet area = 0;\n\t\tfor (const polygon of polygons) {\n\t\t\tarea += polygon.area;\n\t\t}\n\n\t\tprepared.push({\n\t\t\tregionId: region.id ?? i,\n\t\t\tregionIndex: i,\n\t\t\tpolygons,\n\t\t\tarea: Math.max(1e-6, area),\n\t\t});\n\t}\n\treturn prepared;\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\tpointData?.fillModes instanceof Uint8Array\n\t\t\t\t? pointData.fillModes.length\n\t\t\t\t: Number.MAX_SAFE_INTEGER,\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\tlet inside = false;\n\t\t\tfor (const polygon of region.polygons) {\n\t\t\t\tif (!pointInPreparedPolygon(x, y, polygon)) continue;\n\t\t\t\tinside = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (!inside) 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\tWsiImageColorSettings,\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\tuBrightness: WebGLUniformLocation;\n\tuContrast: WebGLUniformLocation;\n\tuSaturation: WebGLUniformLocation;\n}\n\ninterface PointProgram {\n\tprogram: WebGLProgram;\n\tvao: WebGLVertexArrayObject;\n\tposBuffer: WebGLBuffer;\n\ttermBuffer: WebGLBuffer;\n\tfillModeBuffer: WebGLBuffer;\n\tindexBuffer: WebGLBuffer;\n\tpaletteTexture: WebGLTexture;\n\tuCamera: WebGLUniformLocation;\n\tuPointSize: WebGLUniformLocation;\n\tuPalette: WebGLUniformLocation;\n\tuPaletteSize: WebGLUniformLocation;\n\tuPointStrokeScale: 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 WsiViewTransitionOptions {\n\tduration?: number;\n\teasing?: (t: number) => number;\n}\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\timageColorSettings?: WsiImageColorSettings | null;\n\tminZoom?: number;\n\tmaxZoom?: number;\n\tviewTransition?: WsiViewTransitionOptions;\n\tpointSizeByZoom?: PointSizeByZoom;\n\tpointStrokeScale?: number;\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\ninterface ViewAnimationState {\n\tstartMs: number;\n\tdurationMs: number;\n\tfrom: WsiViewState;\n\tto: WsiViewState;\n\teasing: (t: number) => 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\nconst MIN_STROKE_SCALE = 0.1;\nconst MAX_STROKE_SCALE = 5.0;\n\nfunction normalizeStrokeScale(value: number | null | undefined): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) return 1.0;\n\treturn clamp(value, MIN_STROKE_SCALE, MAX_STROKE_SCALE);\n}\n\nconst MIN_IMAGE_COLOR_INPUT = -100;\nconst MAX_IMAGE_COLOR_INPUT = 100;\n\ninterface NormalizedImageColorSettings {\n\tbrightness: number;\n\tcontrast: number;\n\tsaturation: number;\n}\n\nfunction normalizeImageColorInput(value: number | null | undefined): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) return 0;\n\treturn clamp(value, MIN_IMAGE_COLOR_INPUT, MAX_IMAGE_COLOR_INPUT);\n}\n\nfunction toNormalizedImageColorSettings(\n\tsettings: WsiImageColorSettings | null | undefined,\n): NormalizedImageColorSettings {\n\tconst brightnessInput = normalizeImageColorInput(settings?.brightness);\n\tconst contrastInput = normalizeImageColorInput(settings?.contrast);\n\tconst saturationInput = normalizeImageColorInput(settings?.saturation);\n\treturn {\n\t\tbrightness: brightnessInput / 200,\n\t\tcontrast: contrastInput / 100,\n\t\tsaturation: saturationInput / 100,\n\t};\n}\n\nconst MAX_VIEW_TRANSITION_DURATION_MS = 2000;\n\nfunction linearEasing(t: number): number {\n\treturn t;\n}\n\nfunction normalizeViewTransitionDuration(duration: number | null | undefined): number {\n\tif (typeof duration !== \"number\" || !Number.isFinite(duration)) return 0;\n\treturn clamp(duration, 0, MAX_VIEW_TRANSITION_DURATION_MS);\n}\n\nfunction normalizeZoomOverride(value: number | null | undefined): number | null {\n\tif (typeof value !== \"number\" || !Number.isFinite(value) || value <= 0) return null;\n\treturn Math.max(1e-6, value);\n}\n\nfunction normalizeTransitionEasing(\n\teasing: ((t: number) => number) | null | undefined,\n): (t: number) => number {\n\treturn typeof easing === \"function\" ? easing : linearEasing;\n}\n\nfunction isSameViewState(a: WsiViewState, b: WsiViewState): boolean {\n\tconst epsilon = 1e-6;\n\treturn (\n\t\tMath.abs(a.zoom - b.zoom) <= epsilon &&\n\t\tMath.abs(a.offsetX - b.offsetX) <= epsilon &&\n\t\tMath.abs(a.offsetY - b.offsetY) <= epsilon &&\n\t\tMath.abs(a.rotationDeg - b.rotationDeg) <= epsilon\n\t);\n}\n\nexport class WsiTileRenderer {\n\tprivate readonly canvas: HTMLCanvasElement;\n\tprivate readonly source: WsiImageSource;\n\tprivate readonly gl: WebGL2RenderingContext;\n\tprivate readonly camera = new OrthoCamera();\n\tprivate readonly onViewStateChange?: (next: WsiViewState) => void;\n\tprivate readonly onStats?: (stats: WsiRenderStats) => void;\n\tprivate readonly onTileError?: (event: WsiTileErrorEvent) => void;\n\tprivate readonly onContextLost?: () => void;\n\tprivate readonly onContextRestored?: () => void;\n\tprivate readonly resizeObserver: ResizeObserver;\n\tprivate tileProgram: TileVertexProgram;\n\tprivate pointProgram: PointProgram;\n\tprivate readonly tileScheduler: TileScheduler;\n\n\tprivate authToken: string;\n\tprivate destroyed = false;\n\tprivate contextLost = false;\n\tprivate frame: number | null = null;\n\tprivate frameSerial = 0;\n\tprivate dragging = false;\n\tprivate interactionMode: \"none\" | \"pan\" | \"rotate\" = \"none\";\n\tprivate rotateLastAngleRad: number | null = null;\n\tprivate pointerId: number | null = null;\n\tprivate lastPointerX = 0;\n\tprivate lastPointerY = 0;\n\tprivate interactionLocked = false;\n\tprivate ctrlDragRotate = true;\n\tprivate rotationDragSensitivityDegPerPixel = 0.35;\n\tprivate maxCacheTiles: number;\n\tprivate fitZoom = 1;\n\tprivate minZoom = 1e-6;\n\tprivate maxZoom = 1;\n\tprivate minZoomOverride: number | null = null;\n\tprivate maxZoomOverride: number | null = null;\n\tprivate viewTransitionDurationMs = 0;\n\tprivate viewTransitionEasing: (t: number) => number = linearEasing;\n\tprivate viewAnimation: ViewAnimationState | null = null;\n\tprivate viewAnimationFrame: number | null = null;\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 pointStrokeScale = 1.0;\n\tprivate imageColorSettings: NormalizedImageColorSettings = {\n\t\tbrightness: 0,\n\t\tcontrast: 0,\n\t\tsaturation: 0,\n\t};\n\tprivate lastPointData: WsiPointData | null = null;\n\tprivate lastPointPalette: Uint8Array | null = null;\n\tprivate zeroFillModes = new Uint8Array(0);\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\t\tthis.pointStrokeScale = normalizeStrokeScale(options.pointStrokeScale);\n\t\tthis.imageColorSettings = toNormalizedImageColorSettings(\n\t\t\toptions.imageColorSettings,\n\t\t);\n\t\tthis.minZoomOverride = normalizeZoomOverride(options.minZoom);\n\t\tthis.maxZoomOverride = normalizeZoomOverride(options.maxZoom);\n\t\tthis.viewTransitionDurationMs = normalizeViewTransitionDuration(options.viewTransition?.duration);\n\t\tthis.viewTransitionEasing = normalizeTransitionEasing(options.viewTransition?.easing);\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({ duration: 0 });\n\t\tthis.resize();\n\t}\n\n\tprivate resolveDefaultZoomBounds(): { minZoom: number; maxZoom: number } {\n\t\tconst minZoom = Math.max(this.fitZoom * 0.5, 1e-6);\n\t\tconst maxZoom = Math.max(1, this.fitZoom * 8);\n\t\treturn {\n\t\t\tminZoom,\n\t\t\tmaxZoom: Math.max(minZoom, maxZoom),\n\t\t};\n\t}\n\n\tprivate applyZoomBounds(): void {\n\t\tconst defaults = this.resolveDefaultZoomBounds();\n\t\tlet minZoom = this.minZoomOverride ?? defaults.minZoom;\n\t\tlet maxZoom = this.maxZoomOverride ?? defaults.maxZoom;\n\t\tminZoom = Math.max(1e-6, minZoom);\n\t\tmaxZoom = Math.max(1e-6, maxZoom);\n\t\tif (minZoom > maxZoom) {\n\t\t\tminZoom = maxZoom;\n\t\t}\n\t\tthis.minZoom = minZoom;\n\t\tthis.maxZoom = maxZoom;\n\t}\n\n\tprivate resolveTargetViewState(next: Partial<WsiViewState>): WsiViewState {\n\t\tconst current = this.camera.getViewState();\n\t\tconst candidate: WsiViewState = {\n\t\t\tzoom:\n\t\t\t\ttypeof next.zoom === \"number\" && Number.isFinite(next.zoom)\n\t\t\t\t\t? clamp(next.zoom, this.minZoom, this.maxZoom)\n\t\t\t\t\t: current.zoom,\n\t\t\toffsetX:\n\t\t\t\ttypeof next.offsetX === \"number\" && Number.isFinite(next.offsetX)\n\t\t\t\t\t? next.offsetX\n\t\t\t\t\t: current.offsetX,\n\t\t\toffsetY:\n\t\t\t\ttypeof next.offsetY === \"number\" && Number.isFinite(next.offsetY)\n\t\t\t\t\t? next.offsetY\n\t\t\t\t\t: current.offsetY,\n\t\t\trotationDeg:\n\t\t\t\ttypeof next.rotationDeg === \"number\" && Number.isFinite(next.rotationDeg)\n\t\t\t\t\t? next.rotationDeg\n\t\t\t\t\t: current.rotationDeg,\n\t\t};\n\n\t\tthis.camera.setViewState(candidate);\n\t\tthis.clampViewState();\n\t\tconst target = this.camera.getViewState();\n\t\tthis.camera.setViewState(current);\n\t\treturn target;\n\t}\n\n\tprivate cancelViewAnimation(): void {\n\t\tthis.viewAnimation = null;\n\t\tif (this.viewAnimationFrame !== null) {\n\t\t\tcancelAnimationFrame(this.viewAnimationFrame);\n\t\t\tthis.viewAnimationFrame = null;\n\t\t}\n\t}\n\n\tprivate startViewAnimation(\n\t\ttarget: WsiViewState,\n\t\tdurationMs: number,\n\t\teasing: (t: number) => number,\n\t): void {\n\t\tconst from = this.camera.getViewState();\n\t\tthis.cancelViewAnimation();\n\t\tthis.viewAnimation = {\n\t\t\tstartMs: nowMs(),\n\t\t\tdurationMs: Math.max(0, durationMs),\n\t\t\tfrom,\n\t\t\tto: target,\n\t\t\teasing,\n\t\t};\n\n\t\tconst step = (): void => {\n\t\t\tconst animation = this.viewAnimation;\n\t\t\tif (!animation) return;\n\n\t\t\tconst elapsed = Math.max(0, nowMs() - animation.startMs);\n\t\t\tconst rawT =\n\t\t\t\tanimation.durationMs <= 0 ? 1 : clamp(elapsed / animation.durationMs, 0, 1);\n\t\t\tlet eased = rawT;\n\t\t\ttry {\n\t\t\t\teased = animation.easing(rawT);\n\t\t\t} catch {\n\t\t\t\teased = rawT;\n\t\t\t}\n\t\t\tif (!Number.isFinite(eased)) {\n\t\t\t\teased = rawT;\n\t\t\t}\n\t\t\teased = clamp(eased, 0, 1);\n\n\t\t\tconst nextState: WsiViewState = {\n\t\t\t\tzoom: animation.from.zoom + (animation.to.zoom - animation.from.zoom) * eased,\n\t\t\t\toffsetX:\n\t\t\t\t\tanimation.from.offsetX +\n\t\t\t\t\t(animation.to.offsetX - animation.from.offsetX) * eased,\n\t\t\t\toffsetY:\n\t\t\t\t\tanimation.from.offsetY +\n\t\t\t\t\t(animation.to.offsetY - animation.from.offsetY) * eased,\n\t\t\t\trotationDeg:\n\t\t\t\t\tanimation.from.rotationDeg +\n\t\t\t\t\t(animation.to.rotationDeg - animation.from.rotationDeg) * eased,\n\t\t\t};\n\n\t\t\tthis.camera.setViewState(nextState);\n\t\t\tthis.clampViewState();\n\t\t\tthis.emitViewState();\n\t\t\tthis.requestRender();\n\n\t\t\tif (rawT >= 1) {\n\t\t\t\tthis.viewAnimation = null;\n\t\t\t\tthis.viewAnimationFrame = null;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.viewAnimationFrame = requestAnimationFrame(step);\n\t\t};\n\n\t\tthis.viewAnimationFrame = requestAnimationFrame(step);\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\tsetZoomRange(minZoom: number | null | undefined, maxZoom: number | null | undefined): void {\n\t\tconst nextMinOverride = normalizeZoomOverride(minZoom);\n\t\tconst nextMaxOverride = normalizeZoomOverride(maxZoom);\n\t\tif (\n\t\t\tthis.minZoomOverride === nextMinOverride &&\n\t\t\tthis.maxZoomOverride === nextMaxOverride\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.minZoomOverride = nextMinOverride;\n\t\tthis.maxZoomOverride = nextMaxOverride;\n\t\tthis.applyZoomBounds();\n\n\t\tconst target = this.resolveTargetViewState({});\n\t\tconst current = this.camera.getViewState();\n\t\tif (isSameViewState(current, target)) {\n\t\t\treturn;\n\t\t}\n\t\tthis.cancelViewAnimation();\n\t\tthis.camera.setViewState(target);\n\t\tthis.emitViewState();\n\t\tthis.requestRender();\n\t}\n\n\tsetViewTransition(options: WsiViewTransitionOptions | null | undefined): void {\n\t\tthis.viewTransitionDurationMs = normalizeViewTransitionDuration(options?.duration);\n\t\tthis.viewTransitionEasing = normalizeTransitionEasing(options?.easing);\n\t}\n\n\tsetViewState(\n\t\tnext: Partial<WsiViewState>,\n\t\ttransition?: WsiViewTransitionOptions,\n\t): void {\n\t\tconst target = this.resolveTargetViewState(next);\n\t\tconst current = this.camera.getViewState();\n\t\tif (isSameViewState(current, target)) return;\n\n\t\tconst durationMs = normalizeViewTransitionDuration(\n\t\t\ttransition?.duration ?? this.viewTransitionDurationMs,\n\t\t);\n\t\tconst easing = normalizeTransitionEasing(\n\t\t\ttransition?.easing ?? this.viewTransitionEasing,\n\t\t);\n\t\tif (durationMs <= 0) {\n\t\t\tthis.cancelViewAnimation();\n\t\t\tthis.camera.setViewState(target);\n\t\t\tthis.emitViewState();\n\t\t\tthis.requestRender();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.startViewAnimation(target, durationMs, easing);\n\t}\n\n\tgetViewState(): WsiViewState {\n\t\treturn this.camera.getViewState();\n\t}\n\n\tgetZoomRange(): { minZoom: number; maxZoom: number } {\n\t\treturn { minZoom: this.minZoom, maxZoom: this.maxZoom };\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 pointFillModes =\n\t\t\tpoints.fillModes instanceof Uint8Array ? points.fillModes : null;\n\t\tconst hasFillModes = pointFillModes !== null;\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\thasFillModes ? pointFillModes.length : Number.MAX_SAFE_INTEGER,\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 nextFillModes = hasFillModes\n\t\t\t? pointFillModes.subarray(0, safeCount)\n\t\t\t: undefined;\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\tconst prevHasFillModes = prev?.fillModes instanceof Uint8Array;\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\t\tprevHasFillModes !== hasFillModes ||\n\t\t\t(hasFillModes &&\n\t\t\t\t(!prev?.fillModes || !isSameArrayView(prev.fillModes, nextFillModes)));\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\tfillModes: nextFillModes,\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\n\t\t\tgl.bindBuffer(gl.ARRAY_BUFFER, this.pointProgram.fillModeBuffer);\n\t\t\tgl.bufferData(\n\t\t\t\tgl.ARRAY_BUFFER,\n\t\t\t\tthis.lastPointData.fillModes ?? this.getZeroFillModes(safeCount),\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\tprivate getZeroFillModes(count: number): Uint8Array {\n\t\tif (count <= 0) return new Uint8Array(0);\n\t\tif (this.zeroFillModes.length < count) {\n\t\t\tthis.zeroFillModes = new Uint8Array(count);\n\t\t}\n\t\treturn this.zeroFillModes.subarray(0, count);\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\tsetPointStrokeScale(scale: number | null | undefined): void {\n\t\tconst next = normalizeStrokeScale(scale);\n\t\tif (this.pointStrokeScale === next) return;\n\t\tthis.pointStrokeScale = next;\n\t\tthis.requestRender();\n\t}\n\n\tsetImageColorSettings(settings: WsiImageColorSettings | null | undefined): void {\n\t\tconst next = toNormalizedImageColorSettings(settings);\n\t\tconst prev = this.imageColorSettings;\n\t\tif (\n\t\t\tprev.brightness === next.brightness &&\n\t\t\tprev.contrast === next.contrast &&\n\t\t\tprev.saturation === next.saturation\n\t\t) {\n\t\t\treturn;\n\t\t}\n\t\tthis.imageColorSettings = next;\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(\n\t\tworldX: number,\n\t\tworldY: number,\n\t\ttransition?: WsiViewTransitionOptions,\n\t): void {\n\t\tif (!Number.isFinite(worldX) || !Number.isFinite(worldY)) return;\n\t\tconst state = this.camera.getViewState();\n\t\tconst zoom = Math.max(1e-6, state.zoom);\n\t\tconst vp = this.camera.getViewport();\n\t\tthis.setViewState(\n\t\t\t{\n\t\t\t\toffsetX: worldX - vp.width / (2 * zoom),\n\t\t\t\toffsetY: worldY - vp.height / (2 * zoom),\n\t\t\t},\n\t\t\ttransition,\n\t\t);\n\t}\n\n\tgetViewCorners(): [WorldPoint, WorldPoint, WorldPoint, WorldPoint] {\n\t\treturn this.camera.getViewCorners();\n\t}\n\n\tresetRotation(transition?: WsiViewTransitionOptions): void {\n\t\tconst state = this.camera.getViewState();\n\t\tif (Math.abs(state.rotationDeg) < 1e-6) return;\n\t\tthis.setViewState({ rotationDeg: 0 }, transition);\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(transition?: WsiViewTransitionOptions): 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.applyZoomBounds();\n\t\tconst clampedZoom = clamp(safeZoom, this.minZoom, this.maxZoom);\n\t\tconst visibleWorldW = vw / clampedZoom;\n\t\tconst visibleWorldH = vh / clampedZoom;\n\n\t\tthis.setViewState(\n\t\t\t{\n\t\t\t\tzoom: clampedZoom,\n\t\t\t\toffsetX: (this.source.width - visibleWorldW) * 0.5,\n\t\t\t\toffsetY: (this.source.height - visibleWorldH) * 0.5,\n\t\t\t\trotationDeg: 0,\n\t\t\t},\n\t\t\ttransition,\n\t\t);\n\t}\n\n\tzoomBy(\n\t\tfactor: number,\n\t\tscreenX: number,\n\t\tscreenY: number,\n\t\ttransition?: WsiViewTransitionOptions,\n\t): 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\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(state.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\tconst nextCenterX = worldX - worldDx;\n\t\tconst nextCenterY = worldY - worldDy;\n\n\t\tthis.setViewState(\n\t\t\t{\n\t\t\t\tzoom: nextZoom,\n\t\t\t\toffsetX: nextCenterX - vp.width / (2 * nextZoom),\n\t\t\t\toffsetY: nextCenterY - vp.height / (2 * nextZoom),\n\t\t\t},\n\t\t\ttransition,\n\t\t);\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\t\tgl.uniform1f(tileProgram.uBrightness, this.imageColorSettings.brightness);\n\t\tgl.uniform1f(tileProgram.uContrast, this.imageColorSettings.contrast);\n\t\tgl.uniform1f(tileProgram.uSaturation, this.imageColorSettings.saturation);\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.uPointStrokeScale, this.pointStrokeScale);\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\tthis.cancelViewAnimation();\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\t\tthis.cancelViewAnimation();\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\t\tthis.cancelViewAnimation();\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.fillModeBuffer);\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 uniform float uBrightness;\n uniform float uContrast;\n uniform float uSaturation;\n out vec4 outColor;\n void main() {\n vec4 color = texture(uTexture, vUv);\n\n color.rgb = clamp(\n (uContrast + 1.0) * color.rgb - (uContrast / 2.0),\n vec3(0.0),\n vec3(1.0)\n );\n\n float saturation = uSaturation + 1.0;\n float sr = (1.0 - saturation) * 0.2126;\n float sg = (1.0 - saturation) * 0.7152;\n float sb = (1.0 - saturation) * 0.0722;\n mat3 saturationMatrix = mat3(\n sr + saturation, sr, sr,\n sg, sg + saturation, sg,\n sb, sb, sb + saturation\n );\n color.rgb = clamp(saturationMatrix * color.rgb, vec3(0.0), vec3(1.0));\n\n color.rgb = clamp(color.rgb + uBrightness, vec3(0.0), vec3(1.0));\n outColor = color;\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\t\tconst uBrightness = requireUniformLocation(gl, program, \"uBrightness\");\n\t\tconst uContrast = requireUniformLocation(gl, program, \"uContrast\");\n\t\tconst uSaturation = requireUniformLocation(gl, program, \"uSaturation\");\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 {\n\t\t\tprogram,\n\t\t\tvao,\n\t\t\tvbo,\n\t\t\tuCamera,\n\t\t\tuBounds,\n\t\t\tuTexture,\n\t\t\tuBrightness,\n\t\t\tuContrast,\n\t\t\tuSaturation,\n\t\t};\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 in uint aFillMode;\n uniform mat3 uCamera;\n uniform float uPointSize;\n flat out uint vTerm;\n flat out uint vFillMode;\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 vFillMode = aFillMode;\n }`;\n\n\t\tconst pointFragment = `#version 300 es\n precision highp float;\n flat in uint vTerm;\n flat in uint vFillMode;\n uniform sampler2D uPalette;\n uniform float uPaletteSize;\n uniform float uPointSize;\n uniform float uPointStrokeScale;\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 aa = 1.5 / max(1.0, uPointSize);\n float outerMask = 1.0 - smoothstep(1.0 - aa, 1.0 + aa, r);\n float alpha = 0.0;\n if (vFillMode != 0u) {\n alpha = outerMask * color.a;\n } else {\n float s = uPointStrokeScale;\n float ringWidth = clamp(3.0 * s / max(1.0, uPointSize), 0.12 * s, 0.62 * s);\n float innerRadius = 1.0 - ringWidth;\n float innerMask = smoothstep(innerRadius - aa, innerRadius + aa, r);\n alpha = outerMask * innerMask * color.a;\n }\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 uPointStrokeScale = requireUniformLocation(gl, program, \"uPointStrokeScale\");\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 fillModeBuffer = gl.createBuffer();\n\t\tconst indexBuffer = gl.createBuffer();\n\t\tconst paletteTexture = gl.createTexture();\n\t\tif (!vao || !posBuffer || !termBuffer || !fillModeBuffer || !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.ARRAY_BUFFER, fillModeBuffer);\n\t\tgl.bufferData(gl.ARRAY_BUFFER, 0, gl.DYNAMIC_DRAW);\n\t\tconst fillModeLoc = gl.getAttribLocation(program, \"aFillMode\");\n\t\tif (fillModeLoc < 0) {\n\t\t\tthrow new Error(\"point fill mode attribute not found\");\n\t\t}\n\t\tgl.enableVertexAttribArray(fillModeLoc);\n\t\tgl.vertexAttribIPointer(fillModeLoc, 1, gl.UNSIGNED_BYTE, 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\tfillModeBuffer,\n\t\t\tindexBuffer,\n\t\t\tpaletteTexture,\n\t\t\tuCamera,\n\t\t\tuPointSize,\n\t\t\tuPointStrokeScale,\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 {\n type CSSProperties,\n type MutableRefObject,\n type MouseEvent as ReactMouseEvent,\n type ReactNode,\n type PointerEvent as ReactPointerEvent,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} 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 { type PreparedRoiPolygon, prepareRoiPolygons, type RoiGeometry } from \"../wsi/roi-geometry\";\nimport { computeRoiPointGroups, type RoiPointGroupStats } from \"../wsi/roi-term-stats\";\nimport type {\n WsiImageColorSettings,\n WsiImageSource,\n WsiPointData,\n WsiRegion,\n WsiRenderStats,\n WsiViewState,\n} from \"../wsi/types\";\nimport { type PointSizeByZoom, type WsiTileErrorEvent, type WsiViewTransitionOptions, WsiTileRenderer } from \"../wsi/wsi-tile-renderer\";\nimport type {\n BrushOptions,\n DrawAreaTooltipOptions,\n DrawCoordinate,\n DrawOverlayShape,\n DrawRegionCoordinates,\n DrawResult,\n DrawTool,\n PatchDrawResult,\n RegionLabelStyle,\n RegionLabelStyleResolver,\n RegionStrokeStyle,\n RegionStrokeStyleResolver,\n StampOptions,\n} from \"./draw-layer\";\nimport { DrawLayer, mergeRegionLabelStyle, resolveRegionLabelAutoLiftOffsetPx, resolveRegionLabelStyle } from \"./draw-layer\";\nimport { OverviewMap, type OverviewMapOptions } from \"./overview-map\";\n\nconst EMPTY_ROI_REGIONS: WsiRegion[] = [];\nconst EMPTY_ROI_POLYGONS: DrawRegionCoordinates[] = [];\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;\nconst REGION_CONTOUR_HIT_DISTANCE_PX = 6;\nconst TOP_ANCHOR_Y_TOLERANCE = 0.5;\nconst LABEL_MEASURE_FALLBACK_EM = 0.58;\nconst LABEL_MEASURE_CACHE_LIMIT = 4096;\nconst REGION_LABEL_AUTO_LIFT_ANIMATION_DURATION_MS = 180;\nconst REGION_LABEL_AUTO_LIFT_MAX_OFFSET_PX = 20;\n\nlet sharedLabelMeasureContext: CanvasRenderingContext2D | null = null;\nconst labelTextWidthCache = new Map<string, number>();\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\ninterface PreparedRegionHit {\n region: WsiRegion;\n regionIndex: number;\n regionId: string | number;\n polygons: PreparedRoiPolygon[];\n label: string;\n labelAnchor: DrawCoordinate | null;\n}\n\nfunction sanitizePointCount(pointData: WsiPointData): number {\n const fillModesLength = pointData.fillModes instanceof Uint8Array ? pointData.fillModes.length : Number.MAX_SAFE_INTEGER;\n return Math.max(0, Math.min(Math.floor(pointData.count ?? 0), Math.floor((pointData.positions?.length ?? 0) / 2), pointData.paletteIndices?.length ?? 0, fillModesLength));\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 clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, value));\n}\n\nfunction smoothstep01(t: number): number {\n const x = clamp(t, 0, 1);\n return x * x * (3 - 2 * x);\n}\n\nfunction toDrawCoordinate(value: unknown): 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\nfunction getTopAnchor(ring: DrawCoordinate[]): DrawCoordinate | null {\n if (ring.length === 0) return null;\n let minY = Infinity;\n for (const point of ring) {\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 ring) {\n if (Math.abs(point[1] - minY) > TOP_ANCHOR_Y_TOLERANCE) continue;\n if (point[0] < minX) minX = point[0];\n if (point[0] > maxX) maxX = point[0];\n }\n if (!Number.isFinite(minX) || !Number.isFinite(maxX)) return null;\n return [(minX + maxX) * 0.5, minY];\n}\n\nfunction getTopAnchorFromPreparedPolygons(polygons: PreparedRoiPolygon[]): DrawCoordinate | null {\n let best: DrawCoordinate | null = null;\n for (const polygon of polygons) {\n const anchor = getTopAnchor(polygon.outer);\n if (!anchor) continue;\n if (!best || anchor[1] < best[1] || (anchor[1] === best[1] && anchor[0] < best[0])) {\n best = anchor;\n }\n }\n return best;\n}\n\nfunction pointSegmentDistanceSq(px: number, py: number, ax: number, ay: number, bx: number, by: number): number {\n const abx = bx - ax;\n const aby = by - ay;\n const lengthSq = abx * abx + aby * aby;\n if (lengthSq <= 1e-12) {\n const dx = px - ax;\n const dy = py - ay;\n return dx * dx + dy * dy;\n }\n const t = clamp(((px - ax) * abx + (py - ay) * aby) / lengthSq, 0, 1);\n const nx = ax + abx * t;\n const ny = ay + aby * t;\n const dx = px - nx;\n const dy = py - ny;\n return dx * dx + dy * dy;\n}\n\nfunction isPointNearRing(x: number, y: number, ring: DrawCoordinate[], maxDistanceSq: number): boolean {\n for (let i = 1; i < ring.length; i += 1) {\n const prev = ring[i - 1];\n const next = ring[i];\n if (pointSegmentDistanceSq(x, y, prev[0], prev[1], next[0], next[1]) <= maxDistanceSq) {\n return true;\n }\n }\n return false;\n}\n\nfunction isPointNearPolygonContour(x: number, y: number, polygon: PreparedRoiPolygon, maxDistance: number): boolean {\n if (x < polygon.minX - maxDistance || x > polygon.maxX + maxDistance || y < polygon.minY - maxDistance || y > polygon.maxY + maxDistance) {\n return false;\n }\n const maxDistanceSq = maxDistance * maxDistance;\n if (isPointNearRing(x, y, polygon.outer, maxDistanceSq)) return true;\n for (const hole of polygon.holes) {\n if (isPointNearRing(x, y, hole, maxDistanceSq)) return true;\n }\n return false;\n}\n\nfunction getLabelMeasureContext(): CanvasRenderingContext2D | null {\n if (sharedLabelMeasureContext) return sharedLabelMeasureContext;\n if (typeof document === \"undefined\") return null;\n const canvas = document.createElement(\"canvas\");\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return null;\n sharedLabelMeasureContext = ctx;\n return sharedLabelMeasureContext;\n}\n\nfunction measureLabelTextWidth(label: string, labelStyle: RegionLabelStyle): number {\n const key = `${labelStyle.fontWeight}|${labelStyle.fontSize}|${labelStyle.fontFamily}|${label}`;\n const cached = labelTextWidthCache.get(key);\n if (cached !== undefined) return cached;\n\n const fallback = label.length * labelStyle.fontSize * LABEL_MEASURE_FALLBACK_EM;\n const ctx = getLabelMeasureContext();\n let width = fallback;\n if (ctx) {\n ctx.font = `${labelStyle.fontWeight} ${labelStyle.fontSize}px ${labelStyle.fontFamily}`;\n const measured = ctx.measureText(label).width;\n if (Number.isFinite(measured) && measured >= 0) {\n width = measured;\n }\n }\n\n if (labelTextWidthCache.size > LABEL_MEASURE_CACHE_LIMIT) {\n labelTextWidthCache.clear();\n }\n labelTextWidthCache.set(key, width);\n return width;\n}\n\nfunction isScreenPointInsideLabel(\n region: PreparedRegionHit,\n screenCoord: DrawCoordinate,\n renderer: WsiTileRenderer,\n labelStyle: RegionLabelStyle,\n canvasWidth: number,\n canvasHeight: number\n): boolean {\n if (!region.label || !region.labelAnchor) return false;\n\n const anchorScreen = toDrawCoordinate(renderer.worldToScreen(region.labelAnchor[0], region.labelAnchor[1]));\n if (!anchorScreen) return false;\n\n const textWidth = measureLabelTextWidth(region.label, labelStyle);\n const boxWidth = textWidth + labelStyle.paddingX * 2;\n const boxHeight = labelStyle.fontSize + labelStyle.paddingY * 2;\n\n const x = clamp(anchorScreen[0], boxWidth * 0.5 + 1, canvasWidth - boxWidth * 0.5 - 1);\n const y = clamp(anchorScreen[1] - labelStyle.offsetY, boxHeight * 0.5 + 1, canvasHeight - boxHeight * 0.5 - 1);\n const left = x - boxWidth * 0.5;\n const right = x + boxWidth * 0.5;\n const top = y - boxHeight * 0.5;\n const bottom = y + boxHeight * 0.5;\n\n return screenCoord[0] >= left && screenCoord[0] <= right && screenCoord[1] >= top && screenCoord[1] <= bottom;\n}\n\nfunction prepareRegionHits(regions: WsiRegion[]): PreparedRegionHit[] {\n const out: PreparedRegionHit[] = [];\n for (let i = 0; i < regions.length; i += 1) {\n const region = regions[i];\n const polygons = prepareRoiPolygons([region?.coordinates as RoiGeometry | null | undefined]);\n if (polygons.length === 0) continue;\n const label = typeof region?.label === \"string\" ? region.label.trim() : \"\";\n out.push({\n region,\n regionIndex: i,\n regionId: resolveRegionId(region, i),\n polygons,\n label,\n labelAnchor: label ? getTopAnchorFromPreparedPolygons(polygons) : null,\n });\n }\n return out;\n}\n\nfunction pickPreparedRegionAt(\n coord: DrawCoordinate,\n screenCoord: DrawCoordinate,\n regions: PreparedRegionHit[],\n renderer: WsiTileRenderer,\n labelStyle: RegionLabelStyle,\n labelStyleResolver: RegionLabelStyleResolver | undefined,\n labelAutoLiftOffsetPx: number,\n canvasWidth: number,\n canvasHeight: number\n): {\n region: WsiRegion;\n regionIndex: number;\n regionId: string | number;\n} | null {\n const x = coord[0];\n const y = coord[1];\n const zoom = Math.max(1e-6, renderer.getViewState().zoom);\n const labelAutoLiftOffset = Math.max(0, labelAutoLiftOffsetPx);\n const contourHitDistance = REGION_CONTOUR_HIT_DISTANCE_PX / zoom;\n for (let i = regions.length - 1; i >= 0; i -= 1) {\n const region = regions[i];\n for (const polygon of region.polygons) {\n if (!isPointNearPolygonContour(x, y, polygon, contourHitDistance)) continue;\n return {\n region: region.region,\n regionIndex: region.regionIndex,\n regionId: region.regionId,\n };\n }\n let dynamicLabelStyle = mergeRegionLabelStyle(\n labelStyle,\n labelStyleResolver?.({\n region: region.region,\n regionId: region.regionId,\n regionIndex: region.regionIndex,\n zoom,\n })\n );\n if (labelAutoLiftOffset > 0) {\n dynamicLabelStyle = {\n ...dynamicLabelStyle,\n offsetY: dynamicLabelStyle.offsetY + labelAutoLiftOffset,\n };\n }\n if (!isScreenPointInsideLabel(region, screenCoord, renderer, dynamicLabelStyle, canvasWidth, canvasHeight)) continue;\n return {\n region: region.region,\n regionIndex: region.regionIndex,\n regionId: region.regionId,\n };\n }\n return null;\n}\n\nexport interface OverviewMapConfig {\n show?: boolean;\n options?: Partial<OverviewMapOptions>;\n className?: string;\n style?: CSSProperties;\n}\n\nexport interface WsiViewerCanvasProps {\n source: WsiImageSource | null;\n viewState?: Partial<WsiViewState> | null;\n imageColorSettings?: WsiImageColorSettings | 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 pointStrokeScale?: number;\n minZoom?: number;\n maxZoom?: number;\n viewTransition?: WsiViewTransitionOptions;\n roiRegions?: WsiRegion[];\n roiPolygons?: DrawRegionCoordinates[];\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 drawFillColor?: string;\n regionStrokeStyle?: Partial<RegionStrokeStyle>;\n regionStrokeHoverStyle?: Partial<RegionStrokeStyle>;\n regionStrokeActiveStyle?: Partial<RegionStrokeStyle>;\n patchStrokeStyle?: Partial<RegionStrokeStyle>;\n resolveRegionStrokeStyle?: RegionStrokeStyleResolver;\n resolveRegionLabelStyle?: RegionLabelStyleResolver;\n overlayShapes?: DrawOverlayShape[];\n customLayers?: WsiCustomLayer[];\n patchRegions?: WsiRegion[];\n regionLabelStyle?: Partial<RegionLabelStyle>;\n drawAreaTooltip?: DrawAreaTooltipOptions;\n autoLiftRegionLabelAtMaxZoom?: boolean;\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 activeRegionId?: string | number | null;\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 overviewMapConfig?: OverviewMapConfig;\n className?: string;\n style?: CSSProperties;\n}\n\nexport function WsiViewerCanvas({\n source,\n viewState,\n imageColorSettings = null,\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 pointStrokeScale,\n minZoom,\n maxZoom,\n viewTransition,\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 drawFillColor,\n regionStrokeStyle,\n regionStrokeHoverStyle,\n regionStrokeActiveStyle,\n patchStrokeStyle,\n resolveRegionStrokeStyle,\n resolveRegionLabelStyle: resolveRegionLabelStyleProp,\n overlayShapes,\n customLayers,\n patchRegions,\n regionLabelStyle,\n drawAreaTooltip,\n autoLiftRegionLabelAtMaxZoom = false,\n onPointerWorldMove,\n onPointHover,\n onPointClick,\n onRegionHover,\n onRegionClick,\n activeRegionId: controlledActiveRegionId,\n onActiveRegionChange,\n getCellByCoordinatesRef,\n onDrawComplete,\n onPatchComplete,\n overviewMapConfig,\n className,\n style,\n}: WsiViewerCanvasProps): React.ReactElement {\n const showOverviewMap = overviewMapConfig?.show ?? false;\n const overviewMapOptions = overviewMapConfig?.options;\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 [hoveredRegionId, setHoveredRegionId] = useState<string | number | null>(null);\n const [uncontrolledActiveRegionId, setUncontrolledActiveRegionId] = useState<string | number | null>(() => controlledActiveRegionId ?? null);\n const isActiveRegionControlled = controlledActiveRegionId !== undefined;\n const activeRegionId = isActiveRegionControlled ? (controlledActiveRegionId ?? null) : uncontrolledActiveRegionId;\n const [customLayerViewState, setCustomLayerViewState] = useState<WsiViewState | null>(null);\n const [debugStats, setDebugStats] = useState<WsiRenderStats | null>(null);\n const [regionLabelAutoLiftOffsetPx, setRegionLabelAutoLiftOffsetPx] = useState(0);\n const hoveredRegionIdRef = useRef<string | number | null>(null);\n const hoveredPointIndexRef = useRef<number | null>(null);\n const hoveredPointIdRef = useRef<number | null>(null);\n const regionLabelAutoLiftOffsetRef = useRef(0);\n const regionLabelAutoLiftAnimationRef = useRef<{ rafId: number | null; startMs: number; from: number; to: number }>({\n rafId: null,\n startMs: 0,\n from: 0,\n to: 0,\n });\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 const preparedRegionHits = useMemo(() => prepareRegionHits(effectiveRoiRegions), [effectiveRoiRegions]);\n const resolvedRegionLabelStyle = useMemo(() => resolveRegionLabelStyle(regionLabelStyle), [regionLabelStyle]);\n\n const applyRegionLabelAutoLiftOffset = useCallback((next: number) => {\n const clamped = clamp(next, 0, REGION_LABEL_AUTO_LIFT_MAX_OFFSET_PX);\n if (Math.abs(regionLabelAutoLiftOffsetRef.current - clamped) < 1e-4) return;\n regionLabelAutoLiftOffsetRef.current = clamped;\n setRegionLabelAutoLiftOffsetPx(clamped);\n }, []);\n\n const cancelRegionLabelAutoLiftAnimation = useCallback(() => {\n const animation = regionLabelAutoLiftAnimationRef.current;\n if (animation.rafId !== null) {\n cancelAnimationFrame(animation.rafId);\n animation.rafId = null;\n }\n }, []);\n\n const animateRegionLabelAutoLiftTo = useCallback(\n (target: number) => {\n const clampedTarget = clamp(target, 0, REGION_LABEL_AUTO_LIFT_MAX_OFFSET_PX);\n const animation = regionLabelAutoLiftAnimationRef.current;\n const from = regionLabelAutoLiftOffsetRef.current;\n if (Math.abs(from - clampedTarget) < 1e-4) {\n cancelRegionLabelAutoLiftAnimation();\n animation.to = clampedTarget;\n applyRegionLabelAutoLiftOffset(clampedTarget);\n return;\n }\n\n cancelRegionLabelAutoLiftAnimation();\n animation.startMs = performance.now();\n animation.from = from;\n animation.to = clampedTarget;\n\n const step = (timestamp: number) => {\n const current = regionLabelAutoLiftAnimationRef.current;\n const elapsed = Math.max(0, timestamp - current.startMs);\n const rawT = REGION_LABEL_AUTO_LIFT_ANIMATION_DURATION_MS <= 0 ? 1 : clamp(elapsed / REGION_LABEL_AUTO_LIFT_ANIMATION_DURATION_MS, 0, 1);\n const eased = smoothstep01(rawT);\n const nextValue = current.from + (current.to - current.from) * eased;\n applyRegionLabelAutoLiftOffset(nextValue);\n drawInvalidateRef.current?.();\n\n if (rawT >= 1) {\n current.rafId = null;\n applyRegionLabelAutoLiftOffset(current.to);\n return;\n }\n current.rafId = requestAnimationFrame(step);\n };\n\n animation.rafId = requestAnimationFrame(step);\n },\n [applyRegionLabelAutoLiftOffset, cancelRegionLabelAutoLiftAnimation]\n );\n\n const syncRegionLabelAutoLiftTarget = useCallback(\n (zoom: number | null | undefined) => {\n const renderer = rendererRef.current;\n if (!renderer || typeof zoom !== \"number\" || !Number.isFinite(zoom)) {\n animateRegionLabelAutoLiftTo(0);\n return;\n }\n const target = resolveRegionLabelAutoLiftOffsetPx(autoLiftRegionLabelAtMaxZoom, zoom, renderer.getZoomRange());\n animateRegionLabelAutoLiftTo(target);\n },\n [autoLiftRegionLabelAtMaxZoom, animateRegionLabelAutoLiftTo]\n );\n\n const clipPolygons = useMemo<RoiPolygon[]>(() => effectiveRoiRegions.map(region => region.coordinates as RoiPolygon), [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, { 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);\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 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 useEffect(() => {\n if (!isActiveRegionControlled) return;\n setUncontrolledActiveRegionId(controlledActiveRegionId ?? null);\n }, [isActiveRegionControlled, controlledActiveRegionId]);\n\n const commitActiveRegion = useCallback(\n (next: string | number | null) => {\n if (String(activeRegionId) === String(next)) return;\n if (!isActiveRegionControlled) {\n setUncontrolledActiveRegionId(next);\n }\n onActiveRegionChange?.(next);\n },\n [activeRegionId, isActiveRegionControlled, 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 useEffect(() => {\n return () => {\n cancelRegionLabelAutoLiftAnimation();\n };\n }, [cancelRegionLabelAutoLiftAnimation]);\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 syncRegionLabelAutoLiftTarget(next.zoom);\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, syncRegionLabelAutoLiftTarget]\n );\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) return;\n syncRegionLabelAutoLiftTarget(renderer.getViewState().zoom);\n }, [syncRegionLabelAutoLiftTarget, minZoom, maxZoom]);\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 return toDrawCoordinate(raw);\n }, []);\n\n const resolveCanvasPointerSnapshot = useCallback((clientX: number, clientY: number): { screenCoord: DrawCoordinate; canvasWidth: number; canvasHeight: number } | null => {\n const canvas = canvasRef.current;\n if (!canvas) return null;\n const rect = canvas.getBoundingClientRect();\n if (!Number.isFinite(rect.width) || !Number.isFinite(rect.height) || rect.width <= 0 || rect.height <= 0) {\n return null;\n }\n const screenX = clientX - rect.left;\n const screenY = clientY - rect.top;\n if (!Number.isFinite(screenX) || !Number.isFinite(screenY)) {\n return null;\n }\n return {\n screenCoord: [screenX, screenY],\n canvasWidth: Math.max(1, rect.width),\n canvasHeight: Math.max(1, rect.height),\n };\n }, []);\n\n const pickRegionHit = useCallback(\n (coord: DrawCoordinate, screenCoord: DrawCoordinate, canvasWidth: number, canvasHeight: number) => {\n const renderer = rendererRef.current;\n if (!renderer) return null;\n return pickPreparedRegionAt(\n coord,\n screenCoord,\n preparedRegionHits,\n renderer,\n resolvedRegionLabelStyle,\n resolveRegionLabelStyleProp,\n regionLabelAutoLiftOffsetPx,\n canvasWidth,\n canvasHeight\n );\n },\n [preparedRegionHits, resolvedRegionLabelStyle, resolveRegionLabelStyleProp, regionLabelAutoLiftOffsetPx]\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 (!preparedRegionHits.length) return;\n\n const pointerSnapshot = resolveCanvasPointerSnapshot(event.clientX, event.clientY);\n if (!pointerSnapshot) return;\n\n const hit = pickRegionHit(coord, pointerSnapshot.screenCoord, pointerSnapshot.canvasWidth, pointerSnapshot.canvasHeight);\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, preparedRegionHits, resolveWorldCoord, onRegionHover, onPointerWorldMove, source, emitPointHover, getCellByCoordinates, onPointHover, resolveCanvasPointerSnapshot, pickRegionHit]\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 (!preparedRegionHits.length) {\n commitActiveRegion(null);\n return;\n }\n\n const pointerSnapshot = resolveCanvasPointerSnapshot(event.clientX, event.clientY);\n if (!pointerSnapshot) return;\n\n const hit = pickRegionHit(coord, pointerSnapshot.screenCoord, pointerSnapshot.canvasWidth, pointerSnapshot.canvasHeight);\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, preparedRegionHits, resolveWorldCoord, onRegionClick, activeRegionId, commitActiveRegion, emitPointClick, resolveCanvasPointerSnapshot, pickRegionHit]\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 (!preparedRegionHits.length) return false;\n\n const renderer = rendererRef.current;\n const canvas = canvasRef.current;\n if (!renderer || !canvas) return false;\n const rect = canvas.getBoundingClientRect();\n if (rect.width <= 0 || rect.height <= 0) return false;\n\n const screenCoord = toDrawCoordinate(renderer.worldToScreen(coord[0], coord[1]));\n if (!screenCoord) return false;\n const hit = pickRegionHit(coord, screenCoord, rect.width, rect.height);\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, preparedRegionHits, activeRegionId, commitActiveRegion, onRegionClick, pickRegionHit]\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 imageColorSettings,\n ctrlDragRotate,\n pointSizeByZoom,\n pointStrokeScale,\n minZoom,\n maxZoom,\n viewTransition,\n });\n\n rendererRef.current = renderer;\n if (viewState) {\n renderer.setViewState(viewState);\n }\n syncRegionLabelAutoLiftTarget(renderer.getViewState().zoom);\n renderer.setInteractionLock(interactionLock);\n if (shouldTrackCustomLayerViewState) {\n setCustomLayerViewState(renderer.getViewState());\n }\n\n return () => {\n cancelRegionLabelAutoLiftAnimation();\n applyRegionLabelAutoLiftOffset(0);\n renderer.destroy();\n rendererRef.current = null;\n };\n }, [\n source,\n handleRendererStats,\n onTileError,\n onContextLost,\n onContextRestored,\n authToken,\n ctrlDragRotate,\n pointSizeByZoom,\n pointStrokeScale,\n emitViewStateChange,\n shouldTrackCustomLayerViewState,\n syncRegionLabelAutoLiftTarget,\n cancelRegionLabelAutoLiftAnimation,\n applyRegionLabelAutoLiftOffset,\n ]);\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) return;\n renderer.setPointStrokeScale(pointStrokeScale);\n }, [pointStrokeScale]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) return;\n renderer.setZoomRange(minZoom, maxZoom);\n syncRegionLabelAutoLiftTarget(renderer.getViewState().zoom);\n }, [minZoom, maxZoom, syncRegionLabelAutoLiftTarget]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) return;\n renderer.setViewTransition(viewTransition);\n }, [viewTransition]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) return;\n renderer.setImageColorSettings(imageColorSettings);\n }, [imageColorSettings]);\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\n className={className}\n style={mergedStyle}\n onPointerMove={handleRegionPointerMove}\n onPointerLeave={handleRegionPointerLeave}\n onClick={handleRegionClick}\n onContextMenu={handleRegionContextMenu}\n >\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 drawFillColor={drawFillColor}\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 resolveRegionLabelStyle={resolveRegionLabelStyleProp}\n overlayShapes={overlayShapes}\n hoveredRegionId={hoveredRegionId}\n activeRegionId={activeRegionId}\n regionLabelStyle={regionLabelStyle}\n drawAreaTooltip={drawAreaTooltip}\n autoLiftRegionLabelAtMaxZoom={autoLiftRegionLabelAtMaxZoom}\n regionLabelAutoLiftOffsetPx={regionLabelAutoLiftOffsetPx}\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 <OverviewMap\n source={source}\n projectorRef={rendererRef}\n authToken={authToken}\n options={overviewMapOptions}\n invalidateRef={overviewInvalidateRef}\n className={overviewMapConfig?.className}\n style={overviewMapConfig?.style}\n />\n )}\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","DEFAULT_SMOOTHING_PASSES","MAX_SMOOTHING_PASSES","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","smoothClosedRingChaikin","iterations","pass","clampRingToBounds","buildBrushStrokePolygon","circleSides","raster","bestRing","bestArea","area","smoothingPasses","isFiniteNumber","isCoordinatePair","isLinearRing","isPolygonRings","isMultiPolygon","polygon","closeRoiRing","normalizePolygonRings","rings","normalized","outerIndex","outerArea","normalizeRoiGeometry","geometry","pointInRing","inside","j","xi","yi","xj","yj","prepareRoiPolygons","geometries","prepared","multipolygon","outer","pointInPreparedPolygon","hole","pointInAnyPreparedPolygon","polygons","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","DEFAULT_DRAW_PREVIEW_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","DEFAULT_BRUSH_EDGE_SMOOTHING","MIN_BRUSH_EDGE_SMOOTHING","MAX_BRUSH_EDGE_SMOOTHING","MIN_BRUSH_RASTER_STEP","BRUSH_RASTER_DIAMETER_SAMPLES","BRUSH_SCREEN_STEP","DEFAULT_REGION_STROKE_STYLE","DEFAULT_PATCH_STROKE_STYLE","REGION_INTERACTION_SHADOW_COLOR","REGION_INTERACTION_SHADOW_WIDTH","DEFAULT_REGION_LABEL_STYLE","DEFAULT_DRAW_AREA_TOOLTIP_STYLE","DEFAULT_DRAW_AREA_TOOLTIP_OFFSET","REGION_LABEL_AUTO_LIFT_MAX_OFFSET_PX","REGION_LABEL_AUTO_LIFT_MAX_EPSILON","resolveRegionLabelAutoLiftOffsetPx","enabled","zoomRange","minZoom","maxZoom","isStampTool","tool","clampPositiveOrFallback","fallback","resolveStampOptions","clampUnitOpacity","sanitizeBrushLineDash","item","resolveBrushEdgeDetail","resolveBrushEdgeSmoothing","resolveBrushOptions","cursorLineWidth","edgeDetail","edgeSmoothing","mm2ToUm2","areaMm2","createSquareFromCenter","halfLength","projection","screenCenter","screenEdge","screenHL","screenCorners","worldCorners","corner","world","createCircleFromCenter","coords","createRectangle","startScreen","endScreen","createCircle","centerX","centerY","polygonArea","computeBounds","isValidPolygon","tracePath","ctx","close","drawPath","strokeStyle","fill","fillColor","resolveDrawPreviewFillColor","resolveStrokeStyle","style","dash","shadowBlur","shadowOffsetX","shadowOffsetY","mergeStrokeStyle","base","override","isSameRegionId","isNestedRingCoordinates","isCoordinateRing","collectOverlayRings","normalizeOverlayRings","sourceRings","drawInvertedFillMask","outerRing","holeRings","resolveRegionLabelStyle","px","py","bw","oy","br","mergeRegionLabelStyle","resolveDrawAreaTooltipStyle","fontSize","borderRadius","paddingX","paddingY","resolveTooltipCursorOffset","defaultDrawAreaTooltipFormatter","resolveDrawAreaTooltipOptions","format","cursorOffset","resolveRegionInteractionShadowStyle","drawRoundedRect","r","getTopAnchor","getTopAnchorFromPolygons","best","anchor","normalizeDrawRegionPolygons","normalizedOuter","holes","drawRegionLabel","text","canvasWidth","canvasHeight","labelStyle","label","boxWidth","boxHeight","left","top","drawAreaTooltipBox","cursorScreen","clampWorld","coord","imageWidth","imageHeight","toCoord","DrawLayer","stampOptions","brushOptions","projectorRef","onBrushTap","onDrawComplete","onPatchComplete","viewStateSignal","persistedRegions","patchRegions","persistedPolygons","drawFillColor","regionStrokeStyle","regionStrokeHoverStyle","regionStrokeActiveStyle","patchStrokeStyle","resolveRegionStrokeStyle","resolveRegionLabelStyleProp","overlayShapes","hoveredRegionId","activeRegionId","regionLabelStyle","drawAreaTooltip","autoLiftRegionLabelAtMaxZoom","regionLabelAutoLiftOffsetPx","invalidateRef","className","canvasRef","useRef","drawPendingRef","overlayDebugSnapshotRef","lastToolRef","sessionRef","active","mergedPersistedRegions","useMemo","index","mergedPatchRegions","preparedPersistedRegions","region","preparedPatchRegions","resolvedStrokeStyle","resolvedHoverStrokeStyle","resolvedActiveStrokeStyle","resolvedPatchStrokeStyle","resolvedDrawPreviewFillColor","resolvedLabelStyle","resolvedDrawAreaTooltipOptions","resolvedStampOptions","resolvedBrushOptions","mergedStyle","resizeCanvas","useCallback","w","h","worldToScreenPoints","projector","localScreenToWorld","screen","raw","getRectangleProjection","rotationDeg","micronsToWorldPixels","lengthUm","mppValue","imageZoomValue","viewZoomRaw","viewZoom","continuousZoom","umPerScreenPixel","buildStampCoords","stampTool","areaUm2","buildPreviewCoords","session","drawBrushStrokePreview","screenPoints","radiusPx","drawBrushCursor","cursor","drawOverlay","regionIndex","regionKey","state","resolved","interactionShadowStyle","screenOuter","screenHole","debugOverlay","imageOuterRing","shape","renderRings","closedRings","debugKey","debugSignature","preview","line","labelAutoLiftOffset","anchorWorld","anchorScreen","dynamicLabelStyle","areaCoords","areaPx","requestDraw","resetSession","preserveCursor","toWorld","event","toLocalScreen","finishSession","tapPoint","screenPath","screenPolygon","worldPolygon","handleStampAt","intent","result","appendBrushPoint","minScreenStep2","prevScreen","handlePointerDown","handlePointerMove","minWorldStep","minWorldStep2","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","strokeSymmetricDashedPolygon","dashLen","gapLen","len","from","to","sideLen","fittedLen","scale","adjDash","adjGap","toPositiveNumber","isFiniteBounds","DEFAULT_CLOSE_BUTTON_STYLE","OverviewMap","authToken","thumbnailRef","lastBoundsRef","draggingRef","rafRef","contentRect","imgW","imgH","imageAspect","boxAspect","cw","ch","margin","borderWidth","maxThumbnailTiles","backgroundColor","borderColor","viewportBorderColor","viewportBorderStyle","viewportFillColor","interactive","showThumbnail","position","onClose","closeIcon","closeButtonStyle","pos","draw","cssW","cssH","pixelW","pixelH","cx","cy","corners","safeBounds","safeCorners","isDash","right","bottom","rectW","rectH","rectCorners","toWorldFromClient","clientX","clientY","scaleX","scaleY","cxPx","cyPx","cwPx","chPx","nx","ny","recenterTo","worldX","worldY","visibleW","visibleH","drag","cancelled","levelScale","levelWidth","levelHeight","tilesX","tilesY","tileCount","requests","useAuthHeader","results","dw","dh","jsxs","TileViewerCanvas","rendererRef","renderer","sanitizePointCount","pointData","fillModesLength","filterPointDataByPolygons","empty","count","positions","fillModes","pointIds","nextPositions","nextTerms","nextFillModes","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","mapped","nowMs","filterPointDataByPolygonsHybrid","bridgeToDraw","data","safeCount","pointFillModes","bboxFlat","candidateMask","usedWebGpu","candidateCount","candidateIndices","candidateCursor","drawIndices","visibleCount","pointIndex","compactData","workerInstance","workerSupported","requestId","pendingById","createWorker","worker","_documentCurrentScript","handleWorkerMessage","handleWorkerError","msg","pending","indices","paletteIndices","ids","terminateRoiClipWorker","filterPointDataByPolygonsInWorker","positionsCopy","termsCopy","fillModesCopy","idsCopy","startMs","resolve","reject","transfer","filterPointIndicesByPolygonsInWorker","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","ax","bx","ay","by","deg","name","isSameArrayView","clonePointSizeStops","stops","stop","normalizePointSizeStops","pointSizeByZoom","zoomKey","rawSize","size","arePointSizeStopsEqual","resolvePointSizeByZoomStops","span","slope","MIN_STROKE_SCALE","MAX_STROKE_SCALE","normalizeStrokeScale","MIN_IMAGE_COLOR_INPUT","MAX_IMAGE_COLOR_INPUT","normalizeImageColorInput","toNormalizedImageColorSettings","settings","brightnessInput","contrastInput","saturationInput","MAX_VIEW_TRANSITION_DURATION_MS","linearEasing","normalizeViewTransitionDuration","duration","normalizeZoomOverride","normalizeTransitionEasing","easing","WsiTileRenderer","attemptCount","defaults","current","target","durationMs","animation","elapsed","rawT","eased","nextState","nextMinOverride","nextMaxOverride","transition","paletteSize","hasFillModes","nextPaletteIndices","hasDrawIndices","nextDrawIndices","prevHasFillModes","geometryChanged","drawIndicesChanged","maxExclusive","validCount","locked","nextStops","vp","vw","vh","clampedZoom","visibleWorldW","visibleWorldH","factor","nextZoom","worldDx","worldDy","nextCenterX","nextCenterY","marginX","marginY","halfW","halfH","minCenterX","maxCenterX","minCenterY","maxCenterY","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","uBrightness","uContrast","uSaturation","vbo","aUnit","aUv","uPointSize","uPointStrokeScale","uPalette","uPaletteSize","posBuffer","termBuffer","fillModeBuffer","indexBuffer","paletteTexture","posLoc","termLoc","fillModeLoc","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","REGION_CONTOUR_HIT_DISTANCE_PX","TOP_ANCHOR_Y_TOLERANCE","LABEL_MEASURE_FALLBACK_EM","LABEL_MEASURE_CACHE_LIMIT","REGION_LABEL_AUTO_LIFT_ANIMATION_DURATION_MS","sharedLabelMeasureContext","labelTextWidthCache","sanitizeDrawIndices","invalidFound","resolvePointHitGridSize","buildPointSpatialIndex","cellSize","buckets","pushBucket","cellX","cellY","column","bucket","resolveRegionId","smoothstep01","toDrawCoordinate","getTopAnchorFromPreparedPolygons","pointSegmentDistanceSq","lengthSq","isPointNearRing","maxDistanceSq","isPointNearPolygonContour","maxDistance","getLabelMeasureContext","measureLabelTextWidth","measured","isScreenPointInsideLabel","screenCoord","prepareRegionHits","pickPreparedRegionAt","labelStyleResolver","labelAutoLiftOffsetPx","contourHitDistance","WsiViewerCanvas","imageColorSettings","onViewStateChange","onStats","onTileError","onContextLost","onContextRestored","debugOverlayStyle","fitNonce","rotationResetNonce","ctrlDragRotate","pointPalette","pointStrokeScale","viewTransition","roiRegions","roiPolygons","clipPointsToRois","clipMode","onClipStats","onRoiPointGroups","roiPaletteIndexToTermId","interactionLock","drawTool","customLayers","onPointerWorldMove","onPointHover","onPointClick","onRegionHover","onRegionClick","controlledActiveRegionId","onActiveRegionChange","getCellByCoordinatesRef","overviewMapConfig","showOverviewMap","overviewMapOptions","drawInvalidateRef","overviewInvalidateRef","onViewStateChangeRef","onStatsRef","debugOverlayRef","setHoveredRegionId","useState","uncontrolledActiveRegionId","setUncontrolledActiveRegionId","isActiveRegionControlled","customLayerViewState","setCustomLayerViewState","debugStats","setDebugStats","setRegionLabelAutoLiftOffsetPx","hoveredRegionIdRef","hoveredPointIndexRef","hoveredPointIdRef","regionLabelAutoLiftOffsetRef","regionLabelAutoLiftAnimationRef","clipRunIdRef","safeRoiRegions","safePatchRegions","safeRoiPolygons","shouldTrackCustomLayerViewState","mergedDebugOverlayStyle","effectiveRoiRegions","preparedRegionHits","resolvedRegionLabelStyle","applyRegionLabelAutoLiftOffset","clamped","cancelRegionLabelAutoLiftAnimation","animateRegionLabelAutoLiftTo","clampedTarget","timestamp","nextValue","syncRegionLabelAutoLiftTarget","clipPolygons","renderPointData","setRenderPointData","runId","applyResult","stats","outputCount","shouldEnablePointHitTest","pointSpatialIndex","getCellByCoordinates","coordinate","pointSizePx","hitRadiusWorld","baseCellX","baseCellY","cellRadius","nearestIndex","nearestDist2","nearestX","nearestY","pointId","emitPointHover","hit","nextIndex","nextId","emitPointClick","button","commitActiveRegion","handleRendererStats","debugOverlayText","currentHover","hoveredPointIndex","emitViewStateChange","callback","resolveWorldCoord","resolveScreenCoord","resolveCanvasPointerSnapshot","pickRegionHit","requestCustomLayerRedraw","effectiveCustomLayerViewState","customLayerContext","viewStateForLayer","handleRegionPointerMove","isCanvasEvent","insideImage","pointerSnapshot","nextHoverId","prevHoverId","handleRegionPointerLeave","handleRegionClick","nextActive","handleBrushTap","handleRegionContextMenu","layer"],"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/roi-geometry.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\tsmoothingPasses?: 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 DEFAULT_SMOOTHING_PASSES = 1;\nconst MAX_SMOOTHING_PASSES = 4;\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 smoothClosedRingChaikin(\n\tring: BrushStrokeCoordinate[],\n\titerations: number,\n): BrushStrokeCoordinate[] {\n\tlet out = closeRing(ring);\n\tif (iterations <= 0 || out.length < 5) return out;\n\n\tfor (let pass = 0; pass < iterations; pass += 1) {\n\t\tconst open = out.slice(0, -1);\n\t\tif (open.length < 3) break;\n\t\tconst next: BrushStrokeCoordinate[] = [];\n\t\tfor (let i = 0; i < open.length; i += 1) {\n\t\t\tconst a = open[i];\n\t\t\tconst b = open[(i + 1) % open.length];\n\t\t\tnext.push(\n\t\t\t\t[a[0] * 0.75 + b[0] * 0.25, a[1] * 0.75 + b[1] * 0.25],\n\t\t\t\t[a[0] * 0.25 + b[0] * 0.75, a[1] * 0.25 + b[1] * 0.75],\n\t\t\t);\n\t\t}\n\t\tout = closeRing(next);\n\t}\n\treturn out;\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 smoothingPasses =\n\t\ttypeof options.smoothingPasses === \"number\" && Number.isFinite(options.smoothingPasses)\n\t\t\t? Math.round(clamp(options.smoothingPasses, 0, MAX_SMOOTHING_PASSES))\n\t\t\t: DEFAULT_SMOOTHING_PASSES;\n\tconst simplified = simplifyClosedRing(\n\t\tsmoothClosedRingChaikin(\n\t\t\tremoveCollinearVertices(bestRing, raster.step * 1e-3),\n\t\t\tsmoothingPasses,\n\t\t),\n\t\ttolerance,\n\t);\n\treturn clampRingToBounds(simplified, options.clipBounds);\n}\n","export type RoiCoordinate = [number, number];\nexport type RoiLinearRing = RoiCoordinate[];\nexport type RoiPolygonRings = RoiLinearRing[];\nexport type RoiMultiPolygon = RoiPolygonRings[];\nexport type RoiGeometry = RoiLinearRing | RoiPolygonRings | RoiMultiPolygon;\n\nexport interface PreparedRoiPolygon {\n\touter: RoiLinearRing;\n\tholes: RoiLinearRing[];\n\tminX: number;\n\tminY: number;\n\tmaxX: number;\n\tmaxY: number;\n\tarea: number;\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n\treturn typeof value === \"number\" && Number.isFinite(value);\n}\n\nfunction isCoordinatePair(value: unknown): value is RoiCoordinate {\n\treturn (\n\t\tArray.isArray(value) &&\n\t\tvalue.length >= 2 &&\n\t\tisFiniteNumber(value[0]) &&\n\t\tisFiniteNumber(value[1])\n\t);\n}\n\nfunction isLinearRing(value: unknown): value is RoiLinearRing {\n\treturn Array.isArray(value) && value.length > 0 && value.every(point => isCoordinatePair(point));\n}\n\nfunction isPolygonRings(value: unknown): value is RoiPolygonRings {\n\treturn Array.isArray(value) && value.length > 0 && value.every(ring => isLinearRing(ring));\n}\n\nfunction isMultiPolygon(value: unknown): value is RoiMultiPolygon {\n\treturn Array.isArray(value) && value.length > 0 && value.every(polygon => isPolygonRings(polygon));\n}\n\nexport function closeRoiRing(coordinates: readonly RoiCoordinate[]): RoiLinearRing {\n\tif (!Array.isArray(coordinates) || coordinates.length < 3) return [];\n\tconst out: RoiLinearRing = [];\n\tfor (const point of coordinates) {\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 && prev[0] === x && prev[1] === y) continue;\n\t\tout.push([x, y]);\n\t}\n\tif (out.length < 3) return [];\n\tconst first = out[0];\n\tconst last = out[out.length - 1];\n\tif (first[0] !== last[0] || first[1] !== last[1]) {\n\t\tout.push([first[0], first[1]]);\n\t}\n\treturn out.length >= 4 ? out : [];\n}\n\nexport function polygonSignedArea(ring: RoiLinearRing): number {\n\tif (!Array.isArray(ring) || 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 normalizePolygonRings(rings: RoiPolygonRings): RoiPolygonRings {\n\tif (!Array.isArray(rings) || rings.length === 0) return [];\n\tconst normalized: RoiLinearRing[] = [];\n\tfor (const ring of rings) {\n\t\tconst closed = closeRoiRing(ring);\n\t\tif (closed.length >= 4) normalized.push(closed);\n\t}\n\tif (normalized.length === 0) return [];\n\tif (normalized.length === 1) return [normalized[0]];\n\n\tlet outerIndex = 0;\n\tlet outerArea = 0;\n\tfor (let i = 0; i < normalized.length; i += 1) {\n\t\tconst area = Math.abs(polygonSignedArea(normalized[i]));\n\t\tif (area <= outerArea) continue;\n\t\touterArea = area;\n\t\touterIndex = i;\n\t}\n\n\tconst out: RoiPolygonRings = [normalized[outerIndex]];\n\tfor (let i = 0; i < normalized.length; i += 1) {\n\t\tif (i === outerIndex) continue;\n\t\tout.push(normalized[i]);\n\t}\n\treturn out;\n}\n\nexport function normalizeRoiGeometry(geometry: RoiGeometry | null | undefined): RoiMultiPolygon {\n\tif (!geometry) return [];\n\n\tif (isLinearRing(geometry)) {\n\t\tconst polygon = normalizePolygonRings([geometry]);\n\t\treturn polygon.length > 0 ? [polygon] : [];\n\t}\n\n\tif (isPolygonRings(geometry)) {\n\t\tconst polygon = normalizePolygonRings(geometry);\n\t\treturn polygon.length > 0 ? [polygon] : [];\n\t}\n\n\tif (isMultiPolygon(geometry)) {\n\t\tconst out: RoiMultiPolygon = [];\n\t\tfor (const polygon of geometry) {\n\t\t\tconst normalized = normalizePolygonRings(polygon);\n\t\t\tif (normalized.length > 0) out.push(normalized);\n\t\t}\n\t\treturn out;\n\t}\n\n\treturn [];\n}\n\nexport function pointInRing(x: number, y: number, ring: RoiLinearRing): 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\nexport function pointInPolygonWithHoles(\n\tx: number,\n\ty: number,\n\tpolygon: RoiPolygonRings,\n): boolean {\n\tif (!Array.isArray(polygon) || polygon.length === 0) return false;\n\tconst outer = polygon[0];\n\tif (!outer || outer.length < 4) return false;\n\tif (!pointInRing(x, y, outer)) return false;\n\tfor (let i = 1; i < polygon.length; i += 1) {\n\t\tconst hole = polygon[i];\n\t\tif (!hole || hole.length < 4) continue;\n\t\tif (pointInRing(x, y, hole)) return false;\n\t}\n\treturn true;\n}\n\nexport function prepareRoiPolygons(\n\tgeometries: readonly (RoiGeometry | null | undefined)[] | null | undefined,\n): PreparedRoiPolygon[] {\n\tconst prepared: PreparedRoiPolygon[] = [];\n\tfor (const geometry of geometries ?? []) {\n\t\tconst multipolygon = normalizeRoiGeometry(geometry);\n\t\tfor (const polygon of multipolygon) {\n\t\t\tconst outer = polygon[0];\n\t\t\tif (!outer || outer.length < 4) continue;\n\t\t\tlet minX = Infinity;\n\t\t\tlet minY = Infinity;\n\t\t\tlet maxX = -Infinity;\n\t\t\tlet maxY = -Infinity;\n\t\t\tfor (const [x, y] of outer) {\n\t\t\t\tif (x < minX) minX = x;\n\t\t\t\tif (x > maxX) maxX = x;\n\t\t\t\tif (y < minY) minY = y;\n\t\t\t\tif (y > maxY) maxY = y;\n\t\t\t}\n\t\t\tif (\n\t\t\t\t!Number.isFinite(minX) ||\n\t\t\t\t!Number.isFinite(minY) ||\n\t\t\t\t!Number.isFinite(maxX) ||\n\t\t\t\t!Number.isFinite(maxY)\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlet area = Math.abs(polygonSignedArea(outer));\n\t\t\tfor (let i = 1; i < polygon.length; i += 1) {\n\t\t\t\tarea -= Math.abs(polygonSignedArea(polygon[i]));\n\t\t\t}\n\t\t\tprepared.push({\n\t\t\t\touter,\n\t\t\t\tholes: polygon.slice(1),\n\t\t\t\tminX,\n\t\t\t\tminY,\n\t\t\t\tmaxX,\n\t\t\t\tmaxY,\n\t\t\t\tarea: Math.max(1e-6, area),\n\t\t\t});\n\t\t}\n\t}\n\treturn prepared;\n}\n\nexport function pointInPreparedPolygon(\n\tx: number,\n\ty: number,\n\tpolygon: PreparedRoiPolygon,\n): boolean {\n\tif (x < polygon.minX || x > polygon.maxX || y < polygon.minY || y > polygon.maxY) {\n\t\treturn false;\n\t}\n\tif (!pointInRing(x, y, polygon.outer)) return false;\n\tfor (const hole of polygon.holes) {\n\t\tif (pointInRing(x, y, hole)) return false;\n\t}\n\treturn true;\n}\n\nexport function pointInAnyPreparedPolygon(\n\tx: number,\n\ty: number,\n\tpolygons: readonly PreparedRoiPolygon[],\n): boolean {\n\tfor (const polygon of polygons) {\n\t\tif (!pointInPreparedPolygon(x, y, polygon)) continue;\n\t\treturn true;\n\t}\n\treturn false;\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 { normalizeRoiGeometry, type RoiGeometry } from \"../wsi/roi-geometry\";\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];\nexport type DrawRegionCoordinates = DrawCoordinate[] | DrawCoordinate[][] | DrawCoordinate[][][];\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: DrawRegionCoordinates;\n label?: string;\n}\n\nexport interface RegionStyleContext {\n region: DrawRegion;\n regionId: string | number;\n regionIndex: number;\n state: \"default\" | \"hover\" | \"active\";\n}\n\nexport type RegionStrokeStyleResolver = (context: RegionStyleContext) => Partial<RegionStrokeStyle> | null | undefined;\n\nexport interface RegionLabelStyleContext {\n region: DrawRegion;\n regionId: string | number;\n regionIndex: number;\n zoom: number;\n}\n\nexport type RegionLabelStyleResolver = (context: RegionLabelStyleContext) => Partial<RegionLabelStyle> | 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 DrawAreaTooltipStyle {\n fontFamily: string;\n fontSize: number;\n fontWeight: string | number;\n textColor: string;\n backgroundColor: string;\n borderRadius: number;\n paddingX: number;\n paddingY: number;\n}\n\nexport interface DrawAreaTooltipOptions {\n enabled?: boolean;\n format?: (areaMm2: number) => string;\n style?: Partial<DrawAreaTooltipStyle>;\n cursorOffset?: {\n x: number;\n y: number;\n };\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 getZoomRange?: () => { minZoom: number; maxZoom: 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 /**\n * Brush radius in HTML/CSS pixels (px).\n * This value is zoom-invariant: the on-screen brush size stays fixed.\n */\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 * Post-smoothing passes for brush outline to reduce stair-stepping.\n * Range: 0 ~ 4. Default: 1.\n */\n edgeSmoothing?: 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?: DrawRegionCoordinates[];\n drawFillColor?: string;\n regionStrokeStyle?: Partial<RegionStrokeStyle>;\n regionStrokeHoverStyle?: Partial<RegionStrokeStyle>;\n regionStrokeActiveStyle?: Partial<RegionStrokeStyle>;\n patchStrokeStyle?: Partial<RegionStrokeStyle>;\n resolveRegionStrokeStyle?: RegionStrokeStyleResolver;\n resolveRegionLabelStyle?: RegionLabelStyleResolver;\n overlayShapes?: DrawOverlayShape[];\n hoveredRegionId?: string | number | null;\n activeRegionId?: string | number | null;\n regionLabelStyle?: Partial<RegionLabelStyle>;\n drawAreaTooltip?: DrawAreaTooltipOptions;\n autoLiftRegionLabelAtMaxZoom?: boolean;\n regionLabelAutoLiftOffsetPx?: number;\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 cursorScreen: DrawCoordinate | null;\n points: DrawCoordinate[];\n screenPoints: DrawCoordinate[];\n stampCenter: DrawCoordinate | null;\n}\n\ninterface NormalizedDrawRegionPolygon {\n outer: DrawCoordinate[];\n holes: DrawCoordinate[][];\n}\n\ninterface PreparedRenderedRegion {\n region: DrawRegion;\n regionIndex: number;\n regionKey: string | number;\n polygons: NormalizedDrawRegionPolygon[];\n}\n\ninterface ResolvedBrushOptions {\n radius: number;\n edgeDetail: number;\n edgeSmoothing: number;\n clickSelectRoi: boolean;\n fillColor: string;\n fillOpacity: number;\n cursorColor: string;\n cursorActiveColor: string;\n cursorLineWidth: number;\n cursorLineDash: number[];\n}\n\ninterface ResolvedDrawAreaTooltipOptions {\n enabled: boolean;\n format: (areaMm2: number) => string;\n style: DrawAreaTooltipStyle;\n cursorOffsetX: number;\n cursorOffsetY: number;\n}\n\nconst DRAW_FILL = \"rgba(255, 77, 79, 0.16)\";\nconst DEFAULT_DRAW_PREVIEW_FILL = \"transparent\";\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 DEFAULT_BRUSH_EDGE_SMOOTHING = 1;\nconst MIN_BRUSH_EDGE_SMOOTHING = 0;\nconst MAX_BRUSH_EDGE_SMOOTHING = 4;\nconst MIN_BRUSH_RASTER_STEP = 0.05;\nconst BRUSH_RASTER_DIAMETER_SAMPLES = 256;\nconst BRUSH_SCREEN_STEP = 1.5; // CSS px\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 REGION_INTERACTION_SHADOW_COLOR = \"rgba(23, 23, 25, 0.1)\";\nconst REGION_INTERACTION_SHADOW_WIDTH = 6;\n\nconst DEFAULT_REGION_LABEL_STYLE: RegionLabelStyle = {\n fontFamily: \"Pretendard, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\",\n fontSize: 11,\n fontWeight: 600,\n textColor: \"#171719\",\n backgroundColor: \"#FFCC00\",\n borderColor: \"rgba(0, 0, 0, 0)\",\n borderWidth: 0,\n paddingX: 8,\n paddingY: 4,\n offsetY: 10,\n borderRadius: 4,\n};\n\nconst DEFAULT_DRAW_AREA_TOOLTIP_STYLE: DrawAreaTooltipStyle = {\n fontFamily: \"Pretendard, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\",\n fontSize: 13,\n fontWeight: 500,\n textColor: \"#FFFFFF\",\n backgroundColor: \"rgba(23, 23, 25, 0.5)\",\n borderRadius: 4,\n paddingX: 6,\n paddingY: 3,\n};\n\nconst DEFAULT_DRAW_AREA_TOOLTIP_OFFSET = {\n x: 16,\n y: -24,\n} as const;\nconst REGION_LABEL_AUTO_LIFT_MAX_OFFSET_PX = 20;\nconst REGION_LABEL_AUTO_LIFT_MAX_EPSILON = 1e-6;\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, value));\n}\n\nexport function resolveRegionLabelAutoLiftOffsetPx(\n enabled: boolean | undefined,\n zoom: number,\n zoomRange: { minZoom: number; maxZoom: number } | null | undefined\n): number {\n if (!enabled) return 0;\n if (!zoomRange) return 0;\n\n const minZoom = Number(zoomRange.minZoom);\n const maxZoom = Number(zoomRange.maxZoom);\n if (!Number.isFinite(minZoom) || !Number.isFinite(maxZoom)) return 0;\n\n if (maxZoom - minZoom <= REGION_LABEL_AUTO_LIFT_MAX_EPSILON) return 0;\n if (!Number.isFinite(zoom)) return 0;\n return zoom >= maxZoom - REGION_LABEL_AUTO_LIFT_MAX_EPSILON ? REGION_LABEL_AUTO_LIFT_MAX_OFFSET_PX : 0;\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 resolveBrushEdgeSmoothing(value: number | undefined): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return DEFAULT_BRUSH_EDGE_SMOOTHING;\n return Math.round(clamp(value, MIN_BRUSH_EDGE_SMOOTHING, MAX_BRUSH_EDGE_SMOOTHING));\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 const edgeSmoothing = resolveBrushEdgeSmoothing(options?.edgeSmoothing);\n return {\n radius,\n edgeDetail,\n edgeSmoothing,\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(\n center: DrawCoordinate | null,\n halfLength: number,\n projection?: {\n worldToScreen: (x: number, y: number) => DrawCoordinate | null;\n screenToWorld: (screen: DrawCoordinate) => DrawCoordinate | null;\n },\n): DrawCoordinate[] {\n if (!center || !Number.isFinite(halfLength) || halfLength <= 0) return [];\n\n if (projection) {\n const screenCenter = projection.worldToScreen(center[0], center[1]);\n const screenEdge = projection.worldToScreen(center[0] + halfLength, center[1]);\n if (screenCenter && screenEdge) {\n const screenHL = Math.hypot(screenEdge[0] - screenCenter[0], screenEdge[1] - screenCenter[1]);\n const screenCorners: DrawCoordinate[] = [\n [screenCenter[0] - screenHL, screenCenter[1] - screenHL],\n [screenCenter[0] + screenHL, screenCenter[1] - screenHL],\n [screenCenter[0] + screenHL, screenCenter[1] + screenHL],\n [screenCenter[0] - screenHL, screenCenter[1] + screenHL],\n ];\n const worldCorners: DrawCoordinate[] = [];\n for (const corner of screenCorners) {\n const world = projection.screenToWorld(corner);\n if (!world) throw new Error(\"Failed to create rectangle\");\n worldCorners.push(world);\n }\n return closeRing(worldCorners);\n }\n }\n\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(\n start: DrawCoordinate | null,\n end: DrawCoordinate | null,\n projection?: {\n worldToScreen: (x: number, y: number) => DrawCoordinate | null;\n screenToWorld: (screen: DrawCoordinate) => DrawCoordinate | null;\n },\n): DrawCoordinate[] {\n if (!start || !end) return [];\n\n if (projection) {\n const startScreen = projection.worldToScreen(start[0], start[1]);\n const endScreen = projection.worldToScreen(end[0], end[1]);\n\n if (startScreen && endScreen) {\n const screenCorners: DrawCoordinate[] = [\n [startScreen[0], startScreen[1]],\n [endScreen[0], startScreen[1]],\n [endScreen[0], endScreen[1]],\n [startScreen[0], endScreen[1]],\n ];\n const worldCorners: DrawCoordinate[] = [];\n for (const corner of screenCorners) {\n const world = projection.screenToWorld(corner);\n if (!world) return createRectangle(start, end);\n worldCorners.push(world);\n }\n return closeRing(worldCorners);\n }\n }\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(\n ctx: CanvasRenderingContext2D,\n points: DrawCoordinate[],\n strokeStyle: RegionStrokeStyle,\n close = false,\n fill = false,\n fillColor = DRAW_FILL\n): void {\n if (points.length === 0) return;\n\n ctx.beginPath();\n tracePath(ctx, points, close);\n if (fill && close) {\n ctx.fillStyle = fillColor;\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 resolveDrawPreviewFillColor(value: string | undefined): string {\n if (typeof value !== \"string\") return DEFAULT_DRAW_PREVIEW_FILL;\n const next = value.trim();\n return next.length > 0 ? next : DEFAULT_DRAW_PREVIEW_FILL;\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\nexport function resolveRegionLabelStyle(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\nexport function mergeRegionLabelStyle(base: RegionLabelStyle, override: Partial<RegionLabelStyle> | null | undefined): RegionLabelStyle {\n if (!override) return base;\n return resolveRegionLabelStyle({\n fontFamily: override.fontFamily ?? base.fontFamily,\n fontSize: override.fontSize ?? base.fontSize,\n fontWeight: override.fontWeight ?? base.fontWeight,\n textColor: override.textColor ?? base.textColor,\n backgroundColor: override.backgroundColor ?? base.backgroundColor,\n borderColor: override.borderColor ?? base.borderColor,\n borderWidth: override.borderWidth ?? base.borderWidth,\n paddingX: override.paddingX ?? base.paddingX,\n paddingY: override.paddingY ?? base.paddingY,\n offsetY: override.offsetY ?? base.offsetY,\n borderRadius: override.borderRadius ?? base.borderRadius,\n });\n}\n\nfunction resolveDrawAreaTooltipStyle(style: Partial<DrawAreaTooltipStyle> | undefined): DrawAreaTooltipStyle {\n const fontSize = typeof style?.fontSize === \"number\" && Number.isFinite(style.fontSize) ? Math.max(8, style.fontSize) : DEFAULT_DRAW_AREA_TOOLTIP_STYLE.fontSize;\n const borderRadius = typeof style?.borderRadius === \"number\" && Number.isFinite(style.borderRadius) ? Math.max(0, style.borderRadius) : DEFAULT_DRAW_AREA_TOOLTIP_STYLE.borderRadius;\n const paddingX = typeof style?.paddingX === \"number\" && Number.isFinite(style.paddingX) ? Math.max(0, style.paddingX) : DEFAULT_DRAW_AREA_TOOLTIP_STYLE.paddingX;\n const paddingY = typeof style?.paddingY === \"number\" && Number.isFinite(style.paddingY) ? Math.max(0, style.paddingY) : DEFAULT_DRAW_AREA_TOOLTIP_STYLE.paddingY;\n return {\n fontFamily: style?.fontFamily || DEFAULT_DRAW_AREA_TOOLTIP_STYLE.fontFamily,\n fontSize,\n fontWeight: style?.fontWeight || DEFAULT_DRAW_AREA_TOOLTIP_STYLE.fontWeight,\n textColor: style?.textColor || DEFAULT_DRAW_AREA_TOOLTIP_STYLE.textColor,\n backgroundColor: style?.backgroundColor || DEFAULT_DRAW_AREA_TOOLTIP_STYLE.backgroundColor,\n borderRadius,\n paddingX,\n paddingY,\n };\n}\n\nfunction resolveTooltipCursorOffset(value: DrawAreaTooltipOptions[\"cursorOffset\"]): { x: number; y: number } {\n const x = typeof value?.x === \"number\" && Number.isFinite(value.x) ? value.x : DEFAULT_DRAW_AREA_TOOLTIP_OFFSET.x;\n const y = typeof value?.y === \"number\" && Number.isFinite(value.y) ? value.y : DEFAULT_DRAW_AREA_TOOLTIP_OFFSET.y;\n return { x, y };\n}\n\nfunction defaultDrawAreaTooltipFormatter(areaMm2: number): string {\n if (!Number.isFinite(areaMm2)) return \"0.000 mm²\";\n return `${Math.max(0, areaMm2).toFixed(3)} mm²`;\n}\n\nfunction resolveDrawAreaTooltipOptions(options: DrawAreaTooltipOptions | undefined): ResolvedDrawAreaTooltipOptions {\n const format = typeof options?.format === \"function\" ? options.format : defaultDrawAreaTooltipFormatter;\n const cursorOffset = resolveTooltipCursorOffset(options?.cursorOffset);\n return {\n enabled: options?.enabled === true,\n format,\n style: resolveDrawAreaTooltipStyle(options?.style),\n cursorOffsetX: cursorOffset.x,\n cursorOffsetY: cursorOffset.y,\n };\n}\n\nfunction resolveRegionInteractionShadowStyle(strokeStyle: RegionStrokeStyle): RegionStrokeStyle {\n return {\n color: REGION_INTERACTION_SHADOW_COLOR,\n width: REGION_INTERACTION_SHADOW_WIDTH,\n lineDash: EMPTY_DASH,\n lineJoin: strokeStyle.lineJoin,\n lineCap: strokeStyle.lineCap,\n shadowColor: \"rgba(0, 0, 0, 0)\",\n shadowBlur: 0,\n shadowOffsetX: 0,\n shadowOffsetY: 0,\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 getTopAnchorFromPolygons(polygons: NormalizedDrawRegionPolygon[]): DrawCoordinate | null {\n let best: DrawCoordinate | null = null;\n for (const polygon of polygons) {\n const anchor = getTopAnchor(polygon.outer);\n if (!anchor) continue;\n if (!best || anchor[1] < best[1] || (anchor[1] === best[1] && anchor[0] < best[0])) {\n best = anchor;\n }\n }\n return best;\n}\n\nfunction normalizeDrawRegionPolygons(coordinates: DrawRegionCoordinates): NormalizedDrawRegionPolygon[] {\n const multipolygon = normalizeRoiGeometry(coordinates as RoiGeometry);\n if (multipolygon.length === 0) return [];\n\n const out: NormalizedDrawRegionPolygon[] = [];\n for (const polygon of multipolygon) {\n const outer = polygon[0];\n if (!outer || outer.length < 4) continue;\n const normalizedOuter = outer.map(([x, y]) => [x, y] as DrawCoordinate);\n const holes: DrawCoordinate[][] = [];\n for (let i = 1; i < polygon.length; i += 1) {\n const hole = polygon[i];\n if (!hole || hole.length < 4) continue;\n holes.push(hole.map(([x, y]) => [x, y] as DrawCoordinate));\n }\n out.push({\n outer: normalizedOuter,\n holes,\n });\n }\n return out;\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 drawAreaTooltipBox(\n ctx: CanvasRenderingContext2D,\n text: string,\n cursorScreen: DrawCoordinate,\n canvasWidth: number,\n canvasHeight: number,\n style: DrawAreaTooltipStyle,\n offsetX: number,\n offsetY: number\n): void {\n const label = text.trim();\n if (!label) return;\n\n ctx.save();\n ctx.font = `${style.fontWeight} ${style.fontSize}px ${style.fontFamily}`;\n ctx.textAlign = \"center\";\n ctx.textBaseline = \"middle\";\n\n const textWidth = ctx.measureText(label).width;\n const boxWidth = textWidth + style.paddingX * 2;\n const boxHeight = style.fontSize + style.paddingY * 2;\n\n const x = clamp(cursorScreen[0] + offsetX, boxWidth * 0.5 + 1, canvasWidth - boxWidth * 0.5 - 1);\n const y = clamp(cursorScreen[1] + 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 = style.backgroundColor;\n drawRoundedRect(ctx, left, top, boxWidth, boxHeight, style.borderRadius);\n ctx.fill();\n\n ctx.fillStyle = style.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 drawFillColor,\n regionStrokeStyle,\n regionStrokeHoverStyle,\n regionStrokeActiveStyle,\n patchStrokeStyle,\n resolveRegionStrokeStyle,\n resolveRegionLabelStyle: resolveRegionLabelStyleProp,\n overlayShapes,\n hoveredRegionId = null,\n activeRegionId = null,\n regionLabelStyle,\n drawAreaTooltip,\n autoLiftRegionLabelAtMaxZoom = false,\n regionLabelAutoLiftOffsetPx,\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 cursorScreen: null,\n points: [],\n screenPoints: [],\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 const preparedPersistedRegions = useMemo<PreparedRenderedRegion[]>(() => {\n const out: PreparedRenderedRegion[] = [];\n for (let i = 0; i < mergedPersistedRegions.length; i += 1) {\n const region = mergedPersistedRegions[i];\n const polygons = normalizeDrawRegionPolygons(region.coordinates);\n if (polygons.length === 0) continue;\n out.push({\n region,\n regionIndex: i,\n regionKey: region.id ?? i,\n polygons,\n });\n }\n return out;\n }, [mergedPersistedRegions]);\n const preparedPatchRegions = useMemo<PreparedRenderedRegion[]>(() => {\n const out: PreparedRenderedRegion[] = [];\n for (let i = 0; i < mergedPatchRegions.length; i += 1) {\n const region = mergedPatchRegions[i];\n const polygons = normalizeDrawRegionPolygons(region.coordinates);\n if (polygons.length === 0) continue;\n out.push({\n region,\n regionIndex: i,\n regionKey: region.id ?? i,\n polygons,\n });\n }\n return out;\n }, [mergedPatchRegions]);\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 const resolvedDrawPreviewFillColor = useMemo(() => resolveDrawPreviewFillColor(drawFillColor), [drawFillColor]);\n\n const resolvedLabelStyle = useMemo(() => resolveRegionLabelStyle(regionLabelStyle), [regionLabelStyle]);\n const resolvedDrawAreaTooltipOptions = useMemo(() => resolveDrawAreaTooltipOptions(drawAreaTooltip), [drawAreaTooltip]);\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 localScreenToWorld = useCallback(\n (screen: DrawCoordinate): DrawCoordinate | null => {\n const projector = projectorRef.current;\n const canvas = canvasRef.current;\n if (!projector || !canvas) return null;\n const rect = canvas.getBoundingClientRect();\n const raw = toCoord(projector.screenToWorld(rect.left + screen[0], rect.top + screen[1]));\n if (!raw) return null;\n return clampWorld(raw, imageWidth, imageHeight);\n },\n [projectorRef, imageWidth, imageHeight]\n );\n\n const getRectangleProjection = useCallback(() => {\n const projector = projectorRef.current;\n const rotationDeg = projector?.getViewState?.().rotationDeg ?? 0;\n if (Math.abs(rotationDeg % 360) < 0.01 || !projector) return undefined;\n\n return {\n worldToScreen: (x: number, y: number): DrawCoordinate | null =>\n toCoord(projector.worldToScreen(x, y)),\n screenToWorld: localScreenToWorld,\n };\n }, [projectorRef, localScreenToWorld]);\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 return createSquareFromCenter(center, halfLength, getRectangleProjection()).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, getRectangleProjection());\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, getRectangleProjection]\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, getRectangleProjection());\n }\n if (tool === \"circular\") {\n return createCircle(session.start, session.current);\n }\n\n return [];\n }, [tool, buildStampCoords, getRectangleProjection]);\n\n const drawBrushStrokePreview = useCallback(\n (ctx: CanvasRenderingContext2D): void => {\n const session = sessionRef.current;\n if (!session.isDrawing || session.screenPoints.length === 0) return;\n const screenPoints = session.screenPoints;\n if (screenPoints.length === 0) return;\n const radiusPx = 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 [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 =\n session.cursorScreen ??\n toCoord(projectorRef.current?.worldToScreen(cursor[0], cursor[1]) ?? []);\n if (!screen) return;\n const radiusPx = 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, 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 (preparedPersistedRegions.length > 0) {\n for (const entry of preparedPersistedRegions) {\n const { region, polygons, regionIndex, regionKey } = entry;\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,\n state,\n });\n strokeStyle = mergeStrokeStyle(strokeStyle, resolved || undefined);\n }\n const interactionShadowStyle = state === \"default\" ? null : resolveRegionInteractionShadowStyle(strokeStyle);\n\n for (const polygon of polygons) {\n const screenOuter = worldToScreenPoints(polygon.outer);\n if (screenOuter.length >= 4) {\n if (interactionShadowStyle) {\n drawPath(ctx, screenOuter, interactionShadowStyle, true, false);\n }\n drawPath(ctx, screenOuter, strokeStyle, true, false);\n }\n for (const hole of polygon.holes) {\n const screenHole = worldToScreenPoints(hole);\n if (screenHole.length >= 4) {\n if (interactionShadowStyle) {\n drawPath(ctx, screenHole, interactionShadowStyle, true, false);\n }\n drawPath(ctx, screenHole, strokeStyle, true, false);\n }\n }\n }\n }\n }\n\n if (preparedPatchRegions.length > 0) {\n for (const entry of preparedPatchRegions) {\n for (const polygon of entry.polygons) {\n const screenOuter = worldToScreenPoints(polygon.outer);\n if (screenOuter.length >= 4) {\n drawPath(ctx, screenOuter, resolvedPatchStrokeStyle, true, false);\n }\n for (const hole of polygon.holes) {\n const screenHole = worldToScreenPoints(hole);\n if (screenHole.length >= 4) {\n drawPath(ctx, screenHole, resolvedPatchStrokeStyle, true, false);\n }\n }\n }\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 const preview = buildPreviewCoords();\n\n if (active) {\n if (tool === \"brush\") {\n drawBrushStrokePreview(ctx);\n drawBrushCursor(ctx);\n } else 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, resolvedDrawPreviewFillColor);\n }\n } else {\n const polygon = worldToScreenPoints(preview);\n if (polygon.length >= 4) {\n drawPath(ctx, polygon, resolvedStrokeStyle, true, true, resolvedDrawPreviewFillColor);\n }\n }\n }\n }\n\n // Draw labels last so they stay visually on top.\n if (preparedPersistedRegions.length > 0) {\n const zoom = Math.max(1e-6, projectorRef.current?.getViewState?.().zoom ?? 1);\n const labelAutoLiftOffset =\n typeof regionLabelAutoLiftOffsetPx === \"number\" && Number.isFinite(regionLabelAutoLiftOffsetPx)\n ? Math.max(0, regionLabelAutoLiftOffsetPx)\n : resolveRegionLabelAutoLiftOffsetPx(autoLiftRegionLabelAtMaxZoom, zoom, projectorRef.current?.getZoomRange?.());\n for (const entry of preparedPersistedRegions) {\n if (!entry.region.label) continue;\n const anchorWorld = getTopAnchorFromPolygons(entry.polygons);\n if (!anchorWorld) continue;\n const anchorScreen = toCoord(projectorRef.current?.worldToScreen(anchorWorld[0], anchorWorld[1]) ?? []);\n if (!anchorScreen) continue;\n let dynamicLabelStyle = mergeRegionLabelStyle(\n resolvedLabelStyle,\n resolveRegionLabelStyleProp?.({\n region: entry.region,\n regionId: entry.regionKey,\n regionIndex: entry.regionIndex,\n zoom,\n })\n );\n if (labelAutoLiftOffset > 0) {\n dynamicLabelStyle = {\n ...dynamicLabelStyle,\n offsetY: dynamicLabelStyle.offsetY + labelAutoLiftOffset,\n };\n }\n drawRegionLabel(ctx, entry.region.label, anchorScreen, canvasWidth, canvasHeight, dynamicLabelStyle);\n }\n }\n\n if (resolvedDrawAreaTooltipOptions.enabled && active && (tool === \"freehand\" || tool === \"rectangle\" || tool === \"circular\")) {\n const session = sessionRef.current;\n if (session.isDrawing) {\n const areaCoords = tool === \"freehand\" ? closeRing(preview) : preview;\n if (areaCoords.length >= 4) {\n const areaPx = polygonArea(areaCoords);\n const mpp = typeof imageMpp === \"number\" && Number.isFinite(imageMpp) && imageMpp > 0 ? imageMpp : 0;\n const areaMm2 = mpp > 0 ? (areaPx * mpp * mpp) / (MICRONS_PER_MM * MICRONS_PER_MM) : 0;\n let text = defaultDrawAreaTooltipFormatter(areaMm2);\n try {\n text = resolvedDrawAreaTooltipOptions.format(areaMm2);\n } catch {\n text = defaultDrawAreaTooltipFormatter(areaMm2);\n }\n\n const cursor =\n session.cursorScreen ??\n (session.current ? toCoord(projectorRef.current?.worldToScreen(session.current[0], session.current[1]) ?? []) : null);\n if (cursor) {\n drawAreaTooltipBox(\n ctx,\n text,\n cursor,\n canvasWidth,\n canvasHeight,\n resolvedDrawAreaTooltipOptions.style,\n resolvedDrawAreaTooltipOptions.cursorOffsetX,\n resolvedDrawAreaTooltipOptions.cursorOffsetY\n );\n }\n }\n }\n }\n }, [\n active,\n tool,\n buildPreviewCoords,\n drawBrushStrokePreview,\n drawBrushCursor,\n resizeCanvas,\n worldToScreenPoints,\n imageWidth,\n imageHeight,\n projectorRef,\n preparedPersistedRegions,\n overlayShapes,\n hoveredRegionId,\n activeRegionId,\n resolvedStrokeStyle,\n resolvedHoverStrokeStyle,\n resolvedActiveStrokeStyle,\n resolvedDrawPreviewFillColor,\n preparedPatchRegions,\n resolvedPatchStrokeStyle,\n resolveRegionStrokeStyle,\n resolveRegionLabelStyleProp,\n resolvedLabelStyle,\n resolvedDrawAreaTooltipOptions,\n autoLiftRegionLabelAtMaxZoom,\n regionLabelAutoLiftOffsetPx,\n imageMpp,\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.screenPoints = [];\n session.stampCenter = null;\n if (!preserveCursor) {\n session.cursor = null;\n session.cursorScreen = 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 toLocalScreen = useCallback((event: ReactPointerEvent<HTMLCanvasElement>): DrawCoordinate | null => {\n const canvas = canvasRef.current;\n if (!canvas) return null;\n const rect = canvas.getBoundingClientRect();\n const x = clamp(event.clientX - rect.left, 0, rect.width);\n const y = clamp(event.clientY - rect.top, 0, rect.height);\n if (!Number.isFinite(x) || !Number.isFinite(y)) return null;\n return [x, y];\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, getRectangleProjection());\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 const screenPath =\n session.screenPoints.length > 0\n ? session.screenPoints\n : worldToScreenPoints(session.points);\n const screenPolygon = buildBrushStrokePolygon(screenPath, {\n radius: resolvedBrushOptions.radius,\n minRasterStep,\n circleSides: Math.max(24, Math.round(64 * edgeDetail)),\n simplifyTolerance: minRasterStep * 0.25,\n smoothingPasses: resolvedBrushOptions.edgeSmoothing,\n }) as DrawCoordinate[];\n const worldPolygon: DrawCoordinate[] = [];\n for (const point of screenPolygon) {\n const world = localScreenToWorld(point);\n if (!world) continue;\n worldPolygon.push(world);\n }\n coordinates = closeRing(worldPolygon);\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, worldToScreenPoints, localScreenToWorld, getRectangleProjection, resolvedBrushOptions.radius, resolvedBrushOptions.edgeDetail, resolvedBrushOptions.edgeSmoothing, resolvedBrushOptions.clickSelectRoi, 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, screen: DrawCoordinate): void => {\n const minScreenStep2 = BRUSH_SCREEN_STEP * BRUSH_SCREEN_STEP;\n const prevScreen = session.screenPoints[session.screenPoints.length - 1];\n if (!prevScreen) {\n session.points.push(world);\n session.screenPoints.push(screen);\n session.current = world;\n return;\n }\n const dx = screen[0] - prevScreen[0];\n const dy = screen[1] - prevScreen[1];\n if (dx * dx + dy * dy >= minScreenStep2) {\n session.points.push(world);\n session.screenPoints.push(screen);\n } else {\n session.points[session.points.length - 1] = world;\n session.screenPoints[session.screenPoints.length - 1] = screen;\n }\n session.current = world;\n },\n []\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 const screen = toLocalScreen(event);\n if (!screen) 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.cursorScreen = screen;\n session.points = tool === \"freehand\" || tool === \"brush\" ? [world] : [];\n session.screenPoints = tool === \"brush\" ? [screen] : [];\n requestDraw();\n },\n [active, tool, toWorld, toLocalScreen, 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 const screen = toLocalScreen(event);\n if (!screen) return;\n\n const session = sessionRef.current;\n session.cursor = world;\n session.cursorScreen = screen;\n\n if (isStampTool(tool)) {\n session.stampCenter = world;\n event.preventDefault();\n event.stopPropagation();\n requestDraw();\n return;\n }\n\n if (tool === \"brush\") {\n if (!session.isDrawing || session.pointerId !== event.pointerId) {\n requestDraw();\n return;\n }\n event.preventDefault();\n event.stopPropagation();\n appendBrushPoint(session, world, screen);\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, toLocalScreen, 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 const screen = toLocalScreen(event);\n if (world) {\n session.cursor = world;\n if (screen) {\n session.cursorScreen = screen;\n }\n if (tool === \"brush\") {\n if (screen) {\n appendBrushPoint(session, world, screen);\n }\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, toLocalScreen, 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 session.cursorScreen = 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 ReactNode,\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 type ViewportBorderStyle = \"stroke\" | \"dash\";\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\tviewportBorderColor: string;\n\tviewportBorderStyle: ViewportBorderStyle;\n\tviewportFillColor: string;\n\tinteractive: boolean;\n\tshowThumbnail: boolean;\n\tmaxThumbnailTiles: number;\n\tonClose?: () => void;\n\tcloseIcon?: ReactNode;\n\tcloseButtonStyle?: CSSProperties;\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: 200,\n\theight: 125,\n\tmargin: 16,\n\tposition: \"bottom-right\",\n\tborderRadius: 6,\n\tborderWidth: 0,\n\tbackgroundColor: \"rgba(4, 10, 18, 0.88)\",\n\tborderColor: \"rgba(230, 244, 255, 0.35)\",\n\tviewportBorderColor: \"#171719\",\n\tviewportBorderStyle: \"dash\",\n\tviewportFillColor: \"transparent\",\n\tinteractive: true,\n\tshowThumbnail: true,\n\tmaxThumbnailTiles: 16,\n};\n\nfunction strokeSymmetricDashedPolygon(\n\tctx: CanvasRenderingContext2D,\n\tpoints: Array<[number, number]>,\n\tdashLen: number,\n\tgapLen: number,\n): void {\n\tconst len = points.length;\n\tif (len !== 4) return;\n\tif (dashLen <= 0 || gapLen <= 0) return;\n\n\tfor (let i = 0; i < len; i += 1) {\n\t\tconst from = points[i];\n\t\tconst to = points[(i + 1) % len];\n\t\tconst sideLen = Math.hypot(to[0] - from[0], to[1] - from[1]);\n\t\tif (sideLen < 1e-6) continue;\n\n\t\tconst n = Math.max(1, Math.round((sideLen + gapLen) / (dashLen + gapLen)));\n\t\tconst fittedLen = n * dashLen + (n - 1) * gapLen;\n\t\tconst scale = sideLen / Math.max(1e-6, fittedLen);\n\t\tconst adjDash = dashLen * scale;\n\t\tconst adjGap = gapLen * scale;\n\n\t\tctx.beginPath();\n\t\tctx.moveTo(from[0], from[1]);\n\t\tctx.lineTo(to[0], to[1]);\n\t\tctx.setLineDash([adjDash, adjGap]);\n\t\tctx.lineDashOffset = 0;\n\t\tctx.stroke();\n\t}\n\n\tctx.setLineDash([]);\n\tctx.lineDashOffset = 0;\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\nconst DEFAULT_CLOSE_BUTTON_STYLE: CSSProperties = {\n\tposition: \"absolute\",\n\ttop: 4,\n\tright: 4,\n\tzIndex: 1,\n\twidth: 18,\n\theight: 18,\n\tborderRadius: 999,\n\tborder: \"1px solid rgba(255,255,255,0.4)\",\n\tbackground: \"rgba(16, 17, 19, 0.85)\",\n\tcolor: \"#fff\",\n\tfontSize: 12,\n\tlineHeight: 1,\n\tcursor: \"pointer\",\n\tpadding: 0,\n\tdisplay: \"flex\",\n\talignItems: \"center\",\n\tjustifyContent: \"center\",\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\n\tconst contentRect = useMemo(() => {\n\t\tconst imgW = Math.max(1, source.width);\n\t\tconst imgH = Math.max(1, source.height);\n\t\tconst imageAspect = imgW / imgH;\n\t\tconst boxAspect = width / height;\n\n\t\tlet cw: number;\n\t\tlet ch: number;\n\t\tif (imageAspect > boxAspect) {\n\t\t\tcw = width;\n\t\t\tch = width / imageAspect;\n\t\t} else {\n\t\t\tch = height;\n\t\t\tcw = height * imageAspect;\n\t\t}\n\n\t\treturn {\n\t\t\tx: (width - cw) / 2,\n\t\t\ty: (height - ch) / 2,\n\t\t\tw: cw,\n\t\t\th: ch,\n\t\t};\n\t}, [source.width, source.height, width, height]);\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 viewportBorderColor =\n\t\toptions?.viewportBorderColor ||\n\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.viewportBorderColor;\n\tconst viewportBorderStyle =\n\t\toptions?.viewportBorderStyle === \"stroke\" || options?.viewportBorderStyle === \"dash\"\n\t\t\t? options.viewportBorderStyle\n\t\t\t: DEFAULT_OVERVIEW_MAP_OPTIONS.viewportBorderStyle;\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\tconst onClose = options?.onClose;\n\tconst closeIcon = options?.closeIcon;\n\tconst closeButtonStyle = options?.closeButtonStyle;\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 { x: cx, y: cy, w: cw, h: ch } = contentRect;\n\n\t\tconst preview = thumbnailRef.current;\n\t\tif (preview) {\n\t\t\tctx.drawImage(preview, cx, cy, cw, ch);\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 = cw / Math.max(1, source.width);\n\t\tconst sy = ch / 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\tconst isDash = viewportBorderStyle === \"dash\";\n\n\t\tif (safeCorners) {\n\t\t\tconst screenCorners: Array<[number, number]> = safeCorners.map(\n\t\t\t\t(point) => [cx + point[0] * sx, cy + point[1] * sy],\n\t\t\t);\n\n\t\t\tctx.save();\n\t\t\tctx.beginPath();\n\t\t\tctx.rect(cx, cy, cw, ch);\n\t\t\tctx.clip();\n\n\t\t\tctx.beginPath();\n\t\t\tfor (let i = 0; i < screenCorners.length; i += 1) {\n\t\t\t\tif (i === 0) ctx.moveTo(screenCorners[i][0], screenCorners[i][1]);\n\t\t\t\telse ctx.lineTo(screenCorners[i][0], screenCorners[i][1]);\n\t\t\t}\n\t\t\tctx.closePath();\n\t\t\tctx.fillStyle = viewportFillColor;\n\t\t\tctx.fill();\n\n\t\t\tctx.strokeStyle = viewportBorderColor;\n\t\t\tctx.lineWidth = 2.25;\n\t\t\tif (isDash) {\n\t\t\t\tstrokeSymmetricDashedPolygon(ctx, screenCorners, 4, 3);\n\t\t\t} else {\n\t\t\t\tctx.stroke();\n\t\t\t}\n\n\t\t\tctx.restore();\n\t\t\treturn;\n\t\t}\n\n\t\tconst left = clamp(cx + safeBounds[0] * sx, cx, cx + cw);\n\t\tconst top = clamp(cy + safeBounds[1] * sy, cy, cy + ch);\n\t\tconst right = clamp(cx + safeBounds[2] * sx, cx, cx + cw);\n\t\tconst bottom = clamp(cy + safeBounds[3] * sy, cy, cy + ch);\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 = viewportBorderColor;\n\t\tctx.lineWidth = 2.25;\n\t\tif (isDash) {\n\t\t\tconst rectCorners: Array<[number, number]> = [\n\t\t\t\t[left + 0.5, top + 0.5],\n\t\t\t\t[left + 0.5 + Math.max(1, rectW - 1), top + 0.5],\n\t\t\t\t[left + 0.5 + Math.max(1, rectW - 1), top + 0.5 + Math.max(1, rectH - 1)],\n\t\t\t\t[left + 0.5, top + 0.5 + Math.max(1, rectH - 1)],\n\t\t\t];\n\t\t\tstrokeSymmetricDashedPolygon(ctx, rectCorners, 4, 3);\n\t\t} else {\n\t\t\tctx.strokeRect(\n\t\t\t\tleft + 0.5,\n\t\t\t\ttop + 0.5,\n\t\t\t\tMath.max(1, rectW - 1),\n\t\t\t\tMath.max(1, rectH - 1),\n\t\t\t);\n\t\t}\n\t}, [\n\t\twidth,\n\t\theight,\n\t\tcontentRect,\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\tviewportBorderColor,\n\t\tviewportBorderStyle,\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 scaleX = rect.width / width;\n\t\t\tconst scaleY = rect.height / height;\n\t\t\tconst cxPx = contentRect.x * scaleX;\n\t\t\tconst cyPx = contentRect.y * scaleY;\n\t\t\tconst cwPx = contentRect.w * scaleX;\n\t\t\tconst chPx = contentRect.h * scaleY;\n\n\t\t\tconst nx = clamp((clientX - rect.left - cxPx) / cwPx, 0, 1);\n\t\t\tconst ny = clamp((clientY - rect.top - cyPx) / chPx, 0, 1);\n\t\t\treturn [nx * source.width, ny * source.height];\n\t\t},\n\t\t[source.width, source.height, width, height, contentRect],\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(contentRect.w));\n\t\tpreview.height = Math.max(1, Math.round(contentRect.h));\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\tcontentRect,\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<div className={className} style={mergedStyle}>\n\t\t\t<canvas\n\t\t\t\tref={canvasRef}\n\t\t\t\tstyle={{\n\t\t\t\t\twidth: \"100%\",\n\t\t\t\t\theight: \"100%\",\n\t\t\t\t\tdisplay: \"block\",\n\t\t\t\t\tborderRadius: \"inherit\",\n\t\t\t\t}}\n\t\t\t\tonPointerDown={handlePointerDown}\n\t\t\t\tonPointerMove={handlePointerMove}\n\t\t\t\tonPointerUp={handlePointerUp}\n\t\t\t\tonPointerCancel={handlePointerUp}\n\t\t\t\tonContextMenu={(event) => {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}}\n\t\t\t\tonWheel={(event) => {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t}}\n\t\t\t/>\n\t\t\t{onClose && (\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\taria-label=\"Hide overview map\"\n\t\t\t\t\tonClick={(event) => {\n\t\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\t\tonClose();\n\t\t\t\t\t}}\n\t\t\t\t\tstyle={closeButtonStyle\n\t\t\t\t\t\t? {...closeButtonStyle as CSSProperties}\n\t\t\t\t\t\t: { ...DEFAULT_CLOSE_BUTTON_STYLE as CSSProperties }\n\t\t\t\t\t}\n\t\t\t\t>\n\t\t\t\t\t{closeIcon ?? \"×\"}\n\t\t\t\t</button>\n\t\t\t)}\n\t\t</div>\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\";\nimport {\n\tpointInAnyPreparedPolygon,\n\tprepareRoiPolygons,\n\ttype RoiCoordinate,\n\ttype RoiGeometry,\n} from \"./roi-geometry\";\n\nexport type { RoiCoordinate };\nexport type RoiPolygon = RoiGeometry;\n\nfunction sanitizePointCount(pointData: WsiPointData): number {\n\tconst fillModesLength =\n\t\tpointData.fillModes instanceof Uint8Array\n\t\t\t? pointData.fillModes.length\n\t\t\t: Number.MAX_SAFE_INTEGER;\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\tfillModesLength,\n\t\t),\n\t);\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 = prepareRoiPolygons(polygons ?? []);\n\tif (prepared.length === 0) {\n\t\tconst empty: WsiPointData = {\n\t\t\tcount: 0,\n\t\t\tpositions: new Float32Array(0),\n\t\t\tpaletteIndices: new Uint16Array(0),\n\t\t};\n\t\tif (pointData.fillModes instanceof Uint8Array) {\n\t\t\tempty.fillModes = new Uint8Array(0);\n\t\t}\n\t\tif (pointData.ids instanceof Uint32Array) {\n\t\t\tempty.ids = new Uint32Array(0);\n\t\t}\n\t\treturn empty;\n\t}\n\n\tconst count = sanitizePointCount(pointData);\n\tconst positions = pointData.positions;\n\tconst terms = pointData.paletteIndices;\n\tconst fillModes =\n\t\tpointData.fillModes instanceof Uint8Array && pointData.fillModes.length >= count\n\t\t\t? pointData.fillModes\n\t\t\t: null;\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 nextFillModes = fillModes ? new Uint8Array(count) : null;\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 (!pointInAnyPreparedPolygon(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 (nextFillModes) {\n\t\t\tnextFillModes[cursor] = fillModes![i];\n\t\t}\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 (nextFillModes) {\n\t\toutput.fillModes = nextFillModes.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 = prepareRoiPolygons(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 (!pointInAnyPreparedPolygon(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 {\n pointInAnyPreparedPolygon,\n prepareRoiPolygons,\n} from \"./roi-geometry\";\nimport type { WsiPointData } from \"./types\";\nimport { prefilterPointsByBoundsWebGpu } from \"./webgpu\";\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\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 = prepareRoiPolygons(polygons ?? []);\n if (prepared.length === 0) {\n const data: WsiPointData = {\n count: 0,\n positions: new Float32Array(0),\n paletteIndices: new Uint16Array(0),\n };\n if (pointData.fillModes instanceof Uint8Array) {\n data.fillModes = new Uint8Array(0);\n }\n if (pointData.ids instanceof Uint32Array) {\n data.ids = new Uint32Array(0);\n }\n return {\n data,\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 fillModesLength =\n pointData.fillModes instanceof Uint8Array ? pointData.fillModes.length : Number.MAX_SAFE_INTEGER;\n const safeCount = Math.max(0, Math.min(pointData.count, Math.floor(pointData.positions.length / 2), pointData.paletteIndices.length, fillModesLength));\n const pointFillModes = pointData.fillModes instanceof Uint8Array && pointData.fillModes.length >= safeCount ? pointData.fillModes : null;\n const pointIds = pointData.ids instanceof Uint32Array && pointData.ids.length >= safeCount ? pointData.ids : null;\n if (safeCount === 0) {\n const data: WsiPointData = {\n count: 0,\n positions: new Float32Array(0),\n paletteIndices: new Uint16Array(0),\n };\n if (pointFillModes) {\n data.fillModes = new Uint8Array(0);\n }\n if (pointIds) {\n data.ids = new Uint32Array(0);\n }\n return {\n data,\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 polygon = prepared[i];\n bboxFlat[base] = polygon.minX;\n bboxFlat[base + 1] = polygon.minY;\n bboxFlat[base + 2] = polygon.maxX;\n bboxFlat[base + 3] = polygon.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 (pointFillModes) {\n data.fillModes = pointFillModes.subarray(0, safeCount);\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 const data: WsiPointData = {\n count: 0,\n positions: new Float32Array(0),\n paletteIndices: new Uint16Array(0),\n };\n if (pointFillModes) {\n data.fillModes = new Uint8Array(0);\n }\n if (pointIds) {\n data.ids = new Uint32Array(0);\n }\n return {\n data,\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 (!pointInAnyPreparedPolygon(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 (pointFillModes) {\n data.fillModes = pointFillModes.subarray(0, safeCount);\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 nextFillModes = pointFillModes ? new Uint8Array(candidateCount) : null;\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 (!pointInAnyPreparedPolygon(x, y, prepared)) continue;\n nextPositions[cursor * 2] = x;\n nextPositions[cursor * 2 + 1] = y;\n nextTerms[cursor] = pointData.paletteIndices[pointIndex];\n if (nextFillModes) {\n nextFillModes[cursor] = pointFillModes![pointIndex];\n }\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 (nextFillModes) {\n compactData.fillModes = nextFillModes.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 fillModes = msg.fillModes ? new Uint8Array(msg.fillModes) : null;\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 (fillModes) {\n output.fillModes = fillModes.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 fillModesLength = pointData.fillModes instanceof Uint8Array ? pointData.fillModes.length : Number.MAX_SAFE_INTEGER;\n const safeCount = Math.max(0, Math.min(pointData.count, Math.floor(pointData.positions.length / 2), pointData.paletteIndices.length, fillModesLength));\n const positionsCopy = pointData.positions.slice(0, safeCount * 2);\n const termsCopy = pointData.paletteIndices.slice(0, safeCount);\n const fillModesCopy = pointData.fillModes instanceof Uint8Array && pointData.fillModes.length >= safeCount ? pointData.fillModes.slice(0, safeCount) : null;\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 fillModes: fillModesCopy?.buffer,\n ids: idsCopy?.buffer,\n polygons: polygons ?? [],\n };\n const transfer: Transferable[] = [positionsCopy.buffer, termsCopy.buffer];\n if (fillModesCopy) {\n transfer.push(fillModesCopy.buffer);\n }\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 fillModesLength = pointData.fillModes instanceof Uint8Array ? pointData.fillModes.length : Number.MAX_SAFE_INTEGER;\n const safeCount = Math.max(0, Math.min(pointData.count, Math.floor(pointData.positions.length / 2), pointData.paletteIndices.length, fillModesLength));\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\";\nimport {\n\tpointInPreparedPolygon,\n\tprepareRoiPolygons,\n\ttype PreparedRoiPolygon,\n\ttype RoiGeometry,\n} from \"./roi-geometry\";\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\tpolygons: PreparedRoiPolygon[];\n\tarea: number;\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\tconst polygons = prepareRoiPolygons([region?.coordinates as RoiGeometry | null | undefined]);\n\t\tif (polygons.length === 0) continue;\n\n\t\tlet area = 0;\n\t\tfor (const polygon of polygons) {\n\t\t\tarea += polygon.area;\n\t\t}\n\n\t\tprepared.push({\n\t\t\tregionId: region.id ?? i,\n\t\t\tregionIndex: i,\n\t\t\tpolygons,\n\t\t\tarea: Math.max(1e-6, area),\n\t\t});\n\t}\n\treturn prepared;\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\tpointData?.fillModes instanceof Uint8Array\n\t\t\t\t? pointData.fillModes.length\n\t\t\t\t: Number.MAX_SAFE_INTEGER,\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\tlet inside = false;\n\t\t\tfor (const polygon of region.polygons) {\n\t\t\t\tif (!pointInPreparedPolygon(x, y, polygon)) continue;\n\t\t\t\tinside = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (!inside) 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\tWsiImageColorSettings,\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\tuBrightness: WebGLUniformLocation;\n\tuContrast: WebGLUniformLocation;\n\tuSaturation: WebGLUniformLocation;\n}\n\ninterface PointProgram {\n\tprogram: WebGLProgram;\n\tvao: WebGLVertexArrayObject;\n\tposBuffer: WebGLBuffer;\n\ttermBuffer: WebGLBuffer;\n\tfillModeBuffer: WebGLBuffer;\n\tindexBuffer: WebGLBuffer;\n\tpaletteTexture: WebGLTexture;\n\tuCamera: WebGLUniformLocation;\n\tuPointSize: WebGLUniformLocation;\n\tuPalette: WebGLUniformLocation;\n\tuPaletteSize: WebGLUniformLocation;\n\tuPointStrokeScale: 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 WsiViewTransitionOptions {\n\tduration?: number;\n\teasing?: (t: number) => number;\n}\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\timageColorSettings?: WsiImageColorSettings | null;\n\tminZoom?: number;\n\tmaxZoom?: number;\n\tviewTransition?: WsiViewTransitionOptions;\n\tpointSizeByZoom?: PointSizeByZoom;\n\tpointStrokeScale?: number;\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\ninterface ViewAnimationState {\n\tstartMs: number;\n\tdurationMs: number;\n\tfrom: WsiViewState;\n\tto: WsiViewState;\n\teasing: (t: number) => 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\nconst MIN_STROKE_SCALE = 0.1;\nconst MAX_STROKE_SCALE = 5.0;\n\nfunction normalizeStrokeScale(value: number | null | undefined): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) return 1.0;\n\treturn clamp(value, MIN_STROKE_SCALE, MAX_STROKE_SCALE);\n}\n\nconst MIN_IMAGE_COLOR_INPUT = -100;\nconst MAX_IMAGE_COLOR_INPUT = 100;\n\ninterface NormalizedImageColorSettings {\n\tbrightness: number;\n\tcontrast: number;\n\tsaturation: number;\n}\n\nfunction normalizeImageColorInput(value: number | null | undefined): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) return 0;\n\treturn clamp(value, MIN_IMAGE_COLOR_INPUT, MAX_IMAGE_COLOR_INPUT);\n}\n\nfunction toNormalizedImageColorSettings(\n\tsettings: WsiImageColorSettings | null | undefined,\n): NormalizedImageColorSettings {\n\tconst brightnessInput = normalizeImageColorInput(settings?.brightness);\n\tconst contrastInput = normalizeImageColorInput(settings?.contrast);\n\tconst saturationInput = normalizeImageColorInput(settings?.saturation);\n\treturn {\n\t\tbrightness: brightnessInput / 200,\n\t\tcontrast: contrastInput / 100,\n\t\tsaturation: saturationInput / 100,\n\t};\n}\n\nconst MAX_VIEW_TRANSITION_DURATION_MS = 2000;\n\nfunction linearEasing(t: number): number {\n\treturn t;\n}\n\nfunction normalizeViewTransitionDuration(duration: number | null | undefined): number {\n\tif (typeof duration !== \"number\" || !Number.isFinite(duration)) return 0;\n\treturn clamp(duration, 0, MAX_VIEW_TRANSITION_DURATION_MS);\n}\n\nfunction normalizeZoomOverride(value: number | null | undefined): number | null {\n\tif (typeof value !== \"number\" || !Number.isFinite(value) || value <= 0) return null;\n\treturn Math.max(1e-6, value);\n}\n\nfunction normalizeTransitionEasing(\n\teasing: ((t: number) => number) | null | undefined,\n): (t: number) => number {\n\treturn typeof easing === \"function\" ? easing : linearEasing;\n}\n\nfunction isSameViewState(a: WsiViewState, b: WsiViewState): boolean {\n\tconst epsilon = 1e-6;\n\treturn (\n\t\tMath.abs(a.zoom - b.zoom) <= epsilon &&\n\t\tMath.abs(a.offsetX - b.offsetX) <= epsilon &&\n\t\tMath.abs(a.offsetY - b.offsetY) <= epsilon &&\n\t\tMath.abs(a.rotationDeg - b.rotationDeg) <= epsilon\n\t);\n}\n\nexport class WsiTileRenderer {\n\tprivate readonly canvas: HTMLCanvasElement;\n\tprivate readonly source: WsiImageSource;\n\tprivate readonly gl: WebGL2RenderingContext;\n\tprivate readonly camera = new OrthoCamera();\n\tprivate readonly onViewStateChange?: (next: WsiViewState) => void;\n\tprivate readonly onStats?: (stats: WsiRenderStats) => void;\n\tprivate readonly onTileError?: (event: WsiTileErrorEvent) => void;\n\tprivate readonly onContextLost?: () => void;\n\tprivate readonly onContextRestored?: () => void;\n\tprivate readonly resizeObserver: ResizeObserver;\n\tprivate tileProgram: TileVertexProgram;\n\tprivate pointProgram: PointProgram;\n\tprivate readonly tileScheduler: TileScheduler;\n\n\tprivate authToken: string;\n\tprivate destroyed = false;\n\tprivate contextLost = false;\n\tprivate frame: number | null = null;\n\tprivate frameSerial = 0;\n\tprivate dragging = false;\n\tprivate interactionMode: \"none\" | \"pan\" | \"rotate\" = \"none\";\n\tprivate rotateLastAngleRad: number | null = null;\n\tprivate pointerId: number | null = null;\n\tprivate lastPointerX = 0;\n\tprivate lastPointerY = 0;\n\tprivate interactionLocked = false;\n\tprivate ctrlDragRotate = true;\n\tprivate rotationDragSensitivityDegPerPixel = 0.35;\n\tprivate maxCacheTiles: number;\n\tprivate fitZoom = 1;\n\tprivate minZoom = 1e-6;\n\tprivate maxZoom = 1;\n\tprivate minZoomOverride: number | null = null;\n\tprivate maxZoomOverride: number | null = null;\n\tprivate viewTransitionDurationMs = 0;\n\tprivate viewTransitionEasing: (t: number) => number = linearEasing;\n\tprivate viewAnimation: ViewAnimationState | null = null;\n\tprivate viewAnimationFrame: number | null = null;\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 pointStrokeScale = 1.0;\n\tprivate imageColorSettings: NormalizedImageColorSettings = {\n\t\tbrightness: 0,\n\t\tcontrast: 0,\n\t\tsaturation: 0,\n\t};\n\tprivate lastPointData: WsiPointData | null = null;\n\tprivate lastPointPalette: Uint8Array | null = null;\n\tprivate zeroFillModes = new Uint8Array(0);\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\t\tthis.pointStrokeScale = normalizeStrokeScale(options.pointStrokeScale);\n\t\tthis.imageColorSettings = toNormalizedImageColorSettings(\n\t\t\toptions.imageColorSettings,\n\t\t);\n\t\tthis.minZoomOverride = normalizeZoomOverride(options.minZoom);\n\t\tthis.maxZoomOverride = normalizeZoomOverride(options.maxZoom);\n\t\tthis.viewTransitionDurationMs = normalizeViewTransitionDuration(options.viewTransition?.duration);\n\t\tthis.viewTransitionEasing = normalizeTransitionEasing(options.viewTransition?.easing);\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({ duration: 0 });\n\t\tthis.resize();\n\t}\n\n\tprivate resolveDefaultZoomBounds(): { minZoom: number; maxZoom: number } {\n\t\tconst minZoom = Math.max(this.fitZoom * 0.5, 1e-6);\n\t\tconst maxZoom = Math.max(1, this.fitZoom * 8);\n\t\treturn {\n\t\t\tminZoom,\n\t\t\tmaxZoom: Math.max(minZoom, maxZoom),\n\t\t};\n\t}\n\n\tprivate applyZoomBounds(): void {\n\t\tconst defaults = this.resolveDefaultZoomBounds();\n\t\tlet minZoom = this.minZoomOverride ?? defaults.minZoom;\n\t\tlet maxZoom = this.maxZoomOverride ?? defaults.maxZoom;\n\t\tminZoom = Math.max(1e-6, minZoom);\n\t\tmaxZoom = Math.max(1e-6, maxZoom);\n\t\tif (minZoom > maxZoom) {\n\t\t\tminZoom = maxZoom;\n\t\t}\n\t\tthis.minZoom = minZoom;\n\t\tthis.maxZoom = maxZoom;\n\t}\n\n\tprivate resolveTargetViewState(next: Partial<WsiViewState>): WsiViewState {\n\t\tconst current = this.camera.getViewState();\n\t\tconst candidate: WsiViewState = {\n\t\t\tzoom:\n\t\t\t\ttypeof next.zoom === \"number\" && Number.isFinite(next.zoom)\n\t\t\t\t\t? clamp(next.zoom, this.minZoom, this.maxZoom)\n\t\t\t\t\t: current.zoom,\n\t\t\toffsetX:\n\t\t\t\ttypeof next.offsetX === \"number\" && Number.isFinite(next.offsetX)\n\t\t\t\t\t? next.offsetX\n\t\t\t\t\t: current.offsetX,\n\t\t\toffsetY:\n\t\t\t\ttypeof next.offsetY === \"number\" && Number.isFinite(next.offsetY)\n\t\t\t\t\t? next.offsetY\n\t\t\t\t\t: current.offsetY,\n\t\t\trotationDeg:\n\t\t\t\ttypeof next.rotationDeg === \"number\" && Number.isFinite(next.rotationDeg)\n\t\t\t\t\t? next.rotationDeg\n\t\t\t\t\t: current.rotationDeg,\n\t\t};\n\n\t\tthis.camera.setViewState(candidate);\n\t\tthis.clampViewState();\n\t\tconst target = this.camera.getViewState();\n\t\tthis.camera.setViewState(current);\n\t\treturn target;\n\t}\n\n\tprivate cancelViewAnimation(): void {\n\t\tthis.viewAnimation = null;\n\t\tif (this.viewAnimationFrame !== null) {\n\t\t\tcancelAnimationFrame(this.viewAnimationFrame);\n\t\t\tthis.viewAnimationFrame = null;\n\t\t}\n\t}\n\n\tprivate startViewAnimation(\n\t\ttarget: WsiViewState,\n\t\tdurationMs: number,\n\t\teasing: (t: number) => number,\n\t): void {\n\t\tconst from = this.camera.getViewState();\n\t\tthis.cancelViewAnimation();\n\t\tthis.viewAnimation = {\n\t\t\tstartMs: nowMs(),\n\t\t\tdurationMs: Math.max(0, durationMs),\n\t\t\tfrom,\n\t\t\tto: target,\n\t\t\teasing,\n\t\t};\n\n\t\tconst step = (): void => {\n\t\t\tconst animation = this.viewAnimation;\n\t\t\tif (!animation) return;\n\n\t\t\tconst elapsed = Math.max(0, nowMs() - animation.startMs);\n\t\t\tconst rawT =\n\t\t\t\tanimation.durationMs <= 0 ? 1 : clamp(elapsed / animation.durationMs, 0, 1);\n\t\t\tlet eased = rawT;\n\t\t\ttry {\n\t\t\t\teased = animation.easing(rawT);\n\t\t\t} catch {\n\t\t\t\teased = rawT;\n\t\t\t}\n\t\t\tif (!Number.isFinite(eased)) {\n\t\t\t\teased = rawT;\n\t\t\t}\n\t\t\teased = clamp(eased, 0, 1);\n\n\t\t\tconst nextState: WsiViewState = {\n\t\t\t\tzoom: animation.from.zoom + (animation.to.zoom - animation.from.zoom) * eased,\n\t\t\t\toffsetX:\n\t\t\t\t\tanimation.from.offsetX +\n\t\t\t\t\t(animation.to.offsetX - animation.from.offsetX) * eased,\n\t\t\t\toffsetY:\n\t\t\t\t\tanimation.from.offsetY +\n\t\t\t\t\t(animation.to.offsetY - animation.from.offsetY) * eased,\n\t\t\t\trotationDeg:\n\t\t\t\t\tanimation.from.rotationDeg +\n\t\t\t\t\t(animation.to.rotationDeg - animation.from.rotationDeg) * eased,\n\t\t\t};\n\n\t\t\tthis.camera.setViewState(nextState);\n\t\t\tthis.clampViewState();\n\t\t\tthis.emitViewState();\n\t\t\tthis.requestRender();\n\n\t\t\tif (rawT >= 1) {\n\t\t\t\tthis.viewAnimation = null;\n\t\t\t\tthis.viewAnimationFrame = null;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.viewAnimationFrame = requestAnimationFrame(step);\n\t\t};\n\n\t\tthis.viewAnimationFrame = requestAnimationFrame(step);\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\tsetZoomRange(minZoom: number | null | undefined, maxZoom: number | null | undefined): void {\n\t\tconst nextMinOverride = normalizeZoomOverride(minZoom);\n\t\tconst nextMaxOverride = normalizeZoomOverride(maxZoom);\n\t\tif (\n\t\t\tthis.minZoomOverride === nextMinOverride &&\n\t\t\tthis.maxZoomOverride === nextMaxOverride\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.minZoomOverride = nextMinOverride;\n\t\tthis.maxZoomOverride = nextMaxOverride;\n\t\tthis.applyZoomBounds();\n\n\t\tconst target = this.resolveTargetViewState({});\n\t\tconst current = this.camera.getViewState();\n\t\tif (isSameViewState(current, target)) {\n\t\t\treturn;\n\t\t}\n\t\tthis.cancelViewAnimation();\n\t\tthis.camera.setViewState(target);\n\t\tthis.emitViewState();\n\t\tthis.requestRender();\n\t}\n\n\tsetViewTransition(options: WsiViewTransitionOptions | null | undefined): void {\n\t\tthis.viewTransitionDurationMs = normalizeViewTransitionDuration(options?.duration);\n\t\tthis.viewTransitionEasing = normalizeTransitionEasing(options?.easing);\n\t}\n\n\tsetViewState(\n\t\tnext: Partial<WsiViewState>,\n\t\ttransition?: WsiViewTransitionOptions,\n\t): void {\n\t\tconst target = this.resolveTargetViewState(next);\n\t\tconst current = this.camera.getViewState();\n\t\tif (isSameViewState(current, target)) return;\n\n\t\tconst durationMs = normalizeViewTransitionDuration(\n\t\t\ttransition?.duration ?? this.viewTransitionDurationMs,\n\t\t);\n\t\tconst easing = normalizeTransitionEasing(\n\t\t\ttransition?.easing ?? this.viewTransitionEasing,\n\t\t);\n\t\tif (durationMs <= 0) {\n\t\t\tthis.cancelViewAnimation();\n\t\t\tthis.camera.setViewState(target);\n\t\t\tthis.emitViewState();\n\t\t\tthis.requestRender();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.startViewAnimation(target, durationMs, easing);\n\t}\n\n\tgetViewState(): WsiViewState {\n\t\treturn this.camera.getViewState();\n\t}\n\n\tgetZoomRange(): { minZoom: number; maxZoom: number } {\n\t\treturn { minZoom: this.minZoom, maxZoom: this.maxZoom };\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 pointFillModes =\n\t\t\tpoints.fillModes instanceof Uint8Array ? points.fillModes : null;\n\t\tconst hasFillModes = pointFillModes !== null;\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\thasFillModes ? pointFillModes.length : Number.MAX_SAFE_INTEGER,\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 nextFillModes = hasFillModes\n\t\t\t? pointFillModes.subarray(0, safeCount)\n\t\t\t: undefined;\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\tconst prevHasFillModes = prev?.fillModes instanceof Uint8Array;\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\t\tprevHasFillModes !== hasFillModes ||\n\t\t\t(hasFillModes &&\n\t\t\t\t(!prev?.fillModes || !isSameArrayView(prev.fillModes, nextFillModes)));\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\tfillModes: nextFillModes,\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\n\t\t\tgl.bindBuffer(gl.ARRAY_BUFFER, this.pointProgram.fillModeBuffer);\n\t\t\tgl.bufferData(\n\t\t\t\tgl.ARRAY_BUFFER,\n\t\t\t\tthis.lastPointData.fillModes ?? this.getZeroFillModes(safeCount),\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\tprivate getZeroFillModes(count: number): Uint8Array {\n\t\tif (count <= 0) return new Uint8Array(0);\n\t\tif (this.zeroFillModes.length < count) {\n\t\t\tthis.zeroFillModes = new Uint8Array(count);\n\t\t}\n\t\treturn this.zeroFillModes.subarray(0, count);\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\tsetPointStrokeScale(scale: number | null | undefined): void {\n\t\tconst next = normalizeStrokeScale(scale);\n\t\tif (this.pointStrokeScale === next) return;\n\t\tthis.pointStrokeScale = next;\n\t\tthis.requestRender();\n\t}\n\n\tsetImageColorSettings(settings: WsiImageColorSettings | null | undefined): void {\n\t\tconst next = toNormalizedImageColorSettings(settings);\n\t\tconst prev = this.imageColorSettings;\n\t\tif (\n\t\t\tprev.brightness === next.brightness &&\n\t\t\tprev.contrast === next.contrast &&\n\t\t\tprev.saturation === next.saturation\n\t\t) {\n\t\t\treturn;\n\t\t}\n\t\tthis.imageColorSettings = next;\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(\n\t\tworldX: number,\n\t\tworldY: number,\n\t\ttransition?: WsiViewTransitionOptions,\n\t): void {\n\t\tif (!Number.isFinite(worldX) || !Number.isFinite(worldY)) return;\n\t\tconst state = this.camera.getViewState();\n\t\tconst zoom = Math.max(1e-6, state.zoom);\n\t\tconst vp = this.camera.getViewport();\n\t\tthis.setViewState(\n\t\t\t{\n\t\t\t\toffsetX: worldX - vp.width / (2 * zoom),\n\t\t\t\toffsetY: worldY - vp.height / (2 * zoom),\n\t\t\t},\n\t\t\ttransition,\n\t\t);\n\t}\n\n\tgetViewCorners(): [WorldPoint, WorldPoint, WorldPoint, WorldPoint] {\n\t\treturn this.camera.getViewCorners();\n\t}\n\n\tresetRotation(transition?: WsiViewTransitionOptions): void {\n\t\tconst state = this.camera.getViewState();\n\t\tif (Math.abs(state.rotationDeg) < 1e-6) return;\n\t\tthis.setViewState({ rotationDeg: 0 }, transition);\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(transition?: WsiViewTransitionOptions): 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.applyZoomBounds();\n\t\tconst clampedZoom = clamp(safeZoom, this.minZoom, this.maxZoom);\n\t\tconst visibleWorldW = vw / clampedZoom;\n\t\tconst visibleWorldH = vh / clampedZoom;\n\n\t\tthis.setViewState(\n\t\t\t{\n\t\t\t\tzoom: clampedZoom,\n\t\t\t\toffsetX: (this.source.width - visibleWorldW) * 0.5,\n\t\t\t\toffsetY: (this.source.height - visibleWorldH) * 0.5,\n\t\t\t\trotationDeg: 0,\n\t\t\t},\n\t\t\ttransition,\n\t\t);\n\t}\n\n\tzoomBy(\n\t\tfactor: number,\n\t\tscreenX: number,\n\t\tscreenY: number,\n\t\ttransition?: WsiViewTransitionOptions,\n\t): 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\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(state.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\tconst nextCenterX = worldX - worldDx;\n\t\tconst nextCenterY = worldY - worldDy;\n\n\t\tthis.setViewState(\n\t\t\t{\n\t\t\t\tzoom: nextZoom,\n\t\t\t\toffsetX: nextCenterX - vp.width / (2 * nextZoom),\n\t\t\t\toffsetY: nextCenterY - vp.height / (2 * nextZoom),\n\t\t\t},\n\t\t\ttransition,\n\t\t);\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\t\tgl.uniform1f(tileProgram.uBrightness, this.imageColorSettings.brightness);\n\t\tgl.uniform1f(tileProgram.uContrast, this.imageColorSettings.contrast);\n\t\tgl.uniform1f(tileProgram.uSaturation, this.imageColorSettings.saturation);\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.uPointStrokeScale, this.pointStrokeScale);\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\tthis.cancelViewAnimation();\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\t\tthis.cancelViewAnimation();\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\t\tthis.cancelViewAnimation();\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.fillModeBuffer);\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 uniform float uBrightness;\n uniform float uContrast;\n uniform float uSaturation;\n out vec4 outColor;\n void main() {\n vec4 color = texture(uTexture, vUv);\n\n color.rgb = clamp(\n (uContrast + 1.0) * color.rgb - (uContrast / 2.0),\n vec3(0.0),\n vec3(1.0)\n );\n\n float saturation = uSaturation + 1.0;\n float sr = (1.0 - saturation) * 0.2126;\n float sg = (1.0 - saturation) * 0.7152;\n float sb = (1.0 - saturation) * 0.0722;\n mat3 saturationMatrix = mat3(\n sr + saturation, sr, sr,\n sg, sg + saturation, sg,\n sb, sb, sb + saturation\n );\n color.rgb = clamp(saturationMatrix * color.rgb, vec3(0.0), vec3(1.0));\n\n color.rgb = clamp(color.rgb + uBrightness, vec3(0.0), vec3(1.0));\n outColor = color;\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\t\tconst uBrightness = requireUniformLocation(gl, program, \"uBrightness\");\n\t\tconst uContrast = requireUniformLocation(gl, program, \"uContrast\");\n\t\tconst uSaturation = requireUniformLocation(gl, program, \"uSaturation\");\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 {\n\t\t\tprogram,\n\t\t\tvao,\n\t\t\tvbo,\n\t\t\tuCamera,\n\t\t\tuBounds,\n\t\t\tuTexture,\n\t\t\tuBrightness,\n\t\t\tuContrast,\n\t\t\tuSaturation,\n\t\t};\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 in uint aFillMode;\n uniform mat3 uCamera;\n uniform float uPointSize;\n flat out uint vTerm;\n flat out uint vFillMode;\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 vFillMode = aFillMode;\n }`;\n\n\t\tconst pointFragment = `#version 300 es\n precision highp float;\n flat in uint vTerm;\n flat in uint vFillMode;\n uniform sampler2D uPalette;\n uniform float uPaletteSize;\n uniform float uPointSize;\n uniform float uPointStrokeScale;\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 aa = 1.5 / max(1.0, uPointSize);\n float outerMask = 1.0 - smoothstep(1.0 - aa, 1.0 + aa, r);\n float alpha = 0.0;\n if (vFillMode != 0u) {\n alpha = outerMask * color.a;\n } else {\n float s = uPointStrokeScale;\n float ringWidth = clamp(3.0 * s / max(1.0, uPointSize), 0.12 * s, 0.62 * s);\n float innerRadius = 1.0 - ringWidth;\n float innerMask = smoothstep(innerRadius - aa, innerRadius + aa, r);\n alpha = outerMask * innerMask * color.a;\n }\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 uPointStrokeScale = requireUniformLocation(gl, program, \"uPointStrokeScale\");\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 fillModeBuffer = gl.createBuffer();\n\t\tconst indexBuffer = gl.createBuffer();\n\t\tconst paletteTexture = gl.createTexture();\n\t\tif (!vao || !posBuffer || !termBuffer || !fillModeBuffer || !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.ARRAY_BUFFER, fillModeBuffer);\n\t\tgl.bufferData(gl.ARRAY_BUFFER, 0, gl.DYNAMIC_DRAW);\n\t\tconst fillModeLoc = gl.getAttribLocation(program, \"aFillMode\");\n\t\tif (fillModeLoc < 0) {\n\t\t\tthrow new Error(\"point fill mode attribute not found\");\n\t\t}\n\t\tgl.enableVertexAttribArray(fillModeLoc);\n\t\tgl.vertexAttribIPointer(fillModeLoc, 1, gl.UNSIGNED_BYTE, 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\tfillModeBuffer,\n\t\t\tindexBuffer,\n\t\t\tpaletteTexture,\n\t\t\tuCamera,\n\t\t\tuPointSize,\n\t\t\tuPointStrokeScale,\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 {\n type CSSProperties,\n type MutableRefObject,\n type MouseEvent as ReactMouseEvent,\n type ReactNode,\n type PointerEvent as ReactPointerEvent,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} 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 { type PreparedRoiPolygon, prepareRoiPolygons, type RoiGeometry } from \"../wsi/roi-geometry\";\nimport { computeRoiPointGroups, type RoiPointGroupStats } from \"../wsi/roi-term-stats\";\nimport type {\n WsiImageColorSettings,\n WsiImageSource,\n WsiPointData,\n WsiRegion,\n WsiRenderStats,\n WsiViewState,\n} from \"../wsi/types\";\nimport { type PointSizeByZoom, type WsiTileErrorEvent, type WsiViewTransitionOptions, WsiTileRenderer } from \"../wsi/wsi-tile-renderer\";\nimport type {\n BrushOptions,\n DrawAreaTooltipOptions,\n DrawCoordinate,\n DrawOverlayShape,\n DrawRegionCoordinates,\n DrawResult,\n DrawTool,\n PatchDrawResult,\n RegionLabelStyle,\n RegionLabelStyleResolver,\n RegionStrokeStyle,\n RegionStrokeStyleResolver,\n StampOptions,\n} from \"./draw-layer\";\nimport { DrawLayer, mergeRegionLabelStyle, resolveRegionLabelAutoLiftOffsetPx, resolveRegionLabelStyle } from \"./draw-layer\";\nimport { OverviewMap, type OverviewMapOptions } from \"./overview-map\";\n\nconst EMPTY_ROI_REGIONS: WsiRegion[] = [];\nconst EMPTY_ROI_POLYGONS: DrawRegionCoordinates[] = [];\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;\nconst REGION_CONTOUR_HIT_DISTANCE_PX = 6;\nconst TOP_ANCHOR_Y_TOLERANCE = 0.5;\nconst LABEL_MEASURE_FALLBACK_EM = 0.58;\nconst LABEL_MEASURE_CACHE_LIMIT = 4096;\nconst REGION_LABEL_AUTO_LIFT_ANIMATION_DURATION_MS = 180;\nconst REGION_LABEL_AUTO_LIFT_MAX_OFFSET_PX = 20;\n\nlet sharedLabelMeasureContext: CanvasRenderingContext2D | null = null;\nconst labelTextWidthCache = new Map<string, number>();\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\ninterface PreparedRegionHit {\n region: WsiRegion;\n regionIndex: number;\n regionId: string | number;\n polygons: PreparedRoiPolygon[];\n label: string;\n labelAnchor: DrawCoordinate | null;\n}\n\nfunction sanitizePointCount(pointData: WsiPointData): number {\n const fillModesLength = pointData.fillModes instanceof Uint8Array ? pointData.fillModes.length : Number.MAX_SAFE_INTEGER;\n return Math.max(0, Math.min(Math.floor(pointData.count ?? 0), Math.floor((pointData.positions?.length ?? 0) / 2), pointData.paletteIndices?.length ?? 0, fillModesLength));\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 clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, value));\n}\n\nfunction smoothstep01(t: number): number {\n const x = clamp(t, 0, 1);\n return x * x * (3 - 2 * x);\n}\n\nfunction toDrawCoordinate(value: unknown): 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\nfunction getTopAnchor(ring: DrawCoordinate[]): DrawCoordinate | null {\n if (ring.length === 0) return null;\n let minY = Infinity;\n for (const point of ring) {\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 ring) {\n if (Math.abs(point[1] - minY) > TOP_ANCHOR_Y_TOLERANCE) continue;\n if (point[0] < minX) minX = point[0];\n if (point[0] > maxX) maxX = point[0];\n }\n if (!Number.isFinite(minX) || !Number.isFinite(maxX)) return null;\n return [(minX + maxX) * 0.5, minY];\n}\n\nfunction getTopAnchorFromPreparedPolygons(polygons: PreparedRoiPolygon[]): DrawCoordinate | null {\n let best: DrawCoordinate | null = null;\n for (const polygon of polygons) {\n const anchor = getTopAnchor(polygon.outer);\n if (!anchor) continue;\n if (!best || anchor[1] < best[1] || (anchor[1] === best[1] && anchor[0] < best[0])) {\n best = anchor;\n }\n }\n return best;\n}\n\nfunction pointSegmentDistanceSq(px: number, py: number, ax: number, ay: number, bx: number, by: number): number {\n const abx = bx - ax;\n const aby = by - ay;\n const lengthSq = abx * abx + aby * aby;\n if (lengthSq <= 1e-12) {\n const dx = px - ax;\n const dy = py - ay;\n return dx * dx + dy * dy;\n }\n const t = clamp(((px - ax) * abx + (py - ay) * aby) / lengthSq, 0, 1);\n const nx = ax + abx * t;\n const ny = ay + aby * t;\n const dx = px - nx;\n const dy = py - ny;\n return dx * dx + dy * dy;\n}\n\nfunction isPointNearRing(x: number, y: number, ring: DrawCoordinate[], maxDistanceSq: number): boolean {\n for (let i = 1; i < ring.length; i += 1) {\n const prev = ring[i - 1];\n const next = ring[i];\n if (pointSegmentDistanceSq(x, y, prev[0], prev[1], next[0], next[1]) <= maxDistanceSq) {\n return true;\n }\n }\n return false;\n}\n\nfunction isPointNearPolygonContour(x: number, y: number, polygon: PreparedRoiPolygon, maxDistance: number): boolean {\n if (x < polygon.minX - maxDistance || x > polygon.maxX + maxDistance || y < polygon.minY - maxDistance || y > polygon.maxY + maxDistance) {\n return false;\n }\n const maxDistanceSq = maxDistance * maxDistance;\n if (isPointNearRing(x, y, polygon.outer, maxDistanceSq)) return true;\n for (const hole of polygon.holes) {\n if (isPointNearRing(x, y, hole, maxDistanceSq)) return true;\n }\n return false;\n}\n\nfunction getLabelMeasureContext(): CanvasRenderingContext2D | null {\n if (sharedLabelMeasureContext) return sharedLabelMeasureContext;\n if (typeof document === \"undefined\") return null;\n const canvas = document.createElement(\"canvas\");\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return null;\n sharedLabelMeasureContext = ctx;\n return sharedLabelMeasureContext;\n}\n\nfunction measureLabelTextWidth(label: string, labelStyle: RegionLabelStyle): number {\n const key = `${labelStyle.fontWeight}|${labelStyle.fontSize}|${labelStyle.fontFamily}|${label}`;\n const cached = labelTextWidthCache.get(key);\n if (cached !== undefined) return cached;\n\n const fallback = label.length * labelStyle.fontSize * LABEL_MEASURE_FALLBACK_EM;\n const ctx = getLabelMeasureContext();\n let width = fallback;\n if (ctx) {\n ctx.font = `${labelStyle.fontWeight} ${labelStyle.fontSize}px ${labelStyle.fontFamily}`;\n const measured = ctx.measureText(label).width;\n if (Number.isFinite(measured) && measured >= 0) {\n width = measured;\n }\n }\n\n if (labelTextWidthCache.size > LABEL_MEASURE_CACHE_LIMIT) {\n labelTextWidthCache.clear();\n }\n labelTextWidthCache.set(key, width);\n return width;\n}\n\nfunction isScreenPointInsideLabel(\n region: PreparedRegionHit,\n screenCoord: DrawCoordinate,\n renderer: WsiTileRenderer,\n labelStyle: RegionLabelStyle,\n canvasWidth: number,\n canvasHeight: number\n): boolean {\n if (!region.label || !region.labelAnchor) return false;\n\n const anchorScreen = toDrawCoordinate(renderer.worldToScreen(region.labelAnchor[0], region.labelAnchor[1]));\n if (!anchorScreen) return false;\n\n const textWidth = measureLabelTextWidth(region.label, labelStyle);\n const boxWidth = textWidth + labelStyle.paddingX * 2;\n const boxHeight = labelStyle.fontSize + labelStyle.paddingY * 2;\n\n const x = clamp(anchorScreen[0], boxWidth * 0.5 + 1, canvasWidth - boxWidth * 0.5 - 1);\n const y = clamp(anchorScreen[1] - labelStyle.offsetY, boxHeight * 0.5 + 1, canvasHeight - boxHeight * 0.5 - 1);\n const left = x - boxWidth * 0.5;\n const right = x + boxWidth * 0.5;\n const top = y - boxHeight * 0.5;\n const bottom = y + boxHeight * 0.5;\n\n return screenCoord[0] >= left && screenCoord[0] <= right && screenCoord[1] >= top && screenCoord[1] <= bottom;\n}\n\nfunction prepareRegionHits(regions: WsiRegion[]): PreparedRegionHit[] {\n const out: PreparedRegionHit[] = [];\n for (let i = 0; i < regions.length; i += 1) {\n const region = regions[i];\n const polygons = prepareRoiPolygons([region?.coordinates as RoiGeometry | null | undefined]);\n if (polygons.length === 0) continue;\n const label = typeof region?.label === \"string\" ? region.label.trim() : \"\";\n out.push({\n region,\n regionIndex: i,\n regionId: resolveRegionId(region, i),\n polygons,\n label,\n labelAnchor: label ? getTopAnchorFromPreparedPolygons(polygons) : null,\n });\n }\n return out;\n}\n\nfunction pickPreparedRegionAt(\n coord: DrawCoordinate,\n screenCoord: DrawCoordinate,\n regions: PreparedRegionHit[],\n renderer: WsiTileRenderer,\n labelStyle: RegionLabelStyle,\n labelStyleResolver: RegionLabelStyleResolver | undefined,\n labelAutoLiftOffsetPx: number,\n canvasWidth: number,\n canvasHeight: number\n): {\n region: WsiRegion;\n regionIndex: number;\n regionId: string | number;\n} | null {\n const x = coord[0];\n const y = coord[1];\n const zoom = Math.max(1e-6, renderer.getViewState().zoom);\n const labelAutoLiftOffset = Math.max(0, labelAutoLiftOffsetPx);\n const contourHitDistance = REGION_CONTOUR_HIT_DISTANCE_PX / zoom;\n for (let i = regions.length - 1; i >= 0; i -= 1) {\n const region = regions[i];\n for (const polygon of region.polygons) {\n if (!isPointNearPolygonContour(x, y, polygon, contourHitDistance)) continue;\n return {\n region: region.region,\n regionIndex: region.regionIndex,\n regionId: region.regionId,\n };\n }\n let dynamicLabelStyle = mergeRegionLabelStyle(\n labelStyle,\n labelStyleResolver?.({\n region: region.region,\n regionId: region.regionId,\n regionIndex: region.regionIndex,\n zoom,\n })\n );\n if (labelAutoLiftOffset > 0) {\n dynamicLabelStyle = {\n ...dynamicLabelStyle,\n offsetY: dynamicLabelStyle.offsetY + labelAutoLiftOffset,\n };\n }\n if (!isScreenPointInsideLabel(region, screenCoord, renderer, dynamicLabelStyle, canvasWidth, canvasHeight)) continue;\n return {\n region: region.region,\n regionIndex: region.regionIndex,\n regionId: region.regionId,\n };\n }\n return null;\n}\n\nexport interface OverviewMapConfig {\n show?: boolean;\n options?: Partial<OverviewMapOptions>;\n className?: string;\n style?: CSSProperties;\n}\n\nexport interface WsiViewerCanvasProps {\n source: WsiImageSource | null;\n viewState?: Partial<WsiViewState> | null;\n imageColorSettings?: WsiImageColorSettings | 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 pointStrokeScale?: number;\n minZoom?: number;\n maxZoom?: number;\n viewTransition?: WsiViewTransitionOptions;\n roiRegions?: WsiRegion[];\n roiPolygons?: DrawRegionCoordinates[];\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 drawFillColor?: string;\n regionStrokeStyle?: Partial<RegionStrokeStyle>;\n regionStrokeHoverStyle?: Partial<RegionStrokeStyle>;\n regionStrokeActiveStyle?: Partial<RegionStrokeStyle>;\n patchStrokeStyle?: Partial<RegionStrokeStyle>;\n resolveRegionStrokeStyle?: RegionStrokeStyleResolver;\n resolveRegionLabelStyle?: RegionLabelStyleResolver;\n overlayShapes?: DrawOverlayShape[];\n customLayers?: WsiCustomLayer[];\n patchRegions?: WsiRegion[];\n regionLabelStyle?: Partial<RegionLabelStyle>;\n drawAreaTooltip?: DrawAreaTooltipOptions;\n autoLiftRegionLabelAtMaxZoom?: boolean;\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 activeRegionId?: string | number | null;\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 overviewMapConfig?: OverviewMapConfig;\n className?: string;\n style?: CSSProperties;\n}\n\nexport function WsiViewerCanvas({\n source,\n viewState,\n imageColorSettings = null,\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 pointStrokeScale,\n minZoom,\n maxZoom,\n viewTransition,\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 drawFillColor,\n regionStrokeStyle,\n regionStrokeHoverStyle,\n regionStrokeActiveStyle,\n patchStrokeStyle,\n resolveRegionStrokeStyle,\n resolveRegionLabelStyle: resolveRegionLabelStyleProp,\n overlayShapes,\n customLayers,\n patchRegions,\n regionLabelStyle,\n drawAreaTooltip,\n autoLiftRegionLabelAtMaxZoom = false,\n onPointerWorldMove,\n onPointHover,\n onPointClick,\n onRegionHover,\n onRegionClick,\n activeRegionId: controlledActiveRegionId,\n onActiveRegionChange,\n getCellByCoordinatesRef,\n onDrawComplete,\n onPatchComplete,\n overviewMapConfig,\n className,\n style,\n}: WsiViewerCanvasProps): React.ReactElement {\n const showOverviewMap = overviewMapConfig?.show ?? false;\n const overviewMapOptions = overviewMapConfig?.options;\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 [hoveredRegionId, setHoveredRegionId] = useState<string | number | null>(null);\n const [uncontrolledActiveRegionId, setUncontrolledActiveRegionId] = useState<string | number | null>(() => controlledActiveRegionId ?? null);\n const isActiveRegionControlled = controlledActiveRegionId !== undefined;\n const activeRegionId = isActiveRegionControlled ? (controlledActiveRegionId ?? null) : uncontrolledActiveRegionId;\n const [customLayerViewState, setCustomLayerViewState] = useState<WsiViewState | null>(null);\n const [debugStats, setDebugStats] = useState<WsiRenderStats | null>(null);\n const [regionLabelAutoLiftOffsetPx, setRegionLabelAutoLiftOffsetPx] = useState(0);\n const hoveredRegionIdRef = useRef<string | number | null>(null);\n const hoveredPointIndexRef = useRef<number | null>(null);\n const hoveredPointIdRef = useRef<number | null>(null);\n const regionLabelAutoLiftOffsetRef = useRef(0);\n const regionLabelAutoLiftAnimationRef = useRef<{ rafId: number | null; startMs: number; from: number; to: number }>({\n rafId: null,\n startMs: 0,\n from: 0,\n to: 0,\n });\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 const preparedRegionHits = useMemo(() => prepareRegionHits(effectiveRoiRegions), [effectiveRoiRegions]);\n const resolvedRegionLabelStyle = useMemo(() => resolveRegionLabelStyle(regionLabelStyle), [regionLabelStyle]);\n\n const applyRegionLabelAutoLiftOffset = useCallback((next: number) => {\n const clamped = clamp(next, 0, REGION_LABEL_AUTO_LIFT_MAX_OFFSET_PX);\n if (Math.abs(regionLabelAutoLiftOffsetRef.current - clamped) < 1e-4) return;\n regionLabelAutoLiftOffsetRef.current = clamped;\n setRegionLabelAutoLiftOffsetPx(clamped);\n }, []);\n\n const cancelRegionLabelAutoLiftAnimation = useCallback(() => {\n const animation = regionLabelAutoLiftAnimationRef.current;\n if (animation.rafId !== null) {\n cancelAnimationFrame(animation.rafId);\n animation.rafId = null;\n }\n }, []);\n\n const animateRegionLabelAutoLiftTo = useCallback(\n (target: number) => {\n const clampedTarget = clamp(target, 0, REGION_LABEL_AUTO_LIFT_MAX_OFFSET_PX);\n const animation = regionLabelAutoLiftAnimationRef.current;\n const from = regionLabelAutoLiftOffsetRef.current;\n if (Math.abs(from - clampedTarget) < 1e-4) {\n cancelRegionLabelAutoLiftAnimation();\n animation.to = clampedTarget;\n applyRegionLabelAutoLiftOffset(clampedTarget);\n return;\n }\n\n cancelRegionLabelAutoLiftAnimation();\n animation.startMs = performance.now();\n animation.from = from;\n animation.to = clampedTarget;\n\n const step = (timestamp: number) => {\n const current = regionLabelAutoLiftAnimationRef.current;\n const elapsed = Math.max(0, timestamp - current.startMs);\n const rawT = REGION_LABEL_AUTO_LIFT_ANIMATION_DURATION_MS <= 0 ? 1 : clamp(elapsed / REGION_LABEL_AUTO_LIFT_ANIMATION_DURATION_MS, 0, 1);\n const eased = smoothstep01(rawT);\n const nextValue = current.from + (current.to - current.from) * eased;\n applyRegionLabelAutoLiftOffset(nextValue);\n drawInvalidateRef.current?.();\n\n if (rawT >= 1) {\n current.rafId = null;\n applyRegionLabelAutoLiftOffset(current.to);\n return;\n }\n current.rafId = requestAnimationFrame(step);\n };\n\n animation.rafId = requestAnimationFrame(step);\n },\n [applyRegionLabelAutoLiftOffset, cancelRegionLabelAutoLiftAnimation]\n );\n\n const syncRegionLabelAutoLiftTarget = useCallback(\n (zoom: number | null | undefined) => {\n const renderer = rendererRef.current;\n if (!renderer || typeof zoom !== \"number\" || !Number.isFinite(zoom)) {\n animateRegionLabelAutoLiftTo(0);\n return;\n }\n const target = resolveRegionLabelAutoLiftOffsetPx(autoLiftRegionLabelAtMaxZoom, zoom, renderer.getZoomRange());\n animateRegionLabelAutoLiftTo(target);\n },\n [autoLiftRegionLabelAtMaxZoom, animateRegionLabelAutoLiftTo]\n );\n\n const clipPolygons = useMemo<RoiPolygon[]>(() => effectiveRoiRegions.map(region => region.coordinates as RoiPolygon), [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, { 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);\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 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 useEffect(() => {\n if (!isActiveRegionControlled) return;\n setUncontrolledActiveRegionId(controlledActiveRegionId ?? null);\n }, [isActiveRegionControlled, controlledActiveRegionId]);\n\n const commitActiveRegion = useCallback(\n (next: string | number | null) => {\n if (String(activeRegionId) === String(next)) return;\n if (!isActiveRegionControlled) {\n setUncontrolledActiveRegionId(next);\n }\n onActiveRegionChange?.(next);\n },\n [activeRegionId, isActiveRegionControlled, 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 useEffect(() => {\n return () => {\n cancelRegionLabelAutoLiftAnimation();\n };\n }, [cancelRegionLabelAutoLiftAnimation]);\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 syncRegionLabelAutoLiftTarget(next.zoom);\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, syncRegionLabelAutoLiftTarget]\n );\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) return;\n syncRegionLabelAutoLiftTarget(renderer.getViewState().zoom);\n }, [syncRegionLabelAutoLiftTarget, minZoom, maxZoom]);\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 return toDrawCoordinate(raw);\n }, []);\n\n const resolveCanvasPointerSnapshot = useCallback((clientX: number, clientY: number): { screenCoord: DrawCoordinate; canvasWidth: number; canvasHeight: number } | null => {\n const canvas = canvasRef.current;\n if (!canvas) return null;\n const rect = canvas.getBoundingClientRect();\n if (!Number.isFinite(rect.width) || !Number.isFinite(rect.height) || rect.width <= 0 || rect.height <= 0) {\n return null;\n }\n const screenX = clientX - rect.left;\n const screenY = clientY - rect.top;\n if (!Number.isFinite(screenX) || !Number.isFinite(screenY)) {\n return null;\n }\n return {\n screenCoord: [screenX, screenY],\n canvasWidth: Math.max(1, rect.width),\n canvasHeight: Math.max(1, rect.height),\n };\n }, []);\n\n const pickRegionHit = useCallback(\n (coord: DrawCoordinate, screenCoord: DrawCoordinate, canvasWidth: number, canvasHeight: number) => {\n const renderer = rendererRef.current;\n if (!renderer) return null;\n return pickPreparedRegionAt(\n coord,\n screenCoord,\n preparedRegionHits,\n renderer,\n resolvedRegionLabelStyle,\n resolveRegionLabelStyleProp,\n regionLabelAutoLiftOffsetPx,\n canvasWidth,\n canvasHeight\n );\n },\n [preparedRegionHits, resolvedRegionLabelStyle, resolveRegionLabelStyleProp, regionLabelAutoLiftOffsetPx]\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 (!preparedRegionHits.length) return;\n\n const pointerSnapshot = resolveCanvasPointerSnapshot(event.clientX, event.clientY);\n if (!pointerSnapshot) return;\n\n const hit = pickRegionHit(coord, pointerSnapshot.screenCoord, pointerSnapshot.canvasWidth, pointerSnapshot.canvasHeight);\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, preparedRegionHits, resolveWorldCoord, onRegionHover, onPointerWorldMove, source, emitPointHover, getCellByCoordinates, onPointHover, resolveCanvasPointerSnapshot, pickRegionHit]\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 (!preparedRegionHits.length) {\n commitActiveRegion(null);\n return;\n }\n\n const pointerSnapshot = resolveCanvasPointerSnapshot(event.clientX, event.clientY);\n if (!pointerSnapshot) return;\n\n const hit = pickRegionHit(coord, pointerSnapshot.screenCoord, pointerSnapshot.canvasWidth, pointerSnapshot.canvasHeight);\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, preparedRegionHits, resolveWorldCoord, onRegionClick, activeRegionId, commitActiveRegion, emitPointClick, resolveCanvasPointerSnapshot, pickRegionHit]\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 (!preparedRegionHits.length) return false;\n\n const renderer = rendererRef.current;\n const canvas = canvasRef.current;\n if (!renderer || !canvas) return false;\n const rect = canvas.getBoundingClientRect();\n if (rect.width <= 0 || rect.height <= 0) return false;\n\n const screenCoord = toDrawCoordinate(renderer.worldToScreen(coord[0], coord[1]));\n if (!screenCoord) return false;\n const hit = pickRegionHit(coord, screenCoord, rect.width, rect.height);\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, preparedRegionHits, activeRegionId, commitActiveRegion, onRegionClick, pickRegionHit]\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 imageColorSettings,\n ctrlDragRotate,\n pointSizeByZoom,\n pointStrokeScale,\n minZoom,\n maxZoom,\n viewTransition,\n });\n\n rendererRef.current = renderer;\n if (viewState) {\n renderer.setViewState(viewState);\n }\n syncRegionLabelAutoLiftTarget(renderer.getViewState().zoom);\n renderer.setInteractionLock(interactionLock);\n if (shouldTrackCustomLayerViewState) {\n setCustomLayerViewState(renderer.getViewState());\n }\n\n return () => {\n cancelRegionLabelAutoLiftAnimation();\n applyRegionLabelAutoLiftOffset(0);\n renderer.destroy();\n rendererRef.current = null;\n };\n }, [\n source,\n handleRendererStats,\n onTileError,\n onContextLost,\n onContextRestored,\n authToken,\n ctrlDragRotate,\n pointSizeByZoom,\n pointStrokeScale,\n emitViewStateChange,\n shouldTrackCustomLayerViewState,\n syncRegionLabelAutoLiftTarget,\n cancelRegionLabelAutoLiftAnimation,\n applyRegionLabelAutoLiftOffset,\n ]);\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) return;\n renderer.setPointStrokeScale(pointStrokeScale);\n }, [pointStrokeScale]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) return;\n renderer.setZoomRange(minZoom, maxZoom);\n syncRegionLabelAutoLiftTarget(renderer.getViewState().zoom);\n }, [minZoom, maxZoom, syncRegionLabelAutoLiftTarget]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) return;\n renderer.setViewTransition(viewTransition);\n }, [viewTransition]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) return;\n renderer.setImageColorSettings(imageColorSettings);\n }, [imageColorSettings]);\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\n className={className}\n style={mergedStyle}\n onPointerMove={handleRegionPointerMove}\n onPointerLeave={handleRegionPointerLeave}\n onClick={handleRegionClick}\n onContextMenu={handleRegionContextMenu}\n >\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 drawFillColor={drawFillColor}\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 resolveRegionLabelStyle={resolveRegionLabelStyleProp}\n overlayShapes={overlayShapes}\n hoveredRegionId={hoveredRegionId}\n activeRegionId={activeRegionId}\n regionLabelStyle={regionLabelStyle}\n drawAreaTooltip={drawAreaTooltip}\n autoLiftRegionLabelAtMaxZoom={autoLiftRegionLabelAtMaxZoom}\n regionLabelAutoLiftOffsetPx={regionLabelAutoLiftOffsetPx}\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 <OverviewMap\n source={source}\n projectorRef={rendererRef}\n authToken={authToken}\n options={overviewMapOptions}\n invalidateRef={overviewInvalidateRef}\n className={overviewMapConfig?.className}\n style={overviewMapConfig?.style}\n />\n )}\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","DEFAULT_SMOOTHING_PASSES","MAX_SMOOTHING_PASSES","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","smoothClosedRingChaikin","iterations","pass","clampRingToBounds","buildBrushStrokePolygon","circleSides","raster","bestRing","bestArea","area","smoothingPasses","isFiniteNumber","isCoordinatePair","isLinearRing","isPolygonRings","isMultiPolygon","polygon","closeRoiRing","normalizePolygonRings","rings","normalized","outerIndex","outerArea","normalizeRoiGeometry","geometry","pointInRing","inside","j","xi","yi","xj","yj","prepareRoiPolygons","geometries","prepared","multipolygon","outer","pointInPreparedPolygon","hole","pointInAnyPreparedPolygon","polygons","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","DEFAULT_DRAW_PREVIEW_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","DEFAULT_BRUSH_EDGE_SMOOTHING","MIN_BRUSH_EDGE_SMOOTHING","MAX_BRUSH_EDGE_SMOOTHING","MIN_BRUSH_RASTER_STEP","BRUSH_RASTER_DIAMETER_SAMPLES","BRUSH_SCREEN_STEP","DEFAULT_REGION_STROKE_STYLE","DEFAULT_PATCH_STROKE_STYLE","REGION_INTERACTION_SHADOW_COLOR","REGION_INTERACTION_SHADOW_WIDTH","DEFAULT_REGION_LABEL_STYLE","DEFAULT_DRAW_AREA_TOOLTIP_STYLE","DEFAULT_DRAW_AREA_TOOLTIP_OFFSET","REGION_LABEL_AUTO_LIFT_MAX_OFFSET_PX","REGION_LABEL_AUTO_LIFT_MAX_EPSILON","resolveRegionLabelAutoLiftOffsetPx","enabled","zoomRange","minZoom","maxZoom","isStampTool","tool","clampPositiveOrFallback","fallback","resolveStampOptions","clampUnitOpacity","sanitizeBrushLineDash","item","resolveBrushEdgeDetail","resolveBrushEdgeSmoothing","resolveBrushOptions","cursorLineWidth","edgeDetail","edgeSmoothing","mm2ToUm2","areaMm2","createSquareFromCenter","halfLength","projection","screenCenter","screenEdge","screenHL","screenCorners","worldCorners","corner","world","createCircleFromCenter","coords","createRectangle","startScreen","endScreen","createCircle","centerX","centerY","polygonArea","computeBounds","isValidPolygon","tracePath","ctx","close","drawPath","strokeStyle","fill","fillColor","resolveDrawPreviewFillColor","resolveStrokeStyle","style","dash","shadowBlur","shadowOffsetX","shadowOffsetY","mergeStrokeStyle","base","override","isSameRegionId","isNestedRingCoordinates","isCoordinateRing","collectOverlayRings","normalizeOverlayRings","sourceRings","drawInvertedFillMask","outerRing","holeRings","resolveRegionLabelStyle","px","py","bw","oy","br","mergeRegionLabelStyle","resolveDrawAreaTooltipStyle","fontSize","borderRadius","paddingX","paddingY","resolveTooltipCursorOffset","defaultDrawAreaTooltipFormatter","resolveDrawAreaTooltipOptions","format","cursorOffset","resolveRegionInteractionShadowStyle","drawRoundedRect","r","getTopAnchor","getTopAnchorFromPolygons","best","anchor","normalizeDrawRegionPolygons","normalizedOuter","holes","drawRegionLabel","text","canvasWidth","canvasHeight","labelStyle","label","boxWidth","boxHeight","left","top","drawAreaTooltipBox","cursorScreen","clampWorld","coord","imageWidth","imageHeight","toCoord","DrawLayer","stampOptions","brushOptions","projectorRef","onBrushTap","onDrawComplete","onPatchComplete","viewStateSignal","persistedRegions","patchRegions","persistedPolygons","drawFillColor","regionStrokeStyle","regionStrokeHoverStyle","regionStrokeActiveStyle","patchStrokeStyle","resolveRegionStrokeStyle","resolveRegionLabelStyleProp","overlayShapes","hoveredRegionId","activeRegionId","regionLabelStyle","drawAreaTooltip","autoLiftRegionLabelAtMaxZoom","regionLabelAutoLiftOffsetPx","invalidateRef","className","canvasRef","useRef","drawPendingRef","overlayDebugSnapshotRef","lastToolRef","sessionRef","active","mergedPersistedRegions","useMemo","index","mergedPatchRegions","preparedPersistedRegions","region","preparedPatchRegions","resolvedStrokeStyle","resolvedHoverStrokeStyle","resolvedActiveStrokeStyle","resolvedPatchStrokeStyle","resolvedDrawPreviewFillColor","resolvedLabelStyle","resolvedDrawAreaTooltipOptions","resolvedStampOptions","resolvedBrushOptions","mergedStyle","resizeCanvas","useCallback","w","h","worldToScreenPoints","projector","localScreenToWorld","screen","raw","getRectangleProjection","rotationDeg","micronsToWorldPixels","lengthUm","mppValue","imageZoomValue","viewZoomRaw","viewZoom","continuousZoom","umPerScreenPixel","buildStampCoords","stampTool","areaUm2","buildPreviewCoords","session","drawBrushStrokePreview","screenPoints","radiusPx","drawBrushCursor","cursor","drawOverlay","regionIndex","regionKey","state","resolved","interactionShadowStyle","screenOuter","screenHole","debugOverlay","imageOuterRing","shape","renderRings","closedRings","debugKey","debugSignature","preview","line","labelAutoLiftOffset","anchorWorld","anchorScreen","dynamicLabelStyle","areaCoords","areaPx","requestDraw","resetSession","preserveCursor","toWorld","event","toLocalScreen","finishSession","tapPoint","screenPath","screenPolygon","worldPolygon","handleStampAt","intent","result","appendBrushPoint","minScreenStep2","prevScreen","handlePointerDown","handlePointerMove","minWorldStep","minWorldStep2","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","strokeSymmetricDashedPolygon","dashLen","gapLen","len","from","to","sideLen","fittedLen","scale","adjDash","adjGap","toPositiveNumber","isFiniteBounds","DEFAULT_CLOSE_BUTTON_STYLE","OverviewMap","authToken","thumbnailRef","lastBoundsRef","draggingRef","rafRef","contentRect","imgW","imgH","imageAspect","boxAspect","cw","ch","margin","borderWidth","maxThumbnailTiles","backgroundColor","borderColor","viewportBorderColor","viewportBorderStyle","viewportFillColor","interactive","showThumbnail","position","onClose","closeIcon","closeButtonStyle","pos","draw","cssW","cssH","pixelW","pixelH","cx","cy","corners","safeBounds","safeCorners","isDash","right","bottom","rectW","rectH","rectCorners","toWorldFromClient","clientX","clientY","scaleX","scaleY","cxPx","cyPx","cwPx","chPx","nx","ny","recenterTo","worldX","worldY","visibleW","visibleH","drag","cancelled","levelScale","levelWidth","levelHeight","tilesX","tilesY","tileCount","requests","useAuthHeader","results","dw","dh","jsxs","TileViewerCanvas","rendererRef","renderer","sanitizePointCount","pointData","fillModesLength","filterPointDataByPolygons","empty","count","positions","fillModes","pointIds","nextPositions","nextTerms","nextFillModes","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","mapped","nowMs","filterPointDataByPolygonsHybrid","bridgeToDraw","data","safeCount","pointFillModes","bboxFlat","candidateMask","usedWebGpu","candidateCount","candidateIndices","candidateCursor","drawIndices","visibleCount","pointIndex","compactData","workerInstance","workerSupported","requestId","pendingById","createWorker","worker","_documentCurrentScript","handleWorkerMessage","handleWorkerError","msg","pending","indices","paletteIndices","ids","terminateRoiClipWorker","filterPointDataByPolygonsInWorker","positionsCopy","termsCopy","fillModesCopy","idsCopy","startMs","resolve","reject","transfer","filterPointIndicesByPolygonsInWorker","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","ax","bx","ay","by","deg","name","isSameArrayView","clonePointSizeStops","stops","stop","normalizePointSizeStops","pointSizeByZoom","zoomKey","rawSize","size","arePointSizeStopsEqual","resolvePointSizeByZoomStops","span","slope","MIN_STROKE_SCALE","MAX_STROKE_SCALE","normalizeStrokeScale","MIN_IMAGE_COLOR_INPUT","MAX_IMAGE_COLOR_INPUT","normalizeImageColorInput","toNormalizedImageColorSettings","settings","brightnessInput","contrastInput","saturationInput","MAX_VIEW_TRANSITION_DURATION_MS","linearEasing","normalizeViewTransitionDuration","duration","normalizeZoomOverride","normalizeTransitionEasing","easing","WsiTileRenderer","attemptCount","defaults","current","target","durationMs","animation","elapsed","rawT","eased","nextState","nextMinOverride","nextMaxOverride","transition","paletteSize","hasFillModes","nextPaletteIndices","hasDrawIndices","nextDrawIndices","prevHasFillModes","geometryChanged","drawIndicesChanged","maxExclusive","validCount","locked","nextStops","vp","vw","vh","clampedZoom","visibleWorldW","visibleWorldH","factor","nextZoom","worldDx","worldDy","nextCenterX","nextCenterY","marginX","marginY","halfW","halfH","minCenterX","maxCenterX","minCenterY","maxCenterY","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","uBrightness","uContrast","uSaturation","vbo","aUnit","aUv","uPointSize","uPointStrokeScale","uPalette","uPaletteSize","posBuffer","termBuffer","fillModeBuffer","indexBuffer","paletteTexture","posLoc","termLoc","fillModeLoc","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","REGION_CONTOUR_HIT_DISTANCE_PX","TOP_ANCHOR_Y_TOLERANCE","LABEL_MEASURE_FALLBACK_EM","LABEL_MEASURE_CACHE_LIMIT","REGION_LABEL_AUTO_LIFT_ANIMATION_DURATION_MS","sharedLabelMeasureContext","labelTextWidthCache","sanitizeDrawIndices","invalidFound","resolvePointHitGridSize","buildPointSpatialIndex","cellSize","buckets","pushBucket","cellX","cellY","column","bucket","resolveRegionId","smoothstep01","toDrawCoordinate","getTopAnchorFromPreparedPolygons","pointSegmentDistanceSq","lengthSq","isPointNearRing","maxDistanceSq","isPointNearPolygonContour","maxDistance","getLabelMeasureContext","measureLabelTextWidth","measured","isScreenPointInsideLabel","screenCoord","prepareRegionHits","pickPreparedRegionAt","labelStyleResolver","labelAutoLiftOffsetPx","contourHitDistance","WsiViewerCanvas","imageColorSettings","onViewStateChange","onStats","onTileError","onContextLost","onContextRestored","debugOverlayStyle","fitNonce","rotationResetNonce","ctrlDragRotate","pointPalette","pointStrokeScale","viewTransition","roiRegions","roiPolygons","clipPointsToRois","clipMode","onClipStats","onRoiPointGroups","roiPaletteIndexToTermId","interactionLock","drawTool","customLayers","onPointerWorldMove","onPointHover","onPointClick","onRegionHover","onRegionClick","controlledActiveRegionId","onActiveRegionChange","getCellByCoordinatesRef","overviewMapConfig","showOverviewMap","overviewMapOptions","drawInvalidateRef","overviewInvalidateRef","onViewStateChangeRef","onStatsRef","debugOverlayRef","setHoveredRegionId","useState","uncontrolledActiveRegionId","setUncontrolledActiveRegionId","isActiveRegionControlled","customLayerViewState","setCustomLayerViewState","debugStats","setDebugStats","setRegionLabelAutoLiftOffsetPx","hoveredRegionIdRef","hoveredPointIndexRef","hoveredPointIdRef","regionLabelAutoLiftOffsetRef","regionLabelAutoLiftAnimationRef","clipRunIdRef","safeRoiRegions","safePatchRegions","safeRoiPolygons","shouldTrackCustomLayerViewState","mergedDebugOverlayStyle","effectiveRoiRegions","preparedRegionHits","resolvedRegionLabelStyle","applyRegionLabelAutoLiftOffset","clamped","cancelRegionLabelAutoLiftAnimation","animateRegionLabelAutoLiftTo","clampedTarget","timestamp","nextValue","syncRegionLabelAutoLiftTarget","clipPolygons","renderPointData","setRenderPointData","runId","applyResult","stats","outputCount","shouldEnablePointHitTest","pointSpatialIndex","getCellByCoordinates","coordinate","pointSizePx","hitRadiusWorld","baseCellX","baseCellY","cellRadius","nearestIndex","nearestDist2","nearestX","nearestY","pointId","emitPointHover","hit","nextIndex","nextId","emitPointClick","button","commitActiveRegion","handleRendererStats","debugOverlayText","currentHover","hoveredPointIndex","emitViewStateChange","callback","resolveWorldCoord","resolveScreenCoord","resolveCanvasPointerSnapshot","pickRegionHit","requestCustomLayerRedraw","effectiveCustomLayerViewState","customLayerContext","viewStateForLayer","handleRegionPointerMove","isCanvasEvent","insideImage","pointerSnapshot","nextHoverId","prevHoverId","handleRegionPointerLeave","handleRegionClick","nextActive","handleBrushTap","handleRegionContextMenu","layer"],"mappings":"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"}
|