ThinkGeo.com    |     Documentation    |     Premium Support

Draw a straght line, do the distance measurement and remove it

Hi,


I need to implenment a distance measurement function on the client side. 


What I need for the function is that...  when the users press down shift and ctrl keys (the distance measure mode will be enabled), they will be able to draw straight line on the map with the mouse and the distance will be measured and displayed on the map at the same time as they draw.  Upon release of the shift and ctrl keys or mouseup, the line should disapear along with the meaured distance showed previously.


I can basically get this working.  However,  I have the following problems: 1) although I use  Map1.SetDrawMode("Line") , the line being drawn is not straight.  2)The line dispears when users release the shift and ctrl keys before mouse up, but the line stays on the map if mouse up is before the release of shift and ctrl keys..


what I do in the script like below..


function OnClientDrawEnd()

{    

    if (shiftDown && ctrlDown)

    {   

        // Measurement for the line is done.  Remove the line.         Map1.CancelLatestFeature();                   }  }  


And includ it in the cc1 tag in the Default.aspx file like this


<cc1:Map ID="Map1" runat="server" height="100%" width="100%" MapUnit="Meter" 

        onclientdrawend="OnClientDrawEnd">

    </cc1:Map> 


 and I  Map1.SetDrawMode("Line")


was called when the users press down shift and ctrl keys..


Hope you understand what I am talking about.. Can you show me how to fix this so that ... I can meet my requirement..that the line being drawn will be straight and  after the distance measurement the line will be removed no matter whether the keys or the mouse are released first?  


Thanks!


Roson


 



Sorry.. but I don't know how to get rid of the html code in the above... =(


the code I post above is the following


 function OnMapCreated(map) { ...


document.body.onkeydown = function () { 

        if ( event.shiftKey && event.ctrlKey )

        {

            // Measurement of a line is turned on.

            shiftDown = event.shiftKey;

            ctrlDown = event.ctrlKey;

            Map1.SetDrawMode("Line");

            ...

        }

    };


....}


 


 


 function OnClientDrawEnd()

{    

    if (shiftDown && ctrlDown)

    {   

        // Measurement for the line is done.  Remove the line.

        Map1.CancelLatestFeature();              

    }

   


<cc1:Map ID="Map1" runat="server" height="100%" width="100%" MapUnit="Meter" 

        onclientdrawend="OnClientDrawEnd">

    </cc1:Map>


 


 


thanks a lot!


 


Roson




Hi Roson,
The current Web Edition is not able to support that display the measure distance on the map and draw the line at the same time. It can only support that display the distance when you click on the map. Another thing is that the shift key is conflicted to a functionality of OpenLayers, so that you can not use the shift key to implement this. 
We have some code to demonstrate how to implement measure distance by the measure line control, please take a look and have a try:

var measureLineControl;
var tgMap;

var OnMapCreated = function(map) {
    tgMap = map;
}

function activate() {
    if (!measureLineControl) {
        var displayLayer = new OpenLayers.Layer.Vector(‘displayLayer’);

        measureLineControl = new OpenLayers.Control.Measure(OpenLayers.Handler.Path, { persist: true });
        measureLineControl.events.on({
            “measure”: handleMeasurementCompleted,
            “measurepartial”: handleMeasurements
        });

        tgMap.addControl(measureLineControl);
    }
    measureLineControl.activate();
}

function deactivate() {
    if (measureLineControl) {
        measureLineControl.deactivate();
    }
}

function handleMeasurements(event) {
    var geometry = event.geometry;
    var units = event.units;
    var order = event.order;
    var measure = event.measure;

    var element = document.getElementById(‘output’);
    var out = “”;

    out += "Distance: " + measure.toString() + " " + units.toString();

    element.innerHTML = out;
}

function handleMeasurementCompleted(event) {

        }

document.body.onkeydown = function() {
    if (event.ctrlKey) {
        activate();
    }
}

document.body.onkeyup = function() {
    
        deactivate();        
}

Any more questions please let me know.
Thanks,
Sun


Thanks Sun.


I think this works on IE but not Firefox (i press crtl and it doesn't trigger the line drawing which works on IE)?  Is there a way to handle this?


and ... now when I press down Ctrl key .. .. and draw the line: start with a mouse click and end with a doubleclick.. it shows me Error message :"object doesn't support this property or method" with line number where function handleMeasurementCompleted(event) is. After i click ok,  the line stays on the map... how can I remove the line after the doubleclick? (I have tried something but didn't work ..=( )


 


 


Thanks a lot!


 


Roson


 


 



Roson,


For you first question, if you want to add the fire fox support you could use a keyboard handler of OpenLayers to implement this. The code is like this and we don’t need the onkeydown even any more:


[script removed]
    var measureLineControl;
    var tgMap;

    var OnMapCreated = function(map) {
        tgMap = map;

        var keyboardHandler = new OpenLayers.Handler.Keyboard(this, {
            "keydown": defaultKeyPress
        });

        keyboardHandler.setMap(map);
        keyboardHandler.activate();
    }

    var defaultKeyPress = function(evt) {
        if (evt.keyCode == 17) {
            activate();
        }
    }

    function activate() {
        if (!measureLineControl) {
            var displayLayer = new OpenLayers.Layer.Vector('displayLayer');

            measureLineControl = new OpenLayers.Control.Measure(OpenLayers.Handler.Path, { persist: true });
            measureLineControl.events.on({
                "measurepartial": handleMeasurements
            });

            tgMap.addControl(measureLineControl);
        }
        measureLineControl.activate();
    }

    function deactivate() {
        if (measureLineControl) {
            measureLineControl.deactivate();
        }
    }

    function handleMeasurements(event) {
        var geometry = event.geometry;
        var units = event.units;
        var order = event.order;
        var measure = event.measure;

        var element = document.getElementById('output');
        var out = "";

        out += "Distance: " + measure.toString() + " " + units.toString();

        element.innerHTML = out;
    }
[script removed]


For the second question, we don’t do anything in the handleMeasurementCompleted, so please just get rid of it and hook the measurepartial event only:


measureLineControl.events.on({
    "measurepartial": handleMeasurements
});


 
Any more questions please let me know.
 
Thanks,
 
Sun

Hi Sun, 
  
 Thank you.  
 I tried both. the second one works.  didn’t quite get the first one work… I probably made some silly mistake… but have to move on to something else at the moment.  I will let you know if I have any problem with the first one… 
  
 Thanks, 
 Roson

OK, please feel free to let me know if you have any more questions. 
  
 Thanks, 
  
 Sun 


Hi Sun,


I have 2 issues.


FIRST, when the start point and end point is near each other, the measure out put give some erroneous numbers like a huge number, however, this doesn't happen when the two points are too near to each other. Do you have any idea what would be the cause and how to fix it?


 


SECOND, the distance measurement output shows on IE but not FF. To have the measurement show on the map, I have the following



        
  • in the handleMeasurements() method.


{...


var element = document.getElementById('measurement');


document.getElementById('measurement').style.display = "inline";


var out = "";


...


element.innerHTML = out;


}


 



        
  •   in the Default.aspx, I added inside the form


   



        
  •  in the .. samplepic/style.css, I added


#measurement


{


bottom:0;


display:block;


font-family:Arial,Helvetica,sans-serif;


font-size:x-small;


position:absolute;


left:3px;


}


 


Can you see any reason why it only shows on IE and not FF and how could I make it also show on FF?


Thanks a lot!


Roson



Lishan, 
  
 Sorry, we cannot recreate both of your issue. For the first one; I want to clarify is that OpenLayers has two display units for the measurement; one is “km” while the other is ‘m’, so please double check the unit of huge number you have mentioned. It might be correct if you modify it to “m” 
  
 For your second issue, I guess it’s the style of the div affects the appearance such as “z-index” and “top”, so please try to set them and let me know your feedback. 
  
 Thanks, 
 Howard

Hi Howard, 
  
 You are right on both. =]  
 My problems are solved now.  
  
 Thanks a lot! 
  
 Roson

Lishan, 
  
 You are welcome; please let me know if you have more questions. 
  
 Thanks, 
 Howard

Hi, 
  
 I just discovered that the distance measured is not correct (compared the result from Google Map) 
  
 function handleMeasurements(event) { 
     var geometry = event.geometry; 
     var units = event.units; 
     var order = event.order; 
     var measure = geometry.getLength(); 
     var kilometers; 
     var meters; 
     var miles; 
     var feets; 
      
  
      
     if (units ==“km”) 
     { 
    
      kilometers = measure/1000; 
     meters= measure; 
     miles = kilometers* 0.621371192; 
     feets = miles * 5280; } 
     else//units is m 
      { 
      meters = measure; 
     kilometers= measure / 1000; 
     miles = measure * 0.621371192 / 1000; 
     feets = miles * 5280; }   
     
    … 
      if (order == 1) //linear 
       { 
         out += distanceString+ “: " + kilometers.toFixed(2) + kmString+” ," + miles.toFixed(2) +" “+ mileString +” ," + feets.toFixed(2) + " “+ feetString; 
  
     } else { 
     out += distanceString+ “: “+ kilometers.toFixed(2) + kmString+” ,” + miles.toFixed(2) + " " +mileString + " ,”  + feets.toFixed(2) + feetString + “2</” + “sup>”; 
          } 
 …} 
  
 seems like in the output… the distance for miles should be the distance for km (check with Google Map)… so it’s not correct… 
  
 I have  “Map1.MapUnit = GeographyUnit.Meter;” in Page_Load 
  
 Do you have any idea what could cause the incorrect distance measurement? something to do with projection?? 
  
 thanks! 
  
 Roson

Lishan,



When a point is added to the measurement sketch, and then listeners will receive an event with measure, units, oreder, and geometry, the measure property is just the length of line. We found you use the getLength function of geometry to get the distance, that's the distance based on  MapUnit you have set, the default unit is degrees. You could get the right line distance through the code below:



       
var measure = event.measure; 


Any more questions please let me know.

 

Thanks,


Johnny



Hi Jonny, 
  
 I changed it to the following as your said… 
  
  
  
  
   var geometry = event.geometry; 
     var units = event.units; 
     var order = event.order; 
     var measure = event.measure; 
     var kilometers; 
     var meters; 
     var miles; 
     var feets; 
      
  
      
     if (units =="km") 
     { 
    
      kilometers = measure; 
     meters= kilometers* 1000; 
     miles = kilometers* 0.621371192; 
     feets = miles * 5280; } 
     else//units is m 
      { 
      meters = measure; 
     kilometers= measure / 1000; 
     miles = measure * 0.621371192 / 1000; 
     feets = miles * 5280; }   
      
  
  
 it still gives the same and incorrect distance. =( 
  
  
  
 Roson 


Lishan, 



Sorry, we could recreate your problem. We guess the problem maybe was resulted from precision. You could modify the paramerter of toFixed function and test it. Here is a simple sample for you, you could test it and see whether there is problem. Another thing is that we notice that maybe you have something wrong when you covert km to other units in the last post. 



If you still hava any problems, please provide us with your sample and we will address this issue quickly. 



Thanks, 



Johnny



1647-MeatureSample.html (6.98 KB)

Hi Johnny,


 


I have attached the sample.. 


thanks for your help!


 


 


Roson










1649-sample.zip (98.7 KB)

Lishan,



We noticed that you used another projection 900913, and so you may set geodesic to true if you want to calculate geodesic metrics instead of planar metrics. The code likes below:


 measureControls = {
                line: new OpenLayers.Control.Measure(
                    OpenLayers.Handler.Path, {
                        persist: true,
geodesic : true,
                        handlerOptions: {
                            layerOptions: { styleMap: styleMap }
                        }
                    }
                ),
                polygon: new OpenLayers.Control.Measure(
                    OpenLayers.Handler.Polygon, {
                        persist: true,
geodesic : true,
                        handlerOptions: {
                            layerOptions: { styleMap: styleMap }
                        }
                    }
                )
            };



Any more question please let me know.



Thanks,



Johnny



Hi Johnny, 
  
 after i added the  geodesic : true…  
 the result is even more off…  
  
 It gives a huge number…  like 16401.99 km for some distance supposed to be less that 6km… 
  
 How should I change my calculation to make it right? 
 kilometers = event.measure … ?? 
  
 Thanks! 
  
 Roson 


Lishan,


Sorry for that, we can't recreate your issue. Here is a simple sample that use your code on the client side. We just modify some code in order to make it run, not modify your draw code. You may check it. And we have tested the distance you have mentiioned last post, that's right. So we set the center at the Steveston Hwy, Richmond,  you could check it handily.


Any more question please let me know.


Thanks,


Johnny


 


 



1656-MeasureLineSample.zip (9 KB)