mirror of
https://github.com/flynx/ImageGrid.git
synced 2025-10-28 18:00:09 +00:00
refactoring ribbons...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
parent
60dbd82309
commit
055775fc2b
@ -73,123 +73,6 @@ var RIBBON = '.ribbon:not(.clone)'
|
||||
//
|
||||
//
|
||||
//
|
||||
/*********************************************************************/
|
||||
// Low Level dom access...
|
||||
//
|
||||
// XXX think if a way to manage animation timings...
|
||||
// XXX not sure if this is the right way to go...
|
||||
|
||||
var DOMAdapter =
|
||||
module.DOMAdapter = {
|
||||
getOrigin: function(elem){
|
||||
var o = $(elem).origin() || [0, 0]
|
||||
return { left: o[0], top: o[1], }
|
||||
},
|
||||
setOrigin: function(elem, left, top){
|
||||
return $(elem).origin(left, top, 0)
|
||||
},
|
||||
setOriginSync: function(elem, x, y, z){
|
||||
x = x == null ? '50%' : x
|
||||
y = y == null ? '50%' : y
|
||||
z = z == null ? '0' : z
|
||||
var value = x +' '+ y +' '+ z
|
||||
|
||||
elem = $(elem)
|
||||
var e = elem[0]
|
||||
|
||||
e.style.display = 'none'
|
||||
// now kick the browser into recognition of our changes NOW ;)
|
||||
getComputedStyle(e).display
|
||||
|
||||
e.style['-o-transform-origin'] = value
|
||||
e.style['-ms-transform-origin'] = value
|
||||
e.style['-moz-transform-origin'] = value
|
||||
e.style['-webkit-transform-origin'] = value
|
||||
e.style['transform-origin'] = value
|
||||
|
||||
e.style.display = ''
|
||||
getComputedStyle(e).display
|
||||
|
||||
return $(elem)
|
||||
},
|
||||
|
||||
getScale: function(elem){
|
||||
return $(elem).scale() || 1 },
|
||||
setScale: function(elem, scale){
|
||||
return $(elem).scale(scale || 1) },
|
||||
|
||||
getOffset: function(elem){
|
||||
var o = $(elem).transform('x', 'y')
|
||||
return { left: o.x, top: o.y, }
|
||||
},
|
||||
setOffset: function(elem, left, top){
|
||||
return $(elem).transform({x: left || 0, y: top || 0, z: 0})
|
||||
},
|
||||
|
||||
shiftOrigin: function(elem, left, top, scale){
|
||||
var o = this.getOrigin(elem)
|
||||
var scale = scale || this.getScale(elem)
|
||||
var offset = this.getOffset(elem)
|
||||
|
||||
// calculate the offset change and compensate...
|
||||
var cl = offset.left + ((o.left - o.left*scale) - (left - left*scale))
|
||||
var ct = offset.top + ((o.top - o.top*scale) - (top - top*scale))
|
||||
|
||||
this.setOffset(elem, cl, ct)
|
||||
|
||||
return this.setOriginSync(elem, left+'px', top+'px')
|
||||
},
|
||||
// see docs in jli.js
|
||||
relativeOffset: function(container, block, point){
|
||||
point = point == null ? {} : point
|
||||
var l = point.left
|
||||
var t = point.top
|
||||
var scale = point.scale
|
||||
|
||||
// get the input data...
|
||||
var s = this.getScale(block) || 1
|
||||
var o = this.getOrigin(block)
|
||||
// get only the value we need...
|
||||
var W = container.width()
|
||||
var H = container.height()
|
||||
// we need this to make everything relative to the container...
|
||||
var co = container.offset()
|
||||
var offset = this.getOffset(block)
|
||||
var bo = block.offset()
|
||||
|
||||
scale = scale == 'screen' ? 1
|
||||
: scale == 'elem' ? s
|
||||
: scale == null ? s
|
||||
: scale
|
||||
|
||||
// normalize the l,t to element scale...
|
||||
if(l != null && t != null){
|
||||
|
||||
// get only the value we need...
|
||||
// NOTE: width and height are used to calculate the correction
|
||||
// due to origin/scale...
|
||||
var w = block.width()
|
||||
var h = block.height()
|
||||
o = {
|
||||
// target offset scale...
|
||||
top: t*scale
|
||||
// set origin to top left corner of element (compensate
|
||||
// for scaling)...
|
||||
+ (h - h*s) / (h / o.top),
|
||||
left: l*scale
|
||||
+ (w - w*s) / (w / o.left),
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
top: offset.top + (H/2 - offset.top) - o.top,
|
||||
left: offset.left + (W/2 - offset.left) - o.left,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*********************************************************************/
|
||||
|
||||
var RibbonsClassPrototype = {
|
||||
@ -278,8 +161,10 @@ var RibbonsClassPrototype = {
|
||||
}
|
||||
|
||||
|
||||
// NOTE: this is a low level interface, not a set of actions...
|
||||
var RibbonsPrototype = {
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
var IntrospectiveRibbonsPrototype = {
|
||||
//
|
||||
// .viewer (jQuery object)
|
||||
//
|
||||
@ -292,35 +177,13 @@ var RibbonsPrototype = {
|
||||
this.images = images
|
||||
},
|
||||
|
||||
// XXX
|
||||
clone: function(){
|
||||
var o = new this.constructor()
|
||||
if(this.viewer){
|
||||
// XXX does this completely detach from the orriginal???
|
||||
// XXX do we need to reattach something???
|
||||
o.viewer = this.viewer.clone()
|
||||
}
|
||||
if(this.images){
|
||||
o.images = this.images.clone()
|
||||
}
|
||||
return o
|
||||
},
|
||||
|
||||
// DOM Adapter...
|
||||
dom: DOMAdapter,
|
||||
|
||||
// utils...
|
||||
px2v: RibbonsClassPrototype.px2v,
|
||||
px2vw: RibbonsClassPrototype.px2vw,
|
||||
px2vh: RibbonsClassPrototype.px2vh,
|
||||
px2vmin: RibbonsClassPrototype.px2vmin,
|
||||
px2vmax: RibbonsClassPrototype.px2vmax,
|
||||
|
||||
// Constructors...
|
||||
createViewer: RibbonsClassPrototype.createViewer,
|
||||
createRibbon: RibbonsClassPrototype.createRibbon,
|
||||
createImage: RibbonsClassPrototype.createImage,
|
||||
createMark: RibbonsClassPrototype.createMark,
|
||||
|
||||
|
||||
// Generic getters...
|
||||
elemGID: RibbonsClassPrototype.elemGID,
|
||||
@ -351,151 +214,6 @@ var RibbonsPrototype = {
|
||||
},
|
||||
|
||||
|
||||
// Helpers...
|
||||
|
||||
// Prevent CSS transitions...
|
||||
//
|
||||
// Prevent transitions globally (.viewer):
|
||||
// .preventTransitions()
|
||||
// -> data
|
||||
//
|
||||
// Prevent transitions on elem:
|
||||
// .preventTransitions(elem)
|
||||
// -> data
|
||||
//
|
||||
//
|
||||
// NOTE: this will set a .no-transitions CSS class and force
|
||||
// recalculation on the given element
|
||||
// NOTE: for this to have effect proper CSS configuration is needed.
|
||||
preventTransitions: function(target){
|
||||
target = target || this.viewer
|
||||
//prevent_nested = prevent_nested || false
|
||||
if(target.length == 0){
|
||||
return this
|
||||
}
|
||||
var t = target[0]
|
||||
|
||||
// handle nesting...
|
||||
var l = t.getAttribute('__prevent_transitions')
|
||||
if(l != null){
|
||||
t.setAttribute('__prevent_transitions', parseInt(l)+1)
|
||||
return this
|
||||
}
|
||||
t.setAttribute('__prevent_transitions', 0)
|
||||
|
||||
target.addClass('no-transitions')
|
||||
|
||||
var s = getComputedStyle(t)
|
||||
s.webkitTransition
|
||||
s.mozTransition
|
||||
s.msTransition
|
||||
s.oTransition
|
||||
s.transition
|
||||
|
||||
return this
|
||||
},
|
||||
|
||||
// Restore CSS transitions...
|
||||
//
|
||||
// This is a companion to .preventTransitions(..)
|
||||
//
|
||||
// Restore transitions globally (.viewer):
|
||||
// .restoreTransitions()
|
||||
// -> data
|
||||
//
|
||||
// Restore transitions on elem:
|
||||
// .restoreTransitions(elem)
|
||||
// -> data
|
||||
//
|
||||
// Restore transitions on elem (force sync):
|
||||
// .restoreTransitions(elem, true)
|
||||
// -> data
|
||||
//
|
||||
// Force restore transitions:
|
||||
// .restoreTransitions(.., .., true)
|
||||
// -> data
|
||||
//
|
||||
// When at least one .preventTransitions(..) is called with
|
||||
// prevent_nested set to true, this will be a no-op on all nested
|
||||
// levels.
|
||||
// This can be overridden via setting the force to true.
|
||||
//
|
||||
// NOTE: the implementation of this method might seem ugly, but the
|
||||
// code is speed-critical, thus we access the DOM directly and
|
||||
// the two branches are unrolled...
|
||||
restoreTransitions: function(target, now, force){
|
||||
if(target === true || target === false){
|
||||
now = target
|
||||
target = this.viewer
|
||||
} else {
|
||||
target = target || this.viewer
|
||||
}
|
||||
if(target.length == 0){
|
||||
return this
|
||||
}
|
||||
var t = target[0]
|
||||
|
||||
// sync...
|
||||
if(now){
|
||||
// handle nesting...
|
||||
var l = t.getAttribute('__prevent_transitions')
|
||||
if(l != null && !force && l != '0'){
|
||||
t.setAttribute('__prevent_transitions', parseInt(l)-1)
|
||||
return this
|
||||
}
|
||||
t.removeAttribute('__prevent_transitions')
|
||||
|
||||
target.removeClass('no-transitions')
|
||||
|
||||
var s = getComputedStyle(t)
|
||||
s.webkitTransition
|
||||
s.mozTransition
|
||||
s.msTransition
|
||||
s.oTransition
|
||||
s.transition
|
||||
|
||||
// on next exec frame...
|
||||
} else {
|
||||
var that = this
|
||||
setTimeout(function(){
|
||||
// handle nesting...
|
||||
var l = t.getAttribute('__prevent_transitions')
|
||||
if(l != null && !force && l != '0'){
|
||||
t.setAttribute('__prevent_transitions', l-1)
|
||||
return this
|
||||
}
|
||||
t.removeAttribute('__prevent_transitions')
|
||||
|
||||
target.removeClass('no-transitions')
|
||||
|
||||
var s = getComputedStyle(t)
|
||||
s.webkitTransition
|
||||
s.mozTransition
|
||||
s.msTransition
|
||||
s.oTransition
|
||||
s.transition
|
||||
}, 0)
|
||||
}
|
||||
|
||||
return this
|
||||
},
|
||||
|
||||
// Shorthand wrappers of the above...
|
||||
//
|
||||
// XXX do we need custom target support here???
|
||||
noTransitions: function(func){
|
||||
this.preventTransitions()
|
||||
func.apply(this, args2array(arguments).slice(1))
|
||||
this.restoreTransitions(true)
|
||||
return this
|
||||
},
|
||||
noTransitionsDeep: function(func){
|
||||
this.preventTransitions(null, true)
|
||||
func.apply(this, args2array(arguments).slice(1))
|
||||
this.restoreTransitions(true)
|
||||
return this
|
||||
},
|
||||
|
||||
// Scale...
|
||||
//
|
||||
// Get scale...
|
||||
@ -512,7 +230,7 @@ var RibbonsPrototype = {
|
||||
scale: function(scale){
|
||||
// get...
|
||||
if(arguments.length == 0){
|
||||
return this.dom.getScale(this.getRibbonSet()) || 1
|
||||
return this.getRibbonSet().scale() || 1
|
||||
}
|
||||
|
||||
// set...
|
||||
@ -522,53 +240,12 @@ var RibbonsPrototype = {
|
||||
return this
|
||||
}
|
||||
|
||||
this.dom.setScale(ribbon_set, scale)
|
||||
ribbon_set.scale(scale)
|
||||
|
||||
return this
|
||||
},
|
||||
|
||||
// Rotate...
|
||||
//
|
||||
// Get ribbon rotation angle...
|
||||
// .rotate()
|
||||
// -> angle
|
||||
//
|
||||
// Rotate to angle...
|
||||
// .rotate(20)
|
||||
// .rotate(-10)
|
||||
// -> ribbons
|
||||
//
|
||||
// Rotate by angle...
|
||||
// .rotate('-=20')
|
||||
// .rotate('+=30')
|
||||
// -> ribbons
|
||||
//
|
||||
// NOTE: the angles are not base 360 normalised...
|
||||
// NOTE: units are ignored and the final angle is always in deg.
|
||||
rotate: function(angle){
|
||||
// get...
|
||||
if(arguments.length == 0){
|
||||
return this.getRibbonSet().rotate()
|
||||
}
|
||||
|
||||
// set...
|
||||
var ribbon_set = this.getRibbonSet()
|
||||
|
||||
if(ribbon_set.length == 0){
|
||||
return this
|
||||
}
|
||||
|
||||
angle = typeof(angle) == typeof('str')
|
||||
? (/^\+=/.test(angle) ? (ribbon_set.rotate() || 0) + parseFloat(angle.slice(2))
|
||||
:/^\-=/.test(angle) ? (ribbon_set.rotate() || 0) - parseFloat(angle.slice(2))
|
||||
: parseFloat(angle))
|
||||
: angle
|
||||
|
||||
ribbon_set.rotate(angle)
|
||||
|
||||
return this
|
||||
},
|
||||
|
||||
// Get visible image tile size...
|
||||
//
|
||||
// .getVisibleImageSize()
|
||||
@ -667,154 +344,6 @@ var RibbonsPrototype = {
|
||||
return H/h
|
||||
},
|
||||
|
||||
// Make a "shadow" image for use with image oriented animations...
|
||||
//
|
||||
// .makeShadow([<image>][, <animate>][, <delay>])
|
||||
// -> <finalize>
|
||||
//
|
||||
// A shadow is a clone of <image> placed directly above it while it
|
||||
// is hidden (transparent), calling <finalize> will remove the shadwo
|
||||
// and restore the original image, if <animate> is set then the shadow
|
||||
// will be moved to the image location, and <delay> sets the time delay
|
||||
// to provision for shadow animations.
|
||||
//
|
||||
// <finalize> is a function, that when called will remove the shadow
|
||||
// and restore image state.
|
||||
//
|
||||
// <image> is the target image to clone
|
||||
//
|
||||
// <animate> if is set, <finalize> will shift the shadow to target
|
||||
// image offset before removing it (default: false).
|
||||
//
|
||||
// <delay> sets the delay before the shadow is removed and the target
|
||||
// state is restored (default: 200).
|
||||
//
|
||||
//
|
||||
// NOTE: if a previous shadow if the same image exists this will recycle
|
||||
// the existing shadow and cancel it's removal.
|
||||
// ...this is useful for when a second consecutive action with
|
||||
// the same image is issued before the previous has time to
|
||||
// complete, recycling the shadow will enable a single flowing
|
||||
// animation for such series of commands.
|
||||
// Example: several fast consecutive horizontal shifts will result
|
||||
// in a single shadow "flowing" through the ribbon.
|
||||
// NOTE: multiple shadows of different images are supported...
|
||||
// NOTE: the .shadow element is essentially a ribbon.
|
||||
//
|
||||
// XXX add duration configuration...
|
||||
// XXX should we also have a ribbon shadow???
|
||||
// XXX when this cant find a target it will return an empty function,
|
||||
// not sure if this is correct...
|
||||
// XXX should we use transforms instead of css positions???
|
||||
makeShadow: function(target, animate, delay, start_delay){
|
||||
delay = delay || 200
|
||||
start_delay = start_delay || 10
|
||||
|
||||
var img = this.getImage(target)
|
||||
|
||||
if(img.length == 0){
|
||||
// XXX is this correct???
|
||||
return function(){}
|
||||
}
|
||||
|
||||
var gid = this.elemGID(img)
|
||||
var s = this.scale()
|
||||
var vo = this.viewer.offset()
|
||||
var io = img.offset()
|
||||
|
||||
// get the shadow if it exists...
|
||||
var shadow = this.viewer.find('.shadow[gid="'+gid+'"]')
|
||||
|
||||
// recycle the shadow...
|
||||
if(shadow.length > 0){
|
||||
// cancel previous shadow removal ticket...
|
||||
var ticket = shadow.attr('ticket') + 1
|
||||
shadow
|
||||
// reset ticket...
|
||||
// NOTE: this is a possible race condition... (XXX)
|
||||
.attr('ticket', ticket)
|
||||
// place it over the current image...
|
||||
.css({
|
||||
top: io.top - vo.top,
|
||||
left: io.left - vo.left,
|
||||
})
|
||||
|
||||
// create a new shadow...
|
||||
} else {
|
||||
// removal ticket...
|
||||
var ticket = 0
|
||||
|
||||
// make a shadow element...
|
||||
// ...we need to scale it to the current scale...
|
||||
var shadow = this.dom.setScale(
|
||||
$('<div>')
|
||||
.addClass('shadow ribbon clone')
|
||||
.attr({
|
||||
gid: gid,
|
||||
ticket: ticket,
|
||||
})
|
||||
.append(
|
||||
// clone the target into the shadow..
|
||||
img
|
||||
.clone()
|
||||
.addClass('clone')
|
||||
.removeClass('current')
|
||||
.attr('gid', null)),
|
||||
s)
|
||||
// place it over the current image...
|
||||
.css({
|
||||
top: io.top - vo.top,
|
||||
left: io.left - vo.left,
|
||||
})
|
||||
.append(this.getImageMarks(img)
|
||||
.clone()
|
||||
.attr('gid', null))
|
||||
// place in the viewer...
|
||||
// NOTE: placing the shadow in the viewer is a compromise that
|
||||
// lets us do simpler positioning
|
||||
.appendTo(this.viewer)
|
||||
}
|
||||
|
||||
img.addClass('moving')
|
||||
var that = this
|
||||
|
||||
// function to clear the shadow...
|
||||
return function(){
|
||||
// remove only the item with the correct ticket...
|
||||
if(ticket == shadow.attr('ticket')){
|
||||
var s = that.scale()
|
||||
var img = that.getImage(gid)
|
||||
var vo = that.viewer.offset()
|
||||
var io = img.offset()
|
||||
if(animate){
|
||||
if(start_delay){
|
||||
setTimeout(function(){
|
||||
shadow.css({
|
||||
top: io.top - vo.top,
|
||||
left: io.left - vo.left,
|
||||
})
|
||||
}, start_delay)
|
||||
|
||||
} else {
|
||||
shadow.css({
|
||||
top: io.top - vo.top,
|
||||
left: io.left - vo.left,
|
||||
})
|
||||
}
|
||||
}
|
||||
setTimeout(function(){
|
||||
// remove only the item with the correct ticket...
|
||||
if(ticket == shadow.attr('ticket')){
|
||||
img.removeClass('moving')
|
||||
shadow.remove()
|
||||
}
|
||||
}, delay)
|
||||
}
|
||||
return img
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
// Contextual getters...
|
||||
|
||||
// Get ribbon-set...
|
||||
@ -1139,6 +668,383 @@ var RibbonsPrototype = {
|
||||
return this.viewer.find(RIBBON).index(this.getRibbon(target)) },
|
||||
|
||||
|
||||
getImageRotation: function(target){
|
||||
return (this.getImage(target).attr('orientation') || 0)*1 },
|
||||
getImageFlip: function(target){
|
||||
return (this.getImage(target).attr('flipped') || '')
|
||||
.split(',')
|
||||
.map(function(e){ return e.trim() })
|
||||
.filter(function(e){ return e != '' })
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
var IntrospectiveRibbons =
|
||||
module.IntrospectiveRibbons =
|
||||
object.makeConstructor('IntrospectiveRibbons',
|
||||
RibbonsClassPrototype,
|
||||
IntrospectiveRibbonsPrototype)
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
// NOTE: this is a low level interface, not a set of actions...
|
||||
var RibbonsPrototype = {
|
||||
// XXX
|
||||
clone: function(){
|
||||
var o = new this.constructor()
|
||||
if(this.viewer){
|
||||
// XXX does this completely detach from the orriginal???
|
||||
// XXX do we need to reattach something???
|
||||
o.viewer = this.viewer.clone()
|
||||
}
|
||||
if(this.images){
|
||||
o.images = this.images.clone()
|
||||
}
|
||||
return o
|
||||
},
|
||||
|
||||
// Constructors...
|
||||
createViewer: RibbonsClassPrototype.createViewer,
|
||||
createRibbon: RibbonsClassPrototype.createRibbon,
|
||||
createImage: RibbonsClassPrototype.createImage,
|
||||
createMark: RibbonsClassPrototype.createMark,
|
||||
|
||||
// Helpers...
|
||||
|
||||
// Prevent CSS transitions...
|
||||
//
|
||||
// Prevent transitions globally (.viewer):
|
||||
// .preventTransitions()
|
||||
// -> data
|
||||
//
|
||||
// Prevent transitions on elem:
|
||||
// .preventTransitions(elem)
|
||||
// -> data
|
||||
//
|
||||
//
|
||||
// NOTE: this will set a .no-transitions CSS class and force
|
||||
// recalculation on the given element
|
||||
// NOTE: for this to have effect proper CSS configuration is needed.
|
||||
preventTransitions: function(target){
|
||||
target = target || this.viewer
|
||||
//prevent_nested = prevent_nested || false
|
||||
if(target.length == 0){
|
||||
return this
|
||||
}
|
||||
var t = target[0]
|
||||
|
||||
// handle nesting...
|
||||
var l = t.getAttribute('__prevent_transitions')
|
||||
if(l != null){
|
||||
t.setAttribute('__prevent_transitions', parseInt(l)+1)
|
||||
return this
|
||||
}
|
||||
t.setAttribute('__prevent_transitions', 0)
|
||||
|
||||
target.addClass('no-transitions')
|
||||
|
||||
var s = getComputedStyle(t)
|
||||
s.webkitTransition
|
||||
s.mozTransition
|
||||
s.msTransition
|
||||
s.oTransition
|
||||
s.transition
|
||||
|
||||
return this
|
||||
},
|
||||
|
||||
// Restore CSS transitions...
|
||||
//
|
||||
// This is a companion to .preventTransitions(..)
|
||||
//
|
||||
// Restore transitions globally (.viewer):
|
||||
// .restoreTransitions()
|
||||
// -> data
|
||||
//
|
||||
// Restore transitions on elem:
|
||||
// .restoreTransitions(elem)
|
||||
// -> data
|
||||
//
|
||||
// Restore transitions on elem (force sync):
|
||||
// .restoreTransitions(elem, true)
|
||||
// -> data
|
||||
//
|
||||
// Force restore transitions:
|
||||
// .restoreTransitions(.., .., true)
|
||||
// -> data
|
||||
//
|
||||
// When at least one .preventTransitions(..) is called with
|
||||
// prevent_nested set to true, this will be a no-op on all nested
|
||||
// levels.
|
||||
// This can be overridden via setting the force to true.
|
||||
//
|
||||
// NOTE: the implementation of this method might seem ugly, but the
|
||||
// code is speed-critical, thus we access the DOM directly and
|
||||
// the two branches are unrolled...
|
||||
restoreTransitions: function(target, now, force){
|
||||
if(target === true || target === false){
|
||||
now = target
|
||||
target = this.viewer
|
||||
} else {
|
||||
target = target || this.viewer
|
||||
}
|
||||
if(target.length == 0){
|
||||
return this
|
||||
}
|
||||
var t = target[0]
|
||||
|
||||
// sync...
|
||||
if(now){
|
||||
// handle nesting...
|
||||
var l = t.getAttribute('__prevent_transitions')
|
||||
if(l != null && !force && l != '0'){
|
||||
t.setAttribute('__prevent_transitions', parseInt(l)-1)
|
||||
return this
|
||||
}
|
||||
t.removeAttribute('__prevent_transitions')
|
||||
|
||||
target.removeClass('no-transitions')
|
||||
|
||||
var s = getComputedStyle(t)
|
||||
s.webkitTransition
|
||||
s.mozTransition
|
||||
s.msTransition
|
||||
s.oTransition
|
||||
s.transition
|
||||
|
||||
// on next exec frame...
|
||||
} else {
|
||||
var that = this
|
||||
setTimeout(function(){
|
||||
// handle nesting...
|
||||
var l = t.getAttribute('__prevent_transitions')
|
||||
if(l != null && !force && l != '0'){
|
||||
t.setAttribute('__prevent_transitions', l-1)
|
||||
return this
|
||||
}
|
||||
t.removeAttribute('__prevent_transitions')
|
||||
|
||||
target.removeClass('no-transitions')
|
||||
|
||||
var s = getComputedStyle(t)
|
||||
s.webkitTransition
|
||||
s.mozTransition
|
||||
s.msTransition
|
||||
s.oTransition
|
||||
s.transition
|
||||
}, 0)
|
||||
}
|
||||
|
||||
return this
|
||||
},
|
||||
|
||||
// Shorthand wrappers of the above...
|
||||
//
|
||||
// XXX do we need custom target support here???
|
||||
noTransitions: function(func){
|
||||
this.preventTransitions()
|
||||
func.apply(this, args2array(arguments).slice(1))
|
||||
this.restoreTransitions(true)
|
||||
return this
|
||||
},
|
||||
noTransitionsDeep: function(func){
|
||||
this.preventTransitions(null, true)
|
||||
func.apply(this, args2array(arguments).slice(1))
|
||||
this.restoreTransitions(true)
|
||||
return this
|
||||
},
|
||||
|
||||
// Rotate...
|
||||
//
|
||||
// Get ribbon rotation angle...
|
||||
// .rotate()
|
||||
// -> angle
|
||||
//
|
||||
// Rotate to angle...
|
||||
// .rotate(20)
|
||||
// .rotate(-10)
|
||||
// -> ribbons
|
||||
//
|
||||
// Rotate by angle...
|
||||
// .rotate('-=20')
|
||||
// .rotate('+=30')
|
||||
// -> ribbons
|
||||
//
|
||||
// NOTE: the angles are not base 360 normalised...
|
||||
// NOTE: units are ignored and the final angle is always in deg.
|
||||
rotate: function(angle){
|
||||
// get...
|
||||
if(arguments.length == 0){
|
||||
return this.getRibbonSet().rotate()
|
||||
}
|
||||
|
||||
// set...
|
||||
var ribbon_set = this.getRibbonSet()
|
||||
|
||||
if(ribbon_set.length == 0){
|
||||
return this
|
||||
}
|
||||
|
||||
angle = typeof(angle) == typeof('str')
|
||||
? (/^\+=/.test(angle) ? (ribbon_set.rotate() || 0) + parseFloat(angle.slice(2))
|
||||
:/^\-=/.test(angle) ? (ribbon_set.rotate() || 0) - parseFloat(angle.slice(2))
|
||||
: parseFloat(angle))
|
||||
: angle
|
||||
|
||||
ribbon_set.rotate(angle)
|
||||
|
||||
return this
|
||||
},
|
||||
|
||||
// Make a "shadow" image for use with image oriented animations...
|
||||
//
|
||||
// .makeShadow([<image>][, <animate>][, <delay>])
|
||||
// -> <finalize>
|
||||
//
|
||||
// A shadow is a clone of <image> placed directly above it while it
|
||||
// is hidden (transparent), calling <finalize> will remove the shadwo
|
||||
// and restore the original image, if <animate> is set then the shadow
|
||||
// will be moved to the image location, and <delay> sets the time delay
|
||||
// to provision for shadow animations.
|
||||
//
|
||||
// <finalize> is a function, that when called will remove the shadow
|
||||
// and restore image state.
|
||||
//
|
||||
// <image> is the target image to clone
|
||||
//
|
||||
// <animate> if is set, <finalize> will shift the shadow to target
|
||||
// image offset before removing it (default: false).
|
||||
//
|
||||
// <delay> sets the delay before the shadow is removed and the target
|
||||
// state is restored (default: 200).
|
||||
//
|
||||
//
|
||||
// NOTE: if a previous shadow if the same image exists this will recycle
|
||||
// the existing shadow and cancel it's removal.
|
||||
// ...this is useful for when a second consecutive action with
|
||||
// the same image is issued before the previous has time to
|
||||
// complete, recycling the shadow will enable a single flowing
|
||||
// animation for such series of commands.
|
||||
// Example: several fast consecutive horizontal shifts will result
|
||||
// in a single shadow "flowing" through the ribbon.
|
||||
// NOTE: multiple shadows of different images are supported...
|
||||
// NOTE: the .shadow element is essentially a ribbon.
|
||||
//
|
||||
// XXX add duration configuration...
|
||||
// XXX should we also have a ribbon shadow???
|
||||
// XXX when this cant find a target it will return an empty function,
|
||||
// not sure if this is correct...
|
||||
// XXX should we use transforms instead of css positions???
|
||||
makeShadow: function(target, animate, delay, start_delay){
|
||||
delay = delay || 200
|
||||
start_delay = start_delay || 10
|
||||
|
||||
var img = this.getImage(target)
|
||||
|
||||
if(img.length == 0){
|
||||
// XXX is this correct???
|
||||
return function(){}
|
||||
}
|
||||
|
||||
var gid = this.elemGID(img)
|
||||
var s = this.scale()
|
||||
var vo = this.viewer.offset()
|
||||
var io = img.offset()
|
||||
|
||||
// get the shadow if it exists...
|
||||
var shadow = this.viewer.find('.shadow[gid="'+gid+'"]')
|
||||
|
||||
// recycle the shadow...
|
||||
if(shadow.length > 0){
|
||||
// cancel previous shadow removal ticket...
|
||||
var ticket = shadow.attr('ticket') + 1
|
||||
shadow
|
||||
// reset ticket...
|
||||
// NOTE: this is a possible race condition... (XXX)
|
||||
.attr('ticket', ticket)
|
||||
// place it over the current image...
|
||||
.css({
|
||||
top: io.top - vo.top,
|
||||
left: io.left - vo.left,
|
||||
})
|
||||
|
||||
// create a new shadow...
|
||||
} else {
|
||||
// removal ticket...
|
||||
var ticket = 0
|
||||
|
||||
// make a shadow element...
|
||||
// ...we need to scale it to the current scale...
|
||||
var shadow = $('<div>')
|
||||
.addClass('shadow ribbon clone')
|
||||
.attr({
|
||||
gid: gid,
|
||||
ticket: ticket,
|
||||
})
|
||||
.append(
|
||||
// clone the target into the shadow..
|
||||
img
|
||||
.clone()
|
||||
.addClass('clone')
|
||||
.removeClass('current')
|
||||
.attr('gid', null))
|
||||
.scale(s)
|
||||
// place it over the current image...
|
||||
.css({
|
||||
top: io.top - vo.top,
|
||||
left: io.left - vo.left,
|
||||
})
|
||||
.append(this.getImageMarks(img)
|
||||
.clone()
|
||||
.attr('gid', null))
|
||||
// place in the viewer...
|
||||
// NOTE: placing the shadow in the viewer is a compromise that
|
||||
// lets us do simpler positioning
|
||||
.appendTo(this.viewer)
|
||||
}
|
||||
|
||||
img.addClass('moving')
|
||||
var that = this
|
||||
|
||||
// function to clear the shadow...
|
||||
return function(){
|
||||
// remove only the item with the correct ticket...
|
||||
if(ticket == shadow.attr('ticket')){
|
||||
var s = that.scale()
|
||||
var img = that.getImage(gid)
|
||||
var vo = that.viewer.offset()
|
||||
var io = img.offset()
|
||||
if(animate){
|
||||
if(start_delay){
|
||||
setTimeout(function(){
|
||||
shadow.css({
|
||||
top: io.top - vo.top,
|
||||
left: io.left - vo.left,
|
||||
})
|
||||
}, start_delay)
|
||||
|
||||
} else {
|
||||
shadow.css({
|
||||
top: io.top - vo.top,
|
||||
left: io.left - vo.left,
|
||||
})
|
||||
}
|
||||
}
|
||||
setTimeout(function(){
|
||||
// remove only the item with the correct ticket...
|
||||
if(ticket == shadow.attr('ticket')){
|
||||
img.removeClass('moving')
|
||||
shadow.remove()
|
||||
}
|
||||
}, delay)
|
||||
}
|
||||
return img
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
// Basic manipulation...
|
||||
|
||||
// Place a ribbon...
|
||||
@ -1945,8 +1851,6 @@ var RibbonsPrototype = {
|
||||
.css('background-image', 'none')
|
||||
|
||||
// compensate for the offset...
|
||||
//that.dom.setOffset(ribbon, that.dom.getOffset(ribbon).left + l)
|
||||
|
||||
var b = images[-left].offsetLeft
|
||||
var d = ((a - b) / W) * 100
|
||||
var x = parseFloat((ribbon.transform('translate3d') || [0])[0]) + d
|
||||
@ -2024,8 +1928,6 @@ var RibbonsPrototype = {
|
||||
})
|
||||
|
||||
// compensate for the offset...
|
||||
//that.dom.setOffset(ribbon, that.dom.getOffset(ribbon).left - l)
|
||||
|
||||
// XXX is this the correct reference item -- can it be deleted above???
|
||||
var b = images[0].offsetLeft
|
||||
var d = ((a - b) / W) * 100
|
||||
@ -2307,10 +2209,6 @@ var RibbonsPrototype = {
|
||||
return image
|
||||
},
|
||||
|
||||
// Get image rotation...
|
||||
//
|
||||
getImageRotation: function(target){
|
||||
return (this.getImage(target).attr('orientation') || 0)*1 },
|
||||
// Rotate an image...
|
||||
//
|
||||
// Rotate image clockwise:
|
||||
@ -2359,14 +2257,6 @@ var RibbonsPrototype = {
|
||||
return this
|
||||
},
|
||||
|
||||
// Get image flip...
|
||||
//
|
||||
getImageFlip: function(target){
|
||||
return (this.getImage(target).attr('flipped') || '')
|
||||
.split(',')
|
||||
.map(function(e){ return e.trim() })
|
||||
.filter(function(e){ return e != '' })
|
||||
},
|
||||
// Flip an image...
|
||||
//
|
||||
// Flip image relative to view:
|
||||
@ -2650,10 +2540,9 @@ var RibbonsPrototype = {
|
||||
},
|
||||
}
|
||||
|
||||
RibbonsPrototype.__proto__ = IntrospectiveRibbonsPrototype
|
||||
|
||||
|
||||
/*********************************************************************/
|
||||
|
||||
var Ribbons =
|
||||
module.Ribbons =
|
||||
object.makeConstructor('Ribbons',
|
||||
@ -2662,5 +2551,6 @@ object.makeConstructor('Ribbons',
|
||||
|
||||
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* vim:set ts=4 sw=4 : */ return module })
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user