Comparing version 0.3.0 to 0.4.0
214
fitobject.js
/** | ||
* @preserve fitobject - v0.3.0 - 2017-05-11 | ||
* @preserve fitobject - v0.4.0 - 2017-05-11 | ||
* Size and position an object to fit its container. | ||
@@ -17,89 +17,133 @@ * https://github.com/dannydb/fitobject | ||
}(this, function($) { | ||
var $object = null; | ||
var $container = null; | ||
var $objectWrapper = null; | ||
var objectRatio = null; | ||
var containerRatio = null; | ||
var isShallowObject = null; | ||
var fullObjectHeight = null; | ||
var fullObjectWidth = null; | ||
var horizontalOffset = null; | ||
var verticalOffset = null; | ||
var options = { | ||
fit: 'cover', | ||
safeArea: { | ||
'top': 0, | ||
'right': 0, | ||
'bottom': 0, | ||
'left': 0 | ||
} | ||
} | ||
var fitObject = function (params) { | ||
var $els = $(this); | ||
/** | ||
* Given an object and its container, size and position the object to fit | ||
* the container based on the fit parameter according to the behavior of the | ||
* 'cover' and 'contain' values of the CSS background-size property. | ||
* @author: Danny DeBelius | ||
* @param {Object} object A jQuery-wrapped DOM element | ||
* @param {Object} container A jQuery-wrapped DOM element | ||
* @param {Object} params Configuration options | ||
*/ | ||
var fitObject = function (object, container, params) { | ||
var newCss = null; | ||
$els.each(function(index, el) { | ||
var $object = $(this); | ||
var $container = null; | ||
var $objectWrapper = null; | ||
var objectRatio = null; | ||
var containerRatio = null; | ||
var isShallowObject = null; | ||
var fullObject = {}; | ||
var offset = {}; | ||
var cropped = {}; | ||
var newCss = null; | ||
if (params) { | ||
options = $.extend(options, params); | ||
} | ||
var options = { | ||
container: null, | ||
fit: 'cover', | ||
safeArea: { | ||
'top': 0, | ||
'right': 0, | ||
'bottom': 0, | ||
'left': 0 | ||
} | ||
} | ||
$object = $(object); | ||
$container = $(container); | ||
$objectWrapper = $container.find('.object-fit-wrapper'); | ||
$objectWrapper = $object.parents('.fit-object-wrapper'); | ||
objectRatio = $object.innerHeight() / $object.width(); | ||
containerRatio = $container.height() / $container.width(); | ||
isShallowObject = objectRatio < containerRatio; | ||
if ($object.data('safe-area')) { | ||
options['safeArea'] = $object.data('safe-area'); | ||
} | ||
fullObjectHeight = $container.width() * objectRatio; | ||
fullObjectWidth = $container.height() / objectRatio; | ||
if ($object.data('object-fit')) { | ||
options['fit'] = $object.data('fit'); | ||
} | ||
horizontalOffset = ($container.width() - fullObjectWidth) / 2; | ||
verticalOffset = ($container.height() - fullObjectHeight) / 2; | ||
if ($object.data('fit-container')) { | ||
options['container'] = $object.data('fit-container'); | ||
} | ||
if (options['fit'] === 'cover' && isShallowObject){ | ||
newCss = { | ||
height: $container.height(), | ||
width: fullObjectWidth, | ||
left: handleCropBias(horizontalOffset, 'horizontal'), | ||
top: 0 | ||
if (params) { | ||
options = $.extend(options, params); | ||
} | ||
} | ||
if (options['fit'] === 'cover' && !isShallowObject){ | ||
newCss = { | ||
height: fullObjectHeight, | ||
width: $container.width(), | ||
left: 0, | ||
top: handleCropBias(verticalOffset, 'vertical') | ||
if ($objectWrapper.length === 0 && options['container'] === null) { | ||
$container = $object.parent(); | ||
} else if (options['container'] === null) { | ||
$container = $objectWrapper.parent(); | ||
} else { | ||
$container = $(options['container']); | ||
} | ||
} | ||
if (options['fit'] === 'contain' && isShallowObject){ | ||
newCss = { | ||
height: fullObjectHeight, | ||
width: $container.width(), | ||
left: 0, | ||
top: verticalOffset | ||
// Make sure the container has dimensions before starting calculations. | ||
$container.css({ | ||
'display': 'block', | ||
'visibility': 'visible' | ||
}); | ||
// Calculate object and container aspect ratios | ||
objectRatio = $object.innerHeight() / $object.width(); | ||
containerRatio = $container.height() / $container.width(); | ||
isShallowObject = objectRatio < containerRatio; | ||
// Calculate full object dimensions to be cropped | ||
fullObject['height'] = $container.width() * objectRatio; | ||
fullObject['width'] = $container.height() / objectRatio; | ||
// Calculate the pixels hidden by the cover fit crop | ||
cropped['x'] = fullObject['width'] - $container.width(); | ||
cropped['y'] = fullObject['height'] - $container.height(); | ||
// Calculate the centering offset | ||
offset['x'] = ($container.width() - fullObject['width']) / 2; | ||
offset['y'] = ($container.height() - fullObject['height']) / 2; | ||
// Cover image cropped horizontally | ||
if (options['fit'] === 'cover' && isShallowObject){ | ||
newCss = { | ||
height: $container.height(), | ||
width: fullObject['width'], | ||
left: getSafeOffset('horizontal', offset['x'], cropped['x'], options), | ||
top: 0 | ||
} | ||
} | ||
} | ||
if (options['fit'] === 'contain' && !isShallowObject){ | ||
newCss = { | ||
height: $container.height(), | ||
width: fullObjectWidth, | ||
left: horizontalOffset, | ||
top: 0 | ||
// Cover image cropped vertically | ||
if (options['fit'] === 'cover' && !isShallowObject){ | ||
newCss = { | ||
height: fullObject['height'], | ||
width: $container.width(), | ||
left: 0, | ||
top: getSafeOffset('vertical', offset['y'], cropped['y'], options) | ||
} | ||
} | ||
} | ||
// Contained image compressed horizontally | ||
if (options['fit'] === 'contain' && isShallowObject){ | ||
newCss = { | ||
height: fullObject['height'], | ||
width: $container.width(), | ||
left: 0, | ||
top: offset['y'] | ||
} | ||
} | ||
// Contained image compressed vertically | ||
if (options['fit'] === 'contain' && !isShallowObject){ | ||
newCss = { | ||
height: $container.height(), | ||
width: fullObject['width'], | ||
left: offset['x'], | ||
top: 0 | ||
} | ||
} | ||
// Remove the inline style applied before calculations. | ||
$container.attr('style', null); | ||
updatePosition($object, $objectWrapper, $container, newCss); | ||
}) | ||
} | ||
/** | ||
* Apply the new position CSS to the object | ||
* @param {Object} $object The object | ||
* @param {Object} $objectWrapper The object fit wrapper | ||
* @param {Object} $container The object's container | ||
* @param {Object} newCss The new object position styles | ||
*/ | ||
var updatePosition = function($object, $objectWrapper, $container, newCss) { | ||
$.extend(newCss, { | ||
@@ -112,3 +156,3 @@ 'position': 'absolute' | ||
if ($objectWrapper.length < 1) { | ||
$objectWrapper = $('<div class="object-fit-wrapper"></div>'); | ||
$objectWrapper = $('<div class="fit-object-wrapper"></div>'); | ||
$objectWrapper.css(newCss); | ||
@@ -129,26 +173,23 @@ $object.wrap($objectWrapper); | ||
} | ||
} | ||
} | ||
/** | ||
* Modify the offset to avoid cropping into a safe area | ||
* Adapted from NYT5-foundation's responsive-image.js | ||
* @param {Number} offset The original centering offset | ||
* @param {String} direction Either 'vertical' or 'horizontal' | ||
* @param {Object} safeArea Area to avoid cropping into | ||
* @param {Number} offset The centering offset for the overflow dimension | ||
* @param {Number} cropped The pixels cropped on the overflow dimension | ||
* @param {Object} options The fitObject params | ||
* @return {Number} The modified offset | ||
*/ | ||
var handleCropBias = function (offset, direction) { | ||
var getSafeOffset = function (direction, offset, cropped, options) { | ||
var safeArea = options['safeArea']; | ||
var verticalBias = (safeArea['bottom'] - safeArea['top']) / 100; | ||
var horizontalBias = (safeArea['right'] - safeArea['left']) / 100; | ||
var pixelsCropped = null; | ||
if (direction === 'horizontal') { | ||
pixelsCropped = fullObjectWidth - $container.width(); | ||
offset += pixelsCropped * horizontalBias; | ||
offset += cropped * horizontalBias; | ||
} | ||
if (direction === 'vertical') { | ||
pixelsCropped = fullObjectHeight - $container.height(); | ||
offset += pixelsCropped * verticalBias; | ||
offset += cropped * verticalBias; | ||
} | ||
@@ -162,4 +203,4 @@ | ||
// Make sure the biased offset covers the right and bottom | ||
if (offset < -pixelsCropped) { | ||
offset = -pixelsCropped | ||
if (offset < -cropped) { | ||
offset = -cropped | ||
} | ||
@@ -170,4 +211,5 @@ | ||
return fitObject; | ||
$.fn.fitObject = fitObject; | ||
// return fitObject; | ||
})); |
{ | ||
"name": "fitobject", | ||
"version": "0.3.0", | ||
"version": "0.4.0", | ||
"description": "Fit an object to its container.", | ||
@@ -5,0 +5,0 @@ "main": "fitobject.js", |
@@ -14,7 +14,4 @@ # fitobject | ||
To do a simple cover fit of an object to a container, call `fitObject` with two arguments: | ||
For simple cover fitting of an object to a container: | ||
- A selector or jQuery wrapped DOM element for the object. | ||
- A selector or jQuery wrapped DOM element for the container. | ||
```html | ||
@@ -26,16 +23,16 @@ <div class="container"> | ||
<script> | ||
fitObject('.object', '.container'); | ||
$('.object').fitObject(); | ||
</script> | ||
``` | ||
You can also size and position the object to be totally contained inside the container, as with the CSS property `background-size: contain`. | ||
You can size and position the object to be totally contained inside the container, as with the CSS property `background-size: contain`: | ||
```js | ||
fitObject('.object', '.container', { | ||
$('.object').fitObject({ | ||
'fit': 'contain' | ||
}); | ||
``` | ||
Finally, `fitObject` also accepts a `safeArea` parameter to define a region of the object to avoid cropping into when the object fit method is set to `'cover'`. | ||
### Cover fit safe area | ||
Specify a `safeArea` parameter to define a region of the object to avoid cropping into when the object fit method is set to `'cover'`. | ||
@@ -45,4 +42,3 @@ <img src="https://cloud.githubusercontent.com/assets/419297/25910766/8b30a470-357f-11e7-850e-d11e7889f4ed.png" width="400" /> | ||
```js | ||
fitObject('.object', '.container', { | ||
'fit': 'cover', | ||
$('.object').fitObject({ | ||
'safeArea': { | ||
@@ -56,1 +52,46 @@ 'top': 25, // 25% of the vertical dimension from the top | ||
``` | ||
### Non-immediate ancestor fit container | ||
By default, `fitObject` will fit your object to its immediate parent, but can fit to ancestors further up the DOM tree by setting the `container` parameter: | ||
```html | ||
<div class="container-wrapper"> | ||
<div class="container"> | ||
<img class="object" src="http://placehold.it/400x300" /> | ||
</div> | ||
</div> | ||
<script> | ||
$('.object').fitObject({ | ||
'container': '.container-wrapper' | ||
}); | ||
</script> | ||
``` | ||
### Object data attributes | ||
Each of the `fitObject` parameters can be set via HTML data attributes on the object to fit: | ||
```html | ||
<div class="container"> | ||
<img class="object" src="http://placehold.it/400x300" | ||
data-object-fit="cover" | ||
data-fit-container=".container" | ||
data-safe-area="{'top':0,'right':21.23,'bottom':0,'left':19.33}" | ||
/> | ||
</div> | ||
<script> | ||
$('.object').fitObject(); | ||
</script> | ||
``` | ||
Object data attributes will supercede parameters passed into the `fitObject` method. | ||
## List of parameters | ||
|Parameter | Data Attribute | Type | Default | Description | | ||
|-|-|-|-|-| | ||
| `container` | `fit-container` | String, DOM Node or jQuery DOM element | | The container to fit the object to | | ||
| `fit` | `object-fit` | String | `'cover'` | The fit method – either `'cover'` or `'contain'` | | ||
| `safeArea` | `safe-area` | Object | ` { 'top': 0, 'right': 0, 'bottom': 0, 'left': 0 }` | An area of the object to avoid cropping into. Specify a percentage of the X or Y dimension for each side. | |
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
12191
6
177
94
2