Leaflet map in modal - leaflet

I have this modal in my index.html:
<div id="myModal" class="modal">
<span class="close1">×</span>
<div id="mapImage1"></div>
<div id="caption"></div>
</div>
The <div id="mapImage1"> is the leaflet map <div>
Then I have the function, which should load the Leaflet map into the modal. The parameter image is the image which I would like to show on the leaflet map.
function modalImage(modal,image,modalDiv,text,close) {
// Get the modal
var modal = document.getElementById(modal);
var img = document.getElementById(image);
var modalDiv = document.getElementById(modalDiv);
console.log(modalDiv);
var captionText = document.getElementById(text);
img.onclick = function () {
modal.style.display = "block";
initLeafletimage(modalDiv,img);
captionText.innerHTML = this.alt;
}
// Get the <span> element that closes the modal
var span = document.getElementsByClassName(close)[0];
// When the user clicks on <span> (x), close the modal
span.onclick = function () {
modal.style.display = "none";
}
}
The map itself is generated by this code:
function initLeafletimage(map,image){
console.log(image.src)
var imgDimensions={width:300, height:300} //this is the height and width of the image. It hasn't been loaded yet.
var map = L.map(map, {
maxZoom: 24,
minZoom: -24,
crs: L.CRS.Simple
}).setView([imgDimensions.height/2, imgDimensions.width/2], 0);
var imageUrl = image.src;
var imageBounds = [
[imgDimensions.width , 0],
[0, imgDimensions.height]
];
L.imageOverlay(imageUrl, imageBounds).addTo(map);
}
modalImage('myModal','left','mapImage1','caption','close1');
The map is not even showing up in the modal.
What have I missed?

Unfortunately, like #ghybs pointed out, I missed to define the height and width of the map div. That is why no map was present. With this css it works perfectly:
#mapImage1{
height: 100%;
width: 100%;
position: fixed;
}

Related

How can I pass a dynamic height to Leaflet CRS map in my Ionic 3 App?

I am using Leaflet to render a floor plan map on my page. I am able to render my image, but because a user can upload any size of map, I need to be able to account for that.
I am capturing the height/width when the image is uploaded, but not sure how to pass that to my view.
I am trying this (without much luck):
<div #map id="map" ng-style="{'height' : '{{ myObject.mapHeight }}px' }"></div>
mapHeight is available in my .ts file. and I can output it to the view to check that a value is actually coming through. What is the best way to pass the image height to the view?
Here is my .ts file:
map: L.Map = null;
#ViewChild('map') mapContainer: ElementRef;
...
this.map = L.map(this.mapContainer.nativeElement, {
crs: L.CRS.Simple,
});
let geoJson = L.geoJSON(this.geoData, {
style: function (feature) {
return {
weight: 0.8
}
},
onEachFeature: function (feature, layer) {
//
}
}).addTo(this.map);
let bounds: any = [[0, 0], [this.myObject.mapHeight, this.myObject.mapWidth]];
let image: any = L.imageOverlay(this.myObject.mapUrl, bounds).addTo(this.map);
this.map.fitBounds(bounds);
EDIT
If I do this, I can get the height, but watching the logs, it seems this method just runs and runs and runs. I can immagine at some point I'll consume all memory and that's no good.
<div #map id="map" [ngStyle]="getMapStyle()"></div>
.ts
...
getMapStyle() {
console.log('--> getMapStyle called');
console.log('map height: ', this.mapHeight + 'px');
return {
'height': this.myObject.mapHeight + 'px'
};
}
For anyone else trying to do the same, here is what ended up working for me.
.html
<div #map id="map" [style.height.px]="myObject?.mapHeight"></div>

Is there an issue with maxNativeZoom on Tile Layers in Mapboxjs?

