mirror of
https://github.com/blasten/turn.js.git
synced 2026-07-13 21:31:10 +08:00
Replace setInterval with requestAnimationFrame
This commit is contained in:
parent
045845c851
commit
7e7bd0b70a
@ -25,7 +25,8 @@ La compatibilité avec tous les navigateurs et appareils modernes n'est pas enco
|
||||
- restaure les pages originales comme enfants directs ;
|
||||
- restaure les attributs `style` et `class` d'origine ;
|
||||
- supprime les données jQuery internes de turn.js sans effacer les données utilisateur sans lien.
|
||||
- Correction de `animatef(false)` pour que l'annulation d'une animation nettoie bien l'intervalle actif.
|
||||
- Remplacement de la boucle d'animation interne `setInterval` par `requestAnimationFrame`.
|
||||
- Correction de `animatef(false)` pour que l'annulation d'une animation annule bien la frame planifiée.
|
||||
- Ajout d'une démo navigateur minimale avec jQuery `4.0.0`.
|
||||
- Ajout de texte et d'images locales dans la démo minimale.
|
||||
- Correction de la mise en page de la démo minimale afin que les dimensions mesurées par turn.js correspondent à la taille réellement rendue des pages.
|
||||
@ -167,6 +168,7 @@ La suite actuelle couvre :
|
||||
- `addPage` / `removePage` dynamiques ;
|
||||
- l'enregistrement des namespaces d'événements ;
|
||||
- le nettoyage `destroy` et la réinitialisation ;
|
||||
- la planification et l'annulation `requestAnimationFrame` dans `animatef` ;
|
||||
- le rendu de la démo minimale ;
|
||||
- le rendu après page tournée ;
|
||||
- la géométrie en viewport compact ;
|
||||
|
||||
@ -1,154 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
|
||||
<script type="text/javascript" src="../../turn.min.js"></script>
|
||||
|
||||
<style type="text/css">
|
||||
body{
|
||||
background:#ccc;
|
||||
}
|
||||
#book{
|
||||
width:800px;
|
||||
height:500px;
|
||||
}
|
||||
|
||||
#book .turn-page{
|
||||
background-color:white;
|
||||
}
|
||||
|
||||
#book .cover{
|
||||
background:#333;
|
||||
}
|
||||
|
||||
#book .cover h1{
|
||||
color:white;
|
||||
text-align:center;
|
||||
font-size:50px;
|
||||
line-height:500px;
|
||||
margin:0px;
|
||||
}
|
||||
|
||||
#book .loader{
|
||||
background-image:url(loader.gif);
|
||||
width:24px;
|
||||
height:24px;
|
||||
display:block;
|
||||
position:absolute;
|
||||
top:238px;
|
||||
left:188px;
|
||||
}
|
||||
|
||||
#book .data{
|
||||
text-align:center;
|
||||
font-size:40px;
|
||||
color:#999;
|
||||
line-height:500px;
|
||||
}
|
||||
|
||||
#controls{
|
||||
width:800px;
|
||||
text-align:center;
|
||||
margin:20px 0px;
|
||||
font:30px arial;
|
||||
}
|
||||
|
||||
#controls input, #controls label{
|
||||
font:30px arial;
|
||||
}
|
||||
|
||||
#book .odd{
|
||||
background-image:-webkit-linear-gradient(left, #FFF 95%, #ddd 100%);
|
||||
background-image:-moz-linear-gradient(left, #FFF 95%, #ddd 100%);
|
||||
background-image:-o-linear-gradient(left, #FFF 95%, #ddd 100%);
|
||||
background-image:-ms-linear-gradient(left, #FFF 95%, #ddd 100%);
|
||||
}
|
||||
|
||||
#book .even{
|
||||
background-image:-webkit-linear-gradient(right, #FFF 95%, #ddd 100%);
|
||||
background-image:-moz-linear-gradient(right, #FFF 95%, #ddd 100%);
|
||||
background-image:-o-linear-gradient(right, #FFF 95%, #ddd 100%);
|
||||
background-image:-ms-linear-gradient(right, #FFF 95%, #ddd 100%);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="book">
|
||||
<div class="cover"><h1>The Bible</h1></div>
|
||||
</div>
|
||||
|
||||
<div id="controls">
|
||||
<label for="page-number">Page:</label> <input type="text" size="3" id="page-number"> of <span id="number-pages"></span>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
// Sample using dynamic pages with turn.js
|
||||
|
||||
var numberOfPages = 1000;
|
||||
|
||||
|
||||
// Adds the pages that the book will need
|
||||
function addPage(page, book) {
|
||||
// First check if the page is already in the book
|
||||
if (!book.turn('hasPage', page)) {
|
||||
// Create an element for this page
|
||||
var element = $('<div />', {'class': 'page '+((page%2==0) ? 'odd' : 'even'), 'id': 'page-'+page}).html('<i class="loader"></i>');
|
||||
// If not then add the page
|
||||
book.turn('addPage', element, page);
|
||||
// Let's assum that the data is comming from the server and the request takes 1s.
|
||||
setTimeout(function(){
|
||||
element.html('<div class="data">Data for page '+page+'</div>');
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
$(window).ready(function(){
|
||||
$('#book').turn({acceleration: true,
|
||||
pages: numberOfPages,
|
||||
elevation: 50,
|
||||
gradients: !$.isTouch,
|
||||
when: {
|
||||
turning: function(e, page, view) {
|
||||
|
||||
// Gets the range of pages that the book needs right now
|
||||
var range = $(this).turn('range', page);
|
||||
|
||||
// Check if each page is within the book
|
||||
for (page = range[0]; page<=range[1]; page++)
|
||||
addPage(page, $(this));
|
||||
|
||||
},
|
||||
|
||||
turned: function(e, page) {
|
||||
$('#page-number').val(page);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('#number-pages').html(numberOfPages);
|
||||
|
||||
$('#page-number').keydown(function(e){
|
||||
|
||||
if (e.keyCode==13)
|
||||
$('#book').turn('page', $('#page-number').val());
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
$(window).bind('keydown', function(e){
|
||||
|
||||
if (e.target && e.target.tagName.toLowerCase()!='input')
|
||||
if (e.keyCode==37)
|
||||
$('#book').turn('previous');
|
||||
else if (e.keyCode==39)
|
||||
$('#book').turn('next');
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.5 KiB |
@ -25,7 +25,8 @@ Compatibility is not yet guaranteed for every modern browser or device. Safari/W
|
||||
- restores original page elements as direct children;
|
||||
- restores original `style` and `class` attributes;
|
||||
- removes turn.js internal jQuery data while preserving unrelated user data.
|
||||
- Fixed `animatef(false)` so cancelling an animation clears the active interval.
|
||||
- Replaced the internal `setInterval` animation loop with `requestAnimationFrame`.
|
||||
- Fixed `animatef(false)` so cancelling an animation cancels the scheduled animation frame.
|
||||
- Added a minimal browser demo using jQuery `4.0.0`.
|
||||
- Added text and local images to the minimal demo.
|
||||
- Fixed minimal demo layout so turn.js page measurements match the real rendered page size.
|
||||
@ -167,6 +168,7 @@ The current suite covers:
|
||||
- dynamic `addPage` / `removePage`;
|
||||
- event namespace registration;
|
||||
- `destroy` cleanup and re-initialization;
|
||||
- `requestAnimationFrame` scheduling and cancellation in `animatef`;
|
||||
- minimal demo rendering;
|
||||
- page turn rendering;
|
||||
- compact viewport geometry;
|
||||
|
||||
@ -11,7 +11,7 @@ const jqueryDist = dirname(require.resolve('jquery'));
|
||||
const jquerySource = readFileSync(resolve(jqueryDist, 'jquery.js'), 'utf8');
|
||||
const turnSource = readFileSync(resolve(__dirname, '../../turn.js'), 'utf8');
|
||||
|
||||
function createFixture(pageCount = 4) {
|
||||
function createFixture(pageCount = 4, windowOptions = {}) {
|
||||
const pages = Array.from({ length: pageCount }, (_, index) => (
|
||||
`<div class="page">Page ${index + 1}</div>`
|
||||
)).join('');
|
||||
@ -22,6 +22,13 @@ function createFixture(pageCount = 4) {
|
||||
url: 'http://localhost/'
|
||||
});
|
||||
|
||||
Object.entries(windowOptions).forEach(([key, value]) => {
|
||||
Object.defineProperty(dom.window, key, {
|
||||
value,
|
||||
configurable: true,
|
||||
writable: true
|
||||
});
|
||||
});
|
||||
dom.window.eval(jquerySource);
|
||||
const $ = dom.window.jQuery;
|
||||
dom.window.eval(turnSource);
|
||||
@ -166,6 +173,53 @@ describe('turn.js jQuery plugin', () => {
|
||||
expect($book.find('.turn-page-wrapper').length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('uses requestAnimationFrame for animatef animations', () => {
|
||||
fixture.window.close();
|
||||
|
||||
const frameCallbacks = [];
|
||||
let frameHandle = 0;
|
||||
const requestAnimationFrame = vi.fn(callback => {
|
||||
frameCallbacks.push(callback);
|
||||
frameHandle += 1;
|
||||
return frameHandle;
|
||||
});
|
||||
const cancelAnimationFrame = vi.fn();
|
||||
|
||||
fixture = createFixture(4, {
|
||||
performance: { now: vi.fn(() => 0) },
|
||||
requestAnimationFrame,
|
||||
cancelAnimationFrame
|
||||
});
|
||||
|
||||
const { $ } = fixture;
|
||||
const frames = [];
|
||||
const complete = vi.fn();
|
||||
const $element = $('<div></div>');
|
||||
|
||||
$element.animatef({
|
||||
from: 0,
|
||||
to: 10,
|
||||
duration: 32,
|
||||
easing: (x, t, b, c, d) => b + c * (t / d),
|
||||
frame: value => frames.push(value),
|
||||
complete
|
||||
});
|
||||
|
||||
expect(frames).toEqual([0]);
|
||||
expect(requestAnimationFrame).toHaveBeenCalledTimes(1);
|
||||
|
||||
frameCallbacks.shift()(16);
|
||||
expect(frames[1]).toBe(5);
|
||||
expect(requestAnimationFrame).toHaveBeenCalledTimes(2);
|
||||
|
||||
$element.animatef(false);
|
||||
expect(cancelAnimationFrame).toHaveBeenCalledWith(2);
|
||||
|
||||
frameCallbacks.shift()(32);
|
||||
expect(frames).toEqual([0, 5]);
|
||||
expect(complete).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('registers internal handlers with event namespaces', () => {
|
||||
fixture.window.close();
|
||||
fixture = createFixture();
|
||||
|
||||
44
turn.js
44
turn.js
@ -34,6 +34,20 @@ var has3d,
|
||||
events = (isTouch) ? {start: 'touchstart', move: 'touchmove', end: 'touchend'}
|
||||
: {start: 'mousedown', move: 'mousemove', end: 'mouseup'},
|
||||
|
||||
frameTime = (window.performance && window.performance.now) ?
|
||||
function() { return window.performance.now(); } :
|
||||
function() { return new Date().getTime(); },
|
||||
|
||||
requestFrame = window.requestAnimationFrame ||
|
||||
window.webkitRequestAnimationFrame ||
|
||||
window.mozRequestAnimationFrame ||
|
||||
function(callback) { return window.setTimeout(function() { callback(frameTime()); }, 16); },
|
||||
|
||||
cancelFrame = window.cancelAnimationFrame ||
|
||||
window.webkitCancelAnimationFrame ||
|
||||
window.mozCancelAnimationFrame ||
|
||||
function(handle) { window.clearTimeout(handle); },
|
||||
|
||||
turnEventNamespace = '.turn',
|
||||
|
||||
turnFlipEventNamespace = '.turnFlip',
|
||||
@ -2008,7 +2022,7 @@ $.extend($.fn, {
|
||||
var data = this.data();
|
||||
|
||||
if (data.effect)
|
||||
clearInterval(data.effect.handle);
|
||||
cancelFrame(data.effect.handle);
|
||||
|
||||
if (point) {
|
||||
|
||||
@ -2019,11 +2033,16 @@ $.extend($.fn, {
|
||||
var j, diff = [],
|
||||
len = point.to.length,
|
||||
that = this,
|
||||
fps = point.fps || 30,
|
||||
time = - fps,
|
||||
f = function() {
|
||||
var j, v = [];
|
||||
time = Math.min(point.duration, time + fps);
|
||||
startTime = frameTime(),
|
||||
f = function(timestamp) {
|
||||
|
||||
if (that.data().effect!==point)
|
||||
return;
|
||||
|
||||
timestamp = timestamp || frameTime();
|
||||
|
||||
var time = Math.min(point.duration, Math.max(0, timestamp - startTime)),
|
||||
j, v = [];
|
||||
|
||||
for (j = 0; j < len; j++)
|
||||
v.push(point.easing(1, time, point.from[j], diff[j], point.duration));
|
||||
@ -2031,24 +2050,25 @@ $.extend($.fn, {
|
||||
point.frame((len==1) ? v[0] : v);
|
||||
|
||||
if (time==point.duration) {
|
||||
clearInterval(data.effect.handle);
|
||||
delete data['effect'];
|
||||
that.data(data);
|
||||
if (point.complete)
|
||||
point.complete();
|
||||
}
|
||||
};
|
||||
} else {
|
||||
data.effect.handle = requestFrame(f);
|
||||
that.data(data);
|
||||
}
|
||||
};
|
||||
|
||||
for (j = 0; j < len; j++)
|
||||
diff.push(point.to[j] - point.from[j]);
|
||||
|
||||
data.effect = point;
|
||||
data.effect.handle = setInterval(f, fps);
|
||||
this.data(data);
|
||||
f();
|
||||
f(startTime);
|
||||
} else {
|
||||
if (data.effect && data.effect.handle)
|
||||
clearInterval(data.effect.handle);
|
||||
cancelFrame(data.effect.handle);
|
||||
delete data['effect'];
|
||||
}
|
||||
}
|
||||
|
||||
2
turn.min.js
vendored
2
turn.min.js
vendored
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user