Skip to content

Commit

Permalink
Merge pull request #253 from abrin/complex_choices
Browse files Browse the repository at this point in the history
adding support for complex choices
  • Loading branch information
stephenwf authored Apr 5, 2024
2 parents a05137e + be99c73 commit c0fc5a8
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 9 deletions.
70 changes: 64 additions & 6 deletions packages/canvas-panel/src/components/AtlasCanvas/AtlasCanvas.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React, { FC, useEffect, useLayoutEffect, useMemo } from 'preact/compat';
import {
useCanvas,
useResources,
parseSpecificResource,
useResourceEvents,
useRenderingStrategy,
useThumbnail,
Expand All @@ -9,7 +11,7 @@ import {
useAnnotationPageManager,
useManifest,
} from 'react-iiif-vault';
import { createStylesHelper } from '@iiif/vault-helpers';
import { createStylesHelper, SingleChoice, createPaintingAnnotationsHelper } from '@iiif/vault-helpers';
import { Fragment, h } from 'preact';
import { WorldObject, SingleImage } from '../../atlas-components';
import { RenderAnnotationPage } from '../RenderAnnotationPage/RenderAnnotationPage';
Expand All @@ -24,6 +26,7 @@ import { RenderVideo } from '../RenderVideo/RenderVideo';
import { RenderTextLines } from '../RenderTextLines/RenderTextLines';
import { sortAnnotationPages } from '../../helpers/sort-annotation-pages';
import { choiceEventChannel } from '../../helpers/eventbus';
import { AnnotationPageNormalized, ContentResource } from '@iiif/presentation-3';

interface AtlasCanvasProps {
x?: number;
Expand Down Expand Up @@ -70,14 +73,73 @@ export function AtlasCanvas({
strategies: ['images', 'media'],
defaultChoices: defaultChoices?.map(({ id }) => id),
});
const choice = strategy.type === 'images' ? strategy.choice : undefined;

const manager = useAnnotationPageManager(manifest?.id || canvas?.id);
const fullPages = useVaultSelector(
(state, vault) => {
return manager.availablePageIds.map((i) => vault.get(i));
},
[...manager.availablePageIds]
);

useEffect(() => {
// this is all hoisted from https://github.com/IIIF-Commons/iiif-helpers/blob/0f582fbcf4a8899258b7a71d2216ffeb56275de4/src/painting-annotations/helper.ts#L38
// BUT... it doesn't work there because it assumes there's a single choice per page
const vaulthelper = createPaintingAnnotationsHelper(vault);
// get all painting annotations for a canvas
if (canvas?.id) {
const enabledChoices = defaultChoices?.map(({ id }) => id) || [];
const vaultAnnotations = vaulthelper.getAllPaintingAnnotations(canvas.id);
// Extract choices (if any) from a canvas

for (const annotation of vaultAnnotations) {
if (annotation.type !== 'Annotation') {
throw new Error(`getPaintables() accept either a canvas or list of annotations`);
}

const references = Array.from(Array.isArray(annotation.body) ? annotation.body : [annotation.body]);
for (const reference of references) {
const [ref, { selector }] = parseSpecificResource(reference as any);
const body = vault.get(ref) as any;
const type = (body.type || 'unknown').toLowerCase();
// Choice
if (type !== 'choice') {
continue;
}
const nestedBodies = vault.get(body.items) as ContentResource[];

// if the enabledChoices has the id, then turn it on, otherwise choose the 1st item
const selected = enabledChoices.length
? enabledChoices.map((cid) => nestedBodies.find((b) => b.id === cid)).filter(Boolean)
: [nestedBodies[0]];

if (selected.length === 0) {
selected.push(nestedBodies[0]);
}
const choice: SingleChoice = {
type: 'single-choice',
items: nestedBodies.map((b) => ({
id: b.id,
label: (b as any).label as any,
selected: selected.indexOf(b) !== -1,
})) as any[],
label: (ref as any).label,
};
choiceEventChannel.emit('onChoiceChange', {
choice,
partOf: {
canvasId: canvas.id,
choiceId: body.id,
manifestId: manifest?.id,
},
});
}
}
// this returns 1 choice
const choices = vaulthelper.extractChoices(canvas.id);
}
}, [canvas?.id, actions, defaultChoices]);

const pageTypes = useMemo(() => sortAnnotationPages(manager.availablePageIds, vault as any), fullPages);
const hasTextLines = !!pageTypes.pageMapping.supplementing?.length;
const firstTextLines = hasTextLines ? pageTypes.pageMapping.supplementing[0] : null;
Expand Down Expand Up @@ -114,10 +176,6 @@ export function AtlasCanvas({
}
}, [defaultChoices]);

useLayoutEffect(() => {
choiceEventChannel.emit('onChoiceChange', { choice });
}, [choice]);

const thumbnail = useThumbnail({ maxWidth: 256, maxHeight: 256 });

if (!canvas) {
Expand Down
9 changes: 8 additions & 1 deletion packages/canvas-panel/src/helpers/eventbus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,14 @@ export const choiceEventChannel = eventbus<{
* @param payload - the id and options for the choice
*
*/
onChoiceChange: (payload: { choice?: ChoiceDescription }) => void;
onChoiceChange: (payload: {
choice?: ChoiceDescription;
partOf?: {
choiceId?: string;
canvasId?: string;
manifestId?: string;
};
}) => void;
/**
* When a canvas is changed, or a sequence is changed, this signals that
* the current set of choices should be reset
Expand Down
3 changes: 2 additions & 1 deletion packages/canvas-panel/src/hooks/use-generic-atlas-props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ export function useGenericAtlasProps<T = Record<never, never>>(props: GenericAtl
seenChoices.current = {};
});

const onChoiceChange = (payload: { choice?: ChoiceDescription }) => {
const onChoiceChange = (payload: { choice?: ChoiceDescription, partOf?: any }) => {
const choice = payload.choice;
// sort the choices by ID in order to help with de-duping
if (webComponent?.current && choice && choice.items) {
Expand All @@ -181,6 +181,7 @@ export function useGenericAtlasProps<T = Record<never, never>>(props: GenericAtl
(seenChoices.current as any)[key] = value;
// move this outside the IF if we want to fire on every page

(choice as any).partOf = payload.partOf;
webComponent.current.dispatchEvent(new CustomEvent('choice', { detail: { choice } }));
}
};
Expand Down
3 changes: 2 additions & 1 deletion packages/storybook/src/stories/sequence-panel.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export const SequencePanel = () => {



const bayard="https://gist.githubusercontent.com/danieltbrennan/183d6cbb0948948413394cf116e5844a/raw/11fdda729f0c2960ee1d971902cdf0badd7f31df/bayard_w_choices.json"
const bayard="https://data.getty.edu/media/manifest/bayard-custom"

export const MakingChoice = () => {
const viewer = useRef()
Expand Down Expand Up @@ -135,6 +135,7 @@ export const MakingChoice = () => {
<div>
<button onClick={() => viewer.current.sequence.setCurrentCanvasIndex(3)}>Go to: Canvas Index 3</button>
<button onClick={() => viewer.current.sequence.setCurrentCanvasIndex(11)}>Go to: Canvas Index 11</button>
<button onClick={() => viewer.current.sequence.setCurrentCanvasIndex(28)}>Go to: Canvas Index 28</button>
<button onClick={() => viewer.current.sequence.previousCanvas()}>Prev</button>
<button onClick={() => viewer.current.sequence.nextCanvas()}>Next</button>

Expand Down

0 comments on commit c0fc5a8

Please sign in to comment.