How do i use ArcGIS Maps in Angular-Js? - javascript

How do i use ArcGIS Maps in Angular-Js easily with manipulating the;
zoom
locate
adding markers
search my places by Geo coordinates and Place name
loading markers lazily and the like?
Can some one Give me a sample please.

This website has many examples and sample code:
http://esri.github.io/angular-esri-map/#/home

Well, Below is the sample to load ArcGIS/ESRI map using angular-js and for more details and relevance sample/concept read getting-started from below mentioned link:
<!DOCTYPE html>
<html ng-app="esri-map-example">
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<title>Angular Esri Quick Start</title>
<link rel="stylesheet" href="//js.arcgis.com/4.0/esri/css/main.css">
<style type="text/css">
html, body, .esri-view {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
</head>
<body ng-controller="MapController as vm">
<esri-scene-view map="vm.map" view-options="{scale: 50000000, center: [-101.17, 21.78]}">
</esri-scene-view>
<!-- load Esri JSAPI -->
<script src="//js.arcgis.com/4.0/"></script>
<!-- load AngularJS -->
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.js"></script>
<!-- load angular-esri-map -->
<script src="//unpkg.com/angular-esri-map#2"></script>
<script type="text/javascript">
angular.module('esri-map-example', ['esri.map'])
.controller('MapController', function(esriLoader) {
var self = this;
esriLoader.require(['esri/Map'], function(Map) {
self.map = new Map({
basemap: 'streets'
});
});
});
</script>
</body>
</html>
More more details please click here...
Hoping this will help you to understand and start your implementation :)

I came across a very simple way of adding all the mentioned features and be able to control them in this way.
angular.module('eBlood').directive('esriPointRenderersMap', ['$q', 'appConfig', 'esriLoader', 'esriRegistry', function($q, appConfig, esriLoader, esriRegistry) {
return {
// element only directive
restict: 'E',
// isolate the scope
scope: {
// 1-way string binding
rendererActive: '#',
// 2-way object binding
basemapActive: '=',
clusterTolerance: '=',
heatmapRendererParams: '='
},
compile: function($element, $attrs) {
// remove the id attribute from the main element
$element.removeAttr('id');
// append a new div inside this element, this is where we will create our map
$element.append('<div id=' + $attrs.id + '></div>');
// since we are using compile we need to return our linker function
// the 'link' function handles how our directive responds to changes in $scope
// jshint unused: false
return function(scope, element, attrs, controller) {};
},
controller: function($scope, $element, $attrs) {
var mapDeferred = $q.defer();
var esriApp = {};
// add this map to the registry
if ($attrs.registerAs) {
var deregister = esriRegistry._register($attrs.registerAs, mapDeferred.promise);
// remove this from the registry when the scope is destroyed
$scope.$on('$destroy', deregister);
}
esriApp.createGeoCordFinder = coords => {
return esriLoader.require([
'esri/geometry/Point',
'esri/tasks/Locator'
]).then(x => {
var Point = x[0];
if (!esriApp.mapLocator) {
var Locator = x[1];
esriApp.mapLocator = new Locator('https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer');
}
return esriApp.mapLocator.locationToAddress(new Point(coords)).then(res => {
return res.address.Match_addr;
});
});
};
esriApp.zoomToLocation = mapOptions => {
if (mapOptions.view) {
mapOptions.zoom = mapOptions.zoom || appConfig.pointRenderers.mapOptions.zoom;
mapOptions.view.goTo({
target: [mapOptions.coordinates.longitude, mapOptions.coordinates.latitude],
zoom: mapOptions.zoom
});
// change the marker to the current Geo.
var promise = (!mapOptions.address) ? esriApp.createGeoCordFinder(mapOptions.coordinates) : $q.when(mapOptions.address);
promise.then(location => {
esriApp.changeLocationMarker({
view: mapOptions.view,
attributes: {
address: location
},
geometry: {
longitude: mapOptions.coordinates.longitude,
latitude: mapOptions.coordinates.latitude
}
});
});
}
};
esriApp.createLocateIcon = mapOptions => {
var container;
if (!mapOptions || !mapOptions.view)
return $q.reject('Our MapView is setYet');
container = mapOptions.container |"map";
mapOptions.container = undefined;
mapOptions.goToLocationEnabled = appConfig.goToLocationEnabled;
mapOptions.graphic = null;
return esriLoader.require([
'esri/widgets/Locate'
]).then(x => {
var Locate = x[0];
esriApp.locateWidget = new Locate(mapOptions, container);
esriApp.locateWidget.startup();
if (!container)
mapOptions.view.ui.add(esriApp.locateWidget, 'top-left');
esriApp.locateWidget.on('locate', data => {
esriApp.zoomToLocation({
view: mapOptions.view,
coordinates: data.position.coords
});
});
return esriApp.locateWidget;
});
};
function setSearchWidget(opts) {
var srcNodeRef;
if (!opts || !opts.view) {
return $q.reject('MapView is undefined');
}
srcNodeRef = opts.container;
opts.container = undefined;
opts.showPopupOnSelect = false;
opts.autoSelect = false;
return esriLoader.require([
'esri/widgets/Search'
]).then(x => {
var Search = x[0];
var searchWidget = new Search(opts, srcNodeRef);
searchWidget.startup();
if (!srcNodeRef) {
opts.view.ui.add(searchWidget, 'top-right');
}
searchWidget.on('search-complete', e => {
if (e.results.length > 0 && e.results[0].results.length > 0) {
var res = e.results[0].results[0];
var coords = {
longitude: res.feature.geometry.longitude,
latitude: res.feature.geometry.latitude
};
esriApp.zoomToLocation({
view: opts.view,
coordinates: coords,
address: res.name
});
}
});
return searchWidget;
});
}
var mapoption = {
map: esriApp.map,
container: 'map',
zoom: 3,
padding: {
top: 65
},
view: esriApp.mapView
};
esriApp.buildmap = (mapViewDiv) => {
return esriApp.creatMap({
basemap: $scope.basemapActive
})
.then(map => {
mapoption.map = map;
mapoption.container = mapViewDiv;
return esriApp.createMapView(mapoption);
});
};
esriApp.creatMap = properties => {
return esriLoader.require(['esri/Map'])
.then(esriModules => {
var Map = esriModules[0];
return new Map(properties);
});
};
esriApp.createMapView = config => {
return esriLoader.require(['esri/views/MapView'])
.then(x => {
var MapView = x[0];
esriApp.mapView = new MapView(config);
mapDeferred.resolve({
view: esriApp.mapView
});
return mapDeferred.promise;
});
};
esriApp.map = esriApp.buildmap($attrs.id);
mapoption.view = esriApp.mapView;
esriApp.createLocateIcon(mapoption);
setSearchWidget(mapoption);
mapDeferred.promise.then(function(esriApp) {
// clean up
$scope.$on('$destroy', function() {
esriApp.map.destroy();
});
});
// });
}
};
}]);
The simple directive will be very use full. More so now that it updates the 'appConfig' global config object with the map features. This worked very well for me.
Thanks Guys for you contributions.

