Ваш удар и анимация сломаны. Если вы проведете пальцем влево несколько раз, вы увидите, что переход не может следить за текущим состоянием поворота градусов - с новым входом.
Решение
- Используйте переменную для хранения текущего Исходного поворота градусов (
-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°
. Если вы не последуете, представьте, что вы хотите менять лицо на случайное изображение каждый ход, было бы глупо делать это, когда поверхность полностью обращена вперед.
Итак, ход начинается, когда края самолета обращены вперед! Вот математика:
face = round( ((deg + 90) % 360) / 360 ) // 0, 1, 0, 1, 0…
Сделайте вещи немного более реалистичными
Перспектива
Добавление perspective: 1000px;
к родителю, помогает визуализировать преобразования карт в 2D3D .
Анимация
Ослабление swing
или linear
(по умолчанию jQuery .animate()
замедления) не подходят как хороший easeOutCubic
, который лучше всего описывает импульс роста к естественной остановке .
Если вы не хотите включать всю библиотеку пользовательского интерфейса jQuery, вы можете расширить $.easing
// https://github.com/gdsmith/jquery.easing
jQuery.extend(jQuery.easing, {
easeOutCubic :function(x){return 1-Math.pow(1-x,3)}
});
Скорость
Улучшите UX, добавив скорость прокрутки к вращению карты . Вот функция:
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>