Openlayers zoom in on cluster - zooming

Is it possible to zoom in on cluster on click? I also don't know how to disable cluster popup. I read this question , but still have no idea how to do it.
Here is the code:
<html>
<script src="../ol/OpenLayers.js"></script>
<script>
var map, select;
var lat = 53.507;
var lon = 28.145;
var zoom = 7;
function init() {
map = new OpenLayers.Map("map",
{ maxExtent: new OpenLayers.Bounds(-20037508.34,-20037508.34,20037508.34,20037508.34),
numZoomLevels: 19,
maxResolution: 156543.0399,
units: 'm',
projection: new OpenLayers.Projection("EPSG:900913"),
displayProjection: new OpenLayers.Projection("EPSG:4326"),
controls: [
new OpenLayers.Control.Navigation(),
new OpenLayers.Control.PanZoomBar(),
new OpenLayers.Control.ScaleLine(),
new OpenLayers.Control.Permalink('permalink'),
new OpenLayers.Control.Attribution(),
new OpenLayers.Control.MousePosition()
] });
var osm = new OpenLayers.Layer.OSM("OpenStreetMap");
map.addLayer(osm);
var lonLat = new OpenLayers.LonLat(lon, lat).transform(map.displayProjection, map.projection);
if (!map.getCenter()) map.setCenter (lonLat, zoom);
var MyStyle = new OpenLayers.Style({
// 'cursor' : 'pointer',
fillColor : "#336699",
fillOpacity : 0.9,
fontColor: "#000080",
fontFamily: "sans-serif, Arial",
// fontWeight: "bold",
externalGraphic: "atm.png",
graphicWidth: 32,
graphicHeight: 37,
label: "${count}",
labelAlign: "ct",
fontSize: "15px",
});
var layer = new OpenLayers.Layer.Vector("Atm", {
protocol: new OpenLayers.Protocol.HTTP({
url: "atm.txt",
format: new OpenLayers.Format.Text({extractStyles: true}),
params: {
extractAttributes: false,
}
}),
styleMap: MyStyle, <!-- --------------------- style -->
projection: map.displayProjection,
strategies: [
new OpenLayers.Strategy.BBOX({ratio: 1, resFactor: 1.1}),
new OpenLayers.Strategy.Cluster({distance: 50, threshold: 3})
]
});
map.addLayer(layer);
// Interaction; not needed for initial display.
selectControl = new OpenLayers.Control.SelectFeature(layer);
map.addControl(selectControl);
selectControl.activate();
layer.events.on({
'featureselected': onFeatureSelect,
'featureunselected': onFeatureUnselect
});
}
// Needed only for interaction, not for the display.
function onPopupClose(evt) {
// 'this' is the popup.
var feature = this.feature;
if (feature.layer) { // The feature is not destroyed
selectControl.unselect(feature);
} else { // After "moveend" or "refresh" events on POIs layer all
// features have been destroyed by the Strategy.BBOX
this.destroy();
}
}
function onFeatureSelect(evt) {
feature = evt.feature;
popup = new OpenLayers.Popup.FramedCloud("featurePopup",
feature.geometry.getBounds().getCenterLonLat(),
new OpenLayers.Size(100,100),
"<h2>"+feature.attributes.title + "</h2>" +
feature.attributes.description,
null, true, onPopupClose);
feature.popup = popup;
popup.feature = feature;
map.addPopup(popup, true);
}
function onFeatureUnselect(evt) {
feature = evt.feature;
if (feature.popup) {
popup.feature = null;
map.removePopup(feature.popup);
feature.popup.destroy();
feature.popup = null;
}
}
</script>
</head>
<body onload="init()">
<div id="map"></div>
</body>
</html>
Thanks. Your post does not have much context to explain the code sections; please explain your scenario more clearly.

function onFeatureSelect(event) {
if(!event.feature.cluster) // if not cluster
{
// handle your popup code for the individual feature
}
else
{
// fetch the cluster's latlon and set the map center to it and call zoomin function
// which takes you to a one level zoom in and I hope this solves your purpose :)
map.setCenter(event.feature.geometry.getBounds().getCenterLonLat());
map.zoomIn();
}
}

