This line var area = event.geometry.getArea();
should be var area = event.feature.geometry.getArea();
So i believe this is what you're looking for:
vectors.events.on({
featuremodified: featureModified
});
function featureModified(event) {
var area = event.feature.geometry.getArea();
var radius = 0.565352 * Math.sqrt(area);
alert(radius);
}
Here's the modified full working code:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<!--CSS for Map -->
<style type="text/css">
html, body, #map {
margin: 0;
width: 100%;
height: 100%;
}
</style>
<!-- END of CSS for Map -->
<!--CSS for Controls to draw circle and navigate -->
<style type="text/css">
#controls {
position: absolute;
bottom: 1em;
left: 100px;
width: 400px;
z-index: 20000;
padding: 0 0.5em 0.5em 0.5em;
}
#controlToggle {
padding-left: 1em;
}
#controlToggle li {
list-style: none;
}
#form {
position: absolute;
bottom: 1em;
left: 400px;
width: 200px;
z-index: 20000;
padding: 0 0.5em 0.5em 0.5em;
}
</style>
<!-- END CSS for Controls to draw circle -->
<link href="css/style.css" rel="stylesheet" type="text/css" />
<script src="js/firebug.js"></script>
<script src="http://openlayers.org/dev/OpenLayers.js"></script>
<script type="text/javascript">
var lon = 24.0000000000;
var lat = -29.000000000000;
var zoom = 4;
var map, layer, vectors, controls;
function init() {
// Because the Streetmaps system uses 300x300 tiles, we need to set up the scaling variables to work with these
var aRes = [90, 45, 22.500000, 11.250000, 5.625000, 2.812500, 1.406250, 0.703125, 0.351563, 0.175781, 0.087891, 0.043945, 0.021973, 0.010986, 0.005493, 0.002747, 0.001373, 0.000687, 0.000343];
for (var l = 0; l < aRes.length; l++) { aRes[l] = aRes[l] / 300; }
// Normal init, but we pass through the info about the zoom/scaling as options
map = new OpenLayers.Map('map', { tileSize: new OpenLayers.Size(300, 300), projection: 'CRS:84', numZoomLevels: aRes.length, resolutions: aRes, maxResolution: 360 / 300 });
// At this point the control is used as per normal
layer1 = new OpenLayers.Layer.WMS(
'Streetmaps Streets',
'http://www.streetmaps.co.za/WMS/?',
{
key: 'HZPGNWPNDYPREPTIKSIHWKYKQYYOQVYX',
service: 'WMS',
request: 'GetMap',
version: '1.3.0',
layers: 'sm.maps.tiled',
format: 'image/png'
}
);
layer2 = new OpenLayers.Layer.WMS(
'Streetmaps Imagery',
'http://www.streetmaps.co.za/WMS/?',
{
key: 'HZPGNWPNDYPREPTIKSIHWKYKQYYOQVYX',
service: 'WMS',
request: 'GetMap',
version: '1.3.0',
layers: 'sm.imagery',
format: 'image/png'
}
);
// This loads the map
map.addLayer(layer1);
map.addLayer(layer2);
map.setCenter(new OpenLayers.LonLat(lon, lat), zoom);
map.addControl(new OpenLayers.Control.LayerSwitcher());
var vectors = new OpenLayers.Layer.Vector("vector", { isBaseLayer: true });
map.addLayers([vectors]);
// This loads the overlays
var wms = new OpenLayers.Layer.WMS("OpenLayers WMS",
"http://vmap0.tiles.osgeo.org/wms/vmap0?", { layers: 'basic' });
OpenLayers.Feature.Vector.style['default']['strokeWidth'] = '2';
// allow testing of specific renderers via "?renderer=Canvas", etc
var renderer = OpenLayers.Util.getParameters(window.location.href).renderer;
renderer = (renderer) ? [renderer] : OpenLayers.Layer.Vector.prototype.renderers;
vectors = new OpenLayers.Layer.Vector("Vector Layer", {
renderers: renderer
});
map.addLayers([wms, vectors]);
map.addControl(new OpenLayers.Control.LayerSwitcher());
map.addControl(new OpenLayers.Control.MousePosition());
map.setCenter(new OpenLayers.LonLat(lon, lat), zoom);
// Now we call an alert to get the bounds or coordinates from a circle or vector we have drawn
vectors.events.on({
featuresadded: onFeaturesAdded
});
function onFeaturesAdded(event) {
var bounds = event.features[0].geometry.getBounds();
var answer = "bottom: " + bounds.bottom + "\n";
answer += "left: " + bounds.left + "\n";
answer += "right: " + bounds.right + "\n";
answer += "top: " + bounds.top + "\n";
alert(answer);
}
vectors.events.on({
featuremodified: featureModified
});
function featureModified(event) {
var area = event.feature.geometry.getArea();
var radius = 0.565352 * Math.sqrt(area);
alert(radius);
}
controls = {
regular: new OpenLayers.Control.DrawFeature(vectors,
OpenLayers.Handler.RegularPolygon,
{ handlerOptions: { sides: 40} }),
modify: new OpenLayers.Control.ModifyFeature(vectors)
};
for (var key in controls) {
map.addControl(controls[key]);
}
map.setCenter(new OpenLayers.LonLat(0, 0), 3);
document.getElementById('noneToggle').checked = true;
}
function update() {
// reset modification mode
//controls.modify.mode = OpenLayers.Control.ModifyFeature.RESHAPE;
controls["modify"].activate();
controls.modify.mode = OpenLayers.Control.ModifyFeature.ROTATE;
var resize = document.getElementById("resize").checked;
if (resize) {
controls.modify.mode |= OpenLayers.Control.ModifyFeature.RESIZE;
var keepAspectRatio = document.getElementById("keepAspectRatio").checked;
if (keepAspectRatio) {
controls.modify.mode &= ~OpenLayers.Control.ModifyFeature.RESHAPE;
}
}
var drag = document.getElementById("drag").checked;
if (drag) {
controls.modify.mode |= OpenLayers.Control.ModifyFeature.DRAG;
}
// if (rotate || drag) {
// controls.modify.mode &= ~OpenLayers.Control.ModifyFeature.RESHAPE;
// }
// var sides = parseInt(document.getElementById("sides").value);
// sides = Math.max(3, isNaN(sides) ? 0 : sides);
// controls.regular.handler.sides = sides;
// var irregular = document.getElementById("irregular").checked;
// controls.regular.handler.irregular = irregular;
}
function toggleControl(element) {
for (key in controls) {
var control = controls[key];
if (element.value == key && element.checked) {
control.activate();
} else {
control.deactivate();
}
}
}
</script>
</head>
<body onLoad="init()">
<div id="map" class="smallmap"></div>
<div id="controls">
<ul id="controlToggle">
<li>
<input type="radio" name="type" value="none" id="noneToggle"
onclick="toggleControl(this);" checked="checked" />
<label for="noneToggle">navigate</label>
</li>
<li>
<input type="radio" name="type" value="regular" id="regularToggle" onClick="toggleControl(this);" />
<label for="regularToggle">draw regular polygon</label>
</li>
<li>
<input type="radio" name="type" value="modify" id="modifyToggle"
onclick="update();" />
<label for="modifyToggle">modify feature</label>
<ul>
<li>
<input id="rotate" type="hidden"
name="rotate" onChange="update()" checked="checked"/>
</li>
<li>
<input id="resize" type="hidden"
name="resize" onChange="update()" checked="checked"/>
<input id="keepAspectRatio" type="hidden"
name="keepAspectRatio" onChange="update()" checked="checked" />
<label for="keepAspectRatio"></label>
</li>
<li>
<input id="drag" type="hidden"
name="drag" onChange="update()" checked="checked"/>
</li>
</ul>
</li>
</ul>
</body>
</html>
Spent quite some time testing, and as usual, the solution is fairly simple once you know how Leaflet wants to work.
The solution is to specify a custom CRS with a custom transform function. This s where you can specify what each map unit/pixel represents, and this is what is used by Leaflet internally for all distance calculations and - well - transforms :) .
Leaflet does neither support changing CRS (Coordinate Reference System) of a map after its been initialized, nor does it support different CRS per layer. This means you have to specify this custom CRS before you initialize the map. Or you have to reinitialize the map when you want to load a different layer: If you need to do that, know that you can use "map.remove()" to properly remove an already initialized map (this function is not documented, so I had to search a bit).
Look at this fiddle for how I fixed the problem fiddle posted in the question:
https://jsfiddle.net/pdqavdup/2/
var factorx = 0.125
var factory = 0.125
L.CRS.pr = L.extend({}, L.CRS.Simple, {
projection: L.Projection.LonLat,
transformation: new L.Transformation(factorx, 0, -factory, 0),
// Changing the transformation is the key part, everything else is the same.
// By specifying a factor, you specify what distance in meters one pixel occupies (as it still is CRS.Simple in all other regards).
// In this case, I have a tile layer with 256px pieces, so Leaflet thinks it's only 256 meters wide.
// I know the map is supposed to be 2048x2048 meters, so I specify a factor of 0.125 to multiply in both directions.
// In the actual project, I compute all that from the gdal2tiles tilemapresources.xml,
// which gives the necessary information about tilesizes, total bounds and units-per-pixel at different levels.
// Scale, zoom and distance are entirely unchanged from CRS.Simple
scale: function(zoom) {
return Math.pow(2, zoom);
},
zoom: function(scale) {
return Math.log(scale) / Math.LN2;
},
distance: function(latlng1, latlng2) {
var dx = latlng2.lng - latlng1.lng,
dy = latlng2.lat - latlng1.lat;
return Math.sqrt(dx * dx + dy * dy);
},
infinite: true
});
var MAP = L.map('map', {
crs: L.CRS.pr
}).setView([0, 0], 2);
var mapheight = 2048;
var mapwidth = 2048;
var sw = MAP.unproject([0, mapheight], 4); // Level 4, because this is the level where meters-per-pixel is exactly 1
var ne = MAP.unproject([mapwidth, 0], 4);
var layerbounds = new L.LatLngBounds(sw, ne);
var mapname = "beirut"
var mapimage = L.tileLayer('http://tournament.realitymod.com/mapviewer/tiles/' + mapname + '/{z}/{x}/{y}.jpg', {
minZoom: 0,
maxZoom: 5,
bounds: layerbounds,
noWrap: true,
attribution: '<a href="http://tournament.realitymod.com/showthread.php?t=34254">Project Reality Tournament</a>'
})
mapimage.addTo(MAP);
L.control.scale({
imperial: false
}).addTo(MAP);
Best Answer
You should call
map.invalidateSize()
after you change the map size. Or maybe try to wait