[ka-Map-users] Area measurement tool

Jordi Cerdà jordieumoll at gmail.com
Mon Jan 28 07:09:57 EST 2008


Hello,

We have developped an Area measurement tool based on the kaTool prototype.
It's not perfect but it's enough for our needs.
If someone is interested I send the code

Thanks,
Jordi

/**********************************************************************
 *
  *
 * purpose: a simple tool for measuring area
 *
  *
 *
 **********************************************************************
 *
 * To use this tool:
 *
* 1) add a script tag to your page
 *
 * <script type="text/javascript" src="myKaArea.js"></script>
 *
 * 2) create a new instance of myKaRuler
 *
 * myKaArea = new myKaArea( myKaMap);
 *
 * 3) provide some way of activating it.
 *
 * <img id="toolArea" onclick="switchMode(this.id)" title="Area"
alt="mesurar area" src="images/a_pixel.gif" >
 *
 *
 *
 *****************************************************************************/

/**
  * myKaArea constructor
  *
  * construct a new myKaArea object of a given type for a given kaMap
 instance
  *
  * oKaMap - a kaMap instance
  *
  */

 function myKaArea( oKaMap ) {

     kaTool.apply( this, [oKaMap] );

     this.name = 'myKaArea';
     this.cursor = 'default';

     this.canvas = null;

     // the units abrevations (if map units is DD, the distance is in
kilometers)
     this.unitsAbrevations = new Array("ft","in","km","m","mi","km");

     //this is the HTML element that is visible
     this.domObj = document.createElement( 'div' );
     this.domObj.id = 'measureResult';
     this.domObj.style.position = 'absolute';
     this.domObj.style.top = '-300px';
     this.domObj.style.left = '-300px';
     this.domObj.style.width = '150px';
     this.domObj.style.height = '65px';
     this.domObj.style.zIndex = 300;
     this.domObj.style.visibility = 'hidden';
     this.domObj.style.backgroundColor = 'white';
     this.domObj.style.border = '1px solid #999999';
     this.domObj.style.fontFamily = 'Verdana, Arial';
     this.domObj.style.fontSize = '10px';
     document.body.appendChild( this.domObj );

     // the jsgraphic object
     this.jg = null;

     // store the user clicks coordinates
     this.startx = null;
     this.starty = null;
     this.endx = null;
     this.endy = null;

	this.arrayX = new Array();
	this.arrayY = new Array();
	this.nPunts = 0;



     // the total polyline length
     this.total = 0.0;

         this.input = getRawObject('coords');

     for (var p in kaTool.prototype) {
         if (!myKaArea.prototype[p])
             myKaArea.prototype[p]= kaTool.prototype[p];
     }
 };

 /**
  * activate this tool.  Activating the tool causes any existing tools to be
  * deactivated.
  */
 myKaArea.prototype.activate = function() {

     this.kaMap.activateTool( this );
     document.kaCurrentTool = this;

         this.domObj.innerHTML = "<h3>&nbsp;&Agrave;rea: <input
type='text' id='measureTot'
style='border:none;background-color:transparent;width:75px;' />" +
this.unitsAbrevations[this.kaMap.getCurrentMap().units] +"2";

         if(this.canvas == null){
           this.canvas = this.kaMap.createDrawingCanvas( 300 );
           this.canvas.id = "measureCanvas";
         }
         if(this.jg == null){
           this.jg = new jsGraphics("measureCanvas");
           this.jg.setColor("#ff0000");
           this.jg.setStroke(3);
         }
         this.domObj.style.visibility='visible';
 };

 /**
  * deactivate this tool.
  */
 myKaArea.prototype.deactivate = function() {
     this.kaMap.deactivateTool( this );
     document.kaCurrentTool = null;
         this.jg.clear();
         this.jg=null;
         this.kaMap.removeDrawingCanvas(this.canvas);
         this.canvas=null;
         this.domObj.style.visibility='hidden';
 };

 /*
  * draw line representing the measure.
  *
   */
 myKaArea.prototype.drawPolygon = function() {
	var i = 0;
	this.jg.clear();
	
	for (i=1;i<this.nPunts;i++)
	{
		this.jg.drawLine(
			(this.arrayX[i-1]-this.kaMap.xOrigin), (this.arrayY[i-1]-this.kaMap.yOrigin),
			(this.arrayX[i]-this.kaMap.xOrigin),
(this.arrayY[i]-this.kaMap.yOrigin)); // co-ordinates related to
"myCanvas"
	}
	this.jg.drawLine((this.arrayX[0]-this.kaMap.xOrigin),
(this.arrayY[0]-this.kaMap.yOrigin),
                     (this.arrayX[this.nPunts-1]-this.kaMap.xOrigin),
(this.arrayY[this.nPunts-1]-this.kaMap.yOrigin)); // co-ordinates
related to "myCanvas"
	
	this.jg.paint();

	this.measurePolygonArea();


	this.startx = this.endx;
	this.starty = this.endy;
 };



 /**
  * myKaArea.onmouseout( e )
  *
  * called when the mouse leaves theInsideLayer.  hide the result box
  *
  * e - object, the event object or null (in ie)
  */
 myKaArea.prototype.onmouseout = function(e) {
     e = (e)?e:((event)?event:null);
     if (!e.target) e.target = e.srcElement;
         this.domObj.style.visibility='hidden';
 };

 /**
  * myKaArea.onmouseout( e )
  *
  * called when the mouse leaves theInsideLayer.  show the result box
  *
  * e - object, the event object or null (in ie)
  */
 myKaArea.prototype.onmouseover = function(e) {
     e = (e)?e:((event)?event:null);
     if (!e.target) e.target = e.srcElement;
         this.domObj.style.visibility='visible';
 };

 /**
  * myKaArea.onmousemove( e )
  *
  * called when the mouse moves over theInsideLayer.
  *
  * e - object, the event object or null (in ie)
  */
 myKaArea.prototype.onmousemove = function(e) {
     e = (e)?e:((event)?event:null);

         //show coordinate
         var x = e.pageX || (e.clientX +
                     (document.documentElement.scrollLeft ||
 document.body.scrollLeft));
         var y = e.pageY || (e.clientY +
           (document.documentElement.scrollTop || document.body.scrollTop));
     var aPixPos = this.adjustPixPosition( x,y );
       var geoCoo= this.kaMap.pixToGeo(aPixPos[0],aPixPos[1]);
       var gX = geoCoo[0];
     var gY = geoCoo[1];
       var gX= (parseInt(gX*10000))/10000;
     var gY= (parseInt(gY*10000))/10000;
         if(this.input)
         {
           if(this.kaMap.getCurrentMap().units == 5)
         this.input.value = "Lon.: "+gX+" Lat.: "+gY;
             else
               this.input.value = "X: "+gX+" Y: "+gY;
         }
         //**//
         this.domObj.style.left = (e.clientX+5)+"px";
         this.domObj.style.top =  (e.clientY+5)+"px";

         if(this.startx !== null)
         {
           this.endx=-aPixPos[0];
           this.endy=-aPixPos[1];

/*           if(this.kaMap.getCurrentMap().units == 5)    {
               document.getElementById("measureSeg").value =
 this.measureSphericalDistance2Points(this.startx,this.starty,this.endx,this.endy);
             }else{
               document.getElementById("measureSeg").value =
 this.measure2points(this.startx,this.starty,this.endx,this.endy);

//	document.getElementById("measureSeg").value =
parseFloat(this.measurePolygonArea());
             }
*/
         }
     return false;
 }
 ;
 /**
  * myKaArea.onmousedown( e )
  *
  * called when a mouse button is pressed over theInsideLayer.
  *
  * e - object, the event object or null (in ie)
  */
 myKaArea.prototype.onmousedown = function(e) {
	e = (e)?e:((event)?event:null);
	if (e.button==2) {
		this.jg.clear();
		this.jg.clear();
		this.startx=this.starty=this.endx=this.endy=null;
		//document.getElementById("measureSeg").value="0.0";
		document.getElementById("measureTot").value="0";
		this.total = 0.0;
		return this.cancelEvent(e);
	}
	else {
		if (this.kaMap.isIE4)
			document.onkeydown = kaTool_redirect_onkeypress;
		document.onkeypress = kaTool_redirect_onkeypress;
		
		var x = e.pageX || (e.clientX + (document.documentElement.scrollLeft
|| document.body.scrollLeft));
		var y = e.pageY || (e.clientY + (document.documentElement.scrollTop
|| document.body.scrollTop));
		var aPixPos = this.adjustPixPosition( x,y );
		if(this.endx == null)
		{
			this.arrayX[0]=this.startx=this.endx=-aPixPos[0];
			this.arrayY[0]=this.starty=this.endy=-aPixPos[1];
			this.nPunts=1;
		}
		else
		{
			this.arrayX[this.nPunts]=this.endx=-aPixPos[0];
			this.arrayY[this.nPunts]=this.endy=-aPixPos[1];

			this.nPunts++;
		}
/*		if (this.kaMap.getCurrentMap().units == 5)
		{
			this.total +=
this.measureSphericalDistance2Points(this.startx,this.starty,this.endx,this.endy);
		}
		else
		{
			this.total +=
this.measure2points(this.startx,this.starty,this.endx,this.endy);
		}
*/
		this.drawPolygon();
		this.total = this.measurePolygonArea();
		document.getElementById("measureTot").value = parseInt(this.total*100)/100;

		e.cancelBubble = true;
		e.returnValue = false;
		if (e.stopPropogation) e.stopPropogation();
		if (e.preventDefault) e.preventDefault();
		return false;
	}
 };

 /**
  * myKaArea.onmouseup( e )
  *
  * called when a mouse button is clicked over theInsideLayer.
  *
  * e - object, the event object or null (in ie)
  */
 myKaArea.prototype.onmouseup = function(e) {
     e = (e)?e:((event)?event:null);
     return false;
 };
 /**
 * myKaArea.measureSphericalDistance2Points
 *
 * pix1,piy1 - pixel coordinates of the first point
 * pix2,piy2 - pixel coordinates of the second point
 *
 * This function is used to calculate the distance between two points in
 decimel degree unit.
 * It assume that the earth is a perfect sphere, so the calculation isn't
 accurate.
 * In fact the further you are from the equator the least accurate the
 calulation is.
 */
 myKaArea.prototype.measureSphericalDistance2Points =
