get coordinates of drawn feature in OpenLayers - javascript

I'm trying to create an online map using OpenLayers 3.
I'm brand new to using OpenLayers, and all I'm trying to do is to get the coordinates of the points, lines, polygons that I drew on the map. I'm aware that there is a featuresadded parameter available, but I'm not able to implement it correctly.
Can anybody point me in the right direction how to get the coordinates of a drawn feature (either in an alert() or console.log)?
Thanks a ton!!
here's my code:
<html>
<head>
<script src="http://openlayers.org/en/v3.3.0/build/ol.js" type="text/javascript"></script>
<link rel="stylesheet" href="ol.css" type="text/css">
<style type="text/css">
body {
font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
font-size: small;
}
#map {
clear: both;
position: relative;
border: 1px solid black;
}
#wrapper {
width: 337px;
height: 50px;
}
#location {
float: right;
font-family: Arial, Verdana, sans-serif;
font-size: 12px;
color: #483D8B;
background-color: white;
}
#nodelist{
font-family: Arial, Verdana, sans-serif;
font-size: 14px;
color: #000000;
font-style: normal;
background-color: white;
}
</style>
<script type="text/javascript">
var map;
var draw;
var transformed_coordinate;
var vector;
function init() {
var view = new ol.View({
center: ol.proj.transform([13.1929, 55.718],'EPSG:4326', 'EPSG:3857'),
zoom: 12
});
var myZoom = new ol.control.Zoom();
var myZoomSlider = new ol.control.ZoomSlider();
var zoomToExtentControl = new ol.control.ZoomToExtent({
extent: [1453297.22,7490484.81,1483872.03,7513415.91]
});
var myScaleLine = new ol.control.ScaleLine()
var neighborhood = new ol.source.ImageWMS({
url: 'http://localhost:8090/geoserver/project/wms',
params: {'LAYERS': 'project:Neighborhood'}
});
var roads = new ol.source.ImageWMS({
url: 'http://localhost:8090/geoserver/project/wms',
params: {'LAYERS': 'project:Roads_all'}
});
var source = new ol.source.Vector({wrapX: false});
vector = new ol.layer.Vector({
source: source,
style: new ol.style.Style({
fill: new ol.style.Fill({
color: 'rgba(0, 255, 0, 0.5)'
}),
stroke: new ol.style.Stroke({
color: '#ffcc33',
width: 2
}),
image: new ol.style.Circle({
radius: 7,
fill: new ol.style.Fill({
color: '#ffcc33'
})
})
})
});
var layers = [
new ol.layer.Image({
source: neighborhood
}),
new ol.layer.Image({
source: roads
}),
vector
]
map = new ol.Map({
layers: layers,
target: 'map',
view: view
});
map.addControl(myZoom);
map.addControl(myZoomSlider);
map.addControl(zoomToExtentControl);
map.addControl(myScaleLine);
map.on('singleclick', function(evt){
var coord = evt.coordinate;
transformed_coordinate = ol.proj.transform(coord, "EPSG:3857", "EPSG:4326");
//console.log(transformed_coordinate);
})
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);
}
var typeSelect = document.getElementById('type');
function addInteraction() {
var value = typeSelect.value;
if (value !== 'None') {
var geometryFunction, maxPoints;
if (value === 'Square') {
value = 'Circle';
geometryFunction = ol.interaction.Draw.createRegularPolygon(4);
} else if (value === 'Box') {
value = 'LineString';
maxPoints = 2;
geometryFunction = function(coordinates, geometry) {
if (!geometry) {
geometry = new ol.geom.Polygon(null);
}
var start = coordinates[0];
var end = coordinates[1];
geometry.setCoordinates([
[start, [start[0], end[1]], end, [end[0], start[1]], start]
]);
return geometry;
};
}
draw = new ol.interaction.Draw({
source: source,
type: /** #type {ol.geom.GeometryType} */ (value),
geometryFunction: geometryFunction,
maxPoints: maxPoints
});
map.addInteraction(draw);
}
}
/**
* Let user change the geometry type.
* #param {Event} e Change event.
*/
typeSelect.onchange = function(e) {
map.removeInteraction(draw);
addInteraction();
};
addInteraction();
} //end init
</script>
</head>
<body onload="init()">
<div id="map" style="width: 800px; height: 600px"></div>
<form class="form-inline">
<label>Geometry type </label>
<select id="type">
<option value="None">None</option>
<option value="Point">Point</option>
<option value="LineString">LineString</option>
<option value="Polygon">Polygon</option>
</select>
</form>
</body>
</html>

Register a listener on ol.source.Vector and wait until the drawn feature is added:
source.on('addfeature', function(evt){
var feature = evt.feature;
var coords = feature.getGeometry().getCoordinates();
});

Use drawend event
drawend (ol.interaction.DrawEvent) - Triggered upon feature draw ends
Ex:
this.draw = new ol.interaction.Draw();
this.draw.on('drawend', function(evt){
//in evt you will get ol.feature
// from ol.feature get the geometry and than get coordinates
});
Let me know if I am wrong.

Related

Keep Getting this.callInitHooks error (Leaflet)

