Select to view content in your preferred language

Measurement Dijit show wrong distance on mouse move

3236
18
01-31-2014 09:29 AM
BryanLynn
Deactivated User
We are using the Esri measurement dijit in our site.  We have a map that shows 1000' buffers around certain property types.  When you use the measure tool it reports an incorrect value while moving the mouse.  Once the user double clicks to end the measurement the distance seems correct.  Please see the attached images for more details.

This is causing tremendous confusion amoung our users.

Any suggestions?

Thanks,
Bryan

[ATTACH=CONFIG]31041[/ATTACH] [ATTACH=CONFIG]31042[/ATTACH]
0 Kudos
18 Replies
by Anonymous User
Not applicable
Original User: jeff.pace

For coordinate systems other than Web Mercator or geographic CS, this is by design, since there is no better way to do so.
Computing geodesic area/length is only possible with Web Mercator or GCS. Under other CSs, it reprojects the corners (xmin, ymin, xmax, ymax) to GCS, and interpolate the mouse position to find the approximate location under GCS in order to make it possible to calculate geodesic area/length. It is simply not possible to reproject the mouse position point while it's moving. After the drawing ends, as you observed, it shows the accurate result.
The better way is to write a projection conversion for this specific needs.
BTW, your attached image shows 1018feet, instead of 1108.


This is not correct, there is a better way to do it.  I compute area and length on the fly in state plane, web mercator, lat long, and national grid simultaneously, all completely in javascript.  It is an accurate geodesic length on mousemove

The problem is not the calculation, it is that the geometry service is too heavy weight and slow to process it in time.

Granted, my solution requires a few hundred lines of calculus, and it is completely customized to my coordinate systems, it is written purely in javascript, and it does work.

Try the measure tools.  Can even do area calculations on the fly.  I am currently migrating code to AMD.

http://www.mymanatee.org/gisapps/mapviewer/index.jsp?widgetOn=Coordinates:Measure

And the coordinate Tools for mouseover
0 Kudos
JianHuang
Deactivated User
Good work!
As API designer, we cannot just support those coordinate systems specifically, unless in the future we can move the whole projection engine to JavaScript in order to support thousands of different coordinate systems. That was why I suggested to write a specific projection converter for this task.
Jeff, maybe you would like to share your code.
0 Kudos
JianHuang
Deactivated User
Thanks for the info.

2 quick questions:
1) I have looked at the API and don't see an option to turn off the result update while the mouse is moving.  Do you have a snippet of code showing how this is done?

2) You have helped me with this one in the past from another post.  I need to override the results to show State Plane Coordinates with the location tool.  I have the following code which worked in the past but now is acting funny.  Basically, I see the info flash into the results pane but then the tool collapses back to the normal results.

            measurement.on("measure-end", function(evt) {
                if (evt.toolName === "location") {
                    var myResult = "TN State Plane Coordinates (XY):<br />";
                    myResult += Math.round(evt.geometry.x).toString() + ", " + Math.round(evt.geometry.y).toString();
                    myResult += "<br><br>";
                    myResult += "Longitude, Latitude:<br />";
                    myResult += evt.target.locationX.toFixed(6).toString() + ", " + evt.target.locationY.toFixed(6).toString();

                    registry.byNode(measurement.resultValue.domNode).setAttribute("content", myResult);
                }
            });


The code should still work. Did you require "dijit/registry"?
0 Kudos
by Anonymous User
Not applicable
Original User: jeff.pace

Good work!
As API designer, we cannot just support those coordinate systems specifically, unless in the future we can move the whole projection engine to JavaScript in order to support thousands of different coordinate systems. That was why I suggested to write a specific projection converter for this task.
Jeff, maybe you would like to share your code.


I would be happy to

Jian - you don't need to support each coordinate system.  You just need to variabilize the parameters, and use different equations for each style (Transverse Mercator, Lamberic, etc..). I think the issue is if the calculation is not correct yet (since it hasnt been set to geodesic yet) then it should not been shown on mouse over as it is giving false information.  Either show the correct number, or don't show a number, both are acceptable.