Related

Displaying BBOX hash in URL

I think I'm doing something wrong in the variables or syntax... i don't know, help me to correct my code. (I'm using Leaflet for the map show)
Desired Behavior
The user should be able to see the BBOX entering the coordinates into the URL, for example:
.com/#013.0,052.0,013.5,052.5
I only care that the BBOX is shown, I don't care that the URL coordinates change when zooming or moving around the map.
My HTML
<!DOCTYPE html>
<html>
<header>
<link rel="stylesheet" href="style.css" />
<link
rel="stylesheet"
href="https://unpkg.com/leaflet#1.9.3/dist/leaflet.css"
integrity="sha256-kLaT2GOSpHechhsozzB+flnD+zUyjE2LlfWPgU04xyI="
crossorigin=""
/>
<script
src="https://unpkg.com/leaflet#1.9.3/dist/leaflet.js"
integrity="sha256-WBkoXOwTeyKclOHuWtc+i2uENFpDZ9YPdf5Hf+D7ewM="
crossorigin=""
></script>
</header>
<body>
<div id="map"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<script src="https://unpkg.com/leaflet#1.0.1/dist/leaflet.js"></script>
<script src="leaflet-hash.js"></script>
<script>
var map = L.map("map").setView([42, 12], 4);
// var hash = new L.hash(map);
var urlhash = window.location.hash.substring(1).split("/");
var boundingBox = "";
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
maxZoom: 22,
minZoom: 1,
continuousWorld: false,
noWrap: false,
attribution:
'Data by OpenStreetMap, under ODbL.',
detectRetina: false,
}).addTo(map);
var bboxField = L.control({
position: "bottomleft",
});
bboxField.onAdd = function (map) {
//create div container for control
var div = L.DomUtil.create("div", "myButtonBar");
//prevent mouse events from propagating through to the map
L.DomEvent.disableClickPropagation(div);
//create custom radio buttons
div.innerHTML =
'BBOX (Left (LON) ,Bottom (LAT), Right (LON), Top (LAT), comma separated, with or without decimal point):<br><input type="text" id="bbox_field"/><button id="setDimensions">Display BBOX</button><button id="remove">Remove</button>';
return div;
};
bboxField.addTo(map);
$(".myButtonBar").css("font-weight", "bold");
if (urlhash[0] !== "") {
$("#bbox_field").val(urlhash[0]);
draw_bbox(urlhash[0]);
}
function draw_bbox(box) {
var myarray = box.split(",");
var bounds = [
[myarray[1], myarray[0]],
[myarray[3], myarray[2]],
];
boundingBox = L.rectangle(bounds, { color: "#ff7800", weight: 1 });
map.removeLayer(boundingBox);
boundingBox.addTo(map);
map.fitBounds(boundingBox.getBounds());
map.setZoom(map.getZoom() - 1);
}
$("#setDimensions").click(function () {
draw_bbox($("#bbox_field").val());
});
$("#bbox_field").keyup(function (event) {
if (event.keyCode === 13) {
$("#setDimensions").click();
}
});
// console.log(bbox)
$("#remove").click(function () {
map.removeLayer(boundingBox);
});
</script>
</body>
</html>
Leaflet Hash Plugin Code
(function(window) {
var HAS_HASHCHANGE = (function() {
var doc_mode = window.documentMode;
return ('onhashchange' in window) &&
(doc_mode === undefined || doc_mode > 7);
})();
L.hash = function(map) {
this.onHashChange = L.Util.bind(this.onHashChange, this);
if (map) {
this.init(map);
}
};
L.hash.parseHash = function(hash) {
if(hash.indexOf('#') === 0) {
hash = hash.substr(1);
}
var args = hash.split("/");
if (args.length == 3) {
var zoom = parseInt(args[0], 10),
lat = parseFloat(args[1]),
lon = parseFloat(args[2]);
if (isNaN(zoom) || isNaN(lat) || isNaN(lon)) {
return false;
} else {
return {
center: new L.LatLng(lat, lon),
zoom: zoom
};
}
} else {
return false;
}
};
L.hash.formatHash = function(map) {
var center = map.getCenter(),
zoom = map.getZoom(),
precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
return "#" + [zoom,
center.lat.toFixed(precision),
center.lng.toFixed(precision)
].join("/");
},
L.hash.prototype = {
map: null,
lastHash: null,
parseHash: L.hash.parseHash,
formatHash: L.hash.formatHash,
init: function(map) {
this.map = map;
// reset the hash
this.lastHash = null;
this.onHashChange();
if (!this.isListening) {
this.startListening();
}
},
removeFrom: function(map) {
if (this.changeTimeout) {
clearTimeout(this.changeTimeout);
}
if (this.isListening) {
this.stopListening();
}
this.map = null;
},
onMapMove: function() {
// bail if we're moving the map (updating from a hash),
// or if the map is not yet loaded
if (this.movingMap || !this.map._loaded) {
return false;
}
var hash = this.formatHash(this.map);
if (this.lastHash != hash) {
location.replace(hash);
this.lastHash = hash;
}
},
movingMap: false,
update: function() {
var hash = location.hash;
if (hash === this.lastHash) {
return;
}
var parsed = this.parseHash(hash);
if (parsed) {
this.movingMap = true;
this.map.setView(parsed.center, parsed.zoom);
this.movingMap = false;
} else {
this.onMapMove(this.map);
}
},
// defer hash change updates every 100ms
changeDefer: 100,
changeTimeout: null,
onHashChange: function() {
// throttle calls to update() so that they only happen every
// `changeDefer` ms
if (!this.changeTimeout) {
var that = this;
this.changeTimeout = setTimeout(function() {
that.update();
that.changeTimeout = null;
}, this.changeDefer);
}
},
isListening: false,
hashChangeInterval: null,
startListening: function() {
this.map.on("moveend", this.onMapMove, this);
if (HAS_HASHCHANGE) {
L.DomEvent.addListener(window, "hashchange", this.onHashChange);
} else {
clearInterval(this.hashChangeInterval);
this.hashChangeInterval = setInterval(this.onHashChange, 50);
}
this.isListening = true;
},
stopListening: function() {
this.map.off("moveend", this.onMapMove, this);
if (HAS_HASHCHANGE) {
L.DomEvent.removeListener(window, "hashchange", this.onHashChange);
} else {
clearInterval(this.hashChangeInterval);
}
this.isListening = false;
}
};
L.hash = function(map) {
return new L.hash(map);
};
L.map.prototype.addHash = function() {
this._hash = L.hash(this);
};
L.map.prototype.removeHash = function() {
this._hash.removeFrom();
};
})(window);