I'm trying to add markers and a search bar to my leaflet choropleth map. However, I keep running into an error that tells me: Uncaught TypeError: this.callInitHooks is not a function. It comes from my leaflet.js file, and am unsure how to fix it. Most of my error seems to come from the leaflet links I've copied into my body before my script, or because of me trying to add a search bar or markets onto my map. I pasted my code below:
<html>
<head>
<title>How to make a choropleth map with Leaflet.js</title>
<meta charset="utf-8">
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.3.0/dist/leaflet.css" />
<link rel="stylesheet" href="leaflet-search.css" />
<script src="censustracts.js"></script>
<style type="text/css">
html, body, #map{
height: 100%;
padding: 0;
margin: 0;
}
.info {
padding: 6px 8px;
font: 14px/16px Arial, Helvetica, sans-serif;
background: white;
background: rgba(255,255,255,0.8);
box-shadow: 0 0 15px rgba(0,0,0,0.2);
border-radius: 5px;
}
.info h4 {
margin: 0 0 5px;
color: #777;
}
.legend {
line-height: 18px;
color: #555;
}
.legend i {
width: 18px;
height: 18px;
float: left;
margin-right: 8px;
opacity: 0.7;
}
</style>
</head>
<body>
<div id="map"></map>
<script src="https://unpkg.com/leaflet#1.3.0/dist/leaflet.js"></script>
<script src="leaflet-search.js"></script>
<script type="text/javascript">
var map = L.map('map').setView([37.8, -96], 4);
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {attribution: 'OSM'})
.addTo(map);
L.geoJson(statesData).addTo(map);
L.geoJson(statesData).addTo(map);
function getColor(d) {
return d > 1000 ? '#800026' :
d > 500 ? '#BD0026' :
d > 200 ? '#E31A1C' :
d > 100 ? '#FC4E2A' :
d > 50 ? '#FD8D3C' :
d > 20 ? '#FEB24C' :
d > 10 ? '#FED976' :
'#FFEDA0';
}
function style(feature) {
return {
fillColor: getColor(feature.properties.density),
weight: 2,
opacity: 1,
color: 'white',
dashArray: '3',
fillOpacity: 0.7
};
}
L.geoJson(statesData, {style: style}).addTo(map);
///Functionality
function highlightFeature(e) {
var layer = e.target;
layer.setStyle({
weight: 5,
color: '#666',
dashArray: '',
fillOpacity: 0.7
});
info.update(layer.feature.properties);
if (!L.Browser.ie && !L.Browser.opera && !L.Browser.edge) {
layer.bringToFront();
}
}
function resetHighlight(e) {
geojson.resetStyle(e.target);
info.update();
}
function zoomToFeature(e) {
map.fitBounds(e.target.getBounds());
}
function onEachFeature(feature, layer) {
layer.on({
mouseover: highlightFeature,
mouseout: resetHighlight,
click: zoomToFeature
});
}
geojson = L.geoJson(statesData, {
style: style,
onEachFeature: onEachFeature
}).addTo(map);
//Add info
var info = L.control();
info.onAdd = function (map) {
this._div = L.DomUtil.create('div', 'info'); // create a div with a class "info"
this.update();
return this._div;
};
// method that we will use to update the control based on feature properties passed
info.update = function (props) {
this._div.innerHTML = '<h4>US Population Density</h4>' + (props ?
'<b>' + props.name + '</b><br />' + props.density + ' people / mi<sup>2</sup>'
: 'Hover over a state');
};
info.addTo(map);
//Add Legend
var legend = L.control({position: 'bottomright'});
legend.onAdd = function (map) {
var div = L.DomUtil.create('div', 'info legend'),
grades = [0, 10, 20, 50, 100, 200, 500, 1000],
labels = [];
// loop through our density intervals and generate a label with a colored square for each interval
for (var i = 0; i < grades.length; i++) {
div.innerHTML +=
'<i style="background:' + getColor(grades[i] + 1) + '"></i> ' +
grades[i] + (grades[i + 1] ? '–' + grades[i + 1] + '<br>' : '+');
}
return div;
};
legend.addTo(map);
///Bind Popups
var data = [
{"loc":[32,-86], "title":"aquamarine"},
{"loc":[41.575730,13.002411], "title":"black"},
{"loc":[41.807149,13.162994], "title":"blue"},
{"loc":[41.507149,13.172994], "title":"chocolate"},
{"loc":[41.847149,14.132994], "title":"coral"},
{"loc":[41.219190,13.062145], "title":"cyan"},
{"loc":[41.344190,13.242145], "title":"darkblue"},
{"loc":[41.679190,13.122145], "title":"Darkred"},
{"loc":[41.329190,13.192145], "title":"Darkgray"},
{"loc":[41.379290,13.122545], "title":"dodgerblue"},
{"loc":[41.409190,13.362145], "title":"gray"},
{"loc":[41.794008,12.583884], "title":"green"},
{"loc":[41.805008,12.982884], "title":"greenyellow"},
{"loc":[41.536175,13.273590], "title":"red"},
{"loc":[41.516175,13.373590], "title":"rosybrown"},
{"loc":[41.506175,13.273590], "title":"royalblue"},
{"loc":[41.836175,13.673590], "title":"salmon"},
{"loc":[41.796175,13.570590], "title":"seagreen"},
{"loc":[41.436175,13.573590], "title":"seashell"},
{"loc":[41.336175,13.973590], "title":"silver"},
{"loc":[41.236175,13.273590], "title":"skyblue"},
{"loc":[41.546175,13.473590], "title":"yellow"},
{"loc":[41.239190,13.032145], "title":"white"}
];
var markersLayer = new L.LayerGroup(); //layer contain searched elements
map.addLayer(markersLayer);
var controlSearch = L.Control.Search({
position:'topright',
layer: markersLayer,
initial: false,
zoom: 12,
marker: false
});
map.addControl( controlSearch );
for(i in data) {
var title = data[i].title, //value searched
loc = data[i].loc, //position found
marker = new L.Marker(new L.latLng(loc), {title: title} );//se property searched
marker.bindPopup('title: '+ title );
markersLayer.addLayer(marker);
}
</script>
</body>
</html>
Don't use new with lowercase function:
marker = new L.Marker(new L.latLng(loc), {title: title} );
Use new L.LatLng(loc) or L.latLng(loc) without new

Delete function fails when there is more than 1 marker on Google Maps

