I am loading a Webmap made with ArcGIS online into a simple viewer app. I want the position and zoom level to match the original.
I can get the center from map.portalItem.extent, but how do I find the zoom?
app.map=new WebMap({ portalItem: { id: myId }});
app.map.load().then(function() {
app.center[0]=app.map.portalItem.extent.center.longitude;
app.center[1]=app.map.portalItem.extent.center.latitude;
app.zoom=???
});
...
app.mapView.when(function() { app.activeView.goTo({ center:app.center, zoom: app.zoom }) });
The extent is stored in the WebMap (not the zoom level) - but that's ok because the goTo() function you're using takes many different inputs, including an extent. So just change your code to something like this:
app.map=new WebMap({ portalItem: { id: myId }});
app.map.load().then(function() {
app.extent=app.map.portalItem.extent;
});
...
app.mapView.when(function() { app.activeView.goTo(app.extent) });
Related
I am using highmaps in my application with drilledown enabled, it works fine for the sample data given for usa.
But it does not work with the data for srilanka. what could be the issue?
Here is my code:
$('#container').highcharts('Map', {
chart : {
events: {
drilldown: function (e) {
if (!e.seriesOptions) {
var chart = this,
mapKey = 'countries/lk/' + e.point.drilldown + '-all',
// Handle error, the timeout is cleared on success
fail = setTimeout(function () {
if (!Highcharts.maps[mapKey]) {
chart.showLoading('<i class="icon-frown"></i> Failed loading ' + e.point.name);
fail = setTimeout(function () {
chart.hideLoading();
}, 1000);
}
}, 3000);
// Show the spinner
chart.showLoading('<i class="icon-spinner icon-spin icon-3x"></i>'); // Font Awesome spinner
// Load the drilldown map
$.getScript('https://code.highcharts.com/mapdata/' + mapKey + '.js', function () {
data = Highcharts.geojson(Highcharts.maps[mapKey]);
// Set a non-random bogus value
$.each(data, function (i) {
this.value = i;
console.log(i);
});
// Hide loading and add series
chart.hideLoading();
clearTimeout(fail);
chart.addSeriesAsDrilldown(e.point, {
name: e.point.name,
data: data,
dataLabels: {
enabled: true,
format: '{point.name}'
}
});
});
}
this.setTitle(null, { text: e.point.name });
},
drillup: function () {
this.setTitle(null, { text: 'Sri Lanka' });
}
}
}
JSFiddle Link
The drilldown data doesn't exist in the Highmaps Map Collection for Sri Lanka. If you scroll down the page you can see that at the moment the only countries with data below country level (e.g. admin2 level) are Canada, Germany, France, Netherlands, Norway, USA.
When you click a district the fiddle is trying to retrieve data from a corresponding URL:
mapKey = 'countries/lk/' + e.point.drilldown + '-all',
and for Sri Lanka it is failing because the JS file for each district does not exist.
There is more info in the Highmaps docs about creating maps:
Highmaps loads its maps from GeoJSON, an open standard for description
of geographic features. Most GIS software supports this format as
export from for instance Shapefile or KML export. Read more in the API
reference and see the live demo.
There are three basic sources for your map:
Use our Map collection. Read the tutorial article on the map
collection to get started.
Find an SVG map online and convert it using
our (experimental) online converter.
Create your own map from scratch
using an SVG editor, then convert them online. Read our tutorial on
Custom maps for Highmaps.
and about the Highmaps Maps Collection:
For your convenience, Highmaps offers a free collection of maps,
optimized for use with Highmaps. For common maps, it saves you the
trouble of finding or drawing suitable SVG or GeoJSON maps.
For Admin2, we have only compiled selected countries, and these maps
are created from national files with their own license which is
specified on the SVG map and in the other format files as meta data.
If you miss your country, please contact us and we'll try to find a
suitable shapefile and generate more maps.
I have a map with bingmap and I implemented waypoints. I would like when I click in a waypoint it displays an info window.
if (!$scope.directionsManager) { _createDirectionsManager(); }
if($scope.directionsManager.getAllWaypoints().length < 2)
{
$scope.directionsManager.resetDirections();
$scope.waypoints.forEach(function (waypoint) {
var order_waypoint = new Microsoft.Maps.Directions.Waypoint({ location: new Microsoft.Maps.Location(waypoint.lat, waypoint.lng) });
console.log("order_waypoint", order_waypoint)
$scope.directionsManager.addWaypoint(order_waypoint);
})
}
var renderOption = {
itineraryContainer: document.getElementById('directionsItinerary'),
waypointPushpinOptions:{
// icon: "http://vignette3.wikia.nocookie.net/freeciv/images/1/1c/Crystal_128_penguin.png/revision/latest?cb=20071106133132&path-prefix=es",
// hoverIcon: "http://vignette3.wikia.nocookie.net/freeciv/images/1/1c/Crystal_128_penguin.png/revision/latest?cb=20071106133132&path-prefix=es",
// height: 10,
// width: 10,
draggable: false,
textOffset: new Microsoft.Maps.Point(-1, 3)
}
}
$scope.directionsManager.setRenderOptions(renderOption);
$scope.directionsManager.calculateDirections();
Thanks!
I haven't used the Bing maps API, but the docs on the Waypoint class make it look like you might need a custom pushpin in order to intercept its click event.
var location = new Microsoft.Maps.Location(waypoint.lat, waypoint.lng);
var pushpin = new Microsoft.Maps.Pushpin(location);
Microsoft.Maps.Events.addHandler(pushpin, 'click', function() {
// Implementation can go here
});
var order_waypoint = new Microsoft.Maps.Directions.Waypoint(
{location: location, pushpin: pushpin});
$scope.directionsManager.addWaypoint(order_waypoint);
It is possible you can get a reference to the default pushpin on order_waypoint without creating your own custom one, and use addHandler to bind the click event to it. I don't have running code to test that on, and I don't see a way to get a reference to the default pushpin, only the custom one. You could try it anyway (order_waypoint.getPushpin()) and see if it works.
I am working on a SVG map of the US and I would like to display a small info window pointing to each state when you hover over it that shows the population, similar to the info windows on Google Maps. Unfortunately I'm not very good with JSON so I'm stuck at this point.
Currently I have the SVG map of the US up and the fill color changes on hover via CSS. I have a sample group of JSON data and wondering how I can incorporate it into my map so that it displays the population on hover.
Here's an example of the JSON data:
[
{
"id":"AL",
"population":"253045"
},
{
"id":"AR",
"population":"1529923"
},
{
"id":"AZ",
"population":"352416t"
}
]
There's quite a bit of HTML due to the SVG paths, so I won't paste that here, but you can see what I have so far on this JSFiddle
To get info about the hovered state, first put your info in an array, so it can be accessed:
var info = [
{
"id":"AL",
"population":"253045"
},
{
"id":"AR",
"population":"1529923"
},
{
"id":"AZ",
"population":"352416t"
}
]
Then you can get info from your array by filtering it by the id key using filter:
info.filter(function(state) {return state.id === currState});
Here is an example where you get the population of the hovered state:
$('path').hover(function() {
var currState = $(this).attr('id');
var currStateInfo = info.filter(function(x) {return x.id == currState});
if (currInfo[0])
console.log(currInfo[0].population);
});
Here is a working example: https://jsfiddle.net/4tasLo6k/
I have some DOM elements that I don't directly have access to, as they are rendered from an API call. What I would like to do is add a class to this element once it's rendered on the DOM.
Using Template.rendered does not work, as the template renders properly before these DOM elements appear from the API.
My current solution is a Meteor.setTimeout—which might be the definition of a hack—and it only works about 90% of the time.
What is the best way to trigger a function when a particular DOM element is rendered?
Here is some of the relevant code from the API call:
Template.map.rendered = function() {
return this.autorun(function() {
var drawControl, drawnItems, mmap;
if (Mapbox.loaded()) {
L.mapbox.accessToken = '<API KEY>';
L.mapbox.config.FORCE_HTTPS = true;
mmap = L.mapbox.map('map', '<TOKEN>');
L.control.scale().addTo(mmap);
var featureGroup = L.featureGroup().addTo(mmap);
drawControl = new L.Control.Draw({
draw: {
polygon: false,
polyline: false,
rectangle: true,
circle: false,
marker: false
}
});
mmap.addControl(drawControl);
mmap.addControl(L.mapbox.geocoderControl('mapbox.places', {
autocomplete: true
}));
function showPolygonAreaEdited(e) {
e.layers.eachLayer(function(layer) {
showPolygonArea({ layer: layer });
});
}
function showPolygonArea(e) {
coords = {
lat1: normalizeLon(e.layer.toGeoJSON().geometry.coordinates[0][1][0]),
lon1: normalizeLat(e.layer.toGeoJSON().geometry.coordinates[0][1][1]),
lat2: normalizeLon(e.layer.toGeoJSON().geometry.coordinates[0][3][0]),
lon2: normalizeLat(e.layer.toGeoJSON().geometry.coordinates[0][3][1])
}
featureGroup.clearLayers();
featureGroup.addLayer(e.layer);
e.layer.openPopup();
}
mmap.on('draw:created', showPolygonArea);
mmap.on('draw:edited', showPolygonAreaEdited);
}
});
};
I've removed a lot of extraneous code, so this might not compile properly... But it has all the relevant bits.
The selector I initially tried to use was this:
Template.map.rendered = function() {
$('.leaflet-draw-section').attr('data-intro', 'Hello step one!')
...
...
But it didn't work, since the API elements hadn't rendered yet.
Looking at the map box api, it appears that L.mapbox.map does the rendering:
<script>
// Provide your access token
L.mapbox.accessToken = 'id1' //
// Create a map in the div #map
L.mapbox.map('map', 'id2');
// add your class to #map right here!!
</script>
If that doesnt work, them maybe L.mapbox.map is doing something asynchronous. They don't give you a callback, so a window.setTimout(func, 0) may be necessary
Make sure your code looks like this
Template.templatename.onRendered(function(){
//yourcode
});
The solution comes from the Mapbox API. There is a callback on "ready":
var layer = L.mapbox.tileLayer('mapbox.streets');
layer.on('ready', function() {
// the layer has been fully loaded now, and you can
// call .getTileJSON and investigate its properties
});
I'm trying to produce a mapping application with Bing Maps with a button that will retrieve a JSON string and places pins on the map based on the center of the map.
That is working fine, but I'm running into two issues that I'm having trouble diagnosing.
The first is that when I move the map after placing the pins, the majority of them disappear from the map except for 1-3. I've figured out that the pins are still being held in map.entities, but just aren't all displaying.
The second issue is that I have a click event on the pins, and sometimes when I click on a pin it will disappear (and sometimes reappear elsewhere on the map).
Here is my code:
function addPin() {
map.entities.clear();
var pinImg = "images/MapPin.jpg";
var latLong = {};
var name;
for (var i = 0; i < factualJson.response.data.length; ++i) {
latLong['latitude'] = factualJson.response.data[i].latitude;
latLong['longitude'] = factualJson.response.data[i].longitude;
name = factualJson.response.data[i].name;
var pin = new Microsoft.Maps.Pushpin(latLong, {
icon: pinImg,
anchor: new Microsoft.Maps.Point(latLong['latitude'], latLong['longitude']),
draggable: true,
width: 48,
height: 48
});
Microsoft.Maps.Events.addHandler(pin, 'click', displayName);
pin.title = name;
pin.id = 'pin' + i;
map.entities.push(pin);
}
document.getElementById("arrayLength").innerHTML = "Number of locations: " + map.entities.getLength();
}
function displayName(e) {
document.getElementById("name").innerHTML = "";
if (this.target.id != -1) {
document.getElementById("name").innerHTML = this.target.title;
}
}
function boot() {
Microsoft.Maps.loadModule('Microsoft.Maps.Overlays.Style', { callback: getMap });
}
function getMap() {
map = new Microsoft.Maps.Map($gel("bingMap"), {
credentials: getKey(),
customizeOverlays: true,
enableClickableLogo: true,
enableSearchLogo: true,
showDashboard: true,
showBreadcrumb: true,
showCopyright: true,
zoom: 10,
labelOverlay: Microsoft.Maps.LabelOverlay.hidden
});
setGeoLocation();
//setTimeout(optimizeMap, 100);
window.onresize = resizeWin;
resizeWin();
}
Currently I make an ajax call from the button, and the callback function calls 'AddPin' which adds the pins to the map. I thought I'd add in the map initialization code in case it was relevant. Currently boot() is called on body load.
For me the solution was similar to yours #canadian coder
Microsoft.Maps.Location() only accepts float values, no strings and Int.
I use MVC architecture and passed a string using a model. Later i converted that string to float and passed to Location.
Problem solved.
var pushpin = new Microsoft.Maps.Pushpin(
center, { icon: '/Content/BingPushpin.png', width: 50, height: 50, draggable: false });
pushpin.setLocation(new Microsoft.Maps.Location
(parseFloat(#Model.Latitude) , parseFloat(#Model.Longitude)));
dataLayer.push(pushpin);
locations.push(new Microsoft.Maps.Location
(parseFloat(#Model.Latitude) , parseFloat(#Model.Longitude)));
EDIT :
Later found out that problem still exist. Another reason can be that you are calling that Map to load twice. So check for any other instance of the map which is being loaded. In my case see below.
$(document).ready(function () {
loadSearchModule(); //calling Map to Load at a div without pushpins
//code to do something
getMapOnLocation();
}
function getMapOnLocation()
{//code to display map with pushpin
}
In the Above example I was telling the control to load my map with PushPins and when the page is fully Loaded load the map without pushpins.
Hope this helps :)
As always I need to ask the question before I figure it out myself.
The issue was that I needed to push a Microsoft location object into the pin and not an object. Like so:
var loc = new Microsoft.Maps.Location(47.592, -122.332);
And NOT my latLong object.
This also seemed to fix the issue of disappearing pins on click event.