Эффект перелистывания страницы в чистом Javascript

Для веб-приложения для чтения электронных книг я пытаюсь сделать причудливую книжную программу для просмотра электронных книг, например iBooks для iPad и iPhone.

Я нашел отличный плагин jQuery, который я и пытаюсь найти. Единственная проблема в том, что это плагин jQuery, поэтому я не могу его использовать. Как можно было сделать что-то подобное на чистом Javascript?

Ссылка на подключаемый модуль перелистывания страниц jQuery: Плагин Turn JS jQuery


person David Fariña    schedule 09.04.2013    source источник
comment
Пользователи Stackoverflow более охотно реагируют на ответы, когда видят усилия, которые вы приложили для создания чего-либо. Вы пробовали что-то и застряли? У вас есть код, на котором вы застряли? Обычно мы не программируем то, что хотят другие люди, без того, чтобы они сначала не попробовали.   -  person John Riselvato    schedule 09.04.2013
comment
Мы также требуем $$, если вы не докажете нам, что пытались. :)   -  person Sanchit    schedule 09.04.2013
comment
Я не думаю, что вы найдете его, если честно. Похоже, что 90% плагинов сейчас созданы для jQuery. Не для того, чтобы подключать jQuery, но если вы можете кодировать javascript, вы можете очень быстро изучить jQuery.   -  person dgig    schedule 09.04.2013
comment
Хорошо, причина, по которой я ничего не пробовал до сих пор, заключается в том, что я действительно понятия не имею, как начать делать физику листа и так далее. Я подумал, может быть, кто-то знает хороший учебник или подсказку, с чего начать...   -  person David Fariña    schedule 09.04.2013
comment
@user399696 user399696 И я знаю jQuery, на самом деле я начал разрабатывать клиентскую часть с помощью jQuery, пока не понял, что у него больше отрицательных моментов, чем положительных. Одним из основных моментов является производительность. Вот почему я не хочу его использовать...   -  person David Fariña    schedule 09.04.2013
comment
jQuery не делает ваш код менее производительным, это ерунда. Когда это возможно, jquery возвращается к собственному API. Более того, даже в современных браузерах есть масса ошибок, которые превращают использование нативного API в кошмар, если вам требуется кросс-браузерная совместимость. Может быть, вам все равно, но разработчикам библиотек это важно.   -  person mpm    schedule 09.04.2013
comment
Может быть, вы не знаете, что говорите, или вы так любите jquery, что ВАМ все равно. Я очень забочусь о совместимости браузера, и я очень забочусь о производительности. И, может быть, вы не знаете, но каждый раз, когда вы вызываете $, инициализируется весь объект jquery. Это потому, что jQuery использует оболочку для своих прототипов методов, чтобы избежать конфликтов, что делает его значительно медленнее. Для простого селектора сначала требуется почти 80 строк кода, даже для селектора #id, что делает его в сто раз медленнее. Конечно, кто-то использует jquery не просто для селектора ID, а просто в качестве примера.   -  person David Fariña    schedule 09.04.2013
comment
Даже если вы не хотите использовать 90% функциональности jQuery, она инициализируется, независимо от того, используете вы их или нет...   -  person David Fariña    schedule 09.04.2013
comment
@DavidFariña, будьте осторожны, не сосредотачивайтесь на этом уровне производительности слишком рано. Преждевременная оптимизация. ;-) Если вас действительно волнует разница в производительности решения на основе чистого JavaScript и решения на основе jQuery, то вам не следует выполнять анимацию перелистывания страниц для начала.   -  person Travis Watson    schedule 09.04.2013
comment
Почему бы и нет? Все мое приложение будет построено на javascript для внешнего интерфейса. Данные электронной книги будут загружены с помощью игровой платформы в бэкэнде, разработанном в scala. Но поскольку весь пользовательский интерфейс будет построен на javascript, я должен заботиться о производительности настолько глубоко. Мой единственный вопрос был, с чего начать. Я очень хорошо знаю javascript, и я очень хорошо знаю jquery, единственное, чего мне не хватает, это математики, когда она слишком глубока. Если никто не хочет дать мне подсказку, с чего начать, я думаю, что действительно трачу свое время здесь.   -  person David Fariña    schedule 09.04.2013
comment
Вы когда-нибудь строили это?   -  person John Riselvato    schedule 31.10.2013
comment
Я попробовал на вашем примере, и сработало, но к сожалению (или к счастью для меня) моя компания закрыла проект   -  person David Fariña    schedule 05.11.2013


