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

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.

Related

MapBox draw Polygon of Feature on Click

So my idea seems pretty straight forward to me but I struggle nevertheless. What I want to do is basically click on any point of my map and draw a polygon on the main feature, i.e. if I click on a park or a building that specific polygon is displayed and highlighted.
I used a lot of this code: https://www.mapbox.com/mapbox-gl-js/example/queryrenderedfeatures-around-point/
But instead of giving it a set of geojson I want my javascript to select to needed geojson data on mousover (eventhough i am not sure whether that works in general). Right now my code snipped compiles but doesn't show anything.
In a later step I want to collect all polygons of the same feature, i.e. all parks, and display them as highlighted polygons and then export them as a svg file which only consists of the map representations of the feature clicked on. Maybe someone has an idea for that as well?
Thanks in regard :)
This is my javascript as of now:
//Set AccessToken from MapBox
mapboxgl.accessToken = 'pk.eyJ1IjoidG1pbGRuZXIiLCJhIjoiY2o1NmlmNWVnMG5rNzMzcjB5bnV3YTlnbiJ9.r0BCga0qhRaHh0CnDdcGBQ';
//Setup starting view point at Uni-Bremen campus
var map = new mapboxgl.Map({
container: 'content-map',
style: 'mapbox://styles/mapbox/streets-v9',
center: [8.85307, 53.10810],
zoom: 16
});
//Add a search bar -> hidden for presentation
/*map.addControl(new MapboxGeocoder({
accessToken: mapboxgl.accessToken
}));*/
//Function to show all Features of a certian point
map.on('mousemove', function (e) {
var features = map.queryRenderedFeatures(e.point);
document.getElementById('features').innerHTML = JSON.stringify(features, null, 2);
console.log(JSON.stringify(features, null, 2));
drawPolygon();
});
//Draw a Polygon
function drawPolygon () {
//set boundary box as 5px rectangle area around clicked point
var bbox = [[e.point.x - 5, e.point.y - 5], [e.pont.x + 5, e.point.y + 5]];
//set the data on pointer using the bbox
var data = map.queryRenderedFeatures(bbox);
map.on('load', function() {
var dataSource = 'school';
//set school to the feature and use 'setJsonData' as data source.
map.addSource(dataSource, {
'type': 'geojson',
'data': data
});
//adding a new layer for the general display
map.addLayer({
'id': 'dataSet',
'type': 'fill',
'source': dataSource,
'source-layer': 'original',
'paint': {
'fill-outline-color': 'rgba(0,0,0,0.1)',
'fill-color': 'rgba(0,0,0,0.1)'
}
}, 'place-city-sm' ); //place polygon under these labels
//adding a new layer for the polygon to be drawn
map.addLeyer({
'id': 'dataSet-highlighted',
'type': 'fill',
'source': dataSource,
'source-layer': 'original',
'paint': {
'fill-outline-color': '#484896',
'fill-color': '#6e599f',
'fill-opacity': 0.75
},
'filter': ['in', 'FIPS', '']
}, 'place-city-sm'); //place polygon under these labels
//action on click to show the polygon and change their color
map.on('click', function (e) {
//retrieve data from 'dataSource'
var dataFromSource = map.queryRenderedFeatures(bbox, {layers: ['dataSource'] });
// Run through the selected features and set a filter
// to match features with unique FIPS codes to activate
// the `counties-highlighted` layer.
var filter = dataSource.reduce(function(memo, dataSource) {
memo.push(dataSource, properties.FIPS);
return memo;
} ['in', 'FIPS'] );
map.setFilter('dataSet-highlighted', filter);
});
});
}
I'm not 100% sure what you're asking, but my interpretation is that you'd like to specifically style certain types of geometry when you hover over them, such as "parks". You're on the right path, where using map.queryRenderedFeatures() is great. I've put together an example using the same Mapbox Streets style that queries only the building layer and looks for type university on mouseover.
When the interaction encounters a proper feature, it updates the source data with the new feature, which then updates the school-hover layer.
Check out the pen here: https://codepen.io/mapsam/pen/oemqKb
In a later step I want to collect all polygons of the same feature, i.e. all parks, and display them as highlighted polygons and then export them as a svg file which only consists of the map representations of the feature clicked on.
I won't go into file exports, but just remember that all results returned from map.queryRenderedFeatures are specific to the single vector tile you are querying, which can lead to issues on tile boundaries where a polygon isn't fully covered by your current query.
Check out this example where we are highlighting features with similar data, which should allow you get all of the necessary geometries and export to SVG.
Cheers!

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

Leaflet map doesn't always load centered the same WMS Tile Layer

