I am struggling with creating the overlay on my map. I want to incorporate the example like here:
https://openlayers.org/en/latest/examples/overlay.html
https://openlayers.org/en/latest/apidoc/module-ol_Overlay-Overlay.html
but I cannot use the import statement, because I am getting an error:
Uncaught SyntaxError: Cannot use import statement outside a module
which has an explanation here:
https://github.com/TypeStrong/ts-node#syntaxerror
and here:
Why examples don't work? (a struggle with imports)
"Uncaught SyntaxError: Cannot use import statement outside a module" when importing ECMAScript 6
I tried to do sth like this:
<script type="module" src="./layers/overlay.js" type="text/javascript"></script>
but an error still comes out and now it's related to the CORS policy:
Access to script at 'file:///C:/Users.../layers/overlay.js' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, chrome-untrusted, https.
Unfortunately I need this feature offline.
In this thread I found, that there is an alternative to the import feature:
https://gis.stackexchange.com/questions/310482/unexpected-token-identifier-error-import-openlayers/310501#310501
and I tried to adjust my code into it, which looks like this:
var fromLonLat = ol.proj.fromLonLat
var pos = fromLonLat([-0.21005,52.08093]);
var overlay = new ol.Overlay({
element: container,
autoPan: true,
autoPanAnimation: {
duration: 250,
},
});
var popup = new overlay({
element: document.getElementById('popup'),
});
map.addOverlay(popup);
// Vienna marker
var marker = new overlay({
position: pos,
positioning: 'center-center',
element: document.getElementById('marker'),
stopEvent: false,
});
map.addOverlay(marker);
// Vienna label
var vienna = new overlay({
position: pos,
element: document.getElementById('vienna'),
});
map.addOverlay(vienna);
map.on('click', function (evt) {
var element = popup.getElement();
var coordinate = evt.coordinate;
var hdms = toStringHDMS(toLonLat(coordinate));
$(element).popover('dispose');
popup.setPosition(coordinate);
$(element).popover({
container: element,
placement: 'top',
animation: false,
html: true,
content: '<p>The location you clicked was:</p><code>' + hdms + '</code>',
});
$(element).popover('show');
});
and now I am getting an error like this:
Uncaught TypeError: overlay is not a constructor
at overlay.js:15
similar to the issue here:
openlayers3 undefined is not a constructor error on ol.source.StaticVector
Regarding this I found:
https://github.com/Viglino/ol-ext
including all relevant extensions for OpenLayers. Unfortunately after attaching the relevant scripts, the problem is still the same.
My another approaching was to replace everywhere the new overlay with the new ol.Overlay. In this event the console says nothing, but I can't see an overlay at all.
The code might be specicif, because it comes from the QGIS2web plugin. The major script with map as well as the index.html file you can find in this fiddle link below:
https://jsfiddle.net/2adv41bs/
Many sources refers me to the newest ol package
https://openlayers.org/download/
but since I superseded the link in my HTML code it's still doesn't work at all
I am also not familiar with creating the bundle in openlayers
https://openlayers.org/en/latest/doc/tutorials/bundle.html
A similar thread is here:
https://gis.stackexchange.com/questions/380382/incorporating-overlay-for-the-openlayers-map-generated-by-qgis2web-plugin
Is it possible to launch the overlay option for Openlayers map offline?
The good alternative for import can be found here:
https://gis.stackexchange.com/questions/310482/unexpected-token-identifier-error-import-openlayers/310501#310501
which changes the situation completely, because now the final code can look as this:
HTML
<div id="map" class="map">
<div id="popup" class="ol-popup">
<div id="popup-content"></div>
</div>
</div>
<div style="display: none;">
<!-- Clickable label for Vienna -->
<a class="overlay" id="vienna" target="_blank"
href="http://en.wikipedia.org/wiki/Vienna">Vienna</a>
<div id="marker" title="Marker"></div>
<!-- Popup -->
<div id="popup" title="Welcome to OpenLayers"></div>
</div>
Next, our CSS
#marker {
width: 20px;
height: 20px;
border: 1px solid #088;
border-radius: 10px;
background-color: #0FF;
opacity: 0.5;
}
#vienna {
text-decoration: none;
color: white;
font-size: 11pt;
font-weight: bold;
text-shadow: black 0.1em 0.1em 0.2em;
}
.popover-body {
min-width: 276px;
}
and the JS
var fromLonLat = ol.proj.fromLonLat
var pos = fromLonLat([-0.19610,52.07769]);
var popup = new ol.Overlay({
element: document.getElementById('popup'),
});
map.addOverlay(popup);
var marker = new ol.Overlay({
position: pos,
positioning: 'center-center',
element: document.getElementById('marker'),
stopEvent: false,
});
map.addOverlay(marker);
var vienna = new ol.Overlay({
position: pos,
element: document.getElementById('vienna'),
});
map.addOverlay(vienna);
map.on('click', function (evt) {
var element = popup.getElement();
var coordinate = evt.coordinate;
var hdms = toStringHDMS(toLonLat(coordinate));
$(element).popover('dispose');
popup.setPosition(coordinate);
$(element).popover({
container: element,
placement: 'top',
animation: false,
html: true,
content: '<p>The location you clicked was:</p><code>' + hdms + '</code>',
});
$(element).popover('show');
});
Obviously, both CSS and JS files must be attached to the main index.html file if we want it working.
Related
I'm using leaflet to put some markers on a map. I have set that, clicking on a marker, a popup will be opened showing an image. Here's a brief example:
var map = L.map('map')
.addLayer(tile)
.setView([initLat, initLon], initZoom);
var m = L.marker([lat, lon])
.bindPopup('<img src="1.jpg"/>')
.addTo(map);
My objective is to load those images ("1.jpg" in the example above) using lazy load, so it's only loaded when I click on the marker.
Does anyone knows how to do this?
Thanks!
You could set the content of the popup when the popup is opened.
Let's create a custom popup with a lazyload option and without content :
var m = L.marker([0, 0])
.bindPopup(L.popup({
lazyload: '<img src="1.jpg"/>'
}))
.addTo(map);
You can then set a global handler to fill your popup when needed:
map.on('popupopen', function(e) {
var popen = e.popup;
if (popen.options.lazyload) {
popen.setContent(popen.options.lazyload);
}
});
And a demo:
var map = L.map('map', {
center: [0, 0],
zoom: 1
});
var m = L.marker([-30, 0])
.bindPopup(L.popup({
lazyload: '<img src="https://i.stack.imgur.com/shfxy.jpg?s=32&g=1" />'
}))
.addTo(map);
map.on('popupopen', function(e) {
var popen = e.popup;
if (popen.options.lazyload) {
popen.setContent(popen.options.lazyload);
}
});
html, body {
height: 100%;
margin: 0;
}
#map {
width: 100%;
height: 150px;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.3.1/leaflet.css"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.3.1/leaflet.js"></script>
<div id='map'></div>
Actually in the case where you fill your popup with a String content (like you did with .bindPopup('<img src="1.jpg"/>'), Leaflet converts it (through innerHTML) to DOM nodes only when the Popup is first opened on a map. Therefore your image will be loaded only at that moment, which is exactly the lazy loading behaviour you are looking for.
So you do not need to do anything extra from what you already have done in your question code:
(make sure you refresh your page / clear your cache to see the image loading pass in the browser network requests)
var map = L.map('map', {
center: [0, 0],
zoom: 1
});
var m = L.marker([-30, 0])
.bindPopup('<img src="https://i.stack.imgur.com/shfxy.jpg?s=32&g=1" />')
.addTo(map);
html, body {
height: 100%;
margin: 0;
}
#map {
width: 100%;
height: 150px;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.3.1/leaflet.css"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.3.1/leaflet.js"></script>
<div id='map'></div>
From what I see, in v2 of GMaps API there was a property "buttons" of the InfoWindow object that one could define in a way that given InfoWindow has no close button:
marker.openInfoWindowHtml("No Close Button",{buttons:{close:{show:4}}});
The above however does not apply for v3. Does anybody know a way to do it? I read about an utility that replaces InfoWindow called InfoBox but it has not been developed for the past 2 years. I'm currently using the latest 3.13 version of Gmaps v3 API.
A workaround with jQuery is acceptable, if there is no better solution.
You can also do it through the css.
.gm-style-iw + div {display: none;}
edit january 2019
as #antmeehan said in the comment,
Google have changed the HTML, and the close button is now a button element rather than a div
So the css code to hide the "x" button is now:
.gm-style-iw + button {display: none;}
Update
Displaying a <div> on top of a google map is straight forward :
example css:
div.info {
position: absolute;
z-index: 999;
width: 200px;
height: 100px;
display: none;
background-color: #fff;
border: 3px solid #ebebeb;
padding: 10px;
}
A info class <div> somewhere in the markup :
<div id="myinfo" class="info"><p>I am a div on top of a google map .. </p></div>
Always nice to have a short reference to the div :
var info = document.getElementById('myinfo');
The more tricky part, showing the <div>, how and when - here I just assign a click handler to the map (after it is created) and show the info <div> at mouse location XY inside the map :
google.maps.event.addListener(map, 'click', function(args) {
var x=args.pixel.x; //we clicked here
var y=args.pixel.y;
info.style.left=x+'px';
info.style.top=y+'px';
info.style.display='block';
});
What you gain with this is, that the info <div> follows you around on the map, every time you click.
You will need more styling so it suits your need, eg so it "looks like an InfoBox", but that should be easy to find out, I am not a librarian :)
And maybe later on something to close the info with, but that you didn't want in the first place :)
Original answer
You cant! There is no way to do this in the current v3.13 InfoWindow options.
A workaround is to disable the image containing the X :
<style>
img[src="http://maps.gstatic.com/mapfiles/api-3/images/mapcnt3.png"] {
display: none;
}
</style>
But this is in no way advisable!
src="http://maps.gstatic.com/mapfiles/api-3/images/mapcnt3.png is just what the infowindow is referring to today. Tomorrow, or in a month, or in a year, this image-reference for sure has changed. As you can see if you search for similar "solutions", made over time - like this. They are all broken today, eg the effort is meaningless.
I think there is extremely good logic in google "refusing" to follow the request for hiding the close-button. If you not need a close-button, what do you need an InfoWindow for anyway? When you are better off just to show a <div> on the map.
if using jquery just add this
$(".gm-style-iw").next("div").hide();
To extend on Louis Moore's answer, you can also center the text after removing the close button:
.gm-style-iw + div {display: none;}
.gm-style-iw {text-align:center;}
Without Centering:
With Centering:
Thanks Tushar, but also you need put this code in event handler
google.maps.event.addListener(infowindow, 'domready', function(){
$(".gm-style-iw").next("div").hide();
});
I used the answer given by Tushar Gaurav, but expanded it a little...
$(".gm-style-iw:contains(" + infoText + ")").css("left", function() {
return ($(this).parent().width() - $(this).width()) / 2;
}).next("div").remove();
That will remove the X from an infowindow with the text in infoText, and then recenter the text as it's off-center after removing the close button.
Just adding this for anyone else who stumbles across this page as I did.
It should be .gm-style-iw > button to avoid other custom buttons we might have within the box to be hidden too:
.gm-style-iw > button {
display: none !important;
}
closeBoxURL: ""
as stated before doesn't apply for InfoWIndow. This is an option on the InfoBox.
You may for example use this CSS workaround to remove the X, and the surrounding clickable button:
.gm-style-iw + div {
display: none;
}
And as davidkonrad said. This is a workaround on the code as it is today. It will likely be changed.
My own way (without Jquery) and with realign to the center of the infoWindow:
var content = document.querySelector('.gm-style-iw');
content.parentNode.removeChild(content.nextElementSibling);
content.style.setProperty('width', 'auto', 'important');
content.style.setProperty('right', content.style.left, 'important');
content.style.setProperty('text-align', 'center', 'important');
This works
.gm-style-iw > button {display: none !important;}
My solution:
google.maps.event.addListener(marker, 'click', function() {
var wnd = new google.maps.InfoWindow({
content: "<table id='viewObject' >...</table>"
});
google.maps.event.addListener(wnd, 'domready', function(){
$("#viewObject").parent().parent().next().remove();
});
wnd.open(map, marker);
});
============= HTML ==============
<agm-map #gm [latitude]="lat" [longitude]="lng" #AgmMap [fitBounds]="true">
<agm-marker
(mouseOver)="onMouseOver(infoWindow, gm)"
(mouseOut)="onMouseOut(infoWindow, gm)"
>
<div id="test">
<agm-info-window #infoWindow></agm-info-window>
</div>
</agm-marker>
</agm-map>
============= TS ==============
onMouseOver(infoWindow, gm) {
console.log(infoWindow);
if (gm.lastOpen != null) {
gm.lastOpen.close();
}
gm.lastOpen = infoWindow;
infoWindow.open();
setTimeout(() => {
var x = document.getElementsByClassName('gm-ui-hover-effect')[0].remove();
}, 10);
}
onMouseOut(infoWindow, gm) {
gm.lastOpen = infoWindow;
// infoWindow.close();
}
You can use this. This will not hide other images like zoom control, pan control etc.
on dom ready of info window you can use this.
google.maps.event.addListener(infoWindow, 'domready', function () {
document.querySelector(".gm-style-iw").nextElementSibling.style.display = "none";
});
I can't find correct answer in here, so I fixed it myself. It will work well.
google.maps.event.addListener(infowindow, 'domready', function(){
$(".gm-style-iw").parent().find("button").removeAttr("style").hide();
});
.gm-style-iw + button {display: none !important;}
Anno domini 2021 this work better for me
button.gm-ui-hover-effect {
display: none !important;
}
I couldn't get any of the $(".gm-style-iw").next("div").hide(); answers to work even when calling the code after the DOM was loaded, since there was a delay between the code being called and the info window being created. What I did was create an interval that runs until it finds the info window and removes the "X" element. If there's a better way please tell me.
var removeCloseButton = setInterval(
function()
{
if ($(".gm-style-iw").length)
{
$(".gm-style-iw").next("div").remove();
clearInterval(removeCloseButton);
}
},
10
);
Using Archers method I need to do
$(".gm-style-iw").css("left", function() { //remove close and recenter
return ($(this).parent().width() - $(this).find(">:first-child").width()) / 2;
}).next("div").remove();
google.maps.event.addListener(infowindow, 'domready', function() {
var iwOuter = jQuery('.gm-style-iw');
// Reference to the div that groups the close button elements.
var iwCloseBtn = iwOuter.next();
// Apply the desired effect to the close button
iwCloseBtn.remove()
});
As there is no option to hide this by API parameter, you have to find the element by targeting the content window and remove it.
Hope this helps :)
in jQuery's gmap3 plugin this can be accomplished using
google.maps.event.addListener($('#map').gmap3({get:{name:"infowindow"}}), 'domready', function(){
$(".gm-style-iw").next("div").remove();
});
May 2021 : Add this in your CSS:
button.gm-ui-hover-effect {
visibility: hidden;
}
This worked perfectly with Maps API v3.43
Inspect it - it's a div with a class of close on it - you can target it with CSS and set it to display: none;
You can just use the option
closeBoxURL : ""
http://google-maps-utility-library-v3.googlecode.com/svn/trunk/infobox/docs/reference.html
From Google Documentation
closeBoxURL | string | The URL of the image representing the close box. Note: The default is the URL for Google's standard close box. Set
this property to "" if no close box is required.
Example
var infowindow = new google.maps.InfoWindow({
closeBoxURL: "",
closeBoxMargin : ""
});
You can set "closeBoxURL" property of the Info Window to "" and it will make the button disappear.
var infowindow = new google.maps.InfoWindow({
content: contentString,
closeBoxURL: ""
});
I've managed to cluster my markers. What I want to do now is to display a custom icon with the number of points in the cluster, but I can't figure out how to do that or if it's even possible.
I read the documentation and understood that I need to implement my own iconCreateFunction when creating the marker cluster.
addSomeMarkers: function(data, markerProperties) {
var markers = L.markerClusterGroup({
iconCreateFunction: function(cluster) {
// TODO
}
});
....
}
I know I can return L.divIcon with a custom css class and cluster.getChildCount(), but I can't specify markerProperties.iconUrl as an image that should be displayed.
I could also use L.icon with my custom icon from markerProperties.iconUrl, but in that case I don't see how I should get cluster.getChildCount() to display.
So what I need is a combination of both. Is there anything like that? And if not, can someone hint a workaround to achieve this?
Using the example here: https://github.com/Leaflet/Leaflet.markercluster/blob/master/example/marker-clustering-custom.html
And the documentation of L.divIcon is here:
http://leafletjs.com/reference.html#divicon
I came up with this example: http://franceimage.github.io/leaflet/8/?map=46.566414,2.4609375,6
Hopefully it will help you
Meaningful parts are:
var markerCluster = new L.MarkerClusterGroup({
iconCreateFunction: function (cluster) {
var markers = cluster.getAllChildMarkers();
var html = '<div class="circle">' + markers.length + '</div>';
return L.divIcon({ html: html, className: 'mycluster', iconSize: L.point(32, 32) });
},
spiderfyOnMaxZoom: false, showCoverageOnHover: true, zoomToBoundsOnClick: false
});
and css
.circle {
width: 32px;
height: 32px;
line-height: 32px;
background-image: url('circle.png');
text-align: center;
}
There may be other ways ...
I want to add my own button to enable my feature in Google map drawing.
Here is the link for the sample drawing page Google Developers Drawing tools Here you can see 6 options for drawing.
I want to add my option in these 6 option, How can I do that?
Start by adding your own button in HTML
<button id="custom-BtnPolygon">Draw</button>
<button id="custom-BtnPolyline">Draw</button>
and call it from your javascript to invoke google drawingManager
$("#custom-BtnPolygon").click( function(){
drawingManager.setDrawingMode(google.maps.drawing.OverlayType.POLYGON);
});
$("#custom-BtnPolyline").click( function(){
drawingManager.setDrawingMode(google.maps.drawing.OverlayType.POLYLINE);
});
Initiate polygon drawing from custom button
I don't think you can add a custom control to the Drawing Manager controls as stated in the comments. But with a little bit of styling, you can add your own control next to it and make it look like it's part of the group.
What you need for that is to add your custom control to the same control position than your drawing controls:
drawingControlOptions: {
position: google.maps.ControlPosition.TOP_CENTER,
drawingModes: [
google.maps.drawing.OverlayType.MARKER,
google.maps.drawing.OverlayType.CIRCLE,
google.maps.drawing.OverlayType.POLYGON,
google.maps.drawing.OverlayType.POLYLINE,
google.maps.drawing.OverlayType.RECTANGLE]
}
map.controls[google.maps.ControlPosition.TOP_CENTER].push(yourCustomControl);
Check the demo. It might not be perfect but you get the idea.
JSFiddle demo
Also described in this example:
home control example
//set the custom control
var homeControlDiv = document.createElement('DIV'),
homeControl = new mymap.HomeControl(homeControlDiv, map);
homeControlDiv.index = 1;
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(homeControlDiv);
//function
HomeControl: function(controlDiv, map) {
controlDiv.style.padding = '5px';
var controlUI = document.createElement('DIV');
controlUI.style.backgroundColor = 'white';
controlUI.style.borderStyle = 'solid';
controlUI.style.borderColor ='#365e00';
controlUI.style.borderWidth = '2px';
controlUI.style.cursor = 'pointer';
controlUI.style.textAlign = 'center';
controlUI.title = 'Home';
controlDiv.appendChild(controlUI);
var controlText = document.createElement('DIV');
controlText.style.fontFamily = 'Arial,sans-serif';
controlText.style.fontSize = '12px';
controlText.style.paddingLeft = '6px';
controlText.style.paddingTop = '1px';
controlText.style.paddingBottom = '1px';
controlText.style.paddingRight = '6px';
controlText.innerHTML = '<b>Home</b>';
controlUI.appendChild(controlText);
google.maps.event.addDomListener(controlUI, 'click', function() {
var home = new google.maps.LatLng(50.0019, 10.1419);
map.setCenter(home)
map.setZoom(6)
});
},
best
M
To add custom overlays to your map like in the example from the offcial documentation you just need to create some HTML to create the buttons, taken from this example from the documentation.
<body>
<!-- [START region_toolbar] -->
<!-- Add an input button to initiate the toggle method on the overlay. -->
<div id ="panel">
<input type="button" value="Toggle visibility" onclick="overlay.toggle();"></input>
<input type="button" value="Toggle DOM attachment" onclick="overlay.toggleDOM();"></input>
</div>
<!-- [END region_toolbar] -->
<div id="map-canvas"></div>
</body>
Everything beyond that is just pure CSS, how you design the buttons and the other stuff.
<style>
html, body, #map-canvas {
height: 100%;
margin: 0px;
padding: 0px
}
#panel {
position: absolute;
top: 5px;
left: 50%;
margin-left: -180px;
z-index: 5;
background-color: #fff;
padding: 5px;
border: 1px solid #999;
}
</style>
What also could help you for displaying the buttons in a better way are custom controls, you can display them on different points in the map and store your buttons there.
PS: The drawingtools from google are nothing more then Google Maps Controls, so the custom controls are the things you're looking for if you want to display your own drawing tools like google does.
Edit to answer the original question:
According to the API Documention the DrawingManager only accepts the given values from google and null. The given values are static ones.
The actually quote:
The DrawingManager's drawing mode, which defines the type of overlay to be added on the map. Accepted values are MARKER, POLYGON, POLYLINE, RECTANGLE, CIRCLE, or null. A drawing mode of null means that the user can interact with the map as normal, and clicks do not draw anything.
So i don't think that there is a possibility to add custom overlays to the given control from Google. But as mentioned in the comments you could create a custom control and style it like the one from Google and display it right next to them.
I am trying to keep my basemap layer opacity at a constant between different selections (and can be controlled by the user with a slider). Any basemap layers that don't have a related 'reference' layer behave as expected (i.e. if topo is at 25% before changing to imagery, it will update to 25% on change). If a user selects a basemap that also has a reference layer (imagery with labels; light gray canvas, etc), the reference layer ignores the opacity setting when loaded and will only change AFTER the user tries to move the slider. Thoughts?
Fun tidbit... Basemap layer 'Terrain with Labels' ignores this completely on both the imagery and the text when swapping. It almost looks like it refreshes after it loads.
Here is the working example in JSFiddle (http://jsfiddle.net/disuse/ez6mN/) and the dojo code that I am using to replicate my issue. Using the latest Esri ArcGIS Javascript 3.7.
Codeblock
var baseMap_Opacity;
var baseOpacity = 0.25;
require([
"esri/map",
"esri/dijit/BasemapGallery",
"dijit/form/HorizontalSlider",
"dijit/form/HorizontalRule",
"dijit/form/HorizontalRuleLabels",
"dojo/parser",
"dojo/dom",
"dojo/on",
"dojo/ready",
"dojo/domReady!"
], function(
Map,
BasemapGallery,
HorizontalSlider,
HorizontalRule,
HorizontalRuleLabels,
parser,
dom,
on,
ready
) {
ready(function() {
map = new Map("map", {
center: [-121.569, 39.00],
zoom: 7,
optimizePanAnimation: true,
basemap: "topo"
});
var basemapGallery = new BasemapGallery({
showArcGISBasemaps: true,
map: map
}, "basemaps");
basemapGallery.startup();
basemap = map.getLayer("layer0");
basemap.setOpacity(baseOpacity);
on(basemapGallery, "selection-change", function() {
changeBasemapOpacity(baseOpacity);
});
createHorzSlider();
});
function createHorzSlider() {
baseMap_Opacity = dom.byId("baseMap_Opacity");
baseMap_Opacity.innerHTML = Math.round(baseOpacity*100) + "%";
var horzSlider = new HorizontalSlider({
minimum: 0,
maximum: 1,
value: baseOpacity,
intermediateChanges: true,
showButtons: true,
discreteValues: 101,
style: "width: 300px; margin-left: 25px;",
onChange: function(value) {
changeBasemapOpacity(value);
}
}, "horzSlider");
horzSlider.startup();
var horzSliderRule = new HorizontalRule({
container: "bottomDecoration",
count: 2 ,
style: "height: 5px; width: 288px; margin-top: 5px; margin-left: 32px;"
}, "horzSliderRule");
horzSliderRule.startup();
var horzSliderLabels = new HorizontalRuleLabels({
container: "bottomDecoration",
labels: ["0", "100"],
style: "width: 288px; margin-left: 32px;",
labelStyle: "font-style: normal; font-weight: bold; font-size: 14px;"
}, "horzSliderLabels");
horzSliderLabels.startup();
}
function changeBasemapOpacity(value) {
baseOpacity = value;
baseMap_Opacity.innerHTML = Math.round(baseOpacity*100) + "%";
var esriURL = "http://services.arcgisonline.com";
var layers = map.getLayersVisibleAtScale();
for (var i = 0; i < layers.length; i++) {
var lyr = map.getLayer(layers[i].id);
if ((lyr._basemapGalleryLayerType) || (lyr.id == "layer0") || ((lyr.url) && (lyr.url.indexOf(esriURL) == 0))) {
lyr.setOpacity(baseOpacity);
}
}
}
});
The basemap gallery's selection-change event fires after the newly selected basemap is in the map. This fires before reference layers are added and is the intended design, the idea being that you wouldn't want to manipulate reference layers. In your case, that's not what you want so using selection-change is out.
To accomplish what you want, use the map's layer-add-result event and check if layer._basemapGalleryLayerType is truthy. If it is, you know a layer used by the basemap gallery was added to the map and you should update its opacity. Here's a code snippet:
map.on("layer-add-result", function(e) {
if ( e.layer._basemapGalleryLayerType ) {
e.layer.setOpacity(baseOpacity);
}
});
Regarding the issue with the Terrain with Labels basemap, things are working as expected. Because that basemap's reference layer includes labels as well as political boundaries and major roads, it looks like opacity isn't being applied when in fact it is. Using the code above will set opacity on both the layer that represents the terrain basemap as well as the reference layer.
Here's a modified version of your page that I think accomplishes what you want: http://jsbin.com/IyixAPa/1/edit