@genome-spy/core 0.78.0 → 0.79.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bundle/{browser-KWU9rWZT.js → browser-CETrb2cm.js} +53 -33
- package/dist/bundle/esm-BdLYkz-m.js +248 -0
- package/dist/bundle/esm-BwiDsqSb.js +1367 -0
- package/dist/bundle/esm-CDFd1cjk.js +441 -0
- package/dist/bundle/{esm-DVOHLB1e.js → esm-CTUHLDbv.js} +30 -30
- package/dist/bundle/{esm-NIYEaYkc.js → esm-Cx-EbkOj.js} +13 -13
- package/dist/bundle/esm-DlYGqi79.js +128 -0
- package/dist/bundle/{esm-BygJiwh0.js → esm-k9p3oHkt.js} +133 -158
- package/dist/bundle/{esm-CT3ygiMq.js → esm-zAZJQO6D.js} +226 -212
- package/dist/bundle/index.es.js +14879 -11656
- package/dist/bundle/index.js +119 -108
- package/dist/bundle/{parquetRead-DG_-F5j5.js → parquetRead-Cad1SOVV.js} +473 -399
- package/dist/schema.json +18940 -6914
- package/dist/src/config/axisConfig.d.ts +2 -2
- package/dist/src/config/axisConfig.d.ts.map +1 -1
- package/dist/src/config/axisConfig.js +28 -44
- package/dist/src/config/configLayers.d.ts +45 -0
- package/dist/src/config/configLayers.d.ts.map +1 -0
- package/dist/src/config/configLayers.js +110 -0
- package/dist/src/config/defaultConfig.d.ts.map +1 -1
- package/dist/src/config/defaultConfig.js +8 -1
- package/dist/src/config/defaults/legendDefaults.d.ts +14 -0
- package/dist/src/config/defaults/legendDefaults.d.ts.map +1 -0
- package/dist/src/config/defaults/legendDefaults.js +46 -0
- package/dist/src/config/defaults/titleDefaults.d.ts.map +1 -1
- package/dist/src/config/defaults/titleDefaults.js +26 -18
- package/dist/src/config/legendConfig.d.ts +11 -0
- package/dist/src/config/legendConfig.d.ts.map +1 -0
- package/dist/src/config/legendConfig.js +63 -0
- package/dist/src/config/styleUtils.d.ts +8 -2
- package/dist/src/config/styleUtils.d.ts.map +1 -1
- package/dist/src/config/styleUtils.js +25 -1
- package/dist/src/config/themes.d.ts.map +1 -1
- package/dist/src/config/themes.js +21 -2
- package/dist/src/config/titleConfig.d.ts.map +1 -1
- package/dist/src/config/titleConfig.js +2 -18
- package/dist/src/data/collector.d.ts.map +1 -1
- package/dist/src/data/collector.js +40 -18
- package/dist/src/data/flowInit.d.ts +6 -0
- package/dist/src/data/flowInit.d.ts.map +1 -1
- package/dist/src/data/flowInit.js +1 -1
- package/dist/src/data/flowNode.d.ts +32 -0
- package/dist/src/data/flowNode.d.ts.map +1 -1
- package/dist/src/data/flowNode.js +59 -0
- package/dist/src/data/sources/lazy/bamSource.d.ts +0 -1
- package/dist/src/data/sources/lazy/bamSource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/bamSource.js +39 -30
- package/dist/src/data/sources/lazy/bigBedSource.d.ts +0 -10
- package/dist/src/data/sources/lazy/bigBedSource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/bigBedSource.js +127 -62
- package/dist/src/data/sources/lazy/bigWigSource.d.ts +2 -2
- package/dist/src/data/sources/lazy/bigWigSource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/bigWigSource.js +234 -81
- package/dist/src/data/sources/lazy/gff3Source.d.ts +7 -3
- package/dist/src/data/sources/lazy/gff3Source.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/gff3Source.js +7 -8
- package/dist/src/data/sources/lazy/indexedFastaSource.d.ts +1 -1
- package/dist/src/data/sources/lazy/indexedFastaSource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/indexedFastaSource.js +28 -19
- package/dist/src/data/sources/lazy/legendEntriesSource.d.ts +24 -0
- package/dist/src/data/sources/lazy/legendEntriesSource.d.ts.map +1 -0
- package/dist/src/data/sources/lazy/legendEntriesSource.js +218 -0
- package/dist/src/data/sources/lazy/legendGradientSource.d.ts +30 -0
- package/dist/src/data/sources/lazy/legendGradientSource.d.ts.map +1 -0
- package/dist/src/data/sources/lazy/legendGradientSource.js +388 -0
- package/dist/src/data/sources/lazy/mockLazySource.d.ts +4 -1
- package/dist/src/data/sources/lazy/mockLazySource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/mockLazySource.js +49 -4
- package/dist/src/data/sources/lazy/registerCoreLazySources.js +2 -0
- package/dist/src/data/sources/lazy/singleAxisWindowedSource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/singleAxisWindowedSource.js +3 -4
- package/dist/src/data/sources/lazy/tabixSource.d.ts +9 -4
- package/dist/src/data/sources/lazy/tabixSource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/tabixSource.js +201 -70
- package/dist/src/data/sources/lazy/tabixTsvSource.d.ts +2 -3
- package/dist/src/data/sources/lazy/tabixTsvSource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/tabixTsvSource.js +14 -12
- package/dist/src/data/sources/lazy/vcfSource.d.ts +7 -3
- package/dist/src/data/sources/lazy/vcfSource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/vcfSource.js +7 -8
- package/dist/src/data/sources/urlDescriptor.d.ts +165 -0
- package/dist/src/data/sources/urlDescriptor.d.ts.map +1 -0
- package/dist/src/data/sources/urlDescriptor.js +473 -0
- package/dist/src/data/sources/urlDescriptorController.d.ts +25 -0
- package/dist/src/data/sources/urlDescriptorController.d.ts.map +1 -0
- package/dist/src/data/sources/urlDescriptorController.js +72 -0
- package/dist/src/data/sources/urlDescriptorState.d.ts +47 -0
- package/dist/src/data/sources/urlDescriptorState.d.ts.map +1 -0
- package/dist/src/data/sources/urlDescriptorState.js +129 -0
- package/dist/src/data/sources/urlSource.d.ts.map +1 -1
- package/dist/src/data/sources/urlSource.js +101 -61
- package/dist/src/data/transforms/packLegendLabels.d.ts +21 -0
- package/dist/src/data/transforms/packLegendLabels.d.ts.map +1 -0
- package/dist/src/data/transforms/packLegendLabels.js +189 -0
- package/dist/src/data/transforms/transformFactory.d.ts.map +1 -1
- package/dist/src/data/transforms/transformFactory.js +4 -0
- package/dist/src/data/transforms/truncateText.d.ts +27 -0
- package/dist/src/data/transforms/truncateText.d.ts.map +1 -0
- package/dist/src/data/transforms/truncateText.js +94 -0
- package/dist/src/debug/dataflowDebugSnapshot.d.ts +58 -0
- package/dist/src/debug/dataflowDebugSnapshot.d.ts.map +1 -0
- package/dist/src/debug/dataflowDebugSnapshot.js +159 -0
- package/dist/src/debug/markDebugSnapshot.d.ts +54 -0
- package/dist/src/debug/markDebugSnapshot.d.ts.map +1 -0
- package/dist/src/debug/markDebugSnapshot.js +100 -0
- package/dist/src/debug/paramDebugSnapshot.d.ts +53 -0
- package/dist/src/debug/paramDebugSnapshot.d.ts.map +1 -0
- package/dist/src/debug/paramDebugSnapshot.js +86 -0
- package/dist/src/debug/resolutionDebugSnapshot.d.ts +155 -0
- package/dist/src/debug/resolutionDebugSnapshot.d.ts.map +1 -0
- package/dist/src/debug/resolutionDebugSnapshot.js +291 -0
- package/dist/src/debug/valuePreview.d.ts +9 -0
- package/dist/src/debug/valuePreview.d.ts.map +1 -0
- package/dist/src/debug/valuePreview.js +57 -0
- package/dist/src/debug/viewDebugSnapshot.d.ts +131 -0
- package/dist/src/debug/viewDebugSnapshot.d.ts.map +1 -0
- package/dist/src/debug/viewDebugSnapshot.js +390 -0
- package/dist/src/embedFactory.d.ts.map +1 -1
- package/dist/src/embedFactory.js +6 -1
- package/dist/src/encoder/encoder.d.ts +2 -2
- package/dist/src/encoder/encoder.d.ts.map +1 -1
- package/dist/src/encoder/encoder.js +5 -4
- package/dist/src/fonts/bmFontManager.d.ts +1 -1
- package/dist/src/fonts/bmFontManager.d.ts.map +1 -1
- package/dist/src/fonts/bmFontManager.js +45 -10
- package/dist/src/fonts/textMetrics.d.ts +69 -0
- package/dist/src/fonts/textMetrics.d.ts.map +1 -0
- package/dist/src/fonts/textMetrics.js +73 -0
- package/dist/src/genomeSpy/headlessBootstrap.d.ts.map +1 -1
- package/dist/src/genomeSpy/headlessBootstrap.js +6 -0
- package/dist/src/genomeSpy/renderCoordinator.d.ts.map +1 -1
- package/dist/src/genomeSpy/renderCoordinator.js +25 -3
- package/dist/src/genomeSpy/viewDataInit.d.ts +14 -0
- package/dist/src/genomeSpy/viewDataInit.d.ts.map +1 -1
- package/dist/src/genomeSpy/viewDataInit.js +45 -8
- package/dist/src/genomeSpyBase.d.ts +6 -0
- package/dist/src/genomeSpyBase.d.ts.map +1 -1
- package/dist/src/genomeSpyBase.js +20 -3
- package/dist/src/gl/glslScaleGenerator.d.ts +17 -0
- package/dist/src/gl/glslScaleGenerator.d.ts.map +1 -1
- package/dist/src/gl/glslScaleGenerator.js +39 -2
- package/dist/src/gl/includes/common.glsl.js +1 -1
- package/dist/src/gl/vertexRangeIndex.d.ts.map +1 -1
- package/dist/src/gl/vertexRangeIndex.js +4 -2
- package/dist/src/gl/webGLHelper.d.ts +1 -1
- package/dist/src/gl/webGLHelper.d.ts.map +1 -1
- package/dist/src/gl/webGLHelper.js +13 -8
- package/dist/src/marks/__snapshots__/shaderSnapshot.test.js.snap +140 -3
- package/dist/src/marks/mark.d.ts +47 -4
- package/dist/src/marks/mark.d.ts.map +1 -1
- package/dist/src/marks/mark.js +158 -54
- package/dist/src/marks/point.d.ts.map +1 -1
- package/dist/src/marks/point.js +4 -0
- package/dist/src/marks/point.vertex.glsl.js +1 -1
- package/dist/src/marks/text.d.ts +1 -1
- package/dist/src/marks/text.d.ts.map +1 -1
- package/dist/src/marks/text.js +2 -7
- package/dist/src/marks/text.vertex.glsl.js +1 -1
- package/dist/src/paramRuntime/paramUtils.d.ts +43 -9
- package/dist/src/paramRuntime/paramUtils.d.ts.map +1 -1
- package/dist/src/paramRuntime/paramUtils.js +61 -1
- package/dist/src/paramRuntime/viewParamRuntime.d.ts +32 -0
- package/dist/src/paramRuntime/viewParamRuntime.d.ts.map +1 -1
- package/dist/src/paramRuntime/viewParamRuntime.js +63 -0
- package/dist/src/scales/axisResolution.d.ts +35 -0
- package/dist/src/scales/axisResolution.d.ts.map +1 -1
- package/dist/src/scales/axisResolution.js +115 -7
- package/dist/src/scales/legendResolution.d.ts +83 -0
- package/dist/src/scales/legendResolution.d.ts.map +1 -0
- package/dist/src/scales/legendResolution.js +461 -0
- package/dist/src/scales/scaleResolution.d.ts +36 -0
- package/dist/src/scales/scaleResolution.d.ts.map +1 -1
- package/dist/src/scales/scaleResolution.js +59 -0
- package/dist/src/scales/viewLevelGuideConfig.d.ts +53 -0
- package/dist/src/scales/viewLevelGuideConfig.d.ts.map +1 -0
- package/dist/src/scales/viewLevelGuideConfig.js +224 -0
- package/dist/src/scales/viewLevelScaleConfig.d.ts.map +1 -1
- package/dist/src/scales/viewLevelScaleConfig.js +13 -2
- package/dist/src/spec/axis.d.ts +109 -3
- package/dist/src/spec/channel.d.ts +23 -4
- package/dist/src/spec/config.d.ts +59 -4
- package/dist/src/spec/data.d.ts +177 -17
- package/dist/src/spec/legend.d.ts +246 -0
- package/dist/src/spec/mark.d.ts +16 -4
- package/dist/src/spec/title.d.ts +58 -1
- package/dist/src/spec/transform.d.ts +149 -0
- package/dist/src/spec/view.d.ts +39 -6
- package/dist/src/types/embedApi.d.ts +262 -6
- package/dist/src/types/rendering.d.ts +19 -3
- package/dist/src/types/viewContext.d.ts +18 -2
- package/dist/src/utils/arrayUtils.d.ts +11 -0
- package/dist/src/utils/arrayUtils.d.ts.map +1 -1
- package/dist/src/utils/arrayUtils.js +23 -0
- package/dist/src/utils/suspension.d.ts +17 -0
- package/dist/src/utils/suspension.d.ts.map +1 -0
- package/dist/src/utils/suspension.js +41 -0
- package/dist/src/view/axisGridView.d.ts.map +1 -1
- package/dist/src/view/axisGridView.js +1 -4
- package/dist/src/view/axisView.d.ts +18 -2
- package/dist/src/view/axisView.d.ts.map +1 -1
- package/dist/src/view/axisView.js +180 -75
- package/dist/src/view/concatView.d.ts +10 -2
- package/dist/src/view/concatView.d.ts.map +1 -1
- package/dist/src/view/concatView.js +46 -9
- package/dist/src/view/containerMutationHelper.d.ts +20 -1
- package/dist/src/view/containerMutationHelper.d.ts.map +1 -1
- package/dist/src/view/containerMutationHelper.js +196 -33
- package/dist/src/view/facetView.d.ts +1 -1
- package/dist/src/view/gridView/gridChild.d.ts +54 -4
- package/dist/src/view/gridView/gridChild.d.ts.map +1 -1
- package/dist/src/view/gridView/gridChild.js +301 -120
- package/dist/src/view/gridView/gridChildLegends.d.ts +57 -0
- package/dist/src/view/gridView/gridChildLegends.d.ts.map +1 -0
- package/dist/src/view/gridView/gridChildLegends.js +503 -0
- package/dist/src/view/gridView/gridView.d.ts +25 -0
- package/dist/src/view/gridView/gridView.d.ts.map +1 -1
- package/dist/src/view/gridView/gridView.js +490 -78
- package/dist/src/view/gridView/legendLayout.d.ts +30 -0
- package/dist/src/view/gridView/legendLayout.d.ts.map +1 -0
- package/dist/src/view/gridView/legendLayout.js +115 -0
- package/dist/src/view/gridView/scrollbar.d.ts.map +1 -1
- package/dist/src/view/gridView/scrollbar.js +1 -4
- package/dist/src/view/gridView/selectionRect.d.ts.map +1 -1
- package/dist/src/view/gridView/selectionRect.js +1 -4
- package/dist/src/view/gridView/separatorView.d.ts.map +1 -1
- package/dist/src/view/gridView/separatorView.js +1 -4
- package/dist/src/view/layerView.d.ts +9 -2
- package/dist/src/view/layerView.d.ts.map +1 -1
- package/dist/src/view/layerView.js +18 -1
- package/dist/src/view/layout/flexLayout.d.ts +20 -4
- package/dist/src/view/layout/flexLayout.d.ts.map +1 -1
- package/dist/src/view/layout/flexLayout.js +331 -31
- package/dist/src/view/layout/rectangle.d.ts +14 -0
- package/dist/src/view/layout/rectangle.d.ts.map +1 -1
- package/dist/src/view/layout/rectangle.js +40 -0
- package/dist/src/view/legend/legendEntries.d.ts +20 -0
- package/dist/src/view/legend/legendEntries.d.ts.map +1 -0
- package/dist/src/view/legend/legendEntries.js +21 -0
- package/dist/src/view/legendView.d.ts +137 -0
- package/dist/src/view/legendView.d.ts.map +1 -0
- package/dist/src/view/legendView.js +1654 -0
- package/dist/src/view/renderingContext/bufferedViewRenderingContext.d.ts.map +1 -1
- package/dist/src/view/renderingContext/bufferedViewRenderingContext.js +26 -4
- package/dist/src/view/renderingContext/clipOptions.d.ts +44 -0
- package/dist/src/view/renderingContext/clipOptions.d.ts.map +1 -0
- package/dist/src/view/renderingContext/clipOptions.js +140 -0
- package/dist/src/view/renderingContext/simpleViewRenderingContext.d.ts.map +1 -1
- package/dist/src/view/renderingContext/simpleViewRenderingContext.js +12 -1
- package/dist/src/view/resolutionPlanner.d.ts +2 -1
- package/dist/src/view/resolutionPlanner.d.ts.map +1 -1
- package/dist/src/view/resolutionPlanner.js +89 -25
- package/dist/src/view/testUtils.d.ts +4 -2
- package/dist/src/view/testUtils.d.ts.map +1 -1
- package/dist/src/view/testUtils.js +60 -7
- package/dist/src/view/titleView.d.ts +37 -0
- package/dist/src/view/titleView.d.ts.map +1 -0
- package/dist/src/view/titleView.js +584 -0
- package/dist/src/view/unitView.d.ts +3 -3
- package/dist/src/view/unitView.d.ts.map +1 -1
- package/dist/src/view/unitView.js +3 -2
- package/dist/src/view/view.d.ts +25 -24
- package/dist/src/view/view.d.ts.map +1 -1
- package/dist/src/view/view.js +126 -16
- package/dist/src/view/viewChrome.d.ts +33 -0
- package/dist/src/view/viewChrome.d.ts.map +1 -0
- package/dist/src/view/viewChrome.js +64 -0
- package/dist/src/view/viewFactory.d.ts +2 -5
- package/dist/src/view/viewFactory.d.ts.map +1 -1
- package/dist/src/view/viewFactory.js +1 -2
- package/dist/src/view/viewIdentityRegistry.d.ts +37 -0
- package/dist/src/view/viewIdentityRegistry.d.ts.map +1 -0
- package/dist/src/view/viewIdentityRegistry.js +71 -0
- package/dist/src/view/viewMutationAcidTestUtils.d.ts +112 -0
- package/dist/src/view/viewMutationAcidTestUtils.d.ts.map +1 -0
- package/dist/src/view/viewMutationAcidTestUtils.js +234 -0
- package/dist/src/view/viewMutationApi.d.ts +42 -0
- package/dist/src/view/viewMutationApi.d.ts.map +1 -0
- package/dist/src/view/viewMutationApi.js +811 -0
- package/dist/src/view/viewSelectors.d.ts +11 -9
- package/dist/src/view/viewSelectors.d.ts.map +1 -1
- package/dist/src/view/viewSelectors.js +28 -17
- package/package.json +4 -4
- package/dist/bundle/esm-CuMSzCHy.js +0 -298
- package/dist/bundle/esm-DAnOffpD.js +0 -1426
- package/dist/bundle/esm-DMXpJXM4.js +0 -369
- package/dist/bundle/esm-DNtC3H80.js +0 -121
- package/dist/src/view/title.d.ts +0 -13
- package/dist/src/view/title.d.ts.map +0 -1
- package/dist/src/view/title.js +0 -154
- /package/dist/bundle/{AbortablePromiseCache-3gHJdF3E.js → AbortablePromiseCache-BTmAcN-t.js} +0 -0
- /package/dist/bundle/{esm-CuVa5T98.js → esm-VvpZ9hsq.js} +0 -0
- /package/dist/bundle/{chunk-DmhlhrBa.js → rolldown-runtime-Dy4uBu1J.js} +0 -0
|
@@ -2,6 +2,8 @@ import { primaryPositionalChannels } from "../../encoder/encoder.js";
|
|
|
2
2
|
import {
|
|
3
3
|
FlexDimensions,
|
|
4
4
|
getLargestSize,
|
|
5
|
+
getSizeDefMaxPx,
|
|
6
|
+
getSizeDefMinPx,
|
|
5
7
|
mapToPixelCoords,
|
|
6
8
|
parseSizeDef,
|
|
7
9
|
ZERO_SIZEDEF,
|
|
@@ -9,7 +11,11 @@ import {
|
|
|
9
11
|
import Grid from "../layout/grid.js";
|
|
10
12
|
import Padding from "../layout/padding.js";
|
|
11
13
|
import Rectangle from "../layout/rectangle.js";
|
|
12
|
-
import AxisView, {
|
|
14
|
+
import AxisView, {
|
|
15
|
+
CHANNEL_ORIENTS,
|
|
16
|
+
ORIENT_CHANNELS,
|
|
17
|
+
getExternalAxisOverhang,
|
|
18
|
+
} from "../axisView.js";
|
|
13
19
|
import ContainerView from "../containerView.js";
|
|
14
20
|
import {
|
|
15
21
|
propagateInteraction,
|
|
@@ -20,9 +26,26 @@ import UnitView from "../unitView.js";
|
|
|
20
26
|
import { interactionToZoom } from "../zoom.js";
|
|
21
27
|
import GridChild from "./gridChild.js";
|
|
22
28
|
import KeyboardZoomController from "./keyboardZoomController.js";
|
|
29
|
+
import { renderLocalLegends } from "./legendLayout.js";
|
|
30
|
+
import {
|
|
31
|
+
addLegendView,
|
|
32
|
+
createGridChildLegend,
|
|
33
|
+
disposeLegendViews,
|
|
34
|
+
getLegendOverhang,
|
|
35
|
+
getOrderedLegendEntries,
|
|
36
|
+
iterateLegendViews,
|
|
37
|
+
isActiveLegendRegion,
|
|
38
|
+
} from "./gridChildLegends.js";
|
|
23
39
|
import SeparatorView, { resolveSeparatorProps } from "./separatorView.js";
|
|
24
40
|
import { getZoomableResolutions } from "./zoomNavigationUtils.js";
|
|
41
|
+
import { moveArrayItem } from "../../utils/arrayUtils.js";
|
|
25
42
|
import { isHConcatSpec, isVConcatSpec } from "../viewSpecGuards.js";
|
|
43
|
+
import {
|
|
44
|
+
clipCoords,
|
|
45
|
+
combineClipOptions,
|
|
46
|
+
createClipOptions,
|
|
47
|
+
normalizeClipOptions,
|
|
48
|
+
} from "../renderingContext/clipOptions.js";
|
|
26
49
|
|
|
27
50
|
// Secondary ordering within a z-index bucket for GridView-owned decorations.
|
|
28
51
|
// These are not z-indices themselves: actual layering is decided first by the
|
|
@@ -34,6 +57,7 @@ const DECORATION_ORDER = Object.freeze({
|
|
|
34
57
|
grid: 20,
|
|
35
58
|
backgroundStroke: 30,
|
|
36
59
|
axis: 40,
|
|
60
|
+
legend: 50,
|
|
37
61
|
selectionRect: 80,
|
|
38
62
|
scrollbar: 90,
|
|
39
63
|
title: 100,
|
|
@@ -44,6 +68,80 @@ const DECORATION_ORDER = Object.freeze({
|
|
|
44
68
|
// letting an explicit user zindex override the default.
|
|
45
69
|
const CLIPPED_DECORATION_ZINDEX = 10;
|
|
46
70
|
|
|
71
|
+
/**
|
|
72
|
+
* Legends are rendered as guide regions, not grid children. Their thickness is
|
|
73
|
+
* handled as overhang, but their parallel min/max constraints still affect the
|
|
74
|
+
* grid dimension that the parent concat sees.
|
|
75
|
+
*
|
|
76
|
+
* @param {import("./gridChildLegends.js").GridChildLegends} legends
|
|
77
|
+
* @returns {FlexDimensions}
|
|
78
|
+
*/
|
|
79
|
+
function getLegendParallelSizeConstraints(legends) {
|
|
80
|
+
/** @type {import("../layout/flexLayout.js").SizeDef[]} */
|
|
81
|
+
const widths = [];
|
|
82
|
+
/** @type {import("../layout/flexLayout.js").SizeDef[]} */
|
|
83
|
+
const heights = [];
|
|
84
|
+
|
|
85
|
+
for (const [orient, region] of Object.entries(legends)) {
|
|
86
|
+
if (!isActiveLegendRegion(region)) {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const size = region.legendView.getSize();
|
|
91
|
+
if (orient == "top" || orient == "bottom") {
|
|
92
|
+
widths.push(size.width);
|
|
93
|
+
} else {
|
|
94
|
+
// Side gradients can fill the available viewport height, but that
|
|
95
|
+
// available height must be determined by the real grid children and
|
|
96
|
+
// top/bottom chrome. Otherwise a shared right/left legend can make
|
|
97
|
+
// the grid grow to the browser height and then fill that height.
|
|
98
|
+
heights.push({ px: getSizeDefMinPx(size.height), grow: 0 });
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return new FlexDimensions(getLargestSize(widths), getLargestSize(heights));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Treat an explicit concat/grid size as preferred available space while still
|
|
107
|
+
* letting fixed children and guide chrome establish a larger minimum. This
|
|
108
|
+
* mirrors flexbox behavior more closely than treating the explicit size as a
|
|
109
|
+
* hard clipping bound.
|
|
110
|
+
*
|
|
111
|
+
* @param {import("../layout/flexLayout.js").SizeDef} preferred
|
|
112
|
+
* @param {import("../layout/flexLayout.js").SizeDef} content
|
|
113
|
+
* @returns {import("../layout/flexLayout.js").SizeDef}
|
|
114
|
+
*/
|
|
115
|
+
function combinePreferredAndContentSize(preferred, content) {
|
|
116
|
+
const preferredGrow = preferred.grow ?? 0;
|
|
117
|
+
const preferredPx = preferred.px ?? 0;
|
|
118
|
+
const minPx = Math.max(
|
|
119
|
+
getSizeDefMinPx(preferred),
|
|
120
|
+
getSizeDefMinPx(content)
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
if (!preferredGrow) {
|
|
124
|
+
return { px: Math.max(preferredPx, minPx), grow: 0 };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** @type {import("../layout/flexLayout.js").SizeDef} */
|
|
128
|
+
const size = {
|
|
129
|
+
px: Math.max(preferredPx, content.px ?? 0),
|
|
130
|
+
grow: preferredGrow,
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
if (minPx > (size.px ?? 0)) {
|
|
134
|
+
size.minPx = minPx;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const preferredMaxPx = getSizeDefMaxPx(preferred);
|
|
138
|
+
if (preferredMaxPx !== undefined && preferredMaxPx >= minPx) {
|
|
139
|
+
size.maxPx = preferredMaxPx;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return size;
|
|
143
|
+
}
|
|
144
|
+
|
|
47
145
|
/**
|
|
48
146
|
* Modeled after: https://vega.github.io/vega/docs/layout/
|
|
49
147
|
*
|
|
@@ -97,6 +195,9 @@ export default class GridView extends ContainerView {
|
|
|
97
195
|
*/
|
|
98
196
|
#sharedAxes = {};
|
|
99
197
|
|
|
198
|
+
/** @type {import("./gridChildLegends.js").GridChildLegends} */
|
|
199
|
+
#sharedLegends = {};
|
|
200
|
+
|
|
100
201
|
#childSerial = 0;
|
|
101
202
|
|
|
102
203
|
/** @type {Partial<Record<"horizontal" | "vertical", SeparatorView>>} */
|
|
@@ -223,6 +324,17 @@ export default class GridView extends ContainerView {
|
|
|
223
324
|
this.invalidateSizeCache();
|
|
224
325
|
}
|
|
225
326
|
|
|
327
|
+
/**
|
|
328
|
+
* Moves a child within the grid without disposing it.
|
|
329
|
+
*
|
|
330
|
+
* @param {number} fromIndex
|
|
331
|
+
* @param {number} index Destination index after temporarily removing the child.
|
|
332
|
+
*/
|
|
333
|
+
moveChildAt(fromIndex, index) {
|
|
334
|
+
moveArrayItem(this.#children, fromIndex, index);
|
|
335
|
+
this.invalidateSizeCache();
|
|
336
|
+
}
|
|
337
|
+
|
|
226
338
|
get #visibleChildren() {
|
|
227
339
|
return this.#children.filter((gridChild) =>
|
|
228
340
|
gridChild.view.isConfiguredVisible()
|
|
@@ -275,10 +387,25 @@ export default class GridView extends ContainerView {
|
|
|
275
387
|
* @protected
|
|
276
388
|
*/
|
|
277
389
|
async createAxes() {
|
|
390
|
+
await this.syncGuideViews();
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Recreates guide and chrome views that depend on the child hierarchy.
|
|
395
|
+
* Shared guides always depend on the whole container. Grid-child guides can
|
|
396
|
+
* be limited to newly inserted children during mutations.
|
|
397
|
+
*
|
|
398
|
+
* @param {{ gridChildren?: GridChild[] }} [options]
|
|
399
|
+
*/
|
|
400
|
+
async syncGuideViews(options = {}) {
|
|
401
|
+
const gridChildren = options.gridChildren ?? this.#children;
|
|
402
|
+
|
|
278
403
|
await this.syncSharedAxes();
|
|
404
|
+
await this.syncSharedLegends();
|
|
279
405
|
await Promise.all(
|
|
280
|
-
|
|
406
|
+
gridChildren.map((gridChild) => gridChild.createAxes())
|
|
281
407
|
);
|
|
408
|
+
this.invalidateSizeCache();
|
|
282
409
|
}
|
|
283
410
|
|
|
284
411
|
/**
|
|
@@ -325,6 +452,25 @@ export default class GridView extends ContainerView {
|
|
|
325
452
|
await Promise.all(promises);
|
|
326
453
|
}
|
|
327
454
|
|
|
455
|
+
/**
|
|
456
|
+
* Recreates shared legends based on current legend resolutions.
|
|
457
|
+
*
|
|
458
|
+
* Shared legends are GridView-owned for the same reason as shared axes:
|
|
459
|
+
* their placement is relative to the whole child grid, not any individual
|
|
460
|
+
* GridChild.
|
|
461
|
+
*/
|
|
462
|
+
async syncSharedLegends() {
|
|
463
|
+
disposeLegendViews(this.#sharedLegends);
|
|
464
|
+
this.#sharedLegends = {};
|
|
465
|
+
|
|
466
|
+
for (const { definition, resolution } of getOrderedLegendEntries([
|
|
467
|
+
this,
|
|
468
|
+
])) {
|
|
469
|
+
const legend = await createGridChildLegend(definition, this);
|
|
470
|
+
await addLegendView(this.#sharedLegends, legend, resolution);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
328
474
|
/**
|
|
329
475
|
* @returns {IterableIterator<View>}
|
|
330
476
|
*/
|
|
@@ -340,6 +486,8 @@ export default class GridView extends ContainerView {
|
|
|
340
486
|
for (const axisView of Object.values(this.#sharedAxes)) {
|
|
341
487
|
yield axisView;
|
|
342
488
|
}
|
|
489
|
+
|
|
490
|
+
yield* iterateLegendViews(this.#sharedLegends);
|
|
343
491
|
}
|
|
344
492
|
|
|
345
493
|
/**
|
|
@@ -367,17 +515,48 @@ export default class GridView extends ContainerView {
|
|
|
367
515
|
})
|
|
368
516
|
.reduce((a, b) => Math.max(a, b), 0);
|
|
369
517
|
|
|
518
|
+
/**
|
|
519
|
+
* @param {GridChild} child
|
|
520
|
+
* @returns {import("../layout/flexLayout.js").SizeDef}
|
|
521
|
+
*/
|
|
522
|
+
const getPlotSize = (child) => {
|
|
523
|
+
// External overhang is represented by axis/padding slots. The
|
|
524
|
+
// growable view slot should contain only the child's plot area.
|
|
525
|
+
const size = child.view.getViewportSize()[dim];
|
|
526
|
+
const overhang = child.view.getOverhang();
|
|
527
|
+
const overhangSize =
|
|
528
|
+
direction == "column" ? overhang.width : overhang.height;
|
|
529
|
+
|
|
530
|
+
const plotSize = {
|
|
531
|
+
px: Math.max((size.px ?? 0) - overhangSize, 0),
|
|
532
|
+
grow: size.grow,
|
|
533
|
+
minPx:
|
|
534
|
+
size.minPx === undefined
|
|
535
|
+
? undefined
|
|
536
|
+
: Math.max(size.minPx - overhangSize, 0),
|
|
537
|
+
maxPx:
|
|
538
|
+
size.maxPx === undefined
|
|
539
|
+
? undefined
|
|
540
|
+
: Math.max(size.maxPx - overhangSize, 0),
|
|
541
|
+
};
|
|
542
|
+
|
|
543
|
+
const legendSize = getLegendParallelSizeConstraints(child.legends);
|
|
544
|
+
// Side legends constrain row height, while top/bottom legends
|
|
545
|
+
// constrain column width. Their perpendicular size is overhang.
|
|
546
|
+
return getLargestSize([
|
|
547
|
+
plotSize,
|
|
548
|
+
direction == "column" ? legendSize.width : legendSize.height,
|
|
549
|
+
]);
|
|
550
|
+
};
|
|
551
|
+
|
|
370
552
|
return this._cache(`size/directionSizes/${direction}`, () =>
|
|
371
553
|
this.#grid[direction == "column" ? "colIndices" : "rowIndices"].map(
|
|
372
554
|
(col) => ({
|
|
373
555
|
axisBefore: getMaxAxisSize(col, 0),
|
|
374
556
|
axisAfter: getMaxAxisSize(col, 1),
|
|
375
557
|
view: getLargestSize(
|
|
376
|
-
col.map(
|
|
377
|
-
(rowIndex)
|
|
378
|
-
this.#visibleChildren[
|
|
379
|
-
rowIndex
|
|
380
|
-
].view.getViewportSize()[dim]
|
|
558
|
+
col.map((rowIndex) =>
|
|
559
|
+
getPlotSize(this.#visibleChildren[rowIndex])
|
|
381
560
|
)
|
|
382
561
|
),
|
|
383
562
|
})
|
|
@@ -448,12 +627,21 @@ export default class GridView extends ContainerView {
|
|
|
448
627
|
#getFlexSize(direction) {
|
|
449
628
|
let grow = 0;
|
|
450
629
|
let px = 0;
|
|
630
|
+
let minPx = 0;
|
|
631
|
+
let maxPx = 0;
|
|
632
|
+
let hasMaxPx = true;
|
|
451
633
|
|
|
452
634
|
const explicitSize =
|
|
453
635
|
direction == "row" ? this.spec.height : this.spec.width;
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
636
|
+
const preferredSize =
|
|
637
|
+
explicitSize || explicitSize === 0
|
|
638
|
+
? parseSizeDef(explicitSize)
|
|
639
|
+
: undefined;
|
|
640
|
+
const usePreferredAsViewSlot =
|
|
641
|
+
preferredSize &&
|
|
642
|
+
(direction == "column"
|
|
643
|
+
? this.#grid.colIndices.length == 1
|
|
644
|
+
: this.#grid.rowIndices.length == 1);
|
|
457
645
|
|
|
458
646
|
const sizes = this.#getSizes(direction);
|
|
459
647
|
|
|
@@ -461,6 +649,8 @@ export default class GridView extends ContainerView {
|
|
|
461
649
|
if (i > 0) {
|
|
462
650
|
// Spacing
|
|
463
651
|
px += this.#spacing;
|
|
652
|
+
minPx += this.#spacing;
|
|
653
|
+
maxPx += this.#spacing;
|
|
464
654
|
}
|
|
465
655
|
|
|
466
656
|
if (i == 0 || this.wrappingFacet) {
|
|
@@ -470,13 +660,28 @@ export default class GridView extends ContainerView {
|
|
|
470
660
|
|
|
471
661
|
// Axis/padding
|
|
472
662
|
px += size.axisBefore;
|
|
663
|
+
minPx += size.axisBefore;
|
|
664
|
+
maxPx += size.axisBefore;
|
|
473
665
|
|
|
474
666
|
// View
|
|
475
|
-
|
|
476
|
-
|
|
667
|
+
const viewSize = usePreferredAsViewSlot
|
|
668
|
+
? combinePreferredAndContentSize(preferredSize, size.view)
|
|
669
|
+
: size.view;
|
|
670
|
+
px += viewSize.px ?? 0;
|
|
671
|
+
grow += viewSize.grow ?? 0;
|
|
672
|
+
minPx += getSizeDefMinPx(viewSize);
|
|
673
|
+
|
|
674
|
+
const viewMaxPx = getSizeDefMaxPx(viewSize);
|
|
675
|
+
if (viewMaxPx === undefined) {
|
|
676
|
+
hasMaxPx = false;
|
|
677
|
+
} else {
|
|
678
|
+
maxPx += viewMaxPx;
|
|
679
|
+
}
|
|
477
680
|
|
|
478
681
|
// Axis/padding
|
|
479
682
|
px += size.axisAfter;
|
|
683
|
+
minPx += size.axisAfter;
|
|
684
|
+
maxPx += size.axisAfter;
|
|
480
685
|
|
|
481
686
|
if (i == sizes.length - 1 || this.wrappingFacet) {
|
|
482
687
|
//Footer
|
|
@@ -484,7 +689,16 @@ export default class GridView extends ContainerView {
|
|
|
484
689
|
}
|
|
485
690
|
}
|
|
486
691
|
|
|
487
|
-
|
|
692
|
+
const measuredSize = {
|
|
693
|
+
px,
|
|
694
|
+
grow,
|
|
695
|
+
minPx: minPx || undefined,
|
|
696
|
+
maxPx: sizes.length && hasMaxPx ? maxPx : undefined,
|
|
697
|
+
};
|
|
698
|
+
|
|
699
|
+
return preferredSize && !usePreferredAsViewSlot
|
|
700
|
+
? combinePreferredAndContentSize(preferredSize, measuredSize)
|
|
701
|
+
: measuredSize;
|
|
488
702
|
}
|
|
489
703
|
|
|
490
704
|
/**
|
|
@@ -505,7 +719,7 @@ export default class GridView extends ContainerView {
|
|
|
505
719
|
* @return {Padding}
|
|
506
720
|
*/
|
|
507
721
|
getOverhang() {
|
|
508
|
-
return this.#getGridOverhang().
|
|
722
|
+
return this.#getGridOverhang().add(this.#getSharedGuideOverhang());
|
|
509
723
|
}
|
|
510
724
|
|
|
511
725
|
#getGridOverhang() {
|
|
@@ -535,11 +749,7 @@ export default class GridView extends ContainerView {
|
|
|
535
749
|
return 0;
|
|
536
750
|
}
|
|
537
751
|
|
|
538
|
-
return
|
|
539
|
-
axisView.getPerpendicularSize() +
|
|
540
|
-
(axisView.axisProps.offset ?? 0),
|
|
541
|
-
0
|
|
542
|
-
);
|
|
752
|
+
return getExternalAxisOverhang(axisView);
|
|
543
753
|
};
|
|
544
754
|
|
|
545
755
|
return new Padding(
|
|
@@ -550,16 +760,58 @@ export default class GridView extends ContainerView {
|
|
|
550
760
|
);
|
|
551
761
|
}
|
|
552
762
|
|
|
763
|
+
#getSharedLegendOverhang() {
|
|
764
|
+
const getSharedLegendSize = (
|
|
765
|
+
/** @type {import("../../spec/legend.js").LegendOrient} */ orient
|
|
766
|
+
) => getLegendOverhang(this.#sharedLegends, orient);
|
|
767
|
+
|
|
768
|
+
return new Padding(
|
|
769
|
+
getSharedLegendSize("top"),
|
|
770
|
+
getSharedLegendSize("right"),
|
|
771
|
+
getSharedLegendSize("bottom"),
|
|
772
|
+
getSharedLegendSize("left")
|
|
773
|
+
);
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
#getSharedGuideOverhang() {
|
|
777
|
+
return this.#getSharedAxisOverhang().add(
|
|
778
|
+
this.#getSharedLegendOverhang()
|
|
779
|
+
);
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
#getSharedAxesByOrient() {
|
|
783
|
+
/** @type {Partial<Record<import("../../spec/axis.js").AxisOrient, AxisView>>} */
|
|
784
|
+
const axes = {};
|
|
785
|
+
for (const axisView of Object.values(this.#sharedAxes)) {
|
|
786
|
+
axes[axisView.axisProps.orient] = axisView;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
return axes;
|
|
790
|
+
}
|
|
791
|
+
|
|
553
792
|
/**
|
|
554
793
|
* @returns {FlexDimensions}
|
|
555
794
|
*/
|
|
556
795
|
getSize() {
|
|
557
|
-
return this._cache("size", () =>
|
|
558
|
-
|
|
559
|
-
this.#
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
796
|
+
return this._cache("size", () => {
|
|
797
|
+
const parallelLegendSize = getLegendParallelSizeConstraints(
|
|
798
|
+
this.#sharedLegends
|
|
799
|
+
);
|
|
800
|
+
|
|
801
|
+
// Shared legends are placed around the whole grid, so combine their
|
|
802
|
+
// parallel constraints with the child-grid size before adding
|
|
803
|
+
// guide overhang.
|
|
804
|
+
return new FlexDimensions(
|
|
805
|
+
getLargestSize([
|
|
806
|
+
this.#getFlexSize("column"),
|
|
807
|
+
parallelLegendSize.width,
|
|
808
|
+
]),
|
|
809
|
+
getLargestSize([
|
|
810
|
+
this.#getFlexSize("row"),
|
|
811
|
+
parallelLegendSize.height,
|
|
812
|
+
])
|
|
813
|
+
).addPadding(this.#getSharedGuideOverhang());
|
|
814
|
+
});
|
|
563
815
|
}
|
|
564
816
|
|
|
565
817
|
/**
|
|
@@ -578,7 +830,8 @@ export default class GridView extends ContainerView {
|
|
|
578
830
|
// Usually padding is applied by the parent GridView, but if this is the root view, we need to apply it here
|
|
579
831
|
coords = coords.shrink(this.getPadding());
|
|
580
832
|
}
|
|
581
|
-
|
|
833
|
+
const sharedGuideOverhang = this.#getSharedGuideOverhang();
|
|
834
|
+
coords = coords.shrink(sharedGuideOverhang);
|
|
582
835
|
|
|
583
836
|
context.pushView(this, coords);
|
|
584
837
|
|
|
@@ -587,7 +840,7 @@ export default class GridView extends ContainerView {
|
|
|
587
840
|
const flexOpts = {
|
|
588
841
|
devicePixelRatio,
|
|
589
842
|
};
|
|
590
|
-
|
|
843
|
+
let columnFlexCoords = mapToPixelCoords(
|
|
591
844
|
this.#makeFlexItems("column"),
|
|
592
845
|
coords.width,
|
|
593
846
|
flexOpts
|
|
@@ -604,6 +857,33 @@ export default class GridView extends ContainerView {
|
|
|
604
857
|
this.#columns ?? Infinity
|
|
605
858
|
);
|
|
606
859
|
|
|
860
|
+
let columnLayoutDirty = false;
|
|
861
|
+
for (const [i, gridChild] of this.#visibleChildren.entries()) {
|
|
862
|
+
const [col, row] = grid.getCellCoords(i);
|
|
863
|
+
const colLocSize =
|
|
864
|
+
columnFlexCoords[this.#getViewSlot("column", col)];
|
|
865
|
+
const rowLocSize = rowFlexCoords[this.#getViewSlot("row", row)];
|
|
866
|
+
|
|
867
|
+
// Some child views have side overhang that depends on the final
|
|
868
|
+
// row height, such as SampleView's repeated y-axis threshold. Row
|
|
869
|
+
// slots are known here, but final columns may need one more pass if
|
|
870
|
+
// a child reports that its height-dependent overhang changed.
|
|
871
|
+
const layoutChanged =
|
|
872
|
+
/** @type {{ prepareLayoutSize?: (width: number, height: number) => boolean }} */ (
|
|
873
|
+
gridChild.view
|
|
874
|
+
).prepareLayoutSize?.(colLocSize.size, rowLocSize.size);
|
|
875
|
+
columnLayoutDirty ||= layoutChanged === true;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
if (columnLayoutDirty) {
|
|
879
|
+
this._invalidateCacheByPrefix("size/directionSizes/column");
|
|
880
|
+
columnFlexCoords = mapToPixelCoords(
|
|
881
|
+
this.#makeFlexItems("column"),
|
|
882
|
+
coords.width,
|
|
883
|
+
flexOpts
|
|
884
|
+
);
|
|
885
|
+
}
|
|
886
|
+
|
|
607
887
|
/** @param {number} x */
|
|
608
888
|
const round = (x) =>
|
|
609
889
|
Math.round(x * devicePixelRatio) / devicePixelRatio;
|
|
@@ -641,16 +921,36 @@ export default class GridView extends ContainerView {
|
|
|
641
921
|
/**
|
|
642
922
|
* @param {FlexDimensions} size
|
|
643
923
|
* @param {"width" | "height"} dimension
|
|
924
|
+
* @param {boolean} explicitViewport
|
|
644
925
|
*/
|
|
645
|
-
const getLen = (size, dimension) =>
|
|
646
|
-
|
|
647
|
-
?
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
const
|
|
926
|
+
const getLen = (size, dimension, explicitViewport = false) =>
|
|
927
|
+
explicitViewport
|
|
928
|
+
? size[dimension].grow
|
|
929
|
+
? (dimension == "width" ? colLocSize : rowLocSize).size
|
|
930
|
+
: size[dimension].px
|
|
931
|
+
: (dimension == "width" ? colLocSize : rowLocSize).size +
|
|
932
|
+
overhang[dimension];
|
|
933
|
+
|
|
934
|
+
const viewportWidth = getLen(
|
|
935
|
+
viewportSize,
|
|
936
|
+
"width",
|
|
937
|
+
view.spec.viewportWidth != null
|
|
938
|
+
);
|
|
939
|
+
const viewportHeight = getLen(
|
|
940
|
+
viewportSize,
|
|
941
|
+
"height",
|
|
942
|
+
view.spec.viewportHeight != null
|
|
943
|
+
);
|
|
944
|
+
const viewWidth = getLen(
|
|
945
|
+
viewSize,
|
|
946
|
+
"width",
|
|
947
|
+
view.spec.viewportWidth != null
|
|
948
|
+
);
|
|
949
|
+
const viewHeight = getLen(
|
|
950
|
+
viewSize,
|
|
951
|
+
"height",
|
|
952
|
+
view.spec.viewportHeight != null
|
|
953
|
+
);
|
|
654
954
|
|
|
655
955
|
const hScrollbar = gridChild.scrollbars.horizontal;
|
|
656
956
|
const vScrollbar = gridChild.scrollbars.vertical;
|
|
@@ -684,9 +984,8 @@ export default class GridView extends ContainerView {
|
|
|
684
984
|
|
|
685
985
|
gridChild.coords = viewportCoords;
|
|
686
986
|
|
|
687
|
-
const
|
|
688
|
-
|
|
689
|
-
: viewportCoords;
|
|
987
|
+
const parentClip = normalizeClipOptions(options);
|
|
988
|
+
const visibleChildCoords = clipCoords(viewportCoords, parentClip);
|
|
690
989
|
|
|
691
990
|
renderItems.push({
|
|
692
991
|
col,
|
|
@@ -700,7 +999,8 @@ export default class GridView extends ContainerView {
|
|
|
700
999
|
selectionRect,
|
|
701
1000
|
viewportCoords,
|
|
702
1001
|
viewCoords,
|
|
703
|
-
|
|
1002
|
+
parentClip,
|
|
1003
|
+
visibleChildCoords,
|
|
704
1004
|
viewWidth,
|
|
705
1005
|
viewHeight,
|
|
706
1006
|
scrollable,
|
|
@@ -755,7 +1055,7 @@ export default class GridView extends ContainerView {
|
|
|
755
1055
|
() =>
|
|
756
1056
|
item.background?.render(
|
|
757
1057
|
context,
|
|
758
|
-
item.
|
|
1058
|
+
item.visibleChildCoords,
|
|
759
1059
|
{
|
|
760
1060
|
...options,
|
|
761
1061
|
clipRect: undefined,
|
|
@@ -809,7 +1109,8 @@ export default class GridView extends ContainerView {
|
|
|
809
1109
|
selectionRect,
|
|
810
1110
|
viewportCoords,
|
|
811
1111
|
viewCoords,
|
|
812
|
-
|
|
1112
|
+
parentClip,
|
|
1113
|
+
visibleChildCoords,
|
|
813
1114
|
viewWidth,
|
|
814
1115
|
viewHeight,
|
|
815
1116
|
scrollable,
|
|
@@ -818,7 +1119,9 @@ export default class GridView extends ContainerView {
|
|
|
818
1119
|
row,
|
|
819
1120
|
} = item;
|
|
820
1121
|
|
|
821
|
-
const
|
|
1122
|
+
const clippedChildren = isClippedChildren(view);
|
|
1123
|
+
const clipped = clippedChildren || scrollable;
|
|
1124
|
+
const clippedDecorations = hasClippedChildren(view) || scrollable;
|
|
822
1125
|
|
|
823
1126
|
for (const gridLineView of Object.values(gridLines)) {
|
|
824
1127
|
queueDecoration(
|
|
@@ -828,6 +1131,19 @@ export default class GridView extends ContainerView {
|
|
|
828
1131
|
);
|
|
829
1132
|
}
|
|
830
1133
|
|
|
1134
|
+
const childClip = clipped
|
|
1135
|
+
? combineClipOptions(
|
|
1136
|
+
parentClip,
|
|
1137
|
+
createClipOptions(
|
|
1138
|
+
visibleChildCoords,
|
|
1139
|
+
clippedChildren ||
|
|
1140
|
+
Boolean(gridChild.scrollbars.horizontal),
|
|
1141
|
+
clippedChildren ||
|
|
1142
|
+
Boolean(gridChild.scrollbars.vertical)
|
|
1143
|
+
)
|
|
1144
|
+
)
|
|
1145
|
+
: options.clip;
|
|
1146
|
+
|
|
831
1147
|
const renderContent = () =>
|
|
832
1148
|
view.render(
|
|
833
1149
|
context,
|
|
@@ -835,7 +1151,8 @@ export default class GridView extends ContainerView {
|
|
|
835
1151
|
clipped
|
|
836
1152
|
? {
|
|
837
1153
|
...options,
|
|
838
|
-
clipRect:
|
|
1154
|
+
clipRect: childClip?.rect,
|
|
1155
|
+
clip: childClip,
|
|
839
1156
|
}
|
|
840
1157
|
: options
|
|
841
1158
|
);
|
|
@@ -846,11 +1163,11 @@ export default class GridView extends ContainerView {
|
|
|
846
1163
|
queueDecoration(
|
|
847
1164
|
defaultBackgroundStrokeZindex(
|
|
848
1165
|
gridChild.backgroundStrokeZindex,
|
|
849
|
-
|
|
1166
|
+
clippedDecorations
|
|
850
1167
|
),
|
|
851
1168
|
DECORATION_ORDER.backgroundStroke,
|
|
852
1169
|
() =>
|
|
853
|
-
backgroundStroke?.render(context,
|
|
1170
|
+
backgroundStroke?.render(context, visibleChildCoords, {
|
|
854
1171
|
...options,
|
|
855
1172
|
clipRect: undefined,
|
|
856
1173
|
})
|
|
@@ -888,39 +1205,51 @@ export default class GridView extends ContainerView {
|
|
|
888
1205
|
axisView
|
|
889
1206
|
);
|
|
890
1207
|
|
|
891
|
-
let
|
|
1208
|
+
let clip = normalizeClipOptions(options);
|
|
1209
|
+
let clipRect = clip?.rect;
|
|
892
1210
|
|
|
893
1211
|
// Scrollable axes must be clipped along the scroll direction.
|
|
894
1212
|
if (scrollable) {
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
: undefined
|
|
1213
|
+
const axisClip = createClipOptions(
|
|
1214
|
+
viewportCoords,
|
|
1215
|
+
direction == "horizontal",
|
|
1216
|
+
direction == "vertical"
|
|
1217
|
+
);
|
|
1218
|
+
clip = combineClipOptions(clip, axisClip);
|
|
1219
|
+
clipRect = clip?.rect;
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
if (clip && axisView.labelClipPolicy === "anchor") {
|
|
1223
|
+
clip = createClipOptions(
|
|
1224
|
+
clip.rect,
|
|
1225
|
+
ORIENT_CHANNELS[orient] === "x",
|
|
1226
|
+
ORIENT_CHANNELS[orient] === "y"
|
|
910
1227
|
);
|
|
1228
|
+
clipRect = clip?.rect;
|
|
911
1229
|
}
|
|
912
1230
|
|
|
913
1231
|
queueDecoration(
|
|
914
|
-
defaultAxisZindex(axisView.axisProps
|
|
1232
|
+
defaultAxisZindex(axisView.axisProps, clippedDecorations),
|
|
915
1233
|
DECORATION_ORDER.axis,
|
|
916
1234
|
() =>
|
|
917
1235
|
axisView.render(context, translatedCoords, {
|
|
918
1236
|
...options,
|
|
919
1237
|
clipRect,
|
|
1238
|
+
clip,
|
|
920
1239
|
})
|
|
921
1240
|
);
|
|
922
1241
|
}
|
|
923
1242
|
|
|
1243
|
+
renderLocalLegends(
|
|
1244
|
+
gridChild.legends,
|
|
1245
|
+
this.#getLegendOffsetAxes(axes, col, row, grid),
|
|
1246
|
+
viewportCoords,
|
|
1247
|
+
context,
|
|
1248
|
+
options,
|
|
1249
|
+
queueDecoration,
|
|
1250
|
+
DECORATION_ORDER.legend
|
|
1251
|
+
);
|
|
1252
|
+
|
|
924
1253
|
// Axes shared between children
|
|
925
1254
|
// TODO: What if some have scrollable viewports?
|
|
926
1255
|
// Should throw an error because cannot have shared axes in such cases.
|
|
@@ -934,7 +1263,10 @@ export default class GridView extends ContainerView {
|
|
|
934
1263
|
(orient == "bottom" && row == grid.nRows - 1)
|
|
935
1264
|
) {
|
|
936
1265
|
queueDecoration(
|
|
937
|
-
defaultAxisZindex(
|
|
1266
|
+
defaultAxisZindex(
|
|
1267
|
+
axisView.axisProps,
|
|
1268
|
+
clippedDecorations
|
|
1269
|
+
),
|
|
938
1270
|
DECORATION_ORDER.axis,
|
|
939
1271
|
() =>
|
|
940
1272
|
axisView.render(
|
|
@@ -969,13 +1301,24 @@ export default class GridView extends ContainerView {
|
|
|
969
1301
|
|
|
970
1302
|
if (title) {
|
|
971
1303
|
queueDecoration(
|
|
972
|
-
gridChild.
|
|
1304
|
+
gridChild.getTitleZindex(),
|
|
973
1305
|
DECORATION_ORDER.title,
|
|
974
|
-
() =>
|
|
1306
|
+
() =>
|
|
1307
|
+
gridChild.renderTitle(context, viewportCoords, options)
|
|
975
1308
|
);
|
|
976
1309
|
}
|
|
977
1310
|
}
|
|
978
1311
|
|
|
1312
|
+
renderLocalLegends(
|
|
1313
|
+
this.#sharedLegends,
|
|
1314
|
+
this.#getSharedAxesByOrient(),
|
|
1315
|
+
coords,
|
|
1316
|
+
context,
|
|
1317
|
+
options,
|
|
1318
|
+
queueDecoration,
|
|
1319
|
+
DECORATION_ORDER.legend
|
|
1320
|
+
);
|
|
1321
|
+
|
|
979
1322
|
renderDecorations(underlays);
|
|
980
1323
|
|
|
981
1324
|
for (const renderContent of contents) {
|
|
@@ -987,6 +1330,38 @@ export default class GridView extends ContainerView {
|
|
|
987
1330
|
context.popView(this);
|
|
988
1331
|
}
|
|
989
1332
|
|
|
1333
|
+
/**
|
|
1334
|
+
* Local legends are GridChild-owned, but shared axes are GridView-owned.
|
|
1335
|
+
* When they share an orient, the axis should remain next to the plot and
|
|
1336
|
+
* the legend should move outside it. Give legend placement the applicable
|
|
1337
|
+
* shared edge axes so `renderLocalLegends()` can apply the same offset it
|
|
1338
|
+
* already uses for local axes.
|
|
1339
|
+
*
|
|
1340
|
+
* @param {Partial<Record<import("../../spec/axis.js").AxisOrient, AxisView>>} axes
|
|
1341
|
+
* @param {number} col
|
|
1342
|
+
* @param {number} row
|
|
1343
|
+
* @param {Grid} grid
|
|
1344
|
+
*/
|
|
1345
|
+
#getLegendOffsetAxes(axes, col, row, grid) {
|
|
1346
|
+
/** @type {Partial<Record<import("../../spec/axis.js").AxisOrient, AxisView>>} */
|
|
1347
|
+
const offsetAxes = { ...axes };
|
|
1348
|
+
|
|
1349
|
+
for (const axisView of Object.values(this.#sharedAxes)) {
|
|
1350
|
+
const orient = axisView.axisProps.orient;
|
|
1351
|
+
const isEdge =
|
|
1352
|
+
(orient == "left" && col == 0) ||
|
|
1353
|
+
(orient == "right" && col == grid.nCols - 1) ||
|
|
1354
|
+
(orient == "top" && row == 0) ||
|
|
1355
|
+
(orient == "bottom" && row == grid.nRows - 1);
|
|
1356
|
+
|
|
1357
|
+
if (isEdge && !offsetAxes[orient]) {
|
|
1358
|
+
offsetAxes[orient] = axisView;
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
return offsetAxes;
|
|
1363
|
+
}
|
|
1364
|
+
|
|
990
1365
|
/**
|
|
991
1366
|
* @param {import("../../utils/interaction.js").default} event
|
|
992
1367
|
*/
|
|
@@ -1302,6 +1677,22 @@ export function isClippedChildren(view) {
|
|
|
1302
1677
|
return clipped;
|
|
1303
1678
|
}
|
|
1304
1679
|
|
|
1680
|
+
/**
|
|
1681
|
+
* @param {View} view
|
|
1682
|
+
*/
|
|
1683
|
+
function hasClippedChildren(view) {
|
|
1684
|
+
let clipped = false;
|
|
1685
|
+
|
|
1686
|
+
view.visit((v) => {
|
|
1687
|
+
if (v instanceof UnitView) {
|
|
1688
|
+
const clip = v.mark.properties.clip;
|
|
1689
|
+
clipped ||= clip === true || clip === "x" || clip === "y";
|
|
1690
|
+
}
|
|
1691
|
+
});
|
|
1692
|
+
|
|
1693
|
+
return clipped;
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1305
1696
|
/**
|
|
1306
1697
|
* @param {View} view
|
|
1307
1698
|
* @returns {boolean}
|
|
@@ -1337,15 +1728,24 @@ function getSeparatorDirections(spec) {
|
|
|
1337
1728
|
}
|
|
1338
1729
|
|
|
1339
1730
|
/**
|
|
1340
|
-
* Default z-index for axes.
|
|
1731
|
+
* Default z-index for axes. Inside axes default to overlays because they share
|
|
1732
|
+
* plot space with marks. Clipped or scrollable outside axes get a higher
|
|
1341
1733
|
* default to keep guides above visible edge artifacts.
|
|
1342
1734
|
*
|
|
1343
|
-
* @param {
|
|
1735
|
+
* @param {import("../../spec/axis.js").Axis} axisProps
|
|
1344
1736
|
* @param {boolean} clipped
|
|
1345
1737
|
* @returns {number}
|
|
1346
1738
|
*/
|
|
1347
|
-
function defaultAxisZindex(
|
|
1348
|
-
|
|
1739
|
+
function defaultAxisZindex(axisProps, clipped) {
|
|
1740
|
+
if (axisProps.zindex !== undefined) {
|
|
1741
|
+
return axisProps.zindex;
|
|
1742
|
+
} else if (axisProps.placement === "inside") {
|
|
1743
|
+
return 1;
|
|
1744
|
+
} else if (clipped) {
|
|
1745
|
+
return CLIPPED_DECORATION_ZINDEX;
|
|
1746
|
+
} else {
|
|
1747
|
+
return 0;
|
|
1748
|
+
}
|
|
1349
1749
|
}
|
|
1350
1750
|
|
|
1351
1751
|
/**
|
|
@@ -1369,18 +1769,30 @@ function defaultBackgroundStrokeZindex(zindex, clipped) {
|
|
|
1369
1769
|
export function translateAxisCoords(coords, orient, axisView) {
|
|
1370
1770
|
const props = axisView.axisProps;
|
|
1371
1771
|
const ps = axisView.getPerpendicularSize();
|
|
1772
|
+
const inside = props.placement === "inside";
|
|
1773
|
+
const offset = props.offset ?? 0;
|
|
1372
1774
|
|
|
1373
1775
|
if (orient == "bottom") {
|
|
1374
|
-
return
|
|
1375
|
-
.translate(0, coords.height
|
|
1376
|
-
|
|
1776
|
+
return inside
|
|
1777
|
+
? coords.translate(0, coords.height - ps - offset).modify({
|
|
1778
|
+
height: ps,
|
|
1779
|
+
})
|
|
1780
|
+
: coords.translate(0, coords.height + offset).modify({
|
|
1781
|
+
height: ps,
|
|
1782
|
+
});
|
|
1377
1783
|
} else if (orient == "top") {
|
|
1378
|
-
return
|
|
1784
|
+
return inside
|
|
1785
|
+
? coords.translate(0, offset).modify({ height: ps })
|
|
1786
|
+
: coords.translate(0, -ps - offset).modify({ height: ps });
|
|
1379
1787
|
} else if (orient == "left") {
|
|
1380
|
-
return
|
|
1788
|
+
return inside
|
|
1789
|
+
? coords.translate(offset, 0).modify({ width: ps })
|
|
1790
|
+
: coords.translate(-ps - offset, 0).modify({ width: ps });
|
|
1381
1791
|
} else if (orient == "right") {
|
|
1382
|
-
return
|
|
1383
|
-
.translate(coords.width
|
|
1384
|
-
|
|
1792
|
+
return inside
|
|
1793
|
+
? coords.translate(coords.width - ps - offset, 0).modify({
|
|
1794
|
+
width: ps,
|
|
1795
|
+
})
|
|
1796
|
+
: coords.translate(coords.width + offset, 0).modify({ width: ps });
|
|
1385
1797
|
}
|
|
1386
1798
|
}
|