@genome-spy/core 0.64.0 → 0.66.1
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/bundle/{index-CCJIjehY.js → AbortablePromiseCache-CcuMrnn7.js} +22 -91
- package/dist/bundle/browser-BRemItdO.js +138 -0
- package/dist/bundle/index-BatuyGAI.js +271 -0
- package/dist/bundle/index-ByuE8dvu.js +332 -0
- package/dist/bundle/index-Cq3QFUxX.js +1781 -0
- package/dist/bundle/{index-C08YCM2T.js → index-D-w7Mmt9.js} +246 -126
- package/dist/bundle/index-D28m8tSW.js +1607 -0
- package/dist/bundle/index-D74H8TTz.js +508 -0
- package/dist/bundle/index-DbJ0oeYM.js +631 -0
- package/dist/bundle/index.es.js +15034 -13842
- package/dist/bundle/index.js +223 -237
- package/dist/bundle/inflate-GtwLkvSP.js +1048 -0
- package/dist/bundle/unzip-NywezaRR.js +1492 -0
- package/dist/schema.json +22 -4
- package/dist/src/config/scaleDefaults.d.ts +8 -0
- package/dist/src/config/scaleDefaults.d.ts.map +1 -0
- package/dist/src/config/scaleDefaults.js +45 -0
- package/dist/src/data/collector.d.ts +7 -2
- package/dist/src/data/collector.d.ts.map +1 -1
- package/dist/src/data/collector.js +13 -2
- package/dist/src/data/dataFlow.d.ts +20 -42
- package/dist/src/data/dataFlow.d.ts.map +1 -1
- package/dist/src/data/dataFlow.js +57 -80
- package/dist/src/data/flowHandle.d.ts +15 -0
- package/dist/src/data/flowHandle.d.ts.map +1 -0
- package/dist/src/data/flowHandle.js +13 -0
- package/dist/src/data/flowInit.d.ts +85 -0
- package/dist/src/data/flowInit.d.ts.map +1 -0
- package/dist/src/data/flowInit.js +238 -0
- package/dist/src/data/flowInit.test.d.ts +2 -0
- package/dist/src/data/flowInit.test.d.ts.map +1 -0
- package/dist/src/data/flowOptimizer.d.ts +6 -4
- package/dist/src/data/flowOptimizer.d.ts.map +1 -1
- package/dist/src/data/flowOptimizer.js +29 -14
- package/dist/src/data/sources/lazy/axisTickSource.js +1 -1
- package/dist/src/data/sources/lazy/bamSource.js +1 -1
- package/dist/src/data/sources/lazy/bigBedSource.js +1 -1
- package/dist/src/data/sources/lazy/bigWigSource.js +1 -1
- package/dist/src/data/sources/lazy/gff3Source.d.ts +2 -6
- package/dist/src/data/sources/lazy/gff3Source.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/gff3Source.js +4 -8
- package/dist/src/data/sources/lazy/indexedFastaSource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/indexedFastaSource.js +17 -17
- package/dist/src/data/sources/lazy/singleAxisLazySource.d.ts +1 -1
- package/dist/src/data/sources/lazy/singleAxisLazySource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/singleAxisLazySource.js +10 -3
- package/dist/src/data/sources/lazy/singleAxisWindowedSource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/singleAxisWindowedSource.js +5 -1
- package/dist/src/data/sources/lazy/tabixSource.js +1 -1
- package/dist/src/data/transforms/filterScoredLabels.d.ts +1 -1
- package/dist/src/data/transforms/filterScoredLabels.d.ts.map +1 -1
- package/dist/src/data/transforms/filterScoredLabels.js +1 -1
- package/dist/src/data/transforms/linearizeGenomicCoordinate.d.ts.map +1 -1
- package/dist/src/data/transforms/linearizeGenomicCoordinate.js +2 -1
- package/dist/src/encoder/encoder.d.ts +1 -1
- package/dist/src/encoder/encoder.d.ts.map +1 -1
- package/dist/src/encoder/encoder.js +1 -1
- package/dist/src/genome/scaleLocus.d.ts +39 -0
- package/dist/src/genome/scaleLocus.d.ts.map +1 -1
- package/dist/src/genome/scaleLocus.js +76 -0
- package/dist/src/genomeSpy/canvasExport.d.ts +19 -0
- package/dist/src/genomeSpy/canvasExport.d.ts.map +1 -0
- package/dist/src/genomeSpy/canvasExport.js +66 -0
- package/dist/src/genomeSpy/containerUi.d.ts +17 -0
- package/dist/src/genomeSpy/containerUi.d.ts.map +1 -0
- package/dist/src/genomeSpy/containerUi.js +78 -0
- package/dist/src/genomeSpy/eventListenerRegistry.d.ts +19 -0
- package/dist/src/genomeSpy/eventListenerRegistry.d.ts.map +1 -0
- package/dist/src/genomeSpy/eventListenerRegistry.js +38 -0
- package/dist/src/genomeSpy/inputBindingManager.d.ts +14 -0
- package/dist/src/genomeSpy/inputBindingManager.d.ts.map +1 -0
- package/dist/src/genomeSpy/inputBindingManager.js +63 -0
- package/dist/src/genomeSpy/interactionController.d.ts +40 -0
- package/dist/src/genomeSpy/interactionController.d.ts.map +1 -0
- package/dist/src/genomeSpy/interactionController.js +371 -0
- package/dist/src/genomeSpy/keyboardListenerManager.d.ts +10 -0
- package/dist/src/genomeSpy/keyboardListenerManager.d.ts.map +1 -0
- package/dist/src/genomeSpy/keyboardListenerManager.js +31 -0
- package/dist/src/genomeSpy/loadingIndicatorManager.d.ts +15 -0
- package/dist/src/genomeSpy/loadingIndicatorManager.d.ts.map +1 -0
- package/dist/src/genomeSpy/loadingIndicatorManager.js +92 -0
- package/dist/src/genomeSpy/renderCoordinator.d.ts +22 -0
- package/dist/src/genomeSpy/renderCoordinator.d.ts.map +1 -0
- package/dist/src/genomeSpy/renderCoordinator.js +118 -0
- package/dist/src/genomeSpy/viewContextFactory.d.ts +18 -0
- package/dist/src/genomeSpy/viewContextFactory.d.ts.map +1 -0
- package/dist/src/genomeSpy/viewContextFactory.js +79 -0
- package/dist/src/genomeSpy/viewDataInit.d.ts +12 -0
- package/dist/src/genomeSpy/viewDataInit.d.ts.map +1 -0
- package/dist/src/genomeSpy/viewDataInit.js +41 -0
- package/dist/src/genomeSpy/viewHierarchyConfig.d.ts +14 -0
- package/dist/src/genomeSpy/viewHierarchyConfig.d.ts.map +1 -0
- package/dist/src/genomeSpy/viewHierarchyConfig.js +24 -0
- package/dist/src/genomeSpy/viewHighlight.d.ts +5 -0
- package/dist/src/genomeSpy/viewHighlight.d.ts.map +1 -0
- package/dist/src/genomeSpy/viewHighlight.js +30 -0
- package/dist/src/genomeSpy.d.ts +17 -72
- package/dist/src/genomeSpy.d.ts.map +1 -1
- package/dist/src/genomeSpy.js +180 -789
- package/dist/src/gl/glslScaleGenerator.d.ts +1 -1
- package/dist/src/gl/webGLHelper.d.ts +2 -2
- package/dist/src/gl/webGLHelper.d.ts.map +1 -1
- package/dist/src/gl/webGLHelper.js +4 -4
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -12
- package/dist/src/marks/mark.d.ts +1 -0
- package/dist/src/marks/mark.d.ts.map +1 -1
- package/dist/src/marks/mark.js +26 -3
- package/dist/src/{view → scales}/axisResolution.d.ts +12 -14
- package/dist/src/scales/axisResolution.d.ts.map +1 -0
- package/dist/src/{view → scales}/axisResolution.js +38 -12
- package/dist/src/scales/axisResolution.test.d.ts.map +1 -0
- package/dist/src/scales/scaleDomainAggregator.d.ts +57 -0
- package/dist/src/scales/scaleDomainAggregator.d.ts.map +1 -0
- package/dist/src/scales/scaleDomainAggregator.js +162 -0
- package/dist/src/scales/scaleDomainAggregator.test.d.ts +2 -0
- package/dist/src/scales/scaleDomainAggregator.test.d.ts.map +1 -0
- package/dist/src/scales/scaleInstanceManager.d.ts +40 -0
- package/dist/src/scales/scaleInstanceManager.d.ts.map +1 -0
- package/dist/src/scales/scaleInstanceManager.js +313 -0
- package/dist/src/scales/scaleInstanceManager.test.d.ts +2 -0
- package/dist/src/scales/scaleInstanceManager.test.d.ts.map +1 -0
- package/dist/src/scales/scaleInteractionController.d.ts +73 -0
- package/dist/src/scales/scaleInteractionController.d.ts.map +1 -0
- package/dist/src/scales/scaleInteractionController.js +336 -0
- package/dist/src/scales/scaleInteractionController.test.d.ts +2 -0
- package/dist/src/scales/scaleInteractionController.test.d.ts.map +1 -0
- package/dist/src/scales/scalePropsResolver.d.ts +23 -0
- package/dist/src/scales/scalePropsResolver.d.ts.map +1 -0
- package/dist/src/scales/scalePropsResolver.js +74 -0
- package/dist/src/{view → scales}/scaleResolution.d.ts +53 -31
- package/dist/src/scales/scaleResolution.d.ts.map +1 -0
- package/dist/src/scales/scaleResolution.js +658 -0
- package/dist/src/scales/scaleResolution.test.d.ts.map +1 -0
- package/dist/src/scales/scaleResolutionConstants.d.ts +6 -0
- package/dist/src/scales/scaleResolutionConstants.d.ts.map +1 -0
- package/dist/src/scales/scaleResolutionConstants.js +5 -0
- package/dist/src/scales/scaleRules.d.ts +16 -0
- package/dist/src/scales/scaleRules.d.ts.map +1 -0
- package/dist/src/scales/scaleRules.js +103 -0
- package/dist/src/scales/scaleRules.test.d.ts +2 -0
- package/dist/src/scales/scaleRules.test.d.ts.map +1 -0
- package/dist/src/spec/channel.d.ts +13 -18
- package/dist/src/spec/sampleView.d.ts +3 -2
- package/dist/src/spec/scale.d.ts +6 -0
- package/dist/src/types/embedApi.d.ts +5 -0
- package/dist/src/types/scaleResolutionApi.d.ts +1 -1
- package/dist/src/types/viewContext.d.ts +1 -1
- package/dist/src/view/concatView.d.ts +18 -0
- package/dist/src/view/concatView.d.ts.map +1 -1
- package/dist/src/view/concatView.js +73 -0
- package/dist/src/view/concatView.test.d.ts +2 -0
- package/dist/src/view/concatView.test.d.ts.map +1 -0
- package/dist/src/view/containerMutationHelper.d.ts +74 -0
- package/dist/src/view/containerMutationHelper.d.ts.map +1 -0
- package/dist/src/view/containerMutationHelper.js +114 -0
- package/dist/src/view/containerView.d.ts +0 -7
- package/dist/src/view/containerView.d.ts.map +1 -1
- package/dist/src/view/containerView.js +0 -10
- package/dist/src/view/facetView.d.ts.map +1 -1
- package/dist/src/view/facetView.js +0 -14
- package/dist/src/view/flowBuilder.d.ts +2 -2
- package/dist/src/view/flowBuilder.d.ts.map +1 -1
- package/dist/src/view/flowBuilder.js +21 -4
- package/dist/src/view/gridView/gridChild.d.ts +11 -0
- package/dist/src/view/gridView/gridChild.d.ts.map +1 -1
- package/dist/src/view/gridView/gridChild.js +32 -6
- package/dist/src/view/gridView/gridView.d.ts +39 -1
- package/dist/src/view/gridView/gridView.d.ts.map +1 -1
- package/dist/src/view/gridView/gridView.js +113 -42
- package/dist/src/view/gridView/gridView.test.d.ts +2 -0
- package/dist/src/view/gridView/gridView.test.d.ts.map +1 -0
- package/dist/src/view/gridView/scrollbar.d.ts +39 -8
- package/dist/src/view/gridView/scrollbar.d.ts.map +1 -1
- package/dist/src/view/gridView/scrollbar.js +184 -69
- package/dist/src/view/gridView/selectionRect.d.ts +8 -4
- package/dist/src/view/gridView/selectionRect.d.ts.map +1 -1
- package/dist/src/view/gridView/selectionRect.js +28 -3
- package/dist/src/view/gridView/selectionRect.test.d.ts +2 -0
- package/dist/src/view/gridView/selectionRect.test.d.ts.map +1 -0
- package/dist/src/view/layerView.d.ts +14 -0
- package/dist/src/view/layerView.d.ts.map +1 -1
- package/dist/src/view/layerView.js +66 -0
- package/dist/src/view/layerView.test.d.ts +2 -0
- package/dist/src/view/layerView.test.d.ts.map +1 -0
- package/dist/src/view/paramMediator.d.ts +2 -1
- package/dist/src/view/paramMediator.d.ts.map +1 -1
- package/dist/src/view/paramMediator.js +13 -1
- package/dist/src/view/testUtils.d.ts.map +1 -1
- package/dist/src/view/testUtils.js +18 -5
- package/dist/src/view/unitView.d.ts.map +1 -1
- package/dist/src/view/unitView.js +52 -12
- package/dist/src/view/view.d.ts +23 -7
- package/dist/src/view/view.d.ts.map +1 -1
- package/dist/src/view/view.js +61 -5
- package/dist/src/view/viewDispose.test.d.ts +2 -0
- package/dist/src/view/viewDispose.test.d.ts.map +1 -0
- package/dist/src/view/viewUtils.d.ts +4 -4
- package/dist/src/view/viewUtils.d.ts.map +1 -1
- package/dist/src/view/viewUtils.js +19 -15
- package/dist/src/view/viewUtils.test.d.ts +2 -0
- package/dist/src/view/viewUtils.test.d.ts.map +1 -0
- package/package.json +10 -10
- package/dist/bundle/__vite-browser-external-C--ziKoh.js +0 -8
- package/dist/bundle/_commonjsHelpers-DjF3Plf2.js +0 -26
- package/dist/bundle/index-5ajWdKly.js +0 -1319
- package/dist/bundle/index-B03-Om4z.js +0 -274
- package/dist/bundle/index-BftNdA0O.js +0 -27
- package/dist/bundle/index-Bg7C4Xat.js +0 -2750
- package/dist/bundle/index-C3QR8Lv6.js +0 -2131
- package/dist/bundle/index-DTcHjAHp.js +0 -505
- package/dist/bundle/index-DnIkxb0L.js +0 -1025
- package/dist/bundle/index-Ww3TAo6_.js +0 -71
- package/dist/bundle/index-g8iXgW0W.js +0 -651
- package/dist/bundle/long-B-FASCSo.js +0 -2387
- package/dist/bundle/remoteFile-BuaqFGWk.js +0 -94
- package/dist/src/data/collector.test.js +0 -138
- package/dist/src/data/dataFlow.test.js +0 -5
- package/dist/src/data/flow.test.js +0 -81
- package/dist/src/data/flowNode.test.js +0 -50
- package/dist/src/data/flowOptimizer.test.js +0 -204
- package/dist/src/data/formats/fasta.test.js +0 -27
- package/dist/src/data/sources/inlineSource.test.js +0 -63
- package/dist/src/data/sources/sequenceSource.test.js +0 -81
- package/dist/src/data/transforms/aggregate.test.js +0 -134
- package/dist/src/data/transforms/clone.test.js +0 -11
- package/dist/src/data/transforms/coverage.test.js +0 -238
- package/dist/src/data/transforms/filter.test.js +0 -20
- package/dist/src/data/transforms/flatten.test.js +0 -96
- package/dist/src/data/transforms/flattenDelimited.test.js +0 -90
- package/dist/src/data/transforms/flattenSequence.test.js +0 -34
- package/dist/src/data/transforms/formula.test.js +0 -25
- package/dist/src/data/transforms/identifier.test.js +0 -92
- package/dist/src/data/transforms/pileup.test.js +0 -70
- package/dist/src/data/transforms/project.test.js +0 -32
- package/dist/src/data/transforms/regexExtract.test.js +0 -70
- package/dist/src/data/transforms/regexFold.test.js +0 -201
- package/dist/src/data/transforms/sample.test.js +0 -38
- package/dist/src/data/transforms/stack.test.js +0 -91
- package/dist/src/encoder/accessor.test.js +0 -162
- package/dist/src/encoder/encoder.test.js +0 -105
- package/dist/src/genome/genome.test.js +0 -268
- package/dist/src/genome/genomes.test.js +0 -8
- package/dist/src/genome/scaleIndex.test.js +0 -78
- package/dist/src/genome/scaleLocus.test.js +0 -4
- package/dist/src/scale/scale.test.js +0 -326
- package/dist/src/scale/ticks.test.js +0 -46
- package/dist/src/selection/selection.test.js +0 -14
- package/dist/src/utils/addBaseUrl.test.js +0 -30
- package/dist/src/utils/binnedIndex.test.js +0 -201
- package/dist/src/utils/cloner.test.js +0 -35
- package/dist/src/utils/coalesce.test.js +0 -16
- package/dist/src/utils/concatIterables.test.js +0 -8
- package/dist/src/utils/domainArray.test.js +0 -130
- package/dist/src/utils/indexer.test.js +0 -49
- package/dist/src/utils/interactionEvent.test.js +0 -35
- package/dist/src/utils/iterateNestedMaps.test.js +0 -33
- package/dist/src/utils/kWayMerge.test.js +0 -30
- package/dist/src/utils/mergeObjects.test.js +0 -42
- package/dist/src/utils/numberExtractor.test.js +0 -6
- package/dist/src/utils/propertyCacher.test.js +0 -89
- package/dist/src/utils/propertyCoalescer.test.js +0 -25
- package/dist/src/utils/radixSort.test.js +0 -51
- package/dist/src/utils/reservationMap.test.js +0 -20
- package/dist/src/utils/ringBuffer.test.js +0 -39
- package/dist/src/utils/topK.test.js +0 -54
- package/dist/src/utils/trees.test.js +0 -135
- package/dist/src/utils/url.test.js +0 -28
- package/dist/src/utils/variableTools.test.js +0 -13
- package/dist/src/view/axisResolution.d.ts.map +0 -1
- package/dist/src/view/axisResolution.test.d.ts.map +0 -1
- package/dist/src/view/axisResolution.test.js +0 -206
- package/dist/src/view/flowBuilder.test.js +0 -125
- package/dist/src/view/layout/flexLayout.test.js +0 -323
- package/dist/src/view/layout/grid.test.js +0 -71
- package/dist/src/view/layout/rectangle.test.js +0 -192
- package/dist/src/view/paramMediator.test.js +0 -260
- package/dist/src/view/scaleResolution.d.ts.map +0 -1
- package/dist/src/view/scaleResolution.js +0 -1049
- package/dist/src/view/scaleResolution.test.d.ts.map +0 -1
- package/dist/src/view/scaleResolution.test.js +0 -645
- package/dist/src/view/view.test.js +0 -245
- package/dist/src/view/viewFactory.test.js +0 -25
- /package/dist/src/{view → scales}/axisResolution.test.d.ts +0 -0
- /package/dist/src/{view → scales}/scaleResolution.test.d.ts +0 -0
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
import UnitView from "../view/unitView.js";
|
|
2
|
+
import { VISIT_STOP } from "../view/view.js";
|
|
3
|
+
import { readPickingPixel } from "../gl/webGLHelper.js";
|
|
4
|
+
import InteractionEvent from "../utils/interactionEvent.js";
|
|
5
|
+
import Inertia, { makeEventTemplate } from "../utils/inertia.js";
|
|
6
|
+
import Point from "../view/layout/point.js";
|
|
7
|
+
import { isStillZooming } from "../view/zoom.js";
|
|
8
|
+
|
|
9
|
+
export default class InteractionController {
|
|
10
|
+
/** @type {import("../view/view.js").default} */
|
|
11
|
+
#viewRoot;
|
|
12
|
+
/** @type {import("../gl/webGLHelper.js").default} */
|
|
13
|
+
#glHelper;
|
|
14
|
+
/** @type {import("../utils/ui/tooltip.js").default} */
|
|
15
|
+
#tooltip;
|
|
16
|
+
/** @type {import("../utils/animator.js").default} */
|
|
17
|
+
#animator;
|
|
18
|
+
/** @type {(type: string, event: any) => void} */
|
|
19
|
+
#emitEvent;
|
|
20
|
+
/** @type {Record<string, import("../tooltip/tooltipHandler.js").TooltipHandler>} */
|
|
21
|
+
#tooltipHandlers;
|
|
22
|
+
/** @type {() => void} */
|
|
23
|
+
#renderPickingFramebuffer;
|
|
24
|
+
/** @type {() => number} */
|
|
25
|
+
#getDevicePixelRatio;
|
|
26
|
+
/**
|
|
27
|
+
* @type {{ mark: import("../marks/mark.js").default, datum: import("../data/flowNode.js").Datum, uniqueId: number }}
|
|
28
|
+
*/
|
|
29
|
+
#currentHover;
|
|
30
|
+
/** @type {Inertia} */
|
|
31
|
+
#wheelInertia;
|
|
32
|
+
/** @type {Point} */
|
|
33
|
+
#mouseDownCoords;
|
|
34
|
+
/** @type {boolean} */
|
|
35
|
+
#tooltipUpdateRequested;
|
|
36
|
+
/**
|
|
37
|
+
* @param {object} options
|
|
38
|
+
* @param {import("../view/view.js").default} options.viewRoot
|
|
39
|
+
* @param {import("../gl/webGLHelper.js").default} options.glHelper
|
|
40
|
+
* @param {import("../utils/ui/tooltip.js").default} options.tooltip
|
|
41
|
+
* @param {import("../utils/animator.js").default} options.animator
|
|
42
|
+
* @param {(type: string, event: any) => void} options.emitEvent
|
|
43
|
+
* @param {Record<string, import("../tooltip/tooltipHandler.js").TooltipHandler>} options.tooltipHandlers
|
|
44
|
+
* @param {() => void} options.renderPickingFramebuffer
|
|
45
|
+
* @param {() => number} options.getDevicePixelRatio
|
|
46
|
+
*/
|
|
47
|
+
constructor({
|
|
48
|
+
viewRoot,
|
|
49
|
+
glHelper,
|
|
50
|
+
tooltip,
|
|
51
|
+
animator,
|
|
52
|
+
emitEvent,
|
|
53
|
+
tooltipHandlers,
|
|
54
|
+
renderPickingFramebuffer,
|
|
55
|
+
getDevicePixelRatio,
|
|
56
|
+
}) {
|
|
57
|
+
this.#viewRoot = viewRoot;
|
|
58
|
+
this.#glHelper = glHelper;
|
|
59
|
+
this.#tooltip = tooltip;
|
|
60
|
+
this.#animator = animator;
|
|
61
|
+
this.#emitEvent = emitEvent;
|
|
62
|
+
this.#tooltipHandlers = tooltipHandlers;
|
|
63
|
+
this.#renderPickingFramebuffer = renderPickingFramebuffer;
|
|
64
|
+
this.#getDevicePixelRatio = getDevicePixelRatio;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Currently hovered mark and datum
|
|
68
|
+
* @type {{ mark: import("../marks/mark.js").default, datum: import("../data/flowNode.js").Datum, uniqueId: number }}
|
|
69
|
+
*/
|
|
70
|
+
this.#currentHover = undefined;
|
|
71
|
+
|
|
72
|
+
this.#wheelInertia = new Inertia(this.#animator);
|
|
73
|
+
|
|
74
|
+
/** @type {Point} */
|
|
75
|
+
this.#mouseDownCoords = undefined;
|
|
76
|
+
|
|
77
|
+
this.#tooltipUpdateRequested = false;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
getCurrentHover() {
|
|
81
|
+
return this.#currentHover;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
registerMouseEvents() {
|
|
85
|
+
const canvas = this.#glHelper.canvas;
|
|
86
|
+
|
|
87
|
+
let lastWheelEvent = performance.now();
|
|
88
|
+
let longPressTriggered = false;
|
|
89
|
+
|
|
90
|
+
/** @param {Event} event */
|
|
91
|
+
const listener = (event) => {
|
|
92
|
+
const now = performance.now();
|
|
93
|
+
const wheeling = now - lastWheelEvent < 200;
|
|
94
|
+
|
|
95
|
+
if (event instanceof MouseEvent) {
|
|
96
|
+
const rect = canvas.getBoundingClientRect();
|
|
97
|
+
const point = new Point(
|
|
98
|
+
event.clientX - rect.left - canvas.clientLeft,
|
|
99
|
+
event.clientY - rect.top - canvas.clientTop
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
if (event.type == "mousemove" && !wheeling) {
|
|
103
|
+
this.#tooltip.handleMouseMove(event);
|
|
104
|
+
this.#tooltipUpdateRequested = false;
|
|
105
|
+
|
|
106
|
+
// Disable picking during dragging. Also postpone picking until
|
|
107
|
+
// the user has stopped zooming as reading pixels from the
|
|
108
|
+
// picking buffer is slow and ruins smooth animations.
|
|
109
|
+
if (event.buttons == 0 && !isStillZooming()) {
|
|
110
|
+
this.#renderPickingFramebuffer();
|
|
111
|
+
this.#handlePicking(point.x, point.y);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* @param {MouseEvent} dispatchedEvent
|
|
117
|
+
*/
|
|
118
|
+
const dispatchEvent = (dispatchedEvent) => {
|
|
119
|
+
this.#viewRoot.propagateInteractionEvent(
|
|
120
|
+
new InteractionEvent(point, dispatchedEvent)
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
if (!this.#tooltipUpdateRequested) {
|
|
124
|
+
this.#tooltip.clear();
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
if (event.type != "wheel") {
|
|
129
|
+
this.#wheelInertia.cancel();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (
|
|
133
|
+
(event.type == "mousedown" || event.type == "mouseup") &&
|
|
134
|
+
!isStillZooming()
|
|
135
|
+
) {
|
|
136
|
+
// Actually, only needed when clicking on a mark
|
|
137
|
+
this.#renderPickingFramebuffer();
|
|
138
|
+
} else if (event.type == "wheel") {
|
|
139
|
+
lastWheelEvent = now;
|
|
140
|
+
this.#tooltipUpdateRequested = false;
|
|
141
|
+
|
|
142
|
+
const wheelEvent = /** @type {WheelEvent} */ (event);
|
|
143
|
+
|
|
144
|
+
if (
|
|
145
|
+
Math.abs(wheelEvent.deltaX) >
|
|
146
|
+
Math.abs(wheelEvent.deltaY)
|
|
147
|
+
) {
|
|
148
|
+
// If the viewport is panned (horizontally) using the wheel (touchpad),
|
|
149
|
+
// the picking buffer becomes stale and needs redrawing. However, we
|
|
150
|
+
// optimize by just clearing the currently hovered item so that snapping
|
|
151
|
+
// doesn't work incorrectly when zooming in/out.
|
|
152
|
+
|
|
153
|
+
// TODO: More robust solution (handle at higher level such as ScaleResolution's zoom method)
|
|
154
|
+
this.#currentHover = null;
|
|
155
|
+
|
|
156
|
+
this.#wheelInertia.cancel();
|
|
157
|
+
} else {
|
|
158
|
+
// Vertical wheeling zooms.
|
|
159
|
+
// We use inertia to generate fake wheel events for smoother zooming
|
|
160
|
+
|
|
161
|
+
const template = makeEventTemplate(wheelEvent);
|
|
162
|
+
|
|
163
|
+
this.#wheelInertia.setMomentum(
|
|
164
|
+
wheelEvent.deltaY * (wheelEvent.deltaMode ? 80 : 1),
|
|
165
|
+
(delta) => {
|
|
166
|
+
const e = new WheelEvent("wheel", {
|
|
167
|
+
...template,
|
|
168
|
+
deltaMode: 0,
|
|
169
|
+
deltaX: 0,
|
|
170
|
+
deltaY: delta,
|
|
171
|
+
});
|
|
172
|
+
dispatchEvent(e);
|
|
173
|
+
}
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
wheelEvent.preventDefault();
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// TODO: Should be handled at the view level, not globally
|
|
182
|
+
if (event.type == "click") {
|
|
183
|
+
if (longPressTriggered) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const e = this.#currentHover
|
|
188
|
+
? {
|
|
189
|
+
type: event.type,
|
|
190
|
+
viewPath: this.#currentHover.mark.unitView
|
|
191
|
+
.getLayoutAncestors()
|
|
192
|
+
.map(
|
|
193
|
+
/** @param {import("../view/view.js").default} view */
|
|
194
|
+
(view) => view.name
|
|
195
|
+
)
|
|
196
|
+
.reverse(),
|
|
197
|
+
datum: this.#currentHover.datum,
|
|
198
|
+
}
|
|
199
|
+
: {
|
|
200
|
+
type: event.type,
|
|
201
|
+
viewPath: null,
|
|
202
|
+
datum: null,
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
this.#emitEvent("click", e);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (
|
|
209
|
+
event.type != "click" ||
|
|
210
|
+
// Suppress click events if the mouse has been dragged
|
|
211
|
+
this.#mouseDownCoords?.subtract(Point.fromMouseEvent(event))
|
|
212
|
+
.length < 3
|
|
213
|
+
) {
|
|
214
|
+
dispatchEvent(event);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
[
|
|
220
|
+
"mousedown",
|
|
221
|
+
"mouseup",
|
|
222
|
+
"wheel",
|
|
223
|
+
"click",
|
|
224
|
+
"mousemove",
|
|
225
|
+
"gesturechange",
|
|
226
|
+
"contextmenu",
|
|
227
|
+
"dblclick",
|
|
228
|
+
].forEach((type) => canvas.addEventListener(type, listener));
|
|
229
|
+
|
|
230
|
+
canvas.addEventListener("mousedown", (/** @type {MouseEvent} */ e) => {
|
|
231
|
+
this.#mouseDownCoords = Point.fromMouseEvent(e);
|
|
232
|
+
if (this.#tooltip.sticky) {
|
|
233
|
+
this.#tooltip.sticky = false;
|
|
234
|
+
this.#tooltip.clear();
|
|
235
|
+
// A hack to prevent selection if the tooltip is sticky.
|
|
236
|
+
// Let the tooltip be destickified first.
|
|
237
|
+
longPressTriggered = true;
|
|
238
|
+
} else {
|
|
239
|
+
longPressTriggered = false;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const disableTooltip = () => {
|
|
243
|
+
document.addEventListener(
|
|
244
|
+
"mouseup",
|
|
245
|
+
() => this.#tooltip.popEnabledState(),
|
|
246
|
+
{ once: true }
|
|
247
|
+
);
|
|
248
|
+
this.#tooltip.pushEnabledState(false);
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
// Opening context menu or using modifier keys disables the tooltip
|
|
252
|
+
if (e.button == 2 || e.shiftKey || e.ctrlKey || e.metaKey) {
|
|
253
|
+
disableTooltip();
|
|
254
|
+
} else if (this.#tooltip.visible) {
|
|
255
|
+
// Make tooltip sticky if the user long-presses
|
|
256
|
+
const timeout = setTimeout(() => {
|
|
257
|
+
longPressTriggered = true;
|
|
258
|
+
this.#tooltip.sticky = true;
|
|
259
|
+
}, 400);
|
|
260
|
+
|
|
261
|
+
const clear = () => clearTimeout(timeout);
|
|
262
|
+
document.addEventListener("mouseup", clear, { once: true });
|
|
263
|
+
document.addEventListener("mousemove", clear, { once: true });
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
// Prevent text selections etc while dragging
|
|
268
|
+
canvas.addEventListener("dragstart", (event) =>
|
|
269
|
+
event.stopPropagation()
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
canvas.addEventListener("mouseout", () => {
|
|
273
|
+
this.#tooltip.clear();
|
|
274
|
+
this.#currentHover = null;
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* @param {number} x
|
|
280
|
+
* @param {number} y
|
|
281
|
+
*/
|
|
282
|
+
#handlePicking(x, y) {
|
|
283
|
+
const dpr = this.#getDevicePixelRatio();
|
|
284
|
+
const pp = readPickingPixel(
|
|
285
|
+
this.#glHelper.gl,
|
|
286
|
+
this.#glHelper._pickingBufferInfo,
|
|
287
|
+
x * dpr,
|
|
288
|
+
y * dpr
|
|
289
|
+
);
|
|
290
|
+
|
|
291
|
+
const uniqueId = pp[0] | (pp[1] << 8) | (pp[2] << 16) | (pp[3] << 24);
|
|
292
|
+
|
|
293
|
+
if (uniqueId == 0) {
|
|
294
|
+
this.#currentHover = null;
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (uniqueId !== this.#currentHover?.uniqueId) {
|
|
299
|
+
this.#currentHover = null;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (!this.#currentHover) {
|
|
303
|
+
this.#viewRoot.visit((view) => {
|
|
304
|
+
if (view instanceof UnitView) {
|
|
305
|
+
if (
|
|
306
|
+
view.mark.isPickingParticipant() &&
|
|
307
|
+
[...view.facetCoords.values()].some((coords) =>
|
|
308
|
+
coords.containsPoint(x, y)
|
|
309
|
+
)
|
|
310
|
+
) {
|
|
311
|
+
const datum = view
|
|
312
|
+
.getCollector()
|
|
313
|
+
.findDatumByUniqueId(uniqueId);
|
|
314
|
+
if (datum) {
|
|
315
|
+
this.#currentHover = {
|
|
316
|
+
mark: view.mark,
|
|
317
|
+
datum,
|
|
318
|
+
uniqueId,
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
if (this.#currentHover) {
|
|
323
|
+
return VISIT_STOP;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (this.#currentHover) {
|
|
330
|
+
const mark = this.#currentHover.mark;
|
|
331
|
+
this.updateTooltip(this.#currentHover.datum, async (datum) => {
|
|
332
|
+
if (!mark.isPickingParticipant()) {
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
const tooltipProps = mark.properties.tooltip;
|
|
337
|
+
|
|
338
|
+
if (tooltipProps !== null) {
|
|
339
|
+
const handlerName = tooltipProps?.handler ?? "default";
|
|
340
|
+
const handler = this.#tooltipHandlers[handlerName];
|
|
341
|
+
if (!handler) {
|
|
342
|
+
throw new Error(
|
|
343
|
+
"No such tooltip handler: " + handlerName
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return handler(datum, mark, tooltipProps?.params);
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* This method should be called in a mouseMove handler. If not called, the
|
|
355
|
+
* tooltip will be hidden.
|
|
356
|
+
*
|
|
357
|
+
* @param {T} datum
|
|
358
|
+
* @param {function(T):Promise<string | HTMLElement | import("lit").TemplateResult>} [converter]
|
|
359
|
+
* @template T
|
|
360
|
+
*/
|
|
361
|
+
updateTooltip(datum, converter) {
|
|
362
|
+
if (!this.#tooltipUpdateRequested || !datum) {
|
|
363
|
+
this.#tooltip.updateWithDatum(datum, converter);
|
|
364
|
+
this.#tooltipUpdateRequested = true;
|
|
365
|
+
} else {
|
|
366
|
+
throw new Error(
|
|
367
|
+
"Tooltip has already been updated! Duplicate event handler?"
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export default class KeyboardListenerManager {
|
|
2
|
+
/**
|
|
3
|
+
* @param {"keydown" | "keyup"} type
|
|
4
|
+
* @param {(event: KeyboardEvent) => void} listener
|
|
5
|
+
*/
|
|
6
|
+
add(type: "keydown" | "keyup", listener: (event: KeyboardEvent) => void): void;
|
|
7
|
+
removeAll(): void;
|
|
8
|
+
#private;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=keyboardListenerManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keyboardListenerManager.d.ts","sourceRoot":"","sources":["../../../src/genomeSpy/keyboardListenerManager.js"],"names":[],"mappings":"AAAA;IAQI;;;OAGG;IACH,UAHW,SAAS,GAAG,OAAO,YACnB,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,QAUxC;IAED,kBAOC;;CACJ"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export default class KeyboardListenerManager {
|
|
2
|
+
/** @type {Map<string, (function(KeyboardEvent):void)[]>} */
|
|
3
|
+
#listeners;
|
|
4
|
+
|
|
5
|
+
constructor() {
|
|
6
|
+
this.#listeners = new Map();
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @param {"keydown" | "keyup"} type
|
|
11
|
+
* @param {(event: KeyboardEvent) => void} listener
|
|
12
|
+
*/
|
|
13
|
+
add(type, listener) {
|
|
14
|
+
document.addEventListener(type, listener);
|
|
15
|
+
let listeners = this.#listeners.get(type);
|
|
16
|
+
if (!listeners) {
|
|
17
|
+
listeners = [];
|
|
18
|
+
this.#listeners.set(type, listeners);
|
|
19
|
+
}
|
|
20
|
+
listeners.push(listener);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
removeAll() {
|
|
24
|
+
for (const [type, listeners] of this.#listeners) {
|
|
25
|
+
for (const listener of listeners) {
|
|
26
|
+
document.removeEventListener(type, listener);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
this.#listeners.clear();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export default class LoadingIndicatorManager {
|
|
2
|
+
/**
|
|
3
|
+
* @param {HTMLElement} loadingIndicatorsElement
|
|
4
|
+
*/
|
|
5
|
+
constructor(loadingIndicatorsElement: HTMLElement);
|
|
6
|
+
/**
|
|
7
|
+
* @param {import("../view/view.js").default} view
|
|
8
|
+
* @param {import("../types/viewContext.js").DataLoadingStatus} status
|
|
9
|
+
* @param {string} [detail]
|
|
10
|
+
*/
|
|
11
|
+
setDataLoadingStatus(view: import("../view/view.js").default, status: import("../types/viewContext.js").DataLoadingStatus, detail?: string): void;
|
|
12
|
+
updateLayout(): void;
|
|
13
|
+
#private;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=loadingIndicatorManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadingIndicatorManager.d.ts","sourceRoot":"","sources":["../../../src/genomeSpy/loadingIndicatorManager.js"],"names":[],"mappings":"AAIA;IAQI;;OAEG;IACH,sCAFW,WAAW,EASrB;IAED;;;;OAIG;IACH,2BAJW,OAAO,iBAAiB,EAAE,OAAO,UACjC,OAAO,yBAAyB,EAAE,iBAAiB,WACnD,MAAM,QAKhB;IAED,qBAwDC;;CACJ"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { html, nothing, render } from "lit";
|
|
2
|
+
import { styleMap } from "lit/directives/style-map.js";
|
|
3
|
+
import SPINNER from "../img/90-ring-with-bg.svg";
|
|
4
|
+
|
|
5
|
+
export default class LoadingIndicatorManager {
|
|
6
|
+
/** @type {HTMLElement} */
|
|
7
|
+
#loadingIndicatorsElement;
|
|
8
|
+
/**
|
|
9
|
+
* @type {Map<import("../view/view.js").default, { status: import("../types/viewContext.js").DataLoadingStatus, detail?: string }>}
|
|
10
|
+
*/
|
|
11
|
+
#loadingViews;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {HTMLElement} loadingIndicatorsElement
|
|
15
|
+
*/
|
|
16
|
+
constructor(loadingIndicatorsElement) {
|
|
17
|
+
this.#loadingIndicatorsElement = loadingIndicatorsElement;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @type {Map<import("../view/view.js").default, { status: import("../types/viewContext.js").DataLoadingStatus, detail?: string }>}
|
|
21
|
+
*/
|
|
22
|
+
this.#loadingViews = new Map();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @param {import("../view/view.js").default} view
|
|
27
|
+
* @param {import("../types/viewContext.js").DataLoadingStatus} status
|
|
28
|
+
* @param {string} [detail]
|
|
29
|
+
*/
|
|
30
|
+
setDataLoadingStatus(view, status, detail) {
|
|
31
|
+
this.#loadingViews.set(view, { status, detail });
|
|
32
|
+
this.updateLayout();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
updateLayout() {
|
|
36
|
+
/** @type {import("lit").TemplateResult[]} */
|
|
37
|
+
const indicators = [];
|
|
38
|
+
|
|
39
|
+
const isSomethingVisible = () =>
|
|
40
|
+
[...this.#loadingViews.values()].some(
|
|
41
|
+
(v) => v.status == "loading" || v.status == "error"
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
for (const [view, status] of this.#loadingViews) {
|
|
45
|
+
const c = view.coords;
|
|
46
|
+
if (c) {
|
|
47
|
+
const style = {
|
|
48
|
+
left: `${c.x}px`,
|
|
49
|
+
top: `${c.y}px`,
|
|
50
|
+
width: `${c.width}px`,
|
|
51
|
+
height: `${c.height}px`,
|
|
52
|
+
};
|
|
53
|
+
indicators.push(
|
|
54
|
+
html`<div style=${styleMap(style)}>
|
|
55
|
+
<div class=${status.status}>
|
|
56
|
+
${status.status == "error"
|
|
57
|
+
? html`<span
|
|
58
|
+
>Loading
|
|
59
|
+
failed${status.detail
|
|
60
|
+
? html`: ${status.detail}`
|
|
61
|
+
: nothing}</span
|
|
62
|
+
>`
|
|
63
|
+
: html`
|
|
64
|
+
<img src="${SPINNER}" alt="" />
|
|
65
|
+
<span>Loading...</span>
|
|
66
|
+
`}
|
|
67
|
+
</div>
|
|
68
|
+
</div>`
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Do some hacks to stop css animations of the loading indicators.
|
|
74
|
+
// Otherwise they fire animation frames even when their opacity is zero.
|
|
75
|
+
// TODO: Instead of this, replace the animated spinners with static images.
|
|
76
|
+
// Or even better, once more widely supported, use `allow-discrete`
|
|
77
|
+
// https://developer.mozilla.org/en-US/docs/Web/CSS/transition-behavior
|
|
78
|
+
// to enable transition of the display property.
|
|
79
|
+
if (isSomethingVisible()) {
|
|
80
|
+
this.#loadingIndicatorsElement.style.display = "block";
|
|
81
|
+
} else {
|
|
82
|
+
// TODO: Clear previous timeout
|
|
83
|
+
setTimeout(() => {
|
|
84
|
+
if (!isSomethingVisible()) {
|
|
85
|
+
this.#loadingIndicatorsElement.style.display = "none";
|
|
86
|
+
}
|
|
87
|
+
}, 3000);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
render(indicators, this.#loadingIndicatorsElement);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export default class RenderCoordinator {
|
|
2
|
+
/**
|
|
3
|
+
* @param {object} options
|
|
4
|
+
* @param {import("../view/view.js").default} options.viewRoot
|
|
5
|
+
* @param {import("../gl/webGLHelper.js").default} options.glHelper
|
|
6
|
+
* @param {() => string} options.getBackground
|
|
7
|
+
* @param {(type: import("../genomeSpy.js").BroadcastEventType, payload?: any) => void} options.broadcast
|
|
8
|
+
* @param {() => void} options.onLayoutComputed
|
|
9
|
+
*/
|
|
10
|
+
constructor({ viewRoot, glHelper, getBackground, broadcast, onLayoutComputed, }: {
|
|
11
|
+
viewRoot: import("../view/view.js").default;
|
|
12
|
+
glHelper: import("../gl/webGLHelper.js").default;
|
|
13
|
+
getBackground: () => string;
|
|
14
|
+
broadcast: (type: import("../genomeSpy.js").BroadcastEventType, payload?: any) => void;
|
|
15
|
+
onLayoutComputed: () => void;
|
|
16
|
+
});
|
|
17
|
+
computeLayout(): void;
|
|
18
|
+
renderAll(): void;
|
|
19
|
+
renderPickingFramebuffer(): void;
|
|
20
|
+
#private;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=renderCoordinator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderCoordinator.d.ts","sourceRoot":"","sources":["../../../src/genomeSpy/renderCoordinator.js"],"names":[],"mappings":"AAIA;IAiBI;;;;;;;OAOG;IACH,iFANG;QAAmD,QAAQ,EAAnD,OAAO,iBAAiB,EAAE,OAAO;QACe,QAAQ,EAAxD,OAAO,sBAAsB,EAAE,OAAO;QAChB,aAAa,EAAnC,MAAM,MAAM;QACyE,SAAS,EAA9F,CAAC,IAAI,EAAE,OAAO,iBAAiB,EAAE,kBAAkB,EAAE,OAAO,CAAC,EAAE,GAAG,KAAK,IAAI;QACvD,gBAAgB,EAApC,MAAM,IAAI;KACpB,EAqBA;IAED,sBAkDC;IAED,kBAIC;IAED,iCAOC;;CACJ"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import BufferedViewRenderingContext from "../view/renderingContext/bufferedViewRenderingContext.js";
|
|
2
|
+
import CompositeViewRenderingContext from "../view/renderingContext/compositeViewRenderingContext.js";
|
|
3
|
+
import Rectangle from "../view/layout/rectangle.js";
|
|
4
|
+
|
|
5
|
+
export default class RenderCoordinator {
|
|
6
|
+
/** @type {import("../view/view.js").default} */
|
|
7
|
+
#viewRoot;
|
|
8
|
+
/** @type {import("../gl/webGLHelper.js").default} */
|
|
9
|
+
#glHelper;
|
|
10
|
+
/** @type {() => string} */
|
|
11
|
+
#getBackground;
|
|
12
|
+
/** @type {(type: import("../genomeSpy.js").BroadcastEventType, payload?: any) => void} */
|
|
13
|
+
#broadcast;
|
|
14
|
+
/** @type {() => void} */
|
|
15
|
+
#onLayoutComputed;
|
|
16
|
+
/** @type {BufferedViewRenderingContext} */
|
|
17
|
+
#renderingContext;
|
|
18
|
+
/** @type {BufferedViewRenderingContext} */
|
|
19
|
+
#pickingContext;
|
|
20
|
+
/** @type {boolean} */
|
|
21
|
+
#dirtyPickingBuffer;
|
|
22
|
+
/**
|
|
23
|
+
* @param {object} options
|
|
24
|
+
* @param {import("../view/view.js").default} options.viewRoot
|
|
25
|
+
* @param {import("../gl/webGLHelper.js").default} options.glHelper
|
|
26
|
+
* @param {() => string} options.getBackground
|
|
27
|
+
* @param {(type: import("../genomeSpy.js").BroadcastEventType, payload?: any) => void} options.broadcast
|
|
28
|
+
* @param {() => void} options.onLayoutComputed
|
|
29
|
+
*/
|
|
30
|
+
constructor({
|
|
31
|
+
viewRoot,
|
|
32
|
+
glHelper,
|
|
33
|
+
getBackground,
|
|
34
|
+
broadcast,
|
|
35
|
+
onLayoutComputed,
|
|
36
|
+
}) {
|
|
37
|
+
this.#viewRoot = viewRoot;
|
|
38
|
+
this.#glHelper = glHelper;
|
|
39
|
+
this.#getBackground = getBackground;
|
|
40
|
+
this.#broadcast = broadcast;
|
|
41
|
+
this.#onLayoutComputed = onLayoutComputed;
|
|
42
|
+
|
|
43
|
+
/** @type {BufferedViewRenderingContext} */
|
|
44
|
+
this.#renderingContext = undefined;
|
|
45
|
+
/** @type {BufferedViewRenderingContext} */
|
|
46
|
+
this.#pickingContext = undefined;
|
|
47
|
+
|
|
48
|
+
/** Does picking buffer need to be rendered again */
|
|
49
|
+
this.#dirtyPickingBuffer = false;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
computeLayout() {
|
|
53
|
+
const root = this.#viewRoot;
|
|
54
|
+
if (!root) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
this.#broadcast("layout");
|
|
59
|
+
|
|
60
|
+
const canvasSize = this.#glHelper.getLogicalCanvasSize();
|
|
61
|
+
|
|
62
|
+
if (isNaN(canvasSize.width) || isNaN(canvasSize.height)) {
|
|
63
|
+
// TODO: Figure out what causes this
|
|
64
|
+
console.log(
|
|
65
|
+
`NaN in canvas size: ${canvasSize.width}x${canvasSize.height}. Skipping computeLayout().`
|
|
66
|
+
);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const commonOptions = {
|
|
71
|
+
webGLHelper: this.#glHelper,
|
|
72
|
+
canvasSize,
|
|
73
|
+
devicePixelRatio: window.devicePixelRatio ?? 1,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
this.#renderingContext = new BufferedViewRenderingContext(
|
|
77
|
+
{ picking: false },
|
|
78
|
+
{
|
|
79
|
+
...commonOptions,
|
|
80
|
+
clearColor: this.#getBackground(),
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
this.#pickingContext = new BufferedViewRenderingContext(
|
|
84
|
+
{ picking: true },
|
|
85
|
+
{
|
|
86
|
+
...commonOptions,
|
|
87
|
+
framebufferInfo: this.#glHelper._pickingBufferInfo,
|
|
88
|
+
}
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
root.render(
|
|
92
|
+
new CompositeViewRenderingContext(
|
|
93
|
+
this.#renderingContext,
|
|
94
|
+
this.#pickingContext
|
|
95
|
+
),
|
|
96
|
+
// Canvas should now be sized based on the root view or the container
|
|
97
|
+
Rectangle.create(0, 0, canvasSize.width, canvasSize.height)
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
this.#onLayoutComputed();
|
|
101
|
+
this.#broadcast("layoutComputed");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
renderAll() {
|
|
105
|
+
this.#renderingContext?.render();
|
|
106
|
+
|
|
107
|
+
this.#dirtyPickingBuffer = true;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
renderPickingFramebuffer() {
|
|
111
|
+
if (!this.#dirtyPickingBuffer) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
this.#pickingContext.render();
|
|
116
|
+
this.#dirtyPickingBuffer = false;
|
|
117
|
+
}
|
|
118
|
+
}
|