How to set default layer visible in openlayers 2 - javascript

I have two layers and switcher in openlayers. After init immediately I would like to set second layer to be visible, but still showed first added layer.
I tried: setVisibility, setBaseLayer, but without successful.
Here is part of code:
var gmapLayer = new OpenLayers.Layer.Google("Google sattelite", { type: google.maps.MapTypeId.SATELLITE, visibility: false });
var gmapStreetLayer = new OpenLayers.Layer.Google("Google streets", { visibility: false });
map.addLayer(gmapLayer);
map.addLayer(gmapStreetLayer);
map.addControl(new OpenLayers.Control.LayerSwitcher());
After init I tried:
map.setBaseLayer(selLayer);
//or
selLayer.setVisibility(true);

Ok I found problem. I used setBaseLayer wrong because called to array see:
var selLayer = map.getLayersByName(selectedLayer);
if (selLayer !== null) {
map.setBaseLayer(selLayer); //<---Wrong
}
Right solutions is:
var selLayer = map.getLayersByName(selectedLayer);
if (selLayer !== null) {
map.setBaseLayer(selLayer[0]); //<--Good
}

Related

Cant remove markers from leaflet map. Not using layers

Just discovered Leafletjs and loving it. I have been trying to remove all my makers when my json is empty or invalid and I just cant get it right. All the different approches I have tried blink/flash every time my json updates and this is the closest I have managed to get.
Any help would be greatfull. I am taken back at how little examples there are of makers moving and updating without blinking.... and I really dont want to use google maps!
I tried to reset the makers = {}; but this did nothing.
Thank you
data.BMS.forEach(function (obj) {
if (obj.lat !== undefined && obj.lng !== undefined) {
if (!markers.hasOwnProperty(obj.id)) {
markers[obj.id] = new L.Marker([obj.lat, obj.lng], {icon: panicNormal}).addTo(map) .bindTooltip(obj.name,
{
permanent: true,
direction: 'top',
offset: [0, 0]
});
markers[obj.id].previousLatLngs = [];
areaBounds.push([obj.lat, obj.lng]);
} else {
areaBounds.push([obj.lat, obj.lng]);
markers[obj.id].previousLatLngs.push(markers[obj.id].getLatLng());
if(obj.status == "TRUE"){
markers[obj.id].setIcon(panicAlarm);
}else{
if(obj.type == "MO"){
markers[obj.id].setIcon(panicNormal);
}else{
markers[obj.id].setIcon(lora);
}
}
markers[obj.id].setLatLng([obj.lat, obj.lng]);
}
}else{
//How do I remove the markers
}
});
You can use L.FeatureGroup() to add all markers to it and then remove all markers with .clearLayers()
var fg = L.featureGroup().addTo(map);
...
markers[obj.id] = new L.Marker([obj.lat, obj.lng], {icon: panicNormal}).addTo(fg) .bindTooltip
...
}else{
//How do I remove the markers
fg.clearLayers();
}

Printing the map from the canvas is incomplete even after tiles loaded and postrender fired

