Basic Example
-
+
Side by Side enlargement for mouse input.
-
+
In place enlargement for touch input.
-
+
Fluid between breakpoints.
-
+
Initial file size optimized via
srcSet
@@ -76,10 +76,10 @@ export default class BasicExample extends Component {
attributes.
-
+
Please see
-
+
source code
diff --git a/example/src/pages/App.css b/example/src/pages/app.css
similarity index 80%
rename from example/src/pages/App.css
rename to example/src/pages/app.css
index 630f58e6..ec8e789a 100644
--- a/example/src/pages/App.css
+++ b/example/src/pages/app.css
@@ -14,6 +14,11 @@ body {
margin: 0 20px;
}
+.fixed__instructions {
+ flex: 1;
+ margin: 0 20px;
+}
+
a {
color: black;
}
@@ -40,4 +45,9 @@ a:hover {
flex: 0 0 50%;
padding-top: 30px;
}
+
+ .fixed__instructions {
+ padding-top: 30px;
+ margin: 0 10px;
+ }
}
diff --git a/example/src/pages/react-slick.css b/example/src/pages/react-slick.css
index 714aa13e..f1bb6814 100644
--- a/example/src/pages/react-slick.css
+++ b/example/src/pages/react-slick.css
@@ -1,7 +1,7 @@
@import "~slick-carousel/slick/slick.css";
@import "~slick-carousel/slick/slick-theme.css";
-* {
+.react-slick * {
min-height: 0;
min-width: 0;
}
diff --git a/example/src/router.js b/example/src/router.js
index 8d61d62a..8c2f41ae 100644
--- a/example/src/router.js
+++ b/example/src/router.js
@@ -3,11 +3,15 @@ import { Router, Route } from 'react-router';
import SideBySide from './pages/SideBySide';
import ReactSlick from './pages/ReactSlick';
+import EnlargedImageContainerDimensions from './pages/EnlargedImageContainerDimensions';
+import FixedWidthSmallImage from './pages/FixedWidthSmallImage';
const Routes = (props) => (
+
+
);
diff --git a/src/EnlargedImage.js b/src/EnlargedImage.js
index eb5c7e1c..4091e6a8 100644
--- a/src/EnlargedImage.js
+++ b/src/EnlargedImage.js
@@ -43,7 +43,10 @@ export default class extends React.Component {
isActive: PropTypes.bool,
isLazyLoaded: PropTypes.bool,
largeImage: ImageShape,
- smallImage: ImageShape,
+ containerDimensions: PropTypes.shape({
+ width: PropTypes.number,
+ height: PropTypes.number
+ }),
imagePosition: PropTypes.oneOf([
ENLARGED_IMAGE_POSITION.beside,
ENLARGED_IMAGE_POSITION.over
@@ -128,26 +131,28 @@ export default class extends React.Component {
imagePosition,
cursorOffset,
largeImage,
- smallImage,
- position
+ containerDimensions,
+ position,
+ smallImage
} = this.props;
const { over: OVER } = ENLARGED_IMAGE_POSITION;
const isInPlaceMode = imagePosition === OVER;
if (isInPlaceMode) {
- return getInPlaceEnlargedImageCoordinates(
- smallImage,
+ return getInPlaceEnlargedImageCoordinates({
+ containerDimensions,
largeImage,
position
- );
+ });
}
- return getLensModeEnlargedImageCoordinates(
- smallImage,
+ return getLensModeEnlargedImageCoordinates({
+ containerDimensions,
+ cursorOffset,
largeImage,
position,
- cursorOffset
- );
+ smallImage
+ });
}
render() {
@@ -163,7 +168,7 @@ export default class extends React.Component {
onLoad = noop,
onError = noop
},
- smallImage,
+ containerDimensions,
} = this.props;
const {
@@ -175,8 +180,8 @@ export default class extends React.Component {
const defaultContainerStyle = this.getDefaultContainerStyle();
const computedContainerStyle = {
- width: smallImage.width,
- height: smallImage.height,
+ width: containerDimensions.width,
+ height: containerDimensions.height,
opacity: this.state.isTransitionActive ? 1 : 0,
transition: `opacity ${fadeDurationInMs}ms ease-in`,
pointerEvents: 'none'
diff --git a/src/ReactImageMagnify.js b/src/ReactImageMagnify.js
index f39b2965..3e451497 100644
--- a/src/ReactImageMagnify.js
+++ b/src/ReactImageMagnify.js
@@ -8,6 +8,10 @@ import requiredIf from 'react-required-if';
import DisplayUntilActive from './hint/DisplayUntilActive';
import EnlargedImage from './EnlargedImage';
import { getLensCursorOffset } from './lib/lens';
+import {
+ getEnlargedImageContainerDimension,
+ getDefaultEnlargedImageContainerDimensions
+} from './lib/dimensions';
import Hint from './hint/DefaultHint';
import ShadedLens from './shaded-lens';
import ImageShape from './prop-types/ImageShape';
@@ -50,6 +54,7 @@ class ReactImageMagnify extends React.Component {
enlargedImageContainerStyle: PropTypes.object,
enlargedImageClassName: PropTypes.string,
enlargedImageStyle: PropTypes.object,
+ enlargedImageContainerDimensions: PropTypes.object,
fadeDurationInMs: PropTypes.number,
hintComponent: PropTypes.func,
shouldHideHintAfterFirstActivation: PropTypes.bool,
@@ -84,6 +89,10 @@ class ReactImageMagnify extends React.Component {
};
static defaultProps = {
+ enlargedImageContainerDimensions: {
+ width: '100%',
+ height: '100%'
+ },
fadeDurationInMs: 300,
hintComponent: Hint,
shouldHideHintAfterFirstActivation: true,
@@ -169,6 +178,65 @@ class ReactImageMagnify extends React.Component {
return userDefinedEnlargedImagePosition || computedEnlargedImagePosition;
}
+ get smallImage() {
+ const {
+ smallImage,
+ smallImage: {
+ isFluidWidth: isSmallImageFluidWidth
+ },
+ } = this.props;
+ const {
+ smallImageWidth,
+ smallImageHeight
+ } = this.state;
+
+ const fluidWidthSmallImage = objectAssign(
+ {},
+ smallImage,
+ {
+ width: smallImageWidth,
+ height: smallImageHeight
+ }
+ );
+ const fixedWidthSmallImage = smallImage;
+
+ return isSmallImageFluidWidth
+ ? fluidWidthSmallImage
+ : fixedWidthSmallImage
+ }
+
+ get isInPlaceMode() {
+ return this.getEnlargedImagePlacement() === ENLARGED_IMAGE_POSITION.over;
+ }
+
+ get enlargedImageContainerDimensions() {
+ const {
+ enlargedImageContainerDimensions: {
+ width: containerWidth,
+ height: containerHeight
+ }
+ } = this.props;
+ const {
+ width: smallImageWidth,
+ height: smallImageHeight
+ } = this.smallImage;
+
+ if (this.isInPlaceMode) {
+ return getDefaultEnlargedImageContainerDimensions(this.smallImage);
+ }
+
+ return {
+ width: getEnlargedImageContainerDimension({
+ containerDimension: containerWidth,
+ smallImageDimension: smallImageWidth
+ }),
+ height: getEnlargedImageContainerDimension({
+ containerDimension: containerHeight,
+ smallImageDimension: smallImageHeight
+ })
+ };
+ }
+
render() {
const {
className,
@@ -198,29 +266,14 @@ class ReactImageMagnify extends React.Component {
style,
} = this.props;
+ const smallImage = this.smallImage;
+
const {
- smallImageWidth,
- smallImageHeight,
detectedInputType: {
isTouchDetected
}
} = this.state;
- const fluidWidthSmallImage = objectAssign(
- {},
- this.props.smallImage,
- {
- width: smallImageWidth,
- height: smallImageHeight
- }
- );
-
- const fixedWidthSmallImage = this.props.smallImage;
-
- const smallImage = isSmallImageFluidWidth
- ? fluidWidthSmallImage
- : fixedWidthSmallImage
-
const fluidWidthContainerStyle = {
width: 'auto',
height: 'auto',
@@ -270,7 +323,9 @@ class ReactImageMagnify extends React.Component {
!isTouchDetected
);
- const cursorOffset = getLensCursorOffset(smallImage, largeImage);
+ const enlargedImageContainerDimensions = this.enlargedImageContainerDimensions;
+
+ const cursorOffset = getLensCursorOffset(smallImage, largeImage, enlargedImageContainerDimensions);
return (
}
{
const expected = 'width:3px;height:4px;opacity:1;transition:opacity 0ms ease-in;pointer-events:none';
const renderedWrapper = shallowWrapper.render();
-
expect(renderedWrapper.attr('style').endsWith(expected)).to.be.true;
});
@@ -415,6 +414,10 @@ describe('Enlarged Image', () => {
it('computes max coordinates and applies the result to CSS transfrom translate', () => {
shallowWrapper.setProps({
+ containerDimensions: {
+ width: 4,
+ height: 4
+ },
cursorOffset: {
x: 0,
y: 0
@@ -483,6 +486,10 @@ describe('Enlarged Image', () => {
});
const props = {
+ containerDimensions: {
+ width: 3,
+ height: 4
+ },
cursorOffset: {
x: 0,
y: 0
diff --git a/test/lib/dimensions.spec.js b/test/lib/dimensions.spec.js
new file mode 100644
index 00000000..167e4e1f
--- /dev/null
+++ b/test/lib/dimensions.spec.js
@@ -0,0 +1,59 @@
+import { expect } from 'chai';
+import {
+ convertPercentageToDecimal,
+ getDefaultEnlargedImageContainerDimensions,
+ getEnlargedImageContainerDimension,
+ isPercentageFormat
+} from '../../src/lib/dimensions';
+
+describe('Dimensions Library', () => {
+ describe('isPercentageFormat', () => {
+ it('returns true when input is formatted as a percentage', () => {
+ const actual = isPercentageFormat('100%');
+ expect(actual).to.be.true;
+ });
+
+ it('returns false when input is not formatted as a percentage', () => {
+ expect(isPercentageFormat('100')).to.be.false;
+ expect(isPercentageFormat(100)).to.be.false;
+ })
+ });
+
+ describe('convertPercentageToDecimal', () => {
+ it('returns a decimal number for percentage input', () => {
+ expect(convertPercentageToDecimal('75%')).to.equal(0.75);
+ });
+ });
+
+ describe('getEnlargedImageContainerDimension', () => {
+ it('returns correct value when container dimension is a percentage', () => {
+ const actual = getEnlargedImageContainerDimension({
+ containerDimension: '50%',
+ smallImageDimension: 2
+ });
+
+ expect(actual).to.equal(1);
+ });
+
+ it('returns correct value when container dimension is a number', () => {
+ const actual = getEnlargedImageContainerDimension({
+ containerDimension: 4,
+ smallImageDimension: 2
+ });
+
+ expect(actual).to.equal(4);
+ });
+ });
+
+ describe('getDefaultEnlargedImageContainerDimensions', () => {
+ it('returns correct default enlarged image container dimensions', () => {
+ const smallImage = {
+ width: 1,
+ height: 2
+ };
+ const actual = getDefaultEnlargedImageContainerDimensions(smallImage);
+
+ expect(actual).to.deep.equal(smallImage);
+ });
+ });
+});
diff --git a/test/lib/image-coordinates.spec.js b/test/lib/image-coordinates.spec.js
index 2d7f30f5..31347448 100644
--- a/test/lib/image-coordinates.spec.js
+++ b/test/lib/image-coordinates.spec.js
@@ -1,5 +1,4 @@
import { expect } from 'chai';
-import { getLensCursorOffset } from '../../src/lib/lens';
import {
getLensModeEnlargedImageCoordinates,
getInPlaceEnlargedImageCoordinates
@@ -8,6 +7,10 @@ import {
describe('Image Coordinates Library', () => {
describe('getLensModeEnlargedImageCoordinates', () => {
it('returns image coordinates relative to its container', () => {
+ const enlargedImageContainerDimensions = {
+ width: 4,
+ height: 4
+ };
const smallImage = {
width: 4,
height: 4
@@ -20,18 +23,24 @@ describe('Image Coordinates Library', () => {
x: 2,
y: 2
};
- const lensCursorOffset = getLensCursorOffset(smallImage, largeImage);
- const expected = {
- x: -2,
- y: -2
- };
+ const lensCursorOffset = { x: 1, y: 1 };
- const actual = getLensModeEnlargedImageCoordinates(smallImage, largeImage, position, lensCursorOffset);
+ const actual = getLensModeEnlargedImageCoordinates({
+ smallImage,
+ largeImage,
+ position,
+ cursorOffset: lensCursorOffset,
+ containerDimensions: enlargedImageContainerDimensions
+ });
- expect(actual).to.deep.equal(expected);
+ expect(actual).to.deep.equal({ x: -2, y: -2 });
});
it('clamps position according to lens', () => {
+ const enlargedImageContainerDimensions = {
+ width: 4,
+ height: 4
+ };
const smallImage = {
width: 4,
height: 4
@@ -44,21 +53,23 @@ describe('Image Coordinates Library', () => {
x: 1,
y: 3
};
- const lensCursorOffset = getLensCursorOffset(smallImage, largeImage);
- const expected = {
- x: -0,
- y: -4
- };
+ const lensCursorOffset = { x: 1, y: 1 };
- const actual = getLensModeEnlargedImageCoordinates(smallImage, largeImage, position, lensCursorOffset);
+ const actual = getLensModeEnlargedImageCoordinates({
+ smallImage,
+ largeImage,
+ position,
+ cursorOffset: lensCursorOffset,
+ containerDimensions: enlargedImageContainerDimensions
+ });
- expect(actual).to.deep.equal(expected);
+ expect(actual).to.deep.equal({ x: -0, y: -4 });
});
});
describe('getInPlaceEnlargedImageCoordinates', () => {
it('returns image coordinates relative to its container', () => {
- const container = {
+ const containerDimensions = {
width: 4,
height: 4
};
@@ -70,18 +81,14 @@ describe('Image Coordinates Library', () => {
x: 2,
y: 2
};
- const expected = {
- x: -2,
- y: -2
- };
- const actual = getInPlaceEnlargedImageCoordinates(container, largeImage, position);
+ const actual = getInPlaceEnlargedImageCoordinates({ containerDimensions, largeImage, position });
- expect(actual).to.deep.equal(expected);
+ expect(actual).to.deep.equal({ x: -2, y: -2 });
});
it('clamps coordinates to the container when position is outside', () => {
- const container = {
+ const containerDimensions = {
width: 4,
height: 4
};
@@ -93,14 +100,10 @@ describe('Image Coordinates Library', () => {
x: 5,
y: -1
};
- const expected = {
- x: -4,
- y: 0
- };
- const actual = getInPlaceEnlargedImageCoordinates(container, largeImage, position);
+ const actual = getInPlaceEnlargedImageCoordinates({ containerDimensions, largeImage, position });
- expect(actual).to.deep.equal(expected);
+ expect(actual).to.deep.equal({ x: -4, y: 0 });
});
});
});
diff --git a/test/lib/lens.spec.js b/test/lib/lens.spec.js
index cac497a5..92a47ea2 100644
--- a/test/lib/lens.spec.js
+++ b/test/lib/lens.spec.js
@@ -4,6 +4,10 @@ import { getLensCursorOffset } from '../../src/lib/lens';
describe('Lens Library', () => {
describe('getLensCursorOffset', () => {
it('returns a point representing the offset from the cursor to the top-left of the clear lens', () => {
+ const enlargedImageContainerDimensions = {
+ width: 4,
+ height: 4
+ };
const smallImage = {
width: 4,
height: 4
@@ -17,12 +21,16 @@ describe('Lens Library', () => {
y: 1
}
- const actual = getLensCursorOffset(smallImage, largeImage);
+ const actual = getLensCursorOffset(smallImage, largeImage, enlargedImageContainerDimensions);
expect(actual).to.deep.equal(expected);
});
it('rounds values', () => {
+ const enlargedImageContainerDimensions = {
+ width: 4,
+ height: 6
+ };
const smallImage = {
width: 4,
height: 6
@@ -36,7 +44,7 @@ describe('Lens Library', () => {
y: 2 // rounded up from 1.5
}
- const actual = getLensCursorOffset(smallImage, largeImage);
+ const actual = getLensCursorOffset(smallImage, largeImage, enlargedImageContainerDimensions);
expect(actual).to.deep.equal(expected);
});
diff --git a/test/react-image-magnify.spec.js b/test/react-image-magnify.spec.js
index 821fd828..3ab17bfb 100644
--- a/test/react-image-magnify.spec.js
+++ b/test/react-image-magnify.spec.js
@@ -76,6 +76,10 @@ describe('React Image Magnify', () => {
it('has correct default props', () => {
expect(ReactImageMagnify.defaultProps).to.deep.equal({
+ enlargedImageContainerDimensions: {
+ width: '100%',
+ height: '100%'
+ },
fadeDurationInMs: 300,
hoverDelayInMs: 250,
hoverOffDelayInMs: 150,