I currently have features on an ol.source.Vector that I would like to find by drawing a box (MultiPolygon) on the screen. I currently have this functionality working, however, if I move onto the next rendered world ("spin the globe" so to speak) when I draw my box over the same set of rendered features I get nothing back.
Example code:
var featureSource = new ol.source.Vector({
url: '/ShinyService/feature/geoJson',
format: new ol.format.GeoJSON()
});
var featureLayer = new ol.layer.Vector( {
source: featureSource
});
var myMap = new ol.Map({
layers: [ featureLayer],
view: new ol.View({
minZoom: 3,
maxZoom: 10
});
});
//Later within interaction event (draw end)
var boxExtent = box.getGeometry().getExtent();
vectorSource.forEachFeatureInExtent(boxExtent, function(feature){
foundFeature.push(feature.getId());
});
I'm currently thinking the only "solution" to this is to no longer allow the world to be rendered multiple times, but I don't think this is an option for the requirement I'm trying to fulfill.
I'm currently using Openlayers v3.18.2
Any help would be appreciated!
I was able to figure my problem out. It turned out I had to "wrap" the coordinates of my extent in order to get it to work properly as they were going past the -180 to 180 boundary. Once I did this every thing seemed to work.
However, this feels like something that should already be done in Openlayers so there could be something else I could be missing.
Related
Basically, what I have is a geolocation data (longtitude and latitudes) of 300.000 locations. I have different attributes attached to the data and it is approx. 32MB. Reading it through js and putting markers on google maps is what I've tried, and It works OK when i put only 25 to 2500 markers on my map, I cant really put all of my locations at once. Eventually I want to be able to filter markers through the attributes etc. The locations are all at one city, so I might use my own map or something.
What I want to ask/learn is do you have any better solutions for this particular situation?
Here is my code.
function initJS() {
var promise = getData();
var locations1;
var locations;
promise.success( (data) => {
locations1 = parseData(data);
locations = locations1.filter(location => {
return location.DuyuruTipi == "16";
});
//initializing google map
map = new google.maps.Map(document.getElementById("map"), {
center: { lat: latitude, lng:longtitude},
zoom: zooming,
});
//creating a marker
const svgMarker = {
// path: "M10.453 14.016l6.563-6.609-1.406-1.406-5.156 5.203-2.063-2.109-1.406 1.406zM12 2.016q2.906 0 4.945 2.039t2.039 4.945q0 1.453-0.727 3.328t-1.758 3.516-2.039 3.070-1.711 2.273l-0.75 0.797q-0.281-0.328-0.75-0.867t-1.688-2.156-2.133-3.141-1.664-3.445-0.75-3.375q0-2.906 2.039-4.945t4.945-2.039z",
url: "./assets/marker.svg",
size: new google.maps.Size(20,20),
scaledSize: new google.maps.Size(20,20),
origin: new google.maps.Point(0, 0),
anchor: new google.maps.Point(10, 10),
};
for (var i = 0; i < locations.length; i++) { //locations.length
// init markers
var marker = new google.maps.Marker({
position: { lat: parseFloat(locations[i]["YCoor"]), lng: parseFloat(locations[i]["XCoor"])},
map: map,
label: locations[i]["DuyuruId"],
icon: svgMarker
});
console.log(locations[i]["DuyuruTipi"]);
marker.duyurutipi = locations[i]["DuyuruTipi"];
marker.kazatipi = locations[i]["KazaTipi"];
marker.vsegid = locations[i]["vSegID"];
markers.push(marker);
}
});
Displaying 300000 points directly on the map is not the correct approach and will not perform well, especially as more datasets get added to your map.
In addition, sending 32MB of data or more to the browser is bad form, even for a web map application. If you try out e.g. Google Maps with the network panel open, you'll see that you'll barely go over a few MB even after quite some time using it.
There are a couple approaches that web mappers take to counter this:
Use a service such as Geoserver or Mapserver to split up the data into "chunks" based on what is in the the map clients (openlayers, in your case, according to your answer) viewport. This is the best choice if you could potentially have lots of layers or basemaps in future, but is a lot of work to setup and configure.
Write your own implementation of the above in your back-end. For points, this is relatively simple. This is the best choice for something quick with just a couple of points layers.
In both cases, you'll need to configure your points layer in OpenLayers to use the "bbox" strategy, which will tell it to call your API url whenever the viewport changes enough for more features to be loaded. You will also need to set the minimum resolution for your layer so that it doesn't load too many features all at once when zoomed out.
Lastly, with Openlayers, you'll want to use a VectorImageLayer with a VectorSource for this layer, which will improve performance a lot while allowing you to query and edit your point data.
The above should help to improve your mapping performance.
Well, I went with the OpenLayers API, I think it is harder to implement stuff from docs but they have example applications for every feature. You might want to try that, way better performance if your only need is to put some markers and visualize data.
As you can see in the below living atlas layer, there are multiple layers inside (state,county,tract etc..)
But when I add this link, it will display only the first layer.(State). Then, when I zoom in the map, that layer disappears.
I want to display all the 4 layers of that feature service.(state,county, tract, blockgroups)
How do I achieve this?
.ts
const genderLayer = new FeatureLayer({
url: "https://services2.arcgis.com/FiaPA4ga0iQKduv3/ArcGIS/rest/services/US_Census_Age_Gender/FeatureServer",
});
const layersToCreateMyPopupTemplate = [ageLayer,genderLayer];
const map = new Map({
basemap: 'topo-vector',
layers: layersToCreateMyPopupTemplate
});
const view = new MapView({
container,
map: map,
zoom: 3,
center: [-97.63, 38.34],
});
.html
<!-- Map Div -->
<div #mapViewNode></div>
The issue you are having is that,
you are trying to use FeatureLayer with the whole map service, that means in that service you have 4 FeatureLayers, one for each layer of the service,
state https://services2.arcgis.com/FiaPA4ga0iQKduv3/ArcGIS/rest/services/US_Census_Age_Gender/FeatureServer/0
county https://services2.arcgis.com/FiaPA4ga0iQKduv3/ArcGIS/rest/services/US_Census_Age_Gender/FeatureServer/1
tract https://services2.arcgis.com/FiaPA4ga0iQKduv3/ArcGIS/rest/services/US_Census_Age_Gender/FeatureServer/2
block group https://services2.arcgis.com/FiaPA4ga0iQKduv3/ArcGIS/rest/services/US_Census_Age_Gender/FeatureServer/3
it disappear because the state layer, the first one (number 0), it is only visible until Max. Scale: 20000001
That type of service it is made on purpose in that way, to make it efficient (easy to understand) and with good performance. That is, it shows what it need to show at each scale.
Usually is better to display using MapImageLayer or similar and then query the using the feature service. Sadly, in this case it does not offer that kind of service (MapServer), so you will have to creat four FeatureLayer, one for each.
EDIT: I changed the center of the map by user-input before but changed this for testing. Using a fixed center for my map, everything is fine. Question now is: why?
I am looping through a JSON with some features, extracting the coordinates for each feature, and add them to a map.
So far everything is working fine, but I just noticed that the features or better the icons are moving when I am zooming out/in or moe left/right.
The feature location should still be true since I am able to hover over the map and show an overlay (as intended).
I have no idea why the logos would behave like this, maybe someone can help me. Here is my code for one of the layers:
///////////////
// Forst
var Forststyle = new ol.style.Style({
image: new ol.style.Icon({
src: 'images/tree.png'
})
});
var Forstsource = new ol.source.Vector();
$.getJSON('config/Forst.json', function (data) {
$.each(data, function(key, val){
var newMarker = new ol.Feature({
geometry: new ol.geom.Point([this.long, this.lat]),
pointAttributes: {
'Name': this.name,
'Strasse':this.Straße,
}
});
Forstsource.addFeature(newMarker);
});
});
var Forst = new ol.layer.Vector({
title: "Forst",
visible: false,
zIndex: 5,
style: Forststyle,
source: Forstsource});
I am adding the Forst-Layer to the layers of my map.
I thought my projection/view definition might be helpful.
var projection25832 = new ol.proj.Projection({
code: 'EPSG:25832',
// The extent is used to determine zoom level 0. Recommended values for a
// projection's validity extent can be found at https://epsg.io/.
extent: [-1877994.66, 3932281.56, 836715.13, 9440581.95],
units: 'm'
});
I am adding my whole map-call. center and zoom get defined by user-input.
var map = new ol.Map({
target: 'map',
layers:[
new ol.layer.Tile({
title: 'OSM (grau)',
visible: true,
source: new ol.source.TileWMS({
url: 'https://ows.terrestris.de/osm/service?',
params: {
'LAYERS': "OSM-WMS",
'VERSION': '1.1.0',
'FORMAT': 'image/png',
'TILED': false
}
})
}),
Schaefer,
KMR,
GaLaBauSA,
GaLaBauBBG,
Forst,
Lohnunternehmen
],
view: new ol.View({
projection: projection25832,
center: center,
zoom: zoom
})
});
I am adding some images, view1 and view2 are only changed by scrolling left/right, view3 is zoomed in.
Some more edits:
As stated above, when I am using a fixed center everything is working as intended. However, changing it depending on User Input is not working.
var D = $.ajax({
type: "GET",
url: url,
dataType: "json"
}).done(function(){
var Coords = D.responseJSON.results[0].locations[0].latLng;
var utm = "+proj=utm +zone=32";
var new_center = [proj4("WGS84",utm,[Coords.lng, Coords.lat])[0],proj4("WGS84",utm,[Coords.lng, Coords.lat])[1]];
console.log(new_center);
CreateMap([new_center[0], new_center[1]],zoom);
$("#Hintergrund").hide();
});
}
My CreateMap function is taking the coordinates of the center and the zoom, the url is a WEB-API (mapquest) that turns input into coordinates. If I pass e.g. my home-zip-code I get the coordinates that are used as my fixed center in the log, so there should not be a problem with the coordinates right?
Your image moving on zoom, because it automatically scales so the size would be readable regarding the zoom level (It doesn't stick to the map) You would need to anchor the center of the image elsewhere.
To anchor the center image you must play around with offsets.
You can, play with offsets and image size itself with openlayers style class. I dont know which version you are using, so you most likely will have to read about it in the documentation or some other examples, but hare is one.
new ol.style.Style({
image: new ol.style.Icon(({
anchor: [0, 0],
anchorXUnits: "pixels",
anchorYUnits: "pixels",
offset: [0,0],
offsetOrigin: 'bottom-left',
rotation: 0,
src: 'images/tree.png'
}))
});
Setting anchor to 0,0 will be top left if Im not mistaken, you most likely will have to set it to 0, {Half width}
Basically, when you scroll and zoom, OpenLayers adjusts your image scaling from its center point, so in theory it will move if the center point isnt for example at the bottom.
If that doesn't help, see if you have correct projections.
And if that doesn't help, try creating "Markers" instead of points, I don't recall but one of them has way more control flow going.
I imagined it moved by tiny bit, seems like it drastically moves. Might be projections fault. Try to use projection: 'EPSG:4326' if your coordinates are in different one, you can convert it with
.transform(new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913"))
I noticed you create projection manualy, not sure if thats the best approach. Check out this one.
https://openlayers.org/en/latest/examples/epsg-4326.html
Its using 4326. It is always better to use openlayers projection and if you have coordinates built differently, transform them to your needed ones.
To debug this, you can try to draw a linestring on a map (WKT/Polyline) if that changes on zoom, your problem is definitely in projections, if not, then it might be something else.
I was working with openlayers recently as well. And ran into the same problem, which I made by add
style.graphicXOffset= 15;
style.graphicYOffset= 28;
Set these to 0, should help.
So I have (or had) a working version of OpenStreetMaps, but now that I want to add popups onto the map, the whole thing breaks. This is the code pertaining to the issue of the popup. The crazy thing is that I copy and pasted the code from the official wiki in order to just get a working example.
function init() {
map = new OpenLayers.Map( 'heatmapArea');
var query = new OpenLayers.LonLat(-122.2928337167, 37.5549570333).transform(
new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());
var popup = new OpenLayers.Popup.FramedCloud("Popup", query, null, "Text", null, true);
map.addPopup(popup, false);
var lat = 39.3138895;
var lon = -98.2233523;
var zoom = 4;
var position = new OpenLayers.LonLat(lon, lat).transform( EPSG_WGS84, EPSG_900913);
map.setCenter(position, zoom );
}
The issue as it appears in my browser console is:
I have removed the code which I don't think is relevant to this issue but I could provide more if that is necessary. I have googled around extensively and all of the examples that I find work fine on the website I visit, but breaks my map and every StackOverflow answer to somebody else seems to work fine for the original poster, but once again, breaks my map.
Here's one of the website I tried to copy:
http://www.rigacci.org/openlayers/other_examples/markers.html
I am very eager to get this problem solved and any help would be greatly appreciated. Thanks!
-C.J.
Someone who really knows their way around the OL API will be able to explain this properly, but basically, your code is fine, but you need to reorder it. You need to add a map layer, and zoom to an extent, before you can call addPopup. I think this is because addPopup doesn't need an explicit layer of its own; it uses the map layer; and therefore you need a map layer on your map before trying to use it. That makes sense, but I am not sure why you need also to have called a zoom/zoomToExtent function.
Here's a fiddle, I've tried to leave your code as unchanged as possible:
http://jsfiddle.net/sifriday/u3j6h97d/3/
And here's the JS with some comments:
function init() {
var map = new OpenLayers.Map( 'heatmapArea');
// Add a map layer before trying to use addPopup
map.addLayer(new OpenLayers.Layer.OSM());
// Call the zoom function before trying to use addPopup
var lat = 39.3138895;
var lon = -98.2233523;
// I've changed the zoom to 1 so you can immediately see the popup in the small fiddle window
var zoom = 1;
var position = new OpenLayers.LonLat(lon, lat).transform(
"EPSG_WGS84", "EPSG_900913"
);
map.setCenter(position, zoom);
// Finally here's your addPopup code
var query = new OpenLayers.LonLat(
-122.2928337167, 37.5549570333
).transform(
new OpenLayers.Projection("EPSG:4326"),
map.getProjectionObject()
);
var popup = new OpenLayers.Popup.FramedCloud(
"Popup",
query,
// I added a size to make it fit in the small fiddle window
new OpenLayers.Size(100,100),
"Text",
null,
true
);
map.addPopup(popup);
}
Why cant I add feature to Vector? This code is not working:
var features = [new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(-70.702451, 42.374473), {className: "latarnia"})]
vectors = new OpenLayers.Layer.Vector("warstwa", {
strategies: [new OpenLayers.Strategy.Fixed()],
protocol: new OpenLayers.Protocol.HTTP({
format: new OpenLayers.Format.OSM()
}),
features : features,
projection: new OpenLayers.Projection("EPSG:4326")});
map.addLayers([vectors]);
I mean vectors has no features at all.
I tried
layer.addFeatures([feature]);
but it fails as well.
it seems that the projection of your map and point is not the same.
map peojection is EPSG:4326 , but it seems that point projection is EPSG:3857.
it may help you
conv_latlon = new OpenLayers.LonLat(-70.702451, 42.374473).transform('EPSG:3857', 'EPSG:4326')//transform point
var features = [new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(conv_latlon.lon, conv_latlon.lat), {className: "latarnia"})]
For some reason initializing "features" property on OpenLayers.Layer.Vector constructor does not work.
But you should be able to add them afterwards:
vectors.addFeatures(features);
You can then test in browser console:
vectors.features.length; //this should be 1 now
Otherwise the code seems ok.
You should also be able to see the feature on map as an orange circle (default style), but only if the point's coordinates are inside the extent of your base layer.
Tested with OpenLayers version 2.14.