Here maps api: Behavior not reacting in Microsoft Web Browser ActiveX - javascript

I tried example in Here maps about draggable Marker:
Draggable Marker | Here
On first try map didn't show in AX2009 Microsoft Web Browser ActiveX. I switched from vector to raster and added engineType: H.map.render.RenderEngine.EngineType.P2The marker in default web browser like IE11, Chrome, edge is working fine, I can drag marker. But in ActiveX on AX2009 the marker isnt dragging, but i can see map istelf like in default web browser. Any ideas what should i add to code? Any help appreciated.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
<script src="https://js.api.here.com/v3/3.1/mapsjs-core.js"></script>
<script src="https://js.api.here.com/v3/3.1/mapsjs-core-legacy.js"></script>
<script src="https://js.api.here.com/v3/3.1/mapsjs-mapevents.js"></script>
<script src="https://js.api.here.com/v3/3.1/mapsjs-service.js"></script>
<script src="https://js.api.here.com/v3/3.1/mapsjs-service-legacy.js"></script>
<script src="https://js.api.here.com/v3/3.1/mapsjs-ui.js"></script>
<link
rel="stylesheet"
type="text/css"
href="https://js.api.here.com/v3/3.1/mapsjs-ui.css"
/>
<title>Simple Map</title>
<style>
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
#map {
height: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
var point = {lat:56.983849, lng:24.237360};
var apikey = "xxx",
platform = new H.service.Platform({
apikey: apikey,
}),
pixelRatio = window.devicePixelRatio || 1,
ppi,
defaultLayers,
mapElement = document.getElementById("map"),
tileSize,
map,
behavior,
ui;
if (pixelRatio > 1) {
ppi = 250;
}
defaultLayers = platform.createDefaultLayers({
ppi: ppi,
});
map = new H.Map(mapElement, defaultLayers.raster.normal.map, {
zoom: 14,
center: point,
renderBaseBackground: { lower: 2, higher: 2 },
pixelRatio: pixelRatio,
engineType: H.map.render.RenderEngine.EngineType.P2D,
});
window.addEventListener("resize", function () {
map.getViewPort().resize();
});
function addDraggableMarker(map, behavior){
var marker = new H.map.Marker(point, {
// mark the object as volatile for the smooth dragging
volatility: true
});
// Ensure that the marker can receive drag events
marker.draggable = true;
map.addObject(marker);
// disable the default draggability of the underlying map
// and calculate the offset between mouse and target's position
// when starting to drag a marker object:
map.addEventListener('dragstart', function(ev) {
var target = ev.target,
pointer = ev.currentPointer;
if (target instanceof H.map.Marker) {
var targetPosition = map.geoToScreen(target.getGeometry());
target['offset'] = new H.math.Point(pointer.viewportX - targetPosition.x, pointer.viewportY - targetPosition.y);
behavior.disable();
}
}, false);
// re-enable the default draggability of the underlying map
// when dragging has completed
map.addEventListener('dragend', function(ev) {
var target = ev.target;
if (target instanceof H.map.Marker) {
behavior.enable();
}
}, false);
// Listen to the drag event and move the position of the marker
// as necessary
map.addEventListener('drag', function(ev) {
var target = ev.target,
pointer = ev.currentPointer;
if (target instanceof H.map.Marker) {
target.setGeometry(map.screenToGeo(pointer.viewportX - target['offset'].x, pointer.viewportY - target['offset'].y));
}
}, false);
}
behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
ui = H.ui.UI.createDefault(map, defaultLayers);
addDraggableMarker(map, behavior);
</script>
</body>
</html>

Related

Extending leaflet SVG renderer fails to show vector layers

