Skip to content
Closed
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
4 changes: 4 additions & 0 deletions src/GlobalStates/GlobalStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type StoreState = {
initStore:string;
variable: string;
variables: string[];
openVariables: boolean;
plotOn: boolean;
isFlat: boolean;
status: string | null;
Expand Down Expand Up @@ -66,6 +67,7 @@ type StoreState = {
setInitStore: (initStore:string ) => void;
setVariable: (variable: string) => void;
setVariables: (variables: string[]) => void;
setOpenVariables: (openVariables: boolean) => void;
setPlotOn: (plotOn: boolean) => void;
setIsFlat: (isFlat: boolean) => void;
setProgress: (progress: number) => void;
Expand Down Expand Up @@ -98,6 +100,7 @@ export const useGlobalStore = create<StoreState>((set, get) => ({
initStore: ESDC,
variable: 'Default',
variables: [],
openVariables: false,
plotOn: false,
isFlat:false,
progress: 0,
Expand Down Expand Up @@ -150,6 +153,7 @@ export const useGlobalStore = create<StoreState>((set, get) => ({
setInitStore: (initStore) => set({ initStore }),
setVariable: (variable) => set({ variable }),
setVariables: (variables) => set({ variables }),
setOpenVariables: (openVariables) => set({ openVariables }),
setPlotOn: (plotOn) => set({ plotOn }),
setIsFlat: (isFlat) => set({ isFlat }),
setProgress: (progress) => set({ progress }),
Expand Down
48 changes: 29 additions & 19 deletions src/components/LandingHome.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,20 @@ import * as THREE from 'three'
THREE.Cache.enabled = true;
import { GetZarrMetadata, GetVariableNames, GetTitleDescription } from '@/components/zarr/GetMetadata';
import { GetStore } from '@/components/zarr/ZarrLoaderLRU';
import { useEffect, useMemo } from 'react';
import { useEffect } from 'react';
import { PlotArea, Plot, LandingShapes } from '@/components/plots';
import { MainPanel } from '@/components/ui';
import { Loading, Navbar, Error as ErrorComponent } from '@/components/ui';
import { useGlobalStore } from '@/GlobalStates/GlobalStore';
import { useZarrStore } from '@/GlobalStates/ZarrStore';
import { useShallow } from 'zustand/shallow';
import { loadNetCDF, NETCDF_EXT_REGEX } from '@/utils/loadNetCDF';

async function sendPing() {
const url = "https://www.bgc-jena.mpg.de/~jpoehls/browzarr/visitor_logger.php";

try {
const response = await fetch(url, {
method: "GET",
});

if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const response = await fetch(url, { method: "GET" });
if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`);
} catch (error) {
console.error("Request failed:", error);
}
Expand All @@ -30,9 +25,9 @@ async function sendPing() {
export function LandingHome() {
const {
initStore, timeSeries, variable, plotOn,
setZMeta, setVariables, setPlotOn, setTitleDescription,
setZMeta, setVariables, setPlotOn, setTitleDescription,
} = useGlobalStore(useShallow(state => ({
initStore: state.initStore,
initStore: state.initStore,
timeSeries: state.timeSeries,
variable: state.variable,
plotOn: state.plotOn,
Expand All @@ -50,16 +45,31 @@ export function LandingHome() {
setXSlice: state.setXSlice,
setUseNC: state.setUseNC
})))
function resetSlices(){
setZSlice([0,null])
setYSlice([0,null])
setXSlice([0,null])
}
useEffect(() => { // Update store if URL changes

function resetSlices() {
setZSlice([0, null])
setYSlice([0, null])
setXSlice([0, null])
}

useEffect(() => {
resetSlices();
if (initStore.startsWith('local')){ // Don't fetch store if local
return
if (initStore.startsWith('local:')) {
const path = initStore.replace('local:', '');
if (!NETCDF_EXT_REGEX.test(path)) return; // TODO: handled zarr
const filename = path.split('/').pop() ?? 'file.nc';
fetch(`/file?path=${encodeURIComponent(path)}`)
.then(res => {
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.blob();
})
.then(blob => {
return loadNetCDF(blob, filename);
})
.catch(e => useGlobalStore.getState().setStatus(`Failed to load: ${e instanceof Error ? e.message : String(e)}`));
return;
}
if (initStore.startsWith('local')) return; // local_ set by LocalNetCDF/LocalZarr after load
setUseNC(false)
const newStore = GetStore(initStore)
setCurrentStore(newStore)
Expand Down
7 changes: 4 additions & 3 deletions src/components/ui/MainPanel/Dataset.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const DescriptionContent = ({
setOpenVariables,
onCloseDialog,
}: {
setOpenVariables: React.Dispatch<SetStateAction<boolean>>;
setOpenVariables: (open: boolean) => void;
onCloseDialog: () => void;
}) => {
const {titleDescription} = useGlobalStore(useShallow(state => ({
Expand Down Expand Up @@ -89,7 +89,7 @@ const DatasetOption = ({
};


const Dataset = ({setOpenVariables} : {setOpenVariables: React.Dispatch<React.SetStateAction<boolean>>}) => {
const Dataset = () => {
const [showStoreInput, setShowStoreInput] = useState(false);
const [showLocalInput, setShowLocalInput] = useState(false);
const [popoverSide, setPopoverSide] = useState<"left" | "top">("left");
Expand All @@ -101,9 +101,10 @@ const Dataset = ({setOpenVariables} : {setOpenVariables: React.Dispatch<React.Se
useNC:state.fetchNC
})))

const { initStore, setInitStore } = useGlobalStore(
const { initStore, setInitStore, setOpenVariables } = useGlobalStore(
useShallow((state) => ({
setInitStore: state.setInitStore,
setOpenVariables: state.setOpenVariables,
initStore: state.initStore,
}))
);
Expand Down
57 changes: 18 additions & 39 deletions src/components/ui/MainPanel/LocalNetCDF.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
import React, {ChangeEvent, useState} from 'react'
import { Input } from '../input'
import { useGlobalStore } from '@/GlobalStates/GlobalStore';
import { useZarrStore } from '@/GlobalStates/ZarrStore';
import { NetCDF4 } from '@earthyscience/netcdf4-wasm';
import { loadNetCDF, NETCDF_EXT_REGEX } from '@/utils/loadNetCDF';

import {
Alert,
AlertDescription,
Expand All @@ -13,50 +13,29 @@ import { isMobile } from '../MobileUIHider';

interface LocalNCType {
setShowLocal: React.Dispatch<React.SetStateAction<boolean>>;
setOpenVariables: React.Dispatch<React.SetStateAction<boolean>>;
setOpenVariables: (open: boolean) => void;
}

const NETCDF_EXT_REGEX = /\.(nc|netcdf|nc3|nc4)$/i;

const LocalNetCDF = ({ setOpenVariables}:LocalNCType) => {
const {setStatus } = useGlobalStore.getState()
const {ncModule} = useZarrStore.getState()
// const {ncModule} = useZarrStore.getState()
const [ncError, setError] = useState<string | null>(null);

const handleFileSelect = async (event: ChangeEvent<HTMLInputElement>) => {
setError(null);
const files = event.target.files;
if (!files || files.length === 0) {
setStatus(null)
return;
}
const file = files[0]
// Manual validation (iOS-safe)
if (!NETCDF_EXT_REGEX.test(file.name)) {
setError('Please select a valid NetCDF (.nc, .netcdf, .nc3, .nc4) file.');
return;
}

if (ncModule) ncModule.close();
setStatus("Loading...")
const data = await NetCDF4.fromBlobLazy(file)
const [variables, attrs, metadata] = await Promise.all([
data.getVariables(),
data.getGlobalAttributes(),
data.getFullMetadata()
])
useGlobalStore.setState({variables: Object.keys(variables), zMeta: metadata, initStore:`local_${file.name}`})
useZarrStore.setState({ useNC: true, ncModule: data})
const titleDescription = {
title: attrs.title?? file.name,
description: attrs.history?? ''
}
useGlobalStore.setState({titleDescription})

setOpenVariables(true)
// setShowLocal(false)
setStatus(null)
};
setError(null);
const files = event.target.files;
if (!files || files.length === 0) { setStatus(null); return; }
const file = files[0];
if (!NETCDF_EXT_REGEX.test(file.name)) {
setError('Please select a valid NetCDF (.nc, .netcdf, .nc3, .nc4) file.');
return;
}
try {
await loadNetCDF(file, file.name);
} catch (e) {
setError(`Failed to load file: ${e instanceof Error ? e.message : String(e)}`);
}
};

return (
<div className='w-[100%]'>
Expand Down
2 changes: 1 addition & 1 deletion src/components/ui/MainPanel/LocalZarr.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import ZarrParser from '@/components/zarr/ZarrParser';

interface LocalZarrType {
setShowLocal: React.Dispatch<React.SetStateAction<boolean>>;
setOpenVariables: React.Dispatch<React.SetStateAction<boolean>>;
setOpenVariables: (open: boolean) => void;
setInitStore: (store: string) => void;
}

Expand Down
10 changes: 4 additions & 6 deletions src/components/ui/MainPanel/MainPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
"use client";

import React, {useState} from 'react'
import React from 'react'
import '../css/MainPanel.css'
import {PlotType, Variables, Colormaps, AdjustPlot, Dataset, PlayButton, AnalysisOptions} from '../index'
import { Card } from "@/components/ui/card"


const MainPanel = () => {
const [openVariables, setOpenVariables] = useState<boolean>(false)

return (
<Card className="panel-container">
<Dataset setOpenVariables={setOpenVariables} />
<Variables openVariables={openVariables} setOpenVariables={setOpenVariables} />
<Dataset />
<Variables />
<PlotType />
<Colormaps />
<AdjustPlot />
Expand Down
2 changes: 1 addition & 1 deletion src/components/ui/MainPanel/MetaDataInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ function HandleCustomSteps(e: string, chunkSize: number){
}


const MetaDataInfo = ({ meta, metadata, setShowMeta, setOpenVariables, popoverSide }: { meta: any, metadata: Record<string, any>, setShowMeta: React.Dispatch<React.SetStateAction<boolean>>, setOpenVariables: React.Dispatch<React.SetStateAction<boolean>>, popoverSide: string }) => {
const MetaDataInfo = ({ meta, metadata, setShowMeta, setOpenVariables, popoverSide }: { meta: any, metadata: Record<string, any>, setShowMeta: React.Dispatch<React.SetStateAction<boolean>>, setOpenVariables: (open: boolean) => void, popoverSide: string }) => {
const {is4D, idx4D, variable, initStore, setIs4D, setIdx4D, setVariable, setTextureArrayDepths} = useGlobalStore(useShallow(state => ({
is4D: state.is4D, idx4D: state.idx4D, variable: state.variable,
initStore: state.initStore,
Expand Down
16 changes: 5 additions & 11 deletions src/components/ui/MainPanel/Variables.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,26 +29,20 @@ import {
} from "@/components/ui/accordion";


const Variables = ({
openVariables,
setOpenVariables,
}: {
openVariables: boolean;
setOpenVariables: React.Dispatch<React.SetStateAction<boolean>>;
}) => {
const Variables = () => {
const [popoverSide, setPopoverSide] = useState<"left" | "top">("left");
const [openMetaPopover, setOpenMetaPopover] = useState(false);

const [showMeta, setShowMeta] = useState(false);
const { variables, zMeta, metadata, setMetadata, initStore } = useGlobalStore(
const { variables, zMeta, metadata, initStore, openVariables, setMetadata, setOpenVariables } = useGlobalStore(
useShallow((state) => ({
variables: state.variables,
zMeta: state.zMeta,
metadata: state.metadata,
dimNames:state.dimNames,
initStore: state.initStore,
openVariables: state.openVariables,
setMetadata: state.setMetadata,
setDimNames:state.setDimNames,
initStore: state.initStore
setOpenVariables: state.setOpenVariables
}))
);

Expand Down
36 changes: 36 additions & 0 deletions src/utils/loadNetCDF.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// utils/loadNetCDF.ts
import { NetCDF4 } from '@earthyscience/netcdf4-wasm';
import { useGlobalStore } from '@/GlobalStates/GlobalStore';
import { useZarrStore } from '@/GlobalStates/ZarrStore';

const NETCDF_EXT_REGEX = /\.(nc|netcdf|nc3|nc4)$/i;

export async function loadNetCDF(file: Blob, filename: string) {
const { setStatus, setOpenVariables } = useGlobalStore.getState();
const { ncModule } = useZarrStore.getState();
if (ncModule) ncModule.close();
setStatus("Loading...");
try {
const data = await NetCDF4.fromBlobLazy(file);
const [variables, attrs, metadata] = await Promise.all([
data.getVariables(),
data.getGlobalAttributes(),
data.getFullMetadata(),
]);
useGlobalStore.setState({
variables: Object.keys(variables),
zMeta: metadata,
initStore: `local_${filename}`,
titleDescription: {
title: attrs.title ?? filename,
description: attrs.history ?? '',
},
});
useZarrStore.setState({ useNC: true, ncModule: data });
// setOpenVariables(true);
} finally {
setStatus(null);
}
}

export { NETCDF_EXT_REGEX };
Loading