Leaflet, geojson & hype


(Hans-Gerd Claßen) #1

just a test but works pretty neat :slight_smile:
http://www.aachener-zeitung.de/zva/karlo/region_ACDNHS_Bevoelkerung/


(Jonathan Deutsch) #2

Hype content overlaying a google map?


(Hans-Gerd Claßen) #3

hi jonathan,

it’s a hypefile containing a leafletmap, mapboxtile, loading the geojson for our region. the hypeanimation on the top (mouseover the shapes … ) shows a small hypeanimation for a bit of data …


(Hans-Gerd Claßen) #4

leaflet_ACDNHS.hype.zip (101.6 KB)
For anyone to play around … :slight_smile:


Tags: leaflet, geojson to hypeanimation


#5

For those not familiar with Leaflet… http://leafletjs.com …it’s really good for adding maps to your project.

And if you don’t want to use Google Maps, you want to keep the data local, there’s OpenStreetMaps… http://www.openstreetmap.org/ …it has an export function. :smiley:


(kerguelen) #6

Hi @h_classen
I was looking at your example, very interesting !

I’m building a web app to help people from a small island off the western coast of France locate their land parcels from the field. I did manage to deal with every map display, transparency.
The key function of this web app is to be able to enter in a search box the reference of the parcel and have it displayed on the map.

I know how to send and receive request from the WFS server but have no idea on how to display it and pan the map to its position.

Parcels reference is in the format A23, B1240, F239, etc where letter (A to Q) is the section and following figure is the number.
The search box would let user enter this reference but the code will have to process the reference to give it the form LNNNN (A23> A0023, B1240>B1240, F239>F0239) because this is how it is stored. This new reference would have to be attached to the string FR291550000 to match the complete reference of a parcel in the whole french territory.

Then request is sent to the WFS server in this format (request for parcel C24) :
https://geobretagne.fr/geoserver/cadastre/wfs?request=GetFeature&service=WFS&version=2.0.0&typename=cadastre:CP.CadastralParcel&cql_filter=inspireid='FR291550000C0024'&outputFormat=application/json&srsName=EPSG:4326

Request returns a geojson file that can be displayed as it on the map :

{“type”:“FeatureCollection”,“totalFeatures”:1,“features”:[{“type”:“Feature”,“id”:“CP.CadastralParcel.fid-65bc7863_161062b48e0_672c”,“geometry”:{“type”:“MultiPolygon”,“coordinates”:[[[[-5.106463265354574,48.47092972579322],[-5.10650940293892,48.471086186984095],[-5.10656165119024,48.471266285867316],[-5.106615438025359,48.47145016812781],[-5.106634702023252,48.47144722051312],[-5.106582320413657,48.47126450811039],[-5.106515548972968,48.471031051321006],[-5.106486725418512,48.47093191696945],[-5.106463265354574,48.47092972579322]]]]},“geometry_name”:“geometry”,“properties”:{“inspireid”:“FR291550000C0024”,“geo_parcelle”:“20152901550000C0024”,“label”:“24”,“nationalcadastralreference”:“1550000C0024”,“areavalue”:96,“departement”:“29”,“geo_section”:“20151550000C”,“geo_subdsect”:“20151550000C01”,“geo_indp”:“01”,“beginlifespanversion”:“septembre 2016”,“endlifespanversion”:“septembre 2017”,“coar”:null,“tex2”:null,“codm”:null,“creat_date”:“2007-12-18Z”,“update_dat”:“2015-08-12Z”}}],“crs”:{“type”:“name”,“properties”:{“name”:“urn:ogc:def:crs:EPSG::4326”}}}

OK. I guess I’m not that bad explaining steps in doing things but I’m totally not able to develop this myself.

Any help would be greatly appreciated. Enclosed is a basic hype document showing map and cadastre display.

PS : someone helped me figured out how to transform the input reference entered in the search field (but I still dont’t know how to build the search engine and display the returned Geojson) :

var searchInput = document.getElementById("search").value;
var baseInspireId = "FR291550000";
var letter = searchInput.substring(0,1);
var digits = searchInput.substring(1);
// add the maximum possible numbers of zeros
digits = "000"+digits;
// take only the last four digits
digits = digits.substring(digits.length-4);
var result = baseInspireId + letter + digits;

Get_Geojson_Feature.hype.zip (1.3 MB)


(kerguelen) #7

OK, I think I’am almost there :slight_smile:

I did manage to create a working search box transforming a parcel address (G23) in the right format. This address returns the json file that I want to display on screen.

But I can’t make the request/display function to work. Any idea ?

Get_Geojson_Feature.hype.zip (1.3 MB)


(Hans-Gerd Claßen) #8

