0

I am trying to paint over an image in a canvas and getting issue when the canvas css is different than the Canvas width/height:

The issue is that the brush doesn't start painting from the expected mouse click/touch, It starts painting far away from the cursor.

I could solve the issue by making the canvas bigger which will fit the defined sizes in canvas2.width=960; canvas2.height=540;, but i need to keep the size of the canvas small and the quality of the image high.

How can i keep the canvas small but the image resolution high?

DEMO

// CANVAS
//__________________________


 var canvas = document.getElementById('myCanvas');
      var context = canvas.getContext('2d');
      context.beginPath();
      context.rect(0, 0, 284, 120);
      context.lineWidth = 4;
      context.strokeStyle = 'black';
      context.stroke();
 var canvas2 = document.getElementById('myCanvas2');
      canvas2.width=960;
      canvas2.height=540;
      var context2 = canvas2.getContext('2d');
      context2.beginPath();
      context2.rect(0, 0, 960, 540);
      context2.lineWidth = 4;
      context2.strokeStyle = 'black';
      context2.stroke();
var img=document.getElementById("dove");
      context2.drawImage(img,0,0, canvas2.width, canvas2.height);
      context.drawImage(img,0,0, canvas.width, canvas.height);




// BRUSH PAINT OVER IMAGE 2
//__________________________

// Brush colour and size
const colour = "#3d34a5";
const strokeWidth = 25;

// Drawing state
let latestPoint;
let drawing = false;

// Set up our drawing context
//const canvas = document.getElementById("canvas");
//const context = canvas.getContext("2d");

let brush;

// Drawing functions

const continueStroke = newPoint => {
  context2.beginPath();
  context2.moveTo(latestPoint[0], latestPoint[1]);
  context2.strokeStyle = colour;
  context2.lineWidth = strokeWidth;
  context2.lineCap = "round";
  context2.lineJoin = "round";
  context2.lineTo(newPoint[0], newPoint[1]);
  context2.stroke();

  latestPoint = newPoint;
};

// Event helpers

const startStroke = point => {
  drawing = true;
  latestPoint = point;
};

const getTouchPoint = evt => {
  if (!evt.currentTarget) {
    return [0, 0];
  }
  const rect = evt.currentTarget.getBoundingClientRect();
  const touch = evt.targetTouches[0];
  return [touch.clientX - rect.left, touch.clientY - rect.top];
};

const BUTTON = 0b01;
const mouseButtonIsDown = buttons => (BUTTON & buttons) === BUTTON;

// Event handlers

const mouseMove = evt => {
  if (!drawing) {
    return;
  }
  continueStroke([evt.offsetX, evt.offsetY]);
};

const mouseDown = evt => {
  if (drawing) {
    return;
  }
  evt.preventDefault();
  canvas2.addEventListener("mousemove", mouseMove, false);
  startStroke([evt.offsetX, evt.offsetY]);
};

const mouseEnter = evt => {
  if (!mouseButtonIsDown(evt.buttons) || drawing) {
    return;
  }
  mouseDown(evt);
};

const endStroke = evt => {
  if (!drawing) {
    return;
  }
  drawing = false;
  evt.currentTarget.removeEventListener("mousemove", mouseMove, false);
};

const touchStart = evt => {
  if (drawing) {
    return;
  }
  evt.preventDefault();
  startStroke(getTouchPoint(evt));
};

const touchMove = evt => {
  if (!drawing) {
    return;
  }
  continueStroke(getTouchPoint(evt));
};

const touchEnd = evt => {
  drawing = false;
};

// Register event handlers
canvas2.addEventListener("touchstart", touchStart, false);
canvas2.addEventListener("touchend", touchEnd, false);
canvas2.addEventListener("touchcancel", touchEnd, false);
canvas2.addEventListener("touchmove", touchMove, false);

canvas2.addEventListener("mousedown", mouseDown, false);
canvas2.addEventListener("mouseup", endStroke, false);
canvas2.addEventListener("mouseout", endStroke, false);
canvas2.addEventListener("mouseenter", mouseEnter, false);
.canv-wrapper {
  max-width: 49%;
  display:inline-block;
}
<div class="canv-wrapper">
  <canvas id="myCanvas" width="284px" height="120px">hello</canvas>
  <p>1 image 284px x 120px</p>
</div>
<div class="canv-wrapper">
  <canvas id="myCanvas2" style="width:284px;height:120px;"></canvas>
  <p>2 image 960px x 540px - Paint over image</p>
</div>
<img style="display:none;" src="https://wallpapercave.com/wp/wp4712331.jpg" id="dove">
Nash
  • 285
  • 2
  • 15
  • Just to note that you need to wait for loading to finish before drawing the image on canvas otherwise it’s just blank at least the first time (before it is cached). – A Haworth Sep 25 '21 at 06:17
  • While, technically, you can set your canvas to have a much higher resolution than the screen, an image drawn to such a canvas will never display at a resolution higher than that of the screen even if, internally, it's stored at a higher resolution. – Ouroborus Sep 25 '21 at 07:02
  • @Ouroborus, thats correct. But when saving the image it will be downloaded with higher Resolution. – Nash Sep 25 '21 at 07:11
  • That seems to be exactly what you're asking for. Is there some other issue? – Ouroborus Sep 25 '21 at 07:15
  • Just looked at your example. It seems that your actual question is how to make the position of the draw actions match the position of the cursor. – Ouroborus Sep 25 '21 at 07:17
  • @Ouroborus thats right, my only issue is the pencil position, it's not matching the cursor position. You mean it's possible to solve this by adding event listener of mousemove? – Nash Sep 25 '21 at 07:27
  • Looks like you already have an event listener for `mousemove` so it's mainly a matter of converting the mouse coordinates it receives to canvas coordinates by taking into account the effective CSS scaling as in the duplicate question I linked. – Ouroborus Sep 25 '21 at 07:35
  • @Ourborus your suggestions works! – Nash Sep 25 '21 at 08:28

0 Answers0