Here is my code (at least for florida, it is not tested in other coordinate systems) for going from State Plane to LatLong (either lambert or transverse mercator) and then to web mercator and back. On mouse over I capture the coordinates in Web Mercator and convert them to state plane.  I do all my distance calculations in state plane so they are accurate (geodesic). The actual mathematics are  completely borrowed from Dr Bill Hazelton's HP-33S calculator http://homepage.mac.com/nwjh/HP-33S/ 10-Feb-10
0 Kudos
JeffPace
MVP Alum
dojo.provide("org.mymanatee.common.latlong");

dojo.require("dojo.string");

org.mymanatee.common.latlong.convertSPtoLL_LLC = function (uX,uY) {
var a = 20925604.48;     //major radius of ellipsoid, map units (NAD 83)
var ec = 0.08181905782;    //eccentricity of ellipsoid (NAD 83)
var angRad = 0.01745329252;   //number of radians in a degree
var pi4 = Math.PI / 4;   //Pi / 4
var p0 = 24.333333 * angRad;    //latitude of origin
var p1 = 24.333333 * angRad;    //latitude of first standard parallel
var p2 = 31.5 * angRad;   //latitude of second standard parallel
var m0 = -82.000000 * angRad;   //central meridian
var x0 = 656166.666667;   //False easting of central meridian, map units

// Calculate the coordinate system constants.
with (Math) {
var m1 = cos(p1) / sqrt(1 - (pow(ec,2)) * pow(sin(p1),2));
var m2 = cos(p2) / sqrt(1 - (pow(ec,2)) * pow(sin(p2),2));
var t0 = tan(pi4 - (p0 / 2));
var t1 = tan(pi4 - (p1 / 2));
var t2 = tan(pi4 - (p2 / 2));
t0 = t0 / pow(((1 - (ec * (sin(p0)))) / (1 + (ec * (sin(p0))))),ec/2);
t1 = t1 / pow(((1 - (ec * (sin(p1)))) / (1 + (ec * (sin(p1))))),ec/2);
t2 = t2 / pow(((1 - (ec * (sin(p2)))) / (1 + (ec * (sin(p2))))),ec/2);
var n = log(m1 / m2) / log(t1 / t2);
var f = m1 / (n * pow(t1,n));
var rho0 = a * f * pow(t0,n);

// Convert the coordinate to Latitude/Longitude.
// Calculate the Longitude.
var uX = uX - x0;
var pi2 = pi4 * 2;

var rho = sqrt(pow(uX,2) + pow((rho0 - uY),2));
var theta = atan(uX / (rho0 - uY));
var txy = pow((rho / (a * f)),(1 / n));
var lon = (theta / n) + m0;
var uX = uX + x0;

// Estimate the Latitude
var lat0 = pi2 - (2 * atan(txy));

// Substitute the estimate into the iterative calculation that
// converges on the correct Latitude value.
var part1 = (1 - (ec * sin(lat0))) / (1 + (ec * sin(lat0)));
var lat1 = pi2 - (2 * atan(txy * pow(part1,(ec/2))));

while ((abs(lat1 - lat0)) > 0.000000002) {
  lat0 = lat1;
  part1 = (1 - (ec * sin(lat0))) / (1 + (ec * sin(lat0)));
  lat1 = pi2 - (2 * atan(txy * pow(part1,(ec/2))));
  }

// Convert from radians to degrees.
var Lat = lat1 / angRad;
var Lon = lon / angRad;

//alert(Lat);
//alert(Lon);

//Round the latitude and longitude
//lat = (CLng(lat * 100000)) / 100000;
//lon = (CLng(lon * 100000)) / 100000;

Lat = Lat.toPrecision(7);
Lon = Lon.toPrecision(8);

return [Lat,Lon];

}
};
//End of Code for converting map units to decimal degrees.