Ответы (2)


Как бы вы ни думали, что это лучше делать только с помощью JavaScript, вы должны понимать, что это может быть очень сложно, и без надлежащего понимания математики, и все это, вероятно, займет у вас больше времени, чтобы понять, чем подключаемый модуль, который вы показали выше. В любом случае с Google я нашел пару jsfiddles, которые могут привести вас в правильном направлении.

Чистый эффект переворота JavaScript: http://jsfiddle.net/maitrekaio/nuUNd/

// Dimensions of the whole book
var BOOK_WIDTH = 630;
var BOOK_HEIGHT = 260;

// Dimensions of one page in the book
var PAGE_WIDTH = 300;
var PAGE_HEIGHT = 250;

// Vertical spacing between the top edge of the book and the papers
var PAGE_Y = (BOOK_HEIGHT - PAGE_HEIGHT) / 2;

// The canvas size equals to the book dimensions + this padding
var CANVAS_PADDING = 30;

var progress = 1;
var target = -1;

var canvas = document.getElementById("pageflip-canvas");
var context = canvas.getContext("2d");
var fillElt = document.getElementById("fill");
var droppedShadowElt = document.getElementById("droppedShadow");
var sharpShadowElt = document.getElementById("sharpShadow");
var progressElt = document.getElementById("progress");
var foldWidthElt = document.getElementById("foldWidth");
var foldXElt = document.getElementById("foldX");

// Resize the canvas to match the book size
canvas.width = BOOK_WIDTH;
canvas.height = BOOK_HEIGHT + (CANVAS_PADDING * 2);

progressElt.addEventListener("change", render, false);

function render() {

    // Reset all pixels in the canvas
    context.clearRect(0, 0, canvas.width, canvas.height);

    // Ease progress towards the target value 
    progress = progressElt.value;
    // Strength of the fold is strongest in the middle of the book
    var strength = 1 - Math.abs(progress);

    // Width of the folded paper
    var foldWidth = (PAGE_WIDTH * 0.5) * (1 - progress);

    // X position of the folded paper
    var foldX = PAGE_WIDTH * progress + foldWidth;

    // How far the page should outdent vertically due to perspective
    var verticalOutdent = 20 * strength;

    foldWidthElt.value = foldWidth;
    foldXElt.value = foldX;

    context.save();
    context.translate((BOOK_WIDTH / 2), PAGE_Y + CANVAS_PADDING);

    drawFoldedPaper(foldX, foldWidth, verticalOutdent, fillElt.checked);


    if (sharpShadowElt.checked) {
        drawSharpShadow(foldX, foldWidth, verticalOutdent, strength);
    }

    if (droppedShadowElt.checked) {
        drawDroppedShadow(foldX, foldWidth, strength);
    }

    context.restore();
}


// Draw the folded piece of paper
function drawFoldedPaper(foldX, foldWidth, verticalOutdent, fill) {
    context.beginPath();
    context.moveTo(foldX, 0);
    context.lineTo(foldX, PAGE_HEIGHT);
    context.quadraticCurveTo(foldX, PAGE_HEIGHT + (verticalOutdent * 2), foldX - foldWidth, PAGE_HEIGHT + verticalOutdent);
    context.lineTo(foldX - foldWidth, -verticalOutdent);
    context.quadraticCurveTo(foldX, -verticalOutdent * 2, foldX, 0);

    if (fill) {
        // Gradient applied to the folded paper (highlights & shadows)
        var paperShadowWidth = (PAGE_WIDTH * 0.5) * Math.max(Math.min(1 - progress, 0.5), 0);
        var foldGradient = context.createLinearGradient(foldX - paperShadowWidth, 0, foldX, 0);
        foldGradient.addColorStop(0.35, '#fafafa');
        foldGradient.addColorStop(0.73, '#eeeeee');
        foldGradient.addColorStop(0.9, '#fafafa');
        foldGradient.addColorStop(1.0, '#e2e2e2');
        context.fillStyle = foldGradient;
        context.fill();
    }
    context.strokeStyle = 'rgba(0,0,0,0.06)';
    context.lineWidth = 2;
    context.stroke();
}