I am working on modifying the Leaflet SVG renderer for some cosmetic changes, but I have not been able to get even the most basic extension to work (even without any custom code aside from changing things like create() to L.DomUtil.create()).
here is my most simple example setup:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.6.0/dist/leaflet.css" integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ==" crossorigin=""/>
<script src="https://unpkg.com/leaflet#1.6.0/dist/leaflet.js" integrity="sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew==" crossorigin=""></script>
<style>
body{
padding: 0;
margin: 0;
}
#mapid{
width: 100vw;
height: 100vh;
}
</style>
</head>
<body>
<div id="mapid" style=""></div>
<script>
L.SVG.test = L.SVG.extend({
_initPath: function(layer){
const path = layer._path = L.DomUtil.create('path');
// #namespace Path
// #option className: String = null
// Custom class name set on an element. Only for SVG renderer.
if(layer.options.className){
path.classList.add(...L.Util.splitWords(layer.options.className));
}
if(layer.options.interactive){
path.classList.add('leaflet-interactive');
}
this._updateStyle(layer);
this._layers[L.Util.stamp(layer)] = layer;
},
_updateStyle: function(layer){
const path = layer._path,
options = layer.options;
if(!path){
return;
}
if(options.stroke){
path.setAttribute('stroke', options.color);
path.setAttribute('stroke-opacity', options.opacity);
path.setAttribute('stroke-width', options.weight);
path.setAttribute('stroke-linecap', options.lineCap);
path.setAttribute('stroke-linejoin', options.lineJoin);
if(options.dashArray){
path.setAttribute('stroke-dasharray', options.dashArray);
} else {
path.removeAttribute('stroke-dasharray');
}
if(options.dashOffset){
path.setAttribute('stroke-dashoffset', options.dashOffset);
} else {
path.removeAttribute('stroke-dashoffset');
}
} else {
path.setAttribute('stroke', 'none');
}
if(options.fill){
path.setAttribute('fill', options.fillColor || options.color);
path.setAttribute('fill-opacity', options.fillOpacity);
path.setAttribute('fill-rule', options.fillRule || 'evenodd');
} else {
path.setAttribute('fill', 'none');
}
}
});
var testRenderer = new L.SVG.test();
var map = L.map('mapid', {preferCanvas: false, renderer: testRenderer}).setView([51.505, -0.09], 13);
var tiles = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© OpenStreetMap'
}).addTo(map);
L.marker([51.5, -0.09]).addTo(map)
.bindPopup("<b>Hello world!</b><br />I am a popup.");
L.polygon([
[51.509, -0.08],
[51.503, -0.06],
[51.51, -0.047]
], {fillOpacity: 0.5}).addTo(map).bindPopup("I am a polygon.");
L.circle([51.508, -0.11], 500, {fillOpacity: 0.5}).addTo(map).bindPopup("I am a circle.");
</script>
</body>
</html>
It does not throw any errors in the console and I really don't know where to go from here.
Inspecting the dom shows that the layers exist in the svg tag and that they have coordinates, but the g element does not seem to have any height.
what am I doing wrong?

How to detect overlap in Phaser.js?

I am new to Phaserjs, and I am trying to make a shooting game. I want the damage function to fire when a bullet touches plane2, that is the green plane. Can somone please tell me what am I doing wrong here?
Here is my code:
var config = {
type: Phaser.AUTO,
width: 800,
height: 800,
parent:"game",
physics: {
default: 'arcade',
arcade: {
debugging:true,
gravity: {y: 0}
}
},
scene: {
preload: preload,
create: create,
update: update
}
};
var plane1
var plane2
var hp;
var botHp;
function preload (){
this.load.setBaseURL('https://shoot.abaanshanid.repl.co/assets');
this.load.image("bg", "bg.jpg");
this.load.image("plane1", "plane1.png");
this.load.image("plane2", "plane2.png");
this.load.image("bullet", "bullet.png");
}
function create (){
this.background = this.add.image(400, 400, "bg");
plane1 = this.physics.add.sprite(400,700,"plane1");
plane2 = this.physics.add.sprite(400,100,"plane2");
plane1.enableBody = true;
}
function update(){
keys = this.input.keyboard.createCursorKeys();
if (keys.left.isDown) {
plane1.x = plane1.x - 7.5;
}else if(keys.right.isDown){
plane1.x = plane1.x + 7.5;
}else if(keys.space.isDown){
var bullet = this.physics.add.sprite(plane1.x,600,"bullet");
bullet.enableBody = true;
setInterval(function(){
bullet.y = bullet.y - 25;
},50);
this.physics.overlap(bullet,plane2,this.damage);
}
}
function damage(){
console.log("less HP")
}
var game = new Phaser.Game(config);
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>repl.it</title>
<link href="style.css" rel="stylesheet" type="text/css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/phaser/3.54.0/phaser.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/phaser/3.54.0/phaser-arcade-physics.min.js"></script>
</head>
<body>
<div id="game"></div>
<script defer src="script.js"></script>
</body>
</html>
Here is the link to the game if needed https://shoot.abaanshanid.repl.co/
This works:
this.physics.add.overlap(bullet,plane2,damage);
but its kinda laggy. Id try to destroy bullet on impact and i also found:
this.physics.add.collider(bullet,plane2,damage);