//COnversion to LL from State Plane for Florida West (Transverse mercator, not Lamberic
org.mymanatee.common.latlong.convertSPtoLL_TM = function (uX,uY) {

 var    metconv = 1200/3937; //exact survey feet to meters
 var    uXm = uX*metconv;
 var    uYm = uY*metconv;

  var   a = 6378137.000000000000000000; // semimajor axis from ESRI
 var    b =  6356752.314140356100000000; // semiminor axis from ESRI
 var    e2 = ((a*a)-(b*b))/(a*a);//ellipsoid
 var    p0 = 24.333333;    //latitude of origin
 var    m0 = -82.000000;   //central meridian in degrees
 var    x0 = 656166.666667;  //False easting of central meridian, map units
 var    y0 = 0; //False Northing
 var    k0 = 0.999941;    //central scale factor k0
 var    x0m = x0*metconv;
 var    y0m = y0*metconv;

 var    p0rad = p0*Math.PI/180;
 var    m0rad = m0*Math.PI/180;
 var    e = Math.sqrt(e2);


 var    b = a * Math.sqrt(1-e2);
 var    n = (a - b)/(a + b);
 var    G = a*(1-n)*(1-(n*n))*(1+2.25*(n*n)+225/64*(n*n*n*n))*Math.PI/180;
 var    A0 = 1-e2/4-3*(e2*e2)/64-5*(e2*e2*e2)/256;
 var    A2 = 3/8*(e2+(e2*e2)/4+15*(e2*e2*e2)/128);
var     A4 = 15/256*((e2*e2)+0.75*(e2*e2*e2));
var     A6 = 35*(e2*e2*e2)/3072;
var     lat0 = p0rad;
 var    m0atlat0 = a*(A0*lat0-A2*Math.sin(2*lat0)+A4*Math.sin(4*lat0)-A6*Math.sin(6*lat0))
 var    NminusNo = uYm - y0m;

var     m = m0atlat0+NminusNo/k0;
var     s = (m/G)*Math.PI/180;
 var    fpl1 = (1.5*n-27*(n*n*n)/32)*Math.sin(2*s);
  var   fpl2 = (21*(n*n)/16-55*(n*n*n*n)/32)*Math.sin(4*s);
 var    fpl3 = 151*(n*n*n)/96*Math.sin(6*s);
 var    fpl4 = 1097*(n*n*n*n)/512*Math.sin(8*s);
  var   footptlat = (s+fpl1+fpl2+fpl3+fpl4);
  var   rho = a*(1-e2)/Math.pow((1-e2*Math.sin(footptlat)*Math.sin(footptlat)),1.5);
 var    nu = a/(Math.sqrt(1-e2*Math.sin(footptlat)*Math.sin(footptlat)));
 var    psi = nu/rho;
  var   t = Math.tan(footptlat);
 var    E = uXm-x0m;
 var    x = E/k0/nu;

 var    lat1 = x*E/2;
 var    lat2 = (x*x*x)*E/24*(-4*psi*psi+9*psi*(1-t*t)+12*t*t);
  var   lat3 = (x*x*x*x*x)*E/720*(8*(psi*psi*psi*psi)*(11-24*(t*t))-12*(psi*psi*psi)*(21-71*(t*t))+15*(psi*psi)*(15-98*(t*t)+15*(t*t*t*t))+180*psi*(5*(t*t)-3*(t*t*t*t))+360*(t*t*t*t));
 var    lat4 = (x*x*x*x*x*x*x)*E/40320*(1385+3633*(t*t)+4095*(t*t*t*t)+1575*(t*t*t*t*t*t));
 var    lat = footptlat-(t/k0/rho)*(lat1-lat2+lat3-lat4);
 var    latdd = lat*180/Math.PI;

 var    w1 = x/Math.cos(footptlat);
 var    w2 = Math.pow(-1*x,3)/6*(psi+2*t*t)/Math.cos(footptlat);
 var    w3 = Math.pow(x,5)/120/Math.cos(footptlat)*(-4*(psi*psi*psi)*(1-6*(t*t))+(psi*psi)*(9-68*(t*t))+72*(psi)*(t*t)+24*(t*t*t*t));
 var    w4 = Math.pow(-1*x,7)/5040/Math.cos(footptlat)*(61+662*(t*t)+1320*(t*t*t*t)+720*(t*t*t*t*t*t));
 var    w = w1+w2+w3+w4;
 var    lon = (-1*m0)*Math.PI/180-w;
 var    londd = (-1*lon)*180/Math.PI;


//    alert(londd);

    return [latdd,londd];
    };

