map.on('click') coordinates wrong in Firefox - openlayers-3

I am using OpenLayers 3.10.1 and the following code:
map.on('click', function (map, evt) {
var mouseCoords = [evt.originalEvent.offsetX, evt.originalEvent.offsetY];
alert(mouseCoords);
});
When I click as near as I can to the upper left corner of the map in IE or Chrome, I get an alert with the mouse coordinates offset from the top left corner of the map div, i.e. something sensible like [3,4].
But when I try the same things I get the mouse coordinates relative to the browser window and not the map div. Does anyone know why this is? Am I using an outdated way to find the mouse coordinates (ultimately so I can calculate which feature was clicked)?

Some alternatives:
map.on('click', function(evt){
console.info(evt.pixel);
console.info(map.getPixelFromCoordinate(evt.coordinate));
});

The following code works for me (openlayer 4.4, angular 4+)
_initMap() {
console.info("_initMap");
this.mapW = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
target: 'myMapDiv',
controls: ol.control.defaults({
attributionOptions: /** #type {olx.control.AttributionOptions} */ ({
collapsible: false
})
}),
view: new ol.View({
center: ol.proj.fromLonLat([this.lon, this.lat]);,
zoom: 12
})
});
const theMap = this.mapW;
// display on click
this.mapW.on('click', function(evt) {
/* // you want to detect feature click
var feature = theMap.forEachFeatureAtPixel(evt.pixel,
function(feature, layer) {
return feature;
});
if (feature) {
var fname = feature.getProperties().name;
console.info("feature clicked:" + fname);
return;
}
*/
console.info(evt.coordinate);
console.info(ol.proj.toLonLat(evt.coordinate)); // <=== coordinate projection
});
JS console results (when clicking close to Grenoble in France):
(2) [637000.3050167585, 5652336.68427412]
(2) [5.722271099853512, 45.19540527485873]

Related

How to make created Draw visible before mouse is moving

Is there a way to enfore a just created Draw interaction to visualize itself before the first mousemouse event?
I use openlayers 4.6.5. The application creates an ol.interaction.Draw in response to a keyboard event. The type is a LineString.
After the first mousemove the expected circle is shown at the mouse position.
My problem is that the Draw interaction does not visualize anything until the first mouse move by the user.
Interactions are driven by mouse events so you will need to re-run the last event.
Add a listener for pointermove events to your map and save the last one
var lastEvent;
map.on('pointermove', function(event){ lastEvent = event; });
then when you add the interaction get it to handle the last event
map.addInteraction(draw);
draw.handleEvent(lastEvent);
Version 4.6.4 works for me. An interaction is added by after 5 seconds, then removed and new interaction added at 5 and 10 seconds intervals:
var raster = new ol.layer.Tile({
source: new ol.source.OSM()
});
var source = new ol.source.Vector();
var vector = new ol.layer.Vector({
source: source
});
var map = new ol.Map({
layers: [raster, vector],
target: 'map',
view: new ol.View({
center: [-11000000, 4600000],
zoom: 4
})
});
var draw; // global so we can remove it later
function addInteraction() {
draw = new ol.interaction.Draw({
source: source,
type: 'LineString'
});
map.addInteraction(draw);
}
var lastEvent;
map.on('pointermove', function(event){ lastEvent = event; });
var add = false;
setInterval(function(){
add = !add;
if (add) {
addInteraction();
draw.handleEvent(lastEvent);
} else {
map.removeInteraction(draw);
}
}, 5000);
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/openlayers/4.6.4/ol.css" type="text/css">
<!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/openlayers/4.6.4/ol.js"></script>
<div id="map" class="map"></div>

Openlayers map with marker and fullscreen control

