lucidgold
lucidgold

Reputation: 4542

Convert HTML Canvas coordinate system to Cartesian system

The origin (0,0) of an HTML canvas is the upper left (see image below), where positive x coordinates go to the right, and positive y coordinates go down.

enter image description here

However, the origin in mathematics is the "center," and positive y goes up via the Cartesian coordinate system (see below).

enter image description here

I played with offset and scale of the stage in KonvaJS to reflect a Cartesian system with X-max of 10, Y-max of 10, X-min of -10 and Y-min of -10. However, my current solution has the quadrants flipped upside down (See below). Any suggestions?

enter image description here

Current JavaScript approach: JSFiddle

var Width = 500;
var Height = 500;
var minX = -12; var maxX = 12;
var minY  = -12; var maxY  = 12;
var rangeX  = maxX - minX;
var rangeY  = maxY - minY;
var scaleX  = Width / rangeX;
var scaleY = Height  / rangeY;

var stage = new Konva.Stage({
container: 'container',
width: Width,
height: Height,
scaleX: scaleX,
scaleY: scaleY,
offset: {
	x: -12,
	y: -12
}			
});		

var layer = new Konva.Layer();
stage.add(layer);

var rect = new Konva.Rect({
  x: -12,
  y: -12,
  width: 24,
  height: 24,		  

  stroke: 'black',
  strokeWidth: 0.1
});		
layer.add(rect);

var position = new Konva.Text(
{
	fontSize: 0.7,
	x: -11,
	y: -11			
});
 
layer.add(position);

var t0 = new Konva.Text(
{
fontSize: 1,
x: 0,
y: 0,
text: 'Center'

});		 
var t1 = new Konva.Text(
{
fontSize: 0.7,
x: 5,
y: 5,
text: 'Top\nRight',
fill: 'blue'
});		 
var t2 = new Konva.Text(
{
fontSize: 0.7,
x: -5,
y: 5,
text: 'Top\nLeft',
fill: 'blue'
});		 
var t3 = new Konva.Text(
{
fontSize: 0.7,
x: 5,
y: -5,
text: 'Bottom\nRight',
fill: 'blue'
});		 
var t4 = new Konva.Text(
{
fontSize: 0.7,
x: -5,
y: -5,
text: 'Bottom\nLeft',
fill: 'blue'			
});		 
layer.add(t0);	
layer.add(t1);
layer.add(t2);
layer.add(t3);
layer.add(t4);	

 var yaxis = new Konva.Arrow({
  points: [0, 11, 0, -11],
  pointerLength: 0.3,
  pointerWidth: 0.2,
  pointerAtBeginning: true,
  fill: 'green',
  stroke: 'green',
  strokeWidth: 0.1
});
layer.add(yaxis);

var xaxis = new Konva.Arrow({
  points: [11, 0, -11,0],
  pointerLength: 0.3,
  pointerWidth: 0.2,
  pointerAtBeginning: true,
  fill: 'green',
  stroke: 'green',
  strokeWidth: 0.1
});
layer.add(xaxis);

var circle = new Konva.Circle({
  x: 0,
  y: 5,
  radius: 0.5,
  fill: 'purple',
  stroke: 'purple',
  strokeWidth: 0,
  draggable: true
});		

layer.add(circle);

layer.draw();

function updateText(e) {
position.text('(' + Math.round(e.target.x()) + ', ' + Math.round(e.target.y()) + ')');
layer.batchDraw();
}

circle.on('dragmove', updateText);  
  
<script src="https://unpkg.com/konva@2.4.2/konva.min.js"></script>
<body>
 <div id="container"></div>
</body>

Update:

As suggested by Andrew Morton, setting:

scaleY = -Height / rangeY;

Has the right idea, but it required a change in the stage offset to:

      offset: {
          x: -12,
          y: 12           
      }

Which resulted in having the correct quadrants but all text has been inverted (See below). Any other suggestions?

enter image description here

Upvotes: 2

Views: 4942

Answers (3)

Emre Yilmaz
Emre Yilmaz

Reputation: 1

You just need to multiply Y by -1.

function updateText(e) {
  position.text('(' + Math.round(e.target.x()) + ', ' + Math.round(e.target.y())*-1 + ')');
  layer.batchDraw();
}

Upvotes: 0

Andrew Morton
Andrew Morton

Reputation: 25047

As y is upside down, you need

var scaleY = -Height / rangeY

But apparently that results in the text being inverted too. You can correct for that in the Text constructor with the properties

scaleY: -1,
verticalAlign: 'top'

Ref: Konva.Text

Upvotes: 3

Josh Davenport-Smith
Josh Davenport-Smith

Reputation: 5511

You could convert your cartesian (postive/negative x and y) points to positions that make sense to canvas by just working out the midpoint in your canvas and doing some basic arithmetic:

var getCanvasCartesianPoint = function (x, y) {
  var midWidth = width / 2;
  var midHeight = height / 2;
  var cartesianX = midWidth + x;
  var cartesianY = midHeight + y;

  return {x: cartesianX, y: cartesianY};
}

So when you call getCanvasCartesianPoint(0,0) and your width is, say 250, the function would return {x: 125, y: 125} which is in the middle of your canvas.

See this codepen for a demonstration - https://codepen.io/joshdavenport/pen/NobERq

Upvotes: 2

Related Questions