Search code examples
javascriptcanvasgraphicspaperjs

PaperJS canvas drawing area only in top left corner unless external action taken


I am trying to create an interactive svg tool which I hope will eventually be able to 'spot refine' SVGs using PaperJS.

Getting the groundwork done had been going well, but when I load my page (opening the html file locally with paperscript-full.js linked) I can get mouse to follow the cursor but only in a small square at the top left of the canvas. As soon as I use the inspect tool I am now free to use fly about (what I presume is based upon the border) - the entire canvas area.

Here is a fiddle which doesn't actually demonstrate the issue but has all my source code. I did this because I feel it would take too long to indent all of my code on here: fiddle

Also it is not strictly linked to the question but if anyone could tell me why my canvas grows in width every time I resize as well that would be very much appreciated


Solution

  • The issue you are encountering regarding mouse event being only captured in the top left corner is due to the fact that you are resizing canvas programmatically after Paper.js has been set up.
    Because you are using PaperScript, Paper.js has already been set up when your code is run. There are at least 2 ways to work that around:

    • use JavaScript instead of PaperScript and first set canvas size, then bind Paper.js to the canvas manually using paper.setup() method.
    • control canvas size with CSS (I choose this way in following solution).

    About the second part of your question, your canvas grows when you resize the window because of the canvas resize attribute which is implicitly set to true in your code.
    Quoting from documentation:

    resize="true": Makes the canvas object as high and wide as the Browser window and resizes it whenever the user resizes the window. When the window is resized, the size of your global.view is also automatically adjusted.

    There are other improvements that can be done to your code, I directly included them in the following example:

    body,
    html {
      width: 100%;
      height: 100%;
      margin: 0;
    }
    
    
    /* set canvas size and position with CSS */
    
    main {
      height: 100vh;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    
    canvas {
      width: 90vw;
      height: 90vh;
      border: 1px solid;
    }
    
    #opts {
      position: absolute;
      right: 10vw;
      bottom: 10vh;
    }
    <!-- dependencies -->
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/paper.js/0.11.5/paper-full.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    
    <!-- slider -->
    <div id="opts">
      <input id="tool" type="range" name="tool" min="1" max="10" value="1" step="1" />
    </div>
    
    <!-- wrap canvas for easier vertical alignment -->
    <main>
      <canvas id="canvas" resize></canvas>
    </main>
    
    <!-- paper.js code -->
    <script type="text/paperscript" canvas="canvas">
    
        // image should be drawn using paper Raster
        var raster = new Raster({
            source: 'https://picjumbo.com/wp-content/uploads/vineyards-on-italian-coast-free-photo-DSC04256-1080x720.jpg',
            onLoad: function() {
                // position image at view center
                this.fitBounds(view.bounds.scale(0.5));
            }
        });
    
        // create circle
        var path = new Path.Circle({
            // here you can directly use paper view object
            center: view.center,
            radius: 10,
            // style can directly be set in constructor options
            strokeColor: 'red',
            strokeWidth: 3,
            // disable matrix application for easier scale control
            applyMatrix: false,
            // make stroke width independant from scale
            strokeScaling: false
        });
    
        // in paperscript context you can directly use named onMouseMove function
        function onMouseMove(event) {
            path.position = event.point;
        }
    
        // adapt path scale to slider value
        $('#tool').change(function(event) {
            path.scaling = this.value;
        });
    </script>