GoogleMaps API V3: Mouse hot spot area of marker is shifted - marker

I'm trying to create a googlemap which contains a marker with an individual image instead of the standard google pin. The image is a 14 by 14 pixel GIF. By clicking on the image, a small information window shall appear.
Both the GIF and the HTML file are stored in a local directory.
My code works fine, except one thing: The "hot spot" area, that is clickable with the mouse, isn't lying on the GIF itself. Instead, it is a square that is located just left above the GIF - the lower right corner of the hot spot area is at the upper left corner of the GIF. So if I want the infowindow to appear, I have to click left above the GIF, not on the GIF.
I haven't seen this effect on my V2-map. I already was fooling around with the parameters size, origin and anchor of the image object, but to no avail. The anchor parameter just shifts the location of the image, but it also shifts the clickable area. The size parameter has only an effect if it is smaller than the GIF itself; then it cuts the edges of the GIF. Also the origin parameter lets the GIF just look funny.
Any ideas that might help? Here's the code I use:
<!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>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>GMaps V3</title>
<style type="text/css" media="screen">
* { FONT-FAMILY: Arial,sans-serif; FONT-SIZE: 12px; margin: 0.2em; }
</style>
<script src="https://maps.googleapis.com/maps/api/js?v=3&sensor=false&key=" type="text/javascript" ></script>
<script type="text/javascript">
//<![CDATA[
function load() {
var center_of_map = new google.maps.LatLng(50.0, 11.0);
var marker_pos = new google.maps.LatLng(50.03, 10.98);
var mapOptions = { zoom: 10, center: center_of_map };
var map = new google.maps.Map(document.getElementById("map"), mapOptions);
var image = {
url: 'bridge.gif',
size: new google.maps.Size(14, 14),
origin: new google.maps.Point(0,0),
anchor: new google.maps.Point(0, 0)
}
var markerProperties = {
map: map,
title: "Click me!",
icon: image,
position: marker_pos
};
var marker = new google.maps.Marker(markerProperties);
var myInfo = new google.maps.InfoWindow(
{ content: "This is an information window" }
);
google.maps.event.addListener(
marker, 'click', function() {
myInfo.open(map, marker);
}
);
} //load
//]]>
</script>
</head>
<body onload="load()">
<table border="1">
<tr><td><b>This is our map</b></td></tr>
<tr><td><div id="map" style="width: 400px; height: 300px"></div></td><tr>
</table>
</body>
</html>

Okay, it seems that it has something to do with the included style. If I comment out the lines, the effect is no longer visible and everything is as it should be. Funny!

I had the same problem. The fix in my case was to add a class to the body as such:
body.no-zoom {
zoom: 1;
}
However, in my case the map was a direct child div node of the body.
<body class="no-zoom">
<div id="map-canvas">
</div>
</body>

Related

How to get data out of a popup on a map with a feature layer from ArcGIS-api for javascript and reuse that data?

I am using a map with feature layers from ArcGIS and the popup to see some data when the user click on a symbol (feature). Is there a way to style the popups exactly the way we want ? In other words, how could I get the data out of the popup, not display the popup but open a modal with that data instead ? Is that even possible ?
This are actually two questions, can you style the popup?, and can you use your own "popup"?.
For the first one, I would say it is pretty customizable, but obviously it depends what you need.
For the second, you just need to stop the default behavior of the view popup, that is to open on right click, and then catch the event yourself to do what you want. Here is an example I made for you that shows that,
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no" />
<title>PopupTemplate - Auto Open False</title>
<link rel="stylesheet" href="https://js.arcgis.com/4.21/esri/themes/light/main.css" />
<script src="https://js.arcgis.com/4.21/"></script>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 500px;
width: 100%;
}
#features {
margin: 20px;
height: 500px;
width: 100%;
overflow: auto;
}
</style>
<script>
var populationChange;
require(["esri/Map", "esri/views/MapView", "esri/layers/Layer"], function (
Map,
MapView,
Layer
) {
const map = new Map({
basemap: "dark-gray"
});
const view = new MapView({
container: "viewDiv",
map: map,
zoom: 7,
center: [-87, 34]
});
Layer.fromPortalItem({
portalItem: {
id: "e8f85b4982a24210b9c8aa20ba4e1bf7"
}
}).then(function (layer) {
map.add(layer);
view.popup.autoOpenEnabled = false; // <- disable view popup auto open
view.on("click", function (event) { // <- listen to view click event
if (event.button === 0) { // <- check that was left button or touch
view.whenLayerView(layer).then(function (layerView) {
const query = layerView.layer.createQuery();
query.geometry = view.toMap(event);
query.distance = 1;
query.units = "meters";
layerView.queryFeatures(query).then(
response => {
document.getElementById("features").innerText = JSON.stringify(response.features);
console.error(response);
},
err => {
document.getElementById("features").innerText = "Query returns an error, check console to see what happen!.";
console.error(err);
}
);
});
}
});
});
});
</script>
</head>
<body>
<div id="viewDiv"></div>
<div id="features"></div>
</body>
</html>