Using the example code in the linked question I would iterate over all features in the cluster to create a BBX, and then zoom into that extent.
var cluster_bounds=new OpenLayers.Bounds();
event.feature.cluster.forEach(function(feature){
clouster_bounds.extend(feature.geometry);
})
map.zoomToExtent(cluster_bounds)
If you really don't know how to disable the popups then remove these functions:
function onFeatureSelect(evt) {
function onFeatureUnselect(evt) {
And replace it with:
function onFeatureSelect(event) {
var cluster_bounds=new OpenLayers.Bounds();
event.feature.cluster.forEach(function(feature){
cluster_bounds.extend(feature.geometry);
});
map.zoomToExtent(cluster_bounds);
}

Related

i have a geojson layer button and when i click i have to zoom to the particular layer

this is my layer and i have assigned it to a button, but the zoom is not working when I click the layer button. i tried adding the zoom inside the layer but its not working.
rainfall1 = new ol.layer.Vector({
//title: 'CA_DEVELOPMENT_PLAN',
// extent: [-180, -90, -180, 90],
visible:false,
source: new ol.source.Vector({
url:"./data/village.geojson",
zoom: 12,
format: new ol.format.GeoJSON()
}),
style:function(feature) {
labelStyle.getText().setText(feature.getProperties().CA_NAME);
return style1;
},
declutter: true,
});
document.getElementById("lyr").onclick = function() {
layer1.setVisible(!rainfall1.getVisible());
};
var bindLayerButtonToggle = function (lyr, layer) {
document.getElementById(lyr).onclick = function() {
layer.setVisible(!layer.getVisible());
};
}
bindLayerButtonToggle("lyr", rainfall1);
setVisible will not zoom to a layer, it just turns it on or off.
Instead, you would have to update the view extent, and match it with the layer extent
map.getView().fit(rainfall1.getSource().getExtent());
#JGH's answer might work in some cases but if this is the first time the layer is made visible the source will not be loaded, so if there are no features you will need to wait for it to load before zooming.
if (rainfall1.getSource().getFeatures().length > 0) {
map.getView().fit(rainfall1.getSource().getExtent());
} else {
rainfall1.getSource().once('featuresloadend', function() [
map.getView().fit(rainfall1.getSource().getExtent());
});
}

Openlayers - Only display layers above a certain zoom level

I am working on an open layers map with different vector layers. I would like to add the function, that a certain vector layer is only displayed at a specific zoom value, for example at zoom >= 18. I tried it with the function minZoom and minScale / maxScale, but it didn't work. The vector layer I would like to display at zoom level >= 18 is called "dach layer". I also tried to solve it with an if function:
// dach layer anzeigen versuch
const dach = document.getElementById('dach');
dach.addEventListener('click', function (event) {
var checkBox = document.getElementById("dach");
if (checkBox.checked == true) {
if (map.getZoom() > 17) {
dachLayer.setMap(map);
//hitzeLayer.setVisible(true);
}
} else {
//hitzeLayer.setVisible(false);
dachLayer.setMap(undefined);
}
});
This is the code I use:
import 'ol/ol.css';
import Map from 'ol/Map';
import View from 'ol/View';
import TileLayer from 'ol/layer/Tile';
import Stamen from 'ol/source/Stamen';
import VectorLayer from 'ol/layer/Vector';
import Vector from 'ol/source/Vector';
import GeoJSON from 'ol/format/GeoJSON';
import Style from 'ol/style/Style';
import Circle from 'ol/style/Circle';
import Fill from 'ol/style/Fill';
import Stroke from 'ol/style/Stroke';
import Overlay from 'ol/Overlay';
import {
fromLonLat,
toLonLat
} from 'ol/proj';
import sync from 'ol-hashed';
import OSM from 'ol/source/OSM';
import Feature from 'ol/Feature';
import {
circular
} from 'ol/geom/Polygon';
import Point from 'ol/geom/Point';
import Control from 'ol/control/Control';
import * as olProj from 'ol/proj';
import XYZ from 'ol/source/XYZ';
// define the map
const map = new Map({
target: 'map',
view: new View({
center: fromLonLat([16.37, 48.2]),
zoom: 13
})
});
sync(map);
//Adresssuche
const searchResultSource = new Vector();
const searchResultLayer = new VectorLayer({
source: searchResultSource
});
searchResultLayer.setStyle(new Style({
image: new Circle({
fill: new Fill({
color: 'rgba(0, 128, 0, 1)'
}),
stroke: new Stroke({
color: '#000000',
width: 1.25
}),
radius: 15
})
}));
var element = document.getElementById('search');
element.addEventListener('keydown', listenerFunction);
function listenerFunction(event) {
console.log(event);
console.log(event.keyCode);
if (event.keyCode === 13) {
const xhr = new XMLHttpRequest;
xhr.open('GET', 'https://photon.komoot.de/api/?q=' + element.value + '&limit=3');
xhr.onload = function () {
const json = JSON.parse(xhr.responseText);
const geoJsonReader = new GeoJSON({
featureProjection: 'EPSG:3857'
});
searchResultSource.clear();
const features = geoJsonReader.readFeatures(json);
console.log(features);
searchResultSource.addFeatures(features);
if (!searchResultSource.isEmpty()) {
map.getView().fit(searchResultSource.getExtent(), {
maxZoom: 18,
duration: 500
});
}
};
xhr.send();
}
}
//OpenStreetMap
const OSMbaseLayer = new TileLayer({
type: 'base',
source: new OSM()
});
// Statellit
const satellitLayer = new TileLayer({
source: new XYZ({
attributions: ['Powered by Esri', 'Source: Esri, DigitalGlobe, GeoEye, Earthstar Geographics, CNES/Airbus DS, USDA, USGS, AeroGRID, IGN, and the GIS User Community'],
attributionsCollapsible: false,
url: 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
maxZoom: 30
})
});
//shape
const dachLayer = new VectorLayer({
source: new Vector({
name: 'dach',
url: 'data/dach.geojson',
format: new GeoJSON()
})
});
dachLayer.setStyle(new Style({
fill: new Fill({
color: 'brown'
}),
stroke: new Stroke({
color: 'brown',
width: 0.25
}),
}));
// Layer hinzufügen
map.addLayer(OSMbaseLayer);
map.addLayer(searchResultLayer);
dachLayer.setZIndex(15);
// dach layer anzeigen
const dach = document.getElementById('dach');
dach.addEventListener('click', function (event) {
var checkBox = document.getElementById("dach");
if (checkBox.checked == true) {
dachLayer.setMap(map);
//hitzeLayer.setVisible(true);
} else {
//hitzeLayer.setVisible(false);
dachLayer.setMap(undefined);
}
});
// Get the OSMbase Base-Button
const OSMbase = document.getElementById('OSMbase');
OSMbase.addEventListener('click', function (event) {
//contr.style.color = 'ffffff';
//Andere Layer entfernen
map.removeLayer(satellitLayer);
map.removeLayer(searchResultLayer);
//OSM Layer hinzufügen
map.addLayer(OSMbaseLayer);
map.addLayer(searchResultLayer);
});
// Get the satellit Base-Button
const satellit = document.getElementById('satellit');
satellit.addEventListener('click', function (event) {
//Andere Layer entfernen
map.removeLayer(OSMbaseLayer);
map.removeLayer(searchResultLayer);
//Satelliten Layer hinzufügen
map.addLayer(satellitLayer);
map.addLayer(searchResultLayer);
});
The getZoom() method is derived from the View module:
https://openlayers.org/en/latest/apidoc/module-ol_View-View.html#getZoom
The following works:
dach.addEventListener('click', function (event) {
var checkBox = document.getElementById("dach");
if (checkBox.checked == true) {
if (map.getview().getZoom() > 17) {
dachLayer.setMap(map);
//hitzeLayer.setVisible(true);
}
} else {
//hitzeLayer.setVisible(false);
dachLayer.setMap(undefined);
}
});
At the same time you might want to look into the 'moveend' event on the map to listen for zoom changes instead of click:
map.on('moveend', () => {
// do kewl things
}

Adding MapBox imagery to Cesium BaseLayerPicker

I'm able to add a custom base layer picker to may cesium viewer and can add imagery view models, but can't figure out how to add Map Box as one of those layers. Here is my code so far:
// Cesium Viewer
var viewer = new Cesium.Viewer('cesiumContainer', {
timeline: false,
animation: false,
geocoder: false,
baseLayerPicker: false,
imageryProvider: false
});
// Array of view models (map layers)
var imageryViewModels = [];
// MapBox layer (not working)
imageryViewModels.push(new Cesium.ProviderViewModel({
name : 'Map Box layer',
iconUrl : Cesium.buildModuleUrl('Widgets/Images/ImageryProviders/mapBox.png'),
tooltip : 'A custom layer',
creationFunction : function() {
return Cesium.createTileMapServiceImageryProvider({
url : url,
credit : 'MapBox'
});
}
}));
// Working layer from Cesium docs.
imageryViewModels.push(new Cesium.ProviderViewModel({
name : 'Natural Earth\u00a0II',
iconUrl : Cesium.buildModuleUrl('Widgets/Images/ImageryProviders/naturalEarthII.png'),
tooltip : 'Natural Earth II, darkened for contrast.\nhttp://www.naturalearthdata.com/',
creationFunction : function() {
return Cesium.createTileMapServiceImageryProvider({
url : Cesium.buildModuleUrl('Assets/Textures/NaturalEarthII')
});
}
}));
var blp2 = new Cesium.BaseLayerPicker('baseLayerPickerContainer', {
globe:viewer.scene,
imageryProviderViewModels : imageryViewModels
});
When I add the MapBox layer without the Base Layer Picker, it works great, eg:
var viewer = new Cesium.Viewer('cesiumContainer', {
timeline: false,
animation: false,
geocoder: false,
baseLayerPicker: false,
imageryProvider: new Cesium.UrlTemplateImageryProvider({
url: url
})
});
And for completion, my url is generated like this:
var MAPBOX_ACCESS_TOKEN = 'access-token';
var MAPBOX_STYLE_ID = 'style-id';
var MAPBOX_USERNAME = 'username';
var url = 'https://api.mapbox.com/styles/v1/' + MAPBOX_USERNAME + '/' + MAPBOX_STYLE_ID + '/tiles/256/{z}/{x}/{y}?access_token=' + MAPBOX_ACCESS_TOKEN;
When I try adding the MapBox layer with a ProviderViewModel, I get a 404 and the following Cesium error:
An error occurred in "b": Failed to obtain image tile X: 0 Y: 1 Level: 1.
I'm obviously constructing the ProviderViewModel incorrectly for a custom map layer, but I can't figure out what I need to change.
So I had to do some trial and error to get the MapBox URL right, but here is my solution for anyone else looking:
var MAPBOX_ACCESS_TOKEN = 'your_access_token';
var MAPBOX_STYLE_ID = 'style_id_from_your_account';
var MAPBOX_USERNAME = 'your_mapbox_username';
var defaultMap = 'https://api.mapbox.com/styles/v1/' + MAPBOX_USERNAME + '/' + MAPBOX_STYLE_ID + '/tiles/256/{z}/{x}/{y}?access_token=' + MAPBOX_ACCESS_TOKEN;
Then:
You can create an array to store all the different map themes a user can choose from.
var providerViewModels = [];
providerViewModels.push(new Cesium.ProviderViewModel({
name: 'Name of your map theme (can be anything)',
iconUrl: Cesium.buildModuleUrl("path_to_an_icon_image"),
tooltip: 'some tooltip text (optional)',
creationFunction: function() {
return new Cesium.UrlTemplateImageryProvider({
url: defaultMap
});
}
}));
Finally, you add the layers to your map:
var viewer = new Cesium.Viewer('cesiumContainer', {
imageryProviderViewModels: providerViewModels
});

HTML5 geolocation in Dart

I read about accurate html5 geolocation here: http://diveintohtml5.info/geolocation.html
and it gave some examples about it in JavaScript and I read a Stackoverflow question about hwere to put it in JS, but I dont know where to put it in my Dart code, I have tried a few places but it just gives me syntax errors.
So basically I want to input this :
{maximumAge:600000, timeout:5000, enableHighAccuracy: false});
To this:
if (window.navigator.geolocation != null) {
window.navigator.geolocation.getCurrentPosition().then((position) {
final pos = new LatLng(position.coords.latitude,
position.coords.longitude);
final infowindow = new InfoWindow(new InfoWindowOptions()
..position = pos
..content = 'You are here!'
);
final rectangle = new Rectangle(new RectangleOptions()
..strokeColor = '#FF0000'
..strokeOpacity = 0.8
..strokeWeight = 2
..fillColor = '#FF0000'
..fillOpacity = 0.35
..map = map
..bounds = new LatLngBounds(
new LatLng(40.316002, -76.034599),
new LatLng(40.318002, -76.032599))
);
infowindow.open(map);
map.center = pos;
}, onError : (error) {
handleNoGeolocation(true);
});
} else {
// Browser doesn't support Geolocation
handleNoGeolocation(false);
}
Any help? thanks!
You can just do it like this:
window.navigator.geolocation.getCurrentPosition(maximumAge:new Duration(seconds: 600), timeout: new Duration(seconds: 5), enableHighAccuracy: false)...

jQuery Mobile don't' execute function after pageshow

I have in my Phonegap app this JQM; I create a Google map and I load markers from json file.
When i launch page2, i see the first console.log (coordinates) and the last console.log (2222222) - The intermediate console.log that contains numberOfElements is displays only the first time. If I see the map and i return back the whole script isn't loaded.
Why?
$(document).on('pageshow', '#page2', function () {
var latnow = Number(localStorage.getItem("lat"));
var lngnow = Number(localStorage.getItem("lng"));
var coordinate = new google.maps.LatLng(latnow, lngnow);
console.log(latnow + ' ' + lngnow);
$('#map_canvas').gmap({
'center': coordinate,
'disableDefaultUI': true,
'zoom': 5,
'scrollwheel': false,
'panControl': false
});
$('#map_canvas').gmap().bind('init', function () {
var images = "img/icon.png";
var images2 = "img/icon2.png";
$.getJSON('http://www.site.com/app/json.php?lat=' + latnow + '&lat=' + lngnow + '', function (data) {
var myObject = data;
var numberOfElements = data.markers.length;
console.log(numberOfElements); // <- !!!!!!
if (numberOfElements == 0) {
alert("no result");
$.mobile.changePage("#home");
}
var myObject = JSON.stringify(myObject);
localStorage.setItem("json_near", myObject);
$('#map_canvas').gmap('addMarker', {
'position': coordinate,
'icon': images2,
'bounds': true
});
//marker da json
$.each(data.markers, function (i, marker) {
$('#map_canvas').gmap('addMarker', {
'position': new google.maps.LatLng(marker.latitude, marker.longitude),
'draggable': false,
'bounds': true,
'icon': images
}).click(function () {
$('#map_canvas').gmap('openInfoWindow', {
'content': marker.content,
'maxWidt': 200,
'maxHeight': 400,
'autoScroll': true
}, this);
});
});
});
});
map_element = document.getElementById("map_canvas");
var mapwidth = $(window).width();
var mapheight = $(window).height();
$("#map_canvas").height(mapheight);
$("#map_canvas").width(mapwidth);
google.maps.event.trigger(map_element, 'resize');
console.log("2222222");
});
I assume you are using this plugin - http://code.google.com/p/jquery-ui-map/ , right?
I think it is not a problem of jquery mobile. The pageshow event is called as you can see from those console.log messages.
Try to stick console.log("xxx") into the gmap init handler. I think this is the one which is NOT called at the second time.
Something like
$('#map_canvas').gmap().bind('init', function () {
console.log("xxxxxx");
var images = "img/icon.png";
var images2 = "img/icon2.png";
...
...
});
do you see xxxxxxx in the console every time you get in the page?
If not, try to find the way how to check whether the map was already initialized (second, third, fourth time, etc.) and then, call getJSON directly.