2

I'm currently a beginner in javascript and learning the canvas. I was wonder if anyone would explain why if you drew backwards from right to left, it shows the negative numbers in the inputs. Is there anyway to make it positive to display the real size of the rectangle regardless which direction you draw it in?

Here is the JS fiddle. https://jsfiddle.net/asn6wzw4/2/

The HTML

<form id="areaform">
<label for="wid">Width:</label>
<input id="wid" type="number">
<label for="hgt">Height:</label>
<input id="hgt" type="number">
<br/>
<label for="area1">Area:</label>
<output id="area"></output>
<br/>
<label for="perimeter1">Perimeter:</label>
<output id="perim"></output>
<br/>
<button onclick="getarea()" type="button">Get Area</button>
</form>

<div id="drawRectangle">
<canvas id="rectCanvas"  width=500 height=500></canvas>
</div>

The JS

var canvas, context, startX, endX, startY, endY;
var mouseClicked = 0;

function mouseUp(e) {
if (mouseClicked  !== 0) {
    mouseClicked = 0;
    var pos = getMousePos(canvas, e);
    endX = pos.x;
    endY = pos.y;
    drawRectangle(); 
  }
}

 function mouseDown(e) {
    mouseClicked = 1;
    var pos = getMousePos(canvas, e);
    startX = endX = pos.x;
    startY = endY = pos.y;
    drawRectangle();
 }

  function mouseXY(e) {
     if (mouseClicked  !== 0) {
         var pos = getMousePos(canvas, e);
         endX = pos.x;
         endY = pos.y;
         drawRectangle();
      }
  }

 function drawRectangle() {

  var width = endX - startX;
  var height = endY - startY;
  var offsetX = (width > 0);
  var offsetY = (height > 0);


  document.getElementById("wid").value = width;
  document.getElementById("hgt").value = height;

  context.clearRect(0, 0, canvas.width, canvas.height);
  context.beginPath();
  context.rect(startX + offsetX, startY + offsetY, width, height);
  context.fillStyle = "#88EF5E";
  context.fill();

 }

 function getMousePos(canvas, evt) {
    var rect = canvas.getBoundingClientRect();
    return {
        x: evt.clientX - rect.left,
        y: evt.clientY - rect.top
   };

  }


  function init() {
      canvas = document.getElementById("rectCanvas");
      context = canvas.getContext("2d");
      canvas.addEventListener("mousedown", mouseDown);
      canvas.addEventListener("mousemove", mouseXY);
      canvas.addEventListener("mouseup", mouseUp);
  }


  init();
logan26
  • 283
  • 2
  • 18
  • It's showing negative numbers because the starting point is larger than the ending point. So, if start = 100 and end = 10, then end - start = -90. You can just take the absolute value of the number and that should be fine. – Alex Bieg Jul 24 '17 at 16:05

3 Answers3

1

First part of the answer about why there are negatives showing when you go down and right can be seen here:

https://www.w3schools.com/graphics/canvas_coordinates.asp

The canvas specifically states the upper left corner is (0,0) so down will always be negative.

To answer your second question, "can you make sure it's always positive," you could easily do an absolute value of all the numbers to ensure they are always positive.

Michael Platt
  • 1,297
  • 12
  • 25
1

Math.min and Math.max

For a rectangle you can have the coordinates as

const rect = {
    top : 0, 
    left : 0,
    width : 0,  // these two have to be positive for this to make any sense
    height : 0,
}

If you have coordinates that are uncontrolled, ie you don't know which is top or left as you get the values, you will need to convert them.

The following is a simple conversion to the above rect structure

rect.left = Math.min(startX, endX);
rect.top = Math.min(startY, endY);
rect.width = Math.max(startX, endX) - rect.left;
rect.height = Math.max(startY, endY) - rect.top;

And you will always have a positive width and height and the top left will always be the top left.

Math min and max work as follows

Math.min(a,b) //returns the smallest number from the arguments a,b
Math.max(a,b) //returns the largest number from the arguments a,b

They can take many arguments

Math.max(a,b,c,d); // get largest of a,b,c,d

Or an array

var numbers = [10,20,30,183,1823,1,10];
Math.min(...numbers); // will return 1
Community
  • 1
  • 1
Blindman67
  • 51,134
  • 11
  • 73
  • 136
1

Sure, simply use Math.abs() on the resulting calculation:

var width  = Math.abs(endX - startX);
var height = Math.abs(endY - startY);

The reason is that you usually calculate width/height using the end point first, then subtract the start point:

        START       END
        10          30

END - START = 20

However, when your end point starts before start point the value is reversed:

 END    START
 2      10

END - START = -8

using ABS will make the value positive regardless.

var ctx = c.getContext("2d");
var startX = 200, startY = 150, endX, endY;

ctx.font = "16px sans-serif";
window.onmousemove = function(e) {
  endX = e.clientX;
  endY = e.clientY;
  var width = endX - startX;
  var height = endY - startY;
  var absWidth = Math.abs(width)
  var absHeight = Math.abs(height);
  
  ctx.clearRect(0,0,c.width,c.height);
  ctx.strokeRect(startX, startY, width, height);
  
  ctx.fillText("W: " + absWidth + " H: " + absHeight, 10, 20);
};
body {margin:0}
canvas {background:#ccc}
<canvas id=c width=400 height=300></canvas>

If you simply want to prevent it to draw when negative you would limit the values instead:

var width = endX - startX;
var height = endY - startY;

if (width < 0) width = 0;
if (height < 0) height = 0;

0 values are allowed for rectangles but it's better to skip the drawing step if so:

if (width && height) /* draw rectangle */

NB: To calculate correct mouse positions see this answer.