arcGIS 4.18 locate widget custom icon

I have to change the default icon on the Locate widget on arcGIS 4.18. The default icon class is, esri-icon-locate how can I change it to the class, 'esri-icon-navigation'?
I am going through the documentation,
https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Locate.html#iconClass
I have tried to use the property, 'iconClass'. But not reflecting in the map icon. Please find the code below,
var locateBtn = new Locate({
view: view,
// iconClass: '\ue666'
iconClass: 'esri-icon-navigation'
});
view.ui.add(locateBtn, {
position: "manual",
});
KER,
You actually right, does not work as expected. Setting iconClass should be the solution.
Funny fact if you check the default iconClass is actually esri-icon-north-navigation, which obviously in not.
Anyway, I am gonna give a dirty solution, just overlap the class you want,
view.when(_ => {
const n = document.getElementsByClassName("esri-icon-locate");
if (n && n.length === 1) {
n[0].classList += " esri-icon-navigation"
}
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no" />
<title>Locate button | Sample | ArcGIS API for JavaScript 4.18</title>
<link rel="stylesheet" href="https://js.arcgis.com/4.18/esri/themes/light/main.css" />
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<script src="https://js.arcgis.com/4.18/"></script>
<script>
require([
"esri/Map",
"esri/views/MapView",
"esri/widgets/Locate"
], function (Map, MapView, Locate) {
var map = new Map({
basemap: "topo-vector"
});
var view = new MapView({
container: "viewDiv",
map: map,
center: [-56.049, 38.485, 78],
zoom: 3
});
var locateBtn = new Locate({
view: view
});
// Add the locate widget to the top left corner of the view
view.ui.add(locateBtn, {
position: "top-left"
});
view.when(_ => {
const n = document.getElementsByClassName("esri-icon-locate");
if (n && n.length === 1) {
n[0].classList += " esri-icon-navigation"
}
});
});
</script>
</head>
<body>
<div id="viewDiv"></div>
</body>
</html>

Limit map area/zoom in arcGIS SceneView

I'm using arcGIS SceneView in local viewing mode to display a WebMap. I'm trying to constrain the zoom level and bounds of an area so that the user can only see the US, Hawaii, and Alaska and cannot pan outside of this. I also need to constrain the zoom level because if the user zooms out too far the over-zoom the map and see untiled/unmapped space.
Are there any potential solves for this? I first thought that using the constraints property might solve it, but it appears the properties that can be fed to this are quite limited:
https://developers.arcgis.com/javascript/latest/api-reference/esri-views-SceneView.html#constraints
One way to achieve what I think you want is:
listen to view property changes,
check constraints,
act accordingly.
Take a look a the example I made for you. In it, I wait for the view to stop updating (updating property), then I check the constraints. If it is out of scale or out of the extent I reset the view. You probably want another action, I just made it simple.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<title>
View constraints
</title>
<link rel="stylesheet" href="https://js.arcgis.com/4.17/esri/themes/light/main.css" />
<script src="https://js.arcgis.com/4.17/"></script>
<script>
require([
"esri/Map",
"esri/views/SceneView",
"esri/geometry/Extent"
], function (Map, SceneView, Extent) {
const extent = Extent.fromJSON(
{
"spatialReference": {
"latestWkid":3857,
"wkid":102100
},
"xmin":-13119716.983985346,
"ymin":4024337.3961656773,
"xmax":-13096023.097830579,
"ymax":4030581.302795334
}
);
const MIN_SCALE = 12000;
const MAX_SCALE = 48000;
const map = new Map({
basemap: "topo-vector",
ground: "world-elevation"
});
const view = new SceneView({
container: "viewDiv",
map: map,
viewingMode: "local",
center: [-117.75, 33.99],
scale: 24000
});
function resetView() {
console.log('reset');
view.goTo(
{
center:[-117.75, 33.99],
scale: 24000
}
);
}
view.watch("updating", function (value) {
if (!value) {
if (
// out of scale
view.scale < MIN_SCALE ||
view.scale > MAX_SCALE ||
// out of extent
view.extent.xmin < extent.xmin ||
extent.xmax < view.extent.xmax ||
view.extent.ymin < extent.ymin ||
extent.ymax < view.extent.ymax
) {
resetView();
};
}
});
});
</script>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<div id="viewDiv"></div>
</body>
</html>

How to get the coordinates of point where I clicked while using Select interaction?

We use Vue.js and OpenLayers (4.6.5) in our web project. We have a lot of features on the map and some of them are polygons. When I select some particular polygon, its style turns to another color, which means it's highlighted (selected). Of course, I can get the coordinates of selected polygon. But, how can I get the coordinates of point inside that polygon where I clicked?
The code look as following:
markObject (mark) {
if (!mark) {
this.map.un('select', this.onMarkObject)
if (this.markSelection) {
this.markSelection.getFeatures().remove(this.lastSelectedFeature)
this.map.removeInteraction(this.markSelection)
}
return
}
if (!this.markSelection) {
this.markSelection = new Select({
condition: condition.click,
layers: [this.vectorLayer]
})
this.markSelection.on('select', this.onMarkObject)
}
this.map.addInteraction(this.markSelection)
},
onMarkObject (event) {
if (event.selected && event.selected.length > 0) {
const coordinates = event.selected[0].getGeometry().getCoordinates()
}
}
Actually, I've found the solution:
onMarkObject (event) {
const clickCoordinates = event.mapBrowserEvent.coordinate
...
}
Thank you anyway.
What you need is to capture the click event on the map, and then transform pixel to map coordinates, take a look at this example I made for you,
<!doctype html>
<html lang="en">
<head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.1.1/css/ol.css" type="text/css">
<style>
.map {
height: 400px;
width: 100%;
}
#a { display: none; }
</style>
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.1.1/build/ol.js"></script>
<title>Click Pixel Coord</title>
</head>
<body>
<h2>Click on Map to get pixel and coord values</h2>
<p id="p"></p>
<div id="map" class="map"></div>
<script type="text/javascript">
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
view: new ol.View({
center: ol.proj.fromLonLat([37.41, 8.82]),
zoom: 4
})
});
map.on('click', function(evt) {
const coord = map.getCoordinateFromPixel(evt.pixel);
document.getElementById('p').innerHTML =
`Pixel:${evt.pixel[0]} ${evt.pixel[0]}` + '<br>' +
`Coord:${coord[0].toFixed(2)} ${coord[1].toFixed(2)}`;
});
</script>
</body>
</html>