function(pix1,piy1,pix2,piy2)
 {
     var pt1 = this.kaMap.pixToGeo(pix1,piy1);
     var pt2 = this.kaMap.pixToGeo(pix2,piy2);
     /* Convert all the degrees to radians */
     var la1 = pt1[0] * Math.PI/180.0;
     var lo1 = pt1[1] * Math.PI/180.0;
     var la2 = pt2[0] * Math.PI/180.0;
     var lo2 = pt2[1] * Math.PI/180.0;
     /* Find the Great Circle distance */
     var EARTH_RADIUS = 6378; //kilometers //3956;//miles
     var distance =
Math.acos(Math.sin(la1)*Math.sin(la2)+Math.cos(la1)*Math.cos(la2)*Math.cos(lo2-lo1))
* EARTH_RADIUS ;
     return distance ;
 };

// Implementació del càlcul de l'àrea basada en
http://local.wasp.uwa.edu.au/~pbourke/geometry/polyarea/
// Funciona amb polígons simples (sense encreuaments), tant convexos com còncavs
 myKaArea.prototype.measurePolygonArea = function()
 {
	if (this.nPunts<3)
		return 0.0;
	else
	{
		var totalArea = 0;
		var i,j;
		var pi,pj;
		for (i=0;i<this.nPunts;i++) {
			j = (i + 1) % this.nPunts;
			pi = this.kaMap.pixToGeo(this.arrayX[i],this.arrayY[i]);	
			pj = this.kaMap.pixToGeo(this.arrayX[j],this.arrayY[j]);
			totalArea += Math.abs(pi[0]) * Math.abs(pj[1]);
			totalArea -= Math.abs(pi[1]) * Math.abs(pj[0]);
   		}
   		totalArea /= 2;
		return Math.abs(totalArea);
	}
 };

