-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: Lane Sawyer <[email protected]>
- Loading branch information
1 parent
824f293
commit 8cb3cf6
Showing
29 changed files
with
6,386 additions
and
4,142 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
# Examples | ||
|
||
Examples are located in the `apps` directory. | ||
Examples are located in the `examples` directory. | ||
|
||
## Adding New Examples | ||
|
||
To add a new example, create a new directory in the `apps` directory, copy the `package.json` from another example, and then start building! | ||
To add a new example, create a new directory in the `examples` directory, copy the `package.json` from another example, and then start building! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<!doctype html> | ||
<html> | ||
<body> | ||
<div | ||
id="sidebar" | ||
style="top: 0; left: 0; width: 15%; height: 100%; position: absolute" | ||
></div> | ||
<div | ||
id="main" | ||
style="top: 0; left: 15%; width: 85%; height: 100%; position: absolute" | ||
/> | ||
</body> | ||
</html> | ||
<script | ||
type="module" | ||
src="./src/dzi/dzi.ts" | ||
></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,11 @@ | ||
<!doctype html> | ||
<html> | ||
<body> | ||
<div | ||
id="sidebar" | ||
style="top: 0; left: 0; width: 15%; height: 100%; position: absolute" | ||
></div> | ||
<canvas | ||
id="glCanvas" | ||
style="top: 0; left: 15%; width: 85%; height: 100%; position: absolute" | ||
/> | ||
EXAMPLES | ||
<br /> | ||
<ul> | ||
<li><a href="/dzi">Deep Zoom Image</a><br /></li> | ||
<li><a href="/layers">Layers</a><br /></li> | ||
</ul> | ||
</body> | ||
</html> | ||
<script | ||
type="module" | ||
src="./src/layers.ts" | ||
></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<!doctype html> | ||
<html> | ||
<body> | ||
<div | ||
id="sidebar" | ||
style="top: 0; left: 0; width: 15%; height: 100%; position: absolute" | ||
></div> | ||
<canvas | ||
id="glCanvas" | ||
style="top: 0; left: 15%; width: 85%; height: 100%; position: absolute" | ||
/> | ||
</body> | ||
</html> | ||
<script | ||
type="module" | ||
src="./src/layers.ts" | ||
></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,7 +23,7 @@ | |
"email": "[email protected]" | ||
} | ||
], | ||
"license": "TBD", | ||
"license": "BSD-3-Clause", | ||
"type": "module", | ||
"main": "lib/index.js", | ||
"types": "lib/index.d.ts", | ||
|
@@ -45,6 +45,7 @@ | |
"dependencies": { | ||
"@alleninstitute/vis-geometry": "workspace:*", | ||
"@alleninstitute/vis-scatterbrain": "workspace:*", | ||
"@alleninstitute/vis-dzi": "workspace:*", | ||
"@czi-sds/components": "^20.0.1", | ||
"@emotion/css": "^11.11.2", | ||
"@emotion/react": "^11.11.4", | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import React from 'react'; | ||
import { TwoClientsPOC } from './double'; | ||
|
||
export function AppUi() { | ||
return <TwoClientsPOC />; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import { useContext, useEffect, useMemo, useRef, useState } from 'react'; | ||
import { RenderServerProvider } from './render-server-provider'; | ||
import React from 'react'; | ||
import { DziView } from './dziView'; | ||
import type { DziImage, DziRenderSettings } from '@alleninstitute/vis-dzi'; | ||
import { Box2D, Vec2, type box2D } from '@alleninstitute/vis-geometry'; | ||
|
||
const example: DziImage = { | ||
format: 'jpeg', | ||
imagesUrl: | ||
'https://idk-etl-prod-download-bucket.s3.amazonaws.com/idf-23-10-pathology-images/pat_images_HPW332DMO29NC92JPWA/H20.33.029-A12-I6-primary/H20.33.029-A12-I6-primary_files/', | ||
overlap: 1, | ||
size: { | ||
width: 13446, | ||
height: 11596, | ||
}, | ||
tileSize: 512, | ||
}; | ||
const exampleDzi: DziImage = { | ||
imagesUrl: 'https://openseadragon.github.io/example-images/highsmith/highsmith_files/', | ||
format: 'jpg', | ||
overlap: 2, | ||
size: { | ||
width: 7026, | ||
height: 9221, | ||
}, | ||
tileSize: 256, | ||
}; | ||
const exampleSettings: DziRenderSettings = { | ||
camera: { | ||
screenSize: [500, 500], | ||
view: Box2D.create([0, 0], [1, 1]), | ||
}, | ||
}; | ||
|
||
export function TwoClientsPOC() { | ||
const [view, setView] = useState<box2D>(Box2D.create([0, 0], [1, 1])); | ||
const zoom = (e: React.WheelEvent<HTMLCanvasElement>) => { | ||
const scale = e.deltaY > 0 ? 1.1 : 0.9; | ||
const m = Box2D.midpoint(view); | ||
const v = Box2D.translate(Box2D.scale(Box2D.translate(view, Vec2.scale(m, -1)), [scale, scale]), m); | ||
setView(v); | ||
}; | ||
const overlay = useRef<HTMLImageElement>(new Image()); | ||
useEffect(() => { | ||
overlay.current.onload = () => { | ||
console.log('loaded svg!'); | ||
}; | ||
overlay.current.src = | ||
'https://idk-etl-prod-download-bucket.s3.amazonaws.com/idf-22-07-pathology-image-move/pat_images_JGCXWER774NLNWX2NNR/7179-A6-I6-MTG-classified/annotation.svg'; | ||
}, []); | ||
return ( | ||
<RenderServerProvider> | ||
<DziView | ||
id="left" | ||
svgOverlay={overlay.current} | ||
dzi={example} | ||
camera={{ ...exampleSettings.camera, view }} | ||
wheel={zoom} | ||
/> | ||
<DziView | ||
id="right" | ||
dzi={exampleDzi} | ||
svgOverlay={overlay.current} | ||
camera={{ ...exampleSettings.camera, view }} | ||
wheel={zoom} | ||
/> | ||
</RenderServerProvider> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { createRoot } from 'react-dom/client'; | ||
import { AppUi } from './app'; | ||
|
||
const uiroot = createRoot(document.getElementById('main')!); | ||
uiroot.render(AppUi()); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
import { useContext, useEffect, useRef, useState } from 'react'; | ||
import { | ||
buildDziRenderer, | ||
type DziImage, | ||
type DziRenderSettings, | ||
type DziTile, | ||
type GpuProps as CachedPixels, | ||
buildAsyncDziRenderer, | ||
} from '@alleninstitute/vis-dzi'; | ||
import React from 'react'; | ||
import { buildAsyncRenderer, type RenderFrameFn } from '@alleninstitute/vis-scatterbrain'; | ||
import { isEqual } from 'lodash'; | ||
import { renderServerContext } from './render-server-provider'; | ||
import { Vec2, type vec2 } from '@alleninstitute/vis-geometry'; | ||
|
||
type Props = { | ||
id: string; | ||
dzi: DziImage; | ||
svgOverlay: HTMLImageElement; | ||
wheel: (e: React.WheelEvent<HTMLCanvasElement>) => void; | ||
} & DziRenderSettings; | ||
|
||
function buildCompositor(svg: HTMLImageElement, settings: DziRenderSettings) { | ||
return (ctx: CanvasRenderingContext2D, image: ImageData) => { | ||
const { width, height } = svg; | ||
const { camera } = settings; | ||
const svgSize: vec2 = [width, height]; | ||
const start = Vec2.mul(camera.view.minCorner, svgSize); | ||
const wh = Vec2.sub(Vec2.mul(camera.view.maxCorner, svgSize), start); | ||
const [sx, sy] = start; | ||
const [sw, sh] = wh; | ||
// first, draw the results from webGL | ||
ctx.putImageData(image, 0, 0); | ||
// then add our svg overlay | ||
ctx.drawImage(svg, sx, sy, sw, sh, 0, 0, ctx.canvas.width, ctx.canvas.height); | ||
}; | ||
} | ||
|
||
export function DziView(props: Props) { | ||
const { svgOverlay, camera, dzi, wheel, id } = props; | ||
const server = useContext(renderServerContext); | ||
const cnvs = useRef<HTMLCanvasElement>(null); | ||
|
||
// this is a demo, so rather than work hard to have a referentially stable camera, | ||
// we just memoize it like so to prevent over-rendering | ||
const [cam, setCam] = useState(camera); | ||
useEffect(() => { | ||
if (!isEqual(cam, camera)) { | ||
setCam(camera); | ||
} | ||
}, [camera]); | ||
|
||
// the renderer needs WebGL for us to create it, and WebGL needs a canvas to exist, and that canvas needs to be the same canvas forever | ||
// hence the awkwardness of refs + an effect to initialize the whole hting | ||
const renderer = | ||
useRef< | ||
ReturnType<typeof buildAsyncRenderer<DziImage, DziTile, DziRenderSettings, string, string, CachedPixels>> | ||
>(); | ||
|
||
useEffect(() => { | ||
if (server && server.regl) { | ||
renderer.current = buildAsyncDziRenderer(server.regl); | ||
} | ||
return () => { | ||
if (cnvs.current) { | ||
server?.destroyClient(cnvs.current); | ||
} | ||
}; | ||
}, [server]); | ||
|
||
useEffect(() => { | ||
if (server && renderer.current && cnvs.current) { | ||
const renderMyData: RenderFrameFn<DziImage, DziTile> = (target, cache, callback) => { | ||
if (renderer.current) { | ||
// erase the frame before we start drawing on it | ||
return renderer.current(dzi, { camera: cam }, callback, target, cache); | ||
} | ||
return null; | ||
}; | ||
const compose = buildCompositor(svgOverlay, { camera: cam }); | ||
server.beginRendering( | ||
renderMyData, | ||
(e) => { | ||
switch (e.status) { | ||
case 'begin': | ||
server.regl?.clear({ framebuffer: e.target, color: [0, 0, 0, 0], depth: 1 }); | ||
break; | ||
case 'progress': | ||
// wanna see the tiles as they arrive? | ||
e.server.copyToClient(compose); | ||
break; | ||
case 'finished': { | ||
e.server.copyToClient(compose); | ||
} | ||
} | ||
}, | ||
cnvs.current | ||
); | ||
} | ||
}, [server, renderer.current, cnvs.current, cam]); | ||
return ( | ||
<canvas | ||
id={id} | ||
ref={cnvs} | ||
onWheel={wheel} | ||
width={camera.screenSize[0]} | ||
height={camera.screenSize[1]} | ||
></canvas> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { RenderServer } from '@alleninstitute/vis-scatterbrain'; | ||
import React, { createContext, useEffect, useRef, type PropsWithChildren } from 'react'; | ||
|
||
export const renderServerContext = createContext<RenderServer | null>(null); | ||
|
||
export function RenderServerProvider(props: PropsWithChildren<{}>) { | ||
const server = useRef<RenderServer>(); | ||
const { children } = props; | ||
useEffect(() => { | ||
server.current = new RenderServer([2048, 2048], []); | ||
}, []); | ||
return <renderServerContext.Provider value={server.current ?? null}>{children}</renderServerContext.Provider>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.