Skip to content

Commit

Permalink
enable canvas-panel and image-service to rotate
Browse files Browse the repository at this point in the history
This opens up the rotation parameter in Atlas to CanvasPanel and ImageService.

From what I can tell, the rotation-parameter does not operate properly on a sequence (and likely choices) because it would rotate each canvas separately… but not sure how often we have that as a use-case / need.

I _think_ i’ve wired this through properly so that any change to the `rotation` attribute should rotate the canvas.
  • Loading branch information
abrin committed Jul 3, 2024
1 parent 05780c2 commit da9d784
Show file tree
Hide file tree
Showing 11 changed files with 46 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const TileSet: FC<{
tileFormat?: string;
skipSizes?: boolean;
skipThumbnail?: boolean;
rotation: number;
}> = ({
height,
tiles,
Expand All @@ -24,6 +25,7 @@ export const TileSet: FC<{
style,
skipSizes = false,
skipThumbnail = false,
rotation = 0,
viewport,
tileFormat,
children,
Expand All @@ -50,6 +52,7 @@ export const TileSet: FC<{
height={tiles.height}
width={tiles.width}
x={x}
rotation={rotation}
y={y}
{...(props as any)}
>
Expand Down
1 change: 1 addition & 0 deletions packages/canvas-panel/src/atlas-components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const WorldObject = createAtlasWrapper<{
width: number;
x?: number;
y?: number;
rotation?: number;
}>({
displayName: 'Atlas.WorldObject',
component: Atlas.WorldObject,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ interface AtlasCanvasProps {
textEnabled?: boolean;
disableThumbnail?: boolean;
skipSizes?: boolean;
rotation?: number;
}

export function AtlasCanvas({
Expand All @@ -62,6 +63,7 @@ export function AtlasCanvas({
textEnabled,
disableThumbnail,
skipSizes,
rotation,
}: AtlasCanvasProps) {
const manifest = useManifest();
const canvas = useCanvas();
Expand Down Expand Up @@ -177,7 +179,6 @@ export function AtlasCanvas({
}, [defaultChoices]);

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

if (!canvas) {
return null;
}
Expand Down Expand Up @@ -263,7 +264,6 @@ export function AtlasCanvas({
) : null}
</Fragment>
);

return (
<WorldObject key={strategy.type} height={canvas.height} width={canvas.width} x={x} y={y} {...elementProps}>
{strategy.type === 'images'
Expand All @@ -274,6 +274,7 @@ export function AtlasCanvas({
key={image.id}
image={image}
id={image.id}
rotation={rotation}
annotationId={image.annotationId}
thumbnail={idx === 0 && !disableThumbnail ? (thumbnail as any) : undefined}
virtualSizes={virtualSizes}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export function RenderImage({
virtualSizes = [],
x = 0,
y = 0,
rotation = 0,
annotations,
tileFormat,
skipSizes,
Expand All @@ -29,6 +30,7 @@ export function RenderImage({
virtualSizes?: SizeParameter[];
x?: number;
y?: number;
rotation?: number;
annotations?: JSX.Element;
tileFormat?: string;
skipSizes?: boolean;
Expand All @@ -41,7 +43,6 @@ export function RenderImage({
const style = useMemo(() => ({ ...annotationStyles, ...resourceStyle }), [annotationStyles, resourceStyle]);
const events = useResourceEvents(annotationId ? { id: annotationId, type: 'Annotation' } : undefined, ['atlas']);
const resourceEvents = useResourceEvents({ id, type: 'ContentResource' }, ['atlas']);

return (
<React.Fragment>
{!image.service ? (
Expand Down Expand Up @@ -78,6 +79,7 @@ export function RenderImage({
skipThumbnail={skipThumbnail}
x={image.target?.spatial.x + x}
y={image.target?.spatial.y + y}
rotation={rotation}
width={image.target?.spatial.width}
height={image.target?.spatial.height}
style={style}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export function ViewCanvas(props: ViewCanvasProps) {
const manifest = useManifest();
const manager = useAnnotationPageManager(manifest?.id || canvas?.id);
const [annoMode, setAnnoMode] = useState(false);
const rotation = props.rotation || 0;
const aspectRatio =
!props.displayOptions.viewport && canvas
? props.displayOptions.homePosition
Expand Down Expand Up @@ -129,6 +130,7 @@ export function ViewCanvas(props: ViewCanvasProps) {
defaultChoices={props.defaultChoices}
disableThumbnail={props.disableThumbnail}
skipSizes={props.skipSizes}
rotation={rotation}
onCreated={(e: any) => {
if (manifest && canvas && e) {
navigator.clipboard.writeText(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export type AtlasDisplayOptions = AtlasProps & {
aspectRatio?: number;
viewport?: boolean;
responsive?: boolean;
rotation?: number;
};

export type ViewCanvasProps = {
Expand All @@ -34,4 +35,5 @@ export type ViewCanvasProps = {
disableThumbnail?: boolean;
skipSizes?: boolean;
homeCover?: boolean | 'start' | 'end';
rotation?: number;
};
10 changes: 9 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 @@ -127,6 +127,8 @@ export function useGenericAtlasProps<T = Record<never, never>>(props: GenericAtl
}
);

const [rotation, setRotation, , rotationRef] = useSyncedState(props.rotation, { parse: parseNumber });

const [highlight, setHighlight, , highlightRef] = useSyncedState(props.highlight || internalConfig.highlight, {
parse: parseOptionalSelector,
});
Expand Down Expand Up @@ -472,7 +474,12 @@ export function useGenericAtlasProps<T = Record<never, never>>(props: GenericAtl
styles,
thumbnailHelper: thumbs,
imageServiceLoader: loader,

getRotation: () => {
return rotationRef.current;
},
setRotation: (newRotation: string | number) => {
htmlComponent.setAttribute('rotation', newRotation.toString());
},
getHighlight: () => {
return highlightRef.current;
},
Expand Down Expand Up @@ -863,6 +870,7 @@ export function useGenericAtlasProps<T = Record<never, never>>(props: GenericAtl
nested,
x,
y,
rotation,
homeCover,
useProp,
useRegisterWebComponentApi,
Expand Down
1 change: 1 addition & 0 deletions packages/canvas-panel/src/types/generic-atlas-component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export type GenericAtlasComponent<T = Record<never, never>, Props = any> = T & {
class?: string;
x?: number | string;
y?: number | string;
rotation?: number | string;
nested?: boolean | string;
enableNavigator?: boolean;
enablePanOnWait?: boolean;
Expand Down
6 changes: 5 additions & 1 deletion packages/canvas-panel/src/web-components/canvas-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { CanvasContext, VaultProvider } from 'react-iiif-vault';
import { RegisterPublicApi, UseRegisterPublicApi } from '../hooks/use-register-public-api';
import { ViewCanvas } from '../components/ViewCanvas/ViewCanvas';
import { ManifestLoader } from '../components/manifest-loader';
import { parseBool, parseChoices, parseContentStateParameter } from '../helpers/parse-attributes';
import { parseBool, parseChoices, parseContentStateParameter, parseNumber } from '../helpers/parse-attributes';
import { normaliseAxis, parseContentState, serialiseContentState } from '../helpers/content-state/content-state';
import { normaliseContentState } from '../helpers/content-state/content-state';
import { GenericAtlasComponent } from '../types/generic-atlas-component';
Expand All @@ -30,6 +30,7 @@ export type CanvasPanelProps = GenericAtlasComponent<
textEnabled?: 'true' | 'false' | boolean;
followAnnotations?: boolean;
iiifContent?: string;
rotation?: number;
},
UseRegisterPublicApi['properties']
>;
Expand All @@ -45,6 +46,7 @@ const canvasPanelAttributes = [
'follow-annotations',
'iiif-content',
'home-cover',
'rotation',
];

export const CanvasPanel: FC<CanvasPanelProps> = (props) => {
Expand Down Expand Up @@ -80,6 +82,7 @@ export const CanvasPanel: FC<CanvasPanelProps> = (props) => {
parse: parseContentStateParameter,
});
const [canvasId, setCanvasId, , canvasIdRef] = useProp('canvasId');
const [rotation, setRotation, , rotationRef] = useProp('rotation', { parse: parseNumber, defaultValue: 0 });
const [manifestId, setManifestId, , manifestIdRef] = useProp('manifestId');
const [followAnnotations] = useProp('followAnnotations', { parse: parseBool, defaultValue: true });
const [defaultChoices, , , defaultChoiceIdsRef] = useProp('choiceId', { parse: parseChoices });
Expand Down Expand Up @@ -314,6 +317,7 @@ export const CanvasPanel: FC<CanvasPanelProps> = (props) => {
canvasId={canvasId}
displayOptions={atlasProps}
mode={mode}
rotation={rotation || 0}
x={x}
y={y}
textEnabled={textEnabled}
Expand Down
8 changes: 6 additions & 2 deletions packages/canvas-panel/src/web-components/image-service.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@ import { ErrorFallback } from '../components/ErrorFallback/ErrorFallback';
import { ErrorBoundary as _ErrorBoundary } from 'react-error-boundary';
import { useGenericAtlasProps } from '../hooks/use-generic-atlas-props';
import { GenericAtlasComponent } from '../types/generic-atlas-component';
import { parseBool } from '../helpers/parse-attributes';
import { parseBool, parseNumber } from '../helpers/parse-attributes';
import { ImageServiceLoader } from '@atlas-viewer/iiif-image-api';
import { World } from '../atlas-components';

const ErrorBoundary = _ErrorBoundary as any;

Expand All @@ -29,6 +28,7 @@ export type ImageServiceProps = GenericAtlasComponent<
nested?: string;
x?: number;
y?: number;
rotation?: number;
tileFormat?: string;
children?: any;
skipSizes?: boolean | 'true' | 'false';
Expand Down Expand Up @@ -60,6 +60,7 @@ export function ImageService(props: ImageServiceProps) {

const [src] = useProp('src');
const [nested] = useProp('nested', { parse: parseBool });
const [rotation] = useProp('rotation', { parse: parseNumber });
const [tileFormat, setTileFormat] = useProp('tileFormat');
const [skipSizes] = useProp('skipSizes', { parse: parseBool });
const [disableThumbnail] = useProp('disableThumbnail', { parse: parseBool });
Expand Down Expand Up @@ -130,6 +131,7 @@ export function ImageService(props: ImageServiceProps) {
nested={nested}
homeCover={homeCover}
homeOnResize={!!homeCover}
rotation={rotation}
{...atlasProps}
>
<RenderImage
Expand All @@ -142,6 +144,7 @@ export function ImageService(props: ImageServiceProps) {
skipThumbnail={disableThumbnail}
x={x}
y={y}
rotation={rotation}
tileFormat={tileFormat}
/>
</NestedAtlas>
Expand Down Expand Up @@ -196,6 +199,7 @@ if (typeof window !== 'undefined') {
'granular-move-events',
'home-cover',
'tile-format',
'rotation',
],
{
shadow: true,
Expand Down
12 changes: 11 additions & 1 deletion packages/storybook/src/stories/canvas-panel.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ export const ChangingCanvases = () => {
</>
}

export const RotateCanvas = () => {

const [rotation, setRotation] = useState(0);
return <>
<button onClick={()=>{setRotation((rotation + 90) % 360)}}>Rotate Canvas</button>
{/* @ts-ignore */}
<canvas-panel manifest-id={welcome} canvas-id={canvases[0]} rotation={rotation} />
</>
}

export const CanvasWithNavigator = () => {
{/* @ts-ignore */}
return <canvas-panel manifest-id={welcome} canvas-id={canvases[0]} enable-navigator="true" />;
Expand Down Expand Up @@ -54,7 +64,7 @@ export const CanvasWithLandscapeZoom = () => {

export const CanvasWithGettyTouchInteractions = () => {
{/* @ts-ignore */}
return <canvas-panel manifest-id={welcome} canvas-id={canvases[0]} enable-single-finger-touch='false' enable-pan-on-wait='true' pan-on-wait-delay='40' require-meta-key-for-wheel-zoom='true' />;
return <canvas-panel manifest-id={welcome} canvas-id={canvases[0]} ignore-single-finger-touch='false' enable-pan-on-wait='true' pan-on-wait-delay='40' require-meta-key-for-wheel-zoom='true' />;

}

Expand Down

0 comments on commit da9d784

Please sign in to comment.