Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import {
getIiifLeafletMapOptions,
getIiifMaxNativeZoom,
getIiifTileUrl,
IIIF_MIN_ZOOM,
normalizeIiifImageServiceId,
resizeIiifTileToNaturalSize,
} from '../../geoblacklight/iiif_image_layer';

const baseTileOptions = {
Expand Down Expand Up @@ -56,11 +58,28 @@ describe('Leaflet IIIF helpers', () => {
expect(options.gestureHandling).toBe(true);
expect(options.maxBounds.contains(bounds)).toBe(true);
expect(options.maxZoom).toBe(3);
expect(options.minZoom).toBe(0);
expect(options.minZoom).toBe(IIIF_MIN_ZOOM);
expect(options.scrollWheelZoom).toBe(true);
expect(options.zoom).toBe(0);
});

it('allows large CONTENTdm scans to fit by zooming out below native IIIF zoom 0', () => {
const maxNativeZoom = getIiifMaxNativeZoom(8826, 11246, 1024);
const bounds = getIiifImageBounds(Leaflet, 8826, 11246, maxNativeZoom);
const options = getIiifLeafletMapOptions(
Leaflet,
bounds,
maxNativeZoom,
{ SLEEP: false },
{}
);

expect(maxNativeZoom).toBe(4);
expect(bounds.getNorthEast().lng).toBeCloseTo(551.625);
expect(bounds.getSouthWest().lat).toBeCloseTo(-702.875);
expect(options.minZoom).toBe(-5);
});

it('normalizes IIIF service ids from info.json metadata', () => {
expect(
normalizeIiifImageServiceId('https://example.com/fallback/info.json', {
Expand All @@ -80,6 +99,20 @@ describe('Leaflet IIIF helpers', () => {
);
});

it('clamps display zooms below the native IIIF pyramid to zoom 0 tile requests', () => {
expect(
getIiifTileUrl({
...baseTileOptions,
coords: { x: 0, y: 0, z: -2 },
})
).toBe(
getIiifTileUrl({
...baseTileOptions,
coords: { x: 0, y: 0, z: 0 },
})
);
});

it('clips IIIF edge tiles to the image dimensions', () => {
expect(
getIiifTileUrl({
Expand Down Expand Up @@ -111,4 +144,26 @@ describe('Leaflet IIIF helpers', () => {
})
).toBe(EMPTY_IIIF_TILE_URL);
});

it('resizes non-square IIIF tiles to their natural image dimensions', () => {
const tile = document.createElement('img');
Object.defineProperty(tile, 'naturalWidth', { value: 552 });
Object.defineProperty(tile, 'naturalHeight', { value: 703 });

resizeIiifTileToNaturalSize(tile, 1024);

expect(tile.style.width).toBe('552px');
expect(tile.style.height).toBe('703px');
});

it('leaves full-size square IIIF tiles alone', () => {
const tile = document.createElement('img');
Object.defineProperty(tile, 'naturalWidth', { value: 1024 });
Object.defineProperty(tile, 'naturalHeight', { value: 1024 });

resizeIiifTileToNaturalSize(tile, 1024);

expect(tile.style.width).toBe('');
expect(tile.style.height).toBe('');
});
});
13 changes: 12 additions & 1 deletion frontend/src/geoblacklight/iiif_image_layer.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export const EMPTY_IIIF_TILE_URL =
'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=';
export const IIIF_MIN_ZOOM = -5;

function getInfoId(info) {
const id = info.id ?? info['@id'];
Expand Down Expand Up @@ -111,6 +112,16 @@ export function getIiifTileUrl({
return `${baseUrl}/${region}/${size}/0/${tileQuality}.${tileFormat}`;
}

export function resizeIiifTileToNaturalSize(tile, tileSize) {
const { naturalHeight, naturalWidth } = tile;

if (!naturalHeight || !naturalWidth) return;
if (naturalHeight === tileSize && naturalWidth === tileSize) return;

tile.style.width = `${naturalWidth}px`;
tile.style.height = `${naturalHeight}px`;
}

export async function fetchIiifImageInfo(imageServiceOrInfoUrl) {
const base = imageServiceOrInfoUrl.replace(/\/$/, '');
const infoUrl = base.endsWith('/info.json') ? base : `${base}/info.json`;
Expand Down Expand Up @@ -143,7 +154,7 @@ export function getIiifLeafletMapOptions(
maxBounds: imageBounds.pad(0.5),
maxBoundsViscosity: 0.5,
maxZoom: maxNativeZoom,
minZoom: 0,
minZoom: IIIF_MIN_ZOOM,
preferCanvas: false,
zoom: 0,
};
Expand Down
13 changes: 7 additions & 6 deletions frontend/src/geoblacklight/leaflet_viewer_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import {
getIiifTileFormat,
getIiifTileSize,
getIiifTileUrl,
IIIF_MIN_ZOOM,
normalizeIiifImageServiceId,
resizeIiifTileToNaturalSize,
} from './iiif_image_layer';

function buildIiifTileLayer(options) {
Expand All @@ -38,6 +40,9 @@ function buildIiifTileLayer(options) {
updateWhenIdle: true,
});
layer.maxNativeZoom = options.maxNativeZoom || 0;
layer.on('tileload', ({ tile }) => {
resizeIiifTileToNaturalSize(tile, options.tileSize);
});
return layer;
}

Expand Down Expand Up @@ -157,7 +162,8 @@ export default class LeafletViewerController extends BaseLeafletViewerController
imageWidth: width,
maxNativeZoom,
maxZoom: maxNativeZoom,
minZoom: 0,
minNativeZoom: 0,
minZoom: IIIF_MIN_ZOOM,
serviceId: normalizeIiifImageServiceId(this.urlValue, info),
tileFormat: getIiifTileFormat(info),
tileQuality: 'default',
Expand Down Expand Up @@ -214,11 +220,6 @@ export default class LeafletViewerController extends BaseLeafletViewerController
}

addIiifControls() {
if (this.availableValue && this.previewOverlay) {
const opacityControl = this.getControl('Opacity');
if (opacityControl) this.addControl(opacityControl);
}

const fullscreenControl = this.getControl('Fullscreen');
if (fullscreenControl) this.addControl(fullscreenControl);
}
Expand Down
Loading