I am plotting some text graphics on a graphics layer and now I need to give an option on the map to search for a specific text and navigate to that location and zoom in.
Can someone please guide me with the approach?
Here is the sample code where if I search for 560001, the map should be zoom in to that location.
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<link rel="stylesheet" href="https://js.arcgis.com/4.22/esri/themes/light/main.css">
<script src="https://js.arcgis.com/4.22/"></script>
<script>
require([
"esri/WebMap",
"esri/views/MapView",
"esri/Graphic",
"esri/layers/GraphicsLayer",
"esri/symbols/TextSymbol"
], function (WebMap, MapView, Graphic, GraphicsLayer, TextSymbol) {
const webmap = new WebMap({
portalItem: {
id: "36f72c8a71b542399ca09e10c5aa55f4"
}
});
const view = new MapView({
container: "viewDiv",
map: webmap,
center: [-37.731338217717074, 175.22263172713014],
zoom: 10
});
this.objectTypeList = [
{ Location: '560001', latitude: -37.731338217717074, longitude: 175.22263172713014 },
{ Location: '560002', latitude: -37.487705856583744, longitude: 175.09324140306873 },
{ Location: '560003', latitude: -37.505917118655056, longitude: 175.12036900524583 },
{ Location: '560005', latitude: -37.67287982024181, longitude: 175.23882277753953 },
{ Location: '560005', latitude: -37.67310492511848, longitude: 175.23890380457217 }
];
var graphicsLayer = new GraphicsLayer();
webmap.layers.add(graphicsLayer);
this.objectTypeList.forEach(item => {
var point = {
type: "point",
longitude: item.longitude,
latitude: item.latitude
};
var textSymbol = new TextSymbol({
color: "#BB0000",
haloColor: "black",
haloSize: "1px",
text: `${item.Location}`,
font: { size: 12, family: "Josefin Slab", weight: "bold" }
});
var pointGraphic = new Graphic({
geometry: point,
symbol: textSymbol
});
graphicsLayer.add(pointGraphic);
});
});
</script>
</head>
<body>
<div id="viewDiv"></div>
</body>
</html>
You just need to find the selected (somehow) location in the graphics of GraphicLayer using the symbol text property.
Now, you are using geographic (lon, lat) to create the geometries but your map is in another spatial reference system. In that order to zoom to the geometries you will have to project them.
Take a look a the example I put for you, I use a simple select to choose the graphic, and I use a on client projection method, another option would be server side projection.
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<link rel="stylesheet" href="https://js.arcgis.com/4.22/esri/themes/light/main.css">
<script src="https://js.arcgis.com/4.22/"></script>
<script>
require([
"esri/WebMap",
"esri/views/MapView",
"esri/Graphic",
"esri/layers/GraphicsLayer",
"esri/symbols/TextSymbol",
"esri/geometry/SpatialReference",
"esri/geometry/projection"
], function (WebMap, MapView, Graphic, GraphicsLayer, TextSymbol, SpatialReference, projection) {
const webmap = new WebMap({
portalItem: {
id: "36f72c8a71b542399ca09e10c5aa55f4"
}
});
const view = new MapView({
container: "viewDiv",
map: webmap,
center: [-37.731338217717074, 175.22263172713014],
zoom: 10
});
this.objectTypeList = [
{ Location: '560001', latitude: -37.731338217717074, longitude: 175.22263172713014 },
{ Location: '560002', latitude: -37.487705856583744, longitude: 175.09324140306873 },
{ Location: '560003', latitude: -37.505917118655056, longitude: 175.12036900524583 },
{ Location: '560004', latitude: -37.67287982024181, longitude: 175.23882277753953 },
{ Location: '560005', latitude: -37.67310492511848, longitude: 175.23890380457217 }
];
var graphicsLayer = new GraphicsLayer();
webmap.layers.add(graphicsLayer);
this.objectTypeList.forEach(item => {
var point = {
type: "point",
longitude: item.longitude,
latitude: item.latitude
};
var textSymbol = new TextSymbol({
color: "#BB0000",
haloColor: "black",
haloSize: "1px",
text: `${item.Location}`,
font: { size: 12, family: "Josefin Slab", weight: "bold" }
});
var pointGraphic = new Graphic({
geometry: point,
symbol: textSymbol
});
graphicsLayer.add(pointGraphic);
});
projection.load().then(function() {
const outSR = new SpatialReference({wkid: 2193});
const dic = {};
graphicsLayer.graphics.forEach(g => dic[g.symbol.text] = projection.project(g.geometry, outSR));
view.when(function(){
const locationZoomButton = document.getElementById("locationZoomButton");
locationZoomButton.addEventListener("click", function(){
const locationSelect = document.getElementById("locationSelect");
const locationText = locationSelect.value;
if (dic.hasOwnProperty(locationText)) {
view.goTo(dic[locationText]);
}
});
});
});
});
</script>
</head>
<body>
<div>
<select id="locationSelect">
<option value="560001">560001</option>
<option value="560002">560002</option>
<option value="560003">560003</option>
<option value="560004">560004</option>
<option value="560005">560005</option>
</select>
<button id="locationZoomButton"> Zoom </button>
</div>
<div id="viewDiv"></div>
</body>
</html>
Related
I am doing this successfully on another project and I do not understand at all, why I am getting an empty div here instead of a map. The map should render here:
<template>
<div class="row mt-5">
<div style="height: 500px; width: 500px;" ref="map"></div>
</div>
</template>
And the code:
head() {
return {
title: 'Properties',
script: [{
src: "https://maps.googleapis.com/maps/api/js?key=XXX",
hid: "map",
defer: true,
}]
}
},
mounted(){
const mapOptions = {
zoom: 18,
center: new window.google.maps.LatLng(43.758773, -79.391785),
disableDefaultUI: true,
zoomControl: true
};
const map = new window.google.maps.Map(this.$refs.map, mapOptions);
const position = new window.google.maps.LatLng(43.758773, -79.391785)
const marker = new window.google.maps.Marker({ position })
marker.setMap(map)
},
Inside your mapOptions object change center to center: { lat: 43.758773, lng: -79.391785 }
You can reference this https://developers.google.com/maps/documentation/javascript/examples/map-latlng-literal
I am trying to get popups from the ArcGIS API JS to display using the framework Vue-CLI 3.
But even with a simple sample code, I cannot make it work: Here is the code in vanilla JS:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<title>Popup actions | Sample | ArcGIS API for JavaScript 4.17</title>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<link rel="stylesheet" href="https://js.arcgis.com/4.17/esri/themes/light/main.css" />
<script src="https://js.arcgis.com/4.17/"></script>
<script>
require([
"esri/Map",
"esri/layers/FeatureLayer",
"esri/views/MapView",
"esri/geometry/geometryEngine"
], function (Map, FeatureLayer, MapView, geometryEngine) {
// Create the Map
var map = new Map({
basemap: "gray-vector"
});
// Create the MapView
var view = new MapView({
container: "viewDiv",
map: map,
center: [-117.08, 34.1],
zoom: 11
});
var template = {
// autocasts as new PopupTemplate()
title: "Trail run",
content: "{name}",
};
var featureLayer = new FeatureLayer({
url:
"https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/TrailRuns/FeatureServer/0",
outFields: ["*"],
popupTemplate: template,
});
map.add(featureLayer);
});
</script>
</head>
<body>
<div id="viewDiv"></div>
</body>
</html>
As you can see, when clicking a feature, a popup appears.
If I try to implement this in my vue-CLI project I can not make it work. When clicking on the a feature, it will highlight, but nothing will open. Here is my code .vue:
<template>
<div></div>
</template>
<script>
import { loadModules } from "esri-loader";
export default {
name: "web-map",
mounted() {
// lazy load the required ArcGIS API for JavaScript modules and CSS
loadModules([
"esri/Map",
"esri/views/MapView",
"esri/layers/FeatureLayer",
]).then(([ArcGISMap, MapView, FeatureLayer]) => {
const map = new ArcGISMap({
basemap: "topo-vector",
});
this.view = new MapView({
container: this.$el,
map: map,
center: [-117.08, 34.1],
zoom: 11,
});
var template = {
// autocasts as new PopupTemplate()
title: "Trail run",
content: "{name}",
};
var featureLayer = new FeatureLayer({
url:
"https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/TrailRuns/FeatureServer/0",
outFields: ["*"],
popupTemplate: template,
});
map.add(featureLayer);
});
},
beforeDestroy() {
if (this.view) {
// destroy the map view
this.view.destroy();
}
},
};
</script>
<style scoped>
div {
padding: 0;
margin: 0;
width: 100%;
height: 100%;
}
</style>
Am I missing something? (I followed arcgis api js tutorial to get it work in vue-cli -https://developers.arcgis.com/javascript/latest/guide/vue/ )
Thank you very much for your help!
Julien
Your code is fine, you are just not adding css. You are missing { css: true }, that's all.
loadModules(
["esri/Map", "esri/views/MapView", "esri/layers/FeatureLayer"],
{ css: true } // <-- HERE
).then(([ArcGISMap, MapView, FeatureLayer]) => {
//...
}
HERE code with the fix.
Leaflet this is a popular geo library.
For some reason, I have serious performance problems when using this library together with the Vue.
Problem 1:
More than 500 markers and the page is already beginning to stumble, 2,000 markers - strongly breaks, 10,000 markers - does not load.
On an HTML web page, 50,000 are loaded peacefully.
Problem 2:
The Leaflet.markercluster plugin is very weak, it does not collapse the markers.
mounted() {
this.initMap();
setTimeout(() => {
this.initLocation()
}, 100)
},
methods: {
initMap() {
this.map = L.map('map').setView([38.63, -90.23], 12);
this.tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© OpenStreetMap contributors',
});
this.tileLayer.addTo(this.map);
},
initLocation() {
this.map.locate({
setView: true,
maxZoom: 17
});
//Leaflet.markercluster
let markers = L.markerClusterGroup();
function r(min, max) {
return Math.random() * (max - min) + min;
}
let icon = L.divIcon({
className: 'icon'
});
for (let i = 0; i < 500; i++) {
let marker = L.marker([r(53.82477192, 53.97365592), r(27.3878027, 27.70640622)], {
icon: icon
}).addTo(this.map);
markers.addLayer(marker);
}
this.map.addLayer(markers);
},
}
Do not add your marker both to this.map and to your markers Marker Cluster Group (MCG).
Add them only to the MCG, and let it handle the adding to your map as needed.
new Vue({
el: '#app',
data: {
map: null,
tileLayer: null,
},
mounted() {
this.initMap();
setTimeout(() => {
this.initLocation()
}, 100)
},
methods: {
initMap() {
this.map = L.map(this.$refs.map).setView([53.9, 27.6], 9);
this.tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© OpenStreetMap contributors',
});
this.tileLayer.addTo(this.map);
},
initLocation() {
//this.map.locate({setView: true, maxZoom: 17});
//Leaflet.markercluster
let markers = L.markerClusterGroup();
function r(min, max) {
return Math.random() * (max - min) + min;
}
let icon = L.divIcon({
className: 'icon'
});
// Quick test with 5k markers:
for (let i = 0; i < 5000; i++) {
let marker = L.marker([
r(53.82477192, 53.97365592),
r(27.3878027, 27.70640622)
], {
icon: icon
}) /*.addTo(this.map)*/ ; // <= do not add individual `marker` to map!
markers.addLayer(marker); // <= but only to MCG
}
this.map.addLayer(markers);
},
},
});
<script src="https://unpkg.com/vue#2"></script>
<!-- Leaflet assets -->
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.3.1/dist/leaflet.css" integrity="sha512-Rksm5RenBEKSKFjgI3a41vrjkw4EVPlJ3+OiI65vTjIdo9brlAacEuKOiQ5OFh7cOI1bkDwLqdLw3Zg0cRJAAQ==" crossorigin="" />
<script src="https://unpkg.com/leaflet#1.3.1/dist/leaflet-src.js" integrity="sha512-IkGU/uDhB9u9F8k+2OsA6XXoowIhOuQL1NTgNZHY1nkURnqEGlDZq3GsfmdJdKFe1k1zOc6YU2K7qY+hF9AodA==" crossorigin=""></script>
<!-- Leaflet.markercluster assets -->
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster#1.3.0/dist/MarkerCluster.css">
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster#1.3.0/dist/MarkerCluster.Default.css">
<script src="https://unpkg.com/leaflet.markercluster#1.3.0/dist/leaflet.markercluster-src.js"></script>
<div id="app">
<div ref="map" style="height: 180px"></div>
</div>
For greater performance
When handling a lot of markers make sure to make use of the scaling capabilities of markercluster. They have batch methods for adding and removing lots of markers: addLayers(), removeLayers(), and clearLayers(). They are much more performant. Also note that you can use the chunkedLoading option on the markerClusterGroup. Allowing you to return the main thread frequently, to make the UI more snappy.
So extending on the answer from #ghybs above. I would adapt the snippet like this:
new Vue({
el: '#app',
data: {
map: null,
tileLayer: null,
},
mounted() {
this.initMap();
setTimeout(() => {
this.initLocation()
}, 100)
},
methods: {
initMap() {
this.map = L.map(this.$refs.map).setView([53.9, 27.6], 9);
this.tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© OpenStreetMap contributors',
});
this.tileLayer.addTo(this.map);
},
initLocation() {
//Leaflet.markercluster
const markerClusterGroup = L.markerClusterGroup({
chunkedLoading: true
}); // <= Add chunked loading here
function r(min, max) {
return Math.random() * (max - min) + min;
}
let icon = L.divIcon({
className: 'icon'
});
const markers = []
// Quick test with 5k markers:
for (let i = 0; i < 5000; i++) {
let marker = L.marker([
r(53.82477192, 53.97365592),
r(27.3878027, 27.70640622)
], {
icon: icon
})
markers.push(marker)
// markers.addLayer(marker); // <= do not add individual marker to MCG
}
markerClusterGroup.addLayers(markers) // <= use batch method to add markers to MCG
this.map.addLayer(markerClusterGroup);
},
},
});
<script src="https://unpkg.com/vue#2"></script>
<!-- Leaflet assets -->
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.3.1/dist/leaflet.css" integrity="sha512-Rksm5RenBEKSKFjgI3a41vrjkw4EVPlJ3+OiI65vTjIdo9brlAacEuKOiQ5OFh7cOI1bkDwLqdLw3Zg0cRJAAQ==" crossorigin="" />
<script src="https://unpkg.com/leaflet#1.3.1/dist/leaflet-src.js" integrity="sha512-IkGU/uDhB9u9F8k+2OsA6XXoowIhOuQL1NTgNZHY1nkURnqEGlDZq3GsfmdJdKFe1k1zOc6YU2K7qY+hF9AodA==" crossorigin=""></script>
<!-- Leaflet.markercluster assets -->
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster#1.3.0/dist/MarkerCluster.css">
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster#1.3.0/dist/MarkerCluster.Default.css">
<script src="https://unpkg.com/leaflet.markercluster#1.3.0/dist/leaflet.markercluster-src.js"></script>
<div id="app">
<div ref="map" style="height: 300px"></div>
</div>
I hope that helps others.
I'm trying to set a departureTime options but does not seem to work.
in the example the road ss38 between Bormio and Prato allo Stelvio this season is closed.
Starting in August, I expect that you are using this road and not the one that currently offers through the Swiss.
thanks
Here's my code:
function initialize() {
map = new google.maps.Map(document.getElementById("map"), {
mapTypeId: google.maps.MapTypeId.ROADMAP,
mapTypeControlOptions: {
style: google.maps.MapTypeControlStyle.HORIZONTAL_BAR,
position: google.maps.ControlPosition.TOP_CENTER
},
streetViewControl: true,
streetViewControlOptions: {
position: google.maps.ControlPosition.TOP_LEFT
},
zoomControl: true,
zoomControlOptions: {
position: google.maps.ControlPosition.LEFT_TOP
}
});
map.setZoom(10); // This will trigger a zoom_changed on the map
map.setCenter(new google.maps.LatLng(46.6199, 10.5924));
directionsDisplay.setMap(map);
geocoderService = new google.maps.Geocoder();
directionsService = new google.maps.DirectionsService;
var marker = new google.maps.Marker({
position: new google.maps.LatLng(46.6199, 10.5924),
map: map,
draggable: true
});
var marker2 = new google.maps.Marker({
position: new google.maps.LatLng(46.4693, 10.3731),
map: map,
draggable: true
});
calcolapercorso(tipodipercorso);
}
function calcolapercorso(tipodipercorso) {
var request = {
origin: new google.maps.LatLng(46.6199, 10.5924),
destination: new google.maps.LatLng(46.4693, 10.3731),
optimizeWaypoints: false,
avoidHighways: true,
region: "IT",
travelMode: google.maps.TravelMode.DRIVING,
drivingOptions: {
departureTime: new Date('2016-08-11T00:00:00'),
trafficModel: google.maps.TrafficModel.PESSIMISTIC
}
};
//request.travelMode = google.maps.DirectionsTravelMode.DRIVING;
request.unitSystem = google.maps.UnitSystem.METRIC;
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
var polyLine = {
strokeColor: "#2B8B3F",
strokeOpacity: 1,
strokeWeight: 4,
};
directionsDisplay.setOptions({
polylineOptions: polyLine,
suppressMarkers: true
});
directionsDisplay.setDirections(response);
} else if (status == google.maps.DirectionsStatus.ZERO_RESULTS) {
alert("Could not find a route between these points");
} else {
alert("Directions request failed");
}
});
}
I figured out that the departureTime option does not work when you set any waypoints (at least in Google Maps Javascript API. I didn't confirm RestAPI).
Without waypoints, it worked.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<style type="text/css">
#map_canvas {
width: 600px;
height: 400px;
border: 1px solid gray;
float: left;
}
#direction_panel {
width: 250px;
height: 400px;
border: 1px solid gray;
overflow-y:scroll;
}
</style>
<script src="https://maps.googleapis.com/maps/api/js?language=en&v=3.exp&client=[YOUR_CLIENT_ID]"></script>
<script>
function initialize() {
var mapDiv = document.getElementById("map_canvas");
var map = new google.maps.Map(mapDiv, {
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var form = document.getElementById("form");
google.maps.event.addDomListener(form, "submit", function(event) {
if (event.preventDefault) {
event.preventDefault();
} else {
event.cancelBubble = true;
event.returnValue = false;
}
map.set("traffic", google.maps.TrafficModel[this.trafficModel.value]);
});
var directionsService = new google.maps.DirectionsService();
map.set("directionsService", directionsService);
var panelDiv = document.getElementById("direction_panel");
var directionsRenderer = new google.maps.DirectionsRenderer({
map: map,
panel: panelDiv
});
map.set("directionsRenderer", directionsRenderer);
map.addListener("traffic_changed", onTrafficModelChanged);
}
function onTrafficModelChanged() {
var map = this;
var departureDateTime = document.getElementById("departureTime").value;
var directionsService = map.get("directionsService");
var directionsRenderer = map.get("directionsRenderer");
var trafficModel = map.get("traffic");
var request = {
origin: "<YOUR ORIGIN>",
destination: "<YOUR DESTINATION>",
travelMode: google.maps.TravelMode.DRIVING,
drivingOptions: {
departureTime: new Date(departureDateTime),
trafficModel: trafficModel
}
};
directionsService.route(request, function(result, status) {
if (status != google.maps.DirectionsStatus.OK) {
alert(status);
return;
}
directionsRenderer.setDirections(result);
});
}
google.maps.event.addDomListener(window, "load", initialize);
</script>
</head>
<body>
<div id="frame">
<div id="map_canvas"></div>
<div id="direction_panel"></div>
</div>
<form id="form">
Departure Time: <input type="text" id="departureTime" size=40 value="2016/01/25 21:00 PST"><br>
<input type="radio" name="trafficModel" value="OPTIMISTIC">Optimistic
<input type="radio" name="trafficModel" value="BEST_GUESS" checked>BEST_GUESS
<input type="radio" name="trafficModel" value="PESSIMISTIC">PESSIMISTIC
<input type="submit" value="Search">
</form>
</body>
</html>
i am plotting the markers on the map in openlayer3 as shown below
<!DOCTYPE html>
<html>
<head>
<title>Rotation example</title>
<link rel="stylesheet" href="http://openlayers.org/en/v3.0.0/css/ol.css" type="text/css">
<script src="http://openlayers.org/en/v3.11.2/build/ol.js"></script>
</head>
<body>
<div id="map" style="width:1000px;height:1000px"></div>
<script>
var map;
function initMap() {
map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
target: 'map',
controls: ol.control.defaults({
attributionOptions: ({
collapsible: false,
})
}),
view: new ol.View({
center: ol.proj.fromLonLat([103.986908, 1.353199]),
rotation: 68*Math.PI/180,
zoom: 18
})
});
}
function invokeAddMarker(){
var markerData = [
{
"title": 'point1',
"lat": 1.350664,
"lng": 103.985190,
"description": 'yyyy'
}, {
"title": 'point2',
"lat":1.353604,
"lng": 103.986395,
"description": 'zzz'
}, {
"title": 'point3',
"lat": 1.357227,
"lng": 103.9879999,
"description": 'uuu'
}
];
for(var i=0;i<markerData.length;i++){
addmarker(markerData[i].lat,markerData[i].lng);
}
}
function addmarker(lat,lng){
console.log("*****lat******"+lat);
console.log("*****lng******"+lng);
var iconFeature = new ol.Feature({
geometry: new ol.geom.Point(ol.proj.transform([lng,lat],'EPSG:4326', 'EPSG:3857')),
name: 'camera'
});
var iconStyle = new ol.style.Style({
image: new ol.style.Icon(({
anchor: [0.5, 46],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
opacity: 0.75,
src: 'camera.png'
}))
});
iconFeature.setStyle(iconStyle);
vectorSource = new ol.source.Vector({
features: [iconFeature]
});
/*t clear the markers*/
/*vectorSource.clear();*/
vectorLayer = new ol.layer.Vector({
source: vectorSource
});
map.addLayer(vectorLayer);
map.on('click', function(evt) {
var feature = map.forEachFeatureAtPixel(evt.pixel,
function(feature, layer) {
return feature;
});
if (feature) {
alert("video comes here");
}
});
}
initMap();
invokeAddMarker();
</script>
</body>
</html>
I am facing two problem in the above code
1:the click event will fired 3 times ie, the number marker on the map that should only onces by theory
2:when i resize the div say(new width and height of the div is varied to new value in which the map is displayed)the markers will adjust to div but the event is not fired
please say why is this behavior and how to overcome it