I have an app with features layers and graphics layers which don't have the same spatial reference (i.e 102110 and 4326).
My map has the same spatial reference as my features layers (102110).
I can't turn the spatial reference of my graphics layers (4326) into the one of my map and features layers.
Do you have any idea to help me ?
Thanks.
GraphicsLayer or FeatureLayer does not have any SpatialReference information in them. Spatial references are part of the geometry/graphic objects and Map also.
The SpatialReference of FeatureLayer matches with map:
When requests are made for features from a service, the map's spatial
reference will be included which tells the service to re-project
features before sending them to the client.
Whereas, GraphicsLayer are maintained entirely within the application. The developer needs to ensure that projections match before adding the graphics on the map. To change the projection system, you can use GeometryService, below is a sample.
require(["dojo/_base/array", "esri/tasks/GeometryService", "esri/tasks/ProjectParameters", "esri/SpatialReference"], function(GeometryService, ProjectParameters, array) {
var geometries = array.map(graphicsLayer.graphics, function(graphic){
return graphic.geometry;
});
var gsvc = new GeometryService("https://utility.arcgisonline.com/ArcGIS/rest/services/Geometry/GeometryServer");
var outSR = new SpatialReference({wkid:102110});
var params = new ProjectParameters();
params.geometries = geometries ;
params.outSR = outSR;
params.transformation = transformation;
gsvc.project(params, function(projectedGeometries){
for(var i = 0; i < projectedGeometries.length;i++){
graphicsLayer.graphics[i].setGeometry(projectedGeometries[i]);
}
});
});
Related
I would like to show on Google Map using Javascript API v3 some markers. I have two types of data - vehicle positions and building positions. There's a lot of buildings but only few vehicles. I would like to use clustering algorithm for building markers but not for vehicles. Is it possible using offical Google JS API or using some external library?
If you can distinguish the two different types of markers then you can just do this for the markers regarding buildings (using https://github.com/googlemaps/js-marker-clusterer)
var buildingsMarkersArray = [];
...
buildingsMarkersArray.push(someMarker);
// when you are done creating markers then
var clusterOptions = {
imagePath: 'the/path/to/images/m'
};
var buildingsCluster = new MarkerClusterer(map, buildingsMarkersArray, clusterOptions);
This will cluster only the markers you provide.
I'm making a web application that has to work offline. So far everything works and my last step is to take the map tiles offline. Luckily I know exactly what areas of the map will need to be accessible to users, so I don't have to allow caching of millions of tiles.
The map is split into areas and so the idea is to offer the tiles for these areas as downloadable 'packages.'
For instance, when I'm online, I go to the 'tile packages' page, which offers downloads for several areas. I choose the area which I'm interested in, it downloads the tiles, and when I go offline, I'm able to use these tiles. I only need about 2 zoom levels, one far out for quick navigation, and one more up close for more detail.
I'm using leaflet to serve up the map. Has anyone had to do something like this and could give me some guidance? I really just don't know how to even approach this, and it's the last piece of the puzzle.
Sadly you don't point out, what the exact problem is or at which step you fail. So I will try to give a general answer:
Leaflet uses Tiles by different providers to for a slippymap using JS. The map tiles (aka rasterimages) can be offered via an Tile Map Service (TMS) or an slightly different method (for OSM the numbering here described).
So you can create a list of images you want to get and can transfer them by respeciting legal and tecnical terms. For OSM this is for example:
http://wiki.openstreetmap.org/wiki/Legal_FAQ
https://wiki.openstreetmap.org/wiki/Tile_usage_policy
So you need to create an server/client script, that is able to do such a bulk transfer (maybe as packed archive file?) and ask to place it at a certain place for your user. I'm not experienced enough in Leaflet and can't tell you how to provide them, beside you might add them to the browsers cache itself, or to use a local server to provide them as localhost.
Anyway, if you have more questions, just ask.
So here's what I came up with. I import an area of the map to my database. I then offer this section as a downloadable package. When the user downloads the package, the database is queried and returns all tiles associated with that area in JSON format. The images are stored as blobs. I then pass this array of tiles to a custom leaflet layer which parses the data. Here's the code for the layer:
define([], function() {
L.TileLayer.IDBTiles = L.TileLayer.extend({
initialize: function(url, options, tiles) {
options = L.setOptions(this, options);
// detecting retina displays, adjusting tileSize and zoom levels
if (options.detectRetina && L.Browser.retina && options.maxZoom > 0) {
options.tileSize = Math.floor(options.tileSize / 2);
options.zoomOffset++;
if (options.minZoom > 0) {
options.minZoom--;
}
this.options.maxZoom--;
}
this._url = url;
var subdomains = this.options.subdomains;
if (typeof subdomains === 'string') {
this.options.subdomains = subdomains.split('');
}
this.tiles = tiles;
},
getTileUrl: function (tilePoint) {
this._adjustTilePoint(tilePoint);
var z = this._getZoomForUrl();
var x = tilePoint.x;
var y = tilePoint.y;
var result = this.tiles.filter(function(row) {
return (row.value.tile_column === x
&& row.value.tile_row === y
&& row.value.zoom_level === z);
});
if(result[0]) return result[0].value.tile_data;
else return;
}
});
});
I think you can use a quadtree,i.e. space filling curve. MS Bing Map uses the most simple tile map: http://bcdcspatial.blogspot.de/2012/01/onlineoffline-mapping-map-tiles-and.html?m=1. I think the other maps server also uses a space filling curve, buf it's not so obvious. You may search for ms bings maps quadkey or nick's spatial index hilbert curve. You can also download my php class hilbert curve # phpclasses.org. You can use it with many different space filling curves and to generate a quadkey. A good start is also the hacker's cookbook. There is a whole chapter dedicated to the hilbert curve.
What I'm trying to do is to change the default icon that is displayed when you set the Clustering Configuration for a Bing Map using the Bing Maps Ajax Control 6.3.
I have a function that loads a Bing Map like this:
function getMap() {
map = new VEMap('map_canvas');
map.SetDashboardSize(VEDashboardSize.Tiny);
var latLong = new VELatLong(21.983801, -101.557617);
map.LoadMap();
var customPin = '<div style="position:relative; left:-10px;top:-20px;"><img src="../Content/images/icons/pin1.png" style="width:40px; height:40px"></div>';
icon.CustomHTML = custom;
var options = new VEClusteringOptions(icon, null);
map.GetShapeLayerByIndex(0).SetClusteringConfiguration(VEClusteringType.Grid, options);
map.SetCenterAndZoom(latLong, 6);
map.SetMouseWheelZoomToCenter(false);
map.EnableShapeDisplayThreshold(true);
map.AttachEvent("onclick", singleMouseHandler);
map.AttachEvent("ondoubleclick", doubleClickMouseHandler);
}
But so far it keeps displaying the same default icon. What am I missing here?
Another thing I was wondering is if there's a way to change the custom icon if a pin in the cluster changes, like if I have 5 green Push Pins but one of them is updated to be a blue Push Pin, is there a way to change the icon that represents that cluster?
I found the reason my approach wasn't working, I keep thinking I'm dealing with classes with constructors that receive parameters, which in this case the VEClusteringOptions class doesn't receive parameters in its constructor. I had to set the Icon property separately:
function getMap() {
map = new VEMap('map_canvas');
map.SetDashboardSize(VEDashboardSize.Tiny);
var latLong = new VELatLong(21.983801, -101.557617);
map.LoadMap();
var customPin = '<div style="position:relative; left:-10px;top:-20px;"><img src="../Content/images/icons/pin1.png" style="width:40px; height:40px"></div>';
icon.CustomHTML = custom;
var options = new VEClusteringOptions();
options.Icon = icon; // here's the "big" difference
map.GetShapeLayerByIndex(0).SetClusteringConfiguration(VEClusteringType.Grid, options);
map.SetCenterAndZoom(latLong, 6);
map.SetMouseWheelZoomToCenter(false);
map.EnableShapeDisplayThreshold(true);
map.AttachEvent("onclick", singleMouseHandler);
map.AttachEvent("ondoubleclick", doubleClickMouseHandler);
}
Now my custom cluster icons are being loaded great, I need to get used to more to the concept of property in the future.
I did the development long time ago for our company site. Did you try the interactive SDK available here?
http://www.bingmapsportal.com/isdk/ajaxv7#Pushpins15
I have added the reference for pushpin development
http://www.microsoft.com/maps/developers/web.aspx
I have been attempting to overlay tiles from Weather Central onto a Bing map but have been encountering a problem. I am able to call upon a tile and push it onto the map, however, no matter how big the tile is, it puts the tile everywhere on the map. I would like to be able bound it to a specific place but cannot figure out how in 7.0. In 6.3 the specifications seem straightforward : http://msdn.microsoft.com/en-us/library/bb429629.aspx but not in 7.0. They have an example here: http://www.bingmapsportal.com/isdk/ajaxv7#TileLayers1 but even using their code it will still put the tiles everywhere.
Here is my code so far:
function GetMap() {
map = new Microsoft.Maps.Map(document.getElementById("mapDiv"), { credentials: "my creds" });
var tileSource = new Microsoft.Maps.TileSource({ uriConstructor:
'http://datacloud.wxc.com/?type=tile&datatype=forecast&var=Temperature&time=now&bing=023212&vs=0.9&passkey=my_passkey', height: 256, width: 256});
var tilelayer = new Microsoft.Maps.TileLayer({ mercator: tileSource, opacity: .7 });
// Push the tile layer to the map
map.entities.push(tilelayer);
}
Where I do the function GetMap() onload.
Thanks
It looks like you're hardcoding a particular tile quadkey (023212) in your request - you need to replace this with the {quadkey} placeholder to request the appropriate tile image for each location. i.e.:
map = new Microsoft.Maps.Map(document.getElementById("mapDiv"), { credentials: "my creds" });
var tileSource = new Microsoft.Maps.TileSource({ uriConstructor:
'http://datacloud.wxc.com/?type=tile&datatype=forecast&var=Temperature&time=now&bing={quadkey}&vs=0.9&passkey=my_passkey', height: 256, width: 256});
var tilelayer = new Microsoft.Maps.TileLayer({ mercator: tileSource, opacity: .7 });
// Push the tile layer to the map
map.entities.push(tilelayer);
(untested, since I don't have a passkey to access the service in question)
I am having the weirdest problem right now using the ArcGIS Javascript API (v2.4). I'm merely trying to create an instance of an ESRI topo map with an extent, and then add a layer.
Here is the code that works. I create an extent, then a map, then a streetmap layer and then finally add that layer.
var startExtent = new esri.geometry.Extent(-71.5, 42, -71, 42.5, new esri.SpatialReference({wkid:4326}) );
map = new esri.Map("map_canvas", { extent: startExtent,fitExtent:false });
var streetmap = new esri.layers.ArcGISTiledMapServiceLayer("http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer");
map.addLayer(streetmap);
However when I try and do the same thing with a separate server, it doesn't work.
var startExtent = new esri.geometry.Extent(-71.5, 42, -71, 42.5, new esri.SpatialReference({wkid:4326}) );
map = new esri.Map("map_canvas", { extent: startExtent,fitExtent:false });
var basemap = new esri.layers.ArcGISTiledMapServiceLayer("http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer");
map.addLayer(basemap);
I know that the faulty-layer's server works, because if I create a map with no extent, it shows the full world imagery server, so it appears that creating a map in with one layer and an extent works, while creating a map with a different layer but the same extent does not work.
Any ideas why?
In your second example, the layer is in web Mercator.
Try converting the extent from geographic to web Mercator before using it in the map constructor.
The easiest way to convert the extent is to use esri..geometry.geographicToWebMercator.