org.mymanatee.common.latlong.convertLLtoSP_TM = function (lat,lon) {
   var metconv = 1200/3937; //exact survey feet to meters

   var a = 6378137.000000000000000000; // semimajor axis from ESRI
   var b =  6356752.314140356100000000; // semiminor axis from ESRI
   var e2 = ((a*a)-(b*b))/(a*a);//ellipsoid
   var p0 = 24.333333;    //latitude of origin
   var m0 = -82.000000;   //central meridian in degrees
   var x0 = 656166.666667;  //False easting of central meridian, map units
   var y0 = 0; //False Northing
   var k0 = 0.999941;    //central scale factor k0
   var e = Math.sqrt(e2);
    
   var lat0rad_lat0=p0*Math.PI/180;
   var latrad_lat=lat*Math.PI/180;
   var rho_lat=a*(1-e2)/Math.pow((1-e2*Math.sin(latrad_lat)*Math.sin(latrad_lat)),1.5);
 var   nu_lat=a/(Math.sqrt(1-e2*Math.sin(latrad_lat)*Math.sin(latrad_lat)));
  var  omega_lat=((lon)*Math.PI/180)-((m0)*Math.PI/180); //provide negative lon so no negative multiplier
 var   psi_lat=nu_lat/rho_lat;
  var  t_lat=Math.tan(latrad_lat);
  var  a0_lat=1-e2/4-3*e2*e2/64-5*e2*e2*e2/256;
  var  a2_lat=3/8*(e2+e2*e2/4+15*e2*e2*e2/128);
  var  a4_lat=15/256*(e2*e2+0.75*e2*e2*e2);
  var  a6_lat=35*e2*e2*e2/3072;
  var  mlat_lat=a*(a0_lat*latrad_lat-a2_lat*Math.sin(2*latrad_lat)+a4_lat*Math.sin(4*latrad_lat)-a6_lat*Math.sin(6*latrad_lat));
  var  mlat_lat0=a*(a0_lat*lat0rad_lat0-a2_lat*Math.sin(2*lat0rad_lat0)+a4_lat*Math.sin(4*lat0rad_lat0)-a6_lat*Math.sin(6*lat0rad_lat0));
 var   e1_lat=nu_lat*omega_lat*Math.cos(latrad_lat);
 var   e2_lat=nu_lat*omega_lat*omega_lat*omega_lat/6*Math.cos(latrad_lat)*Math.cos(latrad_lat)*Math.cos(latrad_lat)*(psi_lat-t_lat*t_lat);
 var   e3_lat=nu_lat*Math.pow(omega_lat,5)/120*Math.pow(Math.cos(latrad_lat),5)*(4*psi_lat*psi_lat*psi_lat*(1-6*t_lat*t_lat)+psi_lat*psi_lat*(1+8*t_lat*t_lat)-psi_lat*2*t_lat*t_lat+Math.pow(t_lat,4));
  var  e4_lat=nu_lat*Math.pow(omega_lat,7)/5040*Math.pow(Math.cos(latrad_lat),7)*(61-479*t_lat*t_lat+179*Math.pow(t_lat,4)-Math.pow(t_lat,6));
 var   e_lat=k0*(e1_lat+e2_lat+e3_lat+e4_lat);
 var   n1_lat=(omega_lat*omega_lat)/2*Math.cos(latrad_lat);
 var   n1_lat0=n1_lat*nu_lat*Math.sin(latrad_lat);
 var   n2_lat=(Math.pow(omega_lat,4)/24)*(Math.pow(Math.cos(latrad_lat),3))*(4*psi_lat*psi_lat+psi_lat-t_lat*t_lat);
 var   n2_lat0=n2_lat*nu_lat*Math.sin(latrad_lat);
 var   n3_lat=(Math.pow(omega_lat,6)/720)*(Math.pow(Math.cos(latrad_lat),5))*(8*Math.pow(psi_lat,4)*(11-24*t_lat*t_lat)-28*Math.pow(psi_lat,3)*(1-6*t_lat*t_lat)+psi_lat*psi_lat*(1-32*t_lat*t_lat)-2*psi_lat*t_lat*t_lat+Math.pow(t_lat,4));
  var  n3_lat0=n3_lat*nu_lat*Math.sin(latrad_lat);
 var   n4_lat=(Math.pow(omega_lat,8)/40320)*(Math.pow(Math.cos(latrad_lat),7))*(1385-3111*t_lat*t_lat+543*Math.pow(t_lat,4)-Math.pow(t_lat,6));
 var   n4_lat0=n4_lat*nu_lat*Math.sin(latrad_lat);
 var   n_lat=k0*(mlat_lat+nu_lat*Math.sin(latrad_lat)*(n1_lat+n2_lat+n3_lat+n4_lat));
 var   n_lat0=k0*mlat_lat0;
 var   no=n_lat-n_lat0;
  var  x=e_lat+x0*metconv;
 var   y=(n_lat-n_lat0)+y0*metconv;
//    alert(n_lat);
//    alert("x="+x+"y="+y);
  //  alert("a0="+a0_lat+"a2="+a2_lat+"a4="+a4_lat+"a6="+a6_lat);
 var   xft=x/metconv;
 var   yft=y/metconv;
 //   alert("x="+xft+"y="+yft);
  return [xft,yft];
    }

    org.mymanatee.common.latlong.convertWebMercAuxtoLL = function (uX,uY) {
  //code completely borrowed from http://www.frosties.com/index.php?option=com_mojo&Itemid=45&p=7
   // lat and long backwards on link for some reason
   //alert("IN CONVERSION");
  var x = uX;
   // alert("IN CONVERSION2");
  var  y = uY;
   
 var num3 = x / 6378137.0;
 var num4 = num3 * 57.295779513082323;
 //alert("IN CONVERSION3");
 var num5 = Math.floor(((num4 + 180.0) / 360.0));
 var num6 = num4 - (num5 * 360.0);
 //alert("IN CONVERSION4");
var  num7 = 1.5707963267948966 - (2.0 * Math.atan(Math.exp((-1.0 * y) / 6378137.0)));
var lon  = num6;
var lat = num7*57.295779513082323;



   // alert([lat,lon]);


    return [lat,lon];
    };
    
        org.mymanatee.common.latlong.convertLLtoWebMercAux = function (lat,lon) {

var num = lon * 0.017453292519943295;
var x = 6378137.0 * num;
var a = lat * 0.017453292519943295;

var mercatorX = x;
var mercatorY = 3189068.5*Math.log((1.0 + Math.sin(a))/(1.0 - Math.sin(a)));


    return [mercatorX,mercatorY];
    };