Use mapbox-gl with requireJS : self.XMLHttpRequest is not a constructor

I am trying to use mapbox-gl with magento2 which uses requireJS. Mapbox-js seems to load but I have got a js error. I don't know if I missed requirejs config or if the error is due to my js code or if it's a bug ?
If someone can help me, thanks you.
mapbox-gl-js version: v1.0.0, v1.2.0 and v1.3.0
browser: Chrome
Steps to Trigger Behavior
1.Try to use mapbox into magento2 with requireJs
2.
3.
Link to Demonstration
No demonstration available sorry.
Expected Behavior
No error
Actual Behavior
Error in broswer console :
mapbox-gl-3.js:635 Uncaught TypeError: self.XMLHttpRequest is not a constructor at mapbox-gl-3.js:635 at dt (mapbox-gl-3.js:654) at Object.mt [as getArrayBuffer] (mapbox-gl-3.js:656) at Function.v.loadGlyphRange (mapbox-gl-3.js:11511) at mapbox-gl-3.js:11474 at mapbox-gl-3.js:9863 at Array.forEach () at Object.t.asyncAll (mapbox-gl-3.js:9862) at v.getGlyphs (mapbox-gl-3.js:11466) at i.getGlyphs (mapbox-gl-3.js:14227) (anonymous) # mapbox-gl-3.js:635 dt # mapbox-gl-3.js:654 mt # mapbox-gl-3.js:656 v.loadGlyphRange # mapbox-gl-3.js:11511 (anonymous) # mapbox-gl-3.js:11474 (anonymous) # mapbox-gl-3.js:9863 t.asyncAll # mapbox-gl-3.js:9862 v.getGlyphs # mapbox-gl-3.js:11466 i.getGlyphs # mapbox-gl-3.js:14227 du.receive # mapbox-gl-3.js:8739
At this moment, this is undefined, I guess it shouldn't but i don 't know how to fix it.
requirejs-config:
var config = { deps: [ [...] ], map: { '*': { [...] mapboxgl: "js/mapbox-gl-3", MapboxGeocoder: "js/mapbox-gl-geocoder.min", turf: "js/turf.min" } }, paths: { [...] }, config: { mixins: { [...] } }, shim : { 'mapbox-gl': { exports: 'mapbox-gl' }, 'leaflet-mapbox-gl': { deps: ['leaflet','mapbox-gl'] } } };
script JS :
`
require(['mapboxgl', 'MapboxGeocoder', 'turf'], function (mapboxgl, MapboxGeocoder, turf) {
// This will let you use the .remove() function later on
if (!('remove' in Element.prototype)) {
Element.prototype.remove = function () {
if (this.parentNode) {
this.parentNode.removeChild(this);
}
};
}
console.log('vahir2');
mapboxgl.accessToken = 'my_token_here';
// This adds the map
var map = new mapboxgl.Map({
// container id specified in the HTML
container: 'map',
// style URL
style: 'mapbox://styles/mapbox/streets-v9?optimize=true',
// initial position in [long, lat] format
center: [6.8541548, 46.4564862],
// initial zoom
zoom: 5,
scrollZoom: true
});
console.log('vahir3');
map.addControl(new mapboxgl.GeolocateControl({
positionOptions: {
enableHighAccuracy: true
},
trackUserLocation: true,
showUserLocation: true
}));
map.addControl(new mapboxgl.NavigationControl());
//geocoder
var geocoder = new MapboxGeocoder({
accessToken: mapboxgl.accessToken, // Set the access token
mapboxgl: mapboxgl, // Set the mapbox-gl instance
marker: false, // Do not use the default marker style
bbox: [-5.7616150379, 41.9409963458, 19.6387755871, 55.208571099]
});
map.addControl(geocoder, 'top-left');
// This adds the data to the map
map.on('load', function (e) {
map.addSource('single-point', {
type: 'geojson',
data: {
type: 'FeatureCollection',
features: [] // Notice that initially there are no features
}
});
map.addLayer({
id: 'point',
source: 'single-point',
type: 'circle',
paint: {
'circle-radius': 10,
'circle-color': '#007cbf',
'circle-stroke-width': 3,
'circle-stroke-color': '#fff'
}
});
geocoder.on('result', function (ev) {
var searchResult = ev.result.geometry;
map.getSource('single-point').setData(searchResult);
var options = {units: 'kilometers'};
stores.features.forEach(function (store) {
Object.defineProperty(store.properties, 'distance', {
value: turf.distance(searchResult, store.geometry, options),
writable: true,
enumerable: true,
configurable: true
});
});
stores.features.sort(function (a, b) {
if (a.properties.distance > b.properties.distance) {
return 1;
}
if (a.properties.distance < b.properties.distance) {
return -1;
}
// a must be equal to b
return 0;
});
var listings = document.getElementById('listings');
while (listings.firstChild) {
listings.removeChild(listings.firstChild);
}
buildLocationList(stores);
function sortLonLat(storeIdentifier) {
var lats = [stores.features[storeIdentifier].geometry.coordinates[1], searchResult.coordinates[1]];
var lons = [stores.features[storeIdentifier].geometry.coordinates[0], searchResult.coordinates[0]];
var sortedLons = lons.sort(function (a, b) {
if (a > b) {
return 1;
}
if (a.distance < b.distance) {
return -1;
}
return 0;
});
var sortedLats = lats.sort(function (a, b) {
if (a > b) {
return 1;
}
if (a.distance < b.distance) {
return -1;
}
return 0;
});
map.fitBounds([
[sortedLons[0], sortedLats[0]],
[sortedLons[1], sortedLats[1]]
], {
padding: 100
});
}
sortLonLat(0);
createPopUp(stores.features[0]);
});
// This is where your '.addLayer()' used to be, instead add only the source without styling a layer
map.addSource("places", {
"type": "geojson",
"data": stores,
tolerance: 3
});
// Initialize the list
buildLocationList(stores);
});
// This is where your interactions with the symbol layer used to be
// Now you have interactions with DOM markers instead
stores.features.forEach(function (marker, i) {
// Create an img element for the marker
var el = document.createElement('div');
el.id = "marker-" + i;
el.className = 'marker';
// Add markers to the map at all points
new mapboxgl.Marker(el, {
offset: [0, -23]
})
.setLngLat(marker.geometry.coordinates)
.addTo(map);
el.addEventListener('click', function (e) {
// 1. Fly to the point
flyToStore(marker);
// 2. Close all other popups and display popup for clicked store
createPopUp(marker);
// 3. Highlight listing in sidebar (and remove highlight for all other listings)
var activeItem = document.getElementsByClassName('active');
e.stopPropagation();
if (activeItem[0]) {
activeItem[0].classList.remove('active');
}
var listing = document.getElementById('listing-' + i);
listing.classList.add('active');
});
});
function flyToStore(currentFeature) {
map.flyTo({
center: currentFeature.geometry.coordinates,
zoom: 15
});
}
function createPopUp(currentFeature) {
var popUps = document.getElementsByClassName('mapboxgl-popup');
if (popUps[0]) popUps[0].remove();
var popup = new mapboxgl.Popup({
closeOnClick: false
})
.setLngLat(currentFeature.geometry.coordinates)
.setHTML('<h3>' + currentFeature.properties.name + '</h3>' +
'<h4>' + currentFeature.properties.desc + '</h4><img style="padding: 0% 0% 5% 6%;" src="/media/wysiwyg/store-locator/' + currentFeature.properties.image + '" />')
.addTo(map);
}
function buildLocationList(data) {
for (i = 0; i < data.features.length; i++) {
var currentFeature = data.features[i];
var prop = currentFeature.properties;
var listings = document.getElementById('listings');
var listing = listings.appendChild(document.createElement('div'));
listing.className = 'item';
listing.id = "listing-" + i;
if (prop.capsules == 1) {
var icon = listing.appendChild(document.createElement('img'));
icon.src = '/media/wysiwyg/store-locator/icon_capsule.png';
icon.style = 'float: right; height:18px;';
}
if (prop.machines == 1) {
var icon = listing.appendChild(document.createElement('img'));
icon.src = '/media/wysiwyg/store-locator/icon_machine.png';
icon.style = 'float: right; height:18px;';
}
var link = listing.appendChild(document.createElement('a'));
link.href = '#';
link.className = 'title';
link.dataPosition = i;
link.innerHTML = prop.name;
var details = listing.appendChild(document.createElement('div'));
details.innerHTML = prop.desc;
if (prop.distance) {
var roundedDistance = Math.round(prop.distance * 100) / 100;
details.innerHTML += '<p><strong>Distance : ' + roundedDistance + ' km</strong></p>';
}
link.addEventListener('click', function (e) {
// Update the currentFeature to the store associated with the clicked link
var clickedListing = data.features[this.dataPosition];
// 1. Fly to the point
flyToStore(clickedListing);
// 2. Close all other popups and display popup for clicked store
createPopUp(clickedListing);
// 3. Highlight listing in sidebar (and remove highlight for all other listings)
var activeItem = document.getElementsByClassName('active');
if (activeItem[0]) {
activeItem[0].classList.remove('active');
}
this.parentNode.classList.add('active');
});
}
}
});
`
Finally I found out that a tiers vendor overwritten "self".