// Draw a sharp shadow on the left side of the page
function drawSharpShadow(foldX, foldWidth, verticalOutdent, strength) {
    context.strokeStyle = 'rgba(0,0,0,'+(0.05 * strength)+')';
    context.lineWidth = 30 * strength;
    context.beginPath();
    context.moveTo(foldX - foldWidth, -verticalOutdent * 0.5);
    context.lineTo(foldX - foldWidth, PAGE_HEIGHT + (verticalOutdent * 0.5));
    context.stroke();
}

function drawDroppedShadow(foldX, foldWidth, strength) {    
    // Right side drop shadow
    var rightShadowWidth = (PAGE_WIDTH * 0.5) * Math.max(Math.min(strength, 0.5), 0);
    var rightShadowGradient = context.createLinearGradient(foldX, 0, foldX + rightShadowWidth, 0);
    rightShadowGradient.addColorStop(0, 'rgba(0,0,0,'+(strength*0.2)+')');
    rightShadowGradient.addColorStop(0.8, 'rgba(0,0,0,0.0)');

    context.fillStyle = rightShadowGradient;
    context.beginPath();
    context.moveTo(foldX, 0);
    context.lineTo(foldX + rightShadowWidth, 0);
    context.lineTo(foldX + rightShadowWidth, PAGE_HEIGHT);
    context.lineTo(foldX, PAGE_HEIGHT);
    context.fill();


    // Left side drop shadow
    var leftShadowWidth = (PAGE_WIDTH * 0.5) * Math.max(Math.min(strength, 0.5), 0);
    var leftShadowGradient = context.createLinearGradient(foldX - foldWidth - leftShadowWidth, 0, foldX - foldWidth, 0);
    leftShadowGradient.addColorStop(0, 'rgba(0,0,0,0.0)');
    leftShadowGradient.addColorStop(1, 'rgba(0,0,0,'+(strength*0.15)+')');

    context.fillStyle = leftShadowGradient;
    context.beginPath();
    context.moveTo(foldX - foldWidth - leftShadowWidth, 0);
    context.lineTo(foldX - foldWidth, 0);
    context.lineTo(foldX - foldWidth, PAGE_HEIGHT);
    context.lineTo(foldX - foldWidth - leftShadowWidth, PAGE_HEIGHT);
    context.fill();    
}

Эффект переворота jQuery (это не должно быть проблемой при преобразовании в чистый JavaScript): http://jsfiddle.net/pixelass/TW43V/61/

Другой эффект переворота jQuery: http://jsfiddle.net/wdm954/DkZsY/2/

потому что вы хотите, чтобы чистый JavaScript знал, что вам нужно выяснить, как это сделать самостоятельно. Использование этих примеров в качестве рекомендаций будет полезно, даже если они не являются чистым js.

person John Riselvato    schedule 09.04.2013
comment
хорошо, это не совсем то, что я хотел, но больше, чем я ожидал. Спасибо, что уделили мне время - person David Fariña; 10.04.2013

Этот вопрос довольно старый, но я размещу ссылку, откуда была взята идея для утвержденного ответа - http://www.html5rocks.com/en/tutorials/casestudies/20things_pageflip/. Хороший учебник с объяснением и примерами.

person eduard.dudar    schedule 16.09.2013
comment
Это должен быть комментарий к исходному ответу, а не ответ - person froggomad; 08.12.2018