How to open popup at (lng,lat) position in arcgis 4.0

Let's consider this code from the reference (https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Popup.html#open):
view.on("click", function(evt){
view.popup.open({
location: evt.mapPoint, // location of the click on the view
title: "Some title",
});
This works. But how to open a popup at the point, specified by predefined lng,lat coords?
First try:
var point = new Point({latitude:lat,longitude:lng});
view.popup.open({
location: point,
title: "Some title"
});
This does not work. The reason is that created point currently disconnected from map view. Is there a way to receive screen coords (x,y) of the current view by specified (lng,lat)? In google maps api there're methods like latLngToDivPixel, latLngToDivPoint, so what argis offers for this task?
Looks like you're having a SpatialReference issue. Since you're creating the point via lat/lng, it's not in WebMercator, so when you add it to the map it's going to the wrong place. Here's a fixed code for you:
// this works, but needs to be in webmercator:
// var point = new Point({x:-9035831.315416021, y:3095345.196351918});
// as an alternative you can translate to webmercator on the fly:
var point = webMercatorUtils.geographicToWebMercator(new Point({latitude:28.526622,longitude:-81.914063}));
view.popup.open({
location: point,
title: "Some title"
});
Here is the above code in an example.
The answer/issue above was correct for version 4.0 and 4.1.
However, for the newly released version 4.2, this has been simplified. Popup.location now automatically converts WGS84 (latitude, longitude) points to web mercator when map is in web mercator projection.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<meta name="description" content="[Define custom Popup actions - 4.2]">
<!--
ArcGIS API for JavaScript, https://js.arcgis.com
For more information about the popup-actions sample, read the original sample description at developers.arcgis.com.
https://developers.arcgis.com/javascript/latest/popup-actions/index.html
-->
<title>Define custom Popup actions - 4.2</title>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<link rel="stylesheet" href="https://js.arcgis.com/4.2/esri/css/main.css">
<script src="https://js.arcgis.com/4.2/"></script>
<script>
require([
"esri/Map",
"esri/views/MapView",
"esri/geometry/Point",
"dojo/domReady!"
], function(
Map,
MapView,
Point
) {
// Create the Map
var map = new Map({
basemap: "topo"
});
// Create the MapView
var view = new MapView({
container: "viewDiv",
map: map,
center: [-117, 34],
zoom: 9
});
view.then(function() {
var peak = new Point({
latitude: 34.09916,
longitude: -116.82485
});
view.popup.open({
location: peak,
title: "San Gorgonio Mountain",
content: "Tallest peak in Southern California"
});
});
});
</script>
</head>
<body>
<div id="viewDiv"></div>
</body>
</html>
https://jsbin.com/heqotom/edit?html,output