ArcGIS API - Cannot center or zoom - javascript

So, I am using the ARCGIS api in order to show some old maps, that should start center at and zoomed in to a certain city. After finally figuring out how to use the specific map I want as a basemap, I've struggled for a couple of hours trying to zoom and center at the right place. I am able to zoom in to this place using a default basemap (e.g. "streets"), but not using my custom basemap. I've tried both map.centerAndZoom and map.centerAt, but neither seem to work. The relevant code:
var map;
require(["esri/map", "esri/layers/ArcGISTiledMapServiceLayer", "dojo/on", "dojo/_base/json", "dojo/dom-style", "esri/request", "esri/geometry/Point", "esri/dijit/Search", "esri/dijit/LocateButton", "esri/tasks/GeometryService", "esri/tasks/locator", "esri/tasks/ProjectParameters", "esri/symbols/PictureMarkerSymbol", "dojo/domReady!"],
function(Map, ArcGISTiledMapServiceLayer) {
map = new Map("venster_Midden_2_Map");
var customBasemap = new ArcGISTiledMapServiceLayer(
"http://tiles.arcgis.com/tiles/nSZVuSZjHpEZZbRo/arcgis/rest/services/Historische_tijdreis_1815/MapServer");
map.addLayer(customBasemap);
map.centerAndZoom(51.1, 4.3, 0);
});
Does anyone have a clue on how to get the zoom and center working? Or might it be the case that certain maps simply don't allow such operations?

centerAndZoom is more intended for events, like when a user has chosen a certain city from a list and would like the map to automatically zoom to it. As richj points out, it also requires a point, and a zoom level of zero won't work.
If you don't want any of the Esri basemaps at all, just leave that out when initially creating the map. Slightly modifying this Tiled Map Service sample:
require(["esri/map", "esri/layers/ArcGISTiledMapServiceLayer", "dojo/domReady!"],
function(Map, Tiled) {
map = new Map("map", {zoom: 3});
var tiled = new Tiled("http://tiles.arcgis.com/tiles/nSZVuSZjHpEZZbRo/arcgis/rest/services/Historische_tijdreis_1815/MapServer");
map.addLayer(tiled);
}
);
Then, you will be able to include centerAndZoom as a response to an event (e.g. after the Tiled layer has been fully loaded from its web source).
require(["esri/map",
"esri/layers/ArcGISTiledMapServiceLayer",
"esri/geometry/Point",
"esri/SpatialReference",
"dojo/domReady!"],
function(Map, Tiled, Point, SpatRef) {
map = new Map("map", {zoom: 3});
var tiled = new Tiled("http://tiles.arcgis.com/tiles/nSZVuSZjHpEZZbRo/arcgis/rest/services/Historische_tijdreis_1815/MapServer");
map.addLayer(tiled);
var cityCenter = new Point(121000, 495000, new SpatRef({ wkid: 28992 }));
tiled.on("load",function(evt) {
map.centerAndZoom(cityCenter, 6);
});
});
Ref. Point constructor, centerAndZoom method, and Working with events.

From the relevant API documentation the centreAndZoom method takes a Point as its first argument. Also your zoom factor of zero looks like it might cause a problem.
You might have more luck with a Point and a non-zero zoom scale, like this:
map.centerAndZoom(new Point(51.1, 4.3), 0.5);
The method has a Deferred return type so that you can provide a callback to react when the method call has completed.

Maybe it is esri api bug, for me, it sometime (but not always) failed to move map center at lng, lat with zoom level 18
Here is how I work around:
Recommend:
map.centerAndZoom(new Point(lng, lat), 18);
Alternative: (sometimes, not always, it failed to move the map, maybe ESRI need to fix bug for Javascript api v3.24)
map.centerAt(new Point(lng, lat));
//or
// map.centerAt(new Point(lng, lat, new SpatialReference({wkid: 4326})));
map.setZoom(18);

Related

How to add markers to leaflet map with tabletop.js?

