@jbrowse/render-core 5.0.0-beta.1 → 5.0.0-beta.10
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/esm/RenderCanvas.d.ts +2 -2
- package/esm/RenderLifecycleMixin.d.ts +52 -20
- package/esm/RenderLifecycleMixin.js +89 -23
- package/esm/canvas2dUtils.d.ts +90 -23
- package/esm/canvas2dUtils.js +119 -36
- package/esm/colorRampLut.d.ts +5 -5
- package/esm/colorRampLut.js +6 -6
- package/esm/computePipeline.d.ts +14 -0
- package/esm/computePipeline.js +62 -0
- package/esm/contractReports.d.ts +54 -0
- package/esm/contractReports.js +112 -0
- package/esm/coverageBand.d.ts +13 -8
- package/esm/coverageBand.js +15 -5
- package/esm/coverageBandBuffers.d.ts +2 -9
- package/esm/coverageBandBuffers.js +1 -13
- package/esm/createRenderingBackend.d.ts +14 -18
- package/esm/createRenderingBackend.js +4 -2
- package/esm/displayPhase.d.ts +83 -104
- package/esm/displayPhase.js +42 -82
- package/esm/encodeMemo.d.ts +14 -0
- package/esm/encodeMemo.js +48 -0
- package/esm/gpuContextLostError.d.ts +30 -0
- package/esm/gpuContextLostError.js +40 -0
- package/esm/gpuDevice.d.ts +29 -10
- package/esm/gpuDevice.js +35 -16
- package/esm/graphicsCapabilities.d.ts +27 -19
- package/esm/graphicsCapabilities.js +40 -18
- package/esm/hal/createHal.d.ts +4 -5
- package/esm/hal/createHal.js +14 -4
- package/esm/hal/deviceGpuCache.d.ts +25 -30
- package/esm/hal/deviceGpuCache.js +88 -97
- package/esm/hal/gpuHalBase.d.ts +5 -4
- package/esm/hal/gpuHalBase.js +25 -14
- package/esm/hal/index.d.ts +2 -2
- package/esm/hal/index.js +1 -1
- package/esm/hal/mockHal.d.ts +15 -10
- package/esm/hal/mockHal.js +31 -18
- package/esm/hal/oomReporter.d.ts +7 -0
- package/esm/hal/oomReporter.js +10 -0
- package/esm/hal/passIds.d.ts +8 -7
- package/esm/hal/passIds.js +11 -10
- package/esm/hal/regionRegistry.d.ts +0 -1
- package/esm/hal/regionRegistry.js +3 -15
- package/esm/hal/types.d.ts +55 -18
- package/esm/hal/webgl2Hal.d.ts +23 -6
- package/esm/hal/webgl2Hal.js +161 -155
- package/esm/hal/webgpuHal.d.ts +29 -13
- package/esm/hal/webgpuHal.js +221 -153
- package/esm/installUpload.d.ts +16 -3
- package/esm/installUpload.js +13 -41
- package/esm/instanceCache.d.ts +10 -7
- package/esm/instanceCache.js +14 -15
- package/esm/instancePass.d.ts +2 -1
- package/esm/mapUploadSync.d.ts +2 -10
- package/esm/mapUploadSync.js +2 -3
- package/esm/marks/barMark.d.ts +30 -0
- package/esm/marks/barMark.js +149 -0
- package/esm/marks/colorFill.d.ts +17 -0
- package/esm/marks/colorFill.js +26 -0
- package/esm/marks/drawAgainstHit.d.ts +113 -0
- package/esm/marks/drawAgainstHit.js +407 -0
- package/esm/marks/ellipseDistance.d.ts +10 -0
- package/esm/marks/ellipseDistance.js +136 -0
- package/esm/marks/glyphPaint.d.ts +36 -0
- package/esm/marks/glyphPaint.js +77 -0
- package/esm/marks/index.d.ts +33 -0
- package/esm/marks/index.js +20 -0
- package/esm/marks/lineMark.d.ts +37 -0
- package/esm/marks/lineMark.js +416 -0
- package/esm/marks/linkMark.d.ts +76 -0
- package/esm/marks/linkMark.js +585 -0
- package/esm/marks/markBackend.d.ts +118 -0
- package/esm/marks/markBackend.js +196 -0
- package/esm/marks/markHit.d.ts +32 -0
- package/esm/marks/markHit.js +61 -0
- package/esm/marks/markInk.d.ts +18 -0
- package/esm/marks/markInk.js +71 -0
- package/esm/marks/markPaint.d.ts +14 -0
- package/esm/marks/markPaint.js +32 -0
- package/esm/marks/markPlan.d.ts +25 -0
- package/esm/marks/markPlan.js +20 -0
- package/esm/marks/markRamp.d.ts +72 -0
- package/esm/marks/markRamp.js +197 -0
- package/esm/marks/nearestMarkHit.d.ts +55 -0
- package/esm/marks/nearestMarkHit.js +158 -0
- package/esm/marks/pathRecorder.d.ts +14 -0
- package/esm/marks/pathRecorder.js +80 -0
- package/esm/marks/pointMark.d.ts +42 -0
- package/esm/marks/pointMark.js +125 -0
- package/esm/marks/rowLane.d.ts +39 -0
- package/esm/marks/rowLane.js +41 -0
- package/esm/marks/rowSpanIndex.d.ts +29 -0
- package/esm/marks/rowSpanIndex.js +141 -0
- package/esm/marks/rowTable.d.ts +41 -0
- package/esm/marks/rowTable.js +75 -0
- package/esm/marks/ruleMark.d.ts +21 -0
- package/esm/marks/ruleMark.js +91 -0
- package/esm/marks/spanMark.d.ts +42 -0
- package/esm/marks/spanMark.js +81 -0
- package/esm/marks/types.d.ts +261 -0
- package/esm/marks/types.js +175 -0
- package/esm/marks/valueScale.d.ts +23 -0
- package/esm/marks/valueScale.js +11 -0
- package/esm/namedReactions.d.ts +3 -4
- package/esm/namedReactions.js +3 -4
- package/esm/perRegionRenderingBackend.d.ts +21 -3
- package/esm/perRegionRenderingBackend.js +37 -3
- package/esm/regionDataMap.d.ts +2 -2
- package/esm/regionDataMap.js +25 -23
- package/esm/renderBlock.d.ts +14 -0
- package/esm/renderBlock.js +25 -0
- package/esm/renderingBackendBase.d.ts +20 -14
- package/esm/renderingBackendBase.js +12 -7
- package/esm/scoreScale.d.ts +27 -0
- package/esm/scoreScale.js +88 -0
- package/esm/shaders/barMark.generated.d.ts +3 -0
- package/esm/shaders/barMark.generated.js +7 -0
- package/esm/shaders/barMark.glsl.generated.d.ts +2 -0
- package/esm/shaders/barMark.glsl.generated.js +4 -0
- package/esm/shaders/barMark.iface.generated.d.ts +90 -0
- package/esm/shaders/barMark.iface.generated.js +205 -0
- package/esm/shaders/barMark.wgsl.generated.d.ts +1 -0
- package/esm/shaders/barMark.wgsl.generated.js +3 -0
- package/esm/shaders/capsule.js.generated.d.ts +1 -0
- package/esm/shaders/capsule.js.generated.js +11 -0
- package/esm/shaders/clipStrip.generated.d.ts +2 -0
- package/esm/shaders/clipStrip.generated.js +4 -0
- package/esm/shaders/clipStrip.js.generated.d.ts +1 -0
- package/esm/shaders/clipStrip.js.generated.js +21 -0
- package/esm/shaders/colorRampLut.js.generated.d.ts +1 -0
- package/esm/shaders/colorRampLut.js.generated.js +17 -0
- package/esm/shaders/coverageBar.generated.d.ts +2 -3
- package/esm/shaders/coverageBar.generated.js +4 -3
- package/esm/shaders/coverageBar.glsl.generated.d.ts +2 -0
- package/esm/shaders/coverageBar.glsl.generated.js +4 -0
- package/esm/shaders/coverageBar.iface.generated.js +1 -1
- package/esm/shaders/coverageBar.wgsl.generated.d.ts +1 -0
- package/esm/shaders/coverageBar.wgsl.generated.js +3 -0
- package/esm/shaders/coverageClip.generated.d.ts +3 -0
- package/esm/shaders/coverageClip.generated.js +7 -0
- package/esm/shaders/coverageClip.glsl.generated.d.ts +2 -0
- package/esm/shaders/coverageClip.glsl.generated.js +4 -0
- package/esm/shaders/coverageClip.iface.generated.d.ts +85 -0
- package/esm/shaders/coverageClip.iface.generated.js +114 -0
- package/esm/shaders/coverageClip.wgsl.generated.d.ts +1 -0
- package/esm/shaders/coverageClip.wgsl.generated.js +3 -0
- package/esm/shaders/coverageIndicator.generated.d.ts +2 -3
- package/esm/shaders/coverageIndicator.generated.js +4 -3
- package/esm/shaders/coverageIndicator.glsl.generated.d.ts +2 -0
- package/esm/shaders/coverageIndicator.glsl.generated.js +4 -0
- package/esm/shaders/coverageIndicator.iface.generated.js +1 -1
- package/esm/shaders/coverageIndicator.wgsl.generated.d.ts +1 -0
- package/esm/shaders/coverageIndicator.wgsl.generated.js +3 -0
- package/esm/shaders/coverageInterbase.generated.d.ts +2 -3
- package/esm/shaders/coverageInterbase.generated.js +4 -3
- package/esm/shaders/coverageInterbase.glsl.generated.d.ts +2 -0
- package/esm/shaders/coverageInterbase.glsl.generated.js +4 -0
- package/esm/shaders/coverageInterbase.iface.generated.js +1 -1
- package/esm/shaders/coverageInterbase.wgsl.generated.d.ts +1 -0
- package/esm/shaders/coverageInterbase.wgsl.generated.js +3 -0
- package/esm/shaders/coverageMod.generated.d.ts +2 -3
- package/esm/shaders/coverageMod.generated.js +4 -3
- package/esm/shaders/coverageMod.glsl.generated.d.ts +2 -0
- package/esm/shaders/coverageMod.glsl.generated.js +4 -0
- package/esm/shaders/coverageMod.iface.generated.js +1 -1
- package/esm/shaders/coverageMod.wgsl.generated.d.ts +1 -0
- package/esm/shaders/coverageMod.wgsl.generated.js +3 -0
- package/esm/shaders/coverageSnp.generated.d.ts +2 -3
- package/esm/shaders/coverageSnp.generated.js +4 -3
- package/esm/shaders/coverageSnp.glsl.generated.d.ts +2 -0
- package/esm/shaders/coverageSnp.glsl.generated.js +4 -0
- package/esm/shaders/coverageSnp.iface.generated.js +1 -1
- package/esm/shaders/coverageSnp.wgsl.generated.d.ts +1 -0
- package/esm/shaders/coverageSnp.wgsl.generated.js +3 -0
- package/esm/shaders/curveDistance.js.generated.d.ts +5 -0
- package/esm/shaders/curveDistance.js.generated.js +87 -0
- package/esm/shaders/hpmath.js.generated.d.ts +2 -1
- package/esm/shaders/hpmath.js.generated.js +5 -2
- package/esm/shaders/lineCenterMark.generated.d.ts +3 -0
- package/esm/shaders/lineCenterMark.generated.js +7 -0
- package/esm/shaders/lineCenterMark.glsl.generated.d.ts +2 -0
- package/esm/shaders/lineCenterMark.glsl.generated.js +4 -0
- package/esm/shaders/lineCenterMark.iface.generated.d.ts +104 -0
- package/esm/shaders/lineCenterMark.iface.generated.js +237 -0
- package/esm/shaders/lineCenterMark.wgsl.generated.d.ts +1 -0
- package/esm/shaders/lineCenterMark.wgsl.generated.js +3 -0
- package/esm/shaders/lineCommon.generated.d.ts +2 -0
- package/esm/shaders/lineCommon.generated.js +4 -0
- package/esm/shaders/lineStepMark.generated.d.ts +3 -0
- package/esm/shaders/lineStepMark.generated.js +7 -0
- package/esm/shaders/lineStepMark.glsl.generated.d.ts +2 -0
- package/esm/shaders/lineStepMark.glsl.generated.js +4 -0
- package/esm/shaders/lineStepMark.iface.generated.d.ts +98 -0
- package/esm/shaders/lineStepMark.iface.generated.js +225 -0
- package/esm/shaders/lineStepMark.wgsl.generated.d.ts +1 -0
- package/esm/shaders/lineStepMark.wgsl.generated.js +3 -0
- package/esm/shaders/linkMark.consts.generated.d.ts +14 -0
- package/esm/shaders/linkMark.consts.generated.js +16 -0
- package/esm/shaders/linkMark.generated.d.ts +4 -0
- package/esm/shaders/linkMark.generated.js +8 -0
- package/esm/shaders/linkMark.glsl.generated.d.ts +2 -0
- package/esm/shaders/linkMark.glsl.generated.js +4 -0
- package/esm/shaders/linkMark.iface.generated.d.ts +142 -0
- package/esm/shaders/linkMark.iface.generated.js +1829 -0
- package/esm/shaders/linkMark.js.generated.d.ts +7 -0
- package/esm/shaders/linkMark.js.generated.js +159 -0
- package/esm/shaders/linkMark.wgsl.generated.d.ts +1 -0
- package/esm/shaders/linkMark.wgsl.generated.js +3 -0
- package/esm/shaders/markColor.generated.d.ts +9 -0
- package/esm/shaders/markColor.generated.js +11 -0
- package/esm/shaders/pointGlyph.js.generated.d.ts +2 -0
- package/esm/shaders/pointGlyph.js.generated.js +15 -0
- package/esm/shaders/pointMark.consts.generated.d.ts +7 -0
- package/esm/shaders/pointMark.consts.generated.js +9 -0
- package/esm/shaders/pointMark.generated.d.ts +4 -0
- package/esm/shaders/pointMark.generated.js +8 -0
- package/esm/shaders/pointMark.glsl.generated.d.ts +2 -0
- package/esm/shaders/pointMark.glsl.generated.js +4 -0
- package/esm/shaders/pointMark.iface.generated.d.ts +98 -0
- package/esm/shaders/pointMark.iface.generated.js +219 -0
- package/esm/shaders/pointMark.js.generated.d.ts +3 -0
- package/esm/shaders/pointMark.js.generated.js +93 -0
- package/esm/shaders/pointMark.wgsl.generated.d.ts +1 -0
- package/esm/shaders/pointMark.wgsl.generated.js +3 -0
- package/esm/shaders/rowRect.generated.d.ts +0 -1
- package/esm/shaders/rowRect.generated.js +0 -1
- package/esm/shaders/rowTable.generated.d.ts +1 -0
- package/esm/shaders/rowTable.generated.js +3 -0
- package/esm/shaders/rowTable.js.generated.d.ts +5 -0
- package/esm/shaders/rowTable.js.generated.js +29 -0
- package/esm/shaders/scoreScale.generated.d.ts +2 -0
- package/esm/shaders/scoreScale.generated.js +4 -0
- package/esm/shaders/scoreScale.js.generated.d.ts +1 -0
- package/esm/shaders/scoreScale.js.generated.js +50 -23
- package/esm/shaders/spanMark.generated.d.ts +3 -0
- package/esm/shaders/spanMark.generated.js +7 -0
- package/esm/shaders/spanMark.glsl.generated.d.ts +2 -0
- package/esm/shaders/spanMark.glsl.generated.js +4 -0
- package/esm/shaders/spanMark.iface.generated.d.ts +81 -0
- package/esm/shaders/spanMark.iface.generated.js +215 -0
- package/esm/shaders/spanMark.wgsl.generated.d.ts +1 -0
- package/esm/shaders/spanMark.wgsl.generated.js +3 -0
- package/esm/sharedBackendKey.d.ts +18 -0
- package/esm/{keyedRenderingBackend.js → sharedBackendKey.js} +5 -0
- package/esm/slangPass.d.ts +18 -11
- package/esm/slangPass.js +12 -4
- package/esm/useGraphicsCapabilities.d.ts +1 -1
- package/esm/useGraphicsCapabilities.js +1 -1
- package/esm/useRenderingBackend.d.ts +13 -13
- package/esm/useRenderingBackend.js +58 -20
- package/esm/webgpuUtils.d.ts +3 -11
- package/esm/webgpuUtils.js +12 -33
- package/package.json +32 -7
- package/src/shaders/antialias.slang +46 -0
- package/src/shaders/arcHull.test.ts +267 -0
- package/src/shaders/barMark.generated.ts +11 -0
- package/src/shaders/barMark.glsl.generated.ts +6 -0
- package/src/shaders/barMark.iface.generated.ts +285 -0
- package/src/shaders/barMark.slang +167 -0
- package/src/shaders/barMark.wgsl.generated.ts +4 -0
- package/src/shaders/capsule.js.generated.ts +14 -0
- package/src/shaders/capsule.slang +12 -4
- package/src/shaders/clipStrip.generated.ts +6 -0
- package/src/shaders/clipStrip.js.generated.ts +22 -0
- package/src/shaders/clipStrip.slang +34 -0
- package/src/shaders/clipStrip.test.ts +39 -0
- package/src/shaders/colorPack.slang +5 -1
- package/src/shaders/colorRampLut.js.generated.ts +22 -0
- package/src/shaders/colorRampLut.slang +15 -1
- package/src/shaders/coverageBand.slang +64 -32
- package/src/shaders/coverageBar.generated.ts +6 -5
- package/src/shaders/coverageBar.glsl.generated.ts +6 -0
- package/src/shaders/coverageBar.iface.generated.ts +1 -1
- package/src/shaders/coverageBar.slang +10 -10
- package/src/shaders/coverageBar.wgsl.generated.ts +4 -0
- package/src/shaders/coverageClip.generated.ts +11 -0
- package/src/shaders/coverageClip.glsl.generated.ts +6 -0
- package/src/shaders/coverageClip.iface.generated.ts +172 -0
- package/src/shaders/coverageClip.slang +38 -0
- package/src/shaders/coverageClip.wgsl.generated.ts +4 -0
- package/src/shaders/coverageIndicator.generated.ts +6 -5
- package/src/shaders/coverageIndicator.glsl.generated.ts +6 -0
- package/src/shaders/coverageIndicator.iface.generated.ts +1 -1
- package/src/shaders/coverageIndicator.wgsl.generated.ts +4 -0
- package/src/shaders/coverageInterbase.generated.ts +6 -5
- package/src/shaders/coverageInterbase.glsl.generated.ts +6 -0
- package/src/shaders/coverageInterbase.iface.generated.ts +1 -1
- package/src/shaders/coverageInterbase.wgsl.generated.ts +4 -0
- package/src/shaders/coverageMod.generated.ts +6 -5
- package/src/shaders/coverageMod.glsl.generated.ts +6 -0
- package/src/shaders/coverageMod.iface.generated.ts +1 -1
- package/src/shaders/coverageMod.wgsl.generated.ts +4 -0
- package/src/shaders/coverageSnp.generated.ts +6 -5
- package/src/shaders/coverageSnp.glsl.generated.ts +6 -0
- package/src/shaders/coverageSnp.iface.generated.ts +1 -1
- package/src/shaders/coverageSnp.wgsl.generated.ts +4 -0
- package/src/shaders/curveDistance.js.generated.ts +91 -0
- package/src/shaders/curveDistance.slang +265 -0
- package/src/shaders/hpClampFloor.test.ts +87 -0
- package/src/shaders/hpmath.js.generated.ts +6 -2
- package/src/shaders/hpmath.slang +100 -48
- package/src/shaders/insetValueScale.test.ts +67 -0
- package/src/shaders/lineCenterMark.generated.ts +11 -0
- package/src/shaders/lineCenterMark.glsl.generated.ts +6 -0
- package/src/shaders/lineCenterMark.iface.generated.ts +328 -0
- package/src/shaders/lineCenterMark.slang +127 -0
- package/src/shaders/lineCenterMark.wgsl.generated.ts +4 -0
- package/src/shaders/lineCommon.generated.ts +6 -0
- package/src/shaders/lineCommon.slang +102 -0
- package/src/shaders/lineStepMark.generated.ts +11 -0
- package/src/shaders/lineStepMark.glsl.generated.ts +6 -0
- package/src/shaders/lineStepMark.iface.generated.ts +311 -0
- package/src/shaders/lineStepMark.slang +125 -0
- package/src/shaders/lineStepMark.wgsl.generated.ts +4 -0
- package/src/shaders/linkMark.consts.generated.ts +30 -0
- package/src/shaders/linkMark.generated.ts +12 -0
- package/src/shaders/linkMark.glsl.generated.ts +6 -0
- package/src/shaders/linkMark.iface.generated.ts +1954 -0
- package/src/shaders/linkMark.js.generated.ts +167 -0
- package/src/shaders/linkMark.slang +439 -0
- package/src/shaders/linkMark.wgsl.generated.ts +4 -0
- package/src/shaders/markColor.generated.ts +20 -0
- package/src/shaders/markColor.slang +128 -0
- package/src/shaders/pointGlyph.js.generated.ts +20 -0
- package/src/shaders/pointGlyph.slang +23 -7
- package/src/shaders/pointGlyphPad.test.ts +242 -0
- package/src/shaders/pointMark.consts.generated.ts +16 -0
- package/src/shaders/pointMark.generated.ts +12 -0
- package/src/shaders/pointMark.glsl.generated.ts +6 -0
- package/src/shaders/pointMark.iface.generated.ts +304 -0
- package/src/shaders/pointMark.js.generated.ts +99 -0
- package/src/shaders/pointMark.slang +227 -0
- package/src/shaders/pointMark.wgsl.generated.ts +4 -0
- package/src/shaders/rowRect.generated.ts +0 -2
- package/src/shaders/rowRect.slang +39 -58
- package/src/shaders/rowTable.generated.ts +4 -0
- package/src/shaders/rowTable.js.generated.ts +37 -0
- package/src/shaders/rowTable.slang +98 -0
- package/src/shaders/scoreScale.generated.ts +6 -0
- package/src/shaders/scoreScale.js.generated.ts +48 -23
- package/src/shaders/scoreScale.slang +49 -55
- package/src/shaders/sdEllipse.test.ts +211 -0
- package/src/shaders/spanMark.generated.ts +11 -0
- package/src/shaders/spanMark.glsl.generated.ts +6 -0
- package/src/shaders/spanMark.iface.generated.ts +289 -0
- package/src/shaders/spanMark.slang +77 -0
- package/src/shaders/spanMark.wgsl.generated.ts +4 -0
- package/src/shaders/valueScale.slang +26 -0
- package/src/shaders/wideCircleLeg.test.ts +85 -0
- package/esm/globalRenderingBackend.d.ts +0 -90
- package/esm/globalRenderingBackend.js +0 -53
- package/esm/keyedRenderingBackend.d.ts +0 -41
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import type { BlockClipResult } from '../blockClipUtils.ts';
|
|
2
|
+
import type { ClipContext2D } from '../canvas2dUtils.ts';
|
|
3
|
+
import type { GpuHal } from '../hal/index.ts';
|
|
4
|
+
import type { InstancePass } from '../instancePass.ts';
|
|
5
|
+
import type { RenderBlock } from '../renderBlock.ts';
|
|
6
|
+
import type { FrameDimensions } from '../renderingBackendBase.ts';
|
|
7
|
+
/**
|
|
8
|
+
* The 2D-context subset a shape's painter needs, which both a canvas and
|
|
9
|
+
* `@jbrowse/core`'s `SvgCanvas` satisfy: one painter is the fallback and the
|
|
10
|
+
* SVG export.
|
|
11
|
+
*/
|
|
12
|
+
export interface MarkContext2D extends ClipContext2D {
|
|
13
|
+
fillStyle: string | CanvasGradient | CanvasPattern;
|
|
14
|
+
strokeStyle: string | CanvasGradient | CanvasPattern;
|
|
15
|
+
lineWidth: number;
|
|
16
|
+
lineCap?: CanvasLineCap;
|
|
17
|
+
lineJoin?: CanvasLineJoin;
|
|
18
|
+
fillRect(x: number, y: number, w: number, h: number): void;
|
|
19
|
+
strokeRect(x: number, y: number, w: number, h: number): void;
|
|
20
|
+
translate(x: number, y: number): void;
|
|
21
|
+
scale(x: number, y: number): void;
|
|
22
|
+
rotate(angle: number): void;
|
|
23
|
+
moveTo(x: number, y: number): void;
|
|
24
|
+
lineTo(x: number, y: number): void;
|
|
25
|
+
bezierCurveTo(cp1x: number, cp1y: number, cp2x: number, cp2y: number, x: number, y: number): void;
|
|
26
|
+
arc(x: number, y: number, radius: number, startAngle: number, endAngle: number, counterclockwise?: boolean): void;
|
|
27
|
+
ellipse(x: number, y: number, radiusX: number, radiusY: number, rotation: number, startAngle: number, endAngle: number): void;
|
|
28
|
+
setLineDash(segments: number[]): void;
|
|
29
|
+
closePath(): void;
|
|
30
|
+
fill(): void;
|
|
31
|
+
stroke(): void;
|
|
32
|
+
drawImage?(image: CanvasImageSource, sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): void;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* A canvas a mark's pass samples in place of a colour ramp. Hand a fresh object
|
|
36
|
+
* per repaint: the backend uploads on identity.
|
|
37
|
+
*/
|
|
38
|
+
export interface MarkImage {
|
|
39
|
+
image: HTMLCanvasElement | OffscreenCanvas;
|
|
40
|
+
width: number;
|
|
41
|
+
height: number;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* RGBA8 texels with their dimensions: a table a pass samples, such as a row
|
|
45
|
+
* table. Hand a fresh object per change: the backend uploads on identity.
|
|
46
|
+
*/
|
|
47
|
+
export interface MarkTexels {
|
|
48
|
+
bytes: Uint8Array;
|
|
49
|
+
width: number;
|
|
50
|
+
height: number;
|
|
51
|
+
}
|
|
52
|
+
/** What a mark's pass binds: a 256-entry RGBA ramp, a canvas, or texels. */
|
|
53
|
+
export type MarkTexture = Uint8Array | MarkImage | MarkTexels;
|
|
54
|
+
/**
|
|
55
|
+
* A pass's textures by the sampler that reads each: `colorRamp`, `rowTable`,
|
|
56
|
+
* a ring's `strip`. A sampler left out, or answered undefined, keeps what it
|
|
57
|
+
* holds.
|
|
58
|
+
*/
|
|
59
|
+
export type MarkTextures = Readonly<Record<string, MarkTexture | undefined>>;
|
|
60
|
+
export type MarkFrame = FrameDimensions;
|
|
61
|
+
export type MarkValueScaleType = 'linear' | 'log' | 'symlog';
|
|
62
|
+
/**
|
|
63
|
+
* The colour scale a ramp channel's raw `colorValue`s resolve through each
|
|
64
|
+
* frame, with the 256-entry RGBA LUT the pass's sampler binds: straight, its
|
|
65
|
+
* middle stop at the middle, and `mid`, where a diverging ramp puts that stop,
|
|
66
|
+
* read through a uniform.
|
|
67
|
+
*/
|
|
68
|
+
export interface MarkRamp {
|
|
69
|
+
domain: [number, number];
|
|
70
|
+
scale: 'linear' | 'log';
|
|
71
|
+
lut: Uint8Array;
|
|
72
|
+
/** The value the ramp's middle stop sits at; the domain's middle when absent. */
|
|
73
|
+
mid?: number;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* A threshold a value channel's raw `colorValue`s resolve through each frame:
|
|
77
|
+
* the ascending cut points, at most `MAX_COLOR_CUTS` of them, and one packed
|
|
78
|
+
* ABGR per interval between them, `cuts.length + 1` in all. The cuts and
|
|
79
|
+
* colours ride uniforms, so an edit moves them and uploads no instance bytes.
|
|
80
|
+
*/
|
|
81
|
+
export interface MarkThreshold {
|
|
82
|
+
cuts: readonly number[];
|
|
83
|
+
colors: Uint32Array;
|
|
84
|
+
}
|
|
85
|
+
/** The scale a quantitative colour channel resolves through: a ramp or a threshold. */
|
|
86
|
+
export type MarkColorScale = MarkRamp | MarkThreshold;
|
|
87
|
+
/** A horizontal strip of the canvas, in CSS px down from its top edge. */
|
|
88
|
+
export interface MarkBand {
|
|
89
|
+
top: number;
|
|
90
|
+
height: number;
|
|
91
|
+
}
|
|
92
|
+
/** Where a shape's ink sits nearest a cursor, and how far that is. */
|
|
93
|
+
export interface MarkHit {
|
|
94
|
+
index: number;
|
|
95
|
+
x: number;
|
|
96
|
+
y: number;
|
|
97
|
+
distSq: number;
|
|
98
|
+
}
|
|
99
|
+
/** An axis-aligned box of the canvas, in CSS px. */
|
|
100
|
+
export interface InkRect {
|
|
101
|
+
left: number;
|
|
102
|
+
top: number;
|
|
103
|
+
width: number;
|
|
104
|
+
height: number;
|
|
105
|
+
/**
|
|
106
|
+
* The ink as a stroked path, for a shape whose box is mostly empty space (a
|
|
107
|
+
* link's curve): a highlight strokes it, clipped to the box.
|
|
108
|
+
*/
|
|
109
|
+
stroke?: InkStroke;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* An SVG path `d` in canvas px, the width the shape strokes it at, and where
|
|
113
|
+
* the canvas origin sits in the frame the box is in, which `shiftInk` moves
|
|
114
|
+
* with the box.
|
|
115
|
+
*/
|
|
116
|
+
export interface InkStroke {
|
|
117
|
+
d: string;
|
|
118
|
+
widthPx: number;
|
|
119
|
+
originX: number;
|
|
120
|
+
originY: number;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* A shape: one `.slang` pass, a uniform writer and a Canvas2D painter over the
|
|
124
|
+
* same channel arrays, and the geometry its hit test reads. `TParams` reaches
|
|
125
|
+
* the GPU as uniforms and the painter as arguments, so both backends draw the
|
|
126
|
+
* same values.
|
|
127
|
+
*/
|
|
128
|
+
export interface MarkShape<TChannels, TParams> {
|
|
129
|
+
readonly id: string;
|
|
130
|
+
readonly pass: InstancePass<TChannels>;
|
|
131
|
+
/**
|
|
132
|
+
* Draws over the whole canvas from every loaded region's payload, after the
|
|
133
|
+
* blocks and unclipped to any block's column, each region's instances placed
|
|
134
|
+
* through a canvas-wide block of its own: a link, whose curve crosses regions
|
|
135
|
+
* holding neither foot.
|
|
136
|
+
*/
|
|
137
|
+
readonly spansView?: boolean;
|
|
138
|
+
writeUniforms(scratch: ArrayBuffer, clip: BlockClipResult, block: RenderBlock, frame: MarkFrame, params: TParams): void;
|
|
139
|
+
paintBlock(ctx: MarkContext2D, channels: TChannels, block: RenderBlock, frame: MarkFrame, params: TParams): void;
|
|
140
|
+
/**
|
|
141
|
+
* Whether the block carries any ink under these params. Both backends and the
|
|
142
|
+
* hit test skip a block it declines.
|
|
143
|
+
*/
|
|
144
|
+
paintsBlock?(block: RenderBlock, frame: MarkFrame, params: TParams): boolean;
|
|
145
|
+
/**
|
|
146
|
+
* Slots the GPU addresses per instance this frame, where the pass's
|
|
147
|
+
* registered count is a worst case over canvas widths. The canvas chevron
|
|
148
|
+
* pass shades a slot per chevron a line could put on screen, which is the
|
|
149
|
+
* canvas width over the chevron pitch — a tenth of its registered budget at a
|
|
150
|
+
* laptop width, and every surplus slot is a vertex invocation that runs the
|
|
151
|
+
* whole placement before culling itself.
|
|
152
|
+
*/
|
|
153
|
+
verticesPerInstance?(frame: MarkFrame, params: TParams): number;
|
|
154
|
+
/**
|
|
155
|
+
* The textures the pass samples that the params the painter and the hit
|
|
156
|
+
* test read decide (`span`'s row table), so the two backends cannot be
|
|
157
|
+
* handed different tables. A display's own `textures` lens wins for a
|
|
158
|
+
* sampler it answers.
|
|
159
|
+
*/
|
|
160
|
+
textures?(params: TParams): MarkTextures;
|
|
161
|
+
/**
|
|
162
|
+
* The rect `paintBlock` fills for instance `i`, undefined where it paints
|
|
163
|
+
* nothing. `defineMark` derives `hitNearest` from it where none is declared,
|
|
164
|
+
* and a highlight guide draws it. Painter-only overdraw, `span`'s seam, is
|
|
165
|
+
* not ink.
|
|
166
|
+
*/
|
|
167
|
+
ink?(channels: TChannels, block: RenderBlock, frame: MarkFrame, params: TParams, i: number): InkRect | undefined;
|
|
168
|
+
/**
|
|
169
|
+
* The nearest drawn ink to `(xPx, yPx)` among `candidates`, or undefined if
|
|
170
|
+
* nothing beats `maxDistSq`. Distance 0 is on the ink, edges included. Only a
|
|
171
|
+
* strictly nearer candidate replaces the best, so candidates handed back to
|
|
172
|
+
* front answer a tie with the mark on top.
|
|
173
|
+
*/
|
|
174
|
+
hitNearest?(channels: TChannels, block: RenderBlock, frame: MarkFrame, params: TParams, xPx: number, yPx: number, candidates: Iterable<number>, maxDistSq: number): MarkHit | undefined;
|
|
175
|
+
/**
|
|
176
|
+
* The values an instance can hold and still put ink within `radiusPx` of
|
|
177
|
+
* canvas y `yPx`, which a display's index over (bp, value) is searched with.
|
|
178
|
+
* A shape with no value axis leaves it off.
|
|
179
|
+
*/
|
|
180
|
+
valueWindow?(yPx: number, radiusPx: number, frame: MarkFrame, params: TParams): [number, number];
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* The uniform writer and `params` lens whose struct is in the HAL's slot, so a
|
|
184
|
+
* later mark of the same block over both draws without writing it again. Hand
|
|
185
|
+
* every mark of a block one fresh object: a stale one draws against the
|
|
186
|
+
* previous block's clip.
|
|
187
|
+
*/
|
|
188
|
+
export interface StagedUniforms {
|
|
189
|
+
writer: unknown;
|
|
190
|
+
params: unknown;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Puts a texture behind one of a pass's samplers once per identity: a repeat
|
|
194
|
+
* of the bound one costs nothing, and undefined leaves what is bound or binds
|
|
195
|
+
* an inert table where nothing is, since a textured pass missing a texture
|
|
196
|
+
* draws nothing on either GPU HAL.
|
|
197
|
+
*/
|
|
198
|
+
export interface TextureBinder {
|
|
199
|
+
bind(passId: string, sampler: string, texture: MarkTexture | undefined): void;
|
|
200
|
+
}
|
|
201
|
+
/** What `hal.drawPass` takes for one mark of a frame plan. */
|
|
202
|
+
export interface PlannedPass {
|
|
203
|
+
readonly id: string;
|
|
204
|
+
readonly bufferOf: string | undefined;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* A shape bound to a display's region payload and render state, its generics
|
|
208
|
+
* erased so one list holds several shapes.
|
|
209
|
+
*/
|
|
210
|
+
export interface Mark<TRegion, TState extends MarkFrame> {
|
|
211
|
+
readonly pass: InstancePass<TRegion>;
|
|
212
|
+
/** The shape's {@link MarkShape.spansView}. */
|
|
213
|
+
readonly spansView?: boolean;
|
|
214
|
+
/** The pass whose uploaded instance buffer this mark draws from. */
|
|
215
|
+
readonly bufferOf?: string;
|
|
216
|
+
/** What the pass's samplers read this frame; undefined binds an inert table. */
|
|
217
|
+
readonly textures?: (state: TState, region: TRegion) => MarkTextures | undefined;
|
|
218
|
+
/**
|
|
219
|
+
* Whether the mark draws at all under `state`. `planMarks` asks once per
|
|
220
|
+
* frame and every other consumer per block, before any lens.
|
|
221
|
+
*/
|
|
222
|
+
readonly enabled?: (state: TState) => boolean;
|
|
223
|
+
/** The pass a frame plan draws; undefined with a `band` or `paintsBlock`. */
|
|
224
|
+
readonly planned?: PlannedPass;
|
|
225
|
+
drawRegion(hal: GpuHal, scratch: ArrayBuffer, block: RenderBlock, clip: BlockClipResult, region: TRegion, state: TState, regionKey: number, staged?: StagedUniforms, textures?: TextureBinder): void;
|
|
226
|
+
paintBlock(ctx: MarkContext2D, region: TRegion, block: RenderBlock, state: TState): void;
|
|
227
|
+
hitNearest?(region: TRegion, block: RenderBlock, state: TState, xPx: number, yPx: number, candidates: Iterable<number>, maxDistSq: number): MarkHit | undefined;
|
|
228
|
+
/** The box instance `i` painted under the mark's gates, clipped to a band. */
|
|
229
|
+
ink?(region: TRegion, block: RenderBlock, state: TState, i: number): InkRect | undefined;
|
|
230
|
+
/** The shape's `valueWindow` under the mark's gates, if they open. */
|
|
231
|
+
valueWindow?(region: TRegion, block: RenderBlock, state: TState, yPx: number, radiusPx: number): [number, number] | undefined;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* The shape under another pass id. A pass id keys the instance buffer and
|
|
235
|
+
* texture, so two marks of one shape in one display need two ids; pipelines
|
|
236
|
+
* are keyed by content, so the clone compiles nothing.
|
|
237
|
+
*/
|
|
238
|
+
export declare function withPassId<C, P>(shape: MarkShape<C, P>, id: string): MarkShape<C, P>;
|
|
239
|
+
/**
|
|
240
|
+
* Binds a shape to a display's payload and render state through two picks run
|
|
241
|
+
* once per block per frame: `channels` names the region's arrays for the
|
|
242
|
+
* shape's lanes, and answers undefined for a region the mark has nothing in,
|
|
243
|
+
* which then packs, draws and paints nothing; `params` names what reaches the
|
|
244
|
+
* uniforms.
|
|
245
|
+
*
|
|
246
|
+
* `bufferOf` draws off another mark's uploaded buffer of the same instance
|
|
247
|
+
* struct. `textures` binds per pass per frame, each sampler re-uploading when
|
|
248
|
+
* its texture's identity moves, so ramps that differ by region re-upload per
|
|
249
|
+
* region. `band` clips the
|
|
250
|
+
* mark to a strip without offsetting it. `enabled` turns the mark off for a
|
|
251
|
+
* whole frame, for every consumer.
|
|
252
|
+
*/
|
|
253
|
+
export declare function defineMark<TRegion, TState extends MarkFrame, TChannels, TParams>(spec: {
|
|
254
|
+
shape: MarkShape<TChannels, TParams>;
|
|
255
|
+
channels: (region: TRegion) => TChannels | undefined;
|
|
256
|
+
params: (state: TState, region: TRegion, block: RenderBlock) => TParams;
|
|
257
|
+
bufferOf?: Mark<TRegion, TState>;
|
|
258
|
+
band?: (state: TState) => MarkBand;
|
|
259
|
+
textures?: (state: TState, region: TRegion) => MarkTextures | undefined;
|
|
260
|
+
enabled?: (state: TState) => boolean;
|
|
261
|
+
}): Mark<TRegion, TState>;
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { devicePxBand, withClip } from '../canvas2dUtils.js';
|
|
2
|
+
import { shapeHitNearest } from './markHit.js';
|
|
3
|
+
/**
|
|
4
|
+
* The shape under another pass id. A pass id keys the instance buffer and
|
|
5
|
+
* texture, so two marks of one shape in one display need two ids; pipelines
|
|
6
|
+
* are keyed by content, so the clone compiles nothing.
|
|
7
|
+
*/
|
|
8
|
+
export function withPassId(shape, id) {
|
|
9
|
+
return { ...shape, id, pass: { ...shape.pass, id } };
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Binds a shape to a display's payload and render state through two picks run
|
|
13
|
+
* once per block per frame: `channels` names the region's arrays for the
|
|
14
|
+
* shape's lanes, and answers undefined for a region the mark has nothing in,
|
|
15
|
+
* which then packs, draws and paints nothing; `params` names what reaches the
|
|
16
|
+
* uniforms.
|
|
17
|
+
*
|
|
18
|
+
* `bufferOf` draws off another mark's uploaded buffer of the same instance
|
|
19
|
+
* struct. `textures` binds per pass per frame, each sampler re-uploading when
|
|
20
|
+
* its texture's identity moves, so ramps that differ by region re-upload per
|
|
21
|
+
* region. `band` clips the
|
|
22
|
+
* mark to a strip without offsetting it. `enabled` turns the mark off for a
|
|
23
|
+
* whole frame, for every consumer.
|
|
24
|
+
*/
|
|
25
|
+
export function defineMark(spec) {
|
|
26
|
+
const { shape, channels, params, band, textures: ownTextures, enabled } = spec;
|
|
27
|
+
const hitNearest = shapeHitNearest(shape);
|
|
28
|
+
const shapeInk = shape.ink?.bind(shape);
|
|
29
|
+
const shapeValueWindow = shape.valueWindow?.bind(shape);
|
|
30
|
+
const shapeTextures = shape.textures?.bind(shape);
|
|
31
|
+
const samplers = shape.pass.textures?.map(t => t.name) ?? [];
|
|
32
|
+
const lender = spec.bufferOf?.pass;
|
|
33
|
+
if (lender &&
|
|
34
|
+
(lender.instanceStride !== shape.pass.instanceStride ||
|
|
35
|
+
JSON.stringify(lender.vertexAttributes) !==
|
|
36
|
+
JSON.stringify(shape.pass.vertexAttributes))) {
|
|
37
|
+
throw new Error(`mark ${shape.id} draws off ${lender.id}'s buffer but declares a different instance struct`);
|
|
38
|
+
}
|
|
39
|
+
const bufferOf = lender?.id;
|
|
40
|
+
const planned = band || shape.paintsBlock ? undefined : { id: shape.pass.id, bufferOf };
|
|
41
|
+
// `channels` gates `params`: a union payload's params lens may only read its
|
|
42
|
+
// own kind of region.
|
|
43
|
+
function resolve(region, block, state) {
|
|
44
|
+
if (enabled && !enabled(state)) {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
const strip = band?.(state);
|
|
48
|
+
if (strip && !bandIsOpen(strip)) {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
const c = channels(region);
|
|
52
|
+
if (c === undefined) {
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
const p = params(state, region, block);
|
|
56
|
+
if (shape.paintsBlock && !shape.paintsBlock(block, state, p)) {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
return { channels: c, params: p, strip };
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
pass: {
|
|
63
|
+
...shape.pass,
|
|
64
|
+
pack: region => {
|
|
65
|
+
const c = channels(region);
|
|
66
|
+
return c === undefined ? NOTHING : shape.pass.pack(c);
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
bufferOf,
|
|
70
|
+
spansView: shape.spansView,
|
|
71
|
+
textures: ownTextures,
|
|
72
|
+
enabled,
|
|
73
|
+
planned,
|
|
74
|
+
// `resolve`'s gates inline: its picks leaving as a record or through
|
|
75
|
+
// closure state measured 0.80-0.86x of these locals on
|
|
76
|
+
// markUniformDedupe.bench.ts.
|
|
77
|
+
drawRegion(hal, scratch, block, clip, region, state, regionKey, staged, textures) {
|
|
78
|
+
if (enabled && !enabled(state)) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const strip = band?.(state);
|
|
82
|
+
if (strip && !bandIsOpen(strip)) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (channels(region) === undefined) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const p = params(state, region, block);
|
|
89
|
+
if (shape.paintsBlock && !shape.paintsBlock(block, state, p)) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (textures && samplers.length > 0) {
|
|
93
|
+
const own = ownTextures?.(state, region);
|
|
94
|
+
const fromParams = shapeTextures?.(p);
|
|
95
|
+
for (const sampler of samplers) {
|
|
96
|
+
textures.bind(shape.pass.id, sampler, own?.[sampler] ?? fromParams?.[sampler]);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const scissor = strip && devicePxBand(strip.top, strip.height, clip.scaleY, clip.pxH);
|
|
100
|
+
if (scissor?.height === 0) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (scissor) {
|
|
104
|
+
hal.setScissor(clip.pxX, scissor.top, clip.pxW, scissor.height);
|
|
105
|
+
}
|
|
106
|
+
if (staged?.writer !== shape.writeUniforms || staged.params !== params) {
|
|
107
|
+
shape.writeUniforms(scratch, clip, block, state, p);
|
|
108
|
+
hal.writeUniforms(scratch);
|
|
109
|
+
if (staged) {
|
|
110
|
+
staged.writer = shape.writeUniforms;
|
|
111
|
+
staged.params = params;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
hal.drawPass(shape.pass.id, regionKey, bufferOf, shape.verticesPerInstance?.(state, p));
|
|
115
|
+
if (scissor) {
|
|
116
|
+
hal.setScissor(clip.pxX, 0, clip.pxW, clip.pxH);
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
paintBlock(ctx, region, block, state) {
|
|
120
|
+
const open = resolve(region, block, state);
|
|
121
|
+
if (!open) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const { strip } = open;
|
|
125
|
+
if (strip) {
|
|
126
|
+
withClip(ctx, 0, strip.top, state.canvasWidth, strip.height, () => {
|
|
127
|
+
shape.paintBlock(ctx, open.channels, block, state, open.params);
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
shape.paintBlock(ctx, open.channels, block, state, open.params);
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
hitNearest: hitNearest
|
|
135
|
+
? (region, block, state, xPx, yPx, candidates, maxDistSq) => {
|
|
136
|
+
const open = resolve(region, block, state);
|
|
137
|
+
if (!open || bandExcludes(open.strip, yPx)) {
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
140
|
+
const hit = hitNearest(open.channels, block, state, open.params, xPx, yPx, candidates, maxDistSq);
|
|
141
|
+
// Rejecting a nearest hit the band clipped away, rather than asking
|
|
142
|
+
// again, can mask a farther candidate inside the strip.
|
|
143
|
+
return hit && !bandExcludes(open.strip, hit.y) ? hit : undefined;
|
|
144
|
+
}
|
|
145
|
+
: undefined,
|
|
146
|
+
ink: shapeInk
|
|
147
|
+
? (region, block, state, i) => {
|
|
148
|
+
const open = resolve(region, block, state);
|
|
149
|
+
if (!open) {
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
const r = shapeInk(open.channels, block, state, open.params, i);
|
|
153
|
+
return r && open.strip ? clipToBand(r, open.strip) : r;
|
|
154
|
+
}
|
|
155
|
+
: undefined,
|
|
156
|
+
valueWindow: shapeValueWindow
|
|
157
|
+
? (region, block, state, yPx, radiusPx) => {
|
|
158
|
+
const open = resolve(region, block, state);
|
|
159
|
+
return open && shapeValueWindow(yPx, radiusPx, state, open.params);
|
|
160
|
+
}
|
|
161
|
+
: undefined,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function bandIsOpen(strip) {
|
|
165
|
+
return strip.height > 0 && Number.isFinite(strip.top + strip.height);
|
|
166
|
+
}
|
|
167
|
+
function clipToBand(r, strip) {
|
|
168
|
+
const top = Math.max(r.top, strip.top);
|
|
169
|
+
const bottom = Math.min(r.top + r.height, strip.top + strip.height);
|
|
170
|
+
return bottom > top ? { ...r, top, height: bottom - top } : undefined;
|
|
171
|
+
}
|
|
172
|
+
const NOTHING = new ArrayBuffer(0);
|
|
173
|
+
function bandExcludes(strip, yPx) {
|
|
174
|
+
return (strip !== undefined && (yPx < strip.top || yPx > strip.top + strip.height));
|
|
175
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { MarkValueScaleType } from './types.ts';
|
|
2
|
+
/** The y scale a valued shape places its instances through. */
|
|
3
|
+
export interface MarkValueScale {
|
|
4
|
+
/** `[min, max]` the values are read through. */
|
|
5
|
+
domain: [number, number];
|
|
6
|
+
/** How that domain is read; linear when absent. */
|
|
7
|
+
scaleType?: MarkValueScaleType;
|
|
8
|
+
/**
|
|
9
|
+
* symlog's linear-region width, already resolved from `domain` the way the
|
|
10
|
+
* axis resolves it (`resolveSymlogConstant`); d3's 1 when absent.
|
|
11
|
+
*/
|
|
12
|
+
symlogConstant?: number;
|
|
13
|
+
/** Whether the domain's minimum sits at the band's top rather than its bottom. */
|
|
14
|
+
reverse?: boolean;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The two uniforms `valueScale.slang` reads a scale by, which the painter, the
|
|
18
|
+
* ink box and the hit test read too.
|
|
19
|
+
*/
|
|
20
|
+
export declare function valueScaleUniforms({ scaleType, symlogConstant, }: MarkValueScale): {
|
|
21
|
+
valueScaleType: import("../scoreScale.ts").ScaleTypeCode;
|
|
22
|
+
valueSymlogConstant: number;
|
|
23
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { scaleTypeCode } from '../scoreScale.js';
|
|
2
|
+
/**
|
|
3
|
+
* The two uniforms `valueScale.slang` reads a scale by, which the painter, the
|
|
4
|
+
* ink box and the hit test read too.
|
|
5
|
+
*/
|
|
6
|
+
export function valueScaleUniforms({ scaleType, symlogConstant = 1, }) {
|
|
7
|
+
return {
|
|
8
|
+
valueScaleType: scaleTypeCode(scaleType),
|
|
9
|
+
valueSymlogConstant: symlogConstant,
|
|
10
|
+
};
|
|
11
|
+
}
|
package/esm/namedReactions.d.ts
CHANGED
|
@@ -12,10 +12,9 @@ export declare function recordNamedReaction(self: object, name: string, disposer
|
|
|
12
12
|
*
|
|
13
13
|
* The two halves belong together: `reactionDependencies` can only see a
|
|
14
14
|
* reaction that was recorded, so an installer that calls `autorun` and
|
|
15
|
-
* `addDisposer` directly
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* so there is no second spelling to forget.
|
|
15
|
+
* `addDisposer` directly leaves its dependency set out of the tests that are
|
|
16
|
+
* supposed to pin it, and those tests still pass. Every installer goes through
|
|
17
|
+
* here so there is no second spelling to forget.
|
|
19
18
|
*/
|
|
20
19
|
export declare function namedAutorun(self: IAnyStateTreeNode, body: () => void, options: IAutorunOptions & {
|
|
21
20
|
name: string;
|
package/esm/namedReactions.js
CHANGED
|
@@ -23,10 +23,9 @@ export function recordNamedReaction(self, name, disposer) {
|
|
|
23
23
|
*
|
|
24
24
|
* The two halves belong together: `reactionDependencies` can only see a
|
|
25
25
|
* reaction that was recorded, so an installer that calls `autorun` and
|
|
26
|
-
* `addDisposer` directly
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* so there is no second spelling to forget.
|
|
26
|
+
* `addDisposer` directly leaves its dependency set out of the tests that are
|
|
27
|
+
* supposed to pin it, and those tests still pass. Every installer goes through
|
|
28
|
+
* here so there is no second spelling to forget.
|
|
30
29
|
*/
|
|
31
30
|
export function namedAutorun(self, body, options) {
|
|
32
31
|
const disposer = autorun(body, options);
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { Canvas2DRenderingBackendBase, GpuRenderingBackendBase } from './renderingBackendBase.ts';
|
|
2
2
|
import type { BlockClipResult } from './blockClipUtils.ts';
|
|
3
|
+
import type { CanvasScale } from './canvas2dUtils.ts';
|
|
3
4
|
import type { InstancePass } from './instancePass.ts';
|
|
4
5
|
import type { RenderBlock } from './renderBlock.ts';
|
|
5
6
|
import type { FrameDimensions, RenderingBackend } from './renderingBackendBase.ts';
|
|
6
7
|
export type { FrameDimensions } from './renderingBackendBase.ts';
|
|
8
|
+
/** Straight RGBA, each channel 0-1 — what `beginFrame` takes. */
|
|
9
|
+
export type ClearColor = readonly [number, number, number, number];
|
|
7
10
|
/**
|
|
8
11
|
* Shared contract for per-region streamed GPU backends.
|
|
9
12
|
*
|
|
@@ -12,9 +15,8 @@ export type { FrameDimensions } from './renderingBackendBase.ts';
|
|
|
12
15
|
* against a data map passed back through `renderBlocks` each frame.
|
|
13
16
|
*
|
|
14
17
|
* `UploadData` is what the upload-side autorun pushes per region;
|
|
15
|
-
* `RenderData` is what the render-side reads. They default to the same
|
|
16
|
-
*
|
|
17
|
-
* carries a pre-encoded GPU buffer that the render side doesn't need).
|
|
18
|
+
* `RenderData` is what the render-side reads. They default to the same type,
|
|
19
|
+
* and every per-region display keeps the default today.
|
|
18
20
|
*
|
|
19
21
|
* Renderers are stateless: they keep no per-region cache. Canvas2D backends
|
|
20
22
|
* stub `upload` / `release` as no-ops since they read everything from the
|
|
@@ -58,6 +60,15 @@ export declare abstract class Canvas2DPerRegionRenderingBackend<UploadData, Rend
|
|
|
58
60
|
upload(): void;
|
|
59
61
|
release(): void;
|
|
60
62
|
renderBlocks(blocks: Block[], regions: ReadonlyMap<number, RenderData>, state: RenderState): boolean;
|
|
63
|
+
/**
|
|
64
|
+
* What the frame is painted onto before the blocks are drawn — the Canvas2D
|
|
65
|
+
* half of the GPU base's `beginFrame` clear. Undefined, the default, leaves
|
|
66
|
+
* `prepareCanvas`'s `clearRect` as the whole of it, which is transparent.
|
|
67
|
+
* Synteny is the one display that overrides: its indel wedges pre-blend
|
|
68
|
+
* against a KNOWN ground and only agree with the base ribbon beside them over
|
|
69
|
+
* a destination that really is that colour.
|
|
70
|
+
*/
|
|
71
|
+
protected clearColor(_state: RenderState): ClearColor | undefined;
|
|
61
72
|
/**
|
|
62
73
|
* Paint the visible blocks into `this.ctx` (already DPR-prepared). Delegates
|
|
63
74
|
* to the plugin's pure `drawXxxBlocks(ctx, regions, blocks, state)` function.
|
|
@@ -103,6 +114,11 @@ export declare abstract class GpuPerRegionRenderingBackend<UploadData, RenderSta
|
|
|
103
114
|
*/
|
|
104
115
|
upload(displayedRegionIndex: number, data: UploadData): void;
|
|
105
116
|
renderBlocks(blocks: Block[], regions: ReadonlyMap<number, RenderData>, state: RenderState): boolean;
|
|
117
|
+
/**
|
|
118
|
+
* Draw what spans the whole canvas after the blocks, with the scissor and
|
|
119
|
+
* viewport cleared, and answer whether anything drew.
|
|
120
|
+
*/
|
|
121
|
+
protected drawOverBlocks(_regions: ReadonlyMap<number, RenderData>, _state: RenderState, _scale: CanvasScale): boolean;
|
|
106
122
|
/**
|
|
107
123
|
* Write uniforms and issue draw passes for one block whose scissor/viewport
|
|
108
124
|
* are already set to its clipped span. `clip` carries the HP-split bp range
|
|
@@ -111,4 +127,6 @@ export declare abstract class GpuPerRegionRenderingBackend<UploadData, RenderSta
|
|
|
111
127
|
* those whose draw state is fully in the uploaded buffer).
|
|
112
128
|
*/
|
|
113
129
|
protected abstract drawRegion(block: Block, clip: BlockClipResult, region: RenderData, state: RenderState): void;
|
|
130
|
+
/** @see Canvas2DPerRegionRenderingBackend.clearColor */
|
|
131
|
+
protected clearColor(_state: RenderState): ClearColor;
|
|
114
132
|
}
|
|
@@ -2,6 +2,7 @@ import { clipBlock } from './blockClipUtils.js';
|
|
|
2
2
|
import { prepareCanvas } from './canvas2dUtils.js';
|
|
3
3
|
import { uploadPass } from './instancePass.js';
|
|
4
4
|
import { Canvas2DRenderingBackendBase, GpuRenderingBackendBase, } from './renderingBackendBase.js';
|
|
5
|
+
const TRANSPARENT = [0, 0, 0, 0];
|
|
5
6
|
/**
|
|
6
7
|
* Canvas2D-side base for `PerRegionRenderingBackend` implementations. Inherits
|
|
7
8
|
* the `canvas` + 2D context (and no-op `dispose`) from
|
|
@@ -21,9 +22,26 @@ export class Canvas2DPerRegionRenderingBackend extends Canvas2DRenderingBackendB
|
|
|
21
22
|
release() { }
|
|
22
23
|
renderBlocks(blocks, regions, state) {
|
|
23
24
|
prepareCanvas(this.canvas, this.ctx, state.canvasWidth, state.canvasHeight);
|
|
25
|
+
const clear = this.clearColor(state);
|
|
26
|
+
if (clear) {
|
|
27
|
+
const [r, g, b, a] = clear;
|
|
28
|
+
this.ctx.fillStyle = `rgba(${Math.round(r * 255)},${Math.round(g * 255)},${Math.round(b * 255)},${a})`;
|
|
29
|
+
this.ctx.fillRect(0, 0, state.canvasWidth, state.canvasHeight);
|
|
30
|
+
}
|
|
24
31
|
this.draw(blocks, regions, state);
|
|
25
32
|
return blocks.some(block => regions.has(block.displayedRegionIndex));
|
|
26
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* What the frame is painted onto before the blocks are drawn — the Canvas2D
|
|
36
|
+
* half of the GPU base's `beginFrame` clear. Undefined, the default, leaves
|
|
37
|
+
* `prepareCanvas`'s `clearRect` as the whole of it, which is transparent.
|
|
38
|
+
* Synteny is the one display that overrides: its indel wedges pre-blend
|
|
39
|
+
* against a KNOWN ground and only agree with the base ribbon beside them over
|
|
40
|
+
* a destination that really is that colour.
|
|
41
|
+
*/
|
|
42
|
+
clearColor(_state) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
27
45
|
}
|
|
28
46
|
/**
|
|
29
47
|
* GPU-side base for `PerRegionRenderingBackend` implementations. Inherits the
|
|
@@ -70,9 +88,10 @@ export class GpuPerRegionRenderingBackend extends GpuRenderingBackendBase {
|
|
|
70
88
|
// window, so a track dragged past the clamp draws at reduced resolution
|
|
71
89
|
// instead of asking for a viewport its target cannot hold.
|
|
72
90
|
const scale = this.hal.resize(canvasWidth, canvasHeight);
|
|
73
|
-
// Always pair beginFrame/endFrame so the canvas clears
|
|
74
|
-
//
|
|
75
|
-
|
|
91
|
+
// Always pair beginFrame/endFrame so the canvas clears even when every
|
|
92
|
+
// block is skipped (e.g. all regions pruned by a density gate).
|
|
93
|
+
const [clearR, clearG, clearB, clearA] = this.clearColor(state);
|
|
94
|
+
this.hal.beginFrame(clearR, clearG, clearB, clearA);
|
|
76
95
|
for (const block of blocks) {
|
|
77
96
|
const region = regions.get(block.displayedRegionIndex);
|
|
78
97
|
if (region !== undefined) {
|
|
@@ -87,7 +106,22 @@ export class GpuPerRegionRenderingBackend extends GpuRenderingBackendBase {
|
|
|
87
106
|
}
|
|
88
107
|
this.hal.clearScissor();
|
|
89
108
|
this.hal.clearViewport();
|
|
109
|
+
if (this.drawOverBlocks(regions, state, scale)) {
|
|
110
|
+
painted = true;
|
|
111
|
+
this.hal.clearViewport();
|
|
112
|
+
}
|
|
90
113
|
this.hal.endFrame();
|
|
91
114
|
return painted;
|
|
92
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* Draw what spans the whole canvas after the blocks, with the scissor and
|
|
118
|
+
* viewport cleared, and answer whether anything drew.
|
|
119
|
+
*/
|
|
120
|
+
drawOverBlocks(_regions, _state, _scale) {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
/** @see Canvas2DPerRegionRenderingBackend.clearColor */
|
|
124
|
+
clearColor(_state) {
|
|
125
|
+
return TRANSPARENT;
|
|
126
|
+
}
|
|
93
127
|
}
|
package/esm/regionDataMap.d.ts
CHANGED
|
@@ -17,8 +17,8 @@ export declare function isCheckedAtTheStore(map: ReadonlyMap<unknown, unknown>):
|
|
|
17
17
|
* observable object graph — the stored value is not the object the worker
|
|
18
18
|
* produced. A multi-wiggle region is one atom per field per source, so a
|
|
19
19
|
* thousand-sample track pays ~18k on every pan; MAF pays the whole set again
|
|
20
|
-
* for every cached region on every row reorder, since
|
|
21
|
-
*
|
|
20
|
+
* for every cached region on every row reorder, since a reorder re-places
|
|
21
|
+
* them all.
|
|
22
22
|
* - **Read.** Each field access goes through `getObservablePropValue_`. Hot
|
|
23
23
|
* loops that hoist their typed arrays are fine, but the ones that don't were
|
|
24
24
|
* paying it per iteration.
|