Reputation: 3658
I am facing issues using react-responsive-carousel
with react-image-magnifiers
I am trying to use carousel over react-image-magnifier library.
I do not get the magnifier effect when using with carousel but when I use react-image-magnifier alone I get the effect.
import { Carousel } from "react-responsive-carousel";
import { SideBySideMagnifier } from "react-image-magnifiers";
import "react-responsive-carousel/lib/styles/carousel.min.css";
export default function ProductSlider() {
const renderCustomThumbs = () => {
return [
<picture>
<source
data-srcSet="https://i.ibb.co/z5CC6P9/AB-10000008011.jpg"
type="image/jpg"
/>
<img
key="01"
src="https://i.ibb.co/z5CC6P9/AB-10000008011.jpg"
alt="First Thumbnail"
height="70"
/>
</picture>,
<picture>
<source
data-srcSet="https://i.ibb.co/z5CC6P9/AB-10000008011.jpg"
type="image/jpg"
/>
<img
key="02"
src="https://i.ibb.co/z5CC6P9/AB-10000008011.jpg"
alt="Second Thumbnail"
height="70"
/>
</picture>
];
};
return (
<>
<h2>With Carousel magnifiers dosen't works </h2>
<div style={{ width: "50%" }}>
<Carousel
showArrows={false}
showStatus={true}
showIndicators={false}
showThumbs={true}
autoPlay={false}
transitionTime={500}
swipeable={false}
emulateTouch={true}
renderThumbs={renderCustomThumbs}
>
<div>
<SideBySideMagnifier
imageSrc="https://i.ibb.co/z5CC6P9/AB-10000008011.jpg"
imageAlt="First Slide"
alwaysInPlace={false}
fillAvailableSpace={true}
fillAlignTop={true}
fillGapRight={10}
fillGapBottom={10}
fillGapTop={10}
fillGapLeft={0}
/>
</div>
<div>
<SideBySideMagnifier
imageSrc="https://i.ibb.co/z5CC6P9/AB-10000008011.jpg"
imageAlt="Second Slide"
alwaysInPlace={false}
fillAvailableSpace={true}
fillAlignTop={true}
fillGapRight={10}
fillGapBottom={10}
fillGapTop={10}
fillGapLeft={0}
/>
</div>
)
</Carousel>
</div>
<h2>Without Carousel magnifiers works </h2>
<div style={{ width: "50%" }}>
<SideBySideMagnifier
imageSrc={"https://i.ibb.co/z5CC6P9/AB-10000008011.jpg"}
alwaysInPlace={false}
fillAvailableSpace={true}
fillAlignTop={true}
fillGapRight={10}
fillGapBottom={10}
fillGapTop={10}
fillGapLeft={0}
/>
</div>
</>
);
}
Upvotes: 1
Views: 2298
Reputation: 4761
The Magnifiers are not showing because the Carousel wrapper is clipping them. The Magnifiers are drawn within each Carousel slide and to the right of each image, but because they're styled with position: absolute
, they aren't included in calculations involving the slide width. The Carousel has overflow: hidden
set so that all content wider than the current slide is not visible; this is why it clips off the Magnifiers.
Fortunately the docs for react-image-magnifiers
indicate that you can get around this by setting up your own layout with the Magnifier outside of the Carousel. You are currently importing the SideBySideMagnifier
component which automatically sets up both the normal and magnified images. Instead we'll use the following custom layout components:
import { MagnifierContainer, MagnifierPreview, MagnifierZoom } from "react-image-magnifiers";
You can have the normal image (MagnifierPreview
) and zoomed image (MagnifierZoom
) in any hierarchy you want - the only constraint is that they must both be children of the MagnifierContainer
component. So we'll wrap the entire carousel in a MagnifierContainer
component.
We want to show the MagnifierZoom
alongside the carousel. Therefore we'll need to set up two wrapper divs side by side. We can do that with a bit of CSS.
<MagnifierContainer>
<div className="magnifier-content">
<div className="magnifier-carousel">
<!-- this will contain the carousel -->
</div>
<div className="magnifier-zoom">
<!-- this will contain the zoomed images -->
</div>
</div>
</MagnifierContainer>
.magnifier-content {
display: flex;
}
.magnifier-content > div {
width: 50%;
}
Now, each image (MagnifierPreview
) will be connected to its zoomed component (MagnifierZoom
) if they have the same imageSrc
property. That is, for every MagnifierPreview
we have, we will also need a MagnifierZoom
component.
The JSX for the carousel looks pretty much like your current code. We'll need to add each zoom element in as well.
Carousel code goes in the magnifier-carousel
element:
<div className="magnifier-carousel">
<Carousel
...
>
<div>
<MagnifierPreview
imageSrc="https://i.ibb.co/z5CC6P9/AB-10000008011.jpg"
imageAlt="First Slide"
...
/>
</div>
<div>
<MagnifierPreview
imageSrc="https://i.ibb.co/z5CC6P9/AB-10000008011.jpg"
imageAlt="Second Slide"
...
/>
</div>
</Carousel>
</div>
Zoom element code codes in the .magnifier-zoom
element:
<div className="magnifier-zoom">
<MagnifierZoom style={{ height: "400px" }} imageSrc="https://i.ibb.co/z5CC6P9/AB-10000008011.jpg"/>
<MagnifierZoom style={{ height: "400px" }} imageSrc="https://i.ibb.co/z5CC6P9/AB-10000008011.jpg"/>
</div>
If you were to run this, you'd find that it works, but the MagnifierZoom
components are both showing. We want to only show the one currently being viewed. To do this we need to set their position to be absolute
, so that we can give them the correct coordinates in their container, and then use a function to hide/show the MagnifierZoom
s whenever the carousel changes.
The CSS to position them, and to hide them except the first one on page load:
.magnifier-zoom {
position: relative;
}
.magnifier-zoom div {
position: absolute!important;
top: 0;
left: 0;
right: 0;
bottom: 0;
opacity: 0;
}
.magnifier-zoom div:first-child {
opacity: 1;
}
The function to change which one is visible when the carousel slide changes:
const showMagnifier = ( current_index ) => {
document.querySelectorAll('.magnifier-zoom div').forEach(( el, image_index ) => {
if ( current_index === image_index ) {
el.style.opacity = '1';
} else {
el.style.opaccity = '0'
}
})
}
We can now add an onChange
property to the Carousel component:
<Carousel
onChange={showMagnifier}
...
>
And this should be working fine!
The complete code for your App.js and styles.css:
import { Carousel } from "react-responsive-carousel";
import { MagnifierContainer, MagnifierPreview, MagnifierZoom, SideBySideMagnifier } from "react-image-magnifiers";
import "react-responsive-carousel/lib/styles/carousel.min.css";
import "./styles.css";
export default function ProductSlider() {
const renderCustomThumbs = () => {
return [
<picture>
<source
data-srcSet="https://i.ibb.co/z5CC6P9/AB-10000008011.jpg"
type="image/jpg"
/>
<img
key="01"
src="https://i.ibb.co/z5CC6P9/AB-10000008011.jpg"
alt="First Thumbnail"
height="70"
/>
</picture>,
<picture>
<source
data-srcSet="https://i.ibb.co/z5CC6P9/AB-10000008011.jpg"
type="image/jpg"
/>
<img
key="02"
src="https://i.ibb.co/z5CC6P9/AB-10000008011.jpg"
alt="Second Thumbnail"
height="70"
/>
</picture>
];
};
const showMagnifier = ( current_index ) => {
document.querySelectorAll('.magnifier-zoom div').forEach(( el, image_index ) => {
if ( current_index === image_index ) {
el.style.opacity = '1';
} else {
el.style.opaccity = '0'
}
})
}
return (
<>
<MagnifierContainer>
<div className="magnifier-content">
<div className="magnifier-carousel">
<Carousel
showArrows={false}
showStatus={true}
showIndicators={true}
showThumbs={true}
autoPlay={false}
transitionTime={500}
swipeable={false}
emulateTouch={true}
renderThumbs={renderCustomThumbs}
onChange={showMagnifier}
>
<div>
<MagnifierPreview
imageSrc="https://i.ibb.co/z5CC6P9/AB-10000008011.jpg"
imageAlt="First Slide"
alwaysInPlace={false}
fillAvailableSpace={true}
fillAlignTop={true}
fillGapRight={10}
fillGapBottom={10}
fillGapTop={10}
fillGapLeft={0}
/>
</div>
<div>
<MagnifierPreview
imageSrc="https://i.ibb.co/z5CC6P9/AB-10000008011.jpg"
imageAlt="Second Slide"
alwaysInPlace={false}
fillAvailableSpace={true}
fillAlignTop={true}
fillGapRight={10}
fillGapBottom={10}
fillGapTop={10}
fillGapLeft={0}
/>
</div>
</Carousel>
</div>
<div className="magnifier-zoom">
<MagnifierZoom style={{ height: "400px" }} imageSrc="https://i.ibb.co/z5CC6P9/AB-10000008011.jpg"/>
<MagnifierZoom style={{ height: "400px" }} imageSrc="https://i.ibb.co/z5CC6P9/AB-10000008011.jpg"/>
</div>
</div>
</MagnifierContainer>
</>
);
}
.App {
font-family: sans-serif;
text-align: center;
}
.magnifier-content {
display: flex;
}
.magnifier-content > div {
width: 50%;
}
.magnifier-zoom {
position: relative;
}
.magnifier-zoom div {
position: absolute!important;
top: 0;
left: 0;
right: 0;
bottom: 0;
opacity: 0;
}
.magnifier-zoom div:first-child {
opacity: 1;
}
Upvotes: 3