I am displaying markers on the map from geojson file. In the current code, I can add the markers on the map. I want to add fly to or zoom in marker exact location upon click on the marker.how can I achieve that using OpenLayers.
var cityMarker = new ol.layer.Vector({
source: new ol.source.Vector({
format: new ol.format.GeoJSON(),
url: "data/cities.js"
}),
style: new ol.style.Style({
image: new ol.style.Icon({
anchor: [0.5, 0.5],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
scale:0.03,
src: "icons/red-circle.png"
})
})
});
map.addLayer(cityMarker);
bind singleclick event to map
map.on('singleclick', event => {
// get the feature you clicked
const feature = map.forEachFeatureAtPixel(event.pixel, (feature) => {
return feature
})
if(feature instanceof ol.Feature){
// Fit the feature geometry or extent based on the given map
map.getView().fit(feature.getGeometry())
// map.getView().fit(feature.getGeometry().getExtent())
}
})
A separate HTML file for you!
<!DOCTYPE html>
<html>
<head>
<title>GeoJSON</title>
<link
rel="stylesheet"
href="https://openlayers.org/en/v4.6.5/css/ol.css"
type="text/css"
/>
<!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL"></script>
<script src="https://openlayers.org/en/v4.6.5/build/ol.js"></script>
</head>
<body>
<div id="map" class="map"></div>
<script>
var image = new ol.style.Circle({
radius: 5,
fill: null,
stroke: new ol.style.Stroke({ color: "red", width: 1 }),
});
var styles = {
Point: new ol.style.Style({
image: image,
}),
};
var styleFunction = function (feature) {
return styles[feature.getGeometry().getType()];
};
var geojsonObject = {
type: "FeatureCollection",
crs: {
type: "name",
properties: {
name: "EPSG:3857",
},
},
features: [
{
type: "Feature",
geometry: {
type: "Point",
coordinates: [0, 0],
},
},
{
type: "Feature",
geometry: {
type: "Point",
coordinates: [13369643, 3572500],
},
},
],
};
var vectorSource = new ol.source.Vector({
features: new ol.format.GeoJSON().readFeatures(geojsonObject),
});
var vectorLayer = new ol.layer.Vector({
source: vectorSource,
style: styleFunction,
});
var map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM(),
}),
vectorLayer,
],
target: "map",
controls: ol.control.defaults({
attributionOptions: {
collapsible: false,
},
}),
view: new ol.View({
center: [0, 0],
zoom: 2,
}),
});
map.on("singleclick", (event) => {
// get the feature you clicked
const feature = map.forEachFeatureAtPixel(event.pixel, (feature) => {
return feature;
});
if (feature instanceof ol.Feature) {
// Fit the feature geometry or extent based on the given map
map.getView().fit(feature.getGeometry());
// map.getView().fit(feature.getGeometry().getExtent())
}
});
</script>
</body>
</html>
Related
Looked through the docs, but don't see why the events are placed incorrectly in my node app:
Global.js:
var eventList = [];
document.addEventListener('DOMContentLoaded', function() {
var eventDesc = {};
eventDesc = { title: 'Test', start: '2019-10-22', backgroundColor:'red' }; eventList.push( eventDesc );
eventDesc = { title: 'Test2', start: '2019-10-23T10:00:00', end: '2019-10-23T11:00:00', backgroundColor:'blue' }; eventList.push( eventDesc );
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
defaultView: "timeGridWeek",
height: "auto",
slotDuration: "00:60:00",
events: eventList,
plugins: [ 'dayGrid', 'timeGrid' ]
}
);
calendar.render();
});
Getting the following view (expect the blue event to be at 10 am on the grid, but it's off the grid entirely):
grid view
I am trying to center and fit the boundaries of multiple geojson polygon features on my google.maps.Map.
See this non geojson fiddle recreating the effect i'm after.
Is there an easy Google Map API 3 function to do this for geojson data?
See my code below and fiddle here
var map;
window.initMap = function() {
var mapProp = {
center: new google.maps.LatLng(51.8948201,-0.7333298),
zoom: 17,
mapTypeId: 'satellite'
};
map = new google.maps.Map(document.getElementById("map"), mapProp);
map.data.loadGeoJson('https://api.myjson.com/bins/g0tzw');
map.data.setStyle({
strokeColor: '#FF0000',
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: '#FF0000',
fillOpacity: 0.35
});
var bounds = new google.maps.LatLngBounds();
map.fitBounds(bounds);
map.setCenter(bounds.getCenter());
}
I need expert pointers on cleanest and best way approach this.
See working demo of my code above in fiddle.
http://jsfiddle.net/joshmoto/fe2vworc/
I've included my geojson inline so you can see the polygons on the map.
Here is a quick example of how you can get your features bounds. This will just get each feature bounds, extend a LatLngBounds object and then fit the map with these bounds.
var map;
function initialize() {
map = new google.maps.Map(document.getElementById('map-canvas'), {
zoom: 10,
center: {
lat: 0,
lng: 0
}
});
var permits = {
type: "FeatureCollection",
id: "permits",
features: [{
type: "Feature",
properties: {
name: "Alpha Field"
},
geometry: {
type: "Polygon",
coordinates: [
[
[-0.72863, 51.895995],
[-0.730022, 51.896766],
[-0.730754, 51.896524],
[-0.731234, 51.896401],
[-0.731832, 51.896294],
[-0.732345, 51.896219],
[-0.732945, 51.896102],
[-0.732691, 51.895774],
[-0.732618, 51.895531],
[-0.732543, 51.895359],
[-0.73152, 51.894751],
[-0.731037, 51.894488],
[-0.730708, 51.894324],
[-0.72863, 51.895995]
]
]
}
},
{
type: "Feature",
properties: {
name: "Beta Field"
},
geometry: {
type: "Polygon",
coordinates: [
[
[-0.728004, 51.895658],
[-0.72863, 51.895995],
[-0.730708, 51.894324],
[-0.731217, 51.893784],
[-0.730992, 51.893709],
[-0.730793, 51.893567],
[-0.730734, 51.893435],
[-0.730761, 51.89333],
[-0.729696, 51.893244],
[-0.729391, 51.89314],
[-0.729249, 51.893586],
[-0.728991, 51.894152],
[-0.728525, 51.894983],
[-0.728004, 51.895658]
]
]
}
}
]
};
google.maps.event.addListenerOnce(map, 'idle', function() {
// Load GeoJSON.
map.data.addGeoJson(permits);
// Create empty bounds object
var bounds = new google.maps.LatLngBounds();
// Loop through features
map.data.forEach(function(feature) {
var geo = feature.getGeometry();
geo.forEachLatLng(function(LatLng) {
bounds.extend(LatLng);
});
});
map.fitBounds(bounds);
});
}
initialize();
#map-canvas {
height: 150px;
}
<div id="map-canvas"></div>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>
Props to #MrUpsidown for providing the working method to fitBounds.
I'm posting this answer to show my final solution based on #MrUpsidown answer using GeoJson data via loadGeoJson()
Here is my readable GeoJson here http://myjson.com/g0tzw
// initiate map
window.initMap = function() {
// permits json
var permits = 'https://api.myjson.com/bins/g0tzw';
// map properties
var mapProp = {
zoom: 17,
mapTypeId: 'satellite'
};
// google map object
var map = new google.maps.Map(document.getElementById("map"), mapProp);
// load GeoJSON.
map.data.loadGeoJson(permits, null, function () {
// create empty bounds object
var bounds = new google.maps.LatLngBounds();
// loop through features
map.data.forEach(function(feature) {
var geo = feature.getGeometry();
geo.forEachLatLng(function(LatLng) {
bounds.extend(LatLng);
});
});
// fit data to bounds
map.fitBounds(bounds);
});
// map data styles
map.data.setStyle({
strokeColor: '#FF0000',
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: '#FF0000',
fillOpacity: 0.35
});
}
I'm calling initMap via...
<script async defer src="https://maps.googleapis.com/maps/api/js?key=<?=$gmap_api?>&callback=initMap"></script>
See working demo here.
http://jsfiddle.net/joshmoto/eg3vj17m/
I searched for 2 hours now, but it's still not clear if it's possible or not in OL3.
I would like my icons to be fixed size (not to the screen, but to the image map I'm using). I mean, it should cover the same area even if I'm zoomed out, and not covering the half of the map (like I was using a circle polygon, but I have complex Icons so I have to use it as point features). Is there any solution to it?
Like in QGIS: MAP UNITS.
I already have these:
var jelekStyle = function(feature, resolution) {
if(feature.get('tipus')=== 'falu') {
icon = '00_ikonok/falu.png',
size = [115, 233],
scale = 0.05,
anchor = [0.5,46];
} else if(feature.get('tipus')=== 'puszta') {
image = '00_ikonok/puszta.png';
} ...
}
return [new ol.style.Style({
image: new ol.style.Icon({
src: icon,
scale: scale,
size: size,
anchor: anchor,
anchorXUnits: 'fraction',
anchorYUnits: 'pixels'
})
})];
};
...
var jelek = new ol.layer.Vector({
source: new ol.source.Vector({
url: 'sopron_honlap/json/Gorog-Kerekes_Sopron_jelek_GeoJSON.geojson',
format: new ol.format.GeoJSON()
}),
updateWhileAnimating: true,
updateWhileInteracting: true,
style: jelekStyle
});
Yes, there is a solution. In a style function on the layer, you have to scale your icon size by a reference resolution divided by the render resolution.
To update the style even during user interaction, configure your layer with updateWhileInteracting: true and updateWhileAnimating: true. Here is the whole code:
var iconFeature = new ol.Feature(new ol.geom.Point([0, 0]));
var iconStyle = new ol.style.Style({
image: new ol.style.Icon({
anchor: [0.5, 46],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
src: 'https://openlayers.org/en/v4.3.2/examples/data/icon.png'
})
});
var vectorSource = new ol.source.Vector({
features: [iconFeature]
});
var vectorLayer = new ol.layer.Vector({
source: vectorSource,
updateWhileAnimating: true,
updateWhileInteracting: true,
style: function(feature, resolution) {
iconStyle.getImage().setScale(map.getView().getResolutionForZoom(3) / resolution);
return iconStyle;
}
});
var rasterLayer = new ol.layer.Tile({
source: new ol.source.TileJSON({
url: 'https://api.tiles.mapbox.com/v3/mapbox.geography-class.json?secure',
crossOrigin: ''
})
});
var map = new ol.Map({
layers: [rasterLayer, vectorLayer],
target: 'map',
view: new ol.View({
center: [0, 0],
zoom: 3
})
});
html, body, #map {
margin: 0;
width: 100%;
height: 100%;
}
<!DOCTYPE html>
<head>
<link rel="stylesheet" href="https://openlayers.org/en/v4.3.2/css/ol.css">
<script src="https://openlayers.org/en/v4.3.2/build/ol.js"></script>
</head>
<body>
<div id="map" class="map"></div>
</body>
I'm trying to create a small application with Google Maps API.
First, I started with a navigation view named MainView; this is the code:
Ext.define('MyApp.view.MainView', {
extend: 'Ext.navigation.View',
alias: 'widget.mainView',
requires: [
'Ext.navigation.Bar',
'Ext.Button',
'Ext.Panel',
'Ext.Map'
],
config: {
itemId: 'mynavigationview',
navigationBar: {
.......
layout: {
.....
},
items: [
......
]
},
items: [
{
xtype: 'panel',
title: 'Locations',
itemId: 'mapPanel',
items: [
{
xtype: 'map',
height: '100%',
itemId: 'map'
}
]
}
]
}});
Secand, in the controller mapController I made 3 references and 1 control onMapInitialize to center the map on my position with the the library ext.util.Geolocation. This is the code:
Ext.define('MyApp.controller.mapController', {
extend: 'Ext.app.Controller',
alias: 'controller.mapcontroller',
config: {
refs: {
mapView: {
selector: 'mainView #map',
xtype: 'Ext.Map'
},
mainView: {
selector: 'mainView',
xtype: 'Ext.navigation.View'
},
mapPanel: {
selector: 'mainView #mapPanel',
xtype: 'Ext.Panel'
}
},
control: {
"map#map": {
initialize: 'onMapInitialize'
}
}
},
onMapInitialize: function(component, eOpts) {
var map = this.getMapView();
var geo = Ext.create('Ext.util.Geolocation', {
autoUpdate: false,
listeners: {
locationupdate: function(geo) {
var currentLat = geo.getLatitude();
var currentLng = geo.getLongitude();
console.log('marking current location...');
var currentLocation = new google.maps.LatLng(currentLat,currentLng);
map.setCenter(currentLocation);
var marker = new google.maps.Marker({
animation: google.maps.Animation.DROP,
map: map,
position: currentLocation,
title: 'My Current Location'
});
var infoWindow = new google.maps.InfoWindow();
google.maps.event.addListener(marker, "click", function() {
infoWindow.setContent('My current position');
infoWindow.open(this.getMap(), marker);
});
},
locationerror: function(geo, bTimeout, bPermissionDenied, bLocationUnavailable, message) {
if(bTimeout)
Ext.Msg.alert('Timeout occurred',"Could not get current position");
else
alert('Error occurred.');
}
}
});
geo.updateLocation();
}});
But when I test the application in the navigator, this error in this image has also appeared:
I think that, possibly, the instance var map = this.getMapView(); is not working or that's the wrong reference. Can anyone help?
My code (Google Maps API 3 JS) here does just what I want.
Except that each InfoWindow's content is much bigger than this. (And there will be 30 of them!)
So I need to be able to set my own positions for each InfoWindow.
I've spent about 12 hours trying every combination I can think of in the code that follows.
Anyone any ideas what I'm doing wrong, please: I suspect it has to do with (the relationship between):
position: winLatLng
in my creation of the infowindow object and how I call it with:
infowindow.open(map,this);
Ideally, I'd like to use the 5th and 6th elements of the array into winLatLng. But nothing I can do works.
Thanks so much for anyone who has the time to suggest a way to do this!
Full code follows:
<!DOCTYPE html>
<html>
<head>
<title>Foundation 30 Year Anniversary Maps Prototype</title>
<script src='http://code.jquery.com/jquery.min.js' type='text/javascript'></script>
<style>
html {
height: 100%;
}
body {
height: 100%;
margin: 0;
padding: 0;
}
#map_canvas {
width: 900px;
height: 700px;
}
</style>
</head>
<body>
<script type="text/javascript"
src="http://maps.google.com/maps/api/js?">
</script>
<script type="text/javascript">
var infowindow = null;
var MY_MAPTYPE_ID = 'custom_style';
$(document).ready(function () { initialize(); });
function initialize() {
google.maps.Map.prototype.setCenterWithOffset= function(LatLng, offsetX, offsetY) {
var map = this;
var ov = new google.maps.OverlayView();
ov.onAdd = function() {
var proj = this.getProjection();
var aPoint = proj.fromLatLngToContainerPixel(LatLng);
aPoint.x = aPoint.x+offsetX;
aPoint.y = aPoint.y+offsetY;
map.setCenter(proj.fromContainerPixelToLatLng(aPoint));
};
ov.draw = function() {};
ov.setMap(this);
};
var featureOpts = [{
"featureType": "administrative",
"stylers": [
{ "color": "#848080" },
{ "weight": 0.1 }
] },
{
"featureType": "administrative.country",
"elementType": "labels",
"stylers": [
{ "visibility": "off" }
]},{
"featureType": "water",
"stylers": [
{ "color": "#C3C3C6"}
] },{
"featureType": "landscape.natural",
"stylers": [
{ "color": "#F0F0F0"}
] },{
}
]
google.maps.visualRefresh=true;
var myLatlng = new google.maps.LatLng(51.30, 0.7);
var centerMap = new google.maps.LatLng(51.30, 0.7);
var mapOptions = {
zoom: 2,
disableDefaultUI: true,
center: centerMap,
mapTypeControlOptions: {
mapTypeIds: [google.maps.MapTypeId.ROADMAP, MY_MAPTYPE_ID]
},
mapTypeId: MY_MAPTYPE_ID
};
var styledMapOptions = {
name: 'Custom Style'
};
var map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
map.setCenterWithOffset(myLatlng, 50, 225);
var customMapType = new google.maps.StyledMapType(featureOpts, styledMapOptions);
map.mapTypes.set(MY_MAPTYPE_ID, customMapType);
setMarkers(map, sites);
var winLatLng;
infowindow = new google.maps.InfoWindow({
disableAutoPan : true,
position: winLatLng
});
};
var losangelescontentString = 'Los Angeles content';
var portonovocontentstring = 'Porto Novo content';
var florencecontentstring = 'Florence content';
var shackletoncontentstring= 'Shackleton content';
var sites = [
['Los Angeles', 34.054082,-118.24261, losangelescontentString,-17,30],
['Porto Novo', 6.501411,2.604275, portonovocontentstring,-54.054082,0],
['Shackleton', -77.550000, 166.150000, shackletoncontentstring,0,0],
['Florence', 43.773046,11.255901, florencecontentstring,-10,18]
];
function setMarkers(map, markers) {
for (var i = 0; i < markers.length; i++) {
var sites = markers[i];
var siteLatLng = new google.maps.LatLng(sites[1], sites[2]);
var winLatLng = new google.maps.LatLng(sites[4], sites[5]);
var marker = new google.maps.Marker({
title: sites[0],
position: siteLatLng,
html: sites[3],
map: map
});
google.maps.event.addListener(marker, "click", function () {
infowindow.setContent(this.html);
infowindow.open(map,this);
});
}
}
</script>
<div id="map_canvas"></div>
</body>
</html>
If you use the google.maps.InfoWindow.open(map, marker) syntax it positions the infowindow relative to the marker. If you don't want that, use the google.maps.InfoWindow.open(map) after calling google.maps.InfoWindow.setPosition(desiredPosition).
google.maps.event.addListener(marker, "click", function () {
infowindow.setContent(this.html);
infowindow.setPosition(winLatLng);
infowindow.open(map);
});
Although, since you aren't using function closure, you may want to set winLatLng as a property of the marker, then use it in the click listener like this:
function setMarkers(map, markers) {
for (var i = 0; i < markers.length; i++) {
var sites = markers[i];
var siteLatLng = new google.maps.LatLng(sites[1], sites[2]);
var winLatLng = new google.maps.LatLng(sites[4], sites[5]);
var marker = new google.maps.Marker({
title: sites[0],
position: siteLatLng,
html: sites[3],
winLatLng: winLatLng,
map: map
});
google.maps.event.addListener(marker, "click", function () {
infowindow.setContent(this.html);
infowindow.setPosition(this.winLatLng);
infowindow.open(map);
});
}
}
working fiddle