Ako nikome ne smeta ja bi ovdje malo opisao svoj hobi projekt i podjelio štogod skromnog programerskog znanja, a možda bude zanimljivo i forumskim kartomanima.
PROJEKT: https://github.com/uselesshb/BiHDataVisualizationWEB: https://uselesshb.github.io/BiHDataVisualization/CILJ: Stvaranje sustava za vizualizaciju podataka (izbora, popisa i sl.) na karti BiH.
MOTIVACIJA: Kad je teško objasnit, nacrtaj - svak voli kad mi se nešto lijepo vizualno prezentira. Učenje meni nove tehnologije.
PROBLEM 1: Odabir tehnologijeI sa strane osobonog razvoja, a i sa tehničke strane izbor je jasno pao na web tehnologije. Većinu svoje karijere radim u c++-u i c#, a nikad nisam napravio ništa sa html-om i javascriptom, što bi po meni svaki programer trebao malo poznavati. Sa tehničke strane je stvar jasna, sustav treba biti lako dostupan svakome ko bi htio stavit neke podatke na mapu, a nema dostupnije stvari od web stranice.
PROBLEM 2: Karta i granicePrva stvar koja je potrebna jest karta, odnosno granice općina, kantona, entiteta i države koje bi kasnije mogao bojati. Prva opcija je bila da sam nacrtam granice po već postojećim slikama kojih ima i tu na forumu u izobilju. U tu svrhu bi koristio
htmlov svg sustav, vektorski način grafičkog prikaza gdje primjerice možete definirati nekoliko točaka na ekranu, a sustav ih poveže crtom. Iako je riječ o puno točaka, puno crta i puno granica to sam čak bio i napravio pomoću besplatnog alata
Inkscape u kojem linije pravite potezom miša, a točke se automatski definiraju. Međutim, palo mi je na pamet da bi stvar možda puno ljepše izgledala kad bi ispod granica bila slika reljefa ili prometnica, što me je dovelo do google mapsa i spoznaje da oni imaju sustav pomoću kojeg se na njihovim mapama mogu crtati razni oblici. Brzo sam od toga odustao jer se sustav plaća svakim njegovim korištenjem da se nešto ucrta (što bi se događalo svaki put kad bi neki korisnik pristupio mom sustavu vizualizacije). Guglanjem za alternativama naišao sam na
Open Street Map, koja je praktički wikipedija među internet kartama. Moderiraju je korisnici. Uz tu mapu se po forumima najčešće veže sustav koji se zove
OpenLayers - ista stvar kao i googleov sustav crtanja oblika osim što je cijela stvar besplatna. OpenLayers funkcionira na način da crta na dva sloja i sastavi ih za konačni prikaz. Na jednom sloju je karta Open Street Mapa, a na drugom sloju su oblici koje sam nacrtam. Više manje ono što sam tražio.
Da bi cijela stvar bila bolja primjetio sam da kad na Open Street Mapu potražim općinu
Grude, prikaže ju omeđenu narančastom granicom, što je značilo da su granice već negdje ucrtane, a pošto je cijela stvar otvorenog tipa ti podaci bi trebali biti javno dostupni. Tako sam došao do
openstreetmap wiki stranice administrativnih granica bih.
PROBLEM 3: Pravilno formatiranje granica sa OpenStreetMapa wikijaPregledom ove wiki stranice je bilo vidljivo da su razni entuzijasti ucrtavali linije granica, te su se čak trudili to raditi po katastarskim podacima. Granice su formatirane na sljedeći način:
Jedna administrativna granica se naziva
relation. Jedan relation je zapravo lista više
way-ova, a to su zapravo međugranične linije. Jedan way samo lista više
node-ova, a jedan node je točka na karti, odnosno njena koordinata. Na primjeru Gruda:
relation,
way između Gruda i Posušja, prvi
node tog waya.
Podaci su tu, sad je trebalo vidjeti kako OpenLayers crta oblike. U OpenLayers sam između ostalih oblika vidio i mogućnost crtanja poligona, zada se niz točaka koje OpenLayers uveže crtom - sve što treba da se ucrta jedna granica. Zaključak je bio sljedeći - sa wiki stranice me samo zanima koje node-ove ima općina Grude i da su poredani pravilno jedan za drugim (da nije jedan na granici sa Posušjom, pa odmah sljedeći neki na granici sa Ljubuškim i sl. situacije), ne trebam taj među sloj - way-ove. Odlučio sam napraviti jednu listu (
nodes) u kojoj su svi node-ovi koji će mi trebati za sve granice (svaki node ima id i koordinate), a drugu listu u kojoj su područja (
areas) - jedno područje (area) je zapravo samo lista node id-ova koji definiraju njegovu granicu.
Ovo sam postigao
python skriptom koja je iskoritila OpenStreetMap API pomoću kojeg se moglo pristupiti podacima relations, ways, nodes u obliku xml-a.
Primjer Gruda. Skripta je morala obaviti još neke stvari poput pravilnog redanja node-ova za jedan area jer na open streetmap wikiju nije nužno sve bilo uredno posloženo.
PROBLEM 4: OpenLayers crtanje poligonaDa bi bilo šta počeli raditi našem index.html-u moraju biti dodane js skripta OpenLayers sustava, kao i skripte areas i nodes, index.js u kojem pišemo naš kod.
Kod:
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
<script src="nodes.js"></script>
<script src="areas.js"></script>
<script src="index.js"></script>
Budući da su podaci (nodes i areas) uredno posloženi za unos u OpenLayers nije bilo komplicirano nacrtati jedan poligon koristeći taj sustav. Osnova tog sustava je objekt koji se naziva Map, u tom objektu se definiraju slojevi(layers), jedan layer je Open Street Map karta, a drugi vector layer u kojem crtamo naše granice. Map objektu još moramo reći gdje se na karti treba poiziconirati i kojim zoomom. Javascript kod u grubo izgleda ovako:
Kod:
const vectorSource = new ol.source.Vector();
//layer na kojem crtamo granice
const vectorLayer = new ol.layer.Vector({
source: vectorSource,
});
//layer koji će prikazati Open Street Map kartu
const tileLayer = new ol.layer.Tile({
source: new ol.source.OSM()
});
//definira gdje se pozicioniramo na karti i koliki je zoom
const mapView = new ol.View({
center: ol.proj.fromLonLat([17.450, 43.930]),
zoom: 8.45
});
//glavni objekt - kažemo mu koje layere da koristi i koji view
const map = new ol.Map({
target: "map",
layers: [
tileLayer,
vectorLayer
],
view: mapView
});
Osnovne stvari su postavljene, crtanje vlastitih oblika u vector layeru se radi pomoću objekta Feature. Feature je objekt koji u sebi sadrži geometriju koju želimo nacrtati, a geometrija je već praktički definirana u areas.js fileu kojeg sam napravio pomoću python skripte. Kad bi dodao sljedeći kod nacrtao bih granicu BiH koja je prva u tom fileu.
Kod:
//stvori feature koristeći poligon granice BiH
const feature = new ol.Feature({geometry: new ol.geom.MultiPolygon(areas[0].polygons)});
//dodaj feature mapi
map.getLayers().getArray()[1].getSource().addFeature(feature);
Stiliziranje jednog Feature-a je također vrlo jednostavno, definira se boja i debljina granice (Stroke) i boja kojom punimo područje (Fill):
Kod:
const style = new ol.style.Style();
const stroke = new ol.style.Stroke({color: "grey", width: 1.25});
const fill = new ol.style.Fill({color: "rgba(120,100,80,0.5)"});
style.setStroke(stroke);
style.setFill(fill);
feature.setStyle(style);
PROBLEM 5: Unos podataka