diff --git a/__tests__/src/components/CanvasThumbnail.test.js b/__tests__/src/components/CanvasThumbnail.test.js index f3fa0904adba3805658180cf95f5ec4df2130b45..9590dd3fa66ed87cdb55da6850c68cbada1f5a97 100644 --- a/__tests__/src/components/CanvasThumbnail.test.js +++ b/__tests__/src/components/CanvasThumbnail.test.js @@ -3,15 +3,22 @@ import { shallow } from 'enzyme'; import IntersectionObserver from '@researchgate/react-intersection-observer'; import { CanvasThumbnail } from '../../../src/components/CanvasThumbnail'; +/** + * Helper function to create a shallow wrapper around CanvasThumbnail + */ +function createWrapper(props) { + return shallow( + <CanvasThumbnail + imageUrl="https://stacks.stanford.edu/image/iiif/sn904cj3429%2F12027000/full/193,/0/default.jpg" + {...props} + />, + ); +} + describe('CanvasThumbnail', () => { let wrapper; beforeEach(() => { - wrapper = shallow( - <CanvasThumbnail - imageUrl="https://stacks.stanford.edu/image/iiif/sn904cj3429%2F12027000/full/193,/0/default.jpg" - onClick={() => {}} - />, - ); + wrapper = createWrapper(); }); it('renders properly', () => { @@ -32,4 +39,30 @@ describe('CanvasThumbnail', () => { wrapper.instance().handleIntersection({ isIntersecting: true }); expect(wrapper.find('img').props().src).toMatch(/stacks/); }); + + it('can be constrained by maxHeight', () => { + wrapper = createWrapper({ maxHeight: 500 }); + + expect(wrapper.find('img').props().style).toMatchObject({ height: 500, width: 'auto' }); + }); + + it('can be constrained by maxWidth', () => { + wrapper = createWrapper({ maxWidth: 500 }); + + expect(wrapper.find('img').props().style).toMatchObject({ height: 'auto', width: 500 }); + }); + + it('can be constrained by maxWidth and maxHeight', () => { + wrapper = createWrapper({ maxHeight: 400, maxWidth: 500 }); + + expect(wrapper.find('img').props().style).toMatchObject({ height: 400, width: 500 }); + }); + + it('can be constrained by maxWidth and maxHeight and a desired aspect ratio', () => { + wrapper = createWrapper({ maxHeight: 400, maxWidth: 500, aspectRatio: 2 }); + expect(wrapper.find('img').props().style).toMatchObject({ height: 250, width: 500 }); + + wrapper = createWrapper({ maxHeight: 400, maxWidth: 500, aspectRatio: 1 }); + expect(wrapper.find('img').props().style).toMatchObject({ height: 400, width: 400 }); + }); }); diff --git a/src/components/CanvasThumbnail.js b/src/components/CanvasThumbnail.js index 87a03bbc15557e3b202903a2131371f2e3496a94..76d14f6905b082503fe7e81f2e8481b8f227bbe0 100644 --- a/src/components/CanvasThumbnail.js +++ b/src/components/CanvasThumbnail.js @@ -49,12 +49,41 @@ export class CanvasThumbnail extends Component { * */ imageStyles() { - const { height, style } = this.props; - const { image } = this.state; + const { + maxHeight, maxWidth, aspectRatio, style, + } = this.props; + + let height; + let width; + + if (maxHeight && maxWidth && aspectRatio) { + const desiredAspectRatio = maxWidth / maxHeight; + + // size to width + if (desiredAspectRatio < aspectRatio) { + height = maxWidth / aspectRatio; + width = maxWidth; + } else { + height = maxHeight; + width = maxHeight * aspectRatio; + } + } else if (maxHeight && maxWidth) { + height = maxHeight; + width = maxWidth; + } else if (maxHeight && !maxWidth) { + height = maxHeight; + width = 'auto'; + } else if (!maxHeight && maxWidth) { + height = 'auto'; + width = maxWidth; + } else { + height = 'auto'; + width = 'auto'; + } return { height, - width: (image && image.src) ? '100%' : '110px', + width, ...style, }; } @@ -86,14 +115,18 @@ CanvasThumbnail.defaultImgPlaceholder = 'data:image/png;base64,iVBORw0KGgoAAAANS CanvasThumbnail.propTypes = { imageUrl: PropTypes.string, isValid: PropTypes.bool, - height: PropTypes.number, onClick: PropTypes.func.isRequired, + maxHeight: PropTypes.number, + maxWidth: PropTypes.number, + aspectRatio: PropTypes.number, style: PropTypes.object, // eslint-disable-line react/forbid-prop-types, }; CanvasThumbnail.defaultProps = { imageUrl: null, isValid: true, - height: 150, + maxHeight: null, + maxWidth: null, + aspectRatio: null, style: {}, }; diff --git a/src/components/ThumbnailNavigation.js b/src/components/ThumbnailNavigation.js index edd162f34c80021b2c7873d4a2c0071ae38b7534..8943df25f5732866bdcc97fb67ab7a546c8f58de 100644 --- a/src/components/ThumbnailNavigation.js +++ b/src/components/ThumbnailNavigation.js @@ -74,7 +74,7 @@ export class ThumbnailNavigation extends Component { <CanvasThumbnail onClick={() => setCanvas(window.id, currentGroupings[0].index)} imageUrl={new ManifestoCanvas(canvas).thumbnail(null, config.thumbnailNavigation.height)} - height={config.thumbnailNavigation.height} + maxHeight={config.thumbnailNavigation.height} /> </div> ))} diff --git a/src/components/WindowSideBarCanvasPanel.js b/src/components/WindowSideBarCanvasPanel.js index cd71348bcd42def01d0cb8c92b74ded9d2827666..8f457b0779afeba32c37a5d47cf57548846c6154 100644 --- a/src/components/WindowSideBarCanvasPanel.js +++ b/src/components/WindowSideBarCanvasPanel.js @@ -12,13 +12,6 @@ import { getIdAndLabelOfCanvases } from '../state/selectors'; * a panel showing the canvases for a given manifest */ export class WindowSideBarCanvasPanel extends Component { - /** - * calculateScaledWidth - calculates the scaled width according to the given width and aspectRatio - */ - static calculateScaledWidth(height, aspectRatio) { - return Math.floor(height * aspectRatio); - } - /** * render */ @@ -48,7 +41,10 @@ export class WindowSideBarCanvasPanel extends Component { <CanvasThumbnail className={classNames(classes.clickable)} isValid={isValid} - imageUrl={manifestoCanvas.thumbnail(config.canvasNavigation.width, config.canvasNavigation.height)} + imageUrl={manifestoCanvas.thumbnail(width, height)} + maxHeight={config.canvasNavigation.height} + maxWidth={config.canvasNavigation.width} + aspectRatio={manifestoCanvas.aspectRatio} onClick={onClick} style={{ cursor: 'pointer',