I am working on Google Maps feature that allows people to drag markers from a sidebar and place them on a map. When a user clicks a marker the info window pops up and gives some data along with a delete button.
This delete button works fine when there is only 1 marker on the map, but when there is more than one it fails to delete the right marker (as you can see from the gif below).
This is what I have for my JavaScript
var map, iw, drag_area, actual, mark;
var overview, zIndex = 0;
newMarkers = []; //declare empty markers array
id = 0; //marker id set at 0
function helper() {
this.setMap(map);
this.draw = function() {};
}
helper.prototype = new google.maps.OverlayView();
function fillMarker(icon) {
var div = document.createElement("div");
div.style.backgroundImage = "url(" + icon + ")";
var left;
if (mark.id == "m1") {
left = "0px";
} else if (mark.id == "m2") {
left = "50px";
} else if (mark.id == "m3") {
left = "100px";
}
div.style.left = left;
div.id = mark.id;
div.className = "drag";
div.onmousedown = div.ontouchstart = initDrag;
drag_area.replaceChild(div, mark);
mark = null;
}
function createDraggedMarker(latlng, icon) {
var icon = {
url: icon,
size: new google.maps.Size(32, 32),
anchor: new google.maps.Point(15, 32)
};
marker = new google.maps.Marker({
position: latlng,
map: map,
clickable: true,
draggable: true,
crossOnDrag: false,
optimized: false,
icon: icon,
zIndex: zIndex,
id: id++ //increment the ID
});
newMarkers.push(marker);
google.maps.event.addListener(marker, "click", function() {
actual = marker;
var lat = actual.getPosition().lat();
var lng = actual.getPosition().lng();
var contentStr = "<div class='infowindow'>" + lat.toFixed(6) + ", " + lng.toFixed(6) + "<\/div>";
var delMe = "<br /><input type = 'button' value = 'Delete' onclick = 'DeleteMarker(" + marker.id + ")' value = 'Delete' />"
iw.setContent(contentStr + delMe);
iw.open(map, this);
});
google.maps.event.addListener(marker, "dragstart", function() {
if (actual == marker) iw.close();
zIndex += 1;
marker.setZIndex(zIndex);
});
}
function initDrag(evt) {
function getPt(evt) {
var pt = {};
if (evt && evt.touches && evt.touches.length) {
pt.x = evt.touches[0].clientX;
pt.y = evt.touches[0].clientY;
} else {
if (!evt) var evt = window.event;
pt.x = evt.clientX;
pt.y = evt.clientY;
}
return pt;
};
var drag = function(mEvt) {
if (mark && mark.className == "drag") {
var pt = getPt(mEvt),
x = pt.x - o.x,
y = pt.y - o.y;
mark.style.left = (mark.x + x) + "px";
mark.style.top = (mark.y + y) + "px";
mark.onmouseup = mark.ontouchend = function() {
var mapDiv = map.getDiv(),
mapLeft = mapDiv.offsetLeft,
mapTop = mapDiv.offsetTop,
mapWidth = mapDiv.offsetWidth,
mapHeight = mapDiv.offsetHeight;
var dragLeft = drag_area.offsetLeft,
dragTop = drag_area.offsetTop,
iconWidth = mark.offsetWidth,
iconHeight = mark.offsetHeight;
var newLeft = mark.offsetLeft + dragLeft + iconWidth / 2;
var newTop = mark.offsetTop + dragTop + iconHeight / 2;
if (dragLeft > mapLeft && newLeft < (mapLeft + mapWidth) && newTop > mapTop && newTop < (mapTop + mapHeight)) {
var offset = 1;
var divPt = new google.maps.Point(newLeft - mapLeft - offset, newTop - mapTop + (iconHeight / 2));
var proj = overview.getProjection();
var latlng = proj.fromContainerPixelToLatLng(divPt);
var icon = mark.style.backgroundImage.slice(4, -1).replace(/"/g, "");
createDraggedMarker(latlng, icon);
fillMarker(icon);
}
};
}
return false;
};
if (!evt) var evt = window.event;
mark = evt.target ? evt.target : evt.srcElement ? evt.srcElement : evt.touches ? evt.touches[0].target : null;
if (mark.className != "drag") {
if (d.cancelable) d.preventDefault();
mark = null;
return;
} else {
zIndex++;
mark.style.zIndex = zIndex.toString();
mark.x = mark.offsetLeft;
mark.y = mark.offsetTop;
var o = getPt(evt);
if (evt.type === "touchstart") {
mark.onmousedown = null;
mark.ontouchmove = drag;
mark.ontouchend = function() {
mark.ontouchmove = null;
mark.ontouchend = null;
mark.ontouchstart = initDrag;
};
} else {
document.onmousemove = drag;
document.onmouseup = function() {
document.onmousemove = null;
document.onmouseup = null;
if (mark) mark = null;
};
}
}
return false;
}
function initialize() {
var mapOptions = {
center: new google.maps.LatLng(52.052491, 9.84375),
zoom: 4,
mapTypeId: google.maps.MapTypeId.ROADMAP,
streetViewControl: false,
mapTypeControlOptions: {
mapTypeIds: [google.maps.MapTypeId.ROADMAP, google.maps.MapTypeId.SATELLITE, google.maps.MapTypeId.TERRAIN]
},
panControl: false,
zoomControlOptions: {
style: google.maps.ZoomControlStyle.SMALL
}
};
map = new google.maps.Map(document.getElementById("map"), mapOptions);
iw = new google.maps.InfoWindow();
google.maps.event.addListener(map, "click", function() {
if (iw) iw.close();
});
drag_area = document.getElementById("markers");
var divArray = drag_area.getElementsByTagName("div");
for (var i = 0; i < divArray.length; i++) {
var div = divArray[i];
div.onmousedown = div.ontouchstart = initDrag;
}
overview = new helper();
}
//Delete the marker by ID
function DeleteMarker(id) {
for (var i = 0; i < newMarkers.length; i++) {
if (newMarkers[i].id == marker.id) {
console.log("This ID: " + this.marker.id);
//markers[i].setMap(null);
newMarkers[i].setMap(null);
newMarkers.splice(i, -1);
return;
}
}
}
google.maps.event.addDomListener(window, 'load', initialize);
body,
html {
height: 100%;
width: 100%;
}
#map {
float: left;
margin: 0 25px 10px 14px;
width: 64%;
height: 70%;
}
#desc {
float: left;
margin: 0 25px 10px 20px;
width: 10em;
}
#markers {
position: absolute;
top: 140px;
left: 70%;
width: 200px;
height: 110px;
}
.drag {
position: absolute;
width: 32px;
height: 32px;
}
.infowindow {
margin-top: 20px;
width: 180px;
height: 60px;
}
#media screen and (max-width: 890px) {
body,
html,
#map {
margin: 0;
}
#map {
width: 100%;
height: 50%;
}
#desc {
margin: 100px 14px 0;
width: 93%;
}
.include >b {
float: right;
margin-top: 17px;
}
#markers {
/* center horizontal and do not overlap the map */
position: absolute;
top: 50%;
left: 50%;
width: 10em;
height: 6em;
margin-top: 5em;
margin-left: -5em;
}
#markers > p {
margin-top: 0;
font-size: 80%;
}
.infowindow {
margin-top: 10px;
width: 150px;
height: 25px;
}
}
<h3>Delete button does not work when there is more than 1 marker</h3>
<div id="map"></div>
<div id="desc"></div>
<div id="markers">
<p>Drag the markers to a location on the map</p>
<div id="m1" class="drag" style="left:0; background-image: url('http://maps.google.com/mapfiles/ms/micons/blue.png')"></div>
<div id="m2" class="drag" style="left:50px; background-image: url('http://maps.google.com/mapfiles/ms/micons/green.png')"></div>
<div id="m3" class="drag" style="left:100px; background-image: url('http://maps.google.com/mapfiles/ms/micons/yellow.png')"></div>
</div>
<script src="https://maps.googleapis.com/maps/api/js?libraries=geometry,places&ext=.js"></script>
So yeah, the delete button only works if there is only 1 Marker on the map, anything more than that and it fails.
Here is my Fiddle: http://jsfiddle.net/xpvt214o/797910/
I think the problem lies in the fact that you're defining marker as global in createDraggedMarker, therefore marker always has the reference to the last added marker thus delete only works on the last added marker.
Changes to make it work:
Make marker local to the method createDraggedMarker
modify DeleteMarker so that it uses the argument id to search in the array for the marker to delete instead of marker.id
The rest remains unchanged.
I marked the changes in the code with comments.
Working fiddle

