Skip to content

Commit

Permalink
feat(remote-viewport): add initial render machine logic
Browse files Browse the repository at this point in the history
  • Loading branch information
PaulHax committed Jul 19, 2023
1 parent 67d6009 commit 34eb654
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 38 deletions.
4 changes: 2 additions & 2 deletions packages/element/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<title>itk-viewer</title>
<link rel="stylesheet" href="./src/index.css" />
<script type="module" src="/src/image-info-viewport.ts"></script>
<script type="module" src="/src/remote-viewport.ts"></script>
<script type="module" src="/src/itk-remote-viewport.ts"></script>
<script type="module" src="/src/itk-viewer-element.ts"></script>
<script type="module" src="/src/main.ts"></script>
</head>
Expand All @@ -16,7 +16,7 @@
<itk-image-info-viewport id="left-viewport"></itk-image-info-viewport>
<itk-remote-viewport
id="right-viewport"
address="asdf"
address="https://ai.imjoy.io"
></itk-remote-viewport>
</itk-viewer>
</body>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { PropertyValues, css, html } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { Ref, ref, createRef } from 'lit/directives/ref.js';
import { SelectorController } from 'xstate-lit/dist/select-controller.js';

import {
Remote,
RemoteActor,
createRemoteViewport,
createTestActors,
} from '@itk-viewer/remote-viewport/remote-viewport.js';

