PageSourceSearch

https://www.anthrazit.org/appl/js/swissmap/gllppicker.js

js anthrazit.org collected 2026-10-01 14:15:26 UTC 7,524 bytes, 181 lines download raw bytes

1/*
2########################### anthrazit ag ############################
3### swisstopo / OpenLayers implementation of the gllp lat/lon picker ###
4### Drop-in replacement for the google jquery-gmaps-latlon-picker,   ###
5### working on the same .gllpLatlonPicker markup produced by         ###
6### getGeoCoordsPicker():                                            ###
7###   .gllpMap  .gllpLatitude  .gllpLongitude  .gllpZoom  .gllpIcon  ###
8###   .gllpstreet .gllpzip .gllpcity  + search form / locate button  ###
9#####################################################################
10
11Assumes OpenLayers (ol) + SwissMap are already loaded (via loadSwissMapAssets
12or the admin block). Call SwissGllpPicker.initAll() after the markup is in the DOM.
13*/
14
15(function (global) {
16	'use strict';
17
18	function num(v, d) { v = parseFloat(v); return isNaN(v) ? d : v; }
19
20	var SwissGllpPicker = {
21
22		init: function (container) {
23			if (typeof ol === 'undefined' || typeof $ === 'undefined') return;
24			var $c = $(container);
25			var mapEl = $c.find('.gllpMap').get(0);
26			if (!mapEl || mapEl._swissInited) return;
27			mapEl._swissInited = true;
28
29			var $lat = $c.find('.gllpLatitude');
30			var $lng = $c.find('.gllpLongitude');
31			var lat = num($lat.val(), 46.80121);
32			var lng = num($lng.val(), 8.226692);
33			var zoom = parseInt($c.find('.gllpZoom').val(), 10) || 14;
34
35			var icon = null;
36			var iv = $c.find('.gllpIcon').val();
37			if (iv) { try { icon = JSON.parse(iv); } catch (e) {} }
38
39			mapEl.innerHTML = '';
40			mapEl.style.position = 'relative';
41			if (!mapEl.style.width) mapEl.style.width = '100%';
42
43			var base = SwissMap.baseLayerForStyle();
44			var view = new ol.View({ center: ol.proj.fromLonLat([lng, lat]), zoom: zoom, maxZoom: 21 });
45			var map = new ol.Map({
46				target: mapEl,
47				layers: [base],
48				view: view,
49				controls: ol.control.defaults.defaults({ zoom: true, attribution: true, rotate: false })
50			});
51			SwissMap.addAerialToggle(map, base);
52
53			// draggable pin marker (this is the whole point of the picker)
54			var iconUrl = (icon && icon.url) ? icon.url : '/appl/grfx/marker.svg';
55			// draw the pin at the configured marker size ($cfg['map_marker_size']), like the other
56			// maps; height scales any icon (custom or fallback) preserving aspect ratio
57			var markerSize = parseInt(mapEl.getAttribute('data-markersize'), 10) || 32;
58			var pin = new ol.Feature(new ol.geom.Point(ol.proj.fromLonLat([lng, lat])));
59			var pinLayer = new ol.layer.Vector({
60				source: new ol.source.Vector({ features: [pin] }),
61				zIndex: 10,
62				style: new ol.style.Style({ image: new ol.style.Icon({ src: iconUrl, anchor: [0.5, 1], height: markerSize }) })
63			});
64			map.addLayer(pinLayer);
65
66			var revT;
67			function updateFromPin(doReverse) {
68				var c = ol.proj.toLonLat(pin.getGeometry().getCoordinates());
69				$lat.val(c[1]).trigger('change');
70				$lng.val(c[0]).trigger('change');
71				if (doReverse !== false) {
72					clearTimeout(revT);
73					revT = setTimeout(function () { reverse(c[1], c[0]); }, 300);
74				}
75			}
76
77			// drag the pin
78			var translate = new ol.interaction.Translate({ features: new ol.Collection([pin]) });
79			translate.on('translateend', function () { updateFromPin(); });
80			map.addInteraction(translate);
81
82			// click on the map moves the pin there
83			map.on('singleclick', function (evt) {
84				pin.getGeometry().setCoordinates(evt.coordinate);
85				updateFromPin();
86			});
87
88			// pointer cursor when hovering the pin
89			map.on('pointermove', function (evt) {
90				if (evt.dragging) return;
91				var hit = map.hasFeatureAtPixel(evt.pixel, { layerFilter: function (l) { return l === pinLayer; } });
92				map.getTargetElement().style.cursor = hit ? 'move' : '';
93			});
94
95			// move pin + recentre (used by search / locate)
96			function placePin(lon, la) {
97				pin.getGeometry().setCoordinates(ol.proj.fromLonLat([lon, la]));
98				view.animate({ center: ol.proj.fromLonLat([lon, la]), zoom: Math.max(zoom, 17), duration: 300 });
99				updateFromPin();
100			}
101
102			// swisstopo reverse geocode -> fill street / zip / city
103			function reverse(la, lo) {
104				fetch('https://geodesy.geo.admin.ch/reframe/wgs84tolv95?easting=' + lo + '&northing=' + la + '&format=json')
105					.then(function (r) { return r.json(); })
106					.then(function (p) {
107						if (!p || !p.easting) return;
108						var e = p.easting, n = p.northing;
109						var url = 'https://api3.geo.admin.ch/rest/services/api/MapServer/identify'
110							+ '?geometryType=esriGeometryPoint&returnGeometry=false&tolerance=50&sr=2056&lang=de'
111							+ '&layers=all:ch.bfs.gebaeude_wohnungs_register'
112							+ '&geometry=' + e + ',' + n
113							+ '&imageDisplay=100,100,96'
114							+ '&mapExtent=' + (e - 50) + ',' + (n - 50) + ',' + (e + 50) + ',' + (n + 50);
115						return fetch(url).then(function (r) { return r.json(); }).then(function (d) {
116							var a = d && d.results && d.results[0] && d.results[0].attributes;
117							if (!a) return;
118							$c.find('.gllpstreet').val(a.strname_deinr || '');
119							$c.find('.gllpzip').val(a.dplz4 || '');
120							$c.find('.gllpcity').val(a.dplzname || a.ggdename || '');
121						});
122					}).catch(function () {});
123			}
124
125			// swisstopo forward search -> move pin + recentre
126			function search(q) {
127				if (!q) return;
128				fetch('https://api3.geo.admin.ch/rest/services/api/SearchServer?type=locations&sr=4326&limit=1&searchText=' + encodeURIComponent(q))
129					.then(function (r) { return r.json(); })
130					.then(function (d) {
131						var res = d && d.results && d.results[0];
132						if (res && res.attrs) placePin(res.attrs.lon, res.attrs.lat);
133					}).catch(function () {});
134			}
135			$c.find('.gllpSearchButton').on('click', function () { search($c.find('.gllpSearchField').val()); });
136			$c.find('.gllpSearchField').on('keypress', function (e) { if (e.keyCode === 13) { e.preventDefault(); search($(this).val()); } });
137			$c.find('.gllpLocateButton').on('click', function () {
138				if (navigator.geolocation) navigator.geolocation.getCurrentPosition(function (pos) {
139					placePin(pos.coords.longitude, pos.coords.latitude);
140				});
141			});
142
143			// draw bfs (municipality) polygons when a bfs number set is defined
144			if (typeof bfsNumbers !== 'undefined' && bfsNumbers) {
145				$.post('/appl/api.php?do=getBfsPolygon', { bfsnr: bfsNumbers }, function (data) {
146					if (!data || !data.length) return;
147					var feats = [], ext = ol.extent.createEmpty();
148					for (var i = 0; i < data.length; i++) {
149						var ring = [];
150						for (var j = 0; j < data[i].length; j++) {
151							ring.push(ol.proj.fromLonLat([data[i][j][1], data[i][j][0]])); // [lat,lng] -> [lon,lat]
152						}
153						var poly = new ol.Feature(new ol.geom.Polygon([ring]));
154						feats.push(poly);
155						ol.extent.extend(ext, poly.getGeometry().getExtent());
156					}
157					map.addLayer(new ol.layer.Vector({
158						source: new ol.source.Vector({ features: feats }),
159						zIndex: 5,
160						style: new ol.style.Style({
161							stroke: new ol.style.Stroke({ color: 'rgba(17,106,212,0.6)', width: 1 }),
162							fill: new ol.style.Fill({ color: 'rgba(17,106,212,0.25)' })
163						})
164					}));
165					if (!ol.extent.isEmpty(ext)) view.fit(ext, { padding: [20, 20, 20, 20] });
166				}, 'json');
167			}
168
169			global.setTimeout(function () { map.updateSize(); updateFromPin(false); }, 300);
170			if (global.ResizeObserver) new global.ResizeObserver(function () { map.updateSize(); }).observe(mapEl);
171		},
172
173		initAll: function () {
174			if (typeof $ === 'undefined') return;
175			$('.gllpLatlonPicker').each(function () { SwissGllpPicker.init(this); });
176		}
177	};
178
179	global.SwissGllpPicker = SwissGllpPicker;
180
181})(window);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.