Disable redrawing canvas after screen resize and mobile rotation in PaperJS

The use case is for a Christmas "scratch" card, where the user needs to swipe on the image to reveal the content. When the window is resized or the phone is rotated, the canvas is redrawn. My current code is as follows:
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title>Division Raster</title>
<script type="text/javascript" src="wp-content/themes/generatepress_child/paper-full.min.js"></script>
<script type="text/paperscript" canvas="canvas">
// Based on 'JPEG Raster' by Jonathan Puckey:
// http://www.flickr.com/photos/puckey/3179779686/in/photostream/
// Create a raster item using the image with id='mona'
var raster = new Raster('mona');
// Make the raster invisible:
raster.visible = true;
raster.position = view.center;
var lastPos = view.center;
function moveHandler(event) {
if (lastPos.getDistance(event.point) < 1)
return;
lastPos = event.point;
var size = this.bounds.size.clone();
var isLandscape = size.width > size.height;
// If the path is in landscape orientation, we're going to
// split the path horizontally, otherwise vertically:
size /= isLandscape ? [2, 1] : [1, 2];
if (size.ceil().width > 10) {
var path = new Path.Rectangle({
point: this.bounds.topLeft.floor(),
size: size.ceil(),
onMouseMove: moveHandler
});
path.fillColor = raster.getAverageColor(path);
var path = new Path.Rectangle({
point: isLandscape
? this.bounds.topCenter.ceil()
: this.bounds.leftCenter.ceil(),
size: size.floor(),
onMouseMove: moveHandler
});
path.fillColor = raster.getAverageColor(path);
}
this.remove();
}
function onResize(event) {
project.activeLayer.removeChildren();
// Transform the raster so that it fills the bounding rectangle
// of the view:
raster.fitBounds(view.bounds, true);
// Create a path that fills the view, and fill it with
// the average color of the raster:
new Path.Rectangle({
rectangle: view.bounds,
fillColor: raster.getAverageColor(view.bounds),
onMouseMove: moveHandler
});
}
</script>
<style type="text/css" id="wp-custom-css">
#canvas{
background: center center url(/web.jpg);
width:100%;
height:100vh;
position: absolute;
top:0;
bottom: 0;
left: 0;
right: 0;
margin: 0 auto;
}
#cc{
max-width:2560px;
position: absolute;
top:0;
bottom: 0;
left: 0;
right: 0;
margin: 0 auto;
} </style>
</head>
<body>
<canvas id="canvas" resize></canvas>
<img width="1024" height="1024" id="mona" style="display: none;" src="/web.jpg">
</body>
</html>
Is there any way to fix the initial canvas size so the result of the "scratching" isn't lost?
Your problem resides in the onResize function which is called every time the window is resized and which basically reset your drawing.
The resize attribute on the <canvas> element also is part of the problem as it makes sure that the canvas size is updated every time the window is resized.
In your case, I think that you want to get rid of those.
Here is a fiddle adapted from your code, turning it into a static drawing that doesn't respond to resize events.
<html>
<head>
<meta charset="UTF-8">
<title>Division Raster</title>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/paper.js/0.12.2/paper-full.min.js"></script>
<script type="text/paperscript" canvas="canvas">
// Load image then init.
var raster = new Raster({
source: 'http://assets.paperjs.org/images/marilyn.jpg',
crossOrigin: 'anonymous',
onLoad: init
});
function init() {
// Make image fill the whole canvas.
raster.fitBounds(view.bounds, true);
var lastPos = view.center;
function moveHandler(event) {
if (lastPos.getDistance(event.point) < 1) {
return;
}
lastPos = event.point;
var size = this.bounds.size.clone();
var isLandscape = size.width > size.height;
// If the path is in landscape orientation, we're going to
// split the path horizontally, otherwise vertically:
size /= isLandscape ? [2, 1] : [1, 2];
if (size.ceil().width > 10) {
var path = new Path.Rectangle({
point: this.bounds.topLeft.floor(),
size: size.ceil(),
onMouseMove: moveHandler
});
path.fillColor = raster.getAverageColor(path);
var path = new Path.Rectangle({
point: isLandscape
? this.bounds.topCenter.ceil()
: this.bounds.leftCenter.ceil(),
size: size.floor(),
onMouseMove: moveHandler
});
path.fillColor = raster.getAverageColor(path);
}
this.remove();
}
// Create a path that fills the view, and fill it with
// the average color of the raster:
new Path.Rectangle({
rectangle: view.bounds,
fillColor: raster.getAverageColor(view.bounds),
onMouseMove: moveHandler
});
}
</script>
<style type="text/css">
canvas {
width : 100vw;
height : 100vh;
position : absolute;
top : 0;
left : 0;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
</body>
</html>

How can I grab a selection of markers with Leaflet.draw?

Context:
I've made a map, and populated it with around 300 random markers. I can 'select' the markers by clicking on a link in the popup and activate a selection to display data from. I also have the Leaflet.draw plugin to draw shapes like circles, rectangles and custom shapes, and I would like to use it to 'select' a couple of markers.
The issue
How can I grab the leaflet marker object of the markers that fall inside a drawn leaflet.draw shape so I can edit them? I cannot seem to make a selection, It either selects none of the markers, or all of them.
Code snippet, stripped from unnecessary code:
const drawControl = new L.Control.Draw({
draw: {
marker : false,
polygon : true,
polyline : false,
rectangle: true,
circle : {
metric: 'metric'
}
},
edit: false
});
const map = L.map('map', {
layers: [streets, light]
}).setView([CONFIG.MAP.LATITUDE, CONFIG.MAP.LONGITUDE], CONFIG.MAP.ZOOMLEVEL)
map.addControl(drawControl);
map.on(L.Draw.Event.DRAWSTOP, e => {
const hello = e.target;
console.log(hello);
e.target.eachLayer(layer => {
if (layer.options.icon) {
console.log(layer);
}
});
});
Most of what you want can quite easily be done using Leaflet's utility methods. If you want to do this with a complex shape like L.Polygon you're going to need something like TurfJS
For L.Circle you need to calculate the distance between the circle's center and compare it to the radius:
var marker = new L.Marker(...),
circle = new L.Circle(...);
var contains = circle.getLatLng().distanceTo(marker.getLatLng()) < circle.getRadius();
For L.Rectangle you need to fetch it's bounds object and use the contains method:
var marker = new L.Marker(...),
rectangle = new L.Rectangle(...);
var contains = rectangle.getBounds().contains(marker.getLatLng());
As said for complex polygons i'de use Turf but there are more libraries and plugins out there. Here's an example using Turf's inside method. It take a GeoJSON point and polygon feature as parameters so mind the conversion:
var marker = new L.Marker(...),
polygon = new L.Polygon(...);
var contains = turf.inside(marker.toGeoJSON(), polygon.toGeoJSON());
You could wrap those into convenience methods for each respective class:
L.Polygon.include({
contains: function (latLng) {
return turf.inside(new L.Marker(latLng).toGeoJSON(), this.toGeoJSON());
}
});
L.Rectangle.include({
contains: function (latLng) {
return this.getBounds().contains(latLng);
}
});
L.Circle.include({
contains: function (latLng) {
return this.getLatLng().distanceTo(latLng) < this.getRadius();
}
});
var marker = new L.Marker(...),
polygon = new L.Polygon(...),
rectangle = new L.Rectangle(...),
circle = new L.Circle(...);
polygon.contains(marker.getLatLng());
rectangle.contains(marker.getLatLng());
circle.contains(marker.getLatLng());
Note that if you implement the polygon method that there is no need for the rectangle method. Since rectangle is extended from polygon it will inherit the method. I left it in there to be complete.
Now iterating your markers and comparing them is easy:
map.on(L.Draw.Event.CREATED, function (e) {
markers.eachLayer(function (marker) {
if (!e.layer.contains(marker.getLatLng())) {
marker.remove();
}
});
});
Hope that helps, here's a working snippet:
var map = new L.Map('leaflet', {
'center': [0, 0],
'zoom': 0
});
var markers = new L.LayerGroup().addTo(map);
for (var i = 0; i < 300; i++) {
var marker = new L.Marker([
(Math.random() * (90 - -90) + -90).toFixed(5) * 1,
(Math.random() * (180 - -180) + -180).toFixed(5) * 1
]).addTo(markers);
}
new L.Control.Draw({
draw: {
marker : false,
polygon : true,
polyline : false,
rectangle: true,
circle : {
metric: 'metric'
}
},
edit: false
}).addTo(map);
L.Polygon.include({
contains: function (latLng) {
return turf.inside(new L.Marker(latLng).toGeoJSON(), this.toGeoJSON());
}
});
L.Rectangle.include({
contains: function (latLng) {
return this.getBounds().contains(latLng);
}
});
L.Circle.include({
contains: function (latLng) {
return this.getLatLng().distanceTo(latLng) < this.getRadius();
}
});
map.on(L.Draw.Event.CREATED, function (e) {
markers.eachLayer(function (marker) {
if (!e.layer.contains(marker.getLatLng())) {
marker.remove();
}
});
});
body {
margin: 0;
}
html, body, #leaflet {
height: 100%;
}
<!DOCTYPE html>
<html>
<head>
<title>Leaflet 1.0.3</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link type="text/css" rel="stylesheet" href="//unpkg.com/leaflet#1.0.3/dist/leaflet.css" />
<link type="text/css" rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.9/leaflet.draw.css" />
</head>
<body>
<div id="leaflet"></div>
<script type="application/javascript" src="//unpkg.com/leaflet#1.0.3/dist/leaflet.js"></script>
<script type="application/javascript" src="//cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.9/leaflet.draw.js"></script>
<script type="application/javascript" src="//unpkg.com/#turf/turf#latest/turf.min.js"></script>
</body>
</html>
Thanks #iH8 for the cool example. I went further to avoid some repetition with
markers.eachLayer(function (marker) {
...
}
and extended the wrappers with additionnal methods using arrays of markers instead:
First I noticed that a LayerGroup has an object with key-values containing all the markers. I simply use that object to create an array of markers :
// In the on draw event
...
// Set an array containing all the markers
var markers = jsonToArray(layerGroup._layers);
...
function jsonToArray(jsonObject) {
var result = [];
var keys = Object.keys(jsonObject);
keys.forEach(function (key) {
result.push(jsonObject[key]);
});
return result;
}
I then re-use the wrappers with modified contains() methods :
L.Rectangle.include({
// Single marker case
contains: function (marker) {
return this.getBounds().contains(marker.getLatLng());
},
// Array of markers
contains: function (markers) {
var markersContained = [];
markers.forEach(marker => {
markersContained.push(this.getBounds().contains(marker.getLatLng()));
})
return markersContained;
}
});
L.Circle.include({
contains: function (marker) {
return this.getLatLng().distanceTo(marker.getLatLng()) < this.getRadius();
},
contains: function (markers) {
var markersContained = [];
markers.forEach(marker => {
markersContained.push(this.getLatLng().distanceTo(marker.getLatLng()) < this.getRadius());
})
return markersContained;
}
});
and finally on the draw event, I check whether my markers are contained within or not :
map.on(L.Draw.Event.CREATED, function (geometry) {
// Set an array containing all the markers
var markers = jsonToArray(layerGroup._layers);
var result = geometry.layer.contains(markers);
console.log('result => ', result);
});
function jsonToArray(jsonObject) {
var result = [];
var keys = Object.keys(jsonObject);
keys.forEach(function (key) {
result.push(jsonObject[key]);
});
return result;
}
var map = new L.Map('leaflet', {
'center': [0, 0],
'zoom': 0
});
var layerGroup = new L.LayerGroup().addTo(map);
for (var i = 0; i < 10; i++) {
var marker = new L.Marker([
(Math.random() * (90 - -90) + -90).toFixed(5) * 1,
(Math.random() * (180 - -180) + -180).toFixed(5) * 1
]).addTo(layerGroup);
}
new L.Control.Draw({
draw: {
marker : false,
polygon : false,
polyline : false,
rectangle: true,
circle : {
metric: 'metric'
}
},
edit: false
}).addTo(map);
// Define contains() method for each geometry
L.Rectangle.include({
contains: function (marker) {
return this.getBounds().contains(marker.getLatLng());
},
contains: function (markers) {
var markersContained = [];
markers.forEach(marker => {
markersContained.push(this.getBounds().contains(marker.getLatLng()));
})
return markersContained;
}
});
L.Circle.include({
contains: function (marker) {
return this.getLatLng().distanceTo(marker.getLatLng()) < this.getRadius();
},
contains: function (markers) {
var markersContained = [];
markers.forEach(marker => {
markersContained.push(this.getLatLng().distanceTo(marker.getLatLng()) < this.getRadius());
})
return markersContained;
}
});
map.on(L.Draw.Event.CREATED, function (geometry) {
// Set an array containing all the markers
var markers = jsonToArray(layerGroup._layers);
var result = geometry.layer.contains(markers);
console.log('result => ', result);
});
body {
margin: 0;
}
html, body, #leaflet {
height: 100%;
}
<!DOCTYPE html>
<html>
<head>
<title>Leaflet 1.0.3</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link type="text/css" rel="stylesheet" href="//unpkg.com/leaflet#1.0.3/dist/leaflet.css" />
<link type="text/css" rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.9/leaflet.draw.css" />
</head>
<body>
<div id="leaflet"></div>
<script type="application/javascript" src="//unpkg.com/leaflet#1.0.3/dist/leaflet.js"></script>
<script type="application/javascript" src="//cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.9/leaflet.draw.js"></script>
</body>
</html>
I used it:
L.Circle.include({
contains: function (latLng) {
return this.getLatLng().distanceTo(latLng) < this.getRadius();
}
});
Points that are on the edge but not in the circle are also judged.

