Targeting and/or modifying a KML region in OpenLayers - javascript

I've built several Javascript applications for map charts using google maps, and I was hoping to recreate these in OpenLayers. I'm finding the documentation on their site pretty confusing and tough to navigate.
So far, I'm able to load in my KML, using the following code:
var map = new OpenLayers.Map({
div: divName,
layers: [
new OpenLayers.Layer.OSM(),
new OpenLayers.Layer.Vector("KML", {
strategies: [new OpenLayers.Strategy.Fixed()],
protocol: new OpenLayers.Protocol.HTTP({
url: "data.kml",
format: new OpenLayers.Format.KML({
extractStyles: true,
extractAttributes: true,
maxDepth: 4
})
})
})
],
zoom: 4
});
map.setCenter(
new OpenLayers.LonLat(-97, 38).transform(
new OpenLayers.Projection("EPSG:4326"),
map.getProjectionObject()
), 4
);
What I'd like to do is be able to modify or target the individual KML regions. For example, just attaching a click event, or changing the background color of the region.
I've looked around and can't seem to find a good example.
I have jQuery loaded also if that helps.
Any help would be greatly appreciated.

You could add events to OpenLayers maps using the OpenLayers.Control.SelectFeature object
To change the background of the objects something like this should work
var myVectorLayer = map.getLayersByName("KML")[0];
var highlightCtrl = new OpenLayers.Control.SelectFeature(myVectorLayer , {
hover: true,
highlightOnly: true,
renderIntent: "temporary"
});
var selectCtrl = new OpenLayers.Control.SelectFeature(myVectorLayer ,
{clickout: true}
);
map.addControl(highlightCtrl);
map.addControl(selectCtrl);
To fire further events / get more details from the selected features you can employ
myVectorLayer.events.on({
"featureselected": function (e) {
alert(e.type + " - " + e.feature.id);
}
});

Related

Is it possible to specify which ArcGIS base-maps to use for the ESRI basemap gallery (ArcGIS API)?

