Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
"lucide-react": "^0.562.0",
"next": "^16.2.7",
"next-themes": "^0.4.6",
"proj4": "^2.20.9",
"radix-ui": "1.4.3",
"react": "^19.0.0",
"react-day-picker": "^9.14.0",
Expand Down
14 changes: 14 additions & 0 deletions src/GlobalStates/GlobalStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type StoreState = {
shape: THREE.Vector3;
valueScales: { maxVal: number; minVal: number };
colormap: THREE.DataTexture;
remapTexture: THREE.DataTexture | undefined;
colormapName: string;
flipColormap: boolean;
timeSeries: Record<string, Record<string, any>>;
Expand All @@ -31,6 +32,9 @@ type StoreState = {
dimNames: string[];
dimUnits: string[];
dimCoords: Record<string, DimCoords>;
axisDimArrays: number[][];
axisDimNames: string[];
axisDimUnits: string[];
plotDim: number;
flipY:boolean;
initStore:string;
Expand Down Expand Up @@ -69,6 +73,9 @@ type StoreState = {
setDimUnits: (dimUnits: string[]) => void;
setDimCoords: (dimCoords?: Record<string, DimCoords>) => void;
updateDimCoords: (newDims: Record<string, DimCoords>) => void;
setAxisDimArrays: (axisDimArrays: number[][]) => void;
setAxisDimNames: (axisDimNames: string[]) => void;
setAxisDimUnits: (axisDimUnits: string[]) => void;
setPlotDim: (plotDim: number) => void;
setFlipY: (flipY:boolean) => void;
setInitStore: (initStore:string) => void;
Expand Down Expand Up @@ -96,6 +103,7 @@ export const useGlobalStore = create<StoreState>((set, get) => ({
shape: new THREE.Vector3(2, 2, 2),
valueScales: { maxVal: 1, minVal: -1 },
colormap: GetColorMapTexture(),
remapTexture: undefined,
colormapName: "Spectral",
flipColormap: false,
timeSeries: {},
Expand All @@ -105,6 +113,9 @@ export const useGlobalStore = create<StoreState>((set, get) => ({
dimArrays: [[0], [0], [0]],
dimNames: ["Default"],
dimUnits: ["Default"],
axisDimArrays: [[0], [0], [0]],
axisDimNames: ["Default"],
axisDimUnits: ["Default"],
dimCoords: {},
plotDim: 0,
flipY: false,
Expand Down Expand Up @@ -164,6 +175,9 @@ export const useGlobalStore = create<StoreState>((set, get) => ({

set({ dimCoords: limitedDimCoords });
},
setAxisDimArrays: (axisDimArrays) => set({ axisDimArrays }),
setAxisDimNames: (axisDimNames) => set({ axisDimNames }),
setAxisDimUnits: (axisDimUnits) => set({ axisDimUnits }),
setPlotDim: (plotDim) => set({ plotDim }),
setFlipY: (flipY) => set({ flipY }),
setInitStore: (initStore) => set({ initStore }),
Expand Down
4 changes: 4 additions & 0 deletions src/GlobalStates/PlotStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ type PlotState ={
cameraPosition: THREE.Vector3;
disablePointScale: boolean;
camera: THREE.Camera | undefined;
nativeCRS: string | undefined;
destCRS: string | undefined;

setQuality: (quality: number) => void;
setTimeScale: (timeScale : number) =>void;
Expand Down Expand Up @@ -189,6 +191,8 @@ export const usePlotStore = create<PlotState>((set, get) => ({
cameraPosition: new THREE.Vector3(0, 0, 5),
disablePointScale: false,
camera: undefined,
nativeCRS: undefined,
destCRS: undefined,

setVTransferRange: (vTransferRange) => set({ vTransferRange }),
setVTransferScale: (vTransferScale) => set({ vTransferScale }),
Expand Down
10 changes: 10 additions & 0 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,16 @@
.no-spinner {
-moz-appearance: textfield; /* Firefox */
}

.no-scrollbar {
-ms-overflow-style: none; /* IE + Edge */
scrollbar-width: none; /* Firefox */
}

.no-scrollbar::-webkit-scrollbar {
display: none; /* Chrome, Safari */
}

}

/* Height fix for mobile browser UI */
Expand Down
8 changes: 6 additions & 2 deletions src/components/LandingHome.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { useGlobalStore } from '@/GlobalStates/GlobalStore';
import { useZarrStore } from '@/GlobalStates/ZarrStore';
import { useShallow } from 'zustand/shallow';
import { loadNetCDF, NETCDF_EXT_REGEX } from '@/utils/loadNetCDF';
import { usePlotStore } from '@/GlobalStates/PlotStore';

async function sendPing() {
const url = "https://www.bgc-jena.mpg.de/~jpoehls/browzarr/visitor_logger.php";
Expand Down Expand Up @@ -86,8 +87,11 @@ export function LandingHome() {
);
setCurrentStore(newStore);
// Clear after use
useZarrStore.getState().setIcechunkOptions(null);
useZarrStore.getState().setFetchOptions(null);
const {remapTexture} = useGlobalStore.getState();
if (remapTexture) remapTexture.dispose();
useZarrStore.setState({icechunkOptions: null, fetchOptions:null});
useGlobalStore.setState({remapTexture: undefined });
usePlotStore.setState({nativeCRS:undefined, destCRS:undefined});
}, [initStore, fetchKey, setCurrentStore, setUseNC, setZSlice, setYSlice, setXSlice, storeFromURL, setOpenVariables, setStoreFromURL]);

useEffect(() => {
Expand Down
77 changes: 37 additions & 40 deletions src/components/plots/AxisLines.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ const AXIS_CONSTANTS = {
};

const CubeAxis = ({flipX, flipY, flipDown}: {flipX: boolean, flipY: boolean, flipDown: boolean}) =>{
const {dimArrays, dimNames, dimUnits, dataShape, revY, is4D} = useGlobalStore(useShallow(state => ({
dimArrays: state.dimArrays,
dimNames: state.dimNames,
dimUnits: state.dimUnits,
const {axisDimArrays, axisDimNames, axisDimUnits, dataShape, revY, shape} = useGlobalStore(useShallow(state => ({
axisDimArrays: state.axisDimArrays,
axisDimNames: state.axisDimNames,
axisDimUnits: state.axisDimUnits,
dataShape: state.dataShape,
revY: state.flipY,
is4D: state.is4D
shape: state.shape
})))

const {xRange, yRange, zRange, plotType, timeScale, animProg, zSlice, ySlice, xSlice, coarsen} = usePlotStore(useShallow(state => ({
Expand All @@ -55,33 +55,31 @@ const CubeAxis = ({flipX, flipY, flipDown}: {flipX: boolean, flipY: boolean, fli
})))

const {xIdx, yIdx, zIdx} = useAxisIndices()

const dimSlices = useMemo(()=> {
let slices = [
dimArrays[zIdx]?.slice(zSlice[0], zSlice[1] ? zSlice[1] : undefined) ?? [],
revY ? dimArrays[yIdx]?.slice(ySlice[0], ySlice[1] ? ySlice[1] : undefined).reverse() ?? [] : dimArrays[yIdx]?.slice(ySlice[0], ySlice[1] ? ySlice[1] : undefined) ?? [],
dimArrays[xIdx]?.slice(xSlice[0], xSlice[1] ? xSlice[1] : undefined) ?? [],
axisDimArrays[zIdx]?.slice(zSlice[0], zSlice[1] ? zSlice[1] : undefined) ?? [],
revY ? axisDimArrays[yIdx]?.slice(ySlice[0], ySlice[1] ? ySlice[1] : undefined).reverse() ?? [] : axisDimArrays[yIdx]?.slice(ySlice[0], ySlice[1] ? ySlice[1] : undefined) ?? [],
Comment thread
TheJeran marked this conversation as resolved.
axisDimArrays[xIdx]?.slice(xSlice[0], xSlice[1] ? xSlice[1] : undefined) ?? [],
]
if (coarsen) {
const {kernelDepth, kernelSize} = useZarrStore.getState()
slices = slices.map((val, idx) => coarsenFlatArray(val, (idx === 0 ? kernelDepth : kernelSize)))
}
return slices
},[revY, dimArrays, zSlice, ySlice, xSlice, coarsen, xIdx, yIdx, zIdx])
},[revY, axisDimArrays, zSlice, ySlice, xSlice, coarsen, xIdx, yIdx, zIdx])

const dimLengths = dimSlices.map(val => val.length)

const [xResolution, setXResolution] = useState<number>(AXIS_CONSTANTS.INITIAL_RESOLUTION)
const [yResolution, setYResolution] = useState<number>(AXIS_CONSTANTS.INITIAL_RESOLUTION)
const [zResolution, setZResolution] = useState<number>(AXIS_CONSTANTS.INITIAL_RESOLUTION)


const isPC = useMemo(()=>plotType == 'point-cloud',[plotType])
const globalScale = isPC ? dataShape[2]/AXIS_CONSTANTS.PC_GLOBAL_SCALE_DIVISOR : 1

const depthRatio = useMemo(()=>dataShape[0]/dataShape[2]*timeScale,[dataShape, timeScale]);
const shapeRatio = useMemo(()=>dataShape[1]/dataShape[2], [dataShape])
const timeRatio = Math.max(dataShape[0]/dataShape[2], 2);
const depthRatio = useMemo(()=>shape.z/shape.x*timeScale,[shape, timeScale]);
const shapeRatio = useMemo(()=>shape.y/shape.x, [shape])
const timeRatio = Math.max(shape.z/shape.x, 2);

const secondaryColor = useCSSVariable('--text-plot') //replace with needed variable
const colorHex = useMemo(()=>{
Expand Down Expand Up @@ -116,9 +114,9 @@ const CubeAxis = ({flipX, flipY, flipDown}: {flipX: boolean, flipY: boolean, fli
const zDimScale = zResolution/(zResolution-1)
const zValDelta = 1/(zResolution-1)

const xTitleOffset = useMemo(() => ((dimNames[xIdx]?.length || 0) * AXIS_CONSTANTS.TITLE_FONT_SIZE_FACTOR / 2 + 0.1) * globalScale, [dimNames, globalScale, xIdx]);
const yTitleOffset = useMemo(() => ((dimNames[yIdx]?.length || 0) * AXIS_CONSTANTS.TITLE_FONT_SIZE_FACTOR / 2 + 0.1) * globalScale, [dimNames, globalScale, yIdx]);
const zTitleOffset = useMemo(() => ((dimNames[zIdx]?.length || 0) * AXIS_CONSTANTS.TITLE_FONT_SIZE_FACTOR / 2 + 0.1) * globalScale, [dimNames, globalScale, zIdx]);
const xTitleOffset = useMemo(() => ((axisDimNames[xIdx]?.length || 0) * AXIS_CONSTANTS.TITLE_FONT_SIZE_FACTOR / 2 + 0.1) * globalScale, [axisDimNames, globalScale, xIdx]);
const yTitleOffset = useMemo(() => ((axisDimNames[yIdx]?.length || 0) * AXIS_CONSTANTS.TITLE_FONT_SIZE_FACTOR / 2 + 0.1) * globalScale, [axisDimNames, globalScale, yIdx]);
const zTitleOffset = useMemo(() => ((axisDimNames[zIdx]?.length || 0) * AXIS_CONSTANTS.TITLE_FONT_SIZE_FACTOR / 2 + 0.1) * globalScale, [axisDimNames, globalScale, zIdx]);

return (
<group visible={plotType != 'sphere' && plotType != 'flat' && !hideAxis}>
Expand All @@ -142,7 +140,7 @@ const CubeAxis = ({flipX, flipY, flipDown}: {flipX: boolean, flipY: boolean, fli
material-depthTest={false}
rotation={[-Math.PI/2, 0, flipX ? Math.PI : 0]}
position={[0, 0, flipX ? -AXIS_CONSTANTS.TICK_LENGTH_FACTOR*globalScale : AXIS_CONSTANTS.TICK_LENGTH_FACTOR*globalScale]}
>{parseLoc(dimSlices[2]?.[Math.floor((dimLengths[2]-1)*idx*xValDelta)] || 0,dimUnits[xIdx])}</Text>
>{parseLoc(dimSlices[2]?.[Math.floor((dimLengths[2]-1)*idx*xValDelta)] || 0,axisDimUnits[xIdx])}</Text>
</group>
))}
<group rotation={[-Math.PI/2, 0, flipX ? Math.PI : 0]} position={[(xRange[0]+xRange[1])/2*globalScale, 0, flipX ? -AXIS_CONSTANTS.X_TITLE_OFFSET_FACTOR*globalScale : AXIS_CONSTANTS.X_TITLE_OFFSET_FACTOR*globalScale]}>
Expand All @@ -153,7 +151,7 @@ const CubeAxis = ({flipX, flipY, flipDown}: {flipX: boolean, flipY: boolean, fli
fontSize={AXIS_CONSTANTS.TITLE_FONT_SIZE_FACTOR*globalScale}
color={colorHex}
material-depthTest={false}
>{dimNames[xIdx]}</Text>
>{axisDimNames[xIdx]}</Text>
<group visible={!hideAxisControls}>
{xResolution < AXIS_CONSTANTS.MAX_RESOLUTION &&
<Text
Expand Down Expand Up @@ -206,7 +204,7 @@ const CubeAxis = ({flipX, flipY, flipDown}: {flipX: boolean, flipY: boolean, fli
material-depthTest={false}
rotation={[-Math.PI/2, 0, flipY ? Math.PI/2 : -Math.PI/2]}
position={[flipY ? AXIS_CONSTANTS.TICK_LENGTH_FACTOR*globalScale :-AXIS_CONSTANTS.TICK_LENGTH_FACTOR*globalScale, 0, 0]}
>{parseLoc(dimSlices[0]?.[(Math.floor((dimLengths[0]-1)*idx*zValDelta)+Math.floor(dimLengths[0]*animProg))%dimLengths[0]] || 0,dimUnits[zIdx])}</Text>
>{parseLoc(dimSlices[0]?.[(Math.floor((dimLengths[0]-1)*idx*zValDelta)+Math.floor(dimLengths[0]*animProg))%dimLengths[0]] || 0,axisDimUnits[zIdx])}</Text>
</group>
))}
<group rotation={[-Math.PI/2, 0, flipY ? Math.PI/2 : -Math.PI/2]} position={[flipY ? AXIS_CONSTANTS.Z_TITLE_OFFSET_FACTOR*globalScale : -AXIS_CONSTANTS.Z_TITLE_OFFSET_FACTOR*globalScale, 0, isPC ? (zRange[0]+zRange[1])/2*depthRatio*(globalScale) : (zRange[0]+zRange[1])/2]}>
Expand All @@ -217,7 +215,7 @@ const CubeAxis = ({flipX, flipY, flipDown}: {flipX: boolean, flipY: boolean, fli
fontSize={AXIS_CONSTANTS.TITLE_FONT_SIZE_FACTOR*globalScale}
color={colorHex}
material-depthTest={false}
>{dimNames[zIdx]}</Text>
>{axisDimNames[zIdx]}</Text>

<group visible={!hideAxisControls}>
{zResolution < AXIS_CONSTANTS.MAX_RESOLUTION &&
Expand Down Expand Up @@ -272,7 +270,7 @@ const CubeAxis = ({flipX, flipY, flipDown}: {flipX: boolean, flipY: boolean, fli
material-depthTest={false}
rotation={[0, flipX ? Math.PI : 0, 0]}
position={[flipY ? -0.07*globalScale : 0.07*globalScale, 0, 0]}
>{parseLoc(dimSlices[1]?.[Math.floor((dimLengths[1]-1)*idx*yValDelta)] || 0,dimUnits[yIdx])}</Text>
>{parseLoc(dimSlices[1]?.[Math.floor((dimLengths[1]-1)*idx*yValDelta)] || 0,axisDimUnits[yIdx])}</Text>
</group>
))}
<group rotation={[0, flipX ? Math.PI : 0 , 0]} position={[flipY ? -0.32*globalScale : 0.32*globalScale, (yRange[0]+yRange[1])/2*shapeRatio*globalScale, 0]}>
Expand All @@ -285,7 +283,7 @@ const CubeAxis = ({flipX, flipY, flipDown}: {flipX: boolean, flipY: boolean, fli
material-depthTest={false}
rotation={[0, 0, Math.PI / 2]}
>
{dimNames[yIdx]}
{axisDimNames[yIdx]}
</Text>

<group visible={!hideAxisControls}>
Expand Down Expand Up @@ -344,10 +342,10 @@ const FLAT_AXIS_CONSTANTS = {
};

const FlatAxis = () =>{
const {dimArrays, dimNames, dimUnits, flipY} = useGlobalStore(useShallow(state => ({
dimArrays: state.dimArrays,
dimNames: state.dimNames,
dimUnits: state.dimUnits,
const {axisDimArrays, axisDimNames, axisDimUnits, flipY} = useGlobalStore(useShallow(state => ({
axisDimArrays: state.axisDimArrays,
axisDimNames: state.axisDimNames,
axisDimUnits: state.axisDimUnits,
flipY: state.flipY,
})))

Expand All @@ -367,23 +365,23 @@ const FlatAxis = () =>{
axis: state.axis
})))

const originallyFlat = dimArrays.length == 2;
const originallyFlat = axisDimArrays.length == 2;
const slices = originallyFlat ? [ySlice, xSlice] : [zSlice, ySlice, xSlice]
const {xIdx, yIdx, zIdx} = useAxisIndices()

const dimSlices = useMemo(()=> {
return originallyFlat ?
[
flipY ? dimArrays[yIdx]?.slice().reverse() ?? [] : dimArrays[yIdx] ?? [],
dimArrays[xIdx] ?? []
flipY ? axisDimArrays[yIdx]?.slice().reverse() ?? [] : axisDimArrays[yIdx] ?? [],
axisDimArrays[xIdx] ?? []
]
:
[
dimArrays[zIdx]?.slice(zSlice[0], zSlice[1] ? zSlice[1] : undefined) ?? [],
flipY ? dimArrays[yIdx]?.slice(ySlice[0], ySlice[1] ? ySlice[1] : undefined).reverse() ?? [] : dimArrays[yIdx]?.slice(ySlice[0], ySlice[1] ? ySlice[1] : undefined) ?? [],
dimArrays[xIdx]?.slice(xSlice[0], xSlice[1] ? xSlice[1] : undefined) ?? [],
axisDimArrays[zIdx]?.slice(zSlice[0], zSlice[1] ? zSlice[1] : undefined) ?? [],
flipY ? axisDimArrays[yIdx]?.slice(ySlice[0], ySlice[1] ? ySlice[1] : undefined).reverse() ?? [] : axisDimArrays[yIdx]?.slice(ySlice[0], ySlice[1] ? ySlice[1] : undefined) ?? [],
axisDimArrays[xIdx]?.slice(xSlice[0], xSlice[1] ? xSlice[1] : undefined) ?? [],
]
},[dimArrays, flipY, originallyFlat, xSlice, ySlice, zSlice, xIdx, yIdx, zIdx])
},[axisDimArrays, flipY, originallyFlat, xSlice, ySlice, zSlice, xIdx, yIdx, zIdx])

const dimLengths = useMemo(()=>{
if (analysisMode && !originallyFlat){
Expand All @@ -406,13 +404,13 @@ const FlatAxis = () =>{
if (originallyFlat) {
return {
axisArrays: dimSlices,
axisUnits: [dimUnits[yIdx], dimUnits[xIdx]],
axisNames: [dimNames[yIdx], dimNames[xIdx]],
axisUnits: [axisDimUnits[yIdx], axisDimUnits[xIdx]],
axisNames: [axisDimNames[yIdx], axisDimNames[xIdx]],
};
}

const baseUnits = [dimUnits[zIdx], dimUnits[yIdx], dimUnits[xIdx]];
const baseNames = [dimNames[zIdx], dimNames[yIdx], dimNames[xIdx]];
const baseUnits = [axisDimUnits[zIdx], axisDimUnits[yIdx], axisDimUnits[xIdx]];
const baseNames = [axisDimNames[zIdx], axisDimNames[yIdx], axisDimNames[xIdx]];

if (analysisMode) {
return {
Expand All @@ -427,9 +425,8 @@ const FlatAxis = () =>{
axisNames: baseNames,
};
}
}, [analysisMode, dimArrays, dimUnits, dimNames, dimSlices, originallyFlat, axis, xIdx, yIdx, zIdx]);
}, [analysisMode, axisDimArrays, axisDimUnits, axisDimNames, dimSlices, originallyFlat, axis, xIdx, yIdx, zIdx]);


const shapeRatio = useMemo(()=>{
if(analysisMode && axis == 2){
return dimLengths[heightIdx]/dimLengths[widthIdx]
Expand Down
12 changes: 8 additions & 4 deletions src/components/plots/DataCube.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ interface DataCubeProps {

export const DataCube = ({ volTexture: propVolTexture }: DataCubeProps ) => {
const volTexture = usePaddedTextures(propVolTexture);
const {shape, colormap, flipY, textureArrayDepths} = useGlobalStore(useShallow(state=>({
const {shape, colormap, flipY, textureArrayDepths, remapTexture} = useGlobalStore(useShallow(state=>({
shape:state.shape,
colormap:state.colormap,
flipY:state.flipY,
textureArrayDepths: state.textureArrayDepths
textureArrayDepths: state.textureArrayDepths,
remapTexture: state.remapTexture
}))) //We have to useShallow when returning an object instead of a state. I don't fully know the logic yet
const {
valueRange, xRange, yRange, zRange, quality, useOrtho,
Expand Down Expand Up @@ -54,6 +55,7 @@ export const DataCube = ({ volTexture: propVolTexture }: DataCubeProps ) => {
maskValue: {value: maskValue },
textureDepths: {value: new THREE.Vector3(textureArrayDepths[2], textureArrayDepths[1], textureArrayDepths[0])},
cmap:{value: colormap},
remapTexture: { value: remapTexture},
cOffset:{value: cOffset},
cScale: {value: cScale},
threshold: {value: new THREE.Vector2(valueRange[0],valueRange[1])},
Expand All @@ -73,15 +75,17 @@ export const DataCube = ({ volTexture: propVolTexture }: DataCubeProps ) => {
},
defines: {
USE_VORIGIN: 1,
USE_VDIRECTION: 1
USE_VDIRECTION: 1,
REPROJECT: remapTexture ? true : false
},
vertexShader: useOrtho ? orthoVertex : vertexShader,
fragmentShader: useFragOpt ? fragOpt : fragmentShader,
transparent: true,
blending: THREE.NormalBlending,
depthWrite: false,
side: useOrtho ? THREE.FrontSide : THREE.BackSide,
}),[useFragOpt, useOrtho, volTexture]);
}),[useFragOpt, useOrtho, volTexture, remapTexture]);


const geometry = useMemo(() => new THREE.BoxGeometry(shape.x, shape.y, shape.z), [shape]);
useEffect(() => {
Expand Down
Loading
Loading