Prevent google overlay/infowindow from allowing clicks through to markers underneath

I'm trying to make some custom Google maps info windows, but I'm getting the issue where markers underneath my custom info window is clickable through the info window.
Here's an example (basically straight from googles example here)
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<title>Google Maps JavaScript API v3 Example: Info Window Custom</title>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript">
/* An InfoBox is like an info window, but it displays
* under the marker, opens quicker, and has flexible styling.
* #param {GLatLng} latlng Point to place bar at
* #param {Map} map The map on which to display this InfoBox.
* #param {Object} opts Passes configuration options - content,
* offsetVertical, offsetHorizontal, className, height, width
*/
function InfoBox(opts) {
google.maps.OverlayView.call(this);
this.latlng_ = opts.latlng;
this.map_ = opts.map;
this.offsetVertical_ = -195;
this.offsetHorizontal_ = 0;
this.height_ = 165;
this.width_ = 266;
var me = this;
this.boundsChangedListener_ =
google.maps.event.addListener(this.map_, "bounds_changed", function() {
return me.panMap.apply(me);
});
// Once the properties of this OverlayView are initialized, set its map so
// that we can display it. This will trigger calls to panes_changed and
// draw.
this.setMap(this.map_);
}
/* InfoBox extends GOverlay class from the Google Maps API
*/
InfoBox.prototype = new google.maps.OverlayView();
/* Creates the DIV representing this InfoBox
*/
InfoBox.prototype.remove = function() {
if (this.div_) {
this.div_.parentNode.removeChild(this.div_);
this.div_ = null;
}
};
/* Redraw the Bar based on the current projection and zoom level
*/
InfoBox.prototype.draw = function() {
// Creates the element if it doesn't exist already.
this.createElement();
if (!this.div_) return;
// Calculate the DIV coordinates of two opposite corners of our bounds to
// get the size and position of our Bar
var pixPosition = this.getProjection().fromLatLngToDivPixel(this.latlng_);
if (!pixPosition) return;
// Now position our DIV based on the DIV coordinates of our bounds
this.div_.style.width = this.width_ + "px";
this.div_.style.left = (pixPosition.x + this.offsetHorizontal_) + "px";
this.div_.style.height = this.height_ + "px";
this.div_.style.top = (pixPosition.y + this.offsetVertical_) + "px";
this.div_.style.display = 'block';
};
/* Creates the DIV representing this InfoBox in the floatPane. If the panes
* object, retrieved by calling getPanes, is null, remove the element from the
* DOM. If the div exists, but its parent is not the floatPane, move the div
* to the new pane.
* Called from within draw. Alternatively, this can be called specifically on
* a panes_changed event.
*/
InfoBox.prototype.createElement = function() {
var panes = this.getPanes();
var div = this.div_;
if (!div) {
// This does not handle changing panes. You can set the map to be null and
// then reset the map to move the div.
div = this.div_ = document.createElement("div");
div.style.border = "0px none";
div.style.position = "absolute";
div.style.background = "url('http://gmaps-samples.googlecode.com/svn/trunk/images/blueinfowindow.gif')";
div.style.width = this.width_ + "px";
div.style.height = this.height_ + "px";
var contentDiv = document.createElement("div");
contentDiv.style.padding = "30px"
contentDiv.innerHTML = "<b>Hello World!</b>";
var topDiv = document.createElement("div");
topDiv.style.textAlign = "right";
var closeImg = document.createElement("img");
closeImg.style.width = "32px";
closeImg.style.height = "32px";
closeImg.style.cursor = "pointer";
closeImg.src = "http://gmaps-samples.googlecode.com/svn/trunk/images/closebigger.gif";
topDiv.appendChild(closeImg);
function removeInfoBox(ib) {
return function() {
ib.setMap(null);
};
}
google.maps.event.addDomListener(closeImg, 'click', removeInfoBox(this));
div.appendChild(topDiv);
div.appendChild(contentDiv);
div.style.display = 'none';
panes.floatPane.appendChild(div);
this.panMap();
} else if (div.parentNode != panes.floatPane) {
// The panes have changed. Move the div.
div.parentNode.removeChild(div);
panes.floatPane.appendChild(div);
} else {
// The panes have not changed, so no need to create or move the div.
}
}
/* Pan the map to fit the InfoBox.
*/
InfoBox.prototype.panMap = function() {
};
function initialize() {
var myOptions = {
zoom: 8,
center: new google.maps.LatLng(-33.397, 150.644),
mapTypeId: google.maps.MapTypeId.ROADMAP,
sensor: 'true'
}
var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
var marker = new google.maps.Marker({
position: new google.maps.LatLng(-34, 150),
map: map
});
google.maps.event.addListener(marker, "click", function(e) {
var infoBox = new InfoBox({latlng: marker.getPosition(), map: map});
});
var m2 = new google.maps.Marker({
position: new google.maps.LatLng(-33.5, 150.5),
map: map
});
google.maps.event.addListener(m2, "click", function(e) {
var infoBox = new InfoBox({latlng: m2.getPosition(), map: map});
});
}
</script>
</head>
<body style="margin:0px; padding:0px;" onload="initialize()">
<div id="map_canvas" style="width:100%; height:100%"></div>
</body>
</html>
You can see I'm making two markers, one just to the north east of the other. Click the bottom one then observe how the other marker is clickable through the marker (right near the 'W').
How can I fix this?! I've tried altering the z-index but that didn't seem to help.
This is using api v3 btw.
For posterity, you want to disable a bunch of events on the marker pop-up dom, this was the prescribed method, even though it feels like overkill. You could alternatively cycle through all the markers present apart from the one clicked and disable clicking on them (actually that's probably a better solution in hindsight). Depends on how many markers you have perhaps, I had a lot.
Something like this (transcribed here without testing from my coffeescript so...)
// All in a google.maps.OverlayView subclass.
...
this.listeners = new Array(); // save listeners for unbinding later
...
this.cancelEvents = function(){
events = ['mousedown', 'mousemove', 'mouseover',
'mouseout', 'mouseup', 'mousewheel',
'DOMMouseScroll', 'touchstart', 'touchend',
'touchmove', 'dblclick', 'contextmenu'];
// Note, don't disable 'click' if you want to be able to click links in the dom. Some things we're disabling here will can effect how your user might interact with the popup (double click to select text etc)
for(var i = 0; i < events.length; i++){
var event = events[i];
this.listeners.push(
google.maps.event.addDomListener(
this.popup_dom_element,
event,
function(ev){
e.cancelBubble = true;
if(e.stopPropagation){
e.stopPropagation();
}
}
);
);
}
}
this.onAdd = function (){
// build your html popup
var html_code = "...";
// easy way to get a dom element but probably over kill if its your only JQ
this.popup_dom_element = $(html_code);
this.cancelEvents();
}
this.onRemove = function(){
// any other removal code you have
...
for(var i = 0; i < this.listeners.length; i++){
// remove our event listeners
google.maps.event.removeListener(this.listeners[i]);
}
}
Try and use the MapPane overlayMouseTarget instead of floatPane.
If you don't want people to be able to click on a marker, could you call marker.setClickable(false)
i had the same problem and its actually very easy:/
if u are using jquery just set
$(div).bind("click",function(e) {
return false;
});
in the InfoBox.prototype.createElement function. This should help.
Cheers
use:
google.maps.event.addDomListener
instead of
google.maps.event.addListener

Categories