Show loading spinner when image is being loaded

This commit is contained in:
Kimmo Puputti 2018-03-14 16:32:27 +02:00
parent ff99ffc8f6
commit e721889de4
2 changed files with 54 additions and 5 deletions

View file

@ -96,7 +96,27 @@
}
}
.loading {
position: absolute;
top: 50%;
left: 50%;
width: 50px;
height: 50px;
margin-left: -25px;
margin-top: -25px;
opacity: 0;
}
.loadingVisible {
opacity: 1;
transition: opacity var(--transitionStyle);
}
.image {
/* Fit image in the available space as big as possible, keeping the aspect ratio */
object-fit: contain;
}
.imageLoading {
opacity: 0.5;
}

View file

@ -2,7 +2,7 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { injectIntl, intlShape } from 'react-intl';
import classNames from 'classnames';
import { ResponsiveImage } from '../../components';
import { ResponsiveImage, IconSpinner } from '../../components';
import { propTypes } from '../../util/types';
import css from './ImageCarousel.css';
@ -18,7 +18,7 @@ const imageScaledXLarge = 'scaled-xlarge'; // width 2400
class ImageCarousel extends Component {
constructor(props) {
super(props);
this.state = { selectedImageIndex: 0 };
this.state = { selectedImageIndex: 0, selectedImageLoaded: false };
this.onKeyUp = this.onKeyUp.bind(this);
this.prev = this.prev.bind(this);
this.next = this.next.bind(this);
@ -38,16 +38,22 @@ class ImageCarousel extends Component {
}
prev() {
const count = this.props.images.length;
if (count < 2) {
return;
}
this.setState(prevState => {
const newIndex = count > 0 ? (count + prevState.selectedImageIndex - 1) % count : 0;
return { selectedImageIndex: newIndex };
return { selectedImageIndex: newIndex, selectedImageLoaded: false };
});
}
next() {
const count = this.props.images.length;
if (count < 2) {
return;
}
this.setState(prevState => {
const newIndex = count > 0 ? (count + prevState.selectedImageIndex + 1) % count : 0;
return { selectedImageIndex: newIndex };
return { selectedImageIndex: newIndex, selectedImageLoaded: false };
});
}
render() {
@ -76,13 +82,36 @@ class ImageCarousel extends Component {
}
);
const markImageLoaded = index => () => {
this.setState(prevState => {
if (prevState.selectedImageIndex === index) {
// Only mark the image loaded if the current index hasn't
// changed, i.e. user hasn't already changed to another
// image index.
return { selectedImageLoaded: true };
}
return {};
});
};
const currentImageIsLoaded = images.length === 0 || this.state.selectedImageLoaded;
const loadingIconClasses = classNames(css.loading, {
[css.loadingVisible]: !currentImageIsLoaded,
});
const imageClasses = classNames(css.image, {
[css.imageLoading]: !currentImageIsLoaded,
});
return (
<div className={classes}>
<div className={css.imageWrapper}>
<IconSpinner className={loadingIconClasses} />
<ResponsiveImage
className={css.image}
className={imageClasses}
alt={imageAltText}
image={images[this.state.selectedImageIndex]}
onLoad={markImageLoaded(this.state.selectedImageIndex)}
onError={markImageLoaded(this.state.selectedImageIndex)}
nameSet={[
{ name: imageScaledSmall, size: '320w' },
{ name: imageScaledMedium, size: '750w' },