Displaying all layers in ArcGIS feature service in Angular application - javascript

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.

Related

I have a location list of 300000 elements and want to visualize them on my localhost

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.

How to apply a custom local/offline map style to an OpenLayers Map

I have a local webpage as part of a larger desktop application. I want to change the default style of the Open Layer map to "Klokantech Basic". I've downloaded a copy of the style JSON but struggeerling to apply it to the map. Currently my code looks like:
var map = new ol.Map({
layers: [new ol.layer.Tile({ source: new ol.source.OSM() }), vectorLayer],
target: 'map',
style: './mapStyle.json',
view: new ol.View({
center: ol.proj.fromLonLat([-0.146953, 51.493758]),
zoom: 15
})
But setting a style isn't working, I've looked online and there appears to be Map Box, this however uses an API key, something which I don't want to use/ maintain.
The whole page and its resources are stored locally, is there any way of referencing the local style file without an API?
Here is my current code.
The mapbox style is for vector tile source and I pretend you use it for your vector layer.
Openlayers don't seem to support the Mapbox style for MVT. It use a style function to apply to the vector tile.You can see here a exemple of how Openlayers make style function for vector tiles.

how to import legends from mapbox the same way maps are imported

I currently import mapbox maps such as this one by simply using it's map id (ie lri.hb670c6k) and adding it into a jekyll generated website. The trick is to specify this information in an md file like so:
---
layout: map
firstlayer: "lri.hb670c6k"
lat: 33.756
lon: 35.712
zoom: 9
permalink: /climate_change/lri.hb670c6k
---
However there is a legend associated with the above map.. but i'm not sure how to get hold of that information from the map itself using the above technique (or any other technique for that matter).. ideas?
If your map has a legend built in, when you construct your map object, it will load/display with it:
L.mapbox.map('map', 'lri.hb670c6k');
If you're adding it as a tileLayer, you'd be looking at adding the legend from the tileLayer's tileJSON:
tileLayer.on('ready', function() {
legend = map.legendControl.addLegend(tileLayer.getTileJSON().legend);
});

Keeping Rails variables up-to-date for client-side use

I have a Rails template which uses a javascript_tag to get the variables #user.lat and #user.lng to the client for use in a function that generates a Google map.
The problem is that these variables are dynamic and can change often, but my javascript tag only knows the value of the variables at the time of page rendering. When I click around my app (triggering actual page loads) I can see that the values change, but the values in the javascript_tag aren't updated after the initial page load.
How can I keep the variables up-to-date on the client without refreshing the page or writing code to repeatedly query the server for these variables?
The javascript_tag approach you're taking doesn't support "watching" the variables for changes. In other words, your method of getting the data to the client is sort of "set it and forget it" and the client will never know if the value changes on the server without a page reload.
Another approach would be to use a pre-rolled solution for making dynamic server-side data onto the client, keeping an eye on them for changes, such as Gon. Specifically, you might want to take a look at the "watch" functionality provided by that gem.
Yet another approach might be to write up a function that makes an AJAX call to the server to request the latest value every so often. But then you'd just be hand-rolling a solution that does exactly the same thing as the previous suggestion.
'The javascript_tag approach you're taking doesn't support "watching" the variables for changes....'
Yes, true, even when I was clicking around my application and reloading the page, the values in the javascript_tag stayed the same. It was like once my js file loaded on start up of my application, the latitude and longitude values of #user stayed the same, even though they're supposed to change, and the map was always drawn with the same coordinates.
The 'Gon' gem didn't work for me either. Very little documentation, especially for a novice like me.
What succeeded:
On the page where I wanted the map to be generated, show.html.erb:
<!-- This is here, to generate the user's latitude and longitude dynamically -->
<!-- The data-lat and lng attributes are used in 'initialise_google_maps' function, in scripts.js' -->
<div id="user-position" class="hidden" data-lat="<%= #user.lat %>" data-lng="<%= #user.lng %>"></div>
And then in my scripts.js:
function initialize_google_maps() {
var user_longitude = $("#user-position").attr("data-lng");
var user_latitude = $("#user-position").attr("data-lat");
var currentlatlng = new google.maps.LatLng(user_latitude, user_longitude);
var zoom = 10;
var myOptions = {
zoom: zoom,
center: currentlatlng,
mapTypeId: google.maps.MapTypeId.ROADMAP, // ROADMAP, SATELLITE, HYBRID
streetViewControl: false
};
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
var marker = new google.maps.Marker({map: map, position: currentlatlng, icon:{oppacity:0}});
var circle = new google.maps.Circle({
map: map,
fillOpacity: 0,
strokeWeight: 2,
strokeOpacity: 0.7,
radius: 10000,
});
circle.bindTo('center', marker, 'position');
}
Works a treat now.

Creating a map using only toggleable overlays?

I'm trying to create map (using the Google Maps JavaScript API V3) which consists of several partially-transparent layers. By default, these layers should all be overlaid on top of one another to form a complete map, but the user should be able to turn any combination of them on or off (while preserving order) to create whatever view they prefer.
So far, I've had a great deal of luck getting this working for a single layer using map.mapTypes, but when adding all the layers via map.overlayMapTypes, I've hit a couple of snags:
The map doesn't seem to get fully initialized if map.setMapTypeId() is not called (no controls appear and the map is not correctly centered) and it cannot be called with an overlay.
It isn't clear how to toggle the visibility of an overlay without directly modifying the map.overlayMapTypes array, which complicates keeping them correctly ordered. I'd much prefer something analogous to the Traffic/Transit/Photos/etc. control available within Google Maps itself.
Here's the initialize function I'm working with. I'd post a link, but the map imagery isn't publicly available:
function initialize() {
map = new google.maps.Map(document.getElementById("map_canvas"), {
zoom: 0,
center: center
});
/* if these lines are uncommented, the single layer displays perfectly */
//map.mapTypes.set("Layer 3", layers[3]);
//map.setMapTypeId("Layer 3");
//return;
var dummy = new google.maps.ImageMapType({
name: "Dummy",
minZoom: 0,
maxZoom: 6,
tileSize: new google.maps.Size(256, 256),
getTileUrl: function() {return null; }
});
map.mapTypes.set("Dummy", dummy);
map.setMapTypeId("Dummy");
// layers is an array of ImageMapTypes
for (var i = 0; i < layers.length; i++) {
map.overlayMapTypes.push(layers[i]);
}
}
As you can see, I've tried creating a "dummy" maptype (which always returns null for tile URLs) to serve as the base map. While this does cause the controls to display, it still doesn't center correctly.
What's the best way to create a map which consists only of toggleable overlays?
Update: Turns out the dummy maptype works perfectly well if you also remember to set a projection. That's one problem solved, at least. :-)
I use ImageMapType, but I don't add it to mapTypes. I just add it to overlayMapTypes and when I need to remove it I use setAt to set the entry in overlayMapTypes to null.
You will need to add individual controls to the UI that toggle the individual layers.

Categories