<link href="//netdna.bootstrapcdn.com/bootstrap/3.1.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<script src="//netdna.bootstrapcdn.com/bootstrap/3.1.0/js/bootstrap.min.js"></script>
<script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
<!------ Include the above in your HEAD tag ---------->
<!doctype html>
<html>
<head>
<title>Zoom</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
</head>
<body>
<nav class="navbar navbar-default" role="navigation">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header ">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand zoom" href="#">Brand</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="active"><a href="#">Link</a></li>
<li><a href="#">Link</a></li>
<li><a href="#">Link</a></li>
<li><a href="#">Link</a></li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
<script>
Array.prototype.forEach.call(document.querySelectorAll('p'), function (p, i) {
p.style.marginLeft = i * 6 + '%'
})
Zoomerang
.config({
maxHeight: 400,
maxWidth: 400,
bgColor: '#000',
bgOpacity: .85,
onOpen: openCallback,
onClose: closeCallback
})
.listen('.zoom')
function openCallback (el) {
console.log('zoomed in on: ')
console.log(el)
}
function closeCallback (el) {
console.log('zoomed out on: ')
console.log(el)
}
</script>
</body>
</html>
.zoom {
cursor: pointer;
}
/*
* zoomerang.js - http://yyx990803.github.io/zoomerang/
*/
(function () {
// regex
var percentageRE = /^([\d\.]+)%$/
// elements
var overlay = document.createElement('div'),
wrapper = document.createElement('div'),
target,
parent,
placeholder
// state
var shown = false,
lock = false,
originalStyles
// options
var options = {
transitionDuration: '.4s',
transitionTimingFunction: 'cubic-bezier(.4,0,0,1)',
bgColor: '#fff',
bgOpacity: 1,
maxWidth: 300,
maxHeight: 300,
onOpen: null,
onClose: null
}
// compatibility stuff
var trans = sniffTransition(),
transitionProp = trans.transition,
transformProp = trans.transform,
transformCssProp = transformProp.replace(/(.*)Transform/, '-$1-transform'),
transEndEvent = trans.transEnd
setStyle(overlay, {
position: 'fixed',
display: 'none',
zIndex: 99998,
top: 0,
left: 0,
right: 0,
bottom: 0,
opacity: 0,
backgroundColor: options.bgColor,
transition: 'opacity ' +
options.transitionDuration + ' ' +
options.transitionTimingFunction
})
setStyle(wrapper, {
position: 'fixed',
zIndex: 99999,
top: '50%',
left: '50%',
width: 0,
height: 0
})
// helpers ----------------------------------------------------------------
function setStyle (el, styles, remember) {
checkTrans(styles)
var s = el.style,
original = {}
for (var key in styles) {
if (remember) {
original[key] = s[key] || ''
}
s[key] = styles[key]
}
return original
}
function sniffTransition () {
var ret = {},
trans = ['webkitTransition', 'transition', 'mozTransition'],
tform = ['webkitTransform', 'transform', 'mozTransform'],
end = {
'transition' : 'transitionend',
'mozTransition' : 'transitionend',
'webkitTransition' : 'webkitTransitionEnd'
}
trans.some(function (prop) {
if (overlay.style[prop] !== undefined) {
ret.transition = prop
ret.transEnd = end[prop]
return true
}
})
tform.some(function (prop) {
if (overlay.style[prop] !== undefined) {
ret.transform = prop
return true
}
})
return ret
}
function checkTrans (styles) {
if (styles.transition) {
styles[transitionProp] = styles.transition
}
if (styles.transform) {
styles[transformProp] = styles.transform
}
}
var stylesToCopy = [
'position', 'display', 'float',
'top', 'left', 'right', 'bottom',
'marginBottom', 'marginLeft', 'marginRight',
'marginTop', 'font', 'lineHeight', 'verticalAlign'
]
function copy (el, box) {
var styles = getComputedStyle(el),
ph = document.createElement('div'),
i = stylesToCopy.length, key
while (i--) {
key = stylesToCopy[i]
ph.style[key] = styles[key]
}
setStyle(ph, {
visibility: 'hidden',
width: box.width + 'px',
height: box.height + 'px',
display: styles.display === 'inline'
? 'inline-block'
: styles.display
})
if (options.deepCopy) {
ph.innerHTML = el.innerHTML
} else {
ph.textContent = el.textContent
}
return ph
}
var api = {
config: function (opts) {
if (!opts) return options
for (var key in opts) {
options[key] = opts[key]
}
setStyle(overlay, {
backgroundColor: options.bgColor,
transition: 'opacity ' +
options.transitionDuration + ' ' +
options.transitionTimingFunction
})
return this
},
open: function (el, cb) {
if (shown || lock) return
target = typeof el === 'string'
? document.querySelector(el)
: el
shown = true
lock = true
parent = target.parentNode
var p = target.getBoundingClientRect(),
scale = Math.min(options.maxWidth / p.width, options.maxHeight / p.height),
dx = p.left - (window.innerWidth - p.width) / 2,
dy = p.top - (window.innerHeight - p.height) / 2
placeholder = copy(target, p)
originalStyles = setStyle(target, {
position: 'absolute',
top: 0,
left: 0,
right: '',
bottom: '',
whiteSpace: 'nowrap',
marginTop: -p.height / 2 + 'px',
marginLeft: -p.width / 2 + 'px',
transform: 'translate(' + dx + 'px, ' + dy + 'px)',
transition: ''
}, true)
// deal with % width and height
var wPctMatch = target.style.width.match(percentageRE),
hPctMatch = target.style.height.match(percentageRE)
if (wPctMatch || hPctMatch) {
var wPct = wPctMatch ? +wPctMatch[1] / 100 : 1,
hPct = hPctMatch ? +hPctMatch[1] / 100 : 1
setStyle(wrapper, {
width: ~~(p.width / wPct) + 'px',
height: ~~(p.height / hPct) + 'px'
})
}
// insert overlay & placeholder
parent.appendChild(overlay)
parent.appendChild(wrapper)
parent.insertBefore(placeholder, target)
wrapper.appendChild(target)
overlay.style.display = 'block'
// force layout
var force = target.offsetHeight
// trigger transition
overlay.style.opacity = options.bgOpacity
setStyle(target, {
transition:
transformCssProp + ' ' +
options.transitionDuration + ' ' +
options.transitionTimingFunction,
transform: 'scale(' + scale + ')'
})
target.addEventListener(transEndEvent, function onEnd () {
target.removeEventListener(transEndEvent, onEnd)
lock = false
cb = cb || options.onOpen
if (cb) cb(target)
})
return this
},
close: function (cb) {
if (!shown || lock) return
lock = true
var p = placeholder.getBoundingClientRect(),
dx = p.left - (window.innerWidth - p.width) / 2,
dy = p.top - (window.innerHeight - p.height) / 2
overlay.style.opacity = 0
setStyle(target, {
transform: 'translate(' + dx + 'px, ' + dy + 'px)'
})
target.addEventListener(transEndEvent, function onEnd () {
target.removeEventListener(transEndEvent, onEnd)
setStyle(target, originalStyles)
parent.insertBefore(target, placeholder)
parent.removeChild(placeholder)
parent.removeChild(overlay)
parent.removeChild(wrapper)
overlay.style.display = 'none'
placeholder = null
shown = false
lock = false
cb = typeof cb === 'function'
? cb
: options.onClose
if (cb) cb(target)
})
return this
},
listen: function listen (el) {
if (typeof el === 'string') {
var els = document.querySelectorAll(el),
i = els.length
while (i--) {
listen(els[i])
}
return
}
el.addEventListener('click', function (e) {
e.stopPropagation()
if (shown) {
api.close()
} else {
api.open(el)
}
})
return this
}
}
overlay.addEventListener('click', api.close)
wrapper.addEventListener('click', api.close)
// umd expose
if (typeof exports == "object") {
module.exports = api
} else if (typeof define == "function" && define.amd) {
define(function(){ return api })
} else {
this.Zoomerang = api
}
})();