I am using OpenLayers 3.5.0 to embed a map in my website, and place a marker overlay at specific coordinates. I've also added a fullscreen control. Both work individually, but in full-screen mode the marker is no longer at the specified coordinates. It also moves around when panning instead of staying fixed to one map position.
Here's the code that sets up the map:
function map(lon, lat) {
var coords = ol.proj.fromLonLat([lon, lat], 'EPSG:3857');
var layer = new ol.layer.Tile({
source: new ol.source.OSM()
});
var map = new ol.Map({
controls: ol.control.defaults().extend([
new ol.control.FullScreen()
]),
layers: [ layer ],
target: 'map',
view: new ol.View({
maxZoom: 19,
zoom: 15,
center: coords
}),
interactions: ol.interaction.defaults({mouseWheelZoom:false})
});
map.addOverlay(new ol.Overlay({
position: coords,
positioning: 'bottom-center',
element: $('<img>')
.addClass('location-popover')
.attr('src', 'pin.jpg')
}));
}
Is there a way I can make the overlay play nicely in full-screen mode?
I had a similar issue with the popovers/markers being in the wrong position. Not sure if it's the same thing you're experiencing but in my case I was appending data to the page along with the markers, and this was adding a scrollbar to the window. This affected the positioning, so what I had to do was call
map.updateSize();
after I was done adding everything. After that everything lined up correctly.

Re sizing the box based on open layers 3 map zoom

I am new to open layer 3 api's, I have a query : I have marked some locations and custom info window , which opens up on click of these markers. Please find fiddle here
var map = new ol.Map({
target: 'map',
view: new ol.View({
center: ol.proj.fromLonLat([78, 21]),
zoom: 2
}),
layers: [
new ol.layer.Tile({
source: new ol.source.MapQuest({
layer: 'osm'
})
})]
});
Is it possible do re-size the boxes when map is zommed in and out using mouse wheel. I plan to have many more cities marked , and boxes to be drawn on click of each marker and these boxes should be opened by default, so it would cover whole map . Can I change box size depending upon zoom level.
And also which layer to set to have map without any detailed information like airports , roads etc . I want map to have basic minimalist layer ,with country boundaries and city names only.
Thanks
You can listen to the view change:resolution event and make the boxes bigger using the zoom level. Here's an example:
var view = new ol.View({
center: ol.proj.fromLonLat([78, 21])
});
var parentZoom = null;
view.on('change:resolution', function() {
var zoom = view.getZoom();
if (parentZoom !== null) {
$('#zoom').text([
'Parent zoom:',
parentZoom,
', Current zoom:',
zoom
].join(' '));
}
var width = 50 + (zoom * 10);
var height = 30 + (zoom * 10);
$('.mapDivs').width(width + 'px').height(height + 'px');
parentZoom = zoom;
}, this);
view.setZoom(2);
See it live on JSFiddle (your example updated with the above code): http://jsfiddle.net/pe7hyr0x/15/

OL3 : Select Image/Marker to drag drop to another coordinate (Visual Issues OpenLayers 3)