Angularjs: Google Map Api - Google is not defined

I'm working on an angularjs single-page application, and I'm trying to build a mapping system for the application. The map is loading fine, however whenever I attempt to use the geocode functionality, I get the error referenceError: Google is not defined.
Map controller
(function () {
'use strict';
angular
.module('CityWits')
.controller('mapCtrl', mapCtrl);
mapCtrl.$inject = ['$scope', '$http', 'mapApi', '$q'];
function mapCtrl($scope, $http, mapApi, $q){
var vm = this;
vm.setQuery = setQuery;
// todo: Switch this out with deals that are loaded depending on the radius of the map
getBranches();
function setQuery(query) {
console.log("business deal filter controller : query=" + query);
vm.query = query;
vm.focus = false;
}
function getBranches(){
$http.get('app/cwitsTestData/branchData.json').then(function(data){
vm.branches = sortBranches(data.data.branches);
$scope.$broadcast("branchesSorted", vm.branches);
});
}
}
function sortBranches(branches){
var locations, address, text;
locations = [];
for(var branch in branches){
address = branches[branch].address;
text = address.street_line1 + " " + address.city+ " " +address.state;
locations.push(text);
}
return locations;
}
})();
Here's the google factory I wrote to handle the api:
(function() {
'use strict';
angular
.module('CityWits')
.factory('mapApi', mapApi);
function mapApi () {
var mapApi = {}
var markers = [];
var geocoder;
var service;
mapApi.geocode = geocode;
mapApi.marker = marker;
mapApi.distance = distance;
return mapApi;
function geocode (addresses){
geocoder = new google.maps.Geocoder();
var coords = [];
if(geocoder){
for(var i in addresses){
geocoder.geocode( { 'address': addresses[i]}, function(results, status) {
if (status === 'OK') {
coords.push(results[0].geometry.location);
} else {
alert('Geocode was not successful for the following reason: ' + status);
}
});
}
}
}
function distance(start, end, method="DRIVING"){
service = new google.maps.DistanceMatrixService;
service.getDistanceMatrix({
origins: start,
destinations: end,
travelMode: method
}, function (status, response){
if(status ==! "OK"){
console.log("Error: "+status);
} else {
console.log("distance measured");
var result = {};
for(var i in response.rows){
result = response.rows[i].element;
}
return result;
}
});
}
function marker(positions, json){
if(markers.length > 0){
for(o in markers){
markers[o].setMap(null);
}
}
for(x in positions){
}
}
}
})();
And lastly this is the directive that initiates the api:
(function () {
'use strict';
angular
.module('CityWits')
.directive('dealMap', dealMap);
dealMap.$inject = ['$timeout', '$http', 'mapApi'];
function dealMap($timeout, $http, mapApi){
var directive = {
link: link,
templateUrl: 'app/map/map.directive.html',
scope: {
deals: '=',
branches: '='
},
restrict: 'EA'
};
return directive;
function link(scope, element, attrs) {
var script = document.createElement('script');
script.type = 'text/javascript';
script.async = true;
script.defer = true;
script.src = "https://maps.googleapis.com/maps/api/js?key=AIzaSyB4RaOArTNm9C7crfutMVc0KkWIoQG-ZE0";
document.body.appendChild(script);
$timeout(function(){
scope.initialize();
}, 500);
// todo: Do stuff after deals are loaded based on map radius
scope.$on('branchesSorted', function(event, data) {
console.log('deals loaded');
console.log(data);
var points = mapApi.geocode(data);
console.log(points);
});
scope.initialize = function() {
scope.mapOptions = {
zoom: 8,
center: new google.maps.LatLng(22.649907498685803, 88.36255413913727)
};
scope.map = new google.maps.Map(document.getElementById('map'), scope.mapOptions);
};
console.log(scope);
}
}
})();
Apparently this error occurs since the Google Maps API is not yet loaded.
The moment when the data is getting loaded:
$http.get('app/cwitsTestData/branchData.json').then(function(data){
vm.branches = sortBranches(data.data.branches);
$scope.$broadcast("branchesSorted", vm.branches);
});
and afterwards once Geocoder is utilized, there is no any guarantee that Google Maps API is already loaded at that moment:
scope.$on('branchesSorted', function(event, data) {
console.log('deals loaded');
console.log(data);
var points = mapApi.geocode(data); //<--Google Maps API could be still not loaded at that moment
console.log(points);
});
since Google Maps library is getting loaded asynchronously in your example like this:
var script = document.createElement('script');
script.type = 'text/javascript';
script.async = true;
script.defer = true;
script.src = "https://maps.googleapis.com/maps/api/js?key=AIzaSyB4RaOArTNm9C7crfutMVc0KkWIoQG-ZE0";
document.body.appendChild(script);
I would propose the following solution instead.
Let's introduce the following service to load Google Maps API, create the map and notify once it is ready:
.factory('googleMapsApi', function ($rootScope,$window, $q) {
return {
load: function (key) {
var deferred = $q.defer()
if ($window.google && $window.google.maps) {
deferred.resolve($window.google);
}
else {
var url = 'https://maps.googleapis.com/maps/api/js?callback=googleMapsLoad';
if (key) url += "&key=" + key;
var script = document.createElement('script');
script.type = 'text/javascript'
script.src = url;
$window.googleMapsLoad = function () {
deferred.resolve($window.google);
}
document.body.appendChild(script);
}
return deferred.promise;
},
createMap : function(scope,id,options){
var mapObject = new google.maps.Map(document.getElementById(id), options);
scope.$emit('google-maps-loaded',mapObject);
},
onMapReady : function(scope, ready){
var handler = $rootScope.$on('google-maps-loaded', function(evnt,data){ return ready(data);});
scope.$on('$destroy', handler);
}
}
})
Then the map could be created like this via link function of directive:
link: function (scope, element, attributes) {
googleMapsApi.load(scope.key)
.then(function () {
var mapOptions = {
center: scope.center,
zoom: scope.zoom,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
googleMapsApi.createMap(scope,attributes.id,mapOptions);
});
}
and data is loaded in controller like this:
.controller('MyCtrl', function ($scope, googleMapsApi) {
googleMapsApi.onMapReady($scope, function(mapInst) {
console.log('Google Map is ready');
mapInst.data.loadGeoJson('https://storage.googleapis.com/mapsdevsite/json/google.json');
});
});
JSFiddle example

Google Maps AngularJS with multiple addresses

I have an application that uses an AngularJS service and using Angular-Google-Maps and I do get multiple markers on my map but I can't get the click on each marker to work. The only marker that allows a click is the last one which doesn't allow me to close it after opening the window or if I only have one address the marker works as expected. I think I'm close but can't figure out what I might be missing to have the click on the markers work for all of them. Any ideas on what I'm missing or need to do differently?
Here is the markup on my page.
<div ng-app="myMapApp" ng-controller="mapController">
<ui-gmap-google-map center='map.center' zoom='map.zoom' options="options">
<ui-gmap-markers models="directoryMarkers" coords="'self'" icon="'icon'" click="'onClick'">
<ui-gmap-windows show="show">
<div ng-non-bindable>{{organization}}</div>
</ui-gmap-window>
</ui-gmap-markers>
</ui-gmap-google-map>
</div>
The code in myMapApp.js
var app = angular.module("myMapApp", ['uiGmapgoogle-maps', 'ngStorage']);
The code in mapController.js
app.controller('mapController', function ($scope, Geocoder) {
$scope.map = { center: { latitude: 45, longitude: -73 }, zoom: 10 };
var hfValue = $("#ucDirectory_UcResults_hfResults");
$scope.directoryMarkers = [];
var createMarker = function (organization, address, latitude, longitude, i) {
var ret = {
latitude: latitude,
longitude: longitude,
address: address,
organization: organization,
show: false
};
ret.onClick = function () {
console.log("Clicked!");
ret.show = !ret.show;
};
ret["id"] = i;
return ret;
};
var json = jQuery.parseJSON(hfValue[0].value);
var markers = [];
var i = 0;
var org;
for (var key in json) {
if (json.hasOwnProperty(key)) {
org = json[key].organization;
if (json[key].address.length > 0) {
Geocoder.geocodeAddress(json[key].address).then(function (data) {
markers.push(createMarker(org, json[key].address, data.lat, data.lng, i))
$scope.map.center.latitude = data.lat;
$scope.map.center.longitude = data.lng;
});
i++;
}
}
}
$scope.directoryMarkers = markers;
});
The code in geocoder-service.js
* An AngularJS Service for intelligently geocoding addresses using Google's API. Makes use of
* localStorage (via the ngStorage package) to avoid unnecessary trips to the server. Queries
* Google's API synchronously to avoid `google.maps.GeocoderStatus.OVER_QUERY_LIMIT`.
*
* #author: benmj
* #author: amir.valiani
*
* Original source: https://gist.github.com/benmj/6380466
*/
/*global angular: true, google: true, _ : true */
'use strict';
//angular.module('geocoder', ['ngStorage']).factory('Geocoder', function ($localStorage, $q, $timeout, $rootScope) {
app.factory('Geocoder', function ($localStorage, $q, $timeout, $rootScope) {
var locations = $localStorage.locations ? JSON.parse($localStorage.locations) : {};
var queue = [];
// Amount of time (in milliseconds) to pause between each trip to the
// Geocoding API, which places limits on frequency.
var QUERY_PAUSE = 250;
/**
* executeNext() - execute the next function in the queue.
* If a result is returned, fulfill the promise.
* If we get an error, reject the promise (with message).
* If we receive OVER_QUERY_LIMIT, increase interval and try again.
*/
var executeNext = function () {
var task = queue[0],
geocoder = new google.maps.Geocoder();
geocoder.geocode({ address: task.address }, function (result, status) {
if (status === google.maps.GeocoderStatus.OK) {
var parsedResult = {
lat: result[0].geometry.location.lat(),
lng: result[0].geometry.location.lng(),
formattedAddress: result[0].formatted_address
};
locations[task.address] = parsedResult;
$localStorage.locations = JSON.stringify(locations);
queue.shift();
task.d.resolve(parsedResult);
} else if (status === google.maps.GeocoderStatus.ZERO_RESULTS) {
queue.shift();
task.d.reject({
type: 'zero',
message: 'Zero results for geocoding address ' + task.address
});
} else if (status === google.maps.GeocoderStatus.OVER_QUERY_LIMIT) {
if (task.executedAfterPause) {
queue.shift();
task.d.reject({
type: 'busy',
message: 'Geocoding server is busy can not process address ' + task.address
});
}
} else if (status === google.maps.GeocoderStatus.REQUEST_DENIED) {
queue.shift();
task.d.reject({
type: 'denied',
message: 'Request denied for geocoding address ' + task.address
});
} else {
queue.shift();
task.d.reject({
type: 'invalid',
message: 'Invalid request for geocoding: status=' + status + ', address=' + task.address
});
}
if (queue.length) {
if (status === google.maps.GeocoderStatus.OVER_QUERY_LIMIT) {
var nextTask = queue[0];
nextTask.executedAfterPause = true;
$timeout(executeNext, QUERY_PAUSE);
} else {
$timeout(executeNext, 0);
}
}
if (!$rootScope.$$phase) { $rootScope.$apply(); }
});
};
return {
geocodeAddress: function (address) {
var d = $q.defer();
if (_.has(locations, address)) {
d.resolve(locations[address]);
} else {
queue.push({
address: address,
d: d
});
if (queue.length === 1) {
executeNext();
}
}
return d.promise;
}
};
});
As an aside, if you don't have a lot of windows open at the same time, you shouldn't use the windows directive, instead use the window directive and define it as a sibling to your markers. As recommended by the documentation.
But to answer the original question, this plnkr uses your code, minus the geocoding, to produce markers with windows. It takes two clicks on a marker to get to where you want it to be because the click happens before the value is changed.
I think to get the behavior you want it would look more like the following:
html:
<ui-gmap-google-map center='map.center' zoom='map.zoom' options="options">
<ui-gmap-markers fit="true" models="directoryMarkers" coords="'self'" icon="'icon'" click="'onClick'">
</ui-gmap-markers>
<ui-gmap-window show="selected.show" coords="selected">
<div>{{selected.organization}}</div>
</ui-gmap-window>
controller:
$scope.map = {
center: {
latitude: 45,
longitude: -73
},
zoom: 10
};
$scope.directoryMarkers = [];
$scope.selected = null;
var createMarker = function(latitude, longitude, i) {
var ret = {
latitude: latitude,
longitude: longitude,
organization: "Foo",
show: false
};
ret.onClick = function() {
console.log("Clicked!");
$scope.selected = ret;
ret.show = !ret.show;
};
ret["id"] = i;
return ret;
};
var markers = [];
var org;
var coords = chance.coordinates().split(",");
$scope.map.center.latitude = coords[0];
$scope.map.center.longitude = coords[1];
for (var i = 0; i < 20; i++) {
coords = chance.coordinates().split(",");
markers.push(createMarker(coords[0], coords[1], i));
}
$scope.directoryMarkers = markers;
Which can be seen tied together in this plnkr: http://plnkr.co/edit/rT4EufIGcjplgd8orVWu?p=preview

Nokia OVI map autocomplete feature

I am using google API to autocomplete feature of user address. and its working fine.
But now I want to use Nokia OVI Map for address autocomplete feature.
Please help me how to implement the same.
I am using below code
<div id="customSearchBox" class="main-search">
<span class ="caption">Search For Places:</span>
<div module="SearchBox">
<input rel="searchbox-input" class="search-box-bckgrnd" type="text" />
<div rel="searchbox-list" class="search-list"></div>
</div>
</div>
<script>
var customSearchBox = new nokia.places.widgets.SearchBox({
targetNode: 'customSearchBox',
template: 'customSearchBox',
searchCenter: function () {
return {
latitude: 52.516274,
longitude: 13.377678
}
},
onResults: function (data) {
//here you have access to data
alert(data);
}
});
</script>
How to get lat, long in this code
Thanks
Shivam
I got answer of my question by reading document of OVI map.
<script>
var customSearchBox = new nokia.places.widgets.SearchBox({
targetNode: 'customSearchBox',
template: 'customSearchBox',
searchCenter: function () {
return {
latitude: 52.516274,
longitude: 13.377678
}
},
onResults: function (data) {
//here you have access to data
//var a=getData();
renderResults(data);
//alert(data.results[0]);
}
});
function renderResults (data) {
var previewList = document.getElementById ('results');
previewList.innerHTML = '';
var results = data.results;
for (var i = 0, l = results.length; i < l; i++) {
var result = results[i];
var resultLi = document.createElement ('li');
resultLi.innerHTML = result.place.name+" - Lat:"+result.place.location.position.latitude+" Long:"+result.place.location.position.longitude;
//alert(result.place.location.position.longitude);
previewList.appendChild (resultLi);
}
}
</script>
I hope this will help to someone.
Thanks
Shivam
for jQuery you can do it like this with a textfield, because i don't wanted to use the predefined "searchbox widget":
$('#location_address').autocomplete({
focus:function (event, ui) {
return false;
},
search:function () {
$(this).addClass('working');
},
open:function () {
$(this).removeClass('working');
},
select:function (event, ui) {
var position = ui.item.id.split(";");
var coord = new nokia.maps.geo.Coordinate(parseFloat(position[0]), parseFloat(position[1]))
$('#location_address').val(ui.item.label)
$('#location_longitude')[0].value = coord.longitude;
$('#location_latitude')[0].value = coord.latitude;
map.setCenter(coord, "default");
map.setZoomLevel(16);
},
source:function (request, response) {
var searchCenter = {
latitude:52.516274,
longitude:13.377678
};
nokia.places.search.manager.findPlaces({
searchTerm:request.term,
onComplete:function (data, status) {
var nData = data.results.map(function (val, i) {
return {
value:val.place.name,
id:val.place.location.position.latitude + ";" + val.place.location.position.longitude
};
})
response(nData);
},
searchCenter:searchCenter,
didYouMean:5
});
},
minLength:2
});

Categories