@genome-spy/core 0.67.0 → 0.69.0
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.es.js +15884 -13130
- package/dist/bundle/index.js +130 -149
- package/dist/schema.json +6498 -6191
- package/dist/src/data/collector.d.ts +20 -0
- package/dist/src/data/collector.d.ts.map +1 -1
- package/dist/src/data/collector.js +148 -0
- package/dist/src/data/dataFlow.d.ts +6 -0
- package/dist/src/data/dataFlow.d.ts.map +1 -1
- package/dist/src/data/dataFlow.js +20 -0
- package/dist/src/data/flowInit.d.ts.map +1 -1
- package/dist/src/data/flowInit.js +2 -3
- package/dist/src/data/flowNode.d.ts +33 -10
- package/dist/src/data/flowNode.d.ts.map +1 -1
- package/dist/src/data/flowNode.js +84 -13
- package/dist/src/data/flowTestUtils.d.ts +2 -2
- package/dist/src/data/flowTestUtils.d.ts.map +1 -1
- package/dist/src/data/flowTestUtils.js +5 -4
- package/dist/src/data/keyIndex.d.ts +18 -0
- package/dist/src/data/keyIndex.d.ts.map +1 -0
- package/dist/src/data/keyIndex.js +241 -0
- package/dist/src/data/keyIndex.test.d.ts +2 -0
- package/dist/src/data/keyIndex.test.d.ts.map +1 -0
- package/dist/src/data/sources/dataSource.d.ts.map +1 -1
- package/dist/src/data/sources/dataSource.js +7 -3
- package/dist/src/data/sources/dataSourceFactory.d.ts +14 -12
- package/dist/src/data/sources/dataSourceFactory.d.ts.map +1 -1
- package/dist/src/data/sources/dataSourceFactory.js +52 -16
- package/dist/src/data/sources/lazy/bigBedSource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/bigBedSource.js +11 -10
- package/dist/src/data/sources/lazy/bigWigSource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/bigWigSource.js +11 -10
- package/dist/src/data/sources/lazy/mockLazySource.d.ts +29 -0
- package/dist/src/data/sources/lazy/mockLazySource.d.ts.map +1 -0
- package/dist/src/data/sources/lazy/mockLazySource.js +44 -0
- package/dist/src/data/sources/lazy/singleAxisLazySource.d.ts +22 -1
- package/dist/src/data/sources/lazy/singleAxisLazySource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/singleAxisLazySource.js +34 -2
- package/dist/src/data/sources/lazy/singleAxisWindowedSource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/singleAxisWindowedSource.js +16 -1
- package/dist/src/data/sources/lazy/tabixSource.d.ts +0 -1
- package/dist/src/data/sources/lazy/tabixSource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/tabixSource.js +56 -16
- package/dist/src/data/sources/sequenceSource.d.ts.map +1 -1
- package/dist/src/data/sources/sequenceSource.js +5 -3
- package/dist/src/data/sources/urlSource.d.ts.map +1 -1
- package/dist/src/data/sources/urlSource.js +7 -3
- package/dist/src/data/transforms/filter.d.ts +4 -4
- package/dist/src/data/transforms/filter.d.ts.map +1 -1
- package/dist/src/data/transforms/filter.js +13 -7
- package/dist/src/data/transforms/filterScoredLabels.d.ts.map +1 -1
- package/dist/src/data/transforms/filterScoredLabels.js +11 -6
- package/dist/src/data/transforms/filterScoredLabels.test.d.ts +2 -0
- package/dist/src/data/transforms/filterScoredLabels.test.d.ts.map +1 -0
- package/dist/src/data/transforms/formula.d.ts +4 -4
- package/dist/src/data/transforms/formula.d.ts.map +1 -1
- package/dist/src/data/transforms/formula.js +12 -6
- package/dist/src/data/transforms/measureText.d.ts +2 -2
- package/dist/src/data/transforms/measureText.d.ts.map +1 -1
- package/dist/src/data/transforms/measureText.js +16 -12
- package/dist/src/data/transforms/stack.d.ts.map +1 -1
- package/dist/src/data/transforms/stack.js +1 -0
- package/dist/src/data/transforms/transform.d.ts +2 -2
- package/dist/src/data/transforms/transform.d.ts.map +1 -1
- package/dist/src/data/transforms/transform.js +3 -3
- package/dist/src/encoder/accessor.d.ts +51 -4
- package/dist/src/encoder/accessor.d.ts.map +1 -1
- package/dist/src/encoder/accessor.js +174 -10
- package/dist/src/encoder/encoder.d.ts +11 -2
- package/dist/src/encoder/encoder.d.ts.map +1 -1
- package/dist/src/encoder/encoder.js +29 -9
- package/dist/src/encoder/metadataChannels.d.ts +15 -0
- package/dist/src/encoder/metadataChannels.d.ts.map +1 -0
- package/dist/src/encoder/metadataChannels.js +65 -0
- package/dist/src/encoder/metadataChannels.test.d.ts +2 -0
- package/dist/src/encoder/metadataChannels.test.d.ts.map +1 -0
- package/dist/src/genome/genome.d.ts +8 -0
- package/dist/src/genome/genome.d.ts.map +1 -1
- package/dist/src/genome/genome.js +16 -1
- package/dist/src/genome/scaleLocus.d.ts.map +1 -1
- package/dist/src/genome/scaleLocus.js +14 -1
- package/dist/src/genomeSpy/containerUi.d.ts +0 -1
- package/dist/src/genomeSpy/containerUi.d.ts.map +1 -1
- package/dist/src/genomeSpy/containerUi.js +0 -14
- package/dist/src/genomeSpy/inputBindingManager.js +1 -1
- package/dist/src/genomeSpy/interactionController.d.ts.map +1 -1
- package/dist/src/genomeSpy/interactionController.js +7 -1
- package/dist/src/genomeSpy/loadingIndicatorManager.d.ts +3 -7
- package/dist/src/genomeSpy/loadingIndicatorManager.d.ts.map +1 -1
- package/dist/src/genomeSpy/loadingIndicatorManager.js +68 -20
- package/dist/src/genomeSpy/loadingStatusRegistry.d.ts +52 -0
- package/dist/src/genomeSpy/loadingStatusRegistry.d.ts.map +1 -0
- package/dist/src/genomeSpy/loadingStatusRegistry.js +86 -0
- package/dist/src/genomeSpy/viewContextFactory.d.ts.map +1 -1
- package/dist/src/genomeSpy/viewContextFactory.js +0 -1
- package/dist/src/genomeSpy/viewDataInit.d.ts.map +1 -1
- package/dist/src/genomeSpy/viewDataInit.js +56 -11
- package/dist/src/genomeSpy.d.ts +0 -2
- package/dist/src/genomeSpy.d.ts.map +1 -1
- package/dist/src/genomeSpy.js +47 -27
- package/dist/src/gl/glslScaleGenerator.js +1 -1
- package/dist/src/marks/mark.d.ts.map +1 -1
- package/dist/src/marks/mark.js +40 -41
- package/dist/src/marks/markUtils.js +1 -1
- package/dist/src/marks/point.d.ts.map +1 -1
- package/dist/src/marks/point.js +4 -6
- package/dist/src/paramRuntime/expressionCompiler.d.ts +7 -0
- package/dist/src/paramRuntime/expressionCompiler.d.ts.map +1 -0
- package/dist/src/paramRuntime/expressionCompiler.js +10 -0
- package/dist/src/paramRuntime/expressionRef.d.ts +20 -0
- package/dist/src/paramRuntime/expressionRef.d.ts.map +1 -0
- package/dist/src/paramRuntime/expressionRef.js +95 -0
- package/dist/src/paramRuntime/expressionRef.test.d.ts +2 -0
- package/dist/src/paramRuntime/expressionRef.test.d.ts.map +1 -0
- package/dist/src/paramRuntime/graphRuntime.d.ts +176 -0
- package/dist/src/paramRuntime/graphRuntime.d.ts.map +1 -0
- package/dist/src/paramRuntime/graphRuntime.js +628 -0
- package/dist/src/paramRuntime/graphRuntime.test.d.ts +2 -0
- package/dist/src/paramRuntime/graphRuntime.test.d.ts.map +1 -0
- package/dist/src/paramRuntime/index.d.ts +9 -0
- package/dist/src/paramRuntime/index.d.ts.map +1 -0
- package/dist/src/paramRuntime/index.js +8 -0
- package/dist/src/paramRuntime/lifecycleRegistry.d.ts +27 -0
- package/dist/src/paramRuntime/lifecycleRegistry.d.ts.map +1 -0
- package/dist/src/paramRuntime/lifecycleRegistry.js +54 -0
- package/dist/src/paramRuntime/paramRuntime.d.ts +165 -0
- package/dist/src/paramRuntime/paramRuntime.d.ts.map +1 -0
- package/dist/src/paramRuntime/paramRuntime.js +222 -0
- package/dist/src/paramRuntime/paramRuntime.test.d.ts +2 -0
- package/dist/src/paramRuntime/paramRuntime.test.d.ts.map +1 -0
- package/dist/src/paramRuntime/paramStore.d.ts +68 -0
- package/dist/src/paramRuntime/paramStore.d.ts.map +1 -0
- package/dist/src/paramRuntime/paramStore.js +148 -0
- package/dist/src/paramRuntime/paramStore.test.d.ts +2 -0
- package/dist/src/paramRuntime/paramStore.test.d.ts.map +1 -0
- package/dist/src/paramRuntime/paramUtils.d.ts +86 -0
- package/dist/src/paramRuntime/paramUtils.d.ts.map +1 -0
- package/dist/src/paramRuntime/paramUtils.js +272 -0
- package/dist/src/paramRuntime/selectionStore.d.ts +6 -0
- package/dist/src/paramRuntime/selectionStore.d.ts.map +1 -0
- package/dist/src/paramRuntime/selectionStore.js +13 -0
- package/dist/src/paramRuntime/types.d.ts +16 -0
- package/dist/src/paramRuntime/types.d.ts.map +1 -0
- package/dist/src/paramRuntime/types.js +25 -0
- package/dist/src/paramRuntime/viewParamRuntime.d.ts +164 -0
- package/dist/src/paramRuntime/viewParamRuntime.d.ts.map +1 -0
- package/dist/src/paramRuntime/viewParamRuntime.js +443 -0
- package/dist/src/scale/scale.d.ts +6 -1
- package/dist/src/scale/scale.d.ts.map +1 -1
- package/dist/src/scale/scale.js +83 -23
- package/dist/src/scales/axisResolution.d.ts.map +1 -1
- package/dist/src/scales/axisResolution.js +10 -0
- package/dist/src/scales/{scaleDomainAggregator.d.ts → domainPlanner.d.ts} +6 -3
- package/dist/src/scales/domainPlanner.d.ts.map +1 -0
- package/dist/src/scales/{scaleDomainAggregator.js → domainPlanner.js} +128 -10
- package/dist/src/scales/domainPlanner.test.d.ts +2 -0
- package/dist/src/scales/domainPlanner.test.d.ts.map +1 -0
- package/dist/src/scales/scaleInstanceManager.d.ts +6 -3
- package/dist/src/scales/scaleInstanceManager.d.ts.map +1 -1
- package/dist/src/scales/scaleInstanceManager.js +17 -11
- package/dist/src/scales/scaleInteractionController.d.ts +6 -0
- package/dist/src/scales/scaleInteractionController.d.ts.map +1 -1
- package/dist/src/scales/scaleInteractionController.js +41 -3
- package/dist/src/scales/scaleResolution.d.ts +20 -17
- package/dist/src/scales/scaleResolution.d.ts.map +1 -1
- package/dist/src/scales/scaleResolution.js +188 -71
- package/dist/src/scales/scaleResolution.test.d.ts.map +1 -1
- package/dist/src/selection/selection.d.ts +21 -0
- package/dist/src/selection/selection.d.ts.map +1 -1
- package/dist/src/selection/selection.js +83 -1
- package/dist/src/spec/channel.d.ts +52 -15
- package/dist/src/spec/coreSchemaRoot.d.ts +53 -0
- package/dist/src/spec/data.d.ts +4 -0
- package/dist/src/spec/parameter.d.ts +16 -11
- package/dist/src/spec/root.d.ts +1 -1
- package/dist/src/spec/testing.d.ts +12 -0
- package/dist/src/spec/testing.d.ts.map +1 -0
- package/dist/src/spec/testing.js +20 -0
- package/dist/src/spec/view.d.ts +157 -41
- package/dist/src/styles/genome-spy.css +3 -31
- package/dist/src/styles/genome-spy.css.d.ts +1 -1
- package/dist/src/styles/genome-spy.css.d.ts.map +1 -1
- package/dist/src/styles/genome-spy.css.js +0 -29
- package/dist/src/tooltip/dataTooltipHandler.d.ts +1 -1
- package/dist/src/tooltip/dataTooltipHandler.js +23 -32
- package/dist/src/tooltip/dataTooltipHandler.test.d.ts +2 -0
- package/dist/src/tooltip/dataTooltipHandler.test.d.ts.map +1 -0
- package/dist/src/tooltip/flattenDatumRows.d.ts +13 -0
- package/dist/src/tooltip/flattenDatumRows.d.ts.map +1 -0
- package/dist/src/tooltip/flattenDatumRows.js +47 -0
- package/dist/src/tooltip/flattenDatumRows.test.d.ts +2 -0
- package/dist/src/tooltip/flattenDatumRows.test.d.ts.map +1 -0
- package/dist/src/tooltip/refseqGeneTooltipHandler.d.ts +1 -1
- package/dist/src/tooltip/refseqGeneTooltipHandler.js +7 -1
- package/dist/src/tooltip/tooltipContext.d.ts +13 -0
- package/dist/src/tooltip/tooltipContext.d.ts.map +1 -0
- package/dist/src/tooltip/tooltipContext.js +543 -0
- package/dist/src/tooltip/tooltipContext.test.d.ts +2 -0
- package/dist/src/tooltip/tooltipContext.test.d.ts.map +1 -0
- package/dist/src/tooltip/tooltipHandler.d.ts +40 -1
- package/dist/src/tooltip/tooltipHandler.d.ts.map +1 -1
- package/dist/src/tooltip/tooltipHandler.ts +62 -1
- package/dist/src/types/encoder.d.ts +38 -3
- package/dist/src/types/rendering.d.ts +4 -3
- package/dist/src/types/viewContext.d.ts +0 -14
- package/dist/src/utils/inputBinding.d.ts +10 -2
- package/dist/src/utils/inputBinding.d.ts.map +1 -1
- package/dist/src/utils/inputBinding.js +12 -3
- package/dist/src/utils/throttle.d.ts +4 -1
- package/dist/src/utils/throttle.d.ts.map +1 -1
- package/dist/src/utils/throttle.js +54 -23
- package/dist/src/utils/throttle.test.d.ts +2 -0
- package/dist/src/utils/throttle.test.d.ts.map +1 -0
- package/dist/src/utils/transition.d.ts +21 -0
- package/dist/src/utils/transition.d.ts.map +1 -1
- package/dist/src/utils/transition.js +28 -0
- package/dist/src/utils/ui/tooltip.d.ts.map +1 -1
- package/dist/src/utils/ui/tooltip.js +7 -1
- package/dist/src/utils/ui/tooltip.test.d.ts +2 -0
- package/dist/src/utils/ui/tooltip.test.d.ts.map +1 -0
- package/dist/src/view/axisGridView.d.ts.map +1 -1
- package/dist/src/view/axisGridView.js +22 -5
- package/dist/src/view/axisView.d.ts.map +1 -1
- package/dist/src/view/axisView.js +20 -5
- package/dist/src/view/concatView.js +3 -3
- package/dist/src/view/containerMutationHelper.js +1 -1
- package/dist/src/view/containerView.d.ts +9 -5
- package/dist/src/view/containerView.d.ts.map +1 -1
- package/dist/src/view/containerView.js +34 -9
- package/dist/src/view/dataReadiness.d.ts +46 -0
- package/dist/src/view/dataReadiness.d.ts.map +1 -0
- package/dist/src/view/dataReadiness.js +267 -0
- package/dist/src/view/dataReadiness.test.d.ts +2 -0
- package/dist/src/view/dataReadiness.test.d.ts.map +1 -0
- package/dist/src/view/facetView.d.ts.map +1 -1
- package/dist/src/view/facetView.js +7 -5
- package/dist/src/view/flowBuilder.d.ts.map +1 -1
- package/dist/src/view/flowBuilder.js +17 -4
- package/dist/src/view/gridView/gridChild.d.ts.map +1 -1
- package/dist/src/view/gridView/gridChild.js +16 -3
- package/dist/src/view/gridView/gridView.d.ts.map +1 -1
- package/dist/src/view/gridView/gridView.js +119 -2
- package/dist/src/view/gridView/scrollbar.d.ts.map +1 -1
- package/dist/src/view/gridView/scrollbar.js +3 -0
- package/dist/src/view/gridView/selectionRect.d.ts +6 -10
- package/dist/src/view/gridView/selectionRect.d.ts.map +1 -1
- package/dist/src/view/gridView/selectionRect.js +22 -24
- package/dist/src/view/gridView/separatorView.d.ts +51 -0
- package/dist/src/view/gridView/separatorView.d.ts.map +1 -0
- package/dist/src/view/gridView/separatorView.js +275 -0
- package/dist/src/view/layerView.d.ts.map +1 -1
- package/dist/src/view/layerView.js +7 -5
- package/dist/src/view/layout/flexLayout.d.ts +0 -30
- package/dist/src/view/layout/flexLayout.d.ts.map +1 -1
- package/dist/src/view/layout/flexLayout.js +0 -86
- package/dist/src/view/multiscale.d.ts +35 -0
- package/dist/src/view/multiscale.d.ts.map +1 -0
- package/dist/src/view/multiscale.js +233 -0
- package/dist/src/view/multiscale.test.d.ts +2 -0
- package/dist/src/view/multiscale.test.d.ts.map +1 -0
- package/dist/src/view/testUtils.d.ts.map +1 -1
- package/dist/src/view/testUtils.js +6 -1
- package/dist/src/view/unitView.d.ts +8 -13
- package/dist/src/view/unitView.d.ts.map +1 -1
- package/dist/src/view/unitView.js +120 -45
- package/dist/src/view/view.d.ts +27 -18
- package/dist/src/view/view.d.ts.map +1 -1
- package/dist/src/view/view.js +298 -37
- package/dist/src/view/viewFactory.d.ts +0 -12
- package/dist/src/view/viewFactory.d.ts.map +1 -1
- package/dist/src/view/viewFactory.js +55 -25
- package/dist/src/view/viewParamRuntime.test.d.ts +2 -0
- package/dist/src/view/viewParamRuntime.test.d.ts.map +1 -0
- package/dist/src/view/viewSelectors.d.ts +148 -0
- package/dist/src/view/viewSelectors.d.ts.map +1 -0
- package/dist/src/view/viewSelectors.js +776 -0
- package/dist/src/view/viewSelectors.test.d.ts +2 -0
- package/dist/src/view/viewSelectors.test.d.ts.map +1 -0
- package/dist/src/view/viewUtils.d.ts +0 -8
- package/dist/src/view/viewUtils.d.ts.map +1 -1
- package/dist/src/view/viewUtils.js +1 -21
- package/package.json +4 -4
- package/dist/src/scales/scaleDomainAggregator.d.ts.map +0 -1
- package/dist/src/scales/scaleDomainAggregator.test.d.ts +0 -2
- package/dist/src/scales/scaleDomainAggregator.test.d.ts.map +0 -1
- package/dist/src/spec/sampleView.d.ts +0 -197
- package/dist/src/view/paramMediator.d.ts +0 -149
- package/dist/src/view/paramMediator.d.ts.map +0 -1
- package/dist/src/view/paramMediator.js +0 -478
- package/dist/src/view/paramMediator.test.d.ts +0 -2
- package/dist/src/view/paramMediator.test.d.ts.map +0 -1
|
@@ -13,7 +13,7 @@ import { configureDomain } from "../scale/scale.js";
|
|
|
13
13
|
|
|
14
14
|
import ScaleInstanceManager from "./scaleInstanceManager.js";
|
|
15
15
|
import { resolveScalePropsBase } from "./scalePropsResolver.js";
|
|
16
|
-
import
|
|
16
|
+
import DomainPlanner from "./domainPlanner.js";
|
|
17
17
|
import ScaleInteractionController from "./scaleInteractionController.js";
|
|
18
18
|
import {
|
|
19
19
|
INDEX,
|
|
@@ -23,10 +23,10 @@ import {
|
|
|
23
23
|
QUANTITATIVE,
|
|
24
24
|
} from "./scaleResolutionConstants.js";
|
|
25
25
|
|
|
26
|
+
import { getAccessorDomainKey } from "../encoder/accessor.js";
|
|
26
27
|
import { isSecondaryChannel } from "../encoder/encoder.js";
|
|
27
28
|
import { NominalDomain } from "../utils/domainArray.js";
|
|
28
|
-
import {
|
|
29
|
-
import { VISIT_SKIP } from "../view/view.js";
|
|
29
|
+
import { shallowArrayEquals } from "../utils/arrayUtils.js";
|
|
30
30
|
import createIndexer from "../utils/indexer.js";
|
|
31
31
|
|
|
32
32
|
// Register scaleLocus to Vega-Scale.
|
|
@@ -44,7 +44,7 @@ export { INDEX, LOCUS, NOMINAL, ORDINAL, QUANTITATIVE };
|
|
|
44
44
|
* @prop {import("../view/unitView.js").default} view TODO: Get rid of the view reference
|
|
45
45
|
* @prop {T} channel
|
|
46
46
|
* @prop {import("../spec/channel.js").ChannelDefWithScale} channelDef
|
|
47
|
-
* @prop {
|
|
47
|
+
* @prop {boolean} contributesToDomain
|
|
48
48
|
*/
|
|
49
49
|
/**
|
|
50
50
|
* Resolves a shared scale for a channel by merging scale properties and domains
|
|
@@ -53,6 +53,16 @@ export { INDEX, LOCUS, NOMINAL, ORDINAL, QUANTITATIVE };
|
|
|
53
53
|
* notifications, while delegating domain aggregation, scale instance setup, and
|
|
54
54
|
* interaction logic to focused helpers.
|
|
55
55
|
*
|
|
56
|
+
* Documentation overview of current concerns this class (and its helpers) deal with:
|
|
57
|
+
* - Resolution membership and rules (shared/independent/forced/excluded, visibility, registration).
|
|
58
|
+
* - Scale property aggregation (merge props, channel overrides, unique scale names).
|
|
59
|
+
* - Domain computation and caching (configured/data unions, defaults, indexer stability, subscriptions).
|
|
60
|
+
* - Scale instance lifecycle (create, reconfigure props, apply domains, notify changes).
|
|
61
|
+
* - Interaction and zoom (zoom/pan/reset coordination, snapshots, zoom extents).
|
|
62
|
+
* - Rendering integration (range textures, axis sizing/positioning).
|
|
63
|
+
* - Locus-specific conversions (complex intervals, genome extent bindings).
|
|
64
|
+
* - Diagnostics and edge cases (ordinal unknown, nice/zero/padding, log warnings).
|
|
65
|
+
*
|
|
56
66
|
* @implements {ScaleResolutionApi}
|
|
57
67
|
*/
|
|
58
68
|
export default class ScaleResolution {
|
|
@@ -76,6 +86,9 @@ export default class ScaleResolution {
|
|
|
76
86
|
/** @type {Set<ScaleResolutionMember>} The involved views */
|
|
77
87
|
#members = new Set();
|
|
78
88
|
|
|
89
|
+
/** @type {Set<ScaleResolutionMember>} */
|
|
90
|
+
#dataDomainMembers = new Set();
|
|
91
|
+
|
|
79
92
|
/**
|
|
80
93
|
* @type {Record<ScaleResolutionEventType, Set<ScaleResolutionListener>>}
|
|
81
94
|
*/
|
|
@@ -87,7 +100,7 @@ export default class ScaleResolution {
|
|
|
87
100
|
/** @type {ScaleInstanceManager} */
|
|
88
101
|
#scaleManager;
|
|
89
102
|
|
|
90
|
-
/** @type {
|
|
103
|
+
/** @type {DomainPlanner} */
|
|
91
104
|
#domainAggregator;
|
|
92
105
|
|
|
93
106
|
/** @type {ScaleInteractionController} */
|
|
@@ -109,15 +122,17 @@ export default class ScaleResolution {
|
|
|
109
122
|
/** @type {string} An optional unique identifier for the scale */
|
|
110
123
|
this.name = undefined;
|
|
111
124
|
|
|
112
|
-
this.#domainAggregator = new
|
|
125
|
+
this.#domainAggregator = new DomainPlanner({
|
|
113
126
|
getMembers: () => this.#getActiveMembers(),
|
|
127
|
+
getDataMembers: () =>
|
|
128
|
+
this.#getActiveMembers(this.#dataDomainMembers),
|
|
114
129
|
getType: () => this.type,
|
|
115
130
|
getLocusExtent: () => this.#getLocusExtent(),
|
|
116
131
|
fromComplexInterval: this.fromComplexInterval.bind(this),
|
|
117
132
|
});
|
|
118
133
|
|
|
119
134
|
this.#scaleManager = new ScaleInstanceManager({
|
|
120
|
-
|
|
135
|
+
getParamRuntime: () => this.#firstMemberView.paramRuntime,
|
|
121
136
|
onRangeChange: () => this.#notifyListeners("range"),
|
|
122
137
|
onDomainChange: () => this.#notifyListeners("domain"),
|
|
123
138
|
getGenomeStore: () => this.#viewContext.genomeStore,
|
|
@@ -146,10 +161,13 @@ export default class ScaleResolution {
|
|
|
146
161
|
return first.view;
|
|
147
162
|
}
|
|
148
163
|
|
|
149
|
-
|
|
164
|
+
/**
|
|
165
|
+
* @param {Set<ScaleResolutionMember>} [members]
|
|
166
|
+
*/
|
|
167
|
+
#getActiveMembers(members = this.#members) {
|
|
150
168
|
/** @type {Set<ScaleResolutionMember>} */
|
|
151
169
|
const active = new Set();
|
|
152
|
-
for (const member of
|
|
170
|
+
for (const member of members) {
|
|
153
171
|
const view = member.view;
|
|
154
172
|
if (!view.isConfiguredVisible()) {
|
|
155
173
|
continue;
|
|
@@ -289,6 +307,10 @@ export default class ScaleResolution {
|
|
|
289
307
|
}
|
|
290
308
|
|
|
291
309
|
this.#members.add(newMember);
|
|
310
|
+
if (newMember.contributesToDomain) {
|
|
311
|
+
this.#dataDomainMembers.add(newMember);
|
|
312
|
+
}
|
|
313
|
+
this.#domainAggregator.invalidateConfiguredDomain();
|
|
292
314
|
}
|
|
293
315
|
|
|
294
316
|
/**
|
|
@@ -299,10 +321,68 @@ export default class ScaleResolution {
|
|
|
299
321
|
this.#addMember(member);
|
|
300
322
|
return () => {
|
|
301
323
|
const removed = this.#members.delete(member);
|
|
324
|
+
if (removed) {
|
|
325
|
+
this.#dataDomainMembers.delete(member);
|
|
326
|
+
this.#domainAggregator.invalidateConfiguredDomain();
|
|
327
|
+
}
|
|
302
328
|
return removed && this.#members.size === 0;
|
|
303
329
|
};
|
|
304
330
|
}
|
|
305
331
|
|
|
332
|
+
dispose() {
|
|
333
|
+
this.#listeners.domain.clear();
|
|
334
|
+
this.#listeners.range.clear();
|
|
335
|
+
this.#scaleManager.dispose();
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
#hasRenderedMember() {
|
|
339
|
+
for (const member of this.#members) {
|
|
340
|
+
if (member.view.hasRendered()) {
|
|
341
|
+
return true;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return false;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* @param {import("../data/collector.js").default} collector
|
|
349
|
+
* @param {Iterable<import("../types/encoder.js").ScaleAccessor>} accessors
|
|
350
|
+
* @returns {() => void}
|
|
351
|
+
*/
|
|
352
|
+
registerCollectorSubscriptions(collector, accessors) {
|
|
353
|
+
/** @type {Set<string>} */
|
|
354
|
+
const domainKeys = new Set();
|
|
355
|
+
|
|
356
|
+
for (const accessor of accessors) {
|
|
357
|
+
if (accessor.channelDef.domainInert) {
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
domainKeys.add(getAccessorDomainKey(accessor, this.type));
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (domainKeys.size === 0) {
|
|
364
|
+
return () => undefined;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const listener = () => {
|
|
368
|
+
this.reconfigureDomain();
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
/** @type {(() => void)[]} */
|
|
372
|
+
const unregisters = [];
|
|
373
|
+
for (const domainKey of domainKeys) {
|
|
374
|
+
unregisters.push(
|
|
375
|
+
collector.subscribeDomainChanges(domainKey, listener)
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
return () => {
|
|
380
|
+
for (const unregister of unregisters) {
|
|
381
|
+
unregister();
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
|
|
306
386
|
/**
|
|
307
387
|
* Returns true if the domain has been defined explicitly, i.e. not extracted from the data.
|
|
308
388
|
*/
|
|
@@ -432,36 +512,108 @@ export default class ScaleResolution {
|
|
|
432
512
|
* or when scale properties are otherwise re-resolved from the view hierarchy.
|
|
433
513
|
*/
|
|
434
514
|
reconfigure() {
|
|
435
|
-
|
|
436
|
-
|
|
515
|
+
this.#domainAggregator.invalidateConfiguredDomain();
|
|
516
|
+
const state = this.#computeScaleState(true);
|
|
517
|
+
if (!state) {
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
this.#applyReconfigure(state, (scale, props) =>
|
|
521
|
+
this.#scaleManager.reconfigureScale(props)
|
|
522
|
+
);
|
|
523
|
+
this.#finalizeReconfigure(state);
|
|
437
524
|
}
|
|
438
525
|
|
|
439
526
|
/**
|
|
440
527
|
* Reconfigures only the effective domain (configured + data-derived).
|
|
441
528
|
*
|
|
442
529
|
* Use this when data changes but the scale membership and properties are stable.
|
|
530
|
+
*
|
|
443
531
|
*/
|
|
444
532
|
reconfigureDomain() {
|
|
445
|
-
const
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
}
|
|
533
|
+
const state = this.#computeScaleState(true, true);
|
|
534
|
+
if (!state) {
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
const { domainConfig, targetDomain } = state;
|
|
538
|
+
const domainMatches =
|
|
539
|
+
targetDomain != null &&
|
|
540
|
+
shallowArrayEquals(targetDomain, state.scale.domain());
|
|
541
|
+
|
|
542
|
+
if (targetDomain != null && !domainMatches) {
|
|
543
|
+
this.#applyReconfigure(state, (scale) => {
|
|
544
|
+
scale.domain(targetDomain);
|
|
545
|
+
if (domainConfig.applyOrdinalUnknown) {
|
|
546
|
+
// Keep ordinal unknown handling close to the domain write so
|
|
547
|
+
// domainImplicit semantics stay aligned with the applied domain.
|
|
548
|
+
/** @type {any} */ (scale).unknown(
|
|
549
|
+
domainConfig.ordinalUnknown
|
|
550
|
+
);
|
|
551
|
+
}
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
this.#finalizeReconfigure(state);
|
|
449
555
|
}
|
|
450
556
|
|
|
451
557
|
/**
|
|
452
|
-
* @param {
|
|
558
|
+
* @param {boolean} extractDataDomain
|
|
559
|
+
* @param {boolean} [includeDomainConfig]
|
|
560
|
+
* @returns {{
|
|
561
|
+
* scale: ScaleWithProps,
|
|
562
|
+
* props: import("../spec/scale.js").Scale,
|
|
563
|
+
* previousDomain: any[],
|
|
564
|
+
* domainWasInitialized: boolean,
|
|
565
|
+
* domainConfig?: ReturnType<typeof configureDomain>,
|
|
566
|
+
* targetDomain?: any[] | null,
|
|
567
|
+
* } | undefined}
|
|
453
568
|
*/
|
|
454
|
-
#
|
|
569
|
+
#computeScaleState(extractDataDomain, includeDomainConfig = false) {
|
|
455
570
|
const scale = this.#scaleManager.scale;
|
|
456
571
|
|
|
457
572
|
if (!scale || scale.type == "null") {
|
|
458
573
|
return;
|
|
459
574
|
}
|
|
460
575
|
|
|
461
|
-
const
|
|
462
|
-
|
|
576
|
+
const state = {
|
|
577
|
+
scale,
|
|
578
|
+
props: this.#getScaleProps(extractDataDomain),
|
|
579
|
+
previousDomain: scale.domain(),
|
|
580
|
+
domainWasInitialized: this.#isDomainInitialized(),
|
|
581
|
+
};
|
|
582
|
+
|
|
583
|
+
if (includeDomainConfig) {
|
|
584
|
+
const domainConfig = configureDomain(scale, state.props);
|
|
585
|
+
return {
|
|
586
|
+
...state,
|
|
587
|
+
domainConfig,
|
|
588
|
+
targetDomain: domainConfig.domain,
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
return state;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
/**
|
|
596
|
+
* @param {{
|
|
597
|
+
* scale: ScaleWithProps,
|
|
598
|
+
* props: import("../spec/scale.js").Scale,
|
|
599
|
+
* }} inputs
|
|
600
|
+
* @param {(scale: ScaleWithProps, props: import("../spec/scale.js").Scale) => void} apply
|
|
601
|
+
*/
|
|
602
|
+
#applyReconfigure(inputs, apply) {
|
|
603
|
+
this.#scaleManager.withDomainNotificationsSuppressed(() => {
|
|
604
|
+
apply(inputs.scale, inputs.props);
|
|
605
|
+
});
|
|
606
|
+
}
|
|
463
607
|
|
|
464
|
-
|
|
608
|
+
/**
|
|
609
|
+
* @param {{
|
|
610
|
+
* scale: ScaleWithProps,
|
|
611
|
+
* previousDomain: any[],
|
|
612
|
+
* domainWasInitialized: boolean,
|
|
613
|
+
* }} inputs
|
|
614
|
+
*/
|
|
615
|
+
#finalizeReconfigure(inputs) {
|
|
616
|
+
const { scale, previousDomain, domainWasInitialized } = inputs;
|
|
465
617
|
|
|
466
618
|
if (
|
|
467
619
|
this.#domainAggregator.captureInitialDomain(
|
|
@@ -475,13 +627,18 @@ export default class ScaleResolution {
|
|
|
475
627
|
}
|
|
476
628
|
|
|
477
629
|
const newDomain = scale.domain();
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
630
|
+
const action = this.#interactionController.getDomainChangeAction(
|
|
631
|
+
previousDomain,
|
|
632
|
+
newDomain
|
|
633
|
+
);
|
|
634
|
+
|
|
635
|
+
if (action === "restore") {
|
|
636
|
+
// Don't mess with zoomed views, restore the previous domain
|
|
637
|
+
this.#scaleManager.withDomainNotificationsSuppressed(() => {
|
|
638
|
+
scale.domain(previousDomain);
|
|
639
|
+
});
|
|
640
|
+
} else if (action === "animate") {
|
|
641
|
+
if (this.#hasRenderedMember()) {
|
|
485
642
|
// It can be zoomed, so lets make a smooth transition.
|
|
486
643
|
// Restore the previous domain and zoom smoothly to the new domain.
|
|
487
644
|
this.#scaleManager.withDomainNotificationsSuppressed(() => {
|
|
@@ -489,10 +646,12 @@ export default class ScaleResolution {
|
|
|
489
646
|
});
|
|
490
647
|
this.zoomTo(newDomain, 500); // TODO: Configurable duration
|
|
491
648
|
} else {
|
|
492
|
-
// Update immediately if the previous domain was the initial domain [0, 0]
|
|
493
|
-
// Notifications were suppressed during reconfigure; notify explicitly.
|
|
494
649
|
this.#notifyListeners("domain");
|
|
495
650
|
}
|
|
651
|
+
} else if (action === "notify") {
|
|
652
|
+
// Update immediately if the previous domain was the initial domain [0, 0]
|
|
653
|
+
// Notifications were suppressed during reconfigure; notify explicitly.
|
|
654
|
+
this.#notifyListeners("domain");
|
|
496
655
|
}
|
|
497
656
|
}
|
|
498
657
|
|
|
@@ -688,45 +847,3 @@ export default class ScaleResolution {
|
|
|
688
847
|
return /** @type {number[]} */ (interval);
|
|
689
848
|
}
|
|
690
849
|
}
|
|
691
|
-
|
|
692
|
-
/**
|
|
693
|
-
* Reconfigures scale domains for resolutions used by the given view(s).
|
|
694
|
-
*
|
|
695
|
-
* Use this for data-driven updates where only domains need refreshing.
|
|
696
|
-
*
|
|
697
|
-
* TODO: This should be made unnecessary. Collectors should trigger the reconfiguration
|
|
698
|
-
* for those views that get their data from the collector.
|
|
699
|
-
*
|
|
700
|
-
* TODO: This may reconfigure channels that are not affected by the change.
|
|
701
|
-
* Causes performance issues with domains that are extracted from data.
|
|
702
|
-
*
|
|
703
|
-
* @param {import("../view/view.js").default | import("../view/view.js").default[]} fromViews
|
|
704
|
-
* @param {(view: import("../view/view.js").default) => boolean} [viewFilter]
|
|
705
|
-
*/
|
|
706
|
-
export function reconfigureScaleDomains(fromViews, viewFilter) {
|
|
707
|
-
/** @type {Set<ScaleResolution>} */
|
|
708
|
-
const uniqueResolutions = new Set();
|
|
709
|
-
|
|
710
|
-
/** @param {import("../view/view.js").default} view */
|
|
711
|
-
function collectResolutions(view) {
|
|
712
|
-
for (const resolution of Object.values(view.resolutions.scale)) {
|
|
713
|
-
uniqueResolutions.add(resolution);
|
|
714
|
-
}
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
/** @type {import("../view/view.js").VisitorCallback} */
|
|
718
|
-
function collectVisibleResolutions(view) {
|
|
719
|
-
if (viewFilter && !viewFilter(view)) {
|
|
720
|
-
return VISIT_SKIP;
|
|
721
|
-
}
|
|
722
|
-
if (view.options.contributesToScaleDomain) {
|
|
723
|
-
collectResolutions(view);
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
for (const fromView of asArray(fromViews)) {
|
|
728
|
-
fromView.visit(collectVisibleResolutions);
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
uniqueResolutions.forEach((resolution) => resolution.reconfigureDomain());
|
|
732
|
-
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scaleResolution.test.d.ts","sourceRoot":"","sources":["../../../src/scales/scaleResolution.test.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"scaleResolution.test.d.ts","sourceRoot":"","sources":["../../../src/scales/scaleResolution.test.js"],"names":[],"mappings":"sBAWa,OAAO,oBAAoB,EAAE,OAAO"}
|
|
@@ -8,6 +8,27 @@ export function createSinglePointSelection(datum: import("../data/flowNode.js").
|
|
|
8
8
|
* @returns {import("../types/selectionTypes.js").MultiPointSelection}
|
|
9
9
|
*/
|
|
10
10
|
export function createMultiPointSelection(data?: import("../data/flowNode.js").Datum[]): import("../types/selectionTypes.js").MultiPointSelection;
|
|
11
|
+
/**
|
|
12
|
+
* Returns key tuples for a point selection.
|
|
13
|
+
*
|
|
14
|
+
* @param {import("../types/selectionTypes.js").SinglePointSelection | import("../types/selectionTypes.js").MultiPointSelection} selection
|
|
15
|
+
* @param {string[]} keyFields
|
|
16
|
+
* @returns {import("../spec/channel.js").Scalar[][] | undefined}
|
|
17
|
+
*/
|
|
18
|
+
export function getPointSelectionKeyTuples(selection: import("../types/selectionTypes.js").SinglePointSelection | import("../types/selectionTypes.js").MultiPointSelection, keyFields: string[]): import("../spec/channel.js").Scalar[][] | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Resolves key tuples to a point selection value object.
|
|
21
|
+
*
|
|
22
|
+
* @param {"single" | "multi"} type
|
|
23
|
+
* @param {string[]} keyFields
|
|
24
|
+
* @param {import("../spec/channel.js").Scalar[][]} keyTuples
|
|
25
|
+
* @param {(keyFields: string[], keyTuple: import("../spec/channel.js").Scalar[]) => import("../data/flowNode.js").Datum | undefined} resolveDatum
|
|
26
|
+
* @returns {{ selection: import("../types/selectionTypes.js").SinglePointSelection | import("../types/selectionTypes.js").MultiPointSelection, unresolved: import("../spec/channel.js").Scalar[][] } | undefined}
|
|
27
|
+
*/
|
|
28
|
+
export function resolvePointSelectionFromKeyTuples(type: "single" | "multi", keyFields: string[], keyTuples: import("../spec/channel.js").Scalar[][], resolveDatum: (keyFields: string[], keyTuple: import("../spec/channel.js").Scalar[]) => import("../data/flowNode.js").Datum | undefined): {
|
|
29
|
+
selection: import("../types/selectionTypes.js").SinglePointSelection | import("../types/selectionTypes.js").MultiPointSelection;
|
|
30
|
+
unresolved: import("../spec/channel.js").Scalar[][];
|
|
31
|
+
} | undefined;
|
|
11
32
|
/**
|
|
12
33
|
*
|
|
13
34
|
* @param {import("../spec/channel.js").ChannelWithScale[]} channels
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selection.d.ts","sourceRoot":"","sources":["../../../src/selection/selection.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"selection.d.ts","sourceRoot":"","sources":["../../../src/selection/selection.js"],"names":[],"mappings":"AAQA;;;GAGG;AACH,kDAHW,OAAO,qBAAqB,EAAE,KAAK,GACjC,OAAO,4BAA4B,EAAE,oBAAoB,CAQrE;AAED;;;GAGG;AACH,iDAHW,OAAO,qBAAqB,EAAE,KAAK,EAAE,GACnC,OAAO,4BAA4B,EAAE,mBAAmB,CAQpE;AAED;;;;;;GAMG;AACH,sDAJW,OAAO,4BAA4B,EAAE,oBAAoB,GAAG,OAAO,4BAA4B,EAAE,mBAAmB,aACpH,MAAM,EAAE,GACN,OAAO,oBAAoB,EAAE,MAAM,EAAE,EAAE,GAAG,SAAS,CA2B/D;AAED;;;;;;;;GAQG;AACH,yDANW,QAAQ,GAAG,OAAO,aAClB,MAAM,EAAE,aACR,OAAO,oBAAoB,EAAE,MAAM,EAAE,EAAE,gBACvC,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,OAAO,oBAAoB,EAAE,MAAM,EAAE,KAAK,OAAO,qBAAqB,EAAE,KAAK,GAAG,SAAS,GACvH;IAAE,SAAS,EAAE,OAAO,4BAA4B,EAAE,oBAAoB,GAAG,OAAO,4BAA4B,EAAE,mBAAmB,CAAC;IAAC,UAAU,EAAE,OAAO,oBAAoB,EAAE,MAAM,EAAE,EAAE,CAAA;CAAE,GAAG,SAAS,CAsChN;AAED;;;;GAIG;AACH,kDAHW,OAAO,oBAAoB,EAAE,gBAAgB,EAAE,GAC7C,OAAO,4BAA4B,EAAE,iBAAiB,CASlE;AAED;;;;;;;GAOG;AACH,qDAJW,OAAO,4BAA4B,EAAE,mBAAmB,2BACxD,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,QAAQ,GAAG,QAAQ,EAAE,QAAQ,CAAC,OAAO,qBAAqB,EAAE,KAAK,CAAC,CAAC,CAAC,GACzF,OAAO,4BAA4B,EAAE,mBAAmB,CA2BpE;AAED;;;;;GAKG;AACH,oDAHW,OAAO,sBAAsB,EAAE,qBAAqB,aACpD,OAAO,4BAA4B,EAAE,SAAS,UAgExD;AAED;;;GAGG;AACH,+CAHW,OAAO,4BAA4B,EAAE,SAAS,GAC5C,SAAS,IAAI,OAAO,4BAA4B,EAAE,iBAAiB,CAI/E;AAED;;;GAGG;AACH,kDAHW,OAAO,4BAA4B,EAAE,SAAS,GAC5C,SAAS,IAAI,OAAO,4BAA4B,EAAE,oBAAoB,CAIlF;AAED;;;GAGG;AACH,iDAHW,OAAO,4BAA4B,EAAE,SAAS,GAC5C,SAAS,IAAI,OAAO,4BAA4B,EAAE,mBAAmB,CAIjF;AAED;;;GAGG;AACH,gDAHW,OAAO,4BAA4B,EAAE,SAAS,GAC5C,SAAS,IAAI,OAAO,4BAA4B,EAAE,kBAAkB,CAIhF;AAED;;;GAGG;AACH,gDAHW,OAAO,sBAAsB,EAAE,qBAAqB,GAClD,OAAO,sBAAsB,EAAE,eAAe,CA4B1D;AAED;;;GAGG;AACH,+CAHW,OAAO,sBAAsB,EAAE,eAAe,GAC5C,MAAM,IAAI,OAAO,sBAAsB,EAAE,oBAAoB,CAIzE;AAED;;;;GAIG;AACH,kDAHW,OAAO,sBAAsB,EAAE,eAAe,GAC5C,MAAM,IAAI,OAAO,sBAAsB,EAAE,uBAAuB,CAI5E;AAED;;GAEG;AACH,qDAFW,OAAO,4BAA4B,EAAE,iBAAiB,WAMhE;AAED;;;;;GAKG;AACH,kDAHW,iBAAiB,SACjB,aAAa,WAUvB;AAED;;;GAGG;AACH,yCAHW,OAAO,sBAAsB,EAAE,eAAe,CAAC,IAAI,CAAC,GAClD,OAAO,sBAAsB,EAAE,WAAW,CAsBtD;gCAvCY,OAAO,4BAA4B,EAAE,iBAAiB;4BACtD,OAAO,CAAC,MAAM,CAAC,MAAM,iBAAiB,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC,CAAC"}
|
|
@@ -3,7 +3,8 @@ import {
|
|
|
3
3
|
getSecondaryChannel,
|
|
4
4
|
isPrimaryPositionalChannel,
|
|
5
5
|
} from "../encoder/encoder.js";
|
|
6
|
-
import { validateParameterName } from "../
|
|
6
|
+
import { validateParameterName } from "../paramRuntime/paramUtils.js";
|
|
7
|
+
import { field } from "../utils/field.js";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* @param {import("../data/flowNode.js").Datum} datum
|
|
@@ -29,6 +30,87 @@ export function createMultiPointSelection(data) {
|
|
|
29
30
|
};
|
|
30
31
|
}
|
|
31
32
|
|
|
33
|
+
/**
|
|
34
|
+
* Returns key tuples for a point selection.
|
|
35
|
+
*
|
|
36
|
+
* @param {import("../types/selectionTypes.js").SinglePointSelection | import("../types/selectionTypes.js").MultiPointSelection} selection
|
|
37
|
+
* @param {string[]} keyFields
|
|
38
|
+
* @returns {import("../spec/channel.js").Scalar[][] | undefined}
|
|
39
|
+
*/
|
|
40
|
+
export function getPointSelectionKeyTuples(selection, keyFields) {
|
|
41
|
+
if (!keyFields || keyFields.length === 0) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const accessors = keyFields.map((fieldName) => field(fieldName));
|
|
46
|
+
const toTuple = (
|
|
47
|
+
/** @type {import("../data/flowNode.js").Datum} */ datum
|
|
48
|
+
) => accessors.map((accessor) => accessor(datum));
|
|
49
|
+
|
|
50
|
+
if (isSinglePointSelection(selection)) {
|
|
51
|
+
if (!selection.datum) {
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return [toTuple(selection.datum)];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (isMultiPointSelection(selection)) {
|
|
59
|
+
return [...selection.data.values()].map(toTuple);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
throw new Error(
|
|
63
|
+
`Expected a point selection, got: ${JSON.stringify(selection)}`
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Resolves key tuples to a point selection value object.
|
|
69
|
+
*
|
|
70
|
+
* @param {"single" | "multi"} type
|
|
71
|
+
* @param {string[]} keyFields
|
|
72
|
+
* @param {import("../spec/channel.js").Scalar[][]} keyTuples
|
|
73
|
+
* @param {(keyFields: string[], keyTuple: import("../spec/channel.js").Scalar[]) => import("../data/flowNode.js").Datum | undefined} resolveDatum
|
|
74
|
+
* @returns {{ selection: import("../types/selectionTypes.js").SinglePointSelection | import("../types/selectionTypes.js").MultiPointSelection, unresolved: import("../spec/channel.js").Scalar[][] } | undefined}
|
|
75
|
+
*/
|
|
76
|
+
export function resolvePointSelectionFromKeyTuples(
|
|
77
|
+
type,
|
|
78
|
+
keyFields,
|
|
79
|
+
keyTuples,
|
|
80
|
+
resolveDatum
|
|
81
|
+
) {
|
|
82
|
+
if (!keyFields || keyFields.length === 0) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (type === "single" && keyTuples.length > 1) {
|
|
87
|
+
throw new Error(
|
|
88
|
+
"Single point selections expect at most one key tuple."
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** @type {import("../data/flowNode.js").Datum[]} */
|
|
93
|
+
const datums = [];
|
|
94
|
+
/** @type {import("../spec/channel.js").Scalar[][]} */
|
|
95
|
+
const unresolved = [];
|
|
96
|
+
|
|
97
|
+
for (const tuple of keyTuples) {
|
|
98
|
+
const datum = resolveDatum(keyFields, tuple);
|
|
99
|
+
if (datum) {
|
|
100
|
+
datums.push(datum);
|
|
101
|
+
} else {
|
|
102
|
+
unresolved.push(tuple);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const selection =
|
|
107
|
+
type === "single"
|
|
108
|
+
? createSinglePointSelection(datums[0] ?? null)
|
|
109
|
+
: createMultiPointSelection(datums);
|
|
110
|
+
|
|
111
|
+
return { selection, unresolved };
|
|
112
|
+
}
|
|
113
|
+
|
|
32
114
|
/**
|
|
33
115
|
*
|
|
34
116
|
* @param {import("../spec/channel.js").ChannelWithScale[]} channels
|
|
@@ -46,6 +46,7 @@ export type ChannelWithoutScale =
|
|
|
46
46
|
| "uniqueId"
|
|
47
47
|
| "search"
|
|
48
48
|
| "text"
|
|
49
|
+
| "key"
|
|
49
50
|
| "facetIndex"
|
|
50
51
|
| "semanticScore"
|
|
51
52
|
| "uniqueId"
|
|
@@ -121,9 +122,13 @@ export type TypedFieldDef<T extends Type = Type> = FieldDefBase &
|
|
|
121
122
|
TitleMixins &
|
|
122
123
|
TypeMixins<T>;
|
|
123
124
|
|
|
124
|
-
export type ScaleFieldDef<T extends Type> = TypedFieldDef<T> &
|
|
125
|
+
export type ScaleFieldDef<T extends Type> = TypedFieldDef<T> &
|
|
126
|
+
ScaleMixins &
|
|
127
|
+
DomainContributionMixins;
|
|
125
128
|
|
|
126
129
|
export type FieldDefWithoutScale = FieldDefBase & TitleMixins;
|
|
130
|
+
export type KeyDef = FieldDefWithoutScale | FieldDefWithoutScale[];
|
|
131
|
+
export type SearchDef = FieldDefWithoutScale | FieldDefWithoutScale[];
|
|
127
132
|
|
|
128
133
|
export interface ScaleMixins {
|
|
129
134
|
/**
|
|
@@ -145,15 +150,18 @@ export interface ScaleMixins {
|
|
|
145
150
|
* @internal
|
|
146
151
|
*/
|
|
147
152
|
resolutionChannel?: ChannelWithScale;
|
|
153
|
+
}
|
|
148
154
|
|
|
155
|
+
export interface DomainContributionMixins {
|
|
149
156
|
/**
|
|
150
|
-
* Whether the field or evaluated expr should be
|
|
157
|
+
* Whether the field or evaluated expr should be excluded from the scale's domain.
|
|
158
|
+
* Prefer the view-level `domainInert` when an entire subtree should be excluded.
|
|
151
159
|
*
|
|
152
|
-
* **Default value:** `
|
|
160
|
+
* **Default value:** `false`
|
|
153
161
|
*
|
|
154
162
|
* @internal
|
|
155
163
|
*/
|
|
156
|
-
|
|
164
|
+
domainInert?: boolean;
|
|
157
165
|
}
|
|
158
166
|
|
|
159
167
|
export interface ValueDefBase<V extends Value = Scalar> {
|
|
@@ -190,6 +198,7 @@ export type MarkPropFieldDef<T extends Type = Type> = ScaleFieldDef<T> &
|
|
|
190
198
|
export type MarkPropExprDef<T extends Type = Type> = ExprDef &
|
|
191
199
|
TypeMixins<T> &
|
|
192
200
|
ScaleMixins &
|
|
201
|
+
DomainContributionMixins &
|
|
193
202
|
TitleMixins;
|
|
194
203
|
|
|
195
204
|
export type MarkPropDatumDef<T extends Type> = LegendMixins &
|
|
@@ -279,16 +288,18 @@ export type MarkPropFieldOrDatumOrExprDef<T extends Type = Type> =
|
|
|
279
288
|
|
|
280
289
|
export type MarkPropDef<V extends Value, T extends Type = Type> =
|
|
281
290
|
| FieldOrDatumDefWithCondition<MarkPropFieldDef<T>, V>
|
|
282
|
-
| FieldOrDatumDefWithCondition<
|
|
291
|
+
| FieldOrDatumDefWithCondition<ScaleDatumDef, V>
|
|
283
292
|
| ValueDefWithCondition<V>;
|
|
284
293
|
|
|
285
294
|
export type ColorDef = MarkPropDef<string | null>;
|
|
286
295
|
|
|
287
|
-
export type SecondaryFieldDef = FieldDefBase &
|
|
296
|
+
export type SecondaryFieldDef = FieldDefBase &
|
|
297
|
+
TitleMixins &
|
|
298
|
+
DomainContributionMixins;
|
|
288
299
|
|
|
289
300
|
export type NumericValueDef = ValueDef<number>;
|
|
290
301
|
|
|
291
|
-
export type ScaleDatumDef = ScaleMixins & DatumDef;
|
|
302
|
+
export type ScaleDatumDef = ScaleMixins & DatumDef & DomainContributionMixins;
|
|
292
303
|
|
|
293
304
|
export type PositionDatumDefBase = ScaleDatumDef & TypeMixins<Type>;
|
|
294
305
|
|
|
@@ -299,7 +310,8 @@ export type PositionDatumDef = PositionDatumDefBase & PositionMixins;
|
|
|
299
310
|
export type PositionExprDef = ExprDef &
|
|
300
311
|
PositionMixins &
|
|
301
312
|
BandMixins &
|
|
302
|
-
TypeMixins<Type
|
|
313
|
+
TypeMixins<Type> &
|
|
314
|
+
DomainContributionMixins;
|
|
303
315
|
|
|
304
316
|
export type PositionValueDef = NumericValueDef;
|
|
305
317
|
|
|
@@ -344,7 +356,8 @@ export interface ChromPosDefBase extends BandMixins {
|
|
|
344
356
|
|
|
345
357
|
export type SecondaryChromPosDef = ChromPosDefBase &
|
|
346
358
|
TitleMixins &
|
|
347
|
-
PositionMixins
|
|
359
|
+
PositionMixins &
|
|
360
|
+
DomainContributionMixins;
|
|
348
361
|
|
|
349
362
|
export type ChromPosDef = SecondaryChromPosDef &
|
|
350
363
|
TypeMixins<"locus"> &
|
|
@@ -360,8 +373,8 @@ export type PositionDef =
|
|
|
360
373
|
export type Position2Def =
|
|
361
374
|
| (SecondaryFieldDef & BandMixins)
|
|
362
375
|
| SecondaryChromPosDef
|
|
363
|
-
| (
|
|
364
|
-
| (ExprDef & BandMixins)
|
|
376
|
+
| (ScaleDatumDef & BandMixins)
|
|
377
|
+
| (ExprDef & BandMixins & DomainContributionMixins)
|
|
365
378
|
| PositionValueDef;
|
|
366
379
|
|
|
367
380
|
export type NumericMarkPropDef = MarkPropDef<number>;
|
|
@@ -372,10 +385,15 @@ export interface StringFieldDef extends FieldDefWithoutScale, FormatMixins {}
|
|
|
372
385
|
|
|
373
386
|
export type TextDef = StringFieldDef | StringDatumDef | ExprDef; // TODO: Conditions
|
|
374
387
|
|
|
375
|
-
export type ChannelDef =
|
|
388
|
+
export type ChannelDef = Exclude<
|
|
389
|
+
Encoding[keyof Encoding],
|
|
390
|
+
FieldDefWithoutScale[]
|
|
391
|
+
>;
|
|
376
392
|
|
|
377
393
|
// TODO: Does this make sense?
|
|
378
|
-
export type ChannelDefWithScale = ScaleMixins &
|
|
394
|
+
export type ChannelDefWithScale = ScaleMixins &
|
|
395
|
+
TypeMixins<Type> &
|
|
396
|
+
DomainContributionMixins;
|
|
379
397
|
|
|
380
398
|
export interface XIndexDef {
|
|
381
399
|
/**
|
|
@@ -497,14 +515,33 @@ export interface Encoding {
|
|
|
497
515
|
*/
|
|
498
516
|
sample?: FieldDefWithoutScale;
|
|
499
517
|
|
|
518
|
+
/**
|
|
519
|
+
* One or more data fields that uniquely identify data objects for stable
|
|
520
|
+
* point selections and bookmarking across sessions. Unlike `uniqueId` (an
|
|
521
|
+
* implicit surrogate key), key fields must be stable in the source data.
|
|
522
|
+
*
|
|
523
|
+
* Use a single field definition for simple keys, or an array of field
|
|
524
|
+
* definitions for composite keys. For composite keys, field order is
|
|
525
|
+
* significant.
|
|
526
|
+
*/
|
|
527
|
+
key?: KeyDef;
|
|
528
|
+
|
|
500
529
|
/**
|
|
501
530
|
* For internal use
|
|
531
|
+
* @internal
|
|
502
532
|
*/
|
|
503
533
|
// TODO: proper type
|
|
504
534
|
uniqueId?: FieldDefWithoutScale;
|
|
505
535
|
|
|
506
|
-
|
|
507
|
-
|
|
536
|
+
/**
|
|
537
|
+
* One or more fields used by the App's location/search input to match
|
|
538
|
+
* data objects in this view.
|
|
539
|
+
*
|
|
540
|
+
* Use a single field definition for simple search, or an array for
|
|
541
|
+
* matching against multiple fields. A datum matches when any configured
|
|
542
|
+
* search field matches the entered term.
|
|
543
|
+
*/
|
|
544
|
+
search?: SearchDef;
|
|
508
545
|
|
|
509
546
|
/**
|
|
510
547
|
* For internal use
|