@biongff/vizarr 1.0.1 → 1.2.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.
Files changed (114) hide show
  1. package/dist/biongff-vizarr.cjs.js +1 -0
  2. package/dist/biongff-vizarr.es.js +7 -0
  3. package/dist/blosc-CeItQ6qj.cjs +17 -0
  4. package/dist/blosc-DaK8KnI4.js +719 -0
  5. package/dist/chunk-INHXZS53-DiyuLb3Z.js +14 -0
  6. package/dist/chunk-INHXZS53-z3BpFH8p.cjs +1 -0
  7. package/dist/deflate-BeJu5ryY.js +10 -0
  8. package/dist/deflate-Ctyqttht.cjs +1 -0
  9. package/dist/index-BR2zkK5Y.cjs +3811 -0
  10. package/dist/index-CU_d8468.js +49053 -0
  11. package/dist/index.d.ts +67 -0
  12. package/dist/jpeg-BWDIgcDK.js +533 -0
  13. package/dist/jpeg-Mp_UXZAJ.cjs +1 -0
  14. package/dist/jpeg2k-1tnzEScI.js +24 -0
  15. package/dist/jpeg2k-CcF6vCxI.cjs +1 -0
  16. package/dist/lerc-BJaDi7aO.js +1039 -0
  17. package/dist/lerc-D-6RihsZ.cjs +1 -0
  18. package/dist/lz4-CssV0LoA.js +643 -0
  19. package/dist/lz4-PFaIsPAh.cjs +15 -0
  20. package/dist/lzw-DBp1lk8U.js +84 -0
  21. package/dist/lzw-De76dcEC.cjs +1 -0
  22. package/dist/packbits-B6vt-6GN.cjs +1 -0
  23. package/dist/packbits-MT4dFhEA.js +24 -0
  24. package/dist/pako.esm-Bx5X36Wo.js +1074 -0
  25. package/dist/pako.esm-DZC2QrbJ.cjs +1 -0
  26. package/dist/raw-BF-NUDI1.js +9 -0
  27. package/dist/raw-vwCA5qWn.cjs +1 -0
  28. package/dist/ref-DAXKePD4.cjs +1 -0
  29. package/dist/ref-HqVJFnCG.js +196 -0
  30. package/dist/webimage-BQlxeHEQ.cjs +1 -0
  31. package/dist/webimage-DTyyK3Ev.js +19 -0
  32. package/dist/zstd-Cqadn9HA.js +610 -0
  33. package/dist/zstd-_xUhkGOV.cjs +15 -0
  34. package/package.json +25 -20
  35. package/.gitattributes +0 -1
  36. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -32
  37. package/.github/ISSUE_TEMPLATE/documentation_update.md +0 -16
  38. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -19
  39. package/.github/ISSUE_TEMPLATE/maintenance.md +0 -19
  40. package/.github/ISSUE_TEMPLATE/optimisation_request.md +0 -23
  41. package/.github/ISSUE_TEMPLATE/support_request.md +0 -25
  42. package/.github/PULL_REQUEST_TEMPLATE.md +0 -21
  43. package/.github/dependabot.yml +0 -13
  44. package/.github/workflows/deploy.yml +0 -56
  45. package/.github/workflows/npm-publish-dev.yml +0 -49
  46. package/.github/workflows/npm-publish.yml +0 -42
  47. package/.github/workflows/release.yml +0 -37
  48. package/.github/workflows/test.yml +0 -21
  49. package/.releaserc.json +0 -29
  50. package/CHANGELOG.md +0 -56
  51. package/CITATION.cff +0 -56
  52. package/CONTRIBUTING.md +0 -82
  53. package/README.md +0 -85
  54. package/assets/favicon.ico +0 -0
  55. package/assets/favicon.png +0 -0
  56. package/assets/logo-wide.png +0 -0
  57. package/assets/logo-wide.svg +0 -60
  58. package/assets/logo.png +0 -0
  59. package/assets/logo.svg +0 -36
  60. package/assets/robots.txt +0 -3
  61. package/assets/screenshot.png +0 -0
  62. package/biome.json +0 -34
  63. package/index.html +0 -24
  64. package/main.ts +0 -52
  65. package/patches/@vivjs__loaders@0.17.2.patch +0 -13
  66. package/python/.python-version +0 -1
  67. package/python/README.md +0 -14
  68. package/python/Untitled.ipynb +0 -40
  69. package/python/deno.json +0 -22
  70. package/python/notebooks/IDR_example.ipynb +0 -86
  71. package/python/notebooks/README.md +0 -35
  72. package/python/notebooks/create_fixture.py +0 -72
  73. package/python/notebooks/getting_started.ipynb +0 -217
  74. package/python/notebooks/mandelbrot.ipynb +0 -211
  75. package/python/notebooks/spatial_transformations.ipynb +0 -139
  76. package/python/pyproject.toml +0 -18
  77. package/python/src/vizarr/__init__.py +0 -10
  78. package/python/src/vizarr/_widget.js +0 -113
  79. package/python/src/vizarr/_widget.py +0 -67
  80. package/python/uv.lock +0 -2495
  81. package/src/ZarrPixelSource.ts +0 -182
  82. package/src/codecs/jpeg2k.ts +0 -22
  83. package/src/codecs/register.ts +0 -2
  84. package/src/components/LayerController/AcquisitionController.tsx +0 -46
  85. package/src/components/LayerController/AddChannelButton.tsx +0 -122
  86. package/src/components/LayerController/AxisOptions.tsx +0 -93
  87. package/src/components/LayerController/AxisSlider.tsx +0 -86
  88. package/src/components/LayerController/AxisSliders.tsx +0 -29
  89. package/src/components/LayerController/ChannelController.tsx +0 -84
  90. package/src/components/LayerController/ChannelOptions.tsx +0 -183
  91. package/src/components/LayerController/ColorPalette.tsx +0 -40
  92. package/src/components/LayerController/Content.tsx +0 -71
  93. package/src/components/LayerController/Header.tsx +0 -48
  94. package/src/components/LayerController/Labels.tsx +0 -73
  95. package/src/components/LayerController/LayerFitToViewportButton.tsx +0 -43
  96. package/src/components/LayerController/LayerVisibilityButton.tsx +0 -32
  97. package/src/components/LayerController/OpacitySlider.tsx +0 -25
  98. package/src/components/LayerController/index.tsx +0 -42
  99. package/src/components/Menu.tsx +0 -54
  100. package/src/components/Viewer.tsx +0 -136
  101. package/src/hooks.ts +0 -29
  102. package/src/index.tsx +0 -138
  103. package/src/io.ts +0 -276
  104. package/src/layers/grid-layer.ts +0 -214
  105. package/src/layers/label-layer.ts +0 -446
  106. package/src/layers/viv-layers.ts +0 -55
  107. package/src/lru-store.ts +0 -57
  108. package/src/ome.ts +0 -388
  109. package/src/state.ts +0 -202
  110. package/src/theme.ts +0 -80
  111. package/src/types.ts +0 -112
  112. package/src/utils.ts +0 -655
  113. package/tsconfig.json +0 -14
  114. package/vite.config.js +0 -47