I am trying to print the map that I create on the fly. However the image that I am getting from the map canvas sometimes looks half baked:
In the screen shot, the top portion is the openlayers map that eventually got rendered and the bottom portion is what I captured from the canvas after postrender.
I am starting from the official Export PDF example, but I am working with a map that just got created. I keep a track of the tiles loading and the tiles loaded through the tileloadstart and tileloadend map events. I also tried incorporating the postrender event as per this answer on stackoverflow. When all the tiles have been loaded I wait for the postrender event to capture the map image from the canvas.
The problem:
I think the problem has to do with the postrender event firing off two early and I don't know how much time to wait after the event before capturing the image from the canvas. I started with a delay of 100 milliseconds and then moved to 1 second and it seemed like it was working fine. But if I add more layers I had to take the delay to 3 seconds for it to start behaving correctly. So I don't know what the delay should be for maps with a lot of layers.
I also get the problem that sometimes the tileloadstart and tileloadend event keeps on firing even after postrender because some tiles had yet to be loaded and even though the tile load count had equalized.
I have created a codepen to demonstrate the issue:
Print map using tile loading and postrender events
var bingKey = ""; // Please enter a bing key
var exportButton = document.getElementById("prepareMap");
exportButton.addEventListener("click", function() {
exportButton.disabled = true;
document.body.style.cursor = "progress";
prepareMap();
});
var map;
var mapCanvas;
var printDelayAfterLoad = 100;
var loading;
var loaded;
var allLoaded;
var prepareMap = function() {
loading = 0;
loaded = 0;
allLoaded = false;
var raster = new ol.layer.Tile({
source: new ol.source.OSM(),
opacity: 0.7
});
var bingLayer = new ol.layer.Tile({
source: new ol.source.BingMaps({
key: bingKey,
imagerySet: "Aerial"
})
});
var mapLayers = [bingLayer, raster];
map = new ol.Map({
layers: mapLayers,
target: "map",
controls: ol.control.defaults({
attributionOptions: {
collapsible: false
}
}),
view: new ol.View({
center: [0, 0],
zoom: 2
})
});
for (var i = 0; i < mapLayers.length; i++) {
var layerSource = mapLayers[i].getSource();
layerSource.on("tileloadstart", tileLoadStart);
layerSource.on("tileloadend", tileLoadEnd);
layerSource.on("tileloaderror", tileLoadEnd);
}
map.renderSync();
};
var tileLoadStart = function() {
++loading;
if (allLoaded) {
logExtraTilesLoadError();
}
};
var tileLoadEnd = function() {
++loaded;
if (loading === loaded) {
allLoaded = true;
listenToPostRender();
}
};
var alreadyPrinted = false;
var listenToPostRender = function() {
map.once("postrender", function() {
if (!alreadyPrinted) {
console.log("postrender called");
window.setTimeout(function() {
printMap();
}, printDelayAfterLoad);
alreadyPrinted = true;
}
});
// listening to postcompose just to capture the mapCanvas from the event
map.once("postcompose", function(event) {
console.log("postcompose called");
mapCanvas = event.context.canvas;
});
};
var printMap = function() {
console.log("printMap called");
var data = mapCanvas.toDataURL("image/png");
var mapImageElement = document.getElementById("mapImage");
mapImageElement.setAttribute("src", data);
cleanUp();
};
var cleanUp = function() {
console.log("cleanUp called");
//exportButton.disabled = false;
document.body.style.cursor = "auto";
};
var errorMessage =
" more tiles loaded after initially all tiles had been loaded";
var extraTileLoadCount = 0;
var logExtraTilesLoadError = function() {
extraTileLoadCount++;
var errorsDiv = document.getElementById("errorsDiv");
errorsDiv.innerHTML = extraTileLoadCount + errorMessage;
console.error("errorMessage");
};
You would need to enter a Bing Maps Key at the top of the javascript file. A Bing Map Key can be generated from: https://www.bingmapsportal.com/. With the BingMap layer the problem is reproducible more consistently. In the code pen I am also capturing the problem when tileloadstart is called after the postrender and writing an error to the top of the page. Also please note that the behavior is inconsistent and you might have to reload several times for it to reproduce.

Showing a content Div on hover of a marker in HERE Maps

