Как стать автором
Обновить

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

Время на прочтение4 мин
Количество просмотров24K
Представляю вашему вниманию — один из возможных вариантов реализации довольно забавного приема, для создания эффекта реалистичного перелистывания страниц.



Демо и документация
Github
Плагин для React

Подобный эффект я реализовывал данным давно, еще в университете и на Delphi. Получилось вполне достойно, правда времени я потратил тогда очень много. Сейчас, во время самоизоляции, стало интересно реализовать что-то подобное на JS, для PC и мобильных устройств.

Признаться честно, я не уверен в практической применимости данного эффекта, и думаю что в большинстве случаев, нет ничего лучше простой смены картинок без всякой анимации. Но это вполне можно использовать, допустим на сайтов ресторанов, для публикации меню (но главное — что бы рядом дублировалось ссылкой!).

Написано все на Typescript. Не использовались ни какие сторонние библиотеки. Зависимостей нет.

Ключевые особенности библиотеки


  • Работает как с простыми изображениями, с отрисовкой на canvas, так и с html блоками — используя css трансформации
  • Довольно гибкая система конфигурации и простое API
  • Поддерживает мобильные устройства
  • Автоматическая смена ориентации между портретным и ландшафтным режимом

Код писал с оглядкой только на ES6+, и модульная система тоже ES6. Поддержка браузерами в среднем на уровне 90%, основываясь на caniuse.com.

Установка


Установка возможна из npm:

npm install page-flip

Либо, скачать собранные файлы из репозитория

Базовый вариант инициализации библиотеки может быть примерно таким:

<div id="book">
    <div class="my-page">
        Page one
    </div>
    <div class="my-page">
        Page two
    </div>
    <div class="my-page">
        Page three
    </div>
    <div class="my-page">
        Page four
    </div>
</div>

import {PageFlip} from 'page-flip';
const pageFlip = new PageFlip(document.getElementById('book'),
    {
        width: 400, // required parameter - base page width
        height: 600  // required parameter - base page height
    }
);

pageFlip.loadFromHTML(document.querySelectorAll('.my-page'));

Более подробное описание, и спецификацию API — можно найти по ссылке выше.
Я же хочу рассказать о некоторых проблемах и нюансах с которыми столкнулся во время разработки.

Расчеты


Первое, о чем нужно рассказать, это математическая модель. В принципе, все расчеты довольно тривиальны, но у меня отняло немало времени.

Основная задача, которую требуется решить — это определить угол трансформации поворота перелистываемой страницы. Давай посмотрим на следующее изображение:



Точкой «A» обозначена текущая точка касания в книге. Исходя из положения этой точки, необходимо выполнить дальнейшие расчеты.

Для определения угла необходимо рассчитать два значения: расстояние от точки А до верхней и правой границ книги. На изображении ниже они обозначены T и L соответственно.



G — диагональ угла, можно рассчитать по теореме Пифагора.

В итоге, для расчета поворота изображения можно воспользоваться следующей формулой: angle = — 2 * acos(L / G), и главное не забывать что точкой трансформации в данном случае является верхний левый угол страницы.

После расчета угла, остается самая трудоемкая часть — это расчет области видимости страницы. То, что должно быть видимо необходимо оставить, а остальное, соответственно — обрезать.

Для начала, нужно найти точки пересечения перелистываемой страницы с границами книги. На рисунками они обозначены точками B и C.



Я делал это самым простым и незамысловатым способом — в лоб. Строил уравнения прямых по двум точкам, и далее искал их точку пересечения.

Найдя все точки пересечения, определяем вершины области видимости — и по этим точкам уже выполняем обрезку перелистываемой страницы.



В принципе, вся математика здесь и сводится к двум вещам:

  • расчет угла трансформации
  • расчет области видимости страниц

Наложение теней производится уже на основе ранее сделанных расчетов.

Теперь перейдем к некоторым моментам, с которыми пришлось столкнутся при реализации.

Общий алгоритм довольно простой и сводится к поворотам и обрезке страниц.

В случае с canvas и простыми изображениями — все довольно просто. После выполнения расчетов, используются методы 2d контекста холста, такие как translate, rotate и clip.
С html блоками несколько сложнее. И если с поворотом, благодаря css трансформациям, проблем нет, то с обрезкой все оказалось несколько хуже.

В итоге, самым простым способом, оказалось использование свойства clip-path и css фигуры polygon. Но прежде чем задавать вершины многоугольника для обрезки, необходимо выполнить трансформацию координат точек из «глобальных» холста — в локальные, относительно html элемента. Решается это обратным применением матрицы поворота, со сдвигом относительно позиции элемента.

Другой проблемой было масштабирование и авто-позиционирование книги. Это я попытался решить объектом конфигурации, который передается при создании. Но в итоге, параметров стало довольно много, и получилось не совсем удобно и не очевидно.

Для сборки сначала использовал Webpack, но в итоге все-таки решил попробовать rollup.js, и был очень приятно удивлен итоговым кодом. Webpack пока остается, поскольку справляется со сборкой на лету в несколько раз быстрее, а при разработке это удобнее.

Буду рад услышать комментарии, и предложения по дальнейшей разработке библиотеки.
Теги:
Хабы:
+28
Комментарии14

Публикации

Изменить настройки темы

Истории

Работа

Ближайшие события

PG Bootcamp 2024
Дата16 апреля
Время09:30 – 21:00
Место
МинскОнлайн
EvaConf 2024
Дата16 апреля
Время11:00 – 16:00
Место
МоскваОнлайн
Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн