Skip to content

Commit

Permalink
Upgrade TypeScript
Browse files Browse the repository at this point in the history
  • Loading branch information
manzt committed Jul 22, 2024
1 parent d674b2b commit 018a272
Show file tree
Hide file tree
Showing 8 changed files with 47 additions and 34 deletions.
8 changes: 4 additions & 4 deletions src/components/LayerController/AxisSlider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { Divider, Grid, Typography } from "@material-ui/core";
import { Slider } from "@material-ui/core";
import { withStyles } from "@material-ui/styles";
import { useAtom, useAtomValue } from "jotai";
import * as React from "react";
import type { ChangeEvent } from "react";
import React, { useState, useEffect } from "react";
import type { ControllerProps } from "../../state";
import DimensionOptions from "./AxisOptions";

Expand Down Expand Up @@ -32,13 +32,13 @@ function AxisSlider({ sourceAtom, layerAtom, axisIndex, max }: ControllerProps<P
axisLabel = axisLabel.toUpperCase();
}
// state of the slider to update UI while dragging
const [value, setValue] = useState(0);
const [value, setValue] = React.useState(0);

// If axis index change externally, need to update state
useEffect(() => {
React.useEffect(() => {
// Use first channel to get initial value of slider - can be undefined on first render
setValue(layer.layerProps.selections[0] ? layer.layerProps.selections[0][axisIndex] : 1);
}, [layer.layerProps.selections]);
}, [layer.layerProps.selections, axisIndex]);