I'm using this quite nice guide to add markers from a Google sheet to a basic leaflet.js map:
https://rdrn.me/leaflet-maps-google-sheets/
The problem is, using these code snippets here i get all the data logged and returned in the console, but none of the points appear on the map itself.
This is probably some really basic JavaScript issue that i'm not able to see. Sorry, still learning.
Here's a jfiddle, linking to a demo sheets with one marker point
https://jsfiddle.net/xfs19cz7/1/
with the map part:
function init() {
Tabletop.init({
key: '*url to gsheets here*',
callback: myFunction,
simpleSheet: true
})
}
window.addEventListener('DOMContentLoaded', init)
function myFunction(data, tabletop) {
console.log(data);
}
var map = L.map('map-div').setView([64.6220498,25.5689638], 5);
var basemap = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: 'Basemap (c) OpenStreetMap',
minZoom: 5,
maxZoom: 18
});
basemap.addTo(map);
function addPoints(data, tabletop) {
for (var row in data) {
var marker = L.marker([
data[row].Latitude,
data[row].Longitude
]).addTo(map);
marker.bindPopup('<strong>' + data[row].Info + '</strong>');
}
}
This should add one point to a basic map. Now actually the map is not at all rendered, and no marker shows up. I can't find any issues in the code making the map show up blank, but there probably are some.
The marker from gsheets is however logged in the console, i suspect there is something missing in my code relating to really basic javascript functions / looping / sloppy syntax.
Also tried the init() and addPoints(data, tabletop) parts to a map i had where the map with the same basemap link, which rendereded OK. Adding this still left the map rendering, but no markers showed up. Again, the gsheets was loaded as an array of objects.
Could anyone point me to this, probably very basic, issue in the code?
edit:
callback: myFunction,
line above needs to be changed to
callback: addPoints,
also, init function needs to be called and position set to absolute. Thanks for the working fiddle in answer marked as correct below.
Fixes
Try setting map position absolute
calling the init() function
Working fiddle

What would make a Google map Ag object returned without mapDataProvider?