import { ItkViewport } from './itk-viewport.js';
Expand All @@ -14,14 +16,24 @@ export class RemoteViewport extends ItkViewport {
@property({ type: String })
address: string | undefined;

remote: RemoteActor;
canvas: Ref<HTMLImageElement> = createRef();
remote: Remote;
frame: any;

Check warning on line 21 in packages/element/src/itk-remote-viewport.ts

View workflow job for this annotation

GitHub Actions / build-test

Unexpected any. Specify a different type

constructor() {
super();
const { remote, viewport } = createRemoteViewport();
const { remote, viewport } = createRemoteViewport(createTestActors());
this.actor = viewport;
this.remote = remote;
this.frame = new SelectorController(
this,
this.remote,
(state) => state?.context.frame
);
const p = new Promise((resolve) => setTimeout(resolve, 5000));
p.then(() => {
this.remote.send({ type: 'render' });
});
}

willUpdate(changedProperties: PropertyValues<this>) {
Expand All @@ -31,6 +43,7 @@ export class RemoteViewport extends ItkViewport {
}

render() {
console.log(this.frame.value);
return html` <h1>Remote viewport</h1>
<img ${ref(this.canvas)}></img>`;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/remote-viewport/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"vite": "^4.3.9"
},
"dependencies": {
"xstate": "5.0.0-beta.8",
"xstate": "5.0.0-beta.18",
"@itk-viewer/viewer": "workspace:^"
}
}
60 changes: 54 additions & 6 deletions packages/remote-viewport/src/remote-machine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,79 @@ import { assign, createMachine } from 'xstate';

type Context = {
address: string | undefined;
server: any | undefined;

Check warning on line 5 in packages/remote-viewport/src/remote-machine.ts

View workflow job for this annotation

GitHub Actions / build-test

Unexpected any. Specify a different type
frame: any | undefined;

Check warning on line 6 in packages/remote-viewport/src/remote-machine.ts

View workflow job for this annotation

GitHub Actions / build-test

Unexpected any. Specify a different type
};

type SetAddressEvent = {
type: 'setAddress';
address: string | undefined;
};

type RenderEvent = {
type: 'render';
};

export const remoteMachine = createMachine({
types: {} as {
context: Context;
events: SetAddressEvent;
events: SetAddressEvent | RenderEvent;
},
id: 'remote',
initial: 'active',
context: { address: undefined },
initial: 'disconnected',
context: { address: undefined, server: undefined, frame: undefined },
states: {
active: {
disconnected: {
on: {
setAddress: {
actions: [
assign({
address: ({ event: { address } }: { event: SetAddressEvent }) =>
address,
address: ({ event: { address } }: { event: SetAddressEvent }) => {
return address;
},
}),
],
target: 'connecting',
},
},
},
connecting: {
invoke: {
id: 'connect',
src: 'connect',
input: ({ context }: { context: Context }) => ({
address: context.address,
}),
onDone: {
actions: assign({
server: ({ event }) => event.output,
}),
target: 'connected',
},
},
},
connected: {
initial: 'render',
states: {
render: {
invoke: {
id: 'render',
src: 'renderer',
input: ({ context }: { context: Context }) => ({
server: context.server,
}),
onDone: {
actions: assign({
frame: ({ event }) => event.output,
}),
target: 'idle',
},
},
},
idle: {
on: {
render: { target: 'render' },
},
},
},
},
Expand Down
18 changes: 7 additions & 11 deletions packages/remote-viewport/src/remote-viewport.cy.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
import { createRemoteViewport } from './remote-viewport.js';
import { createRemoteViewport, createTestActors } from './remote-viewport.js';

describe('remote-viewport', () => {
it('creates', () => {
cy.mount("<div id='viewport'></div>");
it('remote actor saves server address', () => {
const { remote } = createRemoteViewport(createTestActors());

cy.get('#viewport')
.then((parent) => {
const { element } = createRemoteViewport({
address: 'http://localhost:3000',
});
return parent.append(element);
})
.contains('Remote viewport at http://localhost:3000');
const address = 'foo';
remote.send({ type: 'setAddress', address });

cy.wrap(remote.getSnapshot().context.address).should('equal', address);
});
});
37 changes: 32 additions & 5 deletions packages/remote-viewport/src/remote-viewport.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,41 @@
import { createViewport } from '@itk-viewer/viewer/viewport.js';
import { remoteMachine } from './remote-machine.js';
import { interpret } from 'xstate';
import { fromPromise, interpret } from 'xstate';

const createRemote = () => interpret(remoteMachine).start();
type RemoteConfig = {
actors: {
connect: ReturnType<typeof fromPromise<any>>;

Check warning on line 7 in packages/remote-viewport/src/remote-viewport.ts

View workflow job for this annotation

GitHub Actions / build-test

Unexpected any. Specify a different type
renderer: ReturnType<typeof fromPromise<any>>;

Check warning on line 8 in packages/remote-viewport/src/remote-viewport.ts

View workflow job for this annotation

GitHub Actions / build-test

Unexpected any. Specify a different type
};
};

export const createTestActors: () => RemoteConfig = () => ({
actors: {
connect: fromPromise(async ({ input }) => {
console.log('connecting...', input.address);
await new Promise((resolve) => setTimeout(resolve, 1000));
// return { server: 'asdf' };
return 'aServer';
}),
renderer: fromPromise(async ({ input }) => {
console.log('render', input);
await new Promise((resolve) => setTimeout(resolve, 1000));
return { frame: 'new frame here' };
}),
},
});

const createRemote = (config: RemoteConfig) => {
const hyphaMachine = remoteMachine.provide(config);

return interpret(hyphaMachine).start();
};

export type Remote = ReturnType<typeof createRemote>;
export type RemoteActor = ReturnType<typeof createRemote>;

export const createRemoteViewport = () => {
export const createRemoteViewport = (config: RemoteConfig) => {
const viewport = createViewport();
const remote = createRemote();
const remote = createRemote(config);

return { remote, viewport };
};
2 changes: 1 addition & 1 deletion packages/viewer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,6 @@
},
"dependencies": {
"@itk-viewer/io": "workspace:^",
"xstate": "5.0.0-beta.8"
"xstate": "5.0.0-beta.18"
}
}
10 changes: 7 additions & 3 deletions packages/viewer/src/viewport-machine.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { assign, createMachine } from 'xstate';
import { ActorRef, assign, createMachine } from 'xstate';

import MultiscaleSpatialImage from '@itk-viewer/io/MultiscaleSpatialImage.js';
import { Camera } from './camera-machine.js';
Expand Down Expand Up @@ -32,7 +32,11 @@ export const viewportMachine = createMachine({
},
id: 'viewport',
initial: 'active',
context: { image: undefined, camera: undefined },
context: {
image: undefined,
camera: undefined,
cameraSubscription: undefined,
},
states: {
active: {
on: {
Expand All @@ -54,7 +58,7 @@ export const viewportMachine = createMachine({
context.cameraSubscription.unsubscribe();
context.cameraSubscription = context.camera?.subscribe(
(state) => {
self.send({
(self as ActorRef<SetCameraEvent | SetCameraPoseEvent>).send({
type: 'setCameraPose',
pose: state.context.pose,
});
Expand Down
12 changes: 6 additions & 6 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 34eb654

Please sign in to comment.