Onclick location, using location in function

I'm making tile map with two layers: map from my files stored on HDD, second is OSM. I've made it with gdal2tiles.py
How it looks: Two layers using OpenLayers
I want to add a onclick popup which will show link to the original tile in bigger resolution. My idea is to attach a .csv file with following structure:
[latitude],[longitude],[image index]
My function in python parses this file and gets image index. Here is it:
def find_pic(lat, lng):
my_file = open('log wynikowy epsg 3857.csv', 'r')
list_of_lines = my_file.readlines()
print len(list_of_lines)
for line in list_of_lines:
if (line.rstrip()).split(",")[0] == lat and (line.rstrip()).split(',')[1] == lng:
return line.rstrip().split(',')[2]
Then I tried to rewrite it in JavaScript:
function find_pic(lat, lng) {
fh = fopen(getScriptPath('log wynikowy epsg 3857.csv'), 0);
fh_length = flength(fh);
var allText = fread(fh, fh_length);
var fldData = [];
for (x = 0; x < allTextLines.length; x++) {
fldData = allTextLines[x].split(',');
}
for (i = 0; i < fldData.length.length; i++) {
if (allTextLines[i].split(',')[0] == lat && allTextLines[i].split(',')[1] == lng) {
var result = allTextLines[i].split(',')[2];
}
}
var pic_link = "/data/" + result + ".jpg";
return pic_link;
}
In my html file, I copy-paste popup with location example and try to implement my function. Here is the whole HTML:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
<head>
<title>Ortofotomapa</title>
<meta http-equiv='imagetoolbar' content='no'/>
<style type="text/css"> v\:* {behavior:url(#default#VML);}
html, body { overflow: hidden; padding: 0; height: 100%; width: 100%; font-family: 'Lucida Grande',Geneva,Arial,Verdana,sans-serif; }
body { margin: 10px; background: black; }
h1 { margin: 0; padding: 6px; border:0; font-size: 20pt; }
#header { height: 43px; padding: 0; background-color: #eee; border: 1px solid #888; }
#subheader { height: 12px; text-align: right; font-size: 10px; color: #555;}
#map { height: 95%; border: 1px solid #888; }
.olImageLoadError { display: none; }
.olControlLayerSwitcher .layersDiv { border-radius: 10px 0 0 10px; }
</style>
<script src='http://maps.google.com/maps/api/js?sensor=false&v=3.7'></script>
<script src="http://www.openlayers.org/api/2.12/OpenLayers.js"></script>
<script>
var map;
var mapBounds = new OpenLayers.Bounds( 20.9278783732, 52.0107452018, 20.943887533, 52.0184497743);
var mapMinZoom = 14;
var mapMaxZoom = 20;
var emptyTileURL = "http://www.maptiler.org/img/none.png";
OpenLayers.IMAGE_RELOAD_ATTEMPTS = 3;
function init(){
var options = {
div: "map",
controls: [],
projection: "EPSG:900913",
displayProjection: new OpenLayers.Projection("EPSG:4326"),
numZoomLevels: 20
};
map = new OpenLayers.Map(options);
// Create OSM layer
var osm = new OpenLayers.Layer.OSM("OpenStreetMap");
// create TMS Overlay layer
var tmsoverlay = new OpenLayers.Layer.TMS("TMS Overlay", "",
{
serviceVersion: '.',
layername: '.',
alpha: true,
type: 'png',
isBaseLayer: false,
getURL: getURL
});
if (OpenLayers.Util.alphaHack() == false) {
tmsoverlay.setOpacity(1.0);
}
map.addLayers([osm, tmsoverlay]);
var switcherControl = new OpenLayers.Control.LayerSwitcher();
map.addControl(switcherControl);
switcherControl.maximizeControl();
map.zoomToExtent(mapBounds.transform(map.displayProjection, map.projection));
map.addControls([//new OpenLayers.Control.PanZoomBar(),
new OpenLayers.Control.Navigation(),
new OpenLayers.Control.MousePosition({
numDigits: 10}),
//new OpenLayers.Control.ArgParser(),
new OpenLayers.Control.Attribution()]);
}
function getURL(bounds) {
bounds = this.adjustBounds(bounds);
var res = this.getServerResolution();
var x = Math.round((bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w));
var y = Math.round((bounds.bottom - this.tileOrigin.lat) / (res * this.tileSize.h));
var z = this.getServerZoom();
if (this.map.baseLayer.CLASS_NAME === 'OpenLayers.Layer.Bing') {
z+=1;
}
var path = this.serviceVersion + "/" + this.layername + "/" + z + "/" + x + "/" + y + "." + this.type;
var url = this.url;
if (OpenLayers.Util.isArray(url)) {
url = this.selectUrl(path, url);
}
if (mapBounds.intersectsBounds(bounds) && (z >= mapMinZoom) && (z <= mapMaxZoom)) {
return url + path;
} else {
return emptyTileURL;
}
}
function getWindowHeight() {
if (self.innerHeight) return self.innerHeight;
if (document.documentElement && document.documentElement.clientHeight)
return document.documentElement.clientHeight;
if (document.body) return document.body.clientHeight;
return 0;
}
function getWindowWidth() {
if (self.innerWidth) return self.innerWidth;
if (document.documentElement && document.documentElement.clientWidth)
return document.documentElement.clientWidth;
if (document.body) return document.body.clientWidth;
return 0;
}
function resize() {
var map = document.getElementById("map");
var header = document.getElementById("header");
var subheader = document.getElementById("subheader");
map.style.height = (getWindowHeight()-80) + "px";
map.style.width = (getWindowWidth()-20) + "px";
header.style.width = (getWindowWidth()-20) + "px";
subheader.style.width = (getWindowWidth()-20) + "px";
if (map.updateSize) { map.updateSize(); };
}
function find_pic(lat, lng){
fh = fopen(getScriptPath('log wynikowy epsg 3857.csv'), 0);
fh_length = flength(fh);
var allText = fread(fh, fh_length);
var fldData =[];
for (x=0; x<allTextLines.length; x++){
fldData = allTextLines[x].split(',');
}
for (i=0; i<fldData.length.length; i++){
if (allTextLines[i].split(',')[0] == lat && allTextLines[i].split(',')[1] == lng){
var result = allTextLines[i].split(',')[2];
}
}
var link_pic = "/data/" + result + ".jpg";
return link_pic;
}
var overlay = new ol.Overlay({
element: container,
autoPan: true,
autoPanAnimation: {
duration: 250
}
}));
closer.onclick = function() {
overlay.setPosition(undefined);
closer.blur();
return false;
};
map.on('singleclick', function(evt) {
var coordinate = evt.coordinate;
var link_pic = find_pic(coordinate[0],coordinate[1]);
content.innerHTML = '<p>Link do oryginalnego zdjecia: <a href=link_pic>Klik</a></p>';
overlay.setPosition(coordinate);
});
onresize=function(){ resize(); };
var element = document.getElementById('popup');
</script>
</head>
<body onload="init()">
<div id="header"><h1>Ortofotomapa</h1></div>
<div id="subheader">Generated by MapTiler/GDAL2Tiles, Copyright © 2008 Klokan Petr Pridal, GDAL & OSGeo GSoC
<!-- PLEASE, LET THIS NOTE ABOUT AUTHOR AND PROJECT SOMEWHERE ON YOUR WEBSITE, OR AT LEAST IN THE COMMENT IN HTML. THANK YOU -->
</div>
<div id="map"></div>
<script type="text/javascript" >resize()</script>
</body>
</html>
EDIT:After this, page is all black. I want to have onclick popup, which will contain link to a big resolution photo.

Google Map API - multiple icons in wrong spot

I have a very strange issue that seems to have appeared only recently. I haven't done any major code changes to the project in a while and none to the function in question in a long while.
So the problem, when I add more than one icon to Google Map using API, the icons are appearig on top of each other.
The strange thing is the labels are all correctly located but those use the same coordinates as the icons.
Here is the string that is passed to the function
1344, 52.65665917, -2.49004717, '../Images/Icons/Direction/container_blueN.ico', 'Galahad', '2014 Mar 05 Wednesday, 14:00', 'Wellington Road, Horsehay, Hollybank', 'RESERVED', '0 KPH', 0
The function is
function AddClusterLocation(FID, latitude, longitude, Icon, ID, DateStamp, Location, Event, Speed, IgnitionStatus) {
if (objMap) {
var cssName = 'MarkerIgnitionOff';
switch (IgnitionStatus) {
case '1':
cssName = 'MarkerIgnitionOn';
break;
default:
cssName = 'MarkerIgnitionOff';
}
var adjustedIcon = new google.maps.MarkerImage(
Icon,
new google.maps.Size(32, 32),
new google.maps.Point(0, 0),
new google.maps.Point(16, 16)
);
var objMarker = new MarkerWithLabel({
position: new google.maps.LatLng(latitude, longitude),
draggable: false,
raiseOnDrag: false,
icon: adjustedIcon,
map: objMap,
labelContent: ' ' + ID + ' ',
labelAnchor: new google.maps.Point(-8, -8),
labelClass: cssName, // the CSS class for the label
labelStyle: { opacity: 1.0 }
});
// Add Maker to array
objMakersArray.push(objMarker);
// Wrap the event listener inside an anonymous function
// then we immediately invoke and passes the variables to
(function (ID, DateStamp, Location, Event, Speed, Icon) {
google.maps.event.addListener(objMarker, 'click', function () {
if (!objInfoWindows) {
objInfoWindows = new google.maps.InfoWindow();
}
// Create Paragraph
var para1 = document.createElement('p');
var adiv = document.createElement('div');
adiv.style.cssText = 'width: 300px; font-family: "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 10pt; color: #000000;';
// var htmlstring = '<div style="width: 300px; font-family: "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 6pt; color: #FF0000;">'
var htmlstring = '<table>' // style="width: 300px; font-family: "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 6pt; color: #FF0000;">'
htmlstring = htmlstring + '<tr><td style="width: 100px;"><strong>ID</strong></td><td style="width: 200px;">' + ID + '</td></tr>';
htmlstring = htmlstring + '<tr><td><strong>Date/Time</strong></td><td>' + DateStamp + '</td></tr>';
htmlstring = htmlstring + '<tr><td><strong>Location</strong></td><td>' + Location + '</td></tr>';
htmlstring = htmlstring + '<tr><td><strong>Event</strong></td><td>' + Event + '</td></tr>';
htmlstring = htmlstring + '<tr><td><strong>Speed</strong></td><td>' + Speed + '</td></tr></table>'
// htmlstring = htmlstring + '</div>';
adiv.innerHTML = htmlstring;
// para1.innerHTML = htmlstring;
para1.appendChild(adiv);
// Zoom In DIV
var aDiv = document.createElement('div');
aDiv.style.width = "100px";
aDiv.style.float = 'left';
// Zoom In
var alink = document.createElement('a');
alink.innerHTML = 'Zoom In';
alink.href = '#';
alink.onclick = function () {
objMap.setCenter(objMarker.getPosition());
zoomLevel = objMap.getZoom();
if (zoomLevel != 21) {
objMap.setZoom(zoomLevel + 1);
}
return false;
};
aDiv.appendChild(alink);
// Zoom OUT DIV
var bDiv = document.createElement('div');
bDiv.style.width = '100px';
bDiv.style.float = 'left';
// Zoom In
var blink = document.createElement('a');
blink.innerHTML = 'Zoom Out';
blink.href = '#';
blink.onclick = function () {
objMap.setCenter(objMarker.getPosition());
zoomLevel = objMap.getZoom();
if (zoomLevel != 0) {
objMap.setZoom(zoomLevel - 1);
}
return false;
};
bDiv.appendChild(blink);
// Add Favourite Div
var cDiv = document.createElement('div');
cDiv.style.float = 'right';
cDiv.style.width = '150px';
// Add Favourite
var clink = document.createElement('a');
clink.innerHTML = 'Add to Favourite';
clink.href = '#';
clink.onclick = function () {
position = objMarker.getPosition();
Pane = window.parent.ASPxSplitterDefault.GetPaneByName('PaneDisplay');
if (Pane) {
Pane.SetContentUrl('../Pages/FavouritePage.aspx?latitude=' + position.lat() + '&longitude=' + position.lng(), true);
}
return false;
};
cDiv.appendChild(clink);
var para2 = document.createElement('p');
para2.appendChild(aDiv);
para2.appendChild(bDiv);
para2.appendChild(cDiv);
// Create Master Div to hold everything
var masterDiv = document.createElement('div');
// Get name of DIV that has Atlas
var objDiv = objMap.getDiv();
var divName = objDiv.id;
// Bind to mapping Div
document.getElementById(divName).appendChild(masterDiv);
// Info Div
var infoDiv = document.createElement('div');
infoDiv.style.float = 'left';
infoDiv.style.width = '350px';
infoDiv.appendChild(para1);
infoDiv.appendChild(para2);
masterDiv.appendChild(infoDiv);
// Creating the div that will contain the detail map
var detailDiv = document.createElement('div');
infoDiv.style.float = 'right';
detailDiv.style.width = '200px';
detailDiv.style.height = '200px';
masterDiv.appendChild(detailDiv)
// Setting up small map
// Creating MapOptions for the overview map
var overviewOpts = {
zoom: 14,
icon: adjustedIcon,
center: objMarker.getPosition(),
mapTypeId: google.maps.MapTypeId.HYBRID,
disableDefaultUI: true
};
var objdetailMap = new google.maps.Map(detailDiv, overviewOpts);
// Create a marker that will show in the detail map
var objdetailMarker = new google.maps.Marker({
position: objMarker.getPosition(),
map: objdetailMap,
icon: adjustedIcon,
clickable: false
});
// Setting the content of the InfoWindow
objInfoWindows.setContent(masterDiv);
// Tying the InfoWindow to the marker
objInfoWindows.open(objMap, objMarker);
});
})(ID, DateStamp, Location, Event, Speed, Icon);
objMarker = null;
}
}
The function that would call this would be
function OnCurrentPosition(arg) {
if (arg == null) {
parent.location = '../Security/Login.aspx';
}
if (arg) {
var latitude, longitude
var arrayList = arg.split(";");
alert(arg);
for (i = 0; i < arrayList.length; i++) {
if (arrayList[i].length) {
var arrLocation = arrayList[i].split("$")
AddClusterLocation(arrLocation[0], arrLocation[1], arrLocation[2], arrLocation[3], arrLocation[4], arrLocation[5], arrLocation[6], arrLocation[7], arrLocation[8], arrLocation[9]);
SetBounds(arrLocation[1], arrLocation[2]);
latitude = arrLocation[1];
longitude = arrLocation[2];
}
}
CreateClusterer();
if (flgLockMapToBounds == false) {
if (objMakersArray.length == 1) {
SetMapCentre(latitude, longitude, 14);
}
else {
ZoomToExtend();
}
}
}
}
arg = 1344$52.65665917$-2.49004717$../Images/Icons/Direction/container_blueN.ico$Galahad$2014 Mar 05 Wednesday, 14:00$Wellington Road, Horsehay, Hollybank$RESERVED$0 KPH$0$0.00000000$0.00000000$0;1342$52.65582367$-2.48958417$../Images/Icons/Direction/container_yellowN.ico$Gwinevere$2014 Mar 05 Wednesday, 14:00$Woodlands Lane, Horsehay, Coalbrookdale$RESERVED$0 KPH$0$0.00000000$0.00000000$0;
I'm really at a lost to explain this as the labels are correct, I've checked the latitude and longitude and its different each time the function is called. Plus this was working, only spotted by customer yesterday that it wasn't.
Here's the API that I use
<script src="http://maps.google.com/maps/api/js?sensor=false" type="text/javascript"></script>
Thank you for reading the question, hopefully you be able to help!
Jim
There is an issue with the MarkerWithLabel library. Issue.
MarkerWithLabel v1.1.10 stopped working for me recently after Google Maps Api's experimental version became v3.18. I had Maps API set to "...maps/api/js?v3&..." which by default picks latest experimental version (currently v3.18). By fixing the version to v3.17 MarkerWithLabel worked fine.

Range Rings in Google Maps V3

I have a script that was written a long time ago and not by me that I have updated from V2 to V3 and I am trying to draw range rings from a centered LatLng point. This worked in V2 but it is not working in V3 and I can't figure out why as I know some of the code is depreciated but not sure what it needs to be replaced with.
//Function to draw circles
function doDrawCircle(circleUnits, center, circleRadius, liColor, liWidth, liOpa, fillColor, fillOpa, opts, radials){
var bounds = new google.maps.LatLngBounds();
var circlePoints = Array();
with (Math) {
if (circleUnits == 'KM') {
var d = circleRadius/6378.8; // radians
}
else { //miles
var d = circleRadius/3963.189; // radians
}
var lat1 = (PI/180)* center.lat(); // radians
var lng1 = (PI/180)* center.lng(); // radians
for (var a = 0 ; a < 361 ; a++ ) {
var tc = (PI/180)*a;
var y = asin(sin(lat1)*cos(d)+cos(lat1)*sin(d)*cos(tc));
var dlng = atan2(sin(tc)*sin(d)*cos(lat1),cos(d)-sin(lat1)*sin(y));
var x = ((lng1-dlng+PI) % (2*PI)) - PI ; // MOD function
var point = new google.maps.LatLng(parseFloat(y*(180/PI)),parseFloat(x*(180/PI)));
circlePoints.push(point);
bounds.extend(point);
if(a==0){
var offset = new google.maps.Size(-5,0); // Added the offset - mile markers look a bit better
var label = new ELabel(point, circleRadius, "style1", offset, 40);
map.addOverlay(label);
}
if (((a==0) || (a==45) || (a==90) || (a==135) || (a==180) || (a==225) || (a==270) || (a==315)) && radials) {
//if (((a==0) || (a==45) || (a==90) || (a==135) || (a==180)) && radials) {
var pline = new google.maps.Polyline([center,point] , liColor, liWidth, liOpa);
map.addOverlay(pline);
}
}
var poly = new google.maps.Polygon(circlePoints, liColor, liWidth, liOpa, fillColor, fillOpa, opts);
map.addOverlay(poly); // Add a target circle to the map
map.setZoom(map.getBoundsZoomLevel(bounds)); // This sets the map bounds to be as big as the target circles, comment out if you don't want it
}
}
Then I have this within the initialize() function for the map.
// You can add circles, or change other parameters
// radials should be set to true for the maximum distance if you want radials
// doDrawCircle(circleUnits, center, circleRadius, lineColor, lineWidth, lineOpacity, fillColor, fillOpacity, opts, radials)
doDrawCircle('MI',llCenter, 62, lcolor, 1, .7, "#FFFF00", 0, { clickable: false }, false);
doDrawCircle('MI',llCenter, 124, lcolor, 1, .7, "#FFFF00", 0, { clickable: false }, false);
doDrawCircle('MI',llCenter, 187, lcolor, 1, .7, "#FFFF00", 0, { clickable: false }, false);
doDrawCircle('MI',llCenter, 249, lcolor, 1, .7, "#FFFF00", 0, { clickable: false }, false);
doDrawCircle('MI',llCenter, 312, lcolor, 1, .7, "#FFFF00", 0, { clickable: false }, false);
doDrawCircle('MI',llCenter, 374, lcolor, 1, .7, "#FFFF00", 0, { clickable: false }, false);
// doDrawCircle('MI',llCenter, 374, lcolor, 1, .7, '#00FF00', 0, { clickable: false }, true); // This would add the radials
This is what it is suppose to look like. This is from the working V2 map.
V2 EXAMPLE
Link to full code
FULL MAP CODE
First thing you'll need to do is get the newest version of elabel.js for google maps V3 here:
https://github.com/erunyon/ELabel/blob/master/elabel.js
Then, the good news is you don't need all of that complicated math and stuff which you have going on in your doDrawCircle function. You can now make use of google.maps.Circle as well as the geometry library which must be included via the google maps script tag's url parameters using a 'libraries=geometry' parameter so we can get the text label placement position starting point via google.maps.geometry.spherical.computeOffset. And then I've included a little tweeking of the text placement below to look a bit more tidy.
Test case:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Circles</title>
<style type="text/css">
.style1 {
/* used for range numbers on rings */
color: #FFF;
font-size: 10px;
text-shadow: 2px 2px 2px #000;
font-weight: bold;
font-family: verdana, helvetica, arial, sans-serif;
background-color:black;
}
</style>
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&libraries=geometry"></script>
<!-- elabel.js for google maps V3 from here: https://github.com/erunyon/ELabel/blob/master/elabel.js -->
<script src="elabel.js"></script>
<script>
function initialize() {
var i, meters, options, labelLocation, textLength, textXcenter, label,
//note I declared the actual font pixel size in .style1 css rule
//just to help with visualizing the way I'm positioning the label texts
textPixelSize = 10,
//will need to invert textYcenter as well as textXcenter to negative numbers later
textYcenter = (textPixelSize / 2) + 2, //2px tweak for 'y' position, approximation
mapOptions = {
zoom: 6,
center: new google.maps.LatLng(32.8297,-96.6486),
mapTypeId: google.maps.MapTypeId.HYBRID
},
ranges = [62, 124, 187, 249, 312, 374], //circle radii in miles
circles = [],
labels = [],
map = new google.maps.Map(document.getElementById('map_canvas'), mapOptions);
for (i = 0; i < ranges.length; i++) {
//convert miles to meters:
meters = ranges[i] / 0.00062137;
options = {
strokeColor: '#FF0000',
strokeOpacity: 0.8,
strokeWeight: 1,
fillOpacity: 0,
map: map,
center: mapOptions.center,
radius: meters
};
circles.push(new google.maps.Circle(options));//ta-da! easy circles in V3
//labelLocation will be a google.maps.LatLng object
labelLocation = google.maps.geometry.spherical.computeOffset(mapOptions.center, meters, 0);
textLength = (''+ranges[i]).length;
textXcenter = (textLength * textPixelSize) / 2; //approximation
label = new ELabel({
latlng: labelLocation,
label: ranges[i],
classname: 'style1',
offset: new google.maps.Size(-textXcenter, -textYcenter),//negative will move left and up
opacity: 100,
overlap: true,
clicktarget: false
});
label.setMap(map);
labels.push(label);
}
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
<div id="map_canvas" style="width:780px; height:600px; margin:10px auto;"></div>
</body>
</html>
EDIT:
Here is revised version which allows to toggle visibility of the rings via the 'Range' button. Also removed all the text label positioning adjustment math and replaced with using style classes for different length texts instead (makes it easier to just use em units in the styles if desired). Added LabelCircle constructor for easier encapsulation and simultaneous control of circles & labels.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Circles</title>
<style type="text/css">
.style1 {
/*used for range numbers on rings*/
color: #FFF;
font-size: .6em;
text-shadow: 2px 2px 2px #000;
font-weight: bold;
font-family: verdana, helvetica, arial, sans-serif;
background-color:black;
margin-top: -0.5em;
}
.d2 { /*two-digit numbers on rings*/
margin-left: -1em;
}
.d3 { /*three-digit numbers on rings*/
margin-left: -1.5em;
}
/*direct copy of your existing .button style rule*/
.button{
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
text-align: center;
position: relative;
font-family: Arial, sans-serif;
font-size: 13px;
font-weight:bold;
box-shadow: rgba(0, 0, 0, 0.4) 0 2px 4px;
-moz-box-shadow: rgba(0, 0, 0, 0.4) 0 2px 4px;
-webkit-box-shadow: rgba(0, 0, 0, 0.4) 0 2px 4px;
color: #000;
border: 1px solid #717B87;
background-color: #fff;
margin: 5px;
padding: 1px 6px;
overflow: hidden;
}
</style>
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&libraries=geometry"></script>
<!-- elabel.js for google maps V3 from here: https://github.com/erunyon/ELabel/blob/master/elabel.js -->
<script src="elabel.js"></script>
<script>
function LabelCircle(options) {
this.circle = new google.maps.Circle(options.circleOptions);
this.label = new ELabel(options.labelOptions);
this.label.setMap(options.circleOptions.map);
this.isVisible = true;
}
LabelCircle.prototype.setVisible = function (bool) {
var method = (bool) ? 'show' : 'hide';
this.circle.setVisible(bool);
this.label[method]();
this.isVisible = bool;
};
//a direct copy of your existing function
function buttonControl(options) {
var control = document.createElement('DIV');
control.innerHTML = options.name;
control.className = 'button';
control.index = 1;
// Add the control to the map
options.gmap.controls[options.position].push(control);
google.maps.event.addDomListener(control, 'click', options.action);
return control;
}
function initialize() {
var i, meters, options, labelLocation, textLength, label,
mapOptions = {
zoom: 6,
center: new google.maps.LatLng(32.8297,-96.6486),
mapTypeId: google.maps.MapTypeId.HYBRID
},
ranges = [62, 124, 187, 249, 312, 374], //circle radii in miles
labelCircles = [],
map = new google.maps.Map(document.getElementById('map_canvas'), mapOptions);
for (i = 0; i < ranges.length; i++) {
//convert miles to meters:
meters = ranges[i] / 0.00062137;
//labelLocation will be a google.maps.LatLng object
labelLocation = google.maps.geometry.spherical.computeOffset(mapOptions.center, meters, 0);
//we'll use textLength below to add a class to the label
textLength = (''+ranges[i]).length;
options = {
circleOptions: {
strokeColor: '#FF0000',
strokeOpacity: 0.8,
strokeWeight: 1,
fillColor: 'transparent',
fillOpacity: 0,
map: map,
center: mapOptions.center,
radius: meters
},
labelOptions: {
latlng: labelLocation,
label: ranges[i],
classname: 'style1 d' + textLength,
//offset: //no longer needed, using style classes
opacity: 100,
overlap: true,
clicktarget: false
}
};
labelCircles.push(new LabelCircle(options));
}
var rangeOptions = {
gmap: map,
name: 'Range',
position: google.maps.ControlPosition.TOP_RIGHT,
action: function(){
for (var tmp, i = 0; i < labelCircles.length; i++) {
tmp = labelCircles[i];
tmp.setVisible(!tmp.isVisible);
}
}
};
var rangeButton = buttonControl(rangeOptions);
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
<div id="map_canvas" style="width:780px; height:600px; margin:10px auto;"></div>
</body>
</html>

Categories