Search code examples
javascripthtmlcsspaperjs

Determine scrolled distance on the webpage for Paper.js synchronized scrolling of the view


I have an absolutely positioned canvas laid over a webpage. The canvas has some items created using Paper.js. I want the canvas (or the view) to move in sync with the scrolling of the webpage.

The canvas covers the entire screen (1920 x 1080) not the webpage (1920 x variable length). So, just shifting the canvas's fixed position does not work. It is no longer overlaid on the entire screen.

Later, I found about views in Paper.js and I can use the following line to scroll the view:

project.view.scrollBy(new Point(0, 450));

The problem is that I cannot figure out the value I need to put in place for 450 so that the scrolling is always synchronized.

I do use the following JavaScript to animate the scrolling action on the webpage whenver up and down keys are pressed:

$("section.scrollable").animate({scrollTop : $("section.scrollable").scrollTop() + 300 })

However, putting 300 in the scrollBy values doesn't move the canvas and the webpage in proper synchronization either.

This pen is a very minimal example to show my problem. You might prefer to see it in debug mode.

You can drag over the canvas to create orange lines.

There are three heading and three corresponding lines drawn on an overlaid canvas. The canvas is 1920px wide and 1080px high.

The third heading falls below 1080px so its line is not visible on the canvas. However, it becomes visible when I scroll inside the Paper view by using the following line:

project.view.scrollBy(new Point(0, 600));

Here is my problem with following constraints:

  1. The canvas position has to stay fixed. So, it won't scroll with the rest of the document.
  2. However, the view for Paper.js has to shift in sync with the document so that the lines, paths and other items don't change their relative positions with respect to the webpage. For example, the lines still stay under the same headings.

Solution

  • You need to listen to scroll event and every time it happens, update your paper.js scene y position.
    Rather than using the view, I found that using the active layer was more convenient but you could theoretically do the same with the view.
    Here's a simple fiddle that should get you on the track.

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>Debug Paper.js</title>
        <script src="https://unpkg.com/acorn"></script>
        <script src="https://unpkg.com/paper"></script>
        <style>
            html,
            body {
                margin : 0;
                height : 100%;
            }
    
            canvas {
                position : fixed;
                top      : 0;
                left     : 0;
                width    : 100vw;
                height   : 100vh;
            }
    
            section {
                max-width : 500px;
                margin    : auto;
            }
        </style>
    </head>
    <body>
    
    <section>
        <div>
            <h1>title 1</h1>
            <p>...</p>
        </div>
        <div>
            <h1>title 2</h1>
            <p>...</p>
        </div>
    </section>
    
    <canvas id="canvas" resize></canvas>
    
    <script>
        paper.setup('canvas');
    
        new paper.Path.Circle({
            center: paper.view.center,
            radius: 50,
            fillColor: 'orange'
        });
    
        const originalY = paper.view.center.y;
    
        const update = () => {
            const yOffset = document.scrollingElement.scrollTop;
            paper.view.center.y = originalY - yOffset;
        };
    
        window.addEventListener('scroll', update);
    </script>
    </body>
    </html>