i’ve got no time to check your work at the moment, but say you’ve got the jsonUrl:

  1. load it:

     var request = new XMLHttpRequest();
     request.open('GET', youURL, true);
    
     request.onload = function() {
       if (request.status >= 200 && request.status < 400) {
         // Success!
         var data = JSON.parse(request.responseText);
         loadGeojson(data)//load GeoJson on map
       } else {
         // We reached our target server, but it returned an error
    
       }
     };
    
     request.onerror = function() {
       // There was a connection error of some sort
     };
    
     request.send();	
    
  2. then populate the map

     function loadGeojson(geojsondata){	
    
     function style(feature) {
     	return {
     		weight: 1,
     		opacity: 1,
     		color: 'white',
     		dashArray: '3',
     		fillOpacity: 1,
     		fillColor: "orange"
     	};
     }
    
    
    
     geojson = L.geoJson(geojsondata, {
     	style: style,
     }).addTo(map);
    
  3. map.flyTo([lat, lng here the midpoint of your polygon], 19) <- this’ll animate to the new position

  4. when initialising a new geojson -> geojson.remove() <- to remove the old geojsonlayer


(Hans-Gerd Claßen) #9

so here is an example flyTo_geojson.hype.zip (1.3 MB)

roughly clashed together … but should get you started


(kerguelen) #10

Lovely ! Your example is perfect ! Thanks so much !

I tried to add the request code just after the parcel reference is entered in a search box but it doesn’t connect to the display part of the code in my HTML :

<script>
		function myFunction() {
		var searchInput = document.getElementById("myText").value;
		
		//Turn request into full format
		var baseInspireId = "FR291550000";
		var letter = searchInput.substring(0,1);
		var digits = searchInput.substring(1);
		// add the maximum possible numbers of zeros
		digits = "000"+digits;
		// take only the last four digits
		digits = digits.substring(digits.length-4);
		var result = baseInspireId + letter + digits;
		var adresseParcelle = "https://geobretagne.fr/geoserver/cadastre/wfs?request=GetFeature&service=WFS&version=2.0.0&typename=cadastre:CP.CadastralParcel&cql_filter=inspireid=%27"+result+"%27&outputFormat=application/json&srsName=EPSG:4326"
		// Display full parcel adress
		document.getElementById("addressField").innerHTML = adresseParcelle;
		
		 var request = new XMLHttpRequest();
request.open('GET', adresseParcelle, true);

request.onload = function() {
  if (request.status >= 200 && request.status < 400) {
    // Success!
    var data = JSON.parse(request.responseText);
    loadTile(data)
  } else {
    // We reached our target server, but it returned an error

  }
};

request.onerror = function() {
  // There was a connection error of some sort
};

request.send();	


function loadTile(geojsondata){	
		

	
	function style(feature) {
		return {
			weight: 1,
			opacity: 1,
			color: 'white',
			dashArray: '3',
			fillOpacity: 1,
			fillColor: "orange"
		};
	}



	geojson = L.geoJson(geojsondata, {
		style: style,
	}).addTo(map);
	console.log(geojson._layers[Object.keys(geojson._layers)[0]]._latlngs[0][0])
	
	
	var ltlng = geojson._layers[Object.keys(geojson._layers)[0]]._latlngs[0][0];
	var _ltlng = [];
	for(var i = 0; i < ltlng.length; i++){
	var tmpArray = [];
	console.log(Object.keys(ltlng[i]))
	tmpArray[0] = ltlng[i]['lat'];
	tmpArray[1] = ltlng[i]['lng'];
_ltlng.push(tmpArray);
	}
	
	var getCentroid2 = function (arr) {
    var twoTimesSignedArea = 0;
    var cxTimes6SignedArea = 0;
    var cyTimes6SignedArea = 0;

    var length = arr.length

    var x = function (i) { return arr[i % length][0] };
    var y = function (i) { return arr[i % length][1] };

    for ( var i = 0; i < arr.length; i++) {
        var twoSA = x(i)*y(i+1) - x(i+1)*y(i);
        twoTimesSignedArea += twoSA;
        cxTimes6SignedArea += (x(i) + x(i+1)) * twoSA;
        cyTimes6SignedArea += (y(i) + y(i+1)) * twoSA;
    }
    var sixSignedArea = 3 * twoTimesSignedArea;
    return [ cxTimes6SignedArea / sixSignedArea, cyTimes6SignedArea / sixSignedArea];        
}

map.flyTo(getCentroid2(_ltlng), 19)
	
	}

	



		
			}
</script>

(Mark Hunte) #11

A very quick mash up of both your codes. But mainly using Hans’s code in the Hype function.

The submit button is a normal hype button rather than one written in the input code.
flyTo_geojson.hype 2.zip (1.3 MB)

Looks like you will also need to still do Hans’s step 4, for any new geojson after the first run


(kerguelen) #12

@MarkHunte, Thanks !

We are almost there !
Maps should show up when page is loaded and button may trigger request for feature and flit.
I tried to split your code putting map display in a .js connected to “on load scene” and request/display connected to button click. Display works that way but not request.


(Hans-Gerd Claßen) #13

onsceneload:
window.map = L.map(‘map’).setView([48.456469, -5.096704], 15);

//Layer for orthophoto
var options2 = {
	layers: 'ortho-29', // Layer to display from the global databas
	attribution: 'GeoBretagne', // Légende de la source
    minZoom: 10,
    maxZoom: 19,
    opacity: 0.5,
    tms: false
};
layer2 = L.tileLayer.wms('https://geobretagne.fr/geoserver/photo/ows?', options2).addTo(map);

      
   ///Layer for Cadastre
   var options4 = {
   layers: 'CP.CadastralParcel', // Layer to display from the global database
	style : 'inspire_common_DEFAULT', // display style
	attribution: 'GeoBretagne', // Map source
    minZoom: 9,
    maxZoom: 19,
    opacity: 0.5,
    format: 'image/png',
    transparent: true,
    tms: false
};
layer4 = L.tileLayer.wms('https://geobretagne.fr/geoserver/cadastre/ows?', options4).addTo(map);

onbuttonclicked:

if(window.geojson)window.geojson.remove();


///////--------------GET THE input vale and convert it

var searchInput = document.getElementById(“search”).value;
var baseInspireId = “FR291550000”;
var letter = searchInput.substring(0,1);
var digits = searchInput.substring(1);
// add the maximum possible numbers of zeros
digits = “000”+digits;
// take only the last four digits
digits = digits.substring(digits.length-4);

window.result = baseInspireId + letter + digits;

console.log(window.result)

////--------------------^

        var request = new XMLHttpRequest();

request.open(‘GET’, ‘https://geobretagne.fr/geoserver/cadastre/wfs?request=GetFeature&service=WFS&version=2.0.0&typename=cadastre:CP.CadastralParcel&cql_filter=inspireid=’’ +window.result + ‘%27&outputFormat=application/json&srsName=EPSG:4326’, true);

request.onload = function() {
if (request.status >= 200 && request.status < 400) {
// Success!
var data = JSON.parse(request.responseText);
loadTile(data)
} else {
// We reached our target server, but it returned an error

}
};

request.onerror = function() {
// There was a connection error of some sort
};

request.send();

function loadTile(geojsondata){

function style(feature) {
	return {
		weight: 1,
		opacity: 1,
		color: 'white',
		dashArray: '3',
		fillOpacity: 1,
		fillColor: "orange"
	};
}



window.geojson = L.geoJson(geojsondata, {
	style: style,
}).addTo(map);
console.log(geojson._layers[Object.keys(geojson._layers)[0]]._latlngs[0][0])


var ltlng = geojson._layers[Object.keys(geojson._layers)[0]]._latlngs[0][0];
var _ltlng = [];
for(var i = 0; i < ltlng.length; i++){
var tmpArray = [];
console.log(Object.keys(ltlng[i]))
tmpArray[0] = ltlng[i]['lat'];
tmpArray[1] = ltlng[i]['lng'];

_ltlng.push(tmpArray);
}

var getCentroid2 = function (arr) {
var twoTimesSignedArea = 0;
var cxTimes6SignedArea = 0;
var cyTimes6SignedArea = 0;

var length = arr.length

var x = function (i) { return arr[i % length][0] };
var y = function (i) { return arr[i % length][1] };

for ( var i = 0; i < arr.length; i++) {
    var twoSA = x(i)*y(i+1) - x(i+1)*y(i);
    twoTimesSignedArea += twoSA;
    cxTimes6SignedArea += (x(i) + x(i+1)) * twoSA;
    cyTimes6SignedArea += (y(i) + y(i+1)) * twoSA;
}
var sixSignedArea = 3 * twoTimesSignedArea;
return [ cxTimes6SignedArea / sixSignedArea, cyTimes6SignedArea / sixSignedArea];        

}

map.flyTo(getCentroid2(_ltlng), 19)

}

(kerguelen) #14

Sorry, Hans,
I pasted your code, it is fine for setting up the map on load but on clickedbutton doesn’t work.

flyTo_geojson 3.hype.zip (1.3 MB)


(Hans-Gerd Claßen) #15

flyTo_geojson.hype.zip (1.3 MB)
In our team we’ve got a running gag joking each other to be the “the worst apprentice” … you’ve got it today :wink:


(kerguelen) #16

Well, I guess you’re right. Terrible apprentice :wink: and it’s not the teacher’s fault.
I need to take all this coding thing from the start. The basis are not that solid.
Thanks, Hans, again.
Can you tell me what was wrong in my previous .hype ?


(Hans-Gerd Claßen) #17

sry but i did not have a look :frowning:


(kerguelen) #18

Don’t worry, I’ll look myself, that will be good exercice.
With the engine working I’ll be able to do the UI and add different stuff I have skill for. Thanks again for your help.


(Hans-Gerd Claßen) #19

one thing: you’ve loaded the leaflet library twice … leaflet-src.js is not minified and not necessary.

btw. I’ll take the “the worst apprentice” back to myself for today :slight_smile: and feel free to ask if further help is needed

have a best day :slight_smile:


(kerguelen) #20

Be sure I will, master :wink: Viele danke.
Good day to you too