@genome-spy/core 0.36.1 → 0.37.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/README.md +1 -0
- package/dist/{index.es.js → bundle/index.es.js} +2253 -2115
- package/dist/{index.js → bundle/index.js} +180 -44
- package/dist/src/data/collector.d.ts +36 -0
- package/dist/src/data/collector.d.ts.map +1 -0
- package/dist/src/data/collector.js +184 -0
- package/dist/src/data/collector.test.js +84 -0
- package/dist/src/data/dataFlow.d.ts +65 -0
- package/dist/src/data/dataFlow.d.ts.map +1 -0
- package/dist/src/data/dataFlow.js +142 -0
- package/dist/src/data/dataFlow.test.js +5 -0
- package/dist/src/data/facetNode.d.ts +17 -0
- package/dist/src/data/facetNode.d.ts.map +1 -0
- package/dist/src/data/facetNode.js +17 -0
- package/dist/src/data/flow.test.js +72 -0
- package/dist/src/data/flowNode.d.ts +136 -0
- package/dist/src/data/flowNode.d.ts.map +1 -0
- package/dist/src/data/flowNode.js +286 -0
- package/dist/src/data/flowNode.test.js +50 -0
- package/dist/src/data/flowOptimizer.d.ts +27 -0
- package/dist/src/data/flowOptimizer.d.ts.map +1 -0
- package/dist/src/data/flowOptimizer.js +133 -0
- package/dist/src/data/flowOptimizer.test.js +193 -0
- package/dist/src/data/flowTestUtils.d.ts +30 -0
- package/dist/src/data/flowTestUtils.d.ts.map +1 -0
- package/dist/src/data/flowTestUtils.js +63 -0
- package/dist/src/data/formats/fasta.d.ts +20 -0
- package/dist/src/data/formats/fasta.d.ts.map +1 -0
- package/dist/src/data/formats/fasta.js +32 -0
- package/dist/src/data/formats/fasta.test.js +27 -0
- package/dist/src/data/sources/dataSource.d.ts +12 -0
- package/dist/src/data/sources/dataSource.d.ts.map +1 -0
- package/dist/src/data/sources/dataSource.js +25 -0
- package/dist/src/data/sources/dataSourceFactory.d.ts +16 -0
- package/dist/src/data/sources/dataSourceFactory.d.ts.map +1 -0
- package/dist/src/data/sources/dataSourceFactory.js +127 -0
- package/dist/src/data/sources/dataUtils.d.ts +50 -0
- package/dist/src/data/sources/dataUtils.d.ts.map +1 -0
- package/dist/src/data/sources/dataUtils.js +83 -0
- package/dist/src/data/sources/dynamic/README.md +3 -0
- package/dist/src/data/sources/dynamic/axisGenomeSource.d.ts +13 -0
- package/dist/src/data/sources/dynamic/axisGenomeSource.d.ts.map +1 -0
- package/dist/src/data/sources/dynamic/axisGenomeSource.js +19 -0
- package/dist/src/data/sources/dynamic/axisTickSource.d.ts +18 -0
- package/dist/src/data/sources/dynamic/axisTickSource.d.ts.map +1 -0
- package/dist/src/data/sources/dynamic/axisTickSource.js +73 -0
- package/dist/src/data/sources/dynamic/bamSource.d.ts +46 -0
- package/dist/src/data/sources/dynamic/bamSource.d.ts.map +1 -0
- package/dist/src/data/sources/dynamic/bamSource.js +115 -0
- package/dist/src/data/sources/dynamic/bigBedSource.d.ts +51 -0
- package/dist/src/data/sources/dynamic/bigBedSource.d.ts.map +1 -0
- package/dist/src/data/sources/dynamic/bigBedSource.js +128 -0
- package/dist/src/data/sources/dynamic/bigWigSource.d.ts +58 -0
- package/dist/src/data/sources/dynamic/bigWigSource.d.ts.map +1 -0
- package/dist/src/data/sources/dynamic/bigWigSource.js +166 -0
- package/dist/src/data/sources/dynamic/gff3Source.d.ts +8 -0
- package/dist/src/data/sources/dynamic/gff3Source.d.ts.map +1 -0
- package/dist/src/data/sources/dynamic/gff3Source.js +19 -0
- package/dist/src/data/sources/dynamic/indexedFastaSource.d.ts +30 -0
- package/dist/src/data/sources/dynamic/indexedFastaSource.d.ts.map +1 -0
- package/dist/src/data/sources/dynamic/indexedFastaSource.js +86 -0
- package/dist/src/data/sources/dynamic/singleAxisLazySource.d.ts +42 -0
- package/dist/src/data/sources/dynamic/singleAxisLazySource.d.ts.map +1 -0
- package/dist/src/data/sources/dynamic/singleAxisLazySource.js +129 -0
- package/dist/src/data/sources/dynamic/tabixSource.d.ts +54 -0
- package/dist/src/data/sources/dynamic/tabixSource.d.ts.map +1 -0
- package/dist/src/data/sources/dynamic/tabixSource.js +140 -0
- package/dist/src/data/sources/dynamic/windowedMixin.d.ts +32 -0
- package/dist/src/data/sources/dynamic/windowedMixin.d.ts.map +1 -0
- package/dist/src/data/sources/dynamic/windowedMixin.js +53 -0
- package/dist/src/data/sources/inlineSource.d.ts +16 -0
- package/dist/src/data/sources/inlineSource.d.ts.map +1 -0
- package/dist/src/data/sources/inlineSource.js +68 -0
- package/dist/src/data/sources/inlineSource.test.js +56 -0
- package/dist/src/data/sources/namedSource.d.ts +25 -0
- package/dist/src/data/sources/namedSource.d.ts.map +1 -0
- package/dist/src/data/sources/namedSource.js +80 -0
- package/dist/src/data/sources/sequenceSource.d.ts +17 -0
- package/dist/src/data/sources/sequenceSource.d.ts.map +1 -0
- package/dist/src/data/sources/sequenceSource.js +47 -0
- package/dist/src/data/sources/sequenceSource.test.js +46 -0
- package/dist/src/data/sources/urlSource.d.ts +16 -0
- package/dist/src/data/sources/urlSource.d.ts.map +1 -0
- package/dist/src/data/sources/urlSource.js +74 -0
- package/dist/src/data/transforms/aggregate.d.ts +18 -0
- package/dist/src/data/transforms/aggregate.d.ts.map +1 -0
- package/dist/src/data/transforms/aggregate.js +67 -0
- package/dist/src/data/transforms/clone.d.ts +15 -0
- package/dist/src/data/transforms/clone.d.ts.map +1 -0
- package/dist/src/data/transforms/clone.js +40 -0
- package/dist/src/data/transforms/clone.test.js +11 -0
- package/dist/src/data/transforms/coverage.d.ts +30 -0
- package/dist/src/data/transforms/coverage.d.ts.map +1 -0
- package/dist/src/data/transforms/coverage.js +183 -0
- package/dist/src/data/transforms/coverage.test.js +123 -0
- package/dist/src/data/transforms/filter.d.ts +12 -0
- package/dist/src/data/transforms/filter.d.ts.map +1 -0
- package/dist/src/data/transforms/filter.js +33 -0
- package/dist/src/data/transforms/filter.test.js +18 -0
- package/dist/src/data/transforms/filterScoredLabels.d.ts +29 -0
- package/dist/src/data/transforms/filterScoredLabels.d.ts.map +1 -0
- package/dist/src/data/transforms/filterScoredLabels.js +134 -0
- package/dist/src/data/transforms/flatten.d.ts +10 -0
- package/dist/src/data/transforms/flatten.d.ts.map +1 -0
- package/dist/src/data/transforms/flatten.js +68 -0
- package/dist/src/data/transforms/flatten.test.js +93 -0
- package/dist/src/data/transforms/flattenCompressedExons.d.ts +19 -0
- package/dist/src/data/transforms/flattenCompressedExons.d.ts.map +1 -0
- package/dist/src/data/transforms/flattenCompressedExons.js +53 -0
- package/dist/src/data/transforms/flattenDelimited.d.ts +10 -0
- package/dist/src/data/transforms/flattenDelimited.d.ts.map +1 -0
- package/dist/src/data/transforms/flattenDelimited.js +66 -0
- package/dist/src/data/transforms/flattenDelimited.test.js +87 -0
- package/dist/src/data/transforms/flattenSequence.d.ts +11 -0
- package/dist/src/data/transforms/flattenSequence.d.ts.map +1 -0
- package/dist/src/data/transforms/flattenSequence.js +35 -0
- package/dist/src/data/transforms/flattenSequence.test.js +34 -0
- package/dist/src/data/transforms/formula.d.ts +13 -0
- package/dist/src/data/transforms/formula.d.ts.map +1 -0
- package/dist/src/data/transforms/formula.js +35 -0
- package/dist/src/data/transforms/formula.test.js +19 -0
- package/dist/src/data/transforms/identifier.d.ts +40 -0
- package/dist/src/data/transforms/identifier.d.ts.map +1 -0
- package/dist/src/data/transforms/identifier.js +106 -0
- package/dist/src/data/transforms/identifier.test.js +83 -0
- package/dist/src/data/transforms/linearizeGenomicCoordinate.d.ts +10 -0
- package/dist/src/data/transforms/linearizeGenomicCoordinate.d.ts.map +1 -0
- package/dist/src/data/transforms/linearizeGenomicCoordinate.js +97 -0
- package/dist/src/data/transforms/measureText.d.ts +18 -0
- package/dist/src/data/transforms/measureText.d.ts.map +1 -0
- package/dist/src/data/transforms/measureText.js +42 -0
- package/dist/src/data/transforms/pileup.d.ts +10 -0
- package/dist/src/data/transforms/pileup.d.ts.map +1 -0
- package/dist/src/data/transforms/pileup.js +126 -0
- package/dist/src/data/transforms/pileup.test.js +70 -0
- package/dist/src/data/transforms/project.d.ts +13 -0
- package/dist/src/data/transforms/project.d.ts.map +1 -0
- package/dist/src/data/transforms/project.js +38 -0
- package/dist/src/data/transforms/project.test.js +32 -0
- package/dist/src/data/transforms/regexExtract.d.ts +13 -0
- package/dist/src/data/transforms/regexExtract.d.ts.map +1 -0
- package/dist/src/data/transforms/regexExtract.js +57 -0
- package/dist/src/data/transforms/regexExtract.test.js +67 -0
- package/dist/src/data/transforms/regexFold.d.ts +14 -0
- package/dist/src/data/transforms/regexFold.d.ts.map +1 -0
- package/dist/src/data/transforms/regexFold.js +139 -0
- package/dist/src/data/transforms/regexFold.test.js +160 -0
- package/dist/src/data/transforms/sample.d.ts +42 -0
- package/dist/src/data/transforms/sample.d.ts.map +1 -0
- package/dist/src/data/transforms/sample.js +99 -0
- package/dist/src/data/transforms/sample.test.js +38 -0
- package/dist/src/data/transforms/stack.d.ts +11 -0
- package/dist/src/data/transforms/stack.d.ts.map +1 -0
- package/dist/src/data/transforms/stack.js +134 -0
- package/dist/src/data/transforms/stack.test.js +91 -0
- package/dist/src/data/transforms/transformFactory.d.ts +12 -0
- package/dist/src/data/transforms/transformFactory.d.ts.map +1 -0
- package/dist/src/data/transforms/transformFactory.js +59 -0
- package/dist/src/encoder/accessor.d.ts +15 -0
- package/dist/src/encoder/accessor.d.ts.map +1 -0
- package/dist/src/encoder/accessor.js +76 -0
- package/dist/src/encoder/accessor.test.js +47 -0
- package/dist/src/encoder/encoder.d.ts +144 -0
- package/dist/src/encoder/encoder.d.ts.map +1 -0
- package/dist/src/encoder/encoder.js +400 -0
- package/dist/src/encoder/encoder.test.js +98 -0
- package/dist/src/fonts/Lato-Regular.json +1267 -0
- package/dist/src/fonts/Lato-Regular.png +0 -0
- package/dist/src/fonts/OFL.txt +93 -0
- package/dist/src/fonts/README.md +3 -0
- package/dist/src/fonts/bmFontManager.d.ts +182 -0
- package/dist/src/fonts/bmFontManager.d.ts.map +1 -0
- package/dist/src/fonts/bmFontManager.js +359 -0
- package/dist/src/fonts/bmFontMetrics.d.ts +45 -0
- package/dist/src/fonts/bmFontMetrics.d.ts.map +1 -0
- package/dist/src/fonts/bmFontMetrics.js +108 -0
- package/dist/src/genome/genome.d.ts +172 -0
- package/dist/src/genome/genome.d.ts.map +1 -0
- package/dist/src/genome/genome.js +379 -0
- package/dist/src/genome/genome.test.js +226 -0
- package/dist/src/genome/genomeStore.d.ts +20 -0
- package/dist/src/genome/genomeStore.d.ts.map +1 -0
- package/dist/src/genome/genomeStore.js +54 -0
- package/dist/src/genome/locusFormat.d.ts +14 -0
- package/dist/src/genome/locusFormat.d.ts.map +1 -0
- package/dist/src/genome/locusFormat.js +37 -0
- package/dist/src/genome/scaleIndex.d.ts +6 -0
- package/dist/src/genome/scaleIndex.d.ts.map +1 -0
- package/dist/src/genome/scaleIndex.js +165 -0
- package/dist/src/genome/scaleIndex.test.js +78 -0
- package/dist/src/genome/scaleLocus.d.ts +3 -0
- package/dist/src/genome/scaleLocus.d.ts.map +1 -0
- package/dist/src/genome/scaleLocus.js +101 -0
- package/dist/src/genome/scaleLocus.test.js +4 -0
- package/dist/src/genomeSpy.d.ts +141 -0
- package/dist/src/genomeSpy.d.ts.map +1 -0
- package/dist/src/genomeSpy.js +788 -0
- package/dist/src/gl/arrayBuilder.d.ts +71 -0
- package/dist/src/gl/arrayBuilder.d.ts.map +1 -0
- package/dist/src/gl/arrayBuilder.js +199 -0
- package/dist/src/gl/dataToVertices.d.ts +194 -0
- package/dist/src/gl/dataToVertices.d.ts.map +1 -0
- package/dist/src/gl/dataToVertices.js +639 -0
- package/dist/src/gl/includes/common.glsl.js +2 -0
- package/dist/src/gl/includes/picking.fragment.glsl.js +2 -0
- package/dist/src/gl/includes/picking.vertex.glsl.js +2 -0
- package/dist/src/gl/includes/sampleFacet.glsl.js +2 -0
- package/dist/src/gl/includes/scales.glsl.js +2 -0
- package/dist/src/gl/link.fragment.glsl.js +2 -0
- package/dist/src/gl/link.vertex.glsl.js +2 -0
- package/dist/src/gl/point.fragment.glsl.js +2 -0
- package/dist/src/gl/point.vertex.glsl.js +2 -0
- package/dist/src/gl/rect.fragment.glsl.js +2 -0
- package/dist/src/gl/rect.vertex.glsl.js +2 -0
- package/dist/src/gl/rule.fragment.glsl.js +2 -0
- package/dist/src/gl/rule.vertex.glsl.js +2 -0
- package/dist/src/gl/text.fragment.glsl.js +2 -0
- package/dist/src/gl/text.vertex.glsl.js +2 -0
- package/dist/src/gl/webGLHelper.d.ts +118 -0
- package/dist/src/gl/webGLHelper.d.ts.map +1 -0
- package/dist/src/gl/webGLHelper.js +513 -0
- package/dist/src/img/bowtie.svg +1 -0
- package/dist/src/img/genomespy-favicon.svg +34 -0
- package/dist/src/index.d.ts +15 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.html +11 -0
- package/dist/src/index.js +129 -0
- package/dist/src/marks/link.d.ts +11 -0
- package/dist/src/marks/link.d.ts.map +1 -0
- package/dist/src/marks/link.js +175 -0
- package/dist/src/marks/mark.d.ts +226 -0
- package/dist/src/marks/mark.d.ts.map +1 -0
- package/dist/src/marks/mark.js +1004 -0
- package/dist/src/marks/markUtils.d.ts +23 -0
- package/dist/src/marks/markUtils.d.ts.map +1 -0
- package/dist/src/marks/markUtils.js +125 -0
- package/dist/src/marks/pointMark.d.ts +11 -0
- package/dist/src/marks/pointMark.d.ts.map +1 -0
- package/dist/src/marks/pointMark.js +251 -0
- package/dist/src/marks/rectMark.d.ts +18 -0
- package/dist/src/marks/rectMark.d.ts.map +1 -0
- package/dist/src/marks/rectMark.js +255 -0
- package/dist/src/marks/rule.d.ts +6 -0
- package/dist/src/marks/rule.d.ts.map +1 -0
- package/dist/src/marks/rule.js +250 -0
- package/dist/src/marks/text.d.ts +13 -0
- package/dist/src/marks/text.d.ts.map +1 -0
- package/dist/src/marks/text.js +279 -0
- package/dist/src/scale/colorUtils.d.ts +34 -0
- package/dist/src/scale/colorUtils.d.ts.map +1 -0
- package/dist/src/scale/colorUtils.js +184 -0
- package/dist/src/scale/glslScaleGenerator.d.ts +45 -0
- package/dist/src/scale/glslScaleGenerator.d.ts.map +1 -0
- package/dist/src/scale/glslScaleGenerator.js +506 -0
- package/dist/src/scale/scale.d.ts +10 -0
- package/dist/src/scale/scale.d.ts.map +1 -0
- package/dist/src/scale/scale.js +456 -0
- package/dist/src/scale/scale.test.js +324 -0
- package/dist/src/scale/ticks.d.ts +47 -0
- package/dist/src/scale/ticks.d.ts.map +1 -0
- package/dist/src/scale/ticks.js +203 -0
- package/dist/src/scale/ticks.test.js +40 -0
- package/dist/src/singlePageApp.d.ts +2 -0
- package/dist/src/singlePageApp.d.ts.map +1 -0
- package/dist/src/singlePageApp.js +13 -0
- package/dist/src/spec/axis.d.ts +402 -0
- package/dist/src/spec/channel.d.ts +440 -0
- package/dist/src/spec/data.d.ts +370 -0
- package/dist/src/spec/font.d.ts +15 -0
- package/dist/src/spec/genome.d.ts +35 -0
- package/dist/src/spec/mark.d.ts +435 -0
- package/dist/src/spec/root.d.ts +22 -0
- package/dist/src/spec/sampleView.d.ts +185 -0
- package/dist/src/spec/scale.d.ts +273 -0
- package/dist/src/spec/title.d.ts +102 -0
- package/dist/src/spec/tooltip.d.ts +9 -0
- package/dist/src/spec/transform.d.ts +504 -0
- package/dist/src/spec/view.d.ts +214 -0
- package/dist/src/styles/genome-spy.css.d.ts +3 -0
- package/dist/src/styles/genome-spy.css.d.ts.map +1 -0
- package/dist/src/styles/genome-spy.css.js +114 -0
- package/dist/src/styles/genome-spy.scss +153 -0
- package/dist/src/tooltip/dataTooltipHandler.d.ts +2 -0
- package/dist/src/tooltip/dataTooltipHandler.d.ts.map +1 -0
- package/dist/src/tooltip/dataTooltipHandler.js +64 -0
- package/dist/src/tooltip/refseqGeneTooltipHandler.d.ts +2 -0
- package/dist/src/tooltip/refseqGeneTooltipHandler.d.ts.map +1 -0
- package/dist/src/tooltip/refseqGeneTooltipHandler.js +78 -0
- package/dist/src/tooltip/tooltipHandler.d.ts +9 -0
- package/dist/src/tooltip/tooltipHandler.d.ts.map +1 -0
- package/dist/src/tooltip/tooltipHandler.ts +12 -0
- package/dist/src/types/bmFont.d.ts +58 -0
- package/dist/src/types/embedApi.d.ts +67 -0
- package/dist/src/types/encoder.d.ts +84 -0
- package/dist/src/types/flowBatch.d.ts +40 -0
- package/dist/src/types/rendering.d.ts +65 -0
- package/dist/src/types/scaleResolutionApi.d.ts +40 -0
- package/dist/src/types/viewContext.d.ts +85 -0
- package/dist/src/utils/addBaseUrl.d.ts +6 -0
- package/dist/src/utils/addBaseUrl.d.ts.map +1 -0
- package/dist/src/utils/addBaseUrl.js +19 -0
- package/dist/src/utils/addBaseUrl.test.js +22 -0
- package/dist/src/utils/animator.d.ts +41 -0
- package/dist/src/utils/animator.d.ts.map +1 -0
- package/dist/src/utils/animator.js +83 -0
- package/dist/src/utils/arrayUtils.d.ts +34 -0
- package/dist/src/utils/arrayUtils.d.ts.map +1 -0
- package/dist/src/utils/arrayUtils.js +61 -0
- package/dist/src/utils/binnedIndex.d.ts +23 -0
- package/dist/src/utils/binnedIndex.d.ts.map +1 -0
- package/dist/src/utils/binnedIndex.js +167 -0
- package/dist/src/utils/binnedIndex.test.js +155 -0
- package/dist/src/utils/clamp.d.ts +7 -0
- package/dist/src/utils/clamp.d.ts.map +1 -0
- package/dist/src/utils/clamp.js +8 -0
- package/dist/src/utils/cloner.d.ts +16 -0
- package/dist/src/utils/cloner.d.ts.map +1 -0
- package/dist/src/utils/cloner.js +34 -0
- package/dist/src/utils/cloner.test.js +24 -0
- package/dist/src/utils/coalesce.d.ts +6 -0
- package/dist/src/utils/coalesce.d.ts.map +1 -0
- package/dist/src/utils/coalesce.js +11 -0
- package/dist/src/utils/coalesce.test.js +16 -0
- package/dist/src/utils/concatIterables.d.ts +8 -0
- package/dist/src/utils/concatIterables.d.ts.map +1 -0
- package/dist/src/utils/concatIterables.js +26 -0
- package/dist/src/utils/concatIterables.test.js +8 -0
- package/dist/src/utils/debounce.d.ts +8 -0
- package/dist/src/utils/debounce.d.ts.map +1 -0
- package/dist/src/utils/debounce.js +37 -0
- package/dist/src/utils/domainArray.d.ts +61 -0
- package/dist/src/utils/domainArray.d.ts.map +1 -0
- package/dist/src/utils/domainArray.js +216 -0
- package/dist/src/utils/domainArray.test.js +130 -0
- package/dist/src/utils/eerp.d.ts +12 -0
- package/dist/src/utils/eerp.d.ts.map +1 -0
- package/dist/src/utils/eerp.js +13 -0
- package/dist/src/utils/expression.d.ts +9 -0
- package/dist/src/utils/expression.d.ts.map +1 -0
- package/dist/src/utils/expression.js +32 -0
- package/dist/src/utils/field.d.ts +17 -0
- package/dist/src/utils/field.d.ts.map +1 -0
- package/dist/src/utils/field.js +28 -0
- package/dist/src/utils/formatObject.d.ts +7 -0
- package/dist/src/utils/formatObject.d.ts.map +1 -0
- package/dist/src/utils/formatObject.js +37 -0
- package/dist/src/utils/indexer.d.ts +16 -0
- package/dist/src/utils/indexer.d.ts.map +1 -0
- package/dist/src/utils/indexer.js +43 -0
- package/dist/src/utils/indexer.test.js +47 -0
- package/dist/src/utils/inertia.d.ts +42 -0
- package/dist/src/utils/inertia.d.ts.map +1 -0
- package/dist/src/utils/inertia.js +124 -0
- package/dist/src/utils/interactionEvent.d.ts +26 -0
- package/dist/src/utils/interactionEvent.d.ts.map +1 -0
- package/dist/src/utils/interactionEvent.js +33 -0
- package/dist/src/utils/iterateNestedMaps.d.ts +11 -0
- package/dist/src/utils/iterateNestedMaps.d.ts.map +1 -0
- package/dist/src/utils/iterateNestedMaps.js +21 -0
- package/dist/src/utils/iterateNestedMaps.test.js +33 -0
- package/dist/src/utils/kWayMerge.d.ts +9 -0
- package/dist/src/utils/kWayMerge.d.ts.map +1 -0
- package/dist/src/utils/kWayMerge.js +42 -0
- package/dist/src/utils/kWayMerge.test.js +26 -0
- package/dist/src/utils/layout/flexLayout.d.ts +182 -0
- package/dist/src/utils/layout/flexLayout.d.ts.map +1 -0
- package/dist/src/utils/layout/flexLayout.js +381 -0
- package/dist/src/utils/layout/flexLayout.test.js +323 -0
- package/dist/src/utils/layout/grid.d.ts +29 -0
- package/dist/src/utils/layout/grid.d.ts.map +1 -0
- package/dist/src/utils/layout/grid.js +95 -0
- package/dist/src/utils/layout/grid.test.js +71 -0
- package/dist/src/utils/layout/padding.d.ts +83 -0
- package/dist/src/utils/layout/padding.d.ts.map +1 -0
- package/dist/src/utils/layout/padding.js +155 -0
- package/dist/src/utils/layout/point.d.ts +16 -0
- package/dist/src/utils/layout/point.d.ts.map +1 -0
- package/dist/src/utils/layout/point.js +23 -0
- package/dist/src/utils/layout/rectangle.d.ts +142 -0
- package/dist/src/utils/layout/rectangle.d.ts.map +1 -0
- package/dist/src/utils/layout/rectangle.js +296 -0
- package/dist/src/utils/layout/rectangle.test.js +172 -0
- package/dist/src/utils/mergeObjects.d.ts +15 -0
- package/dist/src/utils/mergeObjects.d.ts.map +1 -0
- package/dist/src/utils/mergeObjects.js +99 -0
- package/dist/src/utils/mergeObjects.test.js +42 -0
- package/dist/src/utils/numberExtractor.d.ts +9 -0
- package/dist/src/utils/numberExtractor.d.ts.map +1 -0
- package/dist/src/utils/numberExtractor.js +24 -0
- package/dist/src/utils/numberExtractor.test.js +6 -0
- package/dist/src/utils/point.d.ts +9 -0
- package/dist/src/utils/point.d.ts.map +1 -0
- package/dist/src/utils/point.js +14 -0
- package/dist/src/utils/propertyCacher.d.ts +30 -0
- package/dist/src/utils/propertyCacher.d.ts.map +1 -0
- package/dist/src/utils/propertyCacher.js +70 -0
- package/dist/src/utils/propertyCacher.test.js +85 -0
- package/dist/src/utils/propertyCoalescer.d.ts +15 -0
- package/dist/src/utils/propertyCoalescer.d.ts.map +1 -0
- package/dist/src/utils/propertyCoalescer.js +42 -0
- package/dist/src/utils/propertyCoalescer.test.js +22 -0
- package/dist/src/utils/reservationMap.d.ts +42 -0
- package/dist/src/utils/reservationMap.d.ts.map +1 -0
- package/dist/src/utils/reservationMap.js +103 -0
- package/dist/src/utils/reservationMap.test.js +20 -0
- package/dist/src/utils/scaleNull.d.ts +13 -0
- package/dist/src/utils/scaleNull.d.ts.map +1 -0
- package/dist/src/utils/scaleNull.js +21 -0
- package/dist/src/utils/setOperations.d.ts +31 -0
- package/dist/src/utils/setOperations.d.ts.map +1 -0
- package/dist/src/utils/setOperations.js +75 -0
- package/dist/src/utils/smoothstep.d.ts +7 -0
- package/dist/src/utils/smoothstep.d.ts.map +1 -0
- package/dist/src/utils/smoothstep.js +10 -0
- package/dist/src/utils/throttle.d.ts +8 -0
- package/dist/src/utils/throttle.d.ts.map +1 -0
- package/dist/src/utils/throttle.js +34 -0
- package/dist/src/utils/topK.d.ts +22 -0
- package/dist/src/utils/topK.d.ts.map +1 -0
- package/dist/src/utils/topK.js +76 -0
- package/dist/src/utils/topK.test.js +64 -0
- package/dist/src/utils/transition.d.ts +44 -0
- package/dist/src/utils/transition.d.ts.map +1 -0
- package/dist/src/utils/transition.js +74 -0
- package/dist/src/utils/trees.d.ts +56 -0
- package/dist/src/utils/trees.d.ts.map +1 -0
- package/dist/src/utils/trees.js +92 -0
- package/dist/src/utils/trees.test.js +130 -0
- package/dist/src/utils/ui/tooltip.d.ts +50 -0
- package/dist/src/utils/ui/tooltip.d.ts.map +1 -0
- package/dist/src/utils/ui/tooltip.js +189 -0
- package/dist/src/utils/url.d.ts +9 -0
- package/dist/src/utils/url.d.ts.map +1 -0
- package/dist/src/utils/url.js +22 -0
- package/dist/src/utils/variableTools.d.ts +14 -0
- package/dist/src/utils/variableTools.d.ts.map +1 -0
- package/dist/src/utils/variableTools.js +24 -0
- package/dist/src/utils/variableTools.test.js +13 -0
- package/dist/src/view/axisGridView.d.ts +39 -0
- package/dist/src/view/axisGridView.d.ts.map +1 -0
- package/dist/src/view/axisGridView.js +246 -0
- package/dist/src/view/axisResolution.d.ts +24 -0
- package/dist/src/view/axisResolution.d.ts.map +1 -0
- package/dist/src/view/axisResolution.js +141 -0
- package/dist/src/view/axisResolution.test.js +201 -0
- package/dist/src/view/axisView.d.ts +49 -0
- package/dist/src/view/axisView.d.ts.map +1 -0
- package/dist/src/view/axisView.js +629 -0
- package/dist/src/view/concatView.d.ts +16 -0
- package/dist/src/view/concatView.d.ts.map +1 -0
- package/dist/src/view/concatView.js +84 -0
- package/dist/src/view/containerView.d.ts +43 -0
- package/dist/src/view/containerView.d.ts.map +1 -0
- package/dist/src/view/containerView.js +137 -0
- package/dist/src/view/facetView.d.ts +71 -0
- package/dist/src/view/facetView.d.ts.map +1 -0
- package/dist/src/view/facetView.js +492 -0
- package/dist/src/view/flowBuilder.d.ts +37 -0
- package/dist/src/view/flowBuilder.d.ts.map +1 -0
- package/dist/src/view/flowBuilder.js +383 -0
- package/dist/src/view/flowBuilder.test.js +125 -0
- package/dist/src/view/gridView.d.ts +111 -0
- package/dist/src/view/gridView.d.ts.map +1 -0
- package/dist/src/view/gridView.js +1086 -0
- package/dist/src/view/implicitRootView.d.ts +9 -0
- package/dist/src/view/implicitRootView.d.ts.map +1 -0
- package/dist/src/view/implicitRootView.js +23 -0
- package/dist/src/view/importView.d.ts +17 -0
- package/dist/src/view/importView.d.ts.map +1 -0
- package/dist/src/view/importView.js +22 -0
- package/dist/src/view/layerView.d.ts +25 -0
- package/dist/src/view/layerView.d.ts.map +1 -0
- package/dist/src/view/layerView.js +77 -0
- package/dist/src/view/renderingContext/bufferedViewRenderingContext.d.ts +30 -0
- package/dist/src/view/renderingContext/bufferedViewRenderingContext.d.ts.map +1 -0
- package/dist/src/view/renderingContext/bufferedViewRenderingContext.js +175 -0
- package/dist/src/view/renderingContext/compositeViewRenderingContext.d.ts +14 -0
- package/dist/src/view/renderingContext/compositeViewRenderingContext.d.ts.map +1 -0
- package/dist/src/view/renderingContext/compositeViewRenderingContext.js +51 -0
- package/dist/src/view/renderingContext/debuggingViewRenderingContext.d.ts +51 -0
- package/dist/src/view/renderingContext/debuggingViewRenderingContext.d.ts.map +1 -0
- package/dist/src/view/renderingContext/debuggingViewRenderingContext.js +94 -0
- package/dist/src/view/renderingContext/layoutRecorderViewRenderingContext.d.ts +60 -0
- package/dist/src/view/renderingContext/layoutRecorderViewRenderingContext.d.ts.map +1 -0
- package/dist/src/view/renderingContext/layoutRecorderViewRenderingContext.js +128 -0
- package/dist/src/view/renderingContext/simpleViewRenderingContext.d.ts +19 -0
- package/dist/src/view/renderingContext/simpleViewRenderingContext.d.ts.map +1 -0
- package/dist/src/view/renderingContext/simpleViewRenderingContext.js +64 -0
- package/dist/src/view/renderingContext/svgViewRenderingContext.d.ts +22 -0
- package/dist/src/view/renderingContext/svgViewRenderingContext.d.ts.map +1 -0
- package/dist/src/view/renderingContext/svgViewRenderingContext.js +125 -0
- package/dist/src/view/renderingContext/viewRenderingContext.d.ts +33 -0
- package/dist/src/view/renderingContext/viewRenderingContext.d.ts.map +1 -0
- package/dist/src/view/renderingContext/viewRenderingContext.js +41 -0
- package/dist/src/view/scaleResolution.d.ts +170 -0
- package/dist/src/view/scaleResolution.d.ts.map +1 -0
- package/dist/src/view/scaleResolution.js +874 -0
- package/dist/src/view/scaleResolution.test.js +658 -0
- package/dist/src/view/testUtils.d.ts +30 -0
- package/dist/src/view/testUtils.d.ts.map +1 -0
- package/dist/src/view/testUtils.js +101 -0
- package/dist/src/view/title.d.ts +6 -0
- package/dist/src/view/title.d.ts.map +1 -0
- package/dist/src/view/title.js +165 -0
- package/dist/src/view/unitView.d.ts +93 -0
- package/dist/src/view/unitView.d.ts.map +1 -0
- package/dist/src/view/unitView.js +345 -0
- package/dist/src/view/view.d.ts +291 -0
- package/dist/src/view/view.d.ts.map +1 -0
- package/dist/src/view/view.js +691 -0
- package/dist/src/view/view.test.js +214 -0
- package/dist/src/view/viewFactory.d.ts +76 -0
- package/dist/src/view/viewFactory.d.ts.map +1 -0
- package/dist/src/view/viewFactory.js +178 -0
- package/dist/src/view/viewFactory.test.js +17 -0
- package/dist/src/view/viewUtils.d.ts +90 -0
- package/dist/src/view/viewUtils.d.ts.map +1 -0
- package/dist/src/view/viewUtils.js +326 -0
- package/dist/src/view/zoom.d.ts +23 -0
- package/dist/src/view/zoom.d.ts.map +1 -0
- package/dist/src/view/zoom.js +89 -0
- package/package.json +17 -12
- package/dist/style.css +0 -1
|
@@ -0,0 +1,788 @@
|
|
|
1
|
+
import { formats as vegaFormats } from "vega-loader";
|
|
2
|
+
|
|
3
|
+
import css from "./styles/genome-spy.css.js";
|
|
4
|
+
import Tooltip from "./utils/ui/tooltip";
|
|
5
|
+
|
|
6
|
+
import AccessorFactory from "./encoder/accessor";
|
|
7
|
+
import {
|
|
8
|
+
resolveScalesAndAxes,
|
|
9
|
+
processImports,
|
|
10
|
+
setImplicitScaleNames,
|
|
11
|
+
calculateCanvasSize,
|
|
12
|
+
} from "./view/viewUtils";
|
|
13
|
+
import UnitView from "./view/unitView";
|
|
14
|
+
|
|
15
|
+
import WebGLHelper from "./gl/webGLHelper";
|
|
16
|
+
import Rectangle from "./utils/layout/rectangle";
|
|
17
|
+
import BufferedViewRenderingContext from "./view/renderingContext/bufferedViewRenderingContext";
|
|
18
|
+
import CompositeViewRenderingContext from "./view/renderingContext/compositeViewRenderingContext";
|
|
19
|
+
import InteractionEvent from "./utils/interactionEvent";
|
|
20
|
+
import Point from "./utils/layout/point";
|
|
21
|
+
import Animator from "./utils/animator";
|
|
22
|
+
import DataFlow from "./data/dataFlow";
|
|
23
|
+
import { buildDataFlow } from "./view/flowBuilder";
|
|
24
|
+
import { optimizeDataFlow } from "./data/flowOptimizer";
|
|
25
|
+
import GenomeStore from "./genome/genomeStore";
|
|
26
|
+
import BmFontManager from "./fonts/bmFontManager";
|
|
27
|
+
import fasta from "./data/formats/fasta";
|
|
28
|
+
import { VISIT_STOP } from "./view/view";
|
|
29
|
+
import Inertia, { makeEventTemplate } from "./utils/inertia";
|
|
30
|
+
import refseqGeneTooltipHandler from "./tooltip/refseqGeneTooltipHandler";
|
|
31
|
+
import dataTooltipHandler from "./tooltip/dataTooltipHandler";
|
|
32
|
+
import { invalidatePrefix } from "./utils/propertyCacher";
|
|
33
|
+
import { ViewFactory } from "./view/viewFactory";
|
|
34
|
+
import ImplicitRootView from "./view/implicitRootView";
|
|
35
|
+
import { reconfigureScales } from "./view/scaleResolution";
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Events that are broadcasted to all views.
|
|
39
|
+
* @typedef {"dataFlowBuilt" | "dataLoaded" | "layout" | "layoutComputed"} BroadcastEventType
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
vegaFormats("fasta", fasta);
|
|
43
|
+
|
|
44
|
+
export default class GenomeSpy {
|
|
45
|
+
/**
|
|
46
|
+
* @typedef {import("./view/view").default} View
|
|
47
|
+
* @typedef {import("./spec/view").ViewSpec} ViewSpec
|
|
48
|
+
* @typedef {import("./spec/root").RootSpec} RootSpec
|
|
49
|
+
* @typedef {import("./spec/root").RootConfig} RootConfig
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
*
|
|
54
|
+
* @param {HTMLElement} container
|
|
55
|
+
* @param {RootSpec} spec
|
|
56
|
+
* @param {import("./types/embedApi").EmbedOptions} [options]
|
|
57
|
+
*/
|
|
58
|
+
constructor(container, spec, options = {}) {
|
|
59
|
+
this.container = container;
|
|
60
|
+
|
|
61
|
+
const styleElement = document.createElement("style");
|
|
62
|
+
styleElement.innerHTML = css;
|
|
63
|
+
container.appendChild(styleElement);
|
|
64
|
+
|
|
65
|
+
/** Root level configuration object */
|
|
66
|
+
this.spec = spec;
|
|
67
|
+
|
|
68
|
+
this.accessorFactory = new AccessorFactory();
|
|
69
|
+
this.viewFactory = new ViewFactory();
|
|
70
|
+
|
|
71
|
+
/** @type {(function(string):object[])[]} */
|
|
72
|
+
this.namedDataProviders = [];
|
|
73
|
+
|
|
74
|
+
this.animator = new Animator(() => this.renderAll());
|
|
75
|
+
|
|
76
|
+
/** @type {GenomeStore} */
|
|
77
|
+
this.genomeStore = undefined;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* View visibility is checked using a predicate that can be overridden
|
|
81
|
+
* for more dynamic visibility management.
|
|
82
|
+
*
|
|
83
|
+
* @type {(view: View) => boolean}
|
|
84
|
+
*/
|
|
85
|
+
this.viewVisibilityPredicate = (view) => view.isVisibleInSpec();
|
|
86
|
+
|
|
87
|
+
/** @type {BufferedViewRenderingContext} */
|
|
88
|
+
this._renderingContext = undefined;
|
|
89
|
+
/** @type {BufferedViewRenderingContext} */
|
|
90
|
+
this._pickingContext = undefined;
|
|
91
|
+
|
|
92
|
+
/** Does picking buffer need to be rendered again */
|
|
93
|
+
this._dirtyPickingBuffer = false;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Currently hovered mark and datum
|
|
97
|
+
* @type {{ mark: import("./marks/mark").default, datum: import("./data/flowNode").Datum, uniqueId: number }}
|
|
98
|
+
*/
|
|
99
|
+
this._currentHover = undefined;
|
|
100
|
+
|
|
101
|
+
this._wheelInertia = new Inertia(this.animator);
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Keeping track so that these can be cleaned up upon finalization.
|
|
105
|
+
* @type {Map<string, (function(KeyboardEvent):void)[]>}
|
|
106
|
+
*/
|
|
107
|
+
this._keyboardListeners = new Map();
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Listers for exposed high-level events such as click on a mark instance.
|
|
111
|
+
* These should probably be in the View class and support bubbling through
|
|
112
|
+
* the hierarchy.
|
|
113
|
+
*
|
|
114
|
+
* @type {Map<string, Set<(event: any) => void>>}
|
|
115
|
+
*/
|
|
116
|
+
this._eventListeners = new Map();
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
*
|
|
120
|
+
* @type {Map<string, Set<(event: any) => void>>}
|
|
121
|
+
*/
|
|
122
|
+
this._extraBroadcastListeners = new Map();
|
|
123
|
+
|
|
124
|
+
/** @type {Record<string, import("./tooltip/tooltipHandler").TooltipHandler>}> */
|
|
125
|
+
this.tooltipHandlers = {
|
|
126
|
+
default: dataTooltipHandler,
|
|
127
|
+
refseqgene: refseqGeneTooltipHandler,
|
|
128
|
+
...(options.tooltipHandlers ?? {}),
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
/** @type {View} */
|
|
132
|
+
this.viewRoot = undefined;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
*
|
|
137
|
+
* @param {(name: string) => any[]} provider
|
|
138
|
+
*/
|
|
139
|
+
registerNamedDataProvider(provider) {
|
|
140
|
+
this.namedDataProviders.unshift(provider);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* @param {string} name
|
|
145
|
+
*/
|
|
146
|
+
getNamedDataFromProvider(name) {
|
|
147
|
+
for (const provider of this.namedDataProviders) {
|
|
148
|
+
const data = provider(name);
|
|
149
|
+
if (data) {
|
|
150
|
+
return data;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
*
|
|
157
|
+
* @param {string} name
|
|
158
|
+
* @param {any[]} data
|
|
159
|
+
*/
|
|
160
|
+
updateNamedData(name, data) {
|
|
161
|
+
const namedSource =
|
|
162
|
+
this.viewRoot.context.dataFlow.findNamedDataSource(name);
|
|
163
|
+
if (!namedSource) {
|
|
164
|
+
throw new Error("No such named data source: " + name);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
namedSource.dataSource.updateDynamicData(data);
|
|
168
|
+
reconfigureScales(namedSource.hosts);
|
|
169
|
+
|
|
170
|
+
this.animator.requestRender();
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Broadcast a message to all views
|
|
175
|
+
|
|
176
|
+
* @param {BroadcastEventType} type
|
|
177
|
+
* @param {any} [payload]
|
|
178
|
+
*/
|
|
179
|
+
broadcast(type, payload) {
|
|
180
|
+
const message = { type, payload };
|
|
181
|
+
this.viewRoot.visit((view) => view.handleBroadcast(message));
|
|
182
|
+
this._extraBroadcastListeners
|
|
183
|
+
.get(type)
|
|
184
|
+
?.forEach((listener) => listener(message));
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
_prepareContainer() {
|
|
188
|
+
this.container.classList.add("genome-spy");
|
|
189
|
+
this.container.classList.add("loading");
|
|
190
|
+
|
|
191
|
+
this._glHelper = new WebGLHelper(
|
|
192
|
+
this.container,
|
|
193
|
+
() =>
|
|
194
|
+
this.viewRoot
|
|
195
|
+
? calculateCanvasSize(this.viewRoot)
|
|
196
|
+
: { width: undefined, height: undefined },
|
|
197
|
+
this.spec.background
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
this.loadingMessageElement = document.createElement("div");
|
|
201
|
+
this.loadingMessageElement.className = "loading-message";
|
|
202
|
+
this.loadingMessageElement.innerHTML = `<div class="message">Loading<span class="ellipsis">...</span></div>`;
|
|
203
|
+
this.container.appendChild(this.loadingMessageElement);
|
|
204
|
+
|
|
205
|
+
this.tooltip = new Tooltip(this.container);
|
|
206
|
+
|
|
207
|
+
this.loadingMessageElement
|
|
208
|
+
.querySelector(".message")
|
|
209
|
+
.addEventListener("transitionend", () => {
|
|
210
|
+
/** @type {HTMLElement} */ (
|
|
211
|
+
this.loadingMessageElement
|
|
212
|
+
).style.display = "none";
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Unregisters all listeners, removes all created dom elements, removes all css classes from the container
|
|
218
|
+
*/
|
|
219
|
+
destroy() {
|
|
220
|
+
// TODO: There's a memory leak somewhere
|
|
221
|
+
|
|
222
|
+
this.container.classList.remove("genome-spy");
|
|
223
|
+
this.container.classList.remove("loading");
|
|
224
|
+
|
|
225
|
+
for (const [type, listeners] of this._keyboardListeners) {
|
|
226
|
+
for (const listener of listeners) {
|
|
227
|
+
document.removeEventListener(type, listener);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
this._glHelper.finalize();
|
|
232
|
+
|
|
233
|
+
while (this.container.firstChild) {
|
|
234
|
+
this.container.firstChild.remove();
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
async _prepareViewsAndData() {
|
|
239
|
+
if (this.spec.genome) {
|
|
240
|
+
this.genomeStore = new GenomeStore(this.spec.baseUrl);
|
|
241
|
+
await this.genomeStore.initialize(this.spec.genome);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// eslint-disable-next-line consistent-this
|
|
245
|
+
const self = this;
|
|
246
|
+
|
|
247
|
+
/** @type {import("./types/viewContext").default} */
|
|
248
|
+
const context = {
|
|
249
|
+
dataFlow: new DataFlow(),
|
|
250
|
+
accessorFactory: this.accessorFactory,
|
|
251
|
+
glHelper: this._glHelper,
|
|
252
|
+
animator: this.animator,
|
|
253
|
+
genomeStore: this.genomeStore,
|
|
254
|
+
fontManager: new BmFontManager(this._glHelper),
|
|
255
|
+
|
|
256
|
+
get devicePixelRatio() {
|
|
257
|
+
return self._glHelper.dpr;
|
|
258
|
+
},
|
|
259
|
+
|
|
260
|
+
requestLayoutReflow: () => {
|
|
261
|
+
// placeholder
|
|
262
|
+
},
|
|
263
|
+
updateTooltip: this.updateTooltip.bind(this),
|
|
264
|
+
getNamedDataFromProvider: this.getNamedDataFromProvider.bind(this),
|
|
265
|
+
getCurrentHover: () => this._currentHover,
|
|
266
|
+
|
|
267
|
+
addKeyboardListener: (type, listener) => {
|
|
268
|
+
// TODO: Listeners should be called only when the mouse pointer is inside the
|
|
269
|
+
// container or the app covers the full document.
|
|
270
|
+
document.addEventListener(type, listener);
|
|
271
|
+
let listeners = this._keyboardListeners.get(type);
|
|
272
|
+
if (!listeners) {
|
|
273
|
+
listeners = [];
|
|
274
|
+
this._keyboardListeners.set(type, listeners);
|
|
275
|
+
}
|
|
276
|
+
listeners.push(listener);
|
|
277
|
+
},
|
|
278
|
+
|
|
279
|
+
addBroadcastListener(type, listener) {
|
|
280
|
+
const listenersByType = self._extraBroadcastListeners;
|
|
281
|
+
|
|
282
|
+
// Copy-paste code. TODO: Refactor into a helper function.
|
|
283
|
+
let listeners = listenersByType.get(type);
|
|
284
|
+
if (!listeners) {
|
|
285
|
+
listeners = new Set();
|
|
286
|
+
listenersByType.set(type, listeners);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
listeners.add(listener);
|
|
290
|
+
},
|
|
291
|
+
|
|
292
|
+
removeBroadcastListener(type, listener) {
|
|
293
|
+
const listenersByType = self._extraBroadcastListeners;
|
|
294
|
+
|
|
295
|
+
listenersByType.get(type)?.delete(listener);
|
|
296
|
+
},
|
|
297
|
+
|
|
298
|
+
isViewConfiguredVisible: self.viewVisibilityPredicate,
|
|
299
|
+
|
|
300
|
+
isViewSpec: (spec) => self.viewFactory.isViewSpec(spec),
|
|
301
|
+
|
|
302
|
+
createView: function (spec, layoutParent, dataParent, defaultName) {
|
|
303
|
+
return self.viewFactory.createView(
|
|
304
|
+
spec,
|
|
305
|
+
context,
|
|
306
|
+
layoutParent,
|
|
307
|
+
dataParent,
|
|
308
|
+
defaultName
|
|
309
|
+
);
|
|
310
|
+
},
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
/** @type {ViewSpec & RootConfig} */
|
|
314
|
+
const rootSpec = this.spec;
|
|
315
|
+
|
|
316
|
+
if (rootSpec.datasets) {
|
|
317
|
+
this.registerNamedDataProvider((name) => rootSpec.datasets[name]);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Create the view hierarchy
|
|
321
|
+
this.viewRoot = context.createView(rootSpec, null, null, "viewRoot");
|
|
322
|
+
|
|
323
|
+
// Replace placeholder ImportViews with actual views.
|
|
324
|
+
await processImports(this.viewRoot);
|
|
325
|
+
|
|
326
|
+
if (this.viewRoot.needsAxes.x || this.viewRoot.needsAxes.y) {
|
|
327
|
+
this.viewRoot = new ImplicitRootView(context, this.viewRoot);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Resolve scales, i.e., if possible, pull them towards the root
|
|
331
|
+
resolveScalesAndAxes(this.viewRoot);
|
|
332
|
+
setImplicitScaleNames(this.viewRoot);
|
|
333
|
+
|
|
334
|
+
// Wrap unit or layer views that need axes
|
|
335
|
+
//this.viewRoot = addDecorators(this.viewRoot);
|
|
336
|
+
|
|
337
|
+
// We should now have a complete view hierarchy. Let's update the canvas size
|
|
338
|
+
// and ensure that the loading message is visible.
|
|
339
|
+
this._glHelper.invalidateSize();
|
|
340
|
+
|
|
341
|
+
// Collect all unit views to a list because they need plenty of initialization
|
|
342
|
+
/** @type {UnitView[]} */
|
|
343
|
+
const unitViews = [];
|
|
344
|
+
this.viewRoot.visit((view) => {
|
|
345
|
+
if (view instanceof UnitView) {
|
|
346
|
+
unitViews.push(view);
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
// Build the data flow based on the view hierarchy
|
|
351
|
+
const flow = buildDataFlow(this.viewRoot, context.dataFlow);
|
|
352
|
+
optimizeDataFlow(flow);
|
|
353
|
+
this.broadcast("dataFlowBuilt", flow);
|
|
354
|
+
|
|
355
|
+
// @ts-expect-error
|
|
356
|
+
if (import.meta.env.DEV) {
|
|
357
|
+
flow.dataSources.forEach((ds) => console.log(ds.subtreeToString()));
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Create encoders (accessors, scales and related metadata)
|
|
361
|
+
unitViews.forEach((view) => view.mark.initializeEncoders());
|
|
362
|
+
|
|
363
|
+
// Compile shaders, create or load textures, etc.
|
|
364
|
+
const graphicsInitialized = Promise.all(
|
|
365
|
+
unitViews.map((view) => view.mark.initializeGraphics())
|
|
366
|
+
);
|
|
367
|
+
|
|
368
|
+
for (const view of unitViews) {
|
|
369
|
+
flow.addObserver((collector) => {
|
|
370
|
+
view.mark.initializeData();
|
|
371
|
+
// Update WebGL buffers
|
|
372
|
+
view.mark.updateGraphicsData();
|
|
373
|
+
}, view);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Have to wait until asynchronous font loading is complete.
|
|
377
|
+
// Text mark's geometry builder needs font metrics before data can be
|
|
378
|
+
// converted into geometries.
|
|
379
|
+
await context.fontManager.waitUntilReady();
|
|
380
|
+
|
|
381
|
+
// Find all data sources and initiate loading
|
|
382
|
+
flow.initialize();
|
|
383
|
+
await Promise.all(
|
|
384
|
+
flow.dataSources.map((dataSource) => dataSource.load())
|
|
385
|
+
);
|
|
386
|
+
|
|
387
|
+
// Now that all data have been loaded, the domains may need adjusting
|
|
388
|
+
// IMPORTANT TODO: Check that discrete domains and indexers match!!!!!!!!!
|
|
389
|
+
reconfigureScales(this.viewRoot);
|
|
390
|
+
|
|
391
|
+
// This event is needed by SampleView so that it can extract the sample ids
|
|
392
|
+
// from the data once they are loaded.
|
|
393
|
+
// TODO: It would be great if this could be attached to the data flow,
|
|
394
|
+
// because now this is somewhat a hack and is incompatible with dynamic data
|
|
395
|
+
// loading in the future.
|
|
396
|
+
this.broadcast("dataLoaded");
|
|
397
|
+
|
|
398
|
+
await graphicsInitialized;
|
|
399
|
+
|
|
400
|
+
this.viewRoot.visit((view) => {
|
|
401
|
+
for (const resolution of Object.values(view.resolutions.scale)) {
|
|
402
|
+
this._glHelper.createRangeTexture(resolution);
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
for (const view of unitViews) {
|
|
407
|
+
view.mark.finalizeGraphicsInitialization();
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// Allow layout computation
|
|
411
|
+
// eslint-disable-next-line require-atomic-updates
|
|
412
|
+
context.requestLayoutReflow = this.computeLayout.bind(this);
|
|
413
|
+
|
|
414
|
+
// Invalidate cached sizes to ensure that step-based sizes are current.
|
|
415
|
+
// TODO: This should be done automatically when the domains of band/point scales are updated.
|
|
416
|
+
this.viewRoot.visit((view) => invalidatePrefix(view, "size"));
|
|
417
|
+
this._glHelper.invalidateSize();
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* TODO: Come up with a sensible name. And maybe this should be called at the end of the constructor.
|
|
422
|
+
* @returns {Promise<boolean>} true if the launch was successful
|
|
423
|
+
*/
|
|
424
|
+
async launch() {
|
|
425
|
+
try {
|
|
426
|
+
this._prepareContainer();
|
|
427
|
+
|
|
428
|
+
await this._prepareViewsAndData();
|
|
429
|
+
|
|
430
|
+
this.registerMouseEvents();
|
|
431
|
+
|
|
432
|
+
this.computeLayout();
|
|
433
|
+
this.animator.requestRender();
|
|
434
|
+
|
|
435
|
+
// Register resize listener after the initial layout computation to prevent
|
|
436
|
+
// incomplete layouts from accidentally polluting any caches related to sizes.
|
|
437
|
+
this._glHelper.addEventListener("resize", () => {
|
|
438
|
+
this.computeLayout();
|
|
439
|
+
// Render immediately, without RAF
|
|
440
|
+
this.renderAll();
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
return true;
|
|
444
|
+
} catch (reason) {
|
|
445
|
+
const message = `${
|
|
446
|
+
reason.view ? `At "${reason.view.getPathString()}": ` : ""
|
|
447
|
+
}${reason.toString()}`;
|
|
448
|
+
console.error(reason.stack);
|
|
449
|
+
createMessageBox(this.container, message);
|
|
450
|
+
|
|
451
|
+
return false;
|
|
452
|
+
} finally {
|
|
453
|
+
this.container.classList.remove("loading");
|
|
454
|
+
// Transition listener doesn't appear to work on observablehq
|
|
455
|
+
window.setTimeout(() => {
|
|
456
|
+
this.loadingMessageElement.style.display = "none";
|
|
457
|
+
}, 2000);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
registerMouseEvents() {
|
|
462
|
+
const canvas = this._glHelper.canvas;
|
|
463
|
+
|
|
464
|
+
// TODO: This function is huge. Refactor this into a separate class
|
|
465
|
+
// that would also contain state-related stuff that currently pollute the
|
|
466
|
+
// GenomeSpy class.
|
|
467
|
+
|
|
468
|
+
/** @param {Event} event */
|
|
469
|
+
const listener = (event) => {
|
|
470
|
+
if (event instanceof MouseEvent) {
|
|
471
|
+
if (event.type == "mousemove") {
|
|
472
|
+
this.tooltip.handleMouseMove(event);
|
|
473
|
+
this._tooltipUpdateRequested = false;
|
|
474
|
+
|
|
475
|
+
if (event.buttons == 0) {
|
|
476
|
+
// Disable during dragging
|
|
477
|
+
this.renderPickingFramebuffer();
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
const rect = canvas.getBoundingClientRect();
|
|
482
|
+
const point = new Point(
|
|
483
|
+
event.clientX - rect.left - canvas.clientLeft,
|
|
484
|
+
event.clientY - rect.top - canvas.clientTop
|
|
485
|
+
);
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* @param {MouseEvent} event
|
|
489
|
+
*/
|
|
490
|
+
const dispatchEvent = (event) => {
|
|
491
|
+
this.viewRoot.propagateInteractionEvent(
|
|
492
|
+
new InteractionEvent(point, event)
|
|
493
|
+
);
|
|
494
|
+
|
|
495
|
+
if (!this._tooltipUpdateRequested) {
|
|
496
|
+
this.tooltip.clear();
|
|
497
|
+
}
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
if (event.type != "wheel") {
|
|
501
|
+
this._wheelInertia.cancel();
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
if (event.type == "mousemove") {
|
|
505
|
+
this._handlePicking(point.x, point.y);
|
|
506
|
+
} else if (
|
|
507
|
+
event.type == "mousedown" ||
|
|
508
|
+
event.type == "mouseup"
|
|
509
|
+
) {
|
|
510
|
+
this.renderPickingFramebuffer();
|
|
511
|
+
} else if (event.type == "wheel") {
|
|
512
|
+
this._tooltipUpdateRequested = false;
|
|
513
|
+
|
|
514
|
+
const wheelEvent = /** @type {WheelEvent} */ (event);
|
|
515
|
+
|
|
516
|
+
if (
|
|
517
|
+
Math.abs(wheelEvent.deltaX) >
|
|
518
|
+
Math.abs(wheelEvent.deltaY)
|
|
519
|
+
) {
|
|
520
|
+
// If the viewport is panned (horizontally) using the wheel (touchpad),
|
|
521
|
+
// the picking buffer becomes stale and needs redrawing. However, we
|
|
522
|
+
// optimize by just clearing the currently hovered item so that snapping
|
|
523
|
+
// doesn't work incorrectly when zooming in/out.
|
|
524
|
+
|
|
525
|
+
// TODO: More robust solution (handle at higher level such as ScaleResolution's zoom method)
|
|
526
|
+
this._currentHover = null;
|
|
527
|
+
|
|
528
|
+
this._wheelInertia.cancel();
|
|
529
|
+
} else {
|
|
530
|
+
// Vertical wheeling zooms.
|
|
531
|
+
// We use inertia to generate fake wheel events for smoother zooming
|
|
532
|
+
|
|
533
|
+
const template = makeEventTemplate(wheelEvent);
|
|
534
|
+
|
|
535
|
+
this._wheelInertia.setMomentum(
|
|
536
|
+
wheelEvent.deltaY * (wheelEvent.deltaMode ? 80 : 1),
|
|
537
|
+
(delta) => {
|
|
538
|
+
const e = new WheelEvent("wheel", {
|
|
539
|
+
...template,
|
|
540
|
+
deltaMode: 0,
|
|
541
|
+
deltaX: 0,
|
|
542
|
+
deltaY: delta,
|
|
543
|
+
});
|
|
544
|
+
dispatchEvent(e);
|
|
545
|
+
}
|
|
546
|
+
);
|
|
547
|
+
|
|
548
|
+
wheelEvent.preventDefault();
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// TODO: Should be handled at the view level, not globally
|
|
554
|
+
if (event.type == "click") {
|
|
555
|
+
const e = this._currentHover
|
|
556
|
+
? {
|
|
557
|
+
type: event.type,
|
|
558
|
+
viewPath: this._currentHover.mark.unitView
|
|
559
|
+
.getLayoutAncestors()
|
|
560
|
+
.map((view) => view.name)
|
|
561
|
+
.reverse(),
|
|
562
|
+
datum: this._currentHover.datum,
|
|
563
|
+
}
|
|
564
|
+
: {
|
|
565
|
+
type: event.type,
|
|
566
|
+
viewPath: null,
|
|
567
|
+
datum: null,
|
|
568
|
+
};
|
|
569
|
+
|
|
570
|
+
this._eventListeners
|
|
571
|
+
.get("click")
|
|
572
|
+
?.forEach((listener) => listener(e));
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
dispatchEvent(event);
|
|
576
|
+
}
|
|
577
|
+
};
|
|
578
|
+
|
|
579
|
+
[
|
|
580
|
+
"mousedown",
|
|
581
|
+
"mouseup",
|
|
582
|
+
"wheel",
|
|
583
|
+
"click",
|
|
584
|
+
"mousemove",
|
|
585
|
+
"gesturechange",
|
|
586
|
+
"contextmenu",
|
|
587
|
+
].forEach((type) => canvas.addEventListener(type, listener));
|
|
588
|
+
|
|
589
|
+
canvas.addEventListener("mousedown", () => {
|
|
590
|
+
document.addEventListener(
|
|
591
|
+
"mouseup",
|
|
592
|
+
() => this.tooltip.popEnabledState(),
|
|
593
|
+
{ once: true }
|
|
594
|
+
);
|
|
595
|
+
this.tooltip.pushEnabledState(false);
|
|
596
|
+
});
|
|
597
|
+
|
|
598
|
+
// Prevent text selections etc while dragging
|
|
599
|
+
canvas.addEventListener("dragstart", (event) =>
|
|
600
|
+
event.stopPropagation()
|
|
601
|
+
);
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* @param {number} x
|
|
606
|
+
* @param {number} y
|
|
607
|
+
*/
|
|
608
|
+
_handlePicking(x, y) {
|
|
609
|
+
const pixelValue = this._glHelper.readPickingPixel(x, y);
|
|
610
|
+
|
|
611
|
+
const uniqueId =
|
|
612
|
+
pixelValue[0] | (pixelValue[1] << 8) | (pixelValue[2] << 16);
|
|
613
|
+
|
|
614
|
+
if (uniqueId == 0) {
|
|
615
|
+
this._currentHover = null;
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
if (uniqueId !== this._currentHover?.uniqueId) {
|
|
620
|
+
this._currentHover = null;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
if (!this._currentHover) {
|
|
624
|
+
// We are doing an exhaustive search of the data. This is a bit slow with
|
|
625
|
+
// millions of items.
|
|
626
|
+
// TODO: Optimize by indexing or something
|
|
627
|
+
|
|
628
|
+
this.viewRoot.visit((view) => {
|
|
629
|
+
if (view instanceof UnitView) {
|
|
630
|
+
if (view.mark.isPickingParticipant()) {
|
|
631
|
+
const accessor = view.mark.encoders.uniqueId.accessor;
|
|
632
|
+
view.getCollector().visitData((d) => {
|
|
633
|
+
if (accessor(d) == uniqueId) {
|
|
634
|
+
this._currentHover = {
|
|
635
|
+
mark: view.mark,
|
|
636
|
+
datum: d,
|
|
637
|
+
uniqueId,
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
if (this._currentHover) {
|
|
643
|
+
return VISIT_STOP;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
if (this._currentHover) {
|
|
650
|
+
const mark = this._currentHover.mark;
|
|
651
|
+
this.updateTooltip(this._currentHover.datum, async (datum) => {
|
|
652
|
+
if (!mark.isPickingParticipant()) {
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
const tooltipProps = mark.properties.tooltip;
|
|
657
|
+
|
|
658
|
+
if (tooltipProps !== null) {
|
|
659
|
+
const handlerName = tooltipProps?.handler ?? "default";
|
|
660
|
+
const handler = this.tooltipHandlers[handlerName];
|
|
661
|
+
if (!handler) {
|
|
662
|
+
throw new Error(
|
|
663
|
+
"No such tooltip handler: " + handlerName
|
|
664
|
+
);
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
return handler(datum, mark, tooltipProps?.params);
|
|
668
|
+
}
|
|
669
|
+
});
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
/**
|
|
674
|
+
* This method should be called in a mouseMove handler. If not called, the
|
|
675
|
+
* tooltip will be hidden.
|
|
676
|
+
*
|
|
677
|
+
* @param {T} datum
|
|
678
|
+
* @param {function(T):Promise<string | HTMLElement | import("lit").TemplateResult>} [converter]
|
|
679
|
+
* @template T
|
|
680
|
+
*/
|
|
681
|
+
updateTooltip(datum, converter) {
|
|
682
|
+
if (!this._tooltipUpdateRequested || !datum) {
|
|
683
|
+
this.tooltip.updateWithDatum(datum, converter);
|
|
684
|
+
this._tooltipUpdateRequested = true;
|
|
685
|
+
} else {
|
|
686
|
+
throw new Error(
|
|
687
|
+
"Tooltip has already been updated! Duplicate event handler?"
|
|
688
|
+
);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
computeLayout() {
|
|
693
|
+
const root = this.viewRoot;
|
|
694
|
+
if (!root) {
|
|
695
|
+
return;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
this.broadcast("layout");
|
|
699
|
+
|
|
700
|
+
const canvasSize = this._glHelper.getLogicalCanvasSize();
|
|
701
|
+
|
|
702
|
+
if (isNaN(canvasSize.width) || isNaN(canvasSize.height)) {
|
|
703
|
+
// TODO: Figure out what causes this
|
|
704
|
+
console.log(
|
|
705
|
+
`NaN in canvas size: ${canvasSize.width}x${canvasSize.height}. Skipping computeLayout().`
|
|
706
|
+
);
|
|
707
|
+
return;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
this._renderingContext = new BufferedViewRenderingContext(
|
|
711
|
+
{
|
|
712
|
+
picking: false,
|
|
713
|
+
},
|
|
714
|
+
this._glHelper
|
|
715
|
+
);
|
|
716
|
+
this._pickingContext = new BufferedViewRenderingContext(
|
|
717
|
+
{
|
|
718
|
+
picking: true,
|
|
719
|
+
},
|
|
720
|
+
this._glHelper
|
|
721
|
+
);
|
|
722
|
+
|
|
723
|
+
root.render(
|
|
724
|
+
new CompositeViewRenderingContext(
|
|
725
|
+
this._renderingContext,
|
|
726
|
+
this._pickingContext
|
|
727
|
+
),
|
|
728
|
+
// Canvas should now be sized based on the root view or the container
|
|
729
|
+
Rectangle.create(0, 0, canvasSize.width, canvasSize.height)
|
|
730
|
+
);
|
|
731
|
+
|
|
732
|
+
this.broadcast("layoutComputed");
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
renderAll() {
|
|
736
|
+
this._renderingContext?.render();
|
|
737
|
+
|
|
738
|
+
this._dirtyPickingBuffer = true;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
renderPickingFramebuffer() {
|
|
742
|
+
if (!this._dirtyPickingBuffer) {
|
|
743
|
+
return;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
this._pickingContext.render();
|
|
747
|
+
this._dirtyPickingBuffer = false;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
getSearchableViews() {
|
|
751
|
+
/** @type {UnitView[]} */
|
|
752
|
+
const views = [];
|
|
753
|
+
this.viewRoot.visit((view) => {
|
|
754
|
+
if (view instanceof UnitView && view.getAccessor("search")) {
|
|
755
|
+
views.push(view);
|
|
756
|
+
}
|
|
757
|
+
});
|
|
758
|
+
return views;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
getNamedScaleResolutions() {
|
|
762
|
+
/** @type {Map<string, import("./view/scaleResolution").default>} */
|
|
763
|
+
const resolutions = new Map();
|
|
764
|
+
this.viewRoot.visit((view) => {
|
|
765
|
+
for (const resolution of Object.values(view.resolutions.scale)) {
|
|
766
|
+
if (resolution.name) {
|
|
767
|
+
resolutions.set(resolution.name, resolution);
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
});
|
|
771
|
+
return resolutions;
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
/**
|
|
776
|
+
*
|
|
777
|
+
* @param {HTMLElement} container
|
|
778
|
+
* @param {string} message
|
|
779
|
+
*/
|
|
780
|
+
function createMessageBox(container, message) {
|
|
781
|
+
// Uh, need a templating thingy
|
|
782
|
+
const messageBox = document.createElement("div");
|
|
783
|
+
messageBox.className = "message-box";
|
|
784
|
+
const messageText = document.createElement("div");
|
|
785
|
+
messageText.textContent = message;
|
|
786
|
+
messageBox.appendChild(messageText);
|
|
787
|
+
container.appendChild(messageBox);
|
|
788
|
+
}
|