I am new to here maps and need to show a div on marker hover. I have been able to put markers with icons but now need to show a div with some extra information. Does HERE maps API provide this functionality?
Any doc URL or piece of code will be appreciated.
NOTE: I am using HERE maps JS API for web.
You can create a tooltip effect by adding various event listeners to the map to check if the mouse pointer is over an object.
(function (ctx) {
// ensure CSS is injected
var tooltipStyleNode = ctx.createElement('style'),
css = '#nm_tooltip{' +
' color:white;' +
' background:black;' +
' border: 1px solid grey;' +
' padding-left: 1em; ' +
' padding-right: 1em; ' +
' display: none; ' +
' min-width: 120px; ' +
'}';
tooltipStyleNode.type = 'text/css';
if (tooltipStyleNode.styleSheet) { // IE
tooltipStyleNode.styleSheet.cssText = css;
} else {
tooltipStyleNode.appendChild(ctx.createTextNode(css));
}
if (ctx.body) {
ctx.body.appendChild(tooltipStyleNode);
} else if (ctx.addEventListener) {
ctx.addEventListener('DOMContentLoaded', function () {
ctx.body.appendChild(tooltipStyleNode);
}, false);
} else {
ctx.attachEvent('DOMContentLoaded', function () {
ctx.body.appendChild(tooltipStyleNode);
});
}
})(document);
Object.defineProperty(Tooltip.prototype, 'visible', {
get: function() {
return this._visible;
},
set: function(visible) {
this._visible = visible;
this.tooltip.style.display = visible ? 'block' : 'none';
}
});
function Tooltip(map) {
var that = this;
that.map = map;
that.tooltip = document.createElement('div');
that.tooltip.id = 'nm_tooltip';
that.tooltip.style.position = 'absolute';
obj = null,
showTooltip = function () {
var point = that.map.geoToScreen(obj.getPosition()),
left = point.x - (that.tooltip.offsetWidth / 2),
top = point.y + 1; // Slight offset to avoid flicker.
that.tooltip.style.left = left + 'px';
that.tooltip.style.top = top + 'px';
that.visible = true;
that.tooltip.innerHTML = obj.title;
};
map.getElement().appendChild(that.tooltip);
map.addEventListener('pointermove', function (evt) {
obj = that.map.getObjectAt(evt.currentPointer.viewportX,
evt.currentPointer.viewportY);
if(obj && obj.title){
showTooltip();
} else {
that.visible = false;
}
});
map.addEventListener('tap', function (evt){
that.tooltip.visible = false;
});
map.addEventListener('drag', function (evt){
if (that.visible) {
showTooltip();
}
});
};
This is initialised by passing the map object as shown:
function addTooltipControlToMap(map) {
tooltip = new Tooltip(map);
}
The code as written is looking for a .title attribute to be added to the map objects - this could be updated to use .getData() if preferred. Tooltips can be initialised as shown below, taking either text or html:
function addMarkersWithTooltips(map) {
// Simple Marker with tooltip
var brandenburgerTorMarker = new H.map.Marker(
{lat:52.516237, lng: 13.35}),
fernsehturmMarker = new H.map.Marker(
{lat:52.520816, lng:13.409417});
brandenburgerTorMarker.title = 'Brandenburger Tor';
// Marker with HTML Tooltip
fernsehturmMarker.title ='<div>' +
'<h2>Tooltip with HTML content<\/h2>' +
'<img width=\'120\' height=90 src=' +
'\'http://upload.wikimedia.org/wikipedia/commons/' +
'8/84/Berlin-fernsehturm.JPG\' ' +
'alt=\'\'/><br/><b>Fernsehturm, Berlin<\/b>' +
'<\/div>';
// Add the markers onto the map
map.addObjects([brandenburgerTorMarker, fernsehturmMarker]);
}
I have been able to find proper mouse over events for HERE map's markers which are pointerenter and pointerleave and sample code to use these events is:
// After Initializing map with your own credentials.
var map = new H.Map(document.getElementById('map'),
defaultLayers.normal.map,{
center: {lat: LAT_VAL, lng: LNG_VAL},
zoom: 12
});
var domMarker = new H.map.DomMarker(coords, {
icon: domIcon
});
var bubble;
domMarker.addEventListener('pointerenter', function(evt) {
bubble = new H.ui.InfoBubble({lat:"SOME_VALUE",lng:"SOME_VALUE"}, {
content: "Your content come here"
});
ui.addBubble(bubble);
}, false);
domMarker.addEventListener('pointerleave', function(evt) {
bubble.close();
}, false);
map.addObject(domMarker);
Depending on the api version you are using, you may find what you are looking for inside the documentation pdf (or at least start from there).
Supposing you need do make some HTML styled marker, you may need:
DomMarker (instead of a Marker, because it allows you to use ->2)
DomIcon (which can embed html)
An example can be found here https://developer.here.com/apiexplorer-v2-sample-data/template-web-default/examples/map-with-dom-marker/index.html
Anyway, if you need to show informations about the marker, I would suggest to use InfoBubbles, which have been developed for this purpose.
From the 3.0.5 docs:
// Create an info bubble object at a specific geographic location:
ui = H.ui.UI.createDefault(self.map, defaultLayers);
var bubble = new H.ui.InfoBubble({ lng: 13.4, lat: 52.51 }, {
content: '<b>Hello World!</b>'
});
// Add info bubble to the UI:
ui.addBubble(bubble);
To show them, you should attach an event to the marker tap event:
marker.addEventListener('tap', function (evt) {
//create and add the bubble
}
In any case, you can find the documentation of your api version here: https://developer.here.com/documentation/versions
You do not have "hover" listener for marker,
but you can show infoBubble on click
http://heremaps.github.io/examples/explorer.html#infobubble-on-marker-click
If this doesn't work for you, you will have to use jquery and to bind "hover" on HTML marker element. (This is not very easy task)

Change position of tooltip in Google Chart

I have a google chart that I'm using where I have set the type of tooltip to be html in my options, like this:
tooltip: { isHtml: true }
Customizing the tooltip to look how I want has been the easy part, but getting the tooltip in the right position has surprisingly difficult. After a lot of searching, I found this answer on tooltip positioning, but cannot seem to get it working.
My javascript (aside from options) for creating the chart and dealing with tooltip positioning is as follows:
var chart = new google.visualization.AreaChart(document.getElementById('chart_div'));
google.visualization.events.addListener(chart, 'ready', function () {
var container = document.querySelector('#chart_div > div:last-child');
function setPosition () {
var tooltip = container.querySelector('div.google-visualization-tooltip');
tooltip.style.top = 0;
tooltip.style.left = '-47px';
}
if (typeof MutationObserver === 'function') {
var observer = new MutationObserver(function (m) {
for (var i = 0; i < m.length; i++) {
console.log("mutation: " + m[i].type);
if (m[i].addedNodes.length) {
setPosition();
break; // once we find the added node, we shouldn't need to look any further
}
}
});
observer.observe(container, {
childList: true
});
} else if (document.addEventListener) {
container.addEventListener('DOMNodeInserted', setPosition);
} else {
container.attachEvent('onDOMNodeInserted', setPosition);
}
});
chart.draw(dataTable, options);
I'm using Google Chrome for testing right now, and if I put a debugger in the typeof MutationObserver snippet, I am getting in there and setting the observer, but it seems as though it never gets observed, as I am not even getting the console messages.
Any help would be very appreciated. My html element with the ID chart_div exists (and the chart is rendered there), so I am not sure what I am missing.

Getting click on Mapbox markers

I have been able to integrate markers to the mapbox we are using, but still wonder if we can get a click on them. If so how?
Following is my code:
<style>
/*
* Unlike other icons, you can style `L.divIcon` with CSS.
* These styles make each marker a circle with a border and centered text.
*/
.count-icon1 {
background:url(images/redpin.png);
color:#000;
font-weight:600;
text-align:center;
padding:19px 0 0 0px; font-size:180%;
}
.count-icon2 {
background:url(images/greenpin.png);
color:#000;
font-weight:600;
text-align:center;
padding:19px 0 0 0px; font-size:180%;
}
</style>
js code:
var defaultLat = 39.12367;
var defaultLon = -76.81229;
if($scope.currentLocDetails != null){
if($scope.currentLocDetails.Lat != null && $scope.currentLocDetails.Lon != null){
defaultLat = $scope.currentLocDetails.Lat;
defaultLon = $scope.currentLocDetails.Lon;
}
}
var x = 0;
if(map != null)
map.remove();
map = L.mapbox.map('map_view', 'your key here').setView([defaultLat, defaultLon], 9);
for (var i = 0; i < responseData.JobLocation.length; i++) {
var eachObj = responseData.JobLocation[i];
if(eachObj.Lat != null && eachObj.Lon != null){
x++;
// Use a little math to position markers.
// Replace this with your own code.
L.marker([
eachObj.Lat,
eachObj.Lon
], {
icon: L.divIcon({
// Specify a class name we can refer to in CSS.
className: ((currentSelectedIndex + 1) == i + 1)?'count-icon1':'count-icon2',
// Define what HTML goes in each marker.
html: i + 1,
// Set a markers width and height.
iconSize: [65, 94]
})
}).addTo(map);
}
}
I tried doing a bit R & D, but get to no where:
We need to use featureLayer, but dunno how.
For the click feature we need to follow this code, but how?
// Listen for individual marker clicks.
myLayer.on('click',function(e) {
// Force the popup closed.
e.layer.closePopup();
var feature = e.layer.feature;
var content = '<div><strong>' + feature.properties.title + '</strong>' +
'<p>' + feature.properties.description + '</p></div>';
info.innerHTML = content;
});
Any help with this is really appreciated.
Thanks
I believe there are various ways of doing this with Mapbox, unfortunately I don't have access to my project where I use it right now so I'm just going off the Mapbox documentation.
Following your example this looks the simplest - if you have added marker, for example:
var marker = L.marker([43.6475, -79.3838], {
icon: L.mapbox.marker.icon({
'marker-color': '#9c89cc'
})
})
.bindPopup('<p>Your html code here</p>')
.addTo(map);
You can pass whatever HTML you want in the bindPopup argument.
https://www.mapbox.com/mapbox.js/example/v1.0.0/clicks-in-popups/
Then it should be be pretty simple via 'addEventListener('click', function)' on that marker variable.
Or alternatively -
myLayer.on('click', function(e) {
resetColors();
e.layer.feature.properties['old-color'] = e.layer.feature.properties['marker-color'];
e.layer.feature.properties['marker-color'] = '#ff8888';
myLayer.setGeoJSON(geoJson);
});
map.on('click', resetColors);
Effectively add an event listener on the map variable - and then listen to what you've clicked on via the event argument passed to the event listener.
This may be useful: https://www.mapbox.com/mapbox.js/example/v1.0.0/change-marker-color-click/
Good luck!

Categories

Resources