/*
// Implementació del càlcul de l'àrea basada en triangles, però que
només funciona amb polígons convexos
 myKaArea.prototype.measurePolygonArea = function()
 {
	if (this.nPunts<3)
		return 0.0;
	else
	{
		var i;
		var p0,p1,p2;
		var totalArea=0.0,area2=0.0;

		p0 = this.kaMap.pixToGeo(this.arrayX[0],this.arrayY[0]);
		for (i=1;i<this.nPunts-1;i++)
		{
			p1 = this.kaMap.pixToGeo(this.arrayX[i],this.arrayY[i]);	
			p2 = this.kaMap.pixToGeo(this.arrayX[i+1],this.arrayY[i+1]);
			//window.alert("p0="+p0[0]+";"+p0[1] +"\np1="+p1[0]+";"+p1[1]
+"\np2="+p2[0]+";"+p2[1]);
			var triangleArea = Math.abs(
Math.abs(p0[0]*p2[1])-Math.abs(p0[0]*p1[1])+Math.abs(p1[0]*p0[1])-Math.abs(p1[0]*p2[1])+Math.abs(p2[0]*p1[1])-Math.abs(p2[0]*p0[1])
);
			triangleArea *= 0.5;
			//window.alert("Area triangle="+triangleArea);
			totalArea += triangleArea;
		}
		area2=this.measurePolygonArea2();
		window.alert("Area total 1 = "+totalArea + ". Area total 2 = "+area2);

	return totalArea;
	}
 };
*/

 /**
 * myKaArea.measureSphericalDistance2Points
 *
 * p1X,p1Y - pixel coordinates of the first point
 * p2X,p2Y - pixel coordinates of the second point
 *
 * This function is used to calculate the distance between two points in
 planar projection.
 * I use the Pythagor algorythm. The result unit is the same as the
 projection unit and is round
 * at two decimals.
 */
 myKaArea.prototype.measure2points = function(p1X,p1Y,p2X,p2Y)
 {
     // Diff X/Y between current new and previous click
     var x_delta = p1X - p2X;
     var y_delta = p1Y - p2Y;
     // Segment length in Pixel
     var segLenPix = Math.sqrt((Math.pow(x_delta, 2)) + (Math.pow(y_delta, 2)));
     // Segment length in  map coordinates,  write values to input boxes
     var extent = this.kaMap.getGeoExtents();
     var xdelta_geo = extent[2]-extent[0];
     var segLenGEO = parseInt( ((segLenPix/this.kaMap.viewportWidth )
* xdelta_geo)*100 )/100;
     return segLenGEO;
 };



More information about the ka-Map-users mailing list