I am currently in the process of upgrading from version 2.1.5 to 3.1.1.
I ran into an issue with the maxNativeZoom option on tile layer.
Basically it looks like it is being ignored and the map keeps zooming displaying white tiles.
My expectation would be that the tiles should be autoscaled.
This worked fine in version 2.1.5.
Here are the fiddles:
2.1.5: https://jsfiddle.net/jfwkq0s4/4/
3.1.1: http://jsfiddle.net/dbpfcoqo/6/
Here is the small sample code from the fiddles above:
L.mapbox.accessToken = 'pk.eyJ1IjoidHZibG9tYmVyZyIsImEiOiJjaXZsZmpsMWwwNXBuMnRudmJqNGQyMjJwIn0.842ovgKydac51tg6b9qKbg';
var map = L.mapbox.map('map', null, { maxZoom: 20})
.setView([40, -74.50], 9);
var layer = new L.mapbox.tileLayer('mapbox.streets', { maxNativeZoom: 17, maxZoom: 20 });
map.addLayer(layer);
I am wondering if MapBox/Leaflet changed the way you need to set these values or maybe they are no longer supported in their current version?
The option is still listed in their documentation.
I appreciate any help!
This seems to be a bug in Mapbox.js starting with version 3.0.0 (which uses Leaflet 1.0.1 or 1.0.2 internally).
It is visible on Mapbox.js example page for over zoom tiles: https://www.mapbox.com/mapbox.js/example/v1.0.0/overzoom/
I see that you have already opened an issue on Mapbox.js repository: https://github.com/mapbox/mapbox.js/issues/1250
What seems to happen is that Mapbox correctly freezes the X and Y coordinates of the tile past maxNativeZoom, but not the Z (zoom) value. Therefore it displays totally incorrect tiles, if available.
This bug is specific to Mapbox.js, Leaflet behaves as expected:
var map = L.map('map', {
maxZoom: 20
}).setView([48.86, 2.35], 11);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors',
maxNativeZoom: 11,
maxZoom: 20
}).addTo(map);
var $zoomLevel = document.getElementById("zoomLevel");
map.on('zoomend', showZoomLevel);
showZoomLevel();
function showZoomLevel() {
$zoomLevel.innerHTML = map.getZoom();
}
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.0.2/dist/leaflet.css">
<script src="https://unpkg.com/leaflet#1.0.2/dist/leaflet-src.js"></script>
Zoom level: <span id='zoomLevel'></span>
<div id="map" style="height: 170px"></div>
Here is my fix. I am also going to send this to MapBox. There are two main issues.
The first issue is the minZoom and maxZoom are always being overwritten by the mapbox tile layer setting.
The second issue is the z point was not being set correctly based on the maxNativeZoom.
This seems to work for me. See code example for details.
var customTileLayer = function (url, options) {
var formatPattern = /\.((?:png|jpg)\d*)(?=$|\?)/;
var tileLayerExtend = L.mapbox.TileLayer.extend({
_setTileJSON: function (json) {
//util.strict(json, 'object');
/*We had to create a function for this since util is private in mapbox */
strict(json, 'object');
if (!this.options.format) {
var match = json.tiles[0].match(formatPattern);
if (match) {
this.options.format = match[1];
}
}
var minZoom = this.options.minZoom || json.minzoom || 0;
var maxZoom = this.options.maxZoom || json.maxzoom || 18;
L.extend(this.options, {
tiles: json.tiles,
attribution: this.options.sanitizer(json.attribution),
minZoom: minZoom,
maxZoom: maxZoom,
tms: json.scheme === 'tms',
// bounds: json.bounds && util.lbounds(json.bounds)
/*We had to create a function for this since util is private in mapbox */
bounds: json.bounds && lBounds(json.bounds)
});
this._tilejson = json;
this.redraw();
return this;
},
getTileUrl: function (tilePoint) {
var tiles = this.options.tiles,
index = Math.floor(Math.abs(tilePoint.x + tilePoint.y) % tiles.length),
url = tiles[index];
tilePoint.z = this._getZoomForUrl();
var templated = L.Util.template(url, tilePoint);
if (!templated || !this.options.format) {
return templated;
} else {
return templated.replace(formatPattern,
(L.Browser.retina ? this.scalePrefix : '.') + this.options.format);
}
}
});
return new tileLayerExtend(url, options);
};
var lBounds = function(_) {
return new L.LatLngBounds([[_[1], _[0]], [_[3], _[2]]]);
};
var strict = function (_, type) {
if (typeof _ !== type) {
throw new Error('Invalid argument: ' + type + ' expected');
}
};
L.mapbox.accessToken = 'pk.eyJ1IjoidHZibG9tYmVyZyIsImEiOiJjaXZsZmpsMWwwNXBuMnRudmJqNGQyMjJwIn0.842ovgKydac51tg6b9qKbg';
var map = L.mapbox.map('map', null, { maxZoom: 20})
.setView([40, -74.50], 9);
var layer = new customTileLayer('mapbox.streets', { maxNativeZoom: 17, maxZoom: 20 });
var $zoomLevel = document.getElementById("zoomLevel");
map.addLayer(layer);
$zoomLevel.innerHTML = map.getZoom();
map.on('zoomend', function(e) {
var zoom = e.target.getZoom();
$zoomLevel.innerHTML= zoom;
});
body { margin:0; padding:0; }
#container { position: absolute; top: 0; bottom: 0; width: 100%; height: 100%; }
#map { height: 100%; width:100%; }
<script src="https://api.mapbox.com/mapbox.js/v3.1.1/mapbox.js"></script>
<link href="https://api.mapbox.com/mapbox.js/v3.1.1/mapbox.css" rel="stylesheet" />
<div id="container">
<span id='zoomLevel'></span>
<div id='map'></div>
</div>

