The effect of realistic page turning on JS

I present to your attention - one of the possible options for implementing a rather funny trick to create the effect of realistic page turning. Github



demo and documentation. I implemented a similar effect for a long time, back at the university and at Delphi. It turned out quite worthy, though I spent a lot of time then. Now - during the time of self-isolation, it became interesting to implement something similar on JS, for PC and mobile devices. Frankly, Iโ€™m not sure of the practical applicability of this effect, and I think that in most cases - there is nothing better than a simple change of pictures without any animation. But it is quite possible to use, say on restaurant sites, to publish a menu (but most importantly - that would be duplicated next to the link!).






Everything is written in Typescript. No third-party libraries were used. There are no dependencies.

Key library features


  • Works both with simple images, with rendering on canvas, and with html blocks - using css transformations
  • Pretty flexible configuration system and simple API
  • Supports mobile devices
  • Automatic orientation change between portrait and landscape mode

The code was written with an eye only on ES6 +, and the modular system is also ES6. Browser support is on average 90% based on caniuse.com.

Installation


Installation is possible from npm:

npm install page-flip

Or, download the collected files from the repository.

The basic library initialization option may be something like this:

<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'));

A more detailed description and specification of the API can be found at the link above.
I want to talk about some of the problems and nuances that I encountered during development.

Calculations


The first thing to talk about is a mathematical model. In principle, all the calculations are pretty trivial, but it took me a lot of time.

The main task that needs to be solved is to determine the angle of transformation of the page turning. Let's look at the following image:



Point โ€œAโ€ indicates the current touch point in the book. Based on the position of this point - it is necessary to perform further calculations.

To determine the angle - it is necessary to calculate two values โ€‹โ€‹- the distance from point A to the upper and right borders of the book. In the image below, they are indicated by T and L, respectively.



G is the diagonal of the angle, can be calculated by the Pythagorean theorem.

As a result, to calculate the rotation of the image, you can use the following formula: angle = - 2 * acos (L / G), and most importantly, do not forget that the transformation point in this case is the upper left corner of the page.

After calculating the angle - the most time-consuming part remains - this is calculating the page visibility. What should be apparently necessary to leave, and the rest, respectively - to trim.

First, you need to find the intersection points of the page to be flipped with the borders of the book. In the figures they are indicated by points B and C.



I did this in the simplest and most uncomplicated way - in the forehead. He built the equations of lines by two points, and then looked for their intersection point.

Having found all the intersection points, we determine the vertices of the visibility area - and at these points we are already trimming the page to be flipped.



Basically, all the math here comes down to two things:

  • transformation angle calculation
  • calculation of page visibility

Shading is already based on previously made calculations.

Now let's move on to some points that we had to face during implementation.

The general algorithm is quite simple and comes down to page turning and cropping.

In the case of canvas and simple images, everything is pretty simple. After performing the calculations, 2d canvas context methods such as translate, rotate, and clip are used.
With html blocks a little more complicated. And if there is no problem with rotation - thanks to css transformations, then with cropping everything turned out to be a little worse.

As a result, the easiest way was to use the clip-path and css properties of the figure - polygon. But before setting the polygon vertices for cropping, it is necessary to transform the coordinates of the points from the "global" canvas - into local ones, relative to the html element. This is solved by the reverse application of the rotation matrix, with a shift relative to the position of the element.

Another problem was the scaling and auto-positioning of the book. I tried to solve this with the configuration object, which is passed during creation. But in the end, there were quite a few parameters, and it turned out not quite convenient and not obvious.

I first used Webpack for the assembly, but in the end I decided to try rollup.js, and was very pleasantly surprised by the final code. Webpack still remains, since it handles the assembly on the fly several times faster, and it is more convenient during development.

I will be glad to hear comments and suggestions for further development of the library.

All Articles