Skip to content

Commit

Permalink
Reduce delay when slicing with h5wasm through viewer config
Browse files Browse the repository at this point in the history
  • Loading branch information
axelboc committed May 31, 2024
1 parent 3ad7123 commit c0cfc91
Show file tree
Hide file tree
Showing 10 changed files with 154 additions and 13 deletions.
29 changes: 29 additions & 0 deletions packages/app/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,17 @@ specific export scenarios. In this case, or if you don't provide a function at
all, `H5GroveProvider` falls back to generating URLs based on the `/data`
endpoint and `format` query param.

#### `viewerConfig: Partial<ViewerConfig>` (optional)

Customise the behaviour of the viewer:

- `slicingTiming: number` – debounce delay for the dimension slicing sliders
(default: 250)

Should be high-enough to not overload your h5grove server and to give enough
time for the data to reach the client. This depends on the size of your users'
datasets, on your users' bandwidths, and on the performance of your server.

#### `key?: Key` (optional)

If the content of the current file changes and you want to ensure that the
Expand Down Expand Up @@ -359,6 +370,17 @@ See
this time, so if you don't provide your own, the export menu will remain
disabled in the toolbar.

#### `viewerConfig: Partial<ViewerConfig>` (optional)

Customise the behaviour of the viewer:

- `slicingTiming: number` – debounce delay for the dimension slicing sliders
(default: 250)

Should be high-enough to not overload your HSDS server and to give enough time
for the data to reach the client. This depends on the size of your users'
datasets, on your users' bandwidths, and on the performance of your server.

#### `key?: Key` (optional)

See
Expand All @@ -382,6 +404,13 @@ See
`MockProvider` provides a very basic fallback implementation of `getExportURL`
that can generate only client-side CSV exports of 1D datasets.

#### `viewerConfig: Partial<ViewerConfig>` (optional)

Customise the behaviour of the viewer:

- `slicingTiming: number` – debounce delay for the dimension slicing sliders
(default: 20)

### Utilities

#### `getFeedbackMailto`
Expand Down
5 changes: 3 additions & 2 deletions packages/app/src/dimension-mapper/SlicingSlider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { useDebouncedCallback, useMeasure } from '@react-hookz/web';
import { useState } from 'react';
import ReactSlider from 'react-slider';

import { useViewerConfig } from '../providers/DataProvider';
import styles from './SlicingSlider.module.css';

const ID = 'h5w-slider';
const MIN_HEIGHT_PER_MARK = 25;
const SLICING_DEBOUNCE_DELAY = 250;

interface Props {
dimension: number;
Expand All @@ -17,12 +17,13 @@ interface Props {

function SlicingSlider(props: Props) {
const { dimension, maxIndex, initialValue, onChange } = props;
const { slicingTiming } = useViewerConfig();

const [value, setValue] = useState(initialValue);
const onDebouncedChange = useDebouncedCallback(
onChange,
[onChange],
SLICING_DEBOUNCE_DELAY,
slicingTiming,
);

const [containerSize, containerRef] = useMeasure<HTMLDivElement>();
Expand Down
9 changes: 8 additions & 1 deletion packages/app/src/providers/DataProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type {
EntitiesStore,
ProgressCallback,
ValuesStore,
ViewerConfig,
} from './models';

export interface DataContextValue {
Expand All @@ -21,6 +22,7 @@ export interface DataContextValue {
entitiesStore: EntitiesStore;
valuesStore: ValuesStore;
attrValuesStore: AttrValuesStore;
viewerConfig: ViewerConfig;

// Undocumented
getExportURL?: DataProviderApi['getExportURL'];
Expand All @@ -34,13 +36,17 @@ const DataContext = createContext({} as DataContextValue);
export function useDataContext() {
return useContext(DataContext);
}
export function useViewerConfig() {
return useContext(DataContext).viewerConfig;
}

interface Props {
api: DataProviderApi;
viewerConfig: ViewerConfig;
}

function DataProvider(props: PropsWithChildren<Props>) {
const { api, children } = props;
const { api, viewerConfig, children } = props;

const entitiesStore = useMemo(() => {
const childCache = new Map<string, Exclude<ChildEntity, Group>>();
Expand Down Expand Up @@ -110,6 +116,7 @@ function DataProvider(props: PropsWithChildren<Props>) {
entitiesStore,
valuesStore,
attrValuesStore,
viewerConfig,
getExportURL: api.getExportURL?.bind(api),
addProgressListener: api.addProgressListener.bind(api),
removeProgressListener: api.removeProgressListener.bind(api),
Expand Down
20 changes: 18 additions & 2 deletions packages/app/src/providers/h5grove/H5GroveProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,40 @@ import { useMemo } from 'react';

import type { DataProviderApi } from '../api';
import DataProvider from '../DataProvider';
import type { ViewerConfig } from '../models';
import { H5GroveApi } from './h5grove-api';

const DEFAULT_VIEWER_CONFIG: ViewerConfig = {
slicingTiming: 250,
};

interface Props {
url: string;
filepath: string;
axiosConfig?: AxiosRequestConfig;
getExportURL?: DataProviderApi['getExportURL'];
viewerConfig?: Partial<ViewerConfig>;
}

function H5GroveProvider(props: PropsWithChildren<Props>) {
const { url, filepath, axiosConfig, getExportURL, children } = props;
const { url, filepath, axiosConfig, getExportURL, viewerConfig, children } =
props;

const api = useMemo(
() => new H5GroveApi(url, filepath, axiosConfig, getExportURL),
[filepath, url, axiosConfig, getExportURL],
);

return <DataProvider api={api}>{children}</DataProvider>;
const mergedViewerConfig = useMemo(
() => ({ ...DEFAULT_VIEWER_CONFIG, ...viewerConfig }),
[viewerConfig],
);

return (
<DataProvider api={api} viewerConfig={mergedViewerConfig}>
{children}
</DataProvider>
);
}

export default H5GroveProvider;
27 changes: 25 additions & 2 deletions packages/app/src/providers/hsds/HsdsProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,48 @@ import { useMemo } from 'react';

import type { DataProviderApi } from '../api';
import DataProvider from '../DataProvider';
import type { ViewerConfig } from '../models';
import { HsdsApi } from './hsds-api';

const DEFAULT_VIEWER_CONFIG: ViewerConfig = {
slicingTiming: 250,
};

interface Props {
url: string;
username: string;
password: string;
filepath: string;
getExportURL?: DataProviderApi['getExportURL'];
viewerConfig?: Partial<ViewerConfig>;
}

function HsdsProvider(props: PropsWithChildren<Props>) {
const { url, username, password, filepath, getExportURL, children } = props;
const {
url,
username,
password,
filepath,
getExportURL,
viewerConfig,
children,
} = props;

const api = useMemo(
() => new HsdsApi(url, username, password, filepath, getExportURL),
[filepath, password, url, username, getExportURL],
);

return <DataProvider api={api}>{children}</DataProvider>;
const mergedViewerConfig = useMemo(
() => ({ ...DEFAULT_VIEWER_CONFIG, ...viewerConfig }),
[viewerConfig],
);

return (
<DataProvider api={api} viewerConfig={mergedViewerConfig}>
{children}
</DataProvider>
);
}

export default HsdsProvider;
19 changes: 17 additions & 2 deletions packages/app/src/providers/mock/MockProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,33 @@ import { useMemo } from 'react';

import type { DataProviderApi } from '../api';
import DataProvider from '../DataProvider';
import type { ViewerConfig } from '../models';
import { MockApi } from './mock-api';

const DEFAULT_VIEWER_CONFIG: ViewerConfig = {
slicingTiming: 20,
};

interface Props {
getExportURL?: DataProviderApi['getExportURL'];
viewerConfig?: Partial<ViewerConfig>;
}

function MockProvider(props: PropsWithChildren<Props>) {
const { getExportURL, children } = props;
const { getExportURL, viewerConfig, children } = props;

const api = useMemo(() => new MockApi(getExportURL), [getExportURL]);

return <DataProvider api={api}>{children}</DataProvider>;
const mergedViewerConfig = useMemo(
() => ({ ...DEFAULT_VIEWER_CONFIG, ...viewerConfig }),
[viewerConfig],
);

return (
<DataProvider api={api} viewerConfig={mergedViewerConfig}>
{children}
</DataProvider>
);
}

export default MockProvider;
4 changes: 4 additions & 0 deletions packages/app/src/providers/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ export interface AttrValuesStore extends FetchStore<AttributeValues, Entity> {
getSingle: (entity: Entity, attrName: AttrName) => unknown;
}

export interface ViewerConfig {
slicingTiming: number;
}

export type ExportFormat = 'json' | 'csv' | 'npy' | 'tiff';
export type ExportURL = URL | (() => Promise<URL | Blob>) | undefined;

Expand Down
15 changes: 15 additions & 0 deletions packages/h5wasm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,16 @@ async function getPlugin(name: Plugin): Promise<ArrayBuffer | undefined> {
}
```

#### `viewerConfig: Partial<ViewerConfig>` (optional)

Customise the behaviour of the viewer:

- `slicingTiming: number` – debounce delay for the dimension slicing sliders
(default: 20)

You may want to choose a higher number to reduce lag when viewing very large
datasets.

### `H5WasmProvider`

- `filename: string` (required) - the name of the file
Expand Down Expand Up @@ -212,3 +222,8 @@ See

See
[`H5WasmLocalFileProvider#getPlugin`](#getplugin-name-plugin--promisearraybuffer--undefined)

#### `viewerConfig: Partial<ViewerConfig>` (optional)

See
[`H5WasmLocalFileProvider#viewerConfig`](#viewerconfig-partialviewerconfig-optional)
20 changes: 18 additions & 2 deletions packages/h5wasm/src/H5WasmProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,27 @@
import type { DataProviderApi } from '@h5web/app';
import { DataProvider } from '@h5web/app';
import type { ViewerConfig } from '@h5web/app/src/providers/models';
import type { PropsWithChildren } from 'react';
import { useMemo, useRef } from 'react';

import { H5WasmApi } from './h5wasm-api';
import type { Plugin } from './models';

const DEFAULT_VIEWER_CONFIG: ViewerConfig = {
slicingTiming: 20,
};

interface Props {
filename: string;
buffer: ArrayBuffer;
getExportURL?: DataProviderApi['getExportURL'];
getPlugin?: (name: Plugin) => Promise<ArrayBuffer | undefined>;
viewerConfig?: Partial<ViewerConfig>;
}

function H5WasmProvider(props: PropsWithChildren<Props>) {
const { filename, buffer, getExportURL, getPlugin, children } = props;
const { filename, buffer, getExportURL, getPlugin, viewerConfig, children } =
props;

const prevApiRef = useRef<H5WasmApi>();

Expand All @@ -27,7 +34,16 @@ function H5WasmProvider(props: PropsWithChildren<Props>) {
return newApi;
}, [buffer, filename, getExportURL, getPlugin]);

return <DataProvider api={api}>{children}</DataProvider>;
const mergedViewerConfig = useMemo(
() => ({ ...DEFAULT_VIEWER_CONFIG, ...viewerConfig }),
[viewerConfig],
);

return (
<DataProvider api={api} viewerConfig={mergedViewerConfig}>
{children}
</DataProvider>
);
}

export default H5WasmProvider;
19 changes: 17 additions & 2 deletions packages/h5wasm/src/local/H5WasmLocalFileProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
import type { DataProviderApi } from '@h5web/app';
import { DataProvider } from '@h5web/app';
import type { ViewerConfig } from '@h5web/app/src/providers/models';
import type { PropsWithChildren } from 'react';
import { useMemo, useRef } from 'react';

import type { Plugin } from '../models';
import { H5WasmLocalFileApi } from './h5wasm-local-file-api';

const DEFAULT_VIEWER_CONFIG: ViewerConfig = {
slicingTiming: 20,
};

interface Props {
file: File;
getExportURL?: DataProviderApi['getExportURL'];
getPlugin?: (name: Plugin) => Promise<ArrayBuffer | undefined>;
viewerConfig?: Partial<ViewerConfig>;
}

function H5WasmLocalFileProvider(props: PropsWithChildren<Props>) {
const { file, getExportURL, getPlugin, children } = props;
const { file, getExportURL, getPlugin, viewerConfig, children } = props;

const prevApiRef = useRef<H5WasmLocalFileApi>();

Expand All @@ -26,7 +32,16 @@ function H5WasmLocalFileProvider(props: PropsWithChildren<Props>) {
return newApi;
}, [file, getExportURL, getPlugin]);

return <DataProvider api={api}>{children}</DataProvider>;
const mergedViewerConfig = useMemo(
() => ({ ...DEFAULT_VIEWER_CONFIG, ...viewerConfig }),
[viewerConfig],
);

return (
<DataProvider api={api} viewerConfig={mergedViewerConfig}>
{children}
</DataProvider>
);
}

export default H5WasmLocalFileProvider;

0 comments on commit c0cfc91

Please sign in to comment.