I'm developing an app using the Ionic framework with AngularJS and the LeafletJS library.
When I load the map for the first time it displays correctly centered.
But, when I change to another view of the app and return to the map view, the WMS Tile Layer displays displaced from the center, only a little bit of it on the top left corner of the map can be seen.
Here it is the snippet of code that creates the map and loads the WMS Tile Layer:
function crearPlano($scope, $http, infoService, sharedProperties, poisService, createModal) {
var building = localStorage.building,
floor = localStorage.planta,
floor_id = building + floor,
building_id = floor_id.replace(/\./g,"_").toLowerCase();
var parameters =
[
'proyecto/ows',
'service=WFS',
'version=1.0.0',
'request=GetFeature',
'typeName=proyecto:'+building_id,
'srsName=epsg:4326',
'outputFormat=application/json'
]
var url = APP_CONSTANTS.URI_Geoserver_1 + 'proyecto/ows?' + parameters.join('&');
$.ajax({
url : url,
type: 'GET',
dataType : 'json',
crossDomain: true,
headers: { 'Access-Control-Allow-Origin': '*' },
success: function(data) {
handleJson(data, sharedProperties, poisService, createModal, function(map){
sharedProperties.setMap(map);
});
}
});
function handleJson(data, floor_id, sharedProperties, poisService, createModal, callback) {
console.log("handleJson", data, floor_id);
var map = sharedProperties.getMap(),
coordinates = data.features[0].geometry.coordinates[0][0][0],
floorCoordinates = new L.latLng(coordinates[1], coordinates[0]);
//Remove previous plan layers
if(!(typeof map == 'undefined')) { map.remove(); }
var imageLayer = new L.tileLayer.wms(APP_CONSTANTS.URI_Geoserver_2 + "sigeuz/wms",
{
layers: 'sigeuz:vista_plantas',
maxZoom: 25,
zIndex: 5,
viewparams : 'PLANTA:'+floor_id,
format: 'image/png', transparent: true, attribution: floor_id
});
console.log("Before create map --> Center", JSON.stringify(floorCoordinates));
console.log("Before create map --> MaxBounds", JSON.stringify(L.geoJson(data).getBounds()));
map= new L.map('plan'
,{
crs: L.CRS.EPSG3857,
layers: [imageLayer]
}
).setView(floorCoordinates, 20);
console.log("After create map --> Center", JSON.stringify(plano.getCenter()));
console.log("After create map --> Bounds", JSON.stringify(plano.getBounds()));
callback(map);
}
}
Why is the map loading centered only the first time, but displaced after?
I've added some console logs to the code in order to debug data passed as parameters to the map's creation and map's data after its creation. This way I can compare if something has changed in both situations described earlier. This is the result:
Before create map --> Center {"lat":41.64063807836347,"lng":-0.90146666131869}
Before create map --> MaxBounds {"_southWest":{"lat":41.64061302810611,"lng":-0.9015017606364195},"_northEast":{"lat":41.64079735418267,"lng":-0.9012732012812255}}
After create map --> Center {"lat":41.6406381751715,"lng":-0.9014656782889374}
After create map --> Bounds {"_southWest":{"lat":41.64032848115259,"lng":-0.9017432869219788},"_northEast":{"lat":41.640947867702096,"lng":-0.9011880696558963}}
Before create map --> Center {"lat":41.64063807836347,"lng":-0.90146666131869}
Before create map --> MaxBounds {"_southWest":{"lat":41.64061302810611,"lng":-0.9015017606364195},"_northEast":{"lat":41.64079735418267,"lng":-0.9012732012812255}}
After create map --> Center {"lat":41.64063807836347,"lng":-0.90146666131869}
After create map --> Bounds {"_southWest":{"lat":41.640637639043334,"lng":-0.9014663100242616},"_northEast":{"lat":41.640637639043334,"lng":-0.9014663100242616}}
As can be seen, data passed as center point and max bounds to the map creation is the same in both cases, but once the map has been created, center of the map coordinates and bounds differ a little bit from the first situation to the second one.
I don't quite understand why it changes.
Run invalidateSize() every time the map container potentially changes size. This includes hiding/displaying it via jquery, ionic, and the like.

how to integrate a pair of fusion tables with GroundOverlays from a KML file? Updated with my attempt to solve (unsuccessful)

