Issam
Issam

Reputation: 35

Draw polygon canvas from coordinates map

How to transform coordinates map to point canvas?

I have a map leaflet Map leaflet and when i select polygon, i want to draw the polygon with canvas html5

I have coordinates like this :

[[2.809510437833253,49.408625488749216],[2.8095461924850422,49.40864172401838],[2.8095226856172806,49.40866595550704],[2.809565304449213,49.40868849340382],[2.8097185865450465,49.40858536874469],[2.809677338568488,49.40856463072128],[2.8096442193374154,49.408580757620854],[2.809609885351463,49.40855283978645],[2.809510437833253,49.408625488749216]]

The difficulty is how to get points from map coordinates

This example to display polygon canvas :

<!DOCTYPE html>
<html>
<body>
<svg height="110" width="200">
<polygon points="130,0 0,160 0,485 270,645 560,485 560,160"/>
</svg>
</body>
</html>

Thanks for your help.

Upvotes: 3

Views: 5738

Answers (1)

Blindman67
Blindman67

Reputation: 54039

Map projections

Difficult problem

The problem with the earth is that is is not flat, and most of what we humans use to draw and render to tends to be flat. To fix the problem we accept some deformation of what the map represents by applying a projection from the round Earth to the flat map. There are many many different types of projections, a common one is the mercator projection (see google maps), it distorts area the further south and north of the equator you are. But it does this to maintain direction. You can put a compass on a mercator projected map and get an accurate bearing, but you can't take a ruler and measure the distance.

But size matters, easy solution

But there is one saving grace in all this. We humans are tiny compared to the Earth and for local maps the distortion caused by the curvature of the Earth is so small to be irrelevant.

If you have a set of coordinates in a small area (eg a city and suburbs) you can just use a square projection. Where lat and long are x and y on the grid of rendering surface.

Step by step

How to take some mapping data and fit it to a canvas maintaining the aspect.

So you have a set of points and a canvas context

<canvas id="canvas" width =300 height = 200></canvas>
ctx = canvas.getContext("2d");

 var myPoints = [[2.809510437833253,49.408625488749216],[2.8095461924850422,49.40864172401838],[2.8095226856172806,49.40866595550704],[2.809565304449213,49.40868849340382],[2.8097185865450465,49.40858536874469],[2.809677338568488,49.40856463072128],[2.8096442193374154,49.408580757620854],[2.809609885351463,49.40855283978645],[2.809510437833253,49.408625488749216]]

Then find the extent of those points (the min and max coordinates)

var minX,minY,maxX,maxY; 
myPoints.forEach((p,i) => {
   if(i === 0){ // if first point 
      minX = maxX = p[0];
      minY = maxY = p[1]; 
   }else{
      minX = Math.min(p[0],minX);
      minY = Math.min(p[1],minY);
      maxX = Math.max(p[0],maxX);
      maxY = Math.max(p[1],maxY);
   }
 });
 // now get the map width and heigth in its local coords
 const mapWidth = maxX-minX;
 const mapHeight = maxY-minY;
 const mapCenterX = (maxX + minX) /2;
 const mapCenterY = (maxY + minY) /2;

Now you have the map extent you can scale it to the canvas by finding the smallest scale to fit both width and height.

 const scale = Math.min(canvas.width / mapWidth,canvas.height / mapHeight);

Now you can draw the map first subtracting the map center, then scaling it up, then moving ot to the canvas center.

 ctx.beginPath();
 myPoints.forEach(p => { 
      ctx.lineTo(
          (p[0] - mapCenterX) * scale + canvas.width /2 ,
          (p[1] - mapCenterY) * scale + canvas.height / 2 
      );
 });
 ctx.stroke();

And a working example.

 ctx = canvas.getContext("2d");
 
 var myPoints = [[2.809510437833253,49.408625488749216],[2.8095461924850422,49.40864172401838],[2.8095226856172806,49.40866595550704],[2.809565304449213,49.40868849340382],[2.8097185865450465,49.40858536874469],[2.809677338568488,49.40856463072128],[2.8096442193374154,49.408580757620854],[2.809609885351463,49.40855283978645],[2.809510437833253,49.408625488749216]]

var minX,minY,maxX,maxY; 
myPoints.forEach((p,i) => {
   if(i === 0){ // if first point 
      minX = maxX = p[0];
      minY = maxY = p[1]; 
   }else{
      minX = Math.min(p[0],minX);
      minY = Math.min(p[1],minY);
      maxX = Math.max(p[0],maxX);
      maxY = Math.max(p[1],maxY);
   }
 });
 // now get the map width and heigth in its local coords
 const mapWidth = maxX-minX;
 const mapHeight = maxY-minY;
 const mapCenterX = (maxX + minX) /2;
 const mapCenterY = (maxY + minY) /2;
 
 // to find the scale that will fit the canvas get the min scale to fit height or width
 const scale = Math.min(canvas.width / mapWidth,canvas.height / mapHeight);
 
 // Now you can draw the map centered on the cavas
 ctx.beginPath();
 myPoints.forEach(p => { 
      ctx.lineTo(
          (p[0] - mapCenterX) * scale + canvas.width /2 ,
          (p[1] - mapCenterY) * scale + canvas.height / 2 
      );
 });
 ctx.stroke();
canvas { border : 2px solid black; }
<canvas id="canvas" width =300 height = 200></canvas>

Upvotes: 7

Related Questions