如何将事件侦听器添加到动画变换旋转?
How to add event listener to animated transform rotate?
所以我有一张 2 面卡片,每次卡片旋转 180 度时,它都会改变面值。
我想过做的一件事是将事件侦听器添加到动画转换旋转中,但似乎这不可能?
这是 fiddle:https://jsfiddle.net/4qovckd7/
我想要实现的是每旋转 180 度更改一次面卡值(正面和背面文本)。
已经尝试使用 jquery 动画步骤和进度,但我似乎无法获得正确的进度值(只有 returns 0 或 1,这是动画的开始和结束)
$('.card').on('swipeleft swiperight', function (event) {
var spinValue = 5 * 180;
if (event.handleObj.type == 'swipeleft')
spinValue = spinValue * -1;
$(this).animate({
borderSpacing: spinValue
}, {
step: function (now, fx) {
$(this).css('transform', 'rotateY(' + now + 'deg)');
},
progress: function (animation, progress, msRemaining) {
//supposedly to get the progress value here
}
});
})
如有任何想法,我们将不胜感激。谢谢!
您的滑动和动画已损坏。如果你多次向左滑动,你会看到过渡无法跟上它当前的度数旋转状态——使用新的输入。
解决方案
- 用一个变量存储当前的原旋转度(
-N° … 0° … N°
)——也就是说,不管有多少每次滑动时,数字将加(或减)到当前组织。度数。
- 标准化你的原始度到相对旋转度使用这个公式:
deg = orgDeg % 360 // This still has negatives: -360° … 0° … 360°
if ( deg < 0 ) deg += 360 // Always 0° … 360°. Now you can rotateY( deg )
- 获取当前面为二进制
0, 1
。
您可能会注意到,一张脸(比如正面)不是从 0 度开始的!
它在 -90°
处开始可见(现在标准化为 270)。后面也一样。它在 +90°
开始它的 "I'm visible!" 旅程。如果你不跟进,想象一下你想每回合将一张脸换成一张随机图像,一旦表面完全面向前方就这样做是愚蠢的。
所以,当飞机的边缘面向前方时开始转弯!这是数学公式:
face = round( ((deg + 90) % 360) / 360 ) // 0, 1, 0, 1, 0…
让事情更真实一些
透视
将 perspective: 1000px;
添加到父项,有助于可视化 2D3D 中的卡片转换。
动画
缓动 swing
或 linear
(默认 jQuery .animate()
缓动)不适合很好的 easeOutCubic
,这最能描述建筑物-上升 势头自然停止 。
如果你不想包含整个 jQuery UI 库,你可以扩展 $.easing
// https://github.com/gdsmith/jquery.easing
jQuery.extend(jQuery.easing, {
easeOutCubic :function(x){return 1-Math.pow(1-x,3)}
});
速度
通过将刷卡速度添加到卡片旋转来改善用户体验。这是一个函数:
function swipeSpeed(e) {
var st = e.swipestart,
sp = e.swipestop,
time = sp.time - st.time,
a = st.coords[0] - st.coords[1],
b = sp.coords[0] - sp.coords[1],
dist = Math.sqrt( a*a + b*b );
return dist / time;
}
清除动画队列
为了播放来回滑动,您必须使用.stop()
:
清除动画队列
.stop().animate({
说够了
// https://github.com/gdsmith/jquery.easing
jQuery.extend(jQuery.easing, {
easeOutCubic: function(x) {
return 1 - Math.pow(1 - x, 3)
}
});
function swipeSpeed(e) {
var st = e.swipestart,
sp = e.swipestop,
time = sp.time - st.time,
a = st.coords[0] - st.coords[1],
b = sp.coords[0] - sp.coords[1],
dist = Math.sqrt(a * a + b * b);
return dist / time;
}
var cats = [ // cause we luw catz
"https://i.stack.imgur.com/bBGtG.jpg",
"https://i.stack.imgur.com/UzdQz.jpg",
"https://i.stack.imgur.com/MJl4g.jpg",
"https://i.stack.imgur.com/7QAyw.jpg",
"https://i.stack.imgur.com/updEN.jpg",
];
var $info = $("#info");
$(".card-wrapper").each(function() {
var $card = $(this).find(".card");
var $back = $(this).find(".card-back");
var _d = 0;
$(this).on({
'swipeleft swiperight': function(e) {
var isLeft = e.type === 'swipeleft';
var sw = Math.min(swipeSpeed(e), 10); // Math.min to prevent excessive momentum
var s = 180 * sw;
var spinDegs = _d + (isLeft ? -s : s);
spinDegs -= spinDegs % 180; // (optional) end rotation as full-face
$card.stop().animate({
sD: spinDegs
}, {
duration: 700 * sw,
easing: "easeOutCubic",
step: function(d) {
_d = d; // store now for later use
var deg = (d %= 360) < 0 ? d + 360 : d; // Degrees Normalization
$(this).css('transform', 'rotateY(' + deg + 'deg)'); // Rotate
// Extra fun!
var face = Math.round(((deg + 90) % 360) / 360);
var idx = Math.abs(Math.round(((_d + 90) / 360)) % cats.length);
$back.css({
backgroundImage: `url('${cats[idx]}')`
});
// Show info
$info.html(`
Face: ${ face }<br>
Org Degrees: ${ _d }<br>
Degrees: ${ deg }<br>
Cat image: ${ idx }
`);
}
});
}
});
});
/* Flipping cards */
.card-wrapper {
width: 200px;
height: 200px;
margin: 0 auto;
perspective: 1000px;
}
.card {
position: relative;
width: 200px;
height: 200px;
transform-style: preserve-3d;
}
.card * {
pointer-events: none;
}
.card .card-front,
.card .card-back {
position: absolute;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
top: 50%;
left: 50%;
backface-visibility: hidden;
font-size: 25px;
color: white;
background: 50% 50%/cover transparent none no-repeat;
}
.card .card-front {
transform: translate(-50%, -50%);
background-color: blue;
}
.card .card-back {
transform: translate(-50%, -50%) rotateY(180deg);
background-color: red;
}
#info {
position: absolute;
pointer-events: none;
top: 0;
left: 0;
}
/* Should all go to top but yeah I'll keep it below-the-fold for this demo*/
/* QuickReset */
* {
margin: 0;
box-sizing: border-box;
}
html,
body {
height: 100%;
font: 14px/1.4 sans-serif;
}
/* jQueryMobile resets */
[data-role="page"] {
outline: none;
}
.ui-loader {
display: none !important;
}
<div class="card-wrapper">
<div class="card">
<div class="card-front"><span class="card-content">SWIPE</span></div>
<div class="card-back"><span class="card-content">:)</span></div>
</div>
</div>
<div id="info"></div>
<script src="//code.jquery.com/jquery-1.11.3.js"></script>
<script src="//code.jquery.com/mobile/1.4.2/jquery.mobile-1.4.2.js"></script>
所以我有一张 2 面卡片,每次卡片旋转 180 度时,它都会改变面值。
我想过做的一件事是将事件侦听器添加到动画转换旋转中,但似乎这不可能?
这是 fiddle:https://jsfiddle.net/4qovckd7/
我想要实现的是每旋转 180 度更改一次面卡值(正面和背面文本)。 已经尝试使用 jquery 动画步骤和进度,但我似乎无法获得正确的进度值(只有 returns 0 或 1,这是动画的开始和结束)
$('.card').on('swipeleft swiperight', function (event) {
var spinValue = 5 * 180;
if (event.handleObj.type == 'swipeleft')
spinValue = spinValue * -1;
$(this).animate({
borderSpacing: spinValue
}, {
step: function (now, fx) {
$(this).css('transform', 'rotateY(' + now + 'deg)');
},
progress: function (animation, progress, msRemaining) {
//supposedly to get the progress value here
}
});
})
如有任何想法,我们将不胜感激。谢谢!
您的滑动和动画已损坏。如果你多次向左滑动,你会看到过渡无法跟上它当前的度数旋转状态——使用新的输入。
解决方案
- 用一个变量存储当前的原旋转度(
-N° … 0° … N°
)——也就是说,不管有多少每次滑动时,数字将加(或减)到当前组织。度数。 - 标准化你的原始度到相对旋转度使用这个公式:
deg = orgDeg % 360 // This still has negatives: -360° … 0° … 360°
if ( deg < 0 ) deg += 360 // Always 0° … 360°. Now you can rotateY( deg )
- 获取当前面为二进制
0, 1
。
您可能会注意到,一张脸(比如正面)不是从 0 度开始的!
它在-90°
处开始可见(现在标准化为 270)。后面也一样。它在+90°
开始它的 "I'm visible!" 旅程。如果你不跟进,想象一下你想每回合将一张脸换成一张随机图像,一旦表面完全面向前方就这样做是愚蠢的。
所以,当飞机的边缘面向前方时开始转弯!这是数学公式:
face = round( ((deg + 90) % 360) / 360 ) // 0, 1, 0, 1, 0…
让事情更真实一些
透视
将 perspective: 1000px;
添加到父项,有助于可视化 2D3D 中的卡片转换。
动画
缓动 swing
或 linear
(默认 jQuery .animate()
缓动)不适合很好的 easeOutCubic
,这最能描述建筑物-上升 势头自然停止 。
如果你不想包含整个 jQuery UI 库,你可以扩展 $.easing
// https://github.com/gdsmith/jquery.easing
jQuery.extend(jQuery.easing, {
easeOutCubic :function(x){return 1-Math.pow(1-x,3)}
});
速度
通过将刷卡速度添加到卡片旋转来改善用户体验。这是一个函数:
function swipeSpeed(e) {
var st = e.swipestart,
sp = e.swipestop,
time = sp.time - st.time,
a = st.coords[0] - st.coords[1],
b = sp.coords[0] - sp.coords[1],
dist = Math.sqrt( a*a + b*b );
return dist / time;
}
清除动画队列
为了播放来回滑动,您必须使用.stop()
:
.stop().animate({
说够了
// https://github.com/gdsmith/jquery.easing
jQuery.extend(jQuery.easing, {
easeOutCubic: function(x) {
return 1 - Math.pow(1 - x, 3)
}
});
function swipeSpeed(e) {
var st = e.swipestart,
sp = e.swipestop,
time = sp.time - st.time,
a = st.coords[0] - st.coords[1],
b = sp.coords[0] - sp.coords[1],
dist = Math.sqrt(a * a + b * b);
return dist / time;
}
var cats = [ // cause we luw catz
"https://i.stack.imgur.com/bBGtG.jpg",
"https://i.stack.imgur.com/UzdQz.jpg",
"https://i.stack.imgur.com/MJl4g.jpg",
"https://i.stack.imgur.com/7QAyw.jpg",
"https://i.stack.imgur.com/updEN.jpg",
];
var $info = $("#info");
$(".card-wrapper").each(function() {
var $card = $(this).find(".card");
var $back = $(this).find(".card-back");
var _d = 0;
$(this).on({
'swipeleft swiperight': function(e) {
var isLeft = e.type === 'swipeleft';
var sw = Math.min(swipeSpeed(e), 10); // Math.min to prevent excessive momentum
var s = 180 * sw;
var spinDegs = _d + (isLeft ? -s : s);
spinDegs -= spinDegs % 180; // (optional) end rotation as full-face
$card.stop().animate({
sD: spinDegs
}, {
duration: 700 * sw,
easing: "easeOutCubic",
step: function(d) {
_d = d; // store now for later use
var deg = (d %= 360) < 0 ? d + 360 : d; // Degrees Normalization
$(this).css('transform', 'rotateY(' + deg + 'deg)'); // Rotate
// Extra fun!
var face = Math.round(((deg + 90) % 360) / 360);
var idx = Math.abs(Math.round(((_d + 90) / 360)) % cats.length);
$back.css({
backgroundImage: `url('${cats[idx]}')`
});
// Show info
$info.html(`
Face: ${ face }<br>
Org Degrees: ${ _d }<br>
Degrees: ${ deg }<br>
Cat image: ${ idx }
`);
}
});
}
});
});
/* Flipping cards */
.card-wrapper {
width: 200px;
height: 200px;
margin: 0 auto;
perspective: 1000px;
}
.card {
position: relative;
width: 200px;
height: 200px;
transform-style: preserve-3d;
}
.card * {
pointer-events: none;
}
.card .card-front,
.card .card-back {
position: absolute;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
top: 50%;
left: 50%;
backface-visibility: hidden;
font-size: 25px;
color: white;
background: 50% 50%/cover transparent none no-repeat;
}
.card .card-front {
transform: translate(-50%, -50%);
background-color: blue;
}
.card .card-back {
transform: translate(-50%, -50%) rotateY(180deg);
background-color: red;
}
#info {
position: absolute;
pointer-events: none;
top: 0;
left: 0;
}
/* Should all go to top but yeah I'll keep it below-the-fold for this demo*/
/* QuickReset */
* {
margin: 0;
box-sizing: border-box;
}
html,
body {
height: 100%;
font: 14px/1.4 sans-serif;
}
/* jQueryMobile resets */
[data-role="page"] {
outline: none;
}
.ui-loader {
display: none !important;
}
<div class="card-wrapper">
<div class="card">
<div class="card-front"><span class="card-content">SWIPE</span></div>
<div class="card-back"><span class="card-content">:)</span></div>
</div>
</div>
<div id="info"></div>
<script src="//code.jquery.com/jquery-1.11.3.js"></script>
<script src="//code.jquery.com/mobile/1.4.2/jquery.mobile-1.4.2.js"></script>