const handleRelease = () => {
setLayer((prev) => {
Expand Down
21 changes: 14 additions & 7 deletions src/components/Viewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,16 @@ import { type WritableAtom, useAtom } from "jotai";
import { useAtomValue } from "jotai";
import * as React from "react";

import type { LayerState, ViewState } from "../state";
import type { LayerProps } from "@deck.gl/core/lib/layer";
import type { ZarrPixelSource } from "../ZarrPixelSource";
import type { ViewState } from "../state";
import { layerAtoms } from "../state";
import { fitBounds, isInterleaved } from "../utils";

function getLayerSize(props: LayerState["layerProps"]) {
type Data = { loader: ZarrPixelSource; rows: number; columns: number };
type VizarrLayer = Layer<unknown, LayerProps<unknown> & Data>;

function getLayerSize(props: Data) {
const { loader } = props;
const [base, maxZoom] = Array.isArray(loader) ? [loader[0], loader.length] : [loader, 0];
const interleaved = isInterleaved(base.shape);
Expand All @@ -24,17 +29,18 @@ function getLayerSize(props: LayerState["layerProps"]) {
}

function WrappedViewStateDeck(props: {
layers: Layer<any, any>[];
layers: Array<VizarrLayer | null>;
viewStateAtom: WritableAtom<ViewState | undefined, ViewState>;
}) {
const [viewState, setViewState] = useAtom(props.viewStateAtom);
const deckRef = React.useRef<DeckGL>(null);
const firstLayerProps = props.layers[0]?.props;

// If viewState hasn't been updated, use the first loader to guess viewState
// TODO: There is probably a better place / way to set the intital view and this is a hack.
if (deckRef.current && !viewState && props.layers[0]?.props?.loader) {
if (deckRef.current && !viewState && firstLayerProps?.loader) {
const { deck } = deckRef.current;
const { width, height, maxZoom } = getLayerSize(props.layers[0].props);
const { width, height, maxZoom } = getLayerSize(firstLayerProps);
const padding = deck.width < 400 ? 10 : deck.width < 600 ? 30 : 50; // Adjust depending on viewport width.
const bounds = fitBounds([width, height], [deck.width, deck.height], maxZoom, padding);
setViewState(bounds);
Expand All @@ -59,10 +65,11 @@ function WrappedViewStateDeck(props: {

function Viewer({ viewStateAtom }: { viewStateAtom: WritableAtom<ViewState | undefined, ViewState> }) {
const layerConstructors = useAtomValue(layerAtoms);
const layers = layerConstructors.map((layer) => {
// @ts-expect-error - Viv types are giving up an issue
const layers: Array<VizarrLayer | null> = layerConstructors.map((layer) => {
return !layer.on ? null : new layer.Layer(layer.layerProps);
});
return <WrappedViewStateDeck viewStateAtom={viewStateAtom} layers={layers as Layer<any, any>[]} />;
return <WrappedViewStateDeck viewStateAtom={viewStateAtom} layers={layers} />;
}

export default Viewer;
2 changes: 1 addition & 1 deletion src/gridLayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ function refreshGridData(props: GridLayerProps) {
return pMap(loaders, mapper, { concurrency });
}

export default class GridLayer<P extends GridLayerProps = GridLayerProps> extends CompositeLayer<unknown, P> {
export default class GridLayer extends CompositeLayer<unknown, CompositeLayerProps<unknown> & GridLayerProps> {
initializeState() {
this.state = { gridData: [], width: 0, height: 0 };
refreshGridData(this.props).then((gridData) => {
Expand Down
2 changes: 1 addition & 1 deletion src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export function createViewer(element: HTMLElement, options: { menuOpen?: boolean
on: emitter.on.bind(emitter),
destroy: () => root.unmount(),
}),
[],
[setViewState, addImage],
);
React.useEffect(() => {
if (ref.current) {
Expand Down
6 changes: 3 additions & 3 deletions src/ome.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Readable } from "@zarrita/storage";
import pMap from "p-map";
import * as zarr from "zarrita";
import type { ImageLayerConfig, SourceData } from "./state";
import type { ImageLayerConfig, OnClickData, SourceData } from "./state";

import { ZarrPixelSource } from "./ZarrPixelSource";
import * as utils from "./utils";
Expand Down Expand Up @@ -105,7 +105,7 @@ export async function loadWell(

sourceData.rows = rows;
sourceData.columns = cols;
sourceData.onClick = (info: Record<string, unknown> & { gridCoord?: { row: number; column: number } }) => {
sourceData.onClick = (info: OnClickData) => {
let gridCoord = info.gridCoord;
if (!gridCoord) {
return;
Expand Down Expand Up @@ -222,7 +222,7 @@ export async function loadPlate(
columns: columns.length,
};
// Us onClick from image config or Open Well in new window
sourceData.onClick = (info: Record<string, unknown> & { gridCoord?: { row: number; column: number } }) => {
sourceData.onClick = (info: OnClickData) => {
let gridCoord = info.gridCoord;
if (!gridCoord) {
return;
Expand Down
15 changes: 10 additions & 5 deletions src/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ interface BaseConfig {
opacity?: number;
acquisition?: string;
model_matrix?: string | number[];
onClick?: (e: any) => void;
onClick?: (e: unknown) => void;
}

export interface MultichannelConfig extends BaseConfig {
Expand All @@ -57,6 +57,10 @@ export interface SingleChannelConfig extends BaseConfig {

export type ImageLayerConfig = MultichannelConfig | SingleChannelConfig;

export type OnClickData = Record<string, unknown> & {
gridCoord?: { row: number; column: number };
};

export type SourceData = {
loader: ZarrPixelSource[];
loaders?: GridLoader[]; // for OME plates
Expand All @@ -77,7 +81,7 @@ export type SourceData = {
};
model_matrix: Matrix4;
axis_labels: string[];
onClick?: (e: any) => void;
onClick?: (e: OnClickData) => void;
};

export type VivProps = ConstructorParameters<typeof MultiscaleImageLayer>[0];
Expand All @@ -92,7 +96,7 @@ export interface BaseLayerProps {
selections: number[][];
modelMatrix: Matrix4;
contrastLimitsRange: [min: number, max: number][];
onClick?: (e: any) => void;
onClick?: (e: OnClickData) => void;
}

interface MultiscaleImageLayerProps extends BaseLayerProps {
Expand All @@ -109,7 +113,8 @@ type LayerMap = {
grid: [GridLayer, { loader: ZarrPixelSource<string[]> | ZarrPixelSource<string[]>[] } & GridLayerProps];
};

export type LayerCtr<T> = new (...args: any[]) => T;
// biome-ignore lint/suspicious/noExplicitAny: Need a catch all for layer types
export type LayerCtr<T> = new (...args: Array<any>) => T;
export type LayerState<T extends "image" | "multiscale" | "grid" = "image" | "multiscale" | "grid"> = {
Layer: LayerCtr<LayerMap[T][0]>;
layerProps: LayerMap[T][1];
Expand All @@ -118,7 +123,7 @@ export type LayerState<T extends "image" | "multiscale" | "grid" = "image" | "mu

type WithId<T> = T & { id: string };

export type ControllerProps<T = {}> = {
export type ControllerProps<T = object> = {
sourceAtom: PrimitiveAtom<WithId<SourceData>>;
layerAtom: PrimitiveAtom<WithId<LayerState>>;
} & T;
Expand Down
18 changes: 11 additions & 7 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,14 @@ async function normalizeStore(source: string | Readable): Promise<zarr.Location<
if (source.endsWith(".json")) {
// import custom store implementation
const [{ default: ReferenceStore }, json] = await Promise.all([
// @ts-expect-error
import("@zarrita/storage/ref"),
fetch(source).then((res) => res.json()),
]);
store = ReferenceStore.fromSpec(json);
} else {
const url = new URL(source);
// @ts-expect-error - pathname always starts with '/'
path = url.pathname;
// grab the path and then set the URL to the root
path = ensureAbosolutePath(url.pathname);
url.pathname = "/";
store = new zarr.FetchStore(url.href);
}
Expand All @@ -48,6 +47,12 @@ async function normalizeStore(source: string | Readable): Promise<zarr.Location<
return zarr.root(source);
}

function ensureAbosolutePath(path: string): `/${string}` {
if (path === "/") return path;
// @ts-expect-error - path always starts with '/'
return path.startsWith("/") ? path : `/${path}`;
}

export async function open(source: string | Readable) {
const location = await normalizeStore(source);
return zarr.open(location);
Expand Down Expand Up @@ -112,8 +117,8 @@ export function rstrip(str: string, remove = " "): string {

export function join(...args: (string | undefined)[]) {
return args
.filter(Boolean)
.map((s: any) => rstrip(s as string, "/"))
.filter((s) => s !== undefined)
.map((s) => rstrip(s, "/"))
.join("/");
}

Expand Down Expand Up @@ -226,7 +231,6 @@ export function fitBounds(
return { zoom, target: [width / 2, height / 2] };
}

// prettier-ignore
type Array16 = [
number,
number,
Expand Down Expand Up @@ -319,7 +323,7 @@ export async function calcConstrastLimits<S extends string[]>(
*/
export function defer<T>() {
let resolve: (value: T | PromiseLike<T>) => void;
let reject: (reason?: any) => void;
let reject: (reason?: unknown) => void;
const promise = new Promise<T>((res, rej) => {
resolve = res;
reject = rej;
Expand Down
9 changes: 3 additions & 6 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,15 @@
"compilerOptions": {
"module": "esnext",
"target": "esnext",
"moduleResolution": "node",
"jsx": "preserve",
"baseUrl": "./",
"moduleResolution": "bundler",
"noEmit": true,
"strict": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"verbatimModuleSyntax": true,
"jsx": "preserve",
"paths": {
"*": ["*", "node_modules/@danmarshall/deckgl-typings/*"]
"*": ["./node_modules/@danmarshall/deckgl-typings/*"]
}
}
}

0 comments on commit 018a272

Please sign in to comment.