Is it possible to specify which ArcGIS base-maps to use for the ESRI base-map gallery (esri/dijit/BasemapGallery)?
Setting showArcGISBasemaps to true brings back all of them but I only want a select few e.g. "road", "national-geographic" and "satellite".
var basemapGallery = new BasemapGallery({
showArcGISBasemaps: true,
map: map,
}, "myPlaceHolder");
Looking through the documentation (https://developers.arcgis.com/javascript/3/jsapi/basemapgallery-amd.html) I can't seem to find anything.
Alternatively, is it possible to create these layers individually after setting showArcGISBasemaps to false?
You can specify the basemaps in the params.basemaps object when you create the BasemapGallery: new BasemapGallery()
There's a code sample in that link too. Good luck!
Turns out I had to locate the layers manually after finding them on the ArcGIS services: http://server.arcgisonline.com/ArcGIS/rest/service
var greyLayer = new esri.dijit.BasemapLayer({
url: "http://server.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer"
});
var greyBasemap = new esri.dijit.Basemap({
url: [greyLayer],
id: "mybaselayerId",
title: "Grey"
});
basemaps.push(greyBasemap);
var basemapGallery = new BasemapGallery({
showArcGISBasemaps: false,
basemaps: basemaps,
map: map,
}, "myPlaceHolder");
There doesn't seem to be an option to filter the basemaps returned from showArcGISBasemaps

Mapbox marker click event in Ionic 2 / Angular 2

I'm getting started with Ionic 2 / Angular 2 and trying to implement Mapbox into my app.
To display custom markers (code example here) Mapbox expects a DOM element, which, as far as I understand it, is not really the Angular way. I want to add a click event on the marker but because Mapbox uses elements, I'm not entirely sure how to approach this cleanly "the Angular way".
Basically, this is the latest version (showing the map and the marker works, but predictably when I click the marker the event listener can't find this.onMarkerClicked):
export class HomePage {
//(...)
refreshMapPosition() {
/*Initializing Map*/
mapboxgl.accessToken = this.config.mapbox_public_token;
this.map = new mapboxgl.Map({ /*https://www.mapbox.com/mapbox-gl-js/api/#map*/
style: 'mapbox://styles/mapbox/light-v9',
center: [this.Coordinates.longitude, this.Coordinates.latitude],
zoom: 16,
pitch: 80,
minZoom: 7.5,
maxZoom: 17,
container: 'map',
interactive: false,
});
var elCreature = document.createElement('div');
elCreature.className = 'icon-creature alpaca';
elCreature.addEventListener('click', function() {
this.onMarkerClicked();
});
var markerCreature = new mapboxgl.Marker(elCreature, {offset: [-20, -20]})
.setLngLat([this.Coordinates.longitude, this.Coordinates.latitude])
.addTo(this.map);
}
onMarkerClicked() {
console.log("click");
}
}
I'd be much happier if it was possible to have elCreature coming from a component, where I could use <div class="icon-creature alpaca" (click)="onMarkerClicked"></div>. What's the best approach there?
// on your marker HTML
var _self = this;
var _data = this.value;
el.addEventListener('click', function() {
self.markerClicked(_data);
});
// angular method
markerClicked(value){
console.log(value);
}
So I found something that maybe could help you, I created a marker as the documentation mentioned and then I got the element of that market with the getElement() function, after that I added the event to the marker, I do not know if it works with various markers but you can try.
var marker = new mapboxgl.Marker()
.setLngLat([lng, lat])
.addTo(this.map);
marker.getElement().addEventListener("click", function(){
console.log("function");
});
After sleep a while I found that there another thing that you can use, so you can create a Popup first and then add that Popou to a Marker object with the setPopup() method and actually it like an onClick event, because, when you click the Marker the Popup appears. Here is an example.
var popup = new mapboxgl.Popup()
.setLngLat(coordinates)
.setHTML("<h1>Hello</h1>");
var marker = new mapboxgl.Marker()
.setLngLat(coordinates)
.setPopup(popup)
.addTo(this.map);
The variable "coordinates" is an array, such that coordinates = [lng,lat], and this.map is just a variable under my Angular class that call to the mapboxgl.Map object.
You have to know that I am using Ionic 4 in this case. If you need more information please tell me.
Regards.

Selecting map objects using ol.source.TileWMS in open layers 3

I am using open layers 3,
and I am using this code for displaying the map:
wmsSource = new ol.source.TileWMS({
url: 'http://demo.boundlessgeo.com/geoserver/wms',
params: { 'LAYERS': 'ne:ne' },
serverType: 'geoserver',
crossOrigin: ''
});
var wmsLayer = new ol.layer.Tile({
source: wmsSource
});
I am using dragbox to make the rectangular selection and when I do the shift + drag I am not able to select the objects in map. Can somebody please help me on how to achieve it?
This is the code I am using for rectangular selection.
dragBox.on('boxend', function(e) {
// features that intersect the box are added to the collection of
// selected features, and their names are displayed in the "info"
// div
var info = [];
var extent = dragBox.getGeometry().getExtent();
wmsSource .forEachFeatureIntersectingExtent(extent, function(feature) {
selectedFeatures.push(feature);
info.push(feature.get('name'));
});
if (info.length > 0) {
infoBox.innerHTML = info.join(', ');
}
}); `
You use a TileWMS source, which is a collection of images (tiles) rendered on the WMS server. OpenLayers does not know about the features used to render the images. Because of this, forEachFeatureIntersectingExtent is only available on vector sources.
You could create a WMS getFeatureInfo-request in the boxend callback, to load the feature information from the server.
Alternatively, you could create a vector source containing the features you want and use for the forEachFeatureIntersectingExtent call.

OpenLayers WMS layer doesn't load

I use the following block of JavaScript to try to show a WMS layer. I'm using OpenLayers 2.8.
The map's base layer (Openstreetmap) shows correctly, it zooms to the correct area, the "pyramid" layer is shown in the layer switcher, but no request to its WMS service is ever made (so the fact that the URL, styles and params are dummies shouldn't matter -- it never even attempts to get them).
OpenLayers does try to get a WMS layer once I pan or zoom far enough so that the Gulf of Guinea is in view (but all my data is in the Netherlands). This suggests a projection problem (WGS84's (0, 0) point is there), but I don't understand why OpenLayers doesn't even try to fetch a map layer elsewhere. My data is in EPSG:3857 (Web Mercator) projection.
/*global $, OpenLayers */
(function () {
"use strict";
$(function () {
$(".map").each(function () {
var div = $(this);
var data_bounds = div.attr("data-bounds");
console.log("data_bounds: " + data_bounds);
if (data_bounds !== "") {
var map = new OpenLayers.Map(div.attr("id"), {
projection: "EPSG:3857"});
var extent = JSON.parse(data_bounds);
var bounds = new OpenLayers.Bounds(
extent.minx, extent.miny,
extent.maxx, extent.maxy);
map.addLayer(
new OpenLayers.Layer.OSM(
"OpenStreetMap NL",
"http://tile.openstreetmap.nl/tiles/${z}/${x}/${y}.png",
{buffer: 0}));
map.addLayer(
new OpenLayers.Layer.WMS(
"pyramid", "http://rasterserver.local:5000/wms", {
layers: "test",
styles: "test"
}, {
singleTile: true,
isBaseLayer: false,
displayInLayerSwitcher: true,
units: 'm'
}));
map.addControl(new OpenLayers.Control.LayerSwitcher());
map.zoomToExtent(bounds);
}
});
});
})();
Edit: the 'data_bounds' console print prints (with some added formatting):
data_bounds: {
"minx": 582918.5701295201,
"miny": 6923595.841021758,
"maxx": 821926.9006116659,
"maxy": 7079960.166533174
}
It zooms to the correct region in the north of the Netherlands, so I don't think the problem is there.
Since posting, I found out that if I don't use the OSM layer, and instead use the WMS layer as baselayer, it works. So perhaps there's some incompatibility with a OSM baselayer and a WMS layer added to it? But then I don't get that it does seem to do something near WGS84 (0, 0).
I eventually managed to fix this by giving the map an explicit maxExtent:
var extent = JSON.parse(data_bounds);
var bounds = new OpenLayers.Bounds(
extent.minx, extent.miny,
extent.maxx, extent.maxy);
var map = new OpenLayers.Map(div.attr("id"), {
projection: "EPSG:3857",
maxExtent: bounds
});
Oddly enough this doesn't limit the user's ability to pan and zoom around the world, but it does make the overlay work...

Display WMS Layer Based on Zoom Level

I've been at this all day long and honestly I'm out of ideas. I have some WMS layers that I would like to display/not display depending on the current zoom level. Yes, I have went through the API docs and they seem to be clear as day, but I follow everything that is suggested and I'm not getting the results desired :(
This was one of the sources that I looked at:
http://trac.osgeo.org/openlayers/wiki/SettingZoomLevels
Then to make matters even worse I found out that if you have an Open Street Map base layer displaying on load it seems to limit your control over the map's numZoomLevels, just what I needed, since I DO want to use this as my loading base layer...
So my questions are:
What am I doing wrong?
Is it true that there really is no workaround on the control of zoom levels when using an Open Street Map base layer on load? Or is there something I just don't know?
Here are some of my code attempts:
Take 1: tib_villages layer should only show when the zoom level is 8-10, doesn't work!
var options = {
controls: [new OpenLayers.Control.Navigation()], //Needed to use GeoExt controls such as the zoomslider
maxExtent: new OpenLayers.Bounds(-20037508.34, -20037508.34, 20037508.34, 20037508.34),
units: 'm',
numZoomLevels: null, //setting the map's zoom levels to null
allOverlays: false
}
var osm = new OpenLayers.Layer.OSM(); //MY base layer
//MY overlay layer
var tib_villages = new OpenLayers.Layer.WMS(
"Villages", "http://localhost:8080/geoserver/wms", {layers: 'cite:tib_villages', transparent: true, numZoomLevels: 10, minZoomLevel: 8}, {isBaseLayer: false, displayInLayerSwitcher: true, visibility: true}
);
Take 2: tib_villages layer should only show when the zoom level is 8-10, map should only have 10 zoom levels, but instead has 19 as the Open Street Map Layer enforces it to, doesn't work!
var options = {
controls: [new OpenLayers.Control.Navigation()], //Needed to use GeoExt controls such as the zoomslider
maxExtent: new OpenLayers.Bounds(-20037508.34, -20037508.34, 20037508.34, 20037508.34),
units: 'm',
numZoomLevels: 10, //setting the map's zoom levels to 10 only
allOverlays: false
}
var osm = new OpenLayers.Layer.OSM(); //MY base layer
//MY overlay layer
var tib_villages = new OpenLayers.Layer.WMS(
"Villages", "http://localhost:8080/geoserver/wms", {layers: 'cite:tib_villages', transparent: true, numZoomLevels: null, minZoomLevel: 8}, {isBaseLayer: false, displayInLayerSwitcher: true, visibility: true}
)
;
Take 3: After getting rid of the Open Street Map base layer on load, the map only has 10 zoom levels as specified, but tib_villages layer should only show when the zoom level is 8-10, doesn't work!
var options = {
controls: [new OpenLayers.Control.Navigation()], //Needed to use GeoExt controls such as the zoomslider
maxExtent: new OpenLayers.Bounds(-20037508.34, -20037508.34, 20037508.34, 20037508.34),
units: 'm',
numZoomLevels: 10, //setting the map's zoom levels to 10
allOverlays: false
}
//MY overlay layer
var tib_villages = new OpenLayers.Layer.WMS(
"Villages", "http://localhost:8080/geoserver/wms", {layers: 'cite:tib_villages', transparent: true, numZoomLevels: 10, minZoomLevel: 8}, {isBaseLayer: false, displayInLayerSwitcher: true, visibility: true}
);
All of your suggestions are sincerely appreciated!
elshae
Try to use minResolution and maxResolution instead of minZoomLevel. It usually works fine. You can get resolution for any zoom lever if you call map.getResolution() method.
Another option is to listen to OpenLayers.Map's zoomend event and toggle layer visibility accordingly. Something like this:
map.events.on({ "zoomend": function (e) {
if (this.getZoom() > 2) {
layer1.setVisibility(false);
layer2.setVisibility(true);
}
else {
layer2.setVisibility(false);
layer1.setVisibility(true);
}
}
});
I would recommend using the maxScale and minScale on the layers instead of resolution, but that maybe is a question of taste. :-) I can't relate to a resolution value, but a scale is easy to understand and to maintain in the longer run, when others look at your code.

Categories

Resources