lolol
lolol

Reputation: 4390

canvas drawing margin correction

I'm trying some draw techniques I found in this URL:

http://perfectionkills.com/exploring-canvas-drawing-techniques/

I just noticed that the higher level css properties are not applied to the canvas element mouse events. Is there a easy way to fix this?

<head>

    <meta charset="utf-8">
    <title>Spray Can</title>

    <style>

    body {
        margin: 0;
        padding: 0;
    }

    #container {
        border: 1px solid #ccc;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
    }

    #canvas {
    }

    </style>

    <script>

        document.addEventListener('DOMContentLoaded', function () {

            var canvas = document.getElementById('canvas');
            var context = canvas.getContext('2d');
            var isDrawing;

            canvas.onmousedown = function(e) {
                isDrawing = true;
                context.moveTo(e.clientX, e.clientY);
            };

            canvas.onmousemove = function(e) {

                if (isDrawing) {

                    var k = 4;

                    var radgrad = context.createRadialGradient(e.clientX, e.clientY, k, e.clientX, e.clientY, k * 2);

                    radgrad.addColorStop(0, 'rgba(0,0,0,1)');
                    radgrad.addColorStop(0.5, 'rgba(0,0,0,0.5)');
                    radgrad.addColorStop(1, 'rgba(0,0,0,0)');
                    context.fillStyle = radgrad;

                    context.fillRect(e.clientX - k * 2, e.clientY - k * 2, k * 2 * 2, k * 2 * 2);

                }

            };

            canvas.onmouseup = function() {
                isDrawing = false;
            };

        });

    </script>

</head>

<body>

    <div id="container">
        <canvas id="canvas" width="400" height="400"></canvas>
    </div>

</body>

https://jsfiddle.net/crpq8t5q/1/

Upvotes: 1

Views: 617

Answers (1)

Kaiido
Kaiido

Reputation: 136698

What you need is to convert your mouse event's coordinates to be relative to the canvas ones.

Since here you don't touch the scale nor rotation this is just a simple canvasX = mouseX - canvas.offsetLeft and canvasY = mouseY - canvas.offsetTop.

These offsetXXX properties are available on the canvas, but you can also use getBoundingClientRect()which will return better results if your css is more complicated (e.g nested elements with different scrollable areas).

But since this offset will change each time you scroll or resize the page, you need to update these values.

Also, it is a very bad idea to create a readialGradient in a mouse event. This event can fire at really high rate, and creating gradients eats memory.
It is then better to create a single gradient, and modify your whole context's matrix so that the gradient be placed at the mouse coordinates :

var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var isDrawing;

var k = 4;
// create the gradient only once
var radgrad = context.createRadialGradient(0, 0, k, 0, 0, k * 2);
radgrad.addColorStop(0, 'rgba(0,0,0,1)');
radgrad.addColorStop(0.5, 'rgba(0,0,0,0.5)');
radgrad.addColorStop(1, 'rgba(0,0,0,0)');
// get our canvas margins;
var rect;

function getRect() {
  rect = canvas.getBoundingClientRect();
}

canvas.onmousedown = function(e) {
  isDrawing = true;
  context.moveTo(e.clientX, e.clientY);
};

canvas.onmousemove = function(e) {

  if (isDrawing) {
    // normalize our mouse event's coordinates
    var x = e.clientX - rect.left;
    var y = e.clientY - rect.top;
    // change the canvas matrix coordinates so we draw at mouse positions
    context.setTransform(1, 0, 0, 1, x, y)
    context.fillStyle = radgrad;
    context.fillRect(-k * 2, -k * 2, k * 2 * 2, k * 2 * 2);
  }
};

canvas.onmouseup = function() {
  isDrawing = false;
};
var debouncing = false;

function resizeHandler() {
  debouncing = false;
  getRect();
}
window.onscroll = window.onresize = function() {
  // debounce the events
  if (!debouncing) {
    requestAnimationFrame(resizeHandler);
  }
  debouncing = true;
}

getRect();
body {
  margin: 0;
  padding: 0;
}
#container {
  border: 1px solid #ccc;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
#canvas {}
<div id="container">
  <canvas id="canvas" width="400" height="400"></canvas>
</div>

Upvotes: 2

Related Questions