I'm working on an SPA project (ionic, so it's angular with ui-router) where I need to display two different maps on two different pages/controllers.
The first map is a general map (let's call it the main map)where a few locations are marked and the second one (let's call it the edit map)is a focus on a specific location where the user can edit the location by dragging the marker.
The general implementation scheme I'm using is that I'm calling a initMap method from mappingService that instanciates a google map from each controller.
$rootScope.markers = [];
this.initMap = function initMap(mapTarget, mapCenter) {
// the initMap function initialize the map it takes two arguments:
// + mapTaget which defines the html element the map is bound to.
// + mapCenter that defines the center of the map and whether to display the center
var markup = "<div id='" + mapTarget.mapId + "'></div>";
document.getElementById(mapTarget.containerId).innerHTML = markup;
var centerPos = new google.maps.LatLng(mapCenter.lat, mapCenter.lng);
$rootScope.map = new google.maps.Map(document.getElementById(mapTarget.mapId), {
center: centerPos,
zoom: 18,
disableDefaultUI: true
});
// eventually place a person marker for the user's position
if (mapCenter.display) {
console.log('placing the position marker');
$rootScope.markers[0] = new google.maps.Marker({
position: {lat: mapCenter.lat, lng: mapCenter.lng},
map: $rootScope.map,
title: 'userLocation',
icon: './img/person_icon.png'
});
}
};
The only difference is that on the main map I'm first calling a geolocate service the return a promise and I'm using the returned location coordinates to then call the mapping service:
geolocateService.getLocalPosition()
.then(function(coords) {
mappingService.initMap(
{containerId: $scope.mapContainer, mapId: $scope.mapId},
{lat: coords.lat, lng: coords.lng, display: true}
);
While on the edit map I'm calling directly the mapping service.
mappingService.initMap(
{containerId: $scope.mapContainer, mapId: $scope.mapId},
{lat: $scope.location.lat, lng: $scope.location.lng, display: false}
);
I am able to render both maps without problem and even to add markers and some event listeners.
However, I run into the problem that after some sequence of actions, for example going from the main map to the edit map two times, one of the map would suddenly become blank (white to be exactly, so it doesn't seems to be something that I could solve by resizing the map). I'm receiving the Ag object and the only difference is that I don't get the mapDataProviders property on the broken map.
When it works, I get:
Ag object when it works
While when it doesn't, I get:
Ag object when it doesn't work
The code snippet above is my last implementation attempt. I've been trying to implement those maps from a lot of different ways to no avail. Among those attempts, I tried:
totally separates both instanciation, dividing the initMap methods into an initMainMap and an initEditMap.
using one instance for both maps and replacing the DOM element> This is what you see above with the following additional method that is called when leaving the view:
this.removeMap = function removeMap(containerId) {
var container = document.getElementById(containerId);
$rootScope.markers = [];
container.innerHTML = '';
// important part:
var old_element = container;
var new_element = old_element.cloneNode(true);
old_element.parentNode.replaceChild(new_element, old_element);
delete $rootScope.map;
}
knowing that on both views I have either:
or
<div id="edit-map-container"></div>
I'm trying to understand what would make the google map API return a map without mapDataProvider (which I believe means that the map works and even starts to render except that it lacks the tiles to display).
P.S. it looks like there is a memory leak, which is apparently a well known issue.
If anyone has the answer to this, I'm a bit lost right here!

Angular google Maps

Hi i am currently working on angular Google maps https://github.com/dylanfprice/angular-gm
i am facing difficulties in setting the bounds and map center
<gm-map gm-map-id="'infoWindows'" gm-center="options.map.center" gm-zoom="options.map.zoom" gm-bounds="bounds" gm-map-options="options.map" class="map">
<gm-markers gm-objects="clinics"
gm-get-lat-lng="{ lat: object.practice.latitude, lng: object.practice.longitude }"
gm-get-marker-options="{ title: object.practice.name }"
gm-on-click="clk = object; infoWindow.open(marker.getMap(), marker);">
</gm-markers>
</gm-map>
make sure your map is already loaded.
therefor it is highly recommended to use promises.
var gmapPromise = angulargmContainer.getMapPromise('<mapId>');
gmapPromise.then(function(gmap) {
$scope.myGoogleMap = gmap;
});
In your case would be 'infoWindows'.
as there is to less context in your question, i can't really give you an answer what is wrong with your particular code but i'll give you some snippet which is always useful:
$scope.updateGoogleMap = function(map, options) {
// triggers a resize of the map and sets the correct center position
// requires a google map object and a google maps mapOptions object
$timeout(function(){
google.maps.event.trigger(map, 'resize');
map.setOptions(options);
});
};
a Google Maps mapOption object looks like this:
{
center: new google.maps.LatLng(47.123, 10.123),
zoom: 3,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
as ng-hide/show lead to some google maps resize misbehaviour, you might wanna call this when toggling views.
**by the way, if your are using the gm-map-options tag with a valid google.maps.MapOptions, you don't need the the extra 'gm-bounds', 'gm-zoom' or 'gm-center' arguments

leaflet js: draw POIs as canvas

I want to draw many geo points with Leaflet. Therefore I want to use HTML5 canvas to improve the performance.
My datasoure is geoJSON. As I saw in the documention of Leaflet, it is not possible to draw the geo positions as canvas yet.
var anotherGeojsonLayer = new L.GeoJSON(coorsField, {
pointToLayer: function (latlng){
return new L.Marker(latlng, {
icon: new BaseballIcon()
});
}
});
I think I should hook up here:
pointToLayer: function (latlng) { }
Does somebody know how to draw my latlng objects as canvas?
I'm Leaflet author. You can do this by using L.CircleMarker instead of regular Marker, and also using an experimental L_PREFER_CANVAS switch to render vectors as Canvas (instead of SVG), like this: https://github.com/CloudMade/Leaflet/blob/master/debug/vector/vector-canvas.html
Expanding on the original answer in case anyone needs this for Leaflet 1.0. You should still use L.circleMarker() (Leaflet circleMarker documentation) instead of L.marker(), but the way to use the canvas has changed.
In Leaflet 1.0, the experimental L_PREFER_CANVAS switch has been upgraded to an official map option preferCanvas (Leaflet preferCanvas documentation).
var map = L.map('mapid', {
preferCanvas: true
});
Alternatively, you can explicitly set the canvas renderer; I think this does the same thing as the preferCavas option. Here's the Leaflet documentation for canvas.
var map = L.map('mapid', {
renderer: L.canvas()
});
Either of these options (preferCanvas: true or renderer: L.canvas()) with L.circleMarker() was significantly faster than a regular layer using L.marker().

How to reproject a vector layer when you switch between base maps of different projections

I have OpenLayers map with two base layers: MetaCarta (EPSG:4326) and Google map (Mercator). sphericalMercator = false, units are degrees. There are also some markers, boxes, and vector data on the map.
When I switch between the base layers (which are of different projections), the simple geometries (such as markers or boxes) are reprojecting automatically and displayed correctly. However vector layers (polylines) are just shifted, not reprojected. I think that I need to call some kind of "rebuild" function or add some parameter so that OpenLayers do this automatically when the base layer projection changes. But I have no idea how to do this.
I read about Spherical Mercator (http://docs.openlayers.org/library/spherical_mercator.html) and look through OpenLayers examples, but didn't find a solution.
The part of my code is below (all coordinates in vector.json is in degrees):
var metaCarta = new OpenLayers.Layer.WMS("MetaCarta",
"http://labs.metacarta.com/wms/vmap0?",
{layers: "basic"}
);
var gmap = new OpenLayers.Layer.Google(
"Google Streets",
{numZoomLevels: 40}
);
map.addLayers([metaCarta, gmap]);
map.setCenter(new OpenLayers.LonLat(139.8, 35.7), 11);
// Load vector data
var jsonFormat = new OpenLayers.Format.GeoJSON();
var vectorLayer = new OpenLayers.Layer.Vector("vector", {
style: {strokeColor: "gray",strokeWidth: 2}
});
OpenLayers.loadURL("vector.json", {}, null, function(response) {
var features = jsonFormat.read(response.responseText);
vectorLayer.addFeatures(features);
});
map.addLayer(vectorLayer);
You will need to define the projections and a suitable transform in OpenLayers. In turn, you will need to include the Proj4JS library (which is used by OpenLayers to perform these projection transformations)

Categories

Resources