0 Kudos
by Anonymous User
Not applicable
Original User: jeff.pace

I had to remove some comments to fit under 10k character cap
Here is the measurement dijit (too big to post code)

www.mymanatee.org/gisapps/mapviewer/js/org/mymanatee/widgets/MeasureWidget.js

and the Coordinate Dijit

http://www.mymanatee.org/gisapps/mapviewer/js/org/mymanatee/widgets/CoordinateWidget.js
0 Kudos
by Anonymous User
Not applicable
Original User: BLynn

The code should still work. Did you require "dijit/registry"?


I did.  Here is a link to a page with the measure tool running if you want to take a look.  Nothing fancy just a map and the measurement tool.  You will see the blink the reformatted results then quickly return to it's normal state.  I think it is something simple I just can't put my finger on it.

http://www.kgis.org/kgismaps/measurement.html

Thanks.
0 Kudos
BryanLynn
Deactivated User
I had to remove some comments to fit under 10k character cap
Here is the measurement dijit (too big to post code)

www.mymanatee.org/gisapps/mapviewer/js/org/mymanatee/widgets/MeasureWidget.js

and the Coordinate Dijit

http://www.mymanatee.org/gisapps/mapviewer/js/org/mymanatee/widgets/CoordinateWidget.js


Thanks for the input and code samples!!

Man, that's some heavy math for 8:00 a.m. with no coffee 😉
0 Kudos
by Anonymous User
Not applicable
Original User: jeff.pace

I have a physical oceanography background that required calc 5.  And mom dad and sis are all math teachers. That said, it was still heavy math, even with coffee.

🙂
0 Kudos