I'm testing around with images to show markers on map. Unfortunately I don't understand the concept of selection and drag/drop yet. Here is my example:
http://codepen.io/kaepten/pen/wDhKt
// Create the background layer
var layer = ga.layer.create('ch.swisstopo.pixelkarte-farbe');
// Create a map
var map = new ga.Map({
target: 'map',
layers: [layer],
view: new ol.View2D({
resolution: 1,
center: [600000, 200000]
})
});
// Create a local GeoJson
var myGeoJson = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
600000.0000000001,
200000.00000000006
]
}
},
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
668900.0000000001,
162000.00000000003
]
}
}
]
};
// Define a geojson data source
var source = new ol.source.GeoJSON();
// Read the local geojson
var features = source.readFeatures(myGeoJson);
// Create a vector source and assign the GeoJson features to it
var vectorSource = new ol.source.Vector({
features: features
});
// Create a vector layer using the vector source
var vectorLayer = new ol.layer.Vector({
source: vectorSource
});
// Create a point icon style
var iconStyle = new ol.style.Style({
image: new ol.style.Icon(({
src: '//map.geo.admin.ch/1403704943/img/marker.png',
offset: [1,1],
}))
});
// Apply the style to the vector layer
vectorLayer.setStyle(iconStyle);
// Add the vector layer in the map
map.addLayer(vectorLayer);
var featureOverlay = new ol.FeatureOverlay({
map: map,
image: new ol.style.Icon({src: '//map.geo.admin.ch/1403704943/img/marker.png'})
});
var highlight;
var displayFeatureInfo = function(pixel) {
var feature = map.forEachFeatureAtPixel(pixel, function(feature, layer) {
return feature;
});
if (feature !== highlight) {
if (highlight) {
featureOverlay.removeFeature(highlight);
}
if (feature) {
featureOverlay.addFeature(feature);
}
highlight = feature;
}
};
$(map.getViewport()).on('mousemove', function(evt) {
var pixel = map.getEventPixel(evt.originalEvent);
displayFeatureInfo(pixel);
});
var modify = new ol.interaction.Modify({
features: featureOverlay.getFeatures(),
// the SHIFT key must be pressed to delete vertices, so
// that new vertices can be drawn at the same position
// of existing vertices
deleteCondition: function(event) {
return ol.events.condition.shiftKeyOnly(event) &&
ol.events.condition.singleClick(event);
}
});
map.addInteraction(modify);
As you can see... there is a marker (Image), and it is draggable BUT the visual is not what I like to have:
Question:
- why I get this weird blue circle for selection/dragging the Image? How can I change this visual? In fact, I like to hide the blue selection circle completely, there should be only a Image.
- can I get the selection to drag the Image on the whole Image (and not only on the position of the Image)? The marker now is only dragable, if I select the blue marker that apears, but I like to have a drag on the complete Image-area.
Any hint will be very welcome!
Thanks
For styles, you need to set style at your overlay level and in in your modify interaction. See this demo forked from your own.
For selecting according to your icon shape, I don't have an exact answer: you can play with pixelTolerance for an intermediate solution.
It's seems there is a work in progress on adding drag ability that may be better in particular for your icon shape question

Why is my Google Map in a jQuery UI tab only displaying one tile at the top left corner of the screen?

I have two Google Map API v3 Maps in jQuery tabs. They both display the first time they appear in their tabs, but the initially deselected tab only displays a tile or so at the top left-hand corner.
Calling google.maps.event.trigger(all_map, 'resize') periodically does not change this.
In my code I have:
<div id='all_map_canvas'>
</div>
<script>
function show_all_map()
{
var center = new google.maps.LatLng(%(center_latitude)s - .15, %(center_longitude)s + .2);
var myoptions = {
zoom: %(zoom)s,
center: center,
mapTypeId: google.maps.MapTypeId.TERRAIN
};
all_map = new google.maps.Map(document.getElementById('all_map_canvas'), myoptions);
all_map.setZoom(%(zoom)s);
jQuery('#all_map_canvas').show();
google.maps.event.trigger(all_map, 'resize');
}
function show_all_map_markers()
{
%(all_map_markers)s
}
var markers = [];
jQuery('#all_map_canvas').width(jQuery(window).width() - 300);
jQuery('#all_map_canvas').height(jQuery(window).height() - 125);
How can I make both maps display in full after tab swaps?
I had the same problem: Google map in div that has style display:none;.
Solved it with this two steps:
Removing all additional styling of the div I'm placing the map except height:100%;
Initiate the map after the holding div is displayed not when the it is created. In my case in the callback function of the show method:
CSS
.main-window #map{
height:100%;
}
JS
$('.main-window').show(3000, function() {
// create the map after the div is displayed
var mapOptions = {
center: new google.maps.LatLng(42.499591, 27.474961),
zoom: 8,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map"), mapOptions);
});
HTML
<div class="main-window">
<div id="map"></div>
</div>
Initiating it in events like jQuery's '$(document).ready(...' or Google's 'google.maps.event.addDomListener(window, "load", ...' is not working for some reason.
Hope it helps.
I am using gmaps.js which is a simplified api for google map. But it's simply a matter of attaching a tabsshow event in javascript and refreshing the map in the delegate's function.
Here's the code I use for gmaps.js
$('#tabs').bind('tabsshow', function(event, ui) {
event.preventDefault();
if (ui.panel.id == "tabs2") {
//gmaps.js method
map.refresh();
map.setCenter(lastLoc.lat(), lastLoc.lng());
//for native google.maps api
google.maps.event.trigger(map, 'resize');
map.panTo(new google.maps.LatLng(lastLoc.lat(), lastLoc.lng()));
}
});

Resources