@@ -1,183 +0,0 @@
1
- import { MoreHoriz, Remove } from "@mui/icons-material";
2
- import { Divider, IconButton, Input, NativeSelect, Paper, Popover, Typography } from "@mui/material";
3
- import { styled } from "@mui/material/styles";
4
- import React, { useState } from "react";
5
- import type { ChangeEvent, MouseEvent } from "react";
6
- import { useLayerState, useSourceData } from "../../hooks";
7
- import ColorPalette from "./ColorPalette";
8
-
9
- const DenseInput = styled(Input)`
10
- width: 5.5em;
11
- font-size: 0.7em;
12
- `;
13
-
14
- interface Props {
15
- channelIndex: number;
16
- }
17
-
18
- function ChannelOptions({ channelIndex }: Props) {
19
- const [sourceData] = useSourceData();
20
- const [layer, setLayer] = useLayerState();
21
- const [anchorEl, setAnchorEl] = useState<null | Element>(null);
22
- const { channel_axis, names } = sourceData;
23
-
24
- const handleClick = (event: MouseEvent<HTMLButtonElement>) => {
25
- setAnchorEl(event.currentTarget);
26
- };
27
-
28
- const handleClose = () => {
29
- setAnchorEl(null);
30
- };
31
-
32
- const handleColorChange = (rgb: [number, number, number]) => {
33
- setLayer((prev) => {
34
- const colors = [...prev.layerProps.colors];
35
- colors[channelIndex] = rgb;
36
- return { ...prev, layerProps: { ...prev.layerProps, colors } };
37
- });
38
- };
39
-
40
- const handleContrastLimitChange = (event: ChangeEvent<HTMLInputElement>) => {
41
- const targetId = event.target.id;
42
- let value = +event.target.value;
43
-
44
- // Only let positive values
45
- if (value < 0) value = 0;
46
-
47
- setLayer((prev) => {
48
- // Need to move sliders in if contrast limits are narrower
49
- const contrastLimitsRange = [...prev.layerProps.contrastLimitsRange];
50
- const contrastLimits = [...prev.layerProps.contrastLimits];
51
-
52
- const [cmin, cmax] = contrastLimitsRange[channelIndex];
53
- const [smin, smax] = contrastLimits[channelIndex];
54
-
55
- // Calculate climit update
56
- const [umin, umax] = targetId === "min" ? [value, cmax] : [cmin, value];
57
-
58
- // Update sliders if needed
59
- if (umin > smin) contrastLimits[channelIndex] = [umin, smax];
60
- if (umax < smax) contrastLimits[channelIndex] = [smin, umax];
61
-
62
- // Update channel constrast limits range
63
- contrastLimitsRange[channelIndex] = [umin, umax];
64
-
65
- return {
66
- ...prev,
67
- layerProps: { ...prev.layerProps, contrastLimits, contrastLimitsRange },
68
- };
69
- });
70
- };
71
-
72
- const handleRemove = () => {
73
- setLayer((prev) => {
74
- const { layerProps } = prev;
75
- const colors = [...layerProps.colors];
76
- const contrastLimits = [...layerProps.contrastLimits];
77
- const contrastLimitsRange = [...layerProps.contrastLimitsRange];
78
- const selections = [...layerProps.selections];
79
- const channelsVisible = [...layerProps.channelsVisible];
80
- colors.splice(channelIndex, 1);
81
- contrastLimits.splice(channelIndex, 1);
82
- contrastLimitsRange.splice(channelIndex, 1);
83
- selections.splice(channelIndex, 1);
84
- channelsVisible.splice(channelIndex, 1);
85
- return {
86
- ...prev,
87
- layerProps: {
88
- ...layerProps,
89
- colors,
90
- selections,
91
- channelsVisible,
92
- contrastLimits,
93
- contrastLimitsRange,
94
- },
95
- };
96
- });
97
- };
98
-
99
- const handleSelectionChange = (event: ChangeEvent<HTMLSelectElement>) => {
100
- setLayer((prev) => {
101
- const selections = [...prev.layerProps.selections];
102
- const channelSelection = [...selections[channelIndex]];
103
- if (Number.isInteger(channel_axis)) {
104
- channelSelection[channel_axis as number] = +event.target.value;
105
- selections[channelIndex] = channelSelection;
106
- }
107
- return { ...prev, layerProps: { ...prev.layerProps, selections } };
108
- });
109
- };
110
-
111
- const open = Boolean(anchorEl);
112
- const id = open ? `channel-${channelIndex}-${sourceData.name}-options` : undefined;
113
- const [min, max] = layer.layerProps.contrastLimitsRange[channelIndex];
114
-
115
- return (
116
- <>
117
- <IconButton
118
- onClick={handleClick}
119
- aria-describedby={id}
120
- style={{
121
- backgroundColor: "transparent",
122
- padding: 0,
123
- zIndex: 2,
124
- cursor: "pointer",
125
- }}
126
- >
127
- <MoreHoriz />
128
- </IconButton>
129
- <Popover
130
- id={id}
131
- open={open}
132
- anchorEl={anchorEl}
133
- onClose={handleClose}
134
- anchorOrigin={{
135
- vertical: "bottom",
136
- horizontal: "left",
137
- }}
138
- transformOrigin={{
139
- vertical: "top",
140
- horizontal: "left",
141
- }}
142
- >
143
- <Paper style={{ padding: "0px 4px", marginBottom: 4 }}>
144
- <div style={{ display: "flex", justifyContent: "space-between" }}>
145
- <Typography variant="caption">remove:</Typography>
146
- <IconButton onClick={handleRemove}>
147
- <Remove />
148
- </IconButton>
149
- </div>
150
- <Divider />
151
- <Typography variant="caption">selection:</Typography>
152
- <Divider />
153
- <NativeSelect
154
- fullWidth
155
- style={{ fontSize: "0.7em" }}
156
- id={`layer-${sourceData.name}-channel-select`}
157
- onChange={handleSelectionChange}
158
- value={layer.layerProps.selections[channelIndex][channel_axis as number]}
159
- >
160
- {names.map((name, i) => (
161
- <option value={i} key={name}>
162
- ({i}) {name}
163
- </option>
164
- ))}
165
- </NativeSelect>
166
- <Divider />
167
- <Typography variant="caption">contrast limits:</Typography>
168
- <Divider />
169
- <DenseInput value={min} onChange={handleContrastLimitChange} type="number" id="min" fullWidth={false} />
170
- <DenseInput value={max} onChange={handleContrastLimitChange} type="number" id="max" fullWidth={false} />
171
- <Divider />
172
- <Typography variant="caption">color:</Typography>
173
- <Divider />
174
- <div style={{ display: "flex", justifyContent: "center" }}>
175
- <ColorPalette handleChange={handleColorChange} />
176
- </div>
177
- </Paper>
178
- </Popover>
179
- </>
180
- );
181
- }
182
-
183
- export default ChannelOptions;
@@ -1,40 +0,0 @@
1
- import { Lens } from "@mui/icons-material";
2
- import { Container, IconButton } from "@mui/material";
3
- import React from "react";
4
- import { COLORS, hexToRGB } from "../../utils";
5
-
6
- const RGB_COLORS: [string, [number, number, number]][] = Object.entries(COLORS).map(([name, hex]) => [
7
- name,
8
- hexToRGB(hex),
9
- ]);
10
- function ColorPalette({
11
- handleChange,
12
- }: {
13
- handleChange: (c: [number, number, number]) => void;
14
- }) {
15
- return (
16
- <Container
17
- sx={{
18
- display: "flex",
19
- justifyContent: "space-between",
20
- alignItems: "center",
21
- padding: "2px",
22
- }}
23
- aria-label="color-swatch"
24
- >
25
- {RGB_COLORS.map(([name, rgb]) => {
26
- return (
27
- <IconButton
28
- sx={{ padding: "3px", width: "16px", height: "16px" }}
29
- key={name}
30
- onClick={() => handleChange(rgb)}
31
- >
32
- <Lens fontSize="small" style={{ color: `rgb(${rgb})` }} />
33
- </IconButton>
34
- );
35
- })}
36
- </Container>
37
- );
38
- }
39
-
40
- export default ColorPalette;
@@ -1,71 +0,0 @@
1
- import { AccordionDetails, Divider, Grid, Typography } from "@mui/material";
2
- import { styled } from "@mui/material/styles";
3
- import React from "react";
4
-
5
- import AcquisitionController from "./AcquisitionController";
6
- import AddChannelButton from "./AddChannelButton";
7
- import AxisSliders from "./AxisSliders";
8
- import ChannelController from "./ChannelController";
9
- import Labels from "./Labels";
10
- import OpacitySlider from "./OpacitySlider";
11
-
12
- import { useLayerState } from "../../hooks";
13
- import { range } from "../../utils";
14
-
15
- const Details = styled(AccordionDetails)`
16
- padding: 2px 5px;
17
- border-left: 1px solid rgba(150, 150, 150, .2);
18
- border-right: 1px solid rgba(150, 150, 150, .2);
19
- `;
20
-
21
- function Content() {
22
- const [layer] = useLayerState();
23
- const nChannels = layer.layerProps.selections.length;
24
- return (
25
- <Details>
26
- <Grid container direction="column">
27
- <AcquisitionController />
28
- <Grid>
29
- <Grid container justifyContent="space-between">
30
- <Grid size={{ xs: 3 }}>
31
- <Typography variant="caption">opacity:</Typography>
32
- </Grid>
33
- <Grid size={{ xs: 8 }}>
34
- <OpacitySlider />
35
- </Grid>
36
- </Grid>
37
- </Grid>
38
- <AxisSliders />
39
- <Grid container justifyContent="space-between">
40
- <Grid size={{ xs: 3 }}>
41
- <Typography variant="caption">channels:</Typography>
42
- </Grid>
43
- <Grid size={{ xs: 1 }}>
44
- <AddChannelButton />
45
- </Grid>
46
- </Grid>
47
- <Divider />
48
- <Grid>
49
- {range(nChannels).map((i) => (
50
- <ChannelController channelIndex={i} key={i} />
51
- ))}
52
- </Grid>
53
- {layer.labels?.length && (
54
- <>
55
- <Grid container justifyContent="space-between">
56
- <Typography variant="caption">labels:</Typography>
57
- </Grid>
58
- <Divider />
59
- <Grid>
60
- {layer.labels.map((label, i) => (
61
- <Labels labelIndex={i} key={label.layerProps.id} />
62
- ))}
63
- </Grid>
64
- </>
65
- )}
66
- </Grid>
67
- </Details>
68
- );
69
- }
70
-
71
- export default Content;
@@ -1,48 +0,0 @@
1
- import { AccordionSummary, Typography } from "@mui/material";
2
- import { styled } from "@mui/material/styles";
3
- import React from "react";
4
- import LayerVisibilityButton from "./LayerVisibilityButton";
5
-
6
- import { useSourceData } from "../../hooks";
7
- import { LayerFitToViewportButton } from "./LayerFitToViewportButton";
8
-
9
- const DenseAccordionSummary = styled(AccordionSummary)`
10
- border-bottom: 1px solid rgba(150, 150, 150, .125);
11
- background-color: rgba(150, 150, 150, 0.25);
12
- display: block;
13
- padding: 0 3px;
14
- height: 27px;
15
- min-height: 27px;
16
- overflow: hidden;
17
- transition: none;
18
-
19
- &.Mui-expanded {
20
- min-height: 27px;
21
- }
22
-
23
- .MuiAccordionSummary-content {
24
- margin: 0;
25
-
26
- &.Mui-expanded {
27
- margin: 0;
28
- }
29
- }
30
- `;
31
-
32
- function Header({ name }: { name: string }) {
33
- const [sourceData] = useSourceData();
34
- const label = `layer-controller-${sourceData.id}`;
35
- return (
36
- <DenseAccordionSummary aria-controls={label} id={label}>
37
- <div style={{ display: "flex", flexDirection: "row" }}>
38
- <LayerVisibilityButton />
39
- <LayerFitToViewportButton />
40
- <Typography style={{ marginTop: "4px", marginLeft: "5px" }} variant="body2">
41
- {name}
42
- </Typography>
43
- </div>
44
- </DenseAccordionSummary>
45
- );
46
- }
47
-
48
- export default Header;
@@ -1,73 +0,0 @@
1
- import { RadioButtonChecked, RadioButtonUnchecked } from "@mui/icons-material";
2
- import { Grid, IconButton, Slider, Typography } from "@mui/material";
3
- import React from "react";
4
-
5
- import { useLayerState, useSourceData } from "../../hooks";
6
- import { assert } from "../../utils";
7
-
8
- export default function Labels({ labelIndex }: { labelIndex: number }) {
9
- const [source] = useSourceData();
10
- const [layer, setLayer] = useLayerState();
11
- assert(source.labels && layer.kind === "multiscale" && layer.labels, "Missing image labels");
12
-
13
- const handleOpacityChange = (_: unknown, value: number | number[]) => {
14
- setLayer((prev) => {
15
- assert(prev.kind === "multiscale" && prev.labels, "Missing image labels");
16
- return {
17
- ...prev,
18
- labels: prev.labels.with(labelIndex, {
19
- ...prev.labels[labelIndex],
20
- layerProps: {
21
- ...prev.labels[labelIndex].layerProps,
22
- opacity: value as number,
23
- },
24
- }),
25
- };
26
- });
27
- };
28
-
29
- const { name } = source.labels[labelIndex];
30
- const label = layer.labels[labelIndex];
31
- return (
32
- <>
33
- <Grid container justifyContent="space-between" wrap="nowrap">
34
- <div style={{ width: 165, overflow: "hidden", textOverflow: "ellipsis" }}>
35
- <Typography variant="caption" noWrap>
36
- {name}
37
- </Typography>
38
- </div>
39
- </Grid>
40
- <Grid container justifyContent="space-between">
41
- <Grid size={{ xs: 2 }}>
42
- <IconButton
43
- style={{ backgroundColor: "transparent", padding: 0, zIndex: 2 }}
44
- onClick={() => {
45
- setLayer((prev) => {
46
- assert(prev.kind === "multiscale" && prev.labels, "Missing image labels");
47
- return {
48
- ...prev,
49
- labels: prev.labels.with(labelIndex, {
50
- ...prev.labels[labelIndex],
51
- on: !prev.labels[labelIndex].on,
52
- }),
53
- };
54
- });
55
- }}
56
- >
57
- {label.on ? <RadioButtonChecked /> : <RadioButtonUnchecked />}
58
- </IconButton>
59
- </Grid>
60
- <Grid size={{ xs: 10 }}>
61
- <Slider
62
- value={label.layerProps.opacity}
63
- onChange={handleOpacityChange}
64
- min={0}
65
- max={1}
66
- step={0.01}
67
- style={{ padding: "10px 0px 5px 0px" }}
68
- />
69
- </Grid>
70
- </Grid>
71
- </>
72
- );
73
- }
@@ -1,43 +0,0 @@
1
- import { ZoomOutMap } from "@mui/icons-material";
2
- import { IconButton } from "@mui/material";
3
- import { useAtomValue } from "jotai";
4
- import { useLayerState, useSourceData, useViewState } from "../../hooks";
5
- import { type VizarrLayer, viewportAtom } from "../../state";
6
- import { fitImageToViewport, getLayerSize } from "../../utils";
7
-
8
- export function LayerFitToViewportButton() {
9
- const [sourceData] = useSourceData();
10
- const [layer] = useLayerState();
11
- const [, setViewState] = useViewState();
12
- const viewport = useAtomValue(viewportAtom);
13
-
14
- const fitToViewport = (event: React.MouseEvent<HTMLButtonElement>) => {
15
- event.stopPropagation();
16
- if (viewport) {
17
- setViewState(() => ({
18
- ...fitImageToViewport({
19
- image: getLayerSize({ props: layer.layerProps } as VizarrLayer),
20
- viewport: viewport,
21
- padding: viewport.width < 400 ? 10 : viewport.width < 600 ? 30 : 50,
22
- matrix: layer.layerProps.modelMatrix,
23
- }),
24
- width: viewport.width,
25
- height: viewport.height,
26
- }));
27
- }
28
- };
29
-
30
- return (
31
- <IconButton
32
- component="span"
33
- aria-label={`fit-layer-to-viewport-${sourceData.id}`}
34
- onClick={fitToViewport}
35
- sx={{
36
- backgroundColor: "transparent",
37
- color: `rgb(255, 255, 255, ${layer.on ? 1 : 0.5})`,
38
- }}
39
- >
40
- <ZoomOutMap />
41
- </IconButton>
42
- );
43
- }
@@ -1,32 +0,0 @@
1
- import { Visibility, VisibilityOff } from "@mui/icons-material";
2
- import { IconButton } from "@mui/material";
3
- import React from "react";
4
- import type { MouseEvent } from "react";
5
- import { useLayerState, useSourceData } from "../../hooks";
6
-
7
- function LayerVisibilityButton() {
8
- const [sourceData] = useSourceData();
9
- const [layer, setLayer] = useLayerState();
10
- const toggle = (event: MouseEvent<HTMLButtonElement>) => {
11
- event.stopPropagation();
12
- setLayer((prev) => {
13
- const on = !prev.on;
14
- return { ...prev, on };
15
- });
16
- };
17
- return (
18
- <IconButton
19
- component="span"
20
- aria-label={`toggle-layer-visibility-${sourceData.id}`}
21
- onClick={toggle}
22
- sx={{
23
- backgroundColor: "transparent",
24
- color: `rgb(255, 255, 255, ${layer.on ? 1 : 0.5})`,
25
- }}
26
- >
27
- {layer.on ? <Visibility /> : <VisibilityOff />}
28
- </IconButton>
29
- );
30
- }
31
-
32
- export default LayerVisibilityButton;
@@ -1,25 +0,0 @@
1
- import { Slider } from "@mui/material";
2
- import { styled } from "@mui/material/styles";
3
- import React from "react";
4
- import type { ChangeEvent } from "react";
5
- import { useLayerState } from "../../hooks";
6
-
7
- const DenseSlider = styled(Slider)`
8
- color: white;
9
- padding: 10px 0px 5px 0px;
10
- margin-right: 5px;
11
- :active {
12
- box-shadow: 0px 0px 0px 8px rgba(158, 158, 158, 0.16);
13
- }
14
- `;
15
-
16
- function OpacitySlider() {
17
- const [layer, setLayer] = useLayerState();
18
- const handleChange = (_: Event, value: number | number[]) => {
19
- const opacity = value as number;
20
- setLayer((prev) => ({ ...prev, layerProps: { ...prev.layerProps, opacity } }));
21
- };
22
- return <DenseSlider value={layer.layerProps.opacity} onChange={handleChange} min={0} max={1} step={0.01} />;
23
- }
24
-
25
- export default OpacitySlider;
@@ -1,42 +0,0 @@
1
- import { Accordion as MuiAccordion } from "@mui/material";
2
- import { styled } from "@mui/material/styles";
3
- import React from "react";
4
-
5
- import { LayerStateContext, useSourceData } from "../../hooks";
6
- import { layerFamilyAtom } from "../../state";
7
- import Content from "./Content";
8
- import Header from "./Header";
9
-
10
- const Accordion = styled(MuiAccordion)`
11
- border-bottom: 1px solid rgba(150, 150, 150, .2);
12
- width: 200;
13
- box-shadow: none;
14
- "&:not(:last-child)": {
15
- border-bottom: 0,
16
- }
17
- "&:before": {
18
- display: none,
19
- }
20
- "&$expanded": {
21
- margin: 0,
22
- padding: 0,
23
- }
24
- &.Mui-expanded : {
25
- padding: 1,
26
- }
27
- `;
28
-
29
- function LayerController() {
30
- const [sourceInfo] = useSourceData();
31
- const layerAtom = layerFamilyAtom(sourceInfo);
32
- return (
33
- <LayerStateContext.Provider value={layerAtom}>
34
- <Accordion defaultExpanded>
35
- <Header name={sourceInfo.name ?? ""} />
36
- <Content />
37
- </Accordion>
38
- </LayerStateContext.Provider>
39
- );
40
- }
41
-
42
- export default LayerController;
@@ -1,54 +0,0 @@
1
- import { Add, Remove } from "@mui/icons-material";
2
- import { Box, Grid, IconButton } from "@mui/material";
3
- import { useAtomValue } from "jotai";
4
- import React, { useReducer } from "react";
5
-
6
- import { SourceDataContext } from "../hooks";
7
- import { sourceInfoAtomAtoms } from "../state";
8
- import LayerController from "./LayerController";
9
-
10
- function Menu(props: { open?: boolean }) {
11
- const sourceAtoms = useAtomValue(sourceInfoAtomAtoms);
12
- const [hidden, toggle] = useReducer((v) => !v, !(props.open ?? true));
13
- return (
14
- <Box
15
- sx={{
16
- zIndex: 1,
17
- position: "absolute",
18
- backgroundColor: "rgba(0, 0, 0, 0.7)",
19
- borderRadius: "5px",
20
- left: "5px",
21
- top: "5px",
22
- }}
23
- style={{ padding: `0px 5px ${hidden ? 0 : 5}px 5px` }}
24
- >
25
- <Grid container direction="column" alignItems="flex-start">
26
- <IconButton style={{ backgroundColor: "transparent", padding: 0 }} onClick={toggle}>
27
- {hidden ? <Add /> : <Remove />}
28
- </IconButton>
29
- <Box
30
- sx={{
31
- maxHeight: 500,
32
- overflowX: "hidden",
33
- overflowY: "scroll",
34
- "&::-webkit-scrollbar": {
35
- display: "none",
36
- background: "transparent",
37
- },
38
- scrollbarWidth: "none",
39
- flexDirection: "column",
40
- }}
41
- style={{ display: hidden ? "none" : "flex" }}
42
- >
43
- {sourceAtoms.map((sourceAtom) => (
44
- <SourceDataContext.Provider key={`${sourceAtom}`} value={sourceAtom}>
45
- <LayerController />
46
- </SourceDataContext.Provider>
47
- ))}
48
- </Box>
49
- </Grid>
50
- </Box>
51
- );
52
- }
53
-
54
- export default Menu;