Performances of ‘lineTo’ method when going beyond canvas dimensions

Using a canvas context, assuming I call beginPath then twice lineTo with x=-999, y=-999 and x=50, y=50 then finally stroke, it will draw a line from the top-left corner to the (50,50) point.

During the process did the top-left outside part of the line was draw from the outside or did it was draw from the visible canvas part, in our case (0,0).

  • In the first case, is it worth safing the coordinates with a safeCoordinates function, particurlarly if we need a lot of points, when we want to draw a mathematical function for example.

  • In the second case well ok it’s perfect.

See the above example where I have two red line without safing the coordinates and two green line with safe coordinates :

const canvas = document.querySelector('canvas');
const context = canvas.getContext('2d');

// Draw a line between two points
const drawLine = (color, fromX, fromY, toX, toY) => {
  context.beginPath();
  context.lineWidth = 5;
  context.lineTo(fromX, fromY);
  context.lineTo(toX, toY);
  context.strokeStyle = color;
  context.stroke();
}

// Without coordinates safing
drawLine('#F00', -999, -999, 50, 50);
drawLine('#F00', 150, 150, 999 + canvas.width, 999 + canvas.height);

const safeCoordinateX = value => 
  value < 0 ? 0 : value > canvas.width ? canvas.width : value;

const safeCoordinateY = value => 
  value < 0 ? 0 : value > canvas.height ? canvas.height : value;

const safeCoordinates = (fromX, fromY, toX, toY) => 
  [safeCoordinateX(fromX), safeCoordinateY(fromY), safeCoordinateX(toX), safeCoordinateY(toY)];

// With coordinates safing
drawLine('#0F0', ...safeCoordinates(150, 50, 999 +  canvas.width, -999));
drawLine('#0F0', ...safeCoordinates(50, 150, -999, 999 + canvas.height));
canvas {
  border: 1px solid rgba(0, 0, 0, .5)
}
<canvas width=200 height=200 />

Answer

To answer your question we need a benchmark. Look at the following, the safe draw is taking longer than the unsafe draw. Probably due to extra calculation on your part.

const canvas = document.querySelector('canvas');
const context = canvas.getContext('2d');

// Draw a line between two points
const drawLine = (color, fromX, fromY, toX, toY) => {
  context.beginPath();
  context.lineWidth = 5;
  context.lineTo(fromX, fromY);
  context.lineTo(toX, toY);
  context.strokeStyle = color;
  context.stroke();
}

const safeCoordinateX = value => 
  value < 0 ? 0 : value > canvas.width ? canvas.width : value;

const safeCoordinateY = value => 
  value < 0 ? 0 : value > canvas.height ? canvas.height : value;

const safeCoordinates = (fromX, fromY, toX, toY) => 
  [safeCoordinateX(fromX), safeCoordinateY(fromY), safeCoordinateX(toX), safeCoordinateY(toY)];
 
   function drawSafe() {
  const t = Date.now();
  
  drawLine('#0F0', ...safeCoordinates(150, 50, 999 +  canvas.width, -999));
  drawLine('#0F0', ...safeCoordinates(50, 150, -999, 999 + canvas.height));
  
  return Date.now() - t;
}

function drawUnsafe() {
  const t = Date.now();
  
  drawLine('#F00', -999, -999, 50, 50);
  drawLine('#F00', 150, 150, 999 + canvas.width, 999 + canvas.height);
  
  return Date.now() - t;
}

function launchAndCalcTotTime(f) {
  let t = 0;

  for (let i = 0; i < 100000; i += 1) {
    t += f();
  }
  
  return t;
}

console.log(`Safe draw took ${launchAndCalcTotTime(drawSafe)}ms`);
console.log(`Unsafe draw took ${launchAndCalcTotTime(drawUnsafe)}ms`);
canvas {
  border: 1px solid rgba(0, 0, 0, .5)
}
<canvas width=200 height=200 />

To be sure about that you can also try to draw an extra big line and see if it changes the result. If the line is drawed, then it should slow down the execution. But answers is no.

const canvas = document.querySelector('canvas');
const context = canvas.getContext('2d');

// Draw a line between two points
const drawLine = (color, fromX, fromY, toX, toY) => {
  context.beginPath();
  context.lineWidth = 5;
  context.lineTo(fromX, fromY);
  context.lineTo(toX, toY);
  context.strokeStyle = color;
  context.stroke();
}

const safeCoordinateX = value => 
  value < 0 ? 0 : value > canvas.width ? canvas.width : value;

const safeCoordinateY = value => 
  value < 0 ? 0 : value > canvas.height ? canvas.height : value;

const safeCoordinates = (fromX, fromY, toX, toY) => 
  [safeCoordinateX(fromX), safeCoordinateY(fromY), safeCoordinateX(toX), safeCoordinateY(toY)];
 
   function drawSafe() {
  const t = Date.now();
  
  drawLine('#0F0', ...safeCoordinates(150, 50, 999 +  canvas.width, -999));
  drawLine('#0F0', ...safeCoordinates(50, 150, -999, 999 + canvas.height));
  
  return Date.now() - t;
}

function drawUnsafe() {
  const t = Date.now();
  
  drawLine('#F00', -999999999, -999999999, 5000000000, 500000000);
  drawLine('#F00', 0, 0, 9990000000 + canvas.width, 9990000000 + canvas.height);
  
  return Date.now() - t;
}

function launchAndCalcTotTime(f) {
  let t = 0;

  for (let i = 0; i < 100000; i += 1) {
    t += f();
  }
  
  return t;
}

console.log(`Safe draw took ${launchAndCalcTotTime(drawSafe)}ms`);
console.log(`Unsafe draw took ${launchAndCalcTotTime(drawUnsafe)}ms`);
canvas {
  border: 1px solid rgba(0, 0, 0, .5)
}
<canvas width=200 height=200 />