So the background of my openlayers implementation appears to be squished into vertical stripes. The weird thing is that it wasn't always like this but even when I stash all my changes back to a point where I know it was working, it still is broken. It makes me wonder if perhaps something has changed about the way the tile assets are being delivered. I have tried switching between using osm and wms layers with no change, any help would be appreciated.
Here is the pertinent code:
initMap: function() {
var view = this;
var map = this.map = new OpenLayers.Map();
map.render(this.$map[0]);
var wmsLayer = new OpenLayers.Layer.WMS( "OpenLayers WMS",
"http://vmap0.tiles.osgeo.org/wms/vmap0?", {layers: 'basic'});
var osmLayer = new OpenLayers.Layer.OSM();
this.layers = {
point: new OpenLayers.Layer.Vector("Point Layer"),
line: new OpenLayers.Layer.Vector("Line Layer"),
polygon: new OpenLayers.Layer.Vector("Polygon Layer")
};
this.setValue(this.value);
map.addLayers([this.layers.point, this.layers.line, this.layers.polygon, osmLayer]);
drawControls = {
point: new OpenLayers.Control.DrawFeature(this.layers.point,
OpenLayers.Handler.Point),
line: new OpenLayers.Control.DrawFeature(this.layers.line,
OpenLayers.Handler.Path),
polygon: new OpenLayers.Control.DrawFeature(this.layers.polygon,
OpenLayers.Handler.Polygon)
};
this.layers[this.layerType].events.on({'sketchcomplete': function(feature) {
if (!view.multiple) {
// deactivate polygon layer once a polygon has been added
drawControls[view.layerType].deactivate();
}
}});
for(var key in drawControls) {
map.addControl(drawControls[key]);
}
if (this.layers[this.layerType].features.length) {
var bounds = this.layers[this.layerType].getDataExtent();
var zoom = this.layers[this.layerType].getZoomForExtent(bounds);
var lon = (bounds.top - bounds.bottom) / 2;
var lat = (bounds.right - bounds.left) / 2;
map.setCenter(new OpenLayers.LonLat(lon,lat), 3);
map.zoomToExtent(bounds);
if (view.multiple) {
drawControls[view.layerType].activate();
}
} else {
map.setCenter(new OpenLayers.LonLat(-11174482.03751,4861394.9982606), 4);
drawControls[view.layerType].activate();
}
this.$('.clear').click(function(e) {
e.preventDefault();
view.layers[view.layerType].destroyFeatures();
drawControls[view.layerType].activate();
});
},
Here is the output:
So I found the problem. Twitter bootstrap has a line in its reset file that sets:
img { max-width: 100% }
This was squishing the images. You can fix it by doing:
img { max-width: none; }
I was having the same problem, are you using bootstrap of twitter?
I found out there was a selector for img elements that was affecting the map. I had the next selector into the bootstrap.css"
img {
max-width: 100%;
vertical-align: middle;
border: 0;
-ms-interpolation-mode: bicubic;
}
I don't know whay the parameter max-width: 100%; makes the vertical stripes in my case. I remove the propertie max-width: 100% and now is working.
Setting img { max-width: 100% } to img { max-width:none; } does resolve the problem.
However this will have an unintended effect on images throughout your website. I am also using Bootstrap Twitter's carousel component for images and when I made the above changed the images did not fit in the carousel. Therefore I changed it so that it only targets the images in the OpenLayers / OpenStreetMap div.
div#outlet_map img { max-width:none; }
Related
What is wrong with my map?
Please go to gtob.openfile.ch/mitglieder, click on «A-Z», then on «Screenbox Multimedia Ltd.». Finally click on the button «Show map», than the same map is displayed in three div's. In the middle div, the map is distorted, and i can not find out why... (Responsive design is not finished now, please show with a screen-width of at least 1200 pixels)
Ok, here is the JavaScript/jquery for building the map:
var memberGoogleMapsData = new Object;
memberGoogleMapsData.mapContainer = $(this).closest('div').find('div.memberMap');
$(this).closest('div').find('button').on('click', function() {
memberGoogleMapsData.mapsPosLat = parseFloat(memberGoogleMapsData.mapContainer.data('mapsposlat'));
memberGoogleMapsData.mapsPosLng = parseFloat(memberGoogleMapsData.mapContainer.data('mapsposlong'));
memberGoogleMapsData.mapsZoom = parseInt(memberGoogleMapsData.mapContainer.data('mapszoom'));
memberGoogleMapsData.markerPosLat = parseFloat(memberGoogleMapsData.mapContainer.data('markerposlat'));
memberGoogleMapsData.markerPosLng = parseFloat(memberGoogleMapsData.mapContainer.data('markerposlng'));
memberGoogleMapsData.mapId = memberGoogleMapsData.mapContainer.prop('id');
memberGoogleMapsData.mapPos = new google.maps.LatLng(memberGoogleMapsData.mapsPosLat, memberGoogleMapsData.mapsPosLng);
memberGoogleMapsData.options = {
zoom: memberGoogleMapsData.mapsZoom,
center: memberGoogleMapsData.mapPos,
mapTypeId: google.maps.MapTypeId.HYBRID,
tilt: 0,
heading: 0
};
memberGoogleMapsData.myMap = new google.maps.Map(document.getElementById(memberGoogleMapsData.mapId),memberGoogleMapsData.options);
memberGoogleMapsData.myMap2 = new google.maps.Map(document.getElementById('testMap'),memberGoogleMapsData.options);
memberGoogleMapsData.myMap3 = new google.maps.Map(document.getElementById('testMap2'),memberGoogleMapsData.options);
});
In the div.memberMap I have data-Tags for providing the required data for building the google map:
<div class="memberMap" id="memberMap207" data-mapsposlat="47.50467769999999" data-mapsposlong="9.39942510000003" data-mapszoom="13" data-markerposlat="47.50467769999999" data-markerposlng="9.39942510000003">
You have the following style in the customer.css file
#members div.members img {
float: right;
max-width: 300px;
max-height: 150px;
}
Your first map is inside the div.members, so this style breaks all the tile images of the map as well.
The second map that is outside of div.members is not affected by this style.
I hope it helps!
I'm using MapBox GL JS to create a map with a custom marker:
var marker = new mapboxgl.Marker(container)
.setLngLat([
datacenters[country][city].coordinates.lng,
datacenters[country][city].coordinates.lat
])
.addTo(map);
However, I seem to have some kind of offset problem with the marker. The thing is: when zoomed out a bit, the bottom of the marker is not really pointing to the exact location:
When I'm zooming in a bit further it reaches its destination and it's pointing to the exact spot.
I really love MapBox GL, but this particular problem is bugging me and I'd love to know how to solve it. When this is fixed my implementation is far more superior to the original mapping software I was using.
From Mapbox GL JS 0.22.0 you're able to set an offset option to the marker. https://www.mapbox.com/mapbox-gl-js/api/#Marker
For example to offset the marker so that it's anchor is the middle bottom (for your pin marker) you would use:
var marker = new mapboxgl.Marker(container, {
offset: [-width / 2, -height]
})
.setLngLat([
datacenters[country][city].coordinates.lng,
datacenters[country][city].coordinates.lat
])
.addTo(map);
New solution for mapbox-gl.js v1.0.0 - Marker objects now have an anchor option to set the position to align to the marker's Lat/Lng: https://docs.mapbox.com/mapbox-gl-js/api/#marker
var marker = new mapboxgl.Marker(container, {anchor: 'bottom');
This should cover most cases and is more reliable than a pixel offset in my experience.
I've found an solution to my problem. It might be somewhat hacky, but it solves the positioning problem of the marker: I'm using a Popup fill it with a font awesome map marker icon and remove it's "tooltip styled" borders:
Javascript:
map.on('load', function() {
var container = document.createElement('div');
var icon = document.createElement('i');
icon.dataset.city = city;
icon.addEventListener('click', function(e) {
var city = e.target.dataset.city;
var country = e.target.dataset.country
flyTo(datacenters[country][city].coordinates);
});
icon.classList.add('fa', 'fa-map-marker', 'fa-2x');
container.appendChild(icon);
var popup = new mapboxgl.Popup({
closeButton: false,
closeOnClick: false
})
.setLngLat([
datacenters[country][city].coordinates.lng,
datacenters[country][city].coordinates.lat
])
.setDOMContent(container)
.addTo(map);
});
CSS:
.map div.mapboxgl-popup-content {
background: none;
padding: 0;
}
.map .mapboxgl-popup-tip {
display: none;
}
I just hope someone comes up with a real solution, because this feels kinda dirty to me. But hey: it does the job just fine!
Mapbox Marker now has an element option see this link Mapbox Marker. So instead of appending the icon HTML to the Div element you can simply add into the options when creating a marker. I found this also gets rid of the offset problem. So using the code above you can do this....
var icon = document.createElement('i');
icon.classList.add('fas', 'fa-map-marker-alt');
icon.style.color = 'blue';
new mapboxgl.Marker(container, {anchor: 'center', offset: [0, 0], element: icon})
Also the CSS for the marker can be updated to allow a pointer
.mapboxgl-marker {
border: none;
cursor: pointer;
}
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 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
I'm trying to get an overlay in google maps api v3 to appear above all markers. But it seems that the google api always put my overlay with lowest z-index priority. Only solution i've found is to iterate up through the DOM tree and manually set z-index to a higher value. Poor solution.
I'm adding my a new div to my overlay with:
onclick : function (e) {
var index = $(e.target).index(),
lngLatXYposition = $.view.overlay.getProjection().fromLatLngToDivPixel(this.getPosition());
icon = this.getIcon(),
x = lngLatXYposition.x - icon.anchor.x,
y = lngLatXYposition.y - icon.anchor.y
$('<div>test</div>').css({ left: x, position: 'absolute', top: y + 'px', zIndex: 1000 }).appendTo('.overlay');
}
I've tried every property I could think of while creating my overlay. zIndex, zPriority etc.
I'm adding my overlay with:
$.view.overlay = new GmapOverlay( { map: view.map.gmap });
And GmapOverlay inherits from new google.maps.OverlayView.
Any ideas?
..fredrik
If anyone was having the same problem as I was, here is my problem and solution:
I needed an OverlayView which would add tooltips to markers, but my popup overlay kept showing behind the markers.
I implemented a subclass of the OverlayView as per the Google documentation:
https://developers.google.com/maps/documentation/javascript/customoverlays
When you write your custom OverlayView.prototype.onAdd function, you need to specify to which Pane to attach your overlay. I just copied the code without actually reading the surrounding explanation.
In their code, they attach the overlay to the overlayLayer pane:
var panes = this.getPanes();
panes.overlayLayer.appendChild(div);
But there are many different MapPanes you can use:
"The set of panes, of type MapPanes, specify the stacking order for different layers on
the map. The following panes are possible, and enumerated in the order in which they are stacked from bottom to top:"
MapPanes.mapPane (Level 0)
MapPanes.overlayLayer (Level 1)
MapPanes.markerLayer (Level 2)
MapPanes.overlayMouseTarget (Level 3)
MapPanes.floatPane (Level 4)
I wanted the overlay to hover over all other info on the map, so I used the floatPane pane and problem solved.
So, instead of :
this.getPanes().overlayLayer.appendChild(div)
you use this :
this.getPanes().floatPane.appendChild(div);
You can't change the zIndex of an OverlayView (it has no such property), but it holds panes that contains DOM nodes. That's where you can use the z-index property;
...
lngLatXYposition = $.view.overlay.getPanes().overlayLayer.style['zIndex'] = 1001;
...
In order to be able to play around with the paneType of the mapLabel class, I added a paneType property to the MapLabel class from google utility library (https://code.google.com/p/google-maps-utility-library-v3/source/browse/trunk/maplabel/src/maplabel.js?r=303).
This is usefull to make the label not to be hidden by a polyline.
Please find the code additions to the mapLabel.js file.
MapLabel.prototype.onAdd = function() {
var canvas = this.canvas_ = document.createElement('canvas');
var style = canvas.style;
style.position = 'absolute';
var ctx = canvas.getContext('2d');
ctx.lineJoin = 'round';
ctx.textBaseline = 'top';
this.drawCanvas_();
var panes = this.getPanes();
if (panes) {
// OLD: panes.mapPane.appendChild(canvas)
var paneType = this.get('paneType');
panes[paneType].appendChild(canvas);
}
};
MapLabel = function (opt_options) {
this.set('fontFamily', 'sans-serif');
this.set('fontSize', 12);
this.set('fontColor', '#000000');
this.set('strokeWeight', 4);
this.set('strokeColor', '#ffffff');
this.set('align', 'center');
this.set('zIndex', 1e3);
this.set('paneType', 'floatPane');
this.setValues(opt_options);
}
Sample code using the paneType:
var mapLabel = new MapLabel({
text: segDoc.curr_value.toFixed(0),
position: new google.maps.LatLng(lblLat, lblLng),
map: map.instance,
fontSize: 12,
align: 'center',
zIndex: 10000,
paneType: 'floatPane',
});
Thanks!
Setting z-index to 104 for the overLay layer seems to be the "magic" number" if you care about interacting with the markers (i.e. dragging markers). Any higher than 104 and you can not interact with the markers. Wondering if there is a less brittle solution...
Use panes.overlayMouseTarget.appendChild
If you want to allow your layer to be targetable through mouse clicks (and use events such as "click" or CSS pseudo ::hover) then you should add your overlay to the map using overlayMouseTarget
var panes = this.getPanes();
panes.overlayMouseTarget.appendChild(this.div_);
Also see:
https://developers.google.com/maps/documentation/javascript/reference?csw=1#MapPanes
Disclaimer: this is a dodgy solution that may stop working at any time and you definitely shouldn't use this in production.
For those looking for a quick and dirty solution, this CSS worked for me:
.gm-style > div:first-child > div:first-child > div:nth-child(4) {
z-index: 99 !important;
}
Use at your own risk!