How to draw a polyline with initial point in Leaflet

I'm using custom polyline drawer from Leaflet.draw
let polylineDrawer = new L.Draw.Polyline(map, {})
polylineDrawer.enable()
I need to programmatically add starting point to polyline
I've tried calling addVertex of L.Draw.Polyline. Looks like it's doesn't work with custom polyline drawer cause of addHooks or something... Tried to change sources, no results.
Also tried firing click on map after drawer is enabled. Like so:
let point = new L.LatLng(x, y)
map.fireEvent('click', {
latlng: point,
layerPoint: map.latLngToLayerPoint(point),
containerPoint: map.latLngToContainerPoint(point),
})
Also doesn't work
EDIT: Actually, AddVertex does work with custom polylines. It "didn't work" because I passed wrong arguments in my function. Somehow, I missed that.
Using addVertex on your drawer object does let you add a starting point to your line :
var polylineDrawer = new L.Draw.Polyline(map, {})
polylineDrawer.enable();
var latlng = L.latLng(48.8583736, 2.2922926);
polylineDrawer.addVertex(latlng);
and a demo
var style = {
stroke: true,
color: 'red',
weight: 4,
opacity: 0.5
};
var map = L.map(document.getElementById('map')).setView([48.8583736, 2.2922926], 15);
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
var drawnItems = new L.geoJson(null, {style: style}).addTo(map);
map.on(L.Draw.Event.CREATED, function (event) {
var layer = event.layer;
drawnItems.addLayer(layer);
});
var polylineDrawer = new L.Draw.Polyline(map, {})
polylineDrawer.enable();
var latlng = L.latLng(48.8583736, 2.2922926);
polylineDrawer.addVertex(latlng);
html, body {
height: 100%;
margin: 0;
}
#map {
width: 100%;
height: 100%;
}
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.2.0/dist/leaflet.css" integrity="sha512-M2wvCLH6DSRazYeZRIm1JnYyh22purTM+FDB5CsyxtQJYeKq83arPe5wgbNmcFXGqiSH2XR8dT/fJISVA1r/zQ==" crossorigin=""/>
<script src="https://unpkg.com/leaflet#1.2.0/dist/leaflet.js" integrity="sha512-lInM/apFSqyy1o6s89K4iQUKg6ppXEgsVxT35HbzUupEVRh2Eu9Wdl4tHj7dZO0s1uvplcYGmt3498TtHq+log==" crossorigin=""></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.12/leaflet.draw.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.12/leaflet.draw.js"></script>
<div id='map'></div>

Multiple Pushpin with infobox in Bing Map

