9am / 9am.github.io

9am Blog 🕘 ㍡
https://9am.github.io/
MIT License
3 stars 0 forks source link

A Flipping Book Magic #11

Open 9am opened 1 year ago

9am commented 1 year ago
After 12 years, I did it again. But with HTML/CSS/JS!
flipping-book hits
9am commented 1 year ago

13 years ago, I just started my career at a startup company. We were building a social APP running on Adobe Flash runtime, which is written in ActionScript3. At that time, web technology is not ready for an RIA(rich interact application), so many things are missing(transition, rotation...) if you want to build something fancy(right in the middle of the Browser Chaos), Flash is the only way to keep the consistency of your app among those browsers.

After 1 year of using the fantastic ActionScript3, I decided to make something outside of work using it. This is my habit of learning a new skill: I will come up with an idea. To fulfill that idea, the proportion of skills I already know to skills I don't know is about 80/20. So after this project, I will test the 80% I've learned and learn 20% new.

The idea to test my ActionScript3 at that time was a Flipping Book.

Flipping Book is an interactive animation that simulates a 3d book flipping effect using 2d programming.

flipr-ss

After 12 years, flash is dead, and the web has evolved a lot in a way I can't even imagine. So same old trick but new technology, I'll build it again. And I know for sure I will learn something new and have some fun during the process. Let's Go!

The Goals

  1. 4 trigger areas at the corner of the book, activate the animation after the mouse enters, and take a drag&drop action to turn the page to the next or previous one.
  2. Make a dynamic shadow effect.
  3. Render the page content from an HTML template.

The Geometry

The geometry is simple as in the old days, take the right top trigger area as an example:

  1. For each frame of the animation, draw a line segment(MR) from the Mouse to the Root corner of the active trigger area.
  2. Draw the perpendicular bisector line of MR as PB.
  3. Find the intersection points of PB and the book boundary lines [i0, i1, i2, i3]
  4. The polygon [R0, R1, i2, i0] will be the mask of the page after the next.
  5. Get the reflection polygon by PB, which will be the mask of the next page.
  6. To make the page looks real, we need to restrain the position of the Mouse. It can not be outside those two circles since one side of the page is stuck to the middle of the book.

Although there are so many details to consider, this model is good enough, to begin with. flipr 001

The Technical Bricks

1. Draw the polygons, HTML, SVG, or Canvas?

In 2023, we have so many choices to do this. SVG has been there for a while and Canvas also provides a bunch of drawing APIs. A normal HTML tag seems to be the last one we consider. It's pretty hard to draw a random polygon with only HTML and CSS. With the old border trick, a triangle is the best we can get.

But to consider actual content in the book, Canvas can only draw an HTMLImageElement. And SVG can only work with its own elements. It would be really nice if we could find a way to draw the polygons using only a normal HTML tag and CSS.

Leave this challenge to the next section, we can build our first implementation with Canvas. polygon

2. Build a mask

As you can see in the GIF, for the next or previous page, we can only see part of the page content. So we need to figure out how to "block" things out.

Canvas provide an API to clip the context CanvasRenderingContext2D.clip(). SVG gives us a <clipPath> element to do the trick. And as for CSS, we have clip-path and mask now.

At this point, everything comes to the right place. We can render any HTML content to the page, and use CSS to transition: rotate() the element and clip-path the area to any path we want. clip

2. A shadow to fool the eyes

We need shadows, without them the book will be like this: shadow-no

SVG and Canvas have filter to make this happen. Lucky for us, CSS gives us linear-gradient and filter too.

To make it even better, we can use CSS custom properties to update the depth of the shadow as we drag the page. shadow-only

@9am/flipr

With all of those in mind, I build a lib. Feel free to try it~ @9am/flipr 📖

npm

npm install @9am/flipr

Edit random-image

What are the new things I've learned from building this?

Well, hope you enjoy it. I'll see you next time.


@9am 🕘