Skip to content
This repository was archived by the owner on Jan 26, 2024. It is now read-only.

Commit 700a01f

Browse files
authored
Merge pull request #23 from benox3/inview
Render only images that are in view
2 parents 9ed0cea + 9973450 commit 700a01f

File tree

12 files changed

+335
-62
lines changed

12 files changed

+335
-62
lines changed

README.md

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
# react-pic
22

3-
[![NPM](https://nodei.co/npm/react-pic.png)](https://nodei.co/npm/react-pic/)
4-
53
[![NPM version](https://img.shields.io/npm/v/react-pic.svg)](https://www.npmjs.com/package/react-pic)
64
[![Build Status](https://travis-ci.org/benox3/react-pic.svg?branch=master)](https://travis-ci.org/benox3/react-pic)
75
[![Coverage Status](https://coveralls.io/repos/github/benox3/react-pic/badge.svg?branch=master)](https://coveralls.io/github/benox3/react-pic?branch=master)
@@ -50,13 +48,17 @@ export default class Example extends Component {
5048

5149
## Props
5250

53-
| name | required | type | description |
54-
|--------------|----------|--------|----------------------------------------------------------------------------------------------------------------------------|
55-
| images | true | Array | The collection of images you would like to use as a source. |
56-
| alt | false | string | Text equivalent of the image. https://www.w3.org/QA/Tips/altAttribute |
57-
| defaultIndex | false | Number | The image object to use on initial render. **Default is 0** |
58-
| noscriptIndex | false | Number | The image object to use on noscript render. **Default is last image in images** |
59-
| style | false | Object | Override the style object. **This will remove the default style:** `{ margin: '0 auto', maxWidth: '100%', width: '100%' }` |
51+
| name | default | required | type | description |
52+
|--------------|----------|--------|----------|-----------------------------------------------------------------------------------------------------------------|
53+
| images | | true | array | The collection of images you would like to use as a source. |
54+
| alt | | false | string | Text equivalent of the image. https://www.w3.org/QA/Tips/altAttribute |
55+
| defaultIndex | 0 | false | number | The image object to use on initial render. |
56+
| noscriptIndex | `images.length-1` | false | number | The image object to use on noscript render. |
57+
| baseStyle | `{ position: 'relative', margin: '-5px', overflow: 'hidden' }` | false | object | Override the container style object. |
58+
| imgStyle | `{ margin: '0 auto', maxWidth: '100%', width: '100%' }` | false | object | Override the image style object. |
59+
| shouldBlur | true | false | boolean | Determines if the image should be blurred before setting the optimal image. |
60+
| blurAmmount | '10px' | false | string | The ammount of blur. Expected format: '10px' or '15%'. |
61+
| renderOutOfView | false | false | boolean | Determines if the optimal image should be selected even if not in view |
6062

6163
## Special Thanks
6264

lib/ImageClient.js

Lines changed: 0 additions & 14 deletions
This file was deleted.

lib/ImageServer.js

Lines changed: 0 additions & 22 deletions
This file was deleted.

lib/client/index.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import React, { Component } from 'react';
2+
import Image from '../common/Image';
3+
import shallowCompare from 'react-addons-shallow-compare';
4+
5+
export default class ImageClient extends Component {
6+
shouldComponentUpdate(nextProps, nextState) {
7+
return shallowCompare(this, nextProps, nextState);
8+
}
9+
10+
render() {
11+
return (
12+
<Image {...this.props} />
13+
);
14+
}
15+
}

lib/common/Image.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import React, { Component } from 'react';
2+
3+
export default class Image extends Component {
4+
getStyle() {
5+
const { imgStyle, isBlurred, blurAmmount } = this.props;
6+
7+
if (isBlurred) {
8+
return {
9+
...imgStyle,
10+
filter: `blur(${blurAmmount})`
11+
};
12+
}
13+
14+
return imgStyle;
15+
}
16+
17+
render() {
18+
const { alt, image } = this.props;
19+
return (
20+
<img
21+
alt={alt}
22+
style={this.getStyle()}
23+
src={image.url} />
24+
);
25+
}
26+
}

lib/index.js

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import React, { Component } from 'react';
22
import getResponsiveImage from './utils/getResponsiveImage';
33
import debounce from './utils/debounce';
4-
import Image from './ImageServer';
4+
import isElementInView from './utils/isElementInView';
5+
import ImageBase from './server/';
56

67
/**
78
* Pic Component
@@ -14,23 +15,39 @@ export default class Pic extends Component {
1415
noScriptImage: props.noscriptIndex ?
1516
props.images[props.noScriptIndex] :
1617
props.images[props.images.length-1],
17-
isMounted: false
18+
isBlurred: props.shouldBlur
1819
};
1920

2021
this.setResponsiveImage = this.setResponsiveImage.bind(this);
2122
}
2223

2324
componentDidMount() {
24-
this.setResponsiveImage();
25+
// set optimal image if in view or if elected to render out of view on mount
26+
this.props.renderOutOfView ? this.setResponsiveImage(): this.inViewHandler();
2527

26-
this.setState({
27-
isMounted: true
28-
});
28+
// set responsive image on scroll
29+
window.addEventListener('scroll', debounce(() => {
30+
this.inViewHandler();
31+
}, 150));
2932

3033
// set responsive image on resize
3134
window.addEventListener('resize', debounce(this.setResponsiveImage, 150));
3235
}
3336

37+
componentWillUnmount() {
38+
window.removeEventListener('scroll', debounce(() => {
39+
this.inViewHandler();
40+
}, 150));
41+
42+
window.removeEventListener('resize', debounce(this.setResponsiveImage, 150));
43+
}
44+
45+
inViewHandler() {
46+
if (isElementInView(this.refs.base)) {
47+
this.setResponsiveImage();
48+
}
49+
}
50+
3451
/**
3552
* Set the optimal image src
3653
*/
@@ -45,7 +62,8 @@ export default class Pic extends Component {
4562
this.state.image
4663
);
4764
this.setState({
48-
image: responsiveImage
65+
image: responsiveImage,
66+
isBlurred: false
4967
});
5068
} catch (e) {
5169
// failed to update image
@@ -58,10 +76,8 @@ export default class Pic extends Component {
5876
}
5977

6078
return (
61-
<div ref='base' style={{
62-
position: 'relative'
63-
}}>
64-
<Image {...this.props} {...this.state} />
79+
<div ref='base' style={this.props.baseStyle}>
80+
<ImageBase {...this.props} {...this.state} />
6581
</div>
6682
);
6783
}
@@ -71,12 +87,20 @@ export default class Pic extends Component {
7187
Pic.defaultProps = {
7288
alt: '',
7389
defaultIndex: 0,
74-
style: {
90+
shouldBlur: true,
91+
blurAmmount: '10px',
92+
baseStyle: {
93+
position: 'relative',
94+
margin: '-5px',
95+
overflow: 'hidden'
96+
},
97+
imgStyle: {
7598
margin: '0 auto',
7699
maxWidth: '100%',
77100
width: '100%'
78101
},
79-
images:[]
102+
images: [],
103+
renderIfOutOfView: false
80104
};
81105

82106
/** Prop Types */
@@ -108,5 +132,10 @@ Pic.propTypes = {
108132
},
109133
defaultIndex: React.PropTypes.number, // The default image to render
110134
noscriptIndex: React.PropTypes.number, // The default image to render on noscript
111-
alt: React.PropTypes.string
135+
alt: React.PropTypes.string,
136+
imgStyle: React.PropTypes.object,
137+
baseStyle: React.PropTypes.object,
138+
shouldBlur: React.PropTypes.bool,
139+
blurAmmount: React.PropTypes.string,
140+
renderOutOfView: React.PropTypes.bool
112141
};
File renamed without changes.

lib/server/index.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import React, { Component } from 'react';
2+
import NoScriptImg from './NoScriptImg';
3+
import Image from '../common/Image';
4+
import shallowCompare from 'react-addons-shallow-compare';
5+
6+
export default class ImageServer extends Component {
7+
shouldComponentUpdate(nextProps, nextState) {
8+
return shallowCompare(this, nextProps, nextState);
9+
}
10+
11+
render() {
12+
const {
13+
alt,
14+
style,
15+
noScriptImage
16+
} = this.props;
17+
18+
return (
19+
<div>
20+
<NoScriptImg
21+
alt={alt}
22+
image={noScriptImage}
23+
style={style} />
24+
25+
<Image {...this.props} />
26+
</div>
27+
);
28+
}
29+
}

lib/utils/isElementInView.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/**
2+
* Check if an element is in view.
3+
* @param {HTMLElement} el - The element to check.
4+
* @return {Boolean}
5+
*/
6+
export default function isElementInView (el) {
7+
const rect = el.getBoundingClientRect();
8+
9+
return (
10+
rect.bottom > 0 &&
11+
rect.right > 0 &&
12+
rect.left < (window.innerWidth || document.documentElement.clientWidth) &&
13+
rect.top < (window.innerHeight || document.documentElement.clientHeight)
14+
);
15+
}

package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-pic",
3-
"version": "0.0.8",
3+
"version": "0.0.9",
44
"description": "React component for progressive and responsive image loading.",
55
"author": "Ben Budnevich",
66
"main": "dist/commonjs/react-pic.js",
@@ -41,6 +41,9 @@
4141
"bugs": {
4242
"url": "https://github.com/benox3/react-pic/issues"
4343
},
44+
"dependencies": {
45+
"react-addons-shallow-compare": "0.14.x || ^15.0.0-0 || 15.x"
46+
},
4447
"devDependencies": {
4548
"babel-cli": "^6.16.0",
4649
"babel-core": "^6.17.0",
@@ -74,7 +77,7 @@
7477
"react-dom": "0.14.x || ^15.0.0-0 || 15.x"
7578
},
7679
"browser": {
77-
"./lib/ImageServer.js": "./lib/ImageClient.js"
80+
"./lib/server/index.js": "./lib/client/index.js"
7881
},
7982
"license": "MIT"
8083
}

0 commit comments

Comments
 (0)