Short version of my question:
How do I integrate a pair of Google Maps fusion tables (polygons and markers) with GroundOverlays from a KML file? Everything clickable.
Background:
I am working on an interactive history mapping project that uses 2 layers of fusion tables (one layer is polygons, the other is location markers).
I also want to overlay old maps via GroundOverlay -- which is not presently possible with fusion tables -- and so I have been experimenting with GroundOverlay in a KML file.
I've complicated it by adding listeners on both the pages to control click boxes.
I have two webpages:
1. the fusion tables and
2. the KML groundoverlays,
both working fine.
What I want to do is integrate them into a single page. I am not a programmer and don't understand JS well enough to make this happen.
The scripting used was all adapted from examples found online.
Here is my first working page:
http://wendysmithtoronto.com/mapping/townofyork-fusiontables2.html
You'll find a link to the second page there.
Your help would be greatly appreciated.
Thank you.
Wendy
Update:
Here's my effort to merge my two sets of data:
http://wendysmithtoronto.com/mapping/townofyork-merged.html
I tried to do this by adding bits of script from the kmlmaps page into the fusiontables page, but clearly I didn't put things in the right place. Or am missing bits of punctuation (or mixing up different types of scripting, or?)
The map appears, with the polygons and the markers both properly appearing. But now (1) the fusion table icons aren't clickable, and (2) the history maps don't appear. However, the fusion table checkboxes (in blue table) DO work.
I don't understand JS well enough to figure it out.
The two sets of controls from the two pages are both here (in the blue and grey boxes, just above the map). Each set of controls (listeners & click boxes) worked fine in its own wepage but now only the fusion tables controls work.
Eric, thanks for having a look at this! (I just now found your reply. I've been watching for a reply notification but wasn't checking the right place.)
Cheers,
Wendy
Your html file had significant errors in the javascript portions. You really should study up on same basic javascript and in particular using JS with the GMap API.
You created 2 global map objects. You did not encapsulate all your map and layer creations within you initialize function(). All map and layer creation must be done within the initialize (on body load) function. You must set globals outside your initialize function, e.g. the map, all the layers, etc. Finally you were failing to call layer.setMap(map) on 2 of your KML layers.
Despite all this I fixed your file, really just re-arranging things. This is just the section I had to fix. Moved everything into the initialize()
function showbuildings(buildingcheck) {
if (buildingcheck.checked == true)
{
campusmap.setMap(map);
} else {
campusmap.setMap(null);
}
}
function showphilpotts(philpottscheck) {
if (philpottscheck.checked == true)
{
philpotts.setMap(map);
} else {
philpotts.setMap(null);
}
}
function showbeartrail(beartrailcheck) {
if (beartrailcheck.checked == true)
{
beartrail.setMap(map);
} else {
beartrail.setMap(null);
}
}
var infoWindow = new google.maps.InfoWindow();
function openIW(FTevent) {
// infoWindow.setContent(FTevent.infoWindowHtml);
// infoWindow.setPosition(FTevent.latLng);
infoWindow.setOptions(
{
content: FTevent.infoWindowHtml,
position: FTevent.latLng,
pixelOffset: FTevent.pixelOffset
});
infoWindow.open(map);
}
// Globals
//Begin map parameters
var map;
var layer_2;
var layer_1;
var tableid_1 = 2920040; // polygons
var tableid_2 = 3189980; // houses
var zoom = 12;
var center = new google.maps.LatLng(43.652417455515476, -79.37926607055226);
var campusmap;
var philpotts;
var beartrail;
function initialize() {
map = new google.maps.Map(document.getElementById('map_canvas'), {
center: center,
zoom: zoom,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
//End map parameters
campusmap = new google.maps.KmlLayer('http://wendysmithtoronto.com/mapping/1851mapshoreline.kml', {preserveViewport:true, suppressInfoWindows:true});
campusmap.setMap(map);
google.maps.event.addListener(campusmap, 'click', function(kmlEvent) {
document.getElementById('sidebarinfo').innerHTML = kmlEvent.featureData.description;
});
philpotts = new google.maps.KmlLayer('http://wendysmithtoronto.com/mapping/1818maplieutphilpottsd.kml', {preserveViewport:true, suppressInfoWindows:true});
google.maps.event.addListener(philpotts, 'click', function(kmlEvent) {
document.getElementById('sidebarinfo').innerHTML = kmlEvent.featureData.description;
});
philpotts.setMap(map);
beartrail = new google.maps.KmlLayer('http://wendysmithtoronto.com/mapping/1842map-jamescaneb.kml', {preserveViewport:true, suppressInfoWindows:true});
google.maps.event.addListener(beartrail, 'click', function(kmlEvent) {
document.getElementById('sidebarinfo').innerHTML = kmlEvent.featureData.description;
});
beartrail.setMap(map);
layer_2 = new google.maps.FusionTablesLayer({
suppressInfoWindows:true,
query: {
select: 'Location',
from: '3189980'
},
styles: [
{where: "'style' = 14", markerOptions:{ iconName:"star"}},
{where: "'style' = 13", markerOptions:{ iconName:"wht_pushpin"}},
{where: "'style' = 11", markerOptions:{iconName:"red_blank"}}, //town houses
{where: "'style' = 12", markerOptions:{ iconName:"orange_blank"}}, //country homes
{where: "'style' = 15", markerOptions:{ iconName:"target"}},
]});
layer_1 = new google.maps.FusionTablesLayer({
suppressInfoWindows:true,
query: {
select: 'Location',
from: '2920040'
}}),
google.maps.event.addListener(layer_1, "click", openIW);
google.maps.event.addListener(layer_2, "click", openIW);
google.maps.event.addListener(map, "click", function() { infoWindow.close();});
layer_1.setMap(map);
layer_2.setMap(map);
} // end initialize

Targeting and/or modifying a KML region in OpenLayers

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);
}
});

Categories

Resources