I am trying to add multiple pushpin with separate infobox. that means each pushpin will have their own infobox with own info.
there is a loop.inside that
latlng = new Microsoft.Maps.Location(latitude[pointerCount], longtitue[pointerCount]);
MarkingLocation[pointerCount] = new Microsoft.Maps.Pushpin(latlng, {icon:"marker2.ico", height:50, width:50, anchor:new Microsoft.Maps.Point(0,50)});
myInfobox = new Microsoft.Maps.Infobox(latlng, myinfoboxOption);
Microsoft.Maps.Events.addHandler(MarkingLocation[pointerCount], 'click', function() {myInfobox.setOptions({ visible:true });});
map.entities.push(MarkingLocation[pointerCount]);
map.entities.push(myInfobox);
Problem is that it's showing the last infobox only for every pushpin. Suppose I've 4 pushpin in Londom,France,Germany,America. now no matter which pin I've clicked, it's only show the America infobox on America pushpin.please can anyone help that what I've been missing.........
And one more thing, can anyone please show the way to use htmlContent in infobox. I've tried to set it thrugh option,but it's not woring......
myinfoboxoption = {width:300,
height: 100,
title: str_loc,
htmlContent: htmlc,
showPointer: false,
offset: new Microsoft.Maps.Point(-100,0)};
Please help........
This is how I implemented multiple infobox:
<html>
<head>
<script charset="UTF-8" type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"></script>
<script>
var pinInfoBox; //the pop up info box
var infoboxLayer = new Microsoft.Maps.EntityCollection();
var pinLayer = new Microsoft.Maps.EntityCollection();
var apiKey = "YourKey";
function GetMap() {
map = new Microsoft.Maps.Map(document.getElementById("map"), {credentials: apiKey});
// Create the info box for the pushpin
pinInfobox = new Microsoft.Maps.Infobox(new Microsoft.Maps.Location(0, 0), { visible: false });
infoboxLayer.push(pinInfobox);
for (var i = 0 ; i < 10; i++){
//add pushpins
var latLon = new Microsoft.Maps.Location(Math.random()*180-90, Math.random()*360-180);
var pin = new Microsoft.Maps.Pushpin(latLon);
pin.Title = name;//usually title of the infobox
pin.Description = "blahblahblah, "+ i; //information you want to display in the infobox
pinLayer.push(pin); //add pushpin to pinLayer
Microsoft.Maps.Events.addHandler(pin, 'click', displayInfobox);
}
map.entities.push(pinLayer);
map.entities.push(infoboxLayer);
}
function displayInfobox(e) {
pinInfobox.setOptions({title: e.target.Title, description: e.target.Description, visible:true, offset: new Microsoft.Maps.Point(0,25)});
pinInfobox.setLocation(e.target.getLocation());
}
function hideInfobox(e) {
pinInfobox.setOptions({ visible: false });
}
</script>
<style>
#map { position: absolute; top: 20; left: 10; width: 700px; height: 500px; border:#555555 2px solid;}
</style>
</head>
<body onload="GetMap()">
<div id="map">
</div>
</body>
In the end, you will get something like this:
Correction:
pin.Title = "TITLE: "+ i; //usually title of the infobox

Drag and Drop in jQuery using Touchevent (iPhone browser)

I using jQuery to listen to the touchstart,touchmove and touchend, and I able to drag the 'dragitem' in iphone Safari(position change that base on the touchmove). But now the issue is how i can make the dropArea response when the 'dragitem' drag to the 'dropArea'.
For example the 'dropArea' will highlight/glow, change background color, and etc when the 'dragitem' is drag within the 'dropArea', but when it is away the 'dropArea' will remain normal. Any idea?
Thank in advance.
HTML:
<div class='dragArea' >
<div id='box1' class='dragitem'>
</div>
<div id='box2' class='dragitem'>
</div>
</div>
<div class='dropArea'></div>
jQuery:
var startTouchX = null;
var startTouchY = null;
var moveTouchX = null;
var moveTouchY = null;
var startPositionX = null;
var startPositionY = null;
$('.dragitem').bind('touchstart',function(event){
event.preventDefault();
var e = event.originalEvent;
startTouchX = e.targetTouches[0].pageX;
startTouchY = e.targetTouches[0].pageY;
startPositionX = $(this).css('left');
startPositionY = $(this).css('top');
});
$('.dragitem').bind('touchmove', function(event){
event.preventDefault();
var e = event.originalEvent;
moveTouchX = e.targetTouches[0].pageX;
moveTouchY = e.targetTouches[0].pageY;
$('#movex').text(moveTouchX);
$('#movey').text(moveTouchY);
$(this).css({top: (moveTouchY - 50), left: (moveTouchX - 5)});
});
$('.dragitem').bind('touchend', function(event){
$(this).animate({top: startPositionY, left: startPositionX}, 'fast');
});
i would check the offset() of the $('.dragitem') array and $('.dropArea.') in the move Handler ... or an interval.