ol-ext/examples/layer/map.carhab.html
2024-06-26 16:24:06 +02:00

537 lines
14 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<!--
Copyright (c) 2015-2018 Jean-Marc VIGLINO,
released under CeCILL-B (french BSD like) licence: http://www.cecill.info/
-->
<title>ol-ext: Carhab</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="icon" type="image/png" href="https://openlayers.org/assets/theme/img/logo70.png" />
<meta name="description" content="Geoportail WFS" />
<meta name="keywords" content="ol, openlayers, layer, source, geoportail, WFS" />
<meta name="msapplication-tap-highlight" content="no" />
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1" />
<!-- jQuery -->
<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.0.min.js"></script>
<!-- ChartJS -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<!-- FontAwesome -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<!-- Openlayers -->
<link rel="stylesheet" href="https://openlayers.org/en/v6.15.1/css/ol.css" />
<script type="text/javascript" src="https://openlayers.org/en/v6.15.1/build/ol.js"></script>
<script src="/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL,Object.assign"></script>
<!-- ol-ext -->
<link rel="stylesheet" href="../../dist/ol-ext.css" />
<script type="text/javascript" src="../../dist/ol-ext.js"></script>
<!-- Pointer events polyfill for old browsers, see https://caniuse.com/#feat=pointer -->
<script src="https://unpkg.com/elm-pep"></script>
<script type="text/javascript" src="../../dist/extra/FontAwesomeDef.js"></script>
<!-- JSTS -->
<script type="text/javascript" src="https://unpkg.com/jsts@1.6.1/dist/jsts.min.js"></script>
<!-- filesaver-js -->
<script type="text/javascript" src="https://cdn.rawgit.com/eligrey/FileSaver.js/aa9f4e0e/FileSaver.min.js"></script>
<link rel="stylesheet" href="../style.css" />
<style>
#map {
position: fixed;
top: 4em;
left: 20em;
bottom: 0;
right: 0;
margin: 0;
}
#data {
position: fixed;
top: 4em;
left: 0;
bottom: 0;
width: 20em;
margin: 0;
padding: .5em;
box-sizing: border-box;
}
#stat {
display: none!important;
max-width: 20em;
}
#stat.visible {
display: block!important;
}
#data > div {
position: relative;
height: 22em;
max-height: calc(100% - 3em);
}
#progressbar {
/*
position: absolute;
bottom: 0;
left: 0;
width: 0;
*/
height: .5em!important;
background-color: #0f0;
transition: .5s;
}
#loading i {
font-size: 2em;
vertical-align: middle;
color: currentColor;
}
#loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
margin: 0;
font-size: 1.5em;
width: 100%;
text-align: center;
opacity: .5;
background: #fff;
padding: 1em 0;
}
.ol-popup.tooltips.black {
margin: 30px 15px;
}
.ol-popup.tooltips .anchor {
display: none;
}
.blend {
mix-blend-mode: multiply;
}
.nodata #data > div {
display: none;
}
#data > .nodata {
display: none;
font-size: 1.2em;
text-align: center;
font-weight: bold;
margin-top: 2em;
}
.nodata #data > .nodata {
display: block;
}
.clip span {
display: block;
opacity: .25;
margin: .5em 0 1em;
font-style: italic;
}
p input:checked ~ span {
opacity: 1;
}
</style>
</head>
<body >
<a href="https://github.com/Viglino/ol-ext" class="icss-github-corner"><i></i></a>
<a href="../../index.html">
<h1>ol-ext: Carhab</h1>
</a>
<!-- DIV pour la carte -->
<div id="map"></div>
<div id="data">
<h2>Statistiques:</h2>
<p class="clip">
<label>
<input name="mode" type="radio" onchange="setMode('map'); clip.setActive(false); calculate();" checked="checked">
Statistique sur la carte
</label>
<br/>
<input id="clip" name="mode" type="radio" onchange="setMode('clip'); clip.setActive(true); calculate();">
<label for="clip">
Statistique autour du pointer
</label>
<span>
radius: <input type="range" min=50 max=400 value=200 onchange="clip.setRadius(parseInt(this.value)); calculate();" style="vertical-align: middle;" />
</span>
<label>
<input name="mode" type="radio" onchange="setMode('com'); clip.setActive(false); calculate();">
Statistiques à la commune
<span style="font-size: .8em; text-align: center;">
<i class="fa fa-spinner fa-pulse fa-lg" style="display: none;"></i> Sélectionnez une commune sur la carte
</span>
</label>
</p>
<p class="nodata">
Pas de données à cette échelle...
<br/>
Zoomer pour afficher des données.
</p>
<div>
<p id="loading"><i class="fa fa-spinner fa-pulse"></i> loading...</p>
<canvas id="stat"></canvas>
</div>
<div id="progressbar"></div>
</div>
<script>
// The map
var map = new ol.Map ({
target: 'map',
view: new ol.View ({
zoom: 14,
center: [696785, 5896331]
}),
layers: [
new ol.layer.Geoportail({
layer: 'ORTHOIMAGERY.ORTHOPHOTOS',
visible: false
}),
new ol.layer.Geoportail({
layer: 'GEOGRAPHICALGRIDSYSTEMS.PLANIGNV2',
visible: true
})
]
});
map.getLayers().item(0).addFilter(new ol.filter.Colorize('grayscale'));
map.getLayers().item(1).addFilter(new ol.filter.Colorize('grayscale'));
var plink = new ol.control.Permalink({ visible: false })
map.addControl(plink);
map.addControl(new ol.control.ScaleLine());
map.addControl(new ol.control.SearchBAN({
zoomOnSelect: 15
}));
var switcher = new ol.control.LayerSwitcher();
map.addControl(switcher);
// Clip interaction
var clip = new ol.interaction.Clip({
radius: 200
});
clip.setActive(false);
/* debug
var v = new ol.layer.Vector({source: new ol.source.Vector})
map.addLayer(v)
*/
var jstsParser = new jsts.io.OL3Parser();
var circle = new ol.geom.Circle([0,0], 0);
// Calculate new statistics
function calculate(b) {
var com = commune.getSource().getFeatures()[0];
config.options.title.text = 'Habitat';
if (mode==='com') {
if (b!==true) {
if (b===false) drawChart([]);
return;
}
if (com) {
console.log(com.getProperties())
config.options.title.text = ['Habitat',com.get('nom')];
}
}
if (map.getView().getZoom() <= carhab.getMinZoom()) {
$('body').addClass('nodata');
return;
} else {
$('body').removeClass('nodata');
}
var t = new Date();
console.log('calculating...')
var ext, gcom;
switch (mode) {
case 'clip': {
circle.setRadius(clip.getRadius()*map.getView().getResolution());
// carhab.changed();
ext = ol.extent.buffer(circle.getCenter().concat(circle.getCenter()), circle.getRadius());
break;
}
case 'com': {
if (com) {
ext = com.getGeometry().getExtent();
gcom = jstsParser.read(com.getGeometry());
} else {
ext = ol.extent.createEmpty();
gcom = null;
}
break;
}
default: {
ext = map.getView().calculateExtent(map.getSize());
break;
}
}
var features = carhab.getSource().getFeaturesInExtent(ext);
var codes = {}, error=0;
features.forEach(function(f) {
var c = f.get('physio');
if (!codes[c]) codes[c] = 0;
if (mode==='map' && ol.extent.containsExtent(ext, f.getGeometry().getExtent())) {
codes[c] += Math.round(ol.sphere.getArea(f.getGeometry(), {
projection: map.getView().getProjection()
}));
} else {
// Using fast extent intersection
var geom;
switch(mode) {
case 'clip': {
geom = circle.intersection(f.getGeometry(), 10);
break;
}
case 'com': {
if (gcom) {
var inter;
try {
inter = gcom.intersection(jstsParser.read(f.getGeometry()));
if (!inter.isEmpty()) {
geom = jstsParser.write(inter);
}
} catch(e) {
// console.log(f.getGeometry().getCoordinates())
error++;
}
}
break;
}
default: {
geom = ol.extent.intersection(ext, f.getGeometry());
break;
}
}
if (geom) {
codes[c] += Math.round(ol.sphere.getArea(geom, {
projection: map.getView().getProjection()
}));
}
/* Using jsts for accurate intersection (complex operation)
var inter = extent.intersection(jstsParser.read(f.getGeometry()));
if (!inter.isEmpty()) {
codes[c] += Math.round(ol.sphere.getArea(jstsParser.write(inter), {
projection: map.getView().getProjection()
}));
}
*/
}
})
drawChart(codes);
if (error) console.log('ERROR:', error);
console.log(((new Date() - t)/1000).toFixed(2)+'s');
// if (tout) clearTimeout(tout);
};
var styleCache = {};
var carhab = new ol.layer.VectorImage({
title: 'Carhab',
className: 'blend',
source: new ol.source.Vector({
format: new ol.format.GeoJSONX(),
url: '../data/habitats_doubs.geojsonx'
}),
style: function(f) {
var physio = f.get('physio');
var style = styleCache[physio];
if (!style) {
if (!carhabStyle[physio]) console.log('INCONNU: ',physio);
style = styleCache[physio] = new ol.style.Style({
fill: new ol.style.Fill({
color: carhabStyle[physio]
})
})
}
return style;
},
opacity: 1,
minZoom: 0 // prevent load on small zoom
});
map.addLayer(carhab);
$('#loading').hide();
carhab.once('change', function() {
calculate();
})
// Set clip interaction
//clip.addLayer(carhab);
clip.addLayer(map.getLayers().item(0));
clip.addLayer(map.getLayers().item(1));
map.addInteraction(clip);
circle.setRadius(200);
// Display chart on move end
map.on('moveend', calculate);
var tout;
map.on('pointermove', function(e) {
if (clip.getActive()) {
circle.setCenter(e.coordinate);
// carhab.changed();
if (tout) clearTimeout(tout);
tout = setTimeout(function() { calculate(); }, 100);
}
});
/* draw chart */
var stat = document.getElementById('stat');
var config = {
type: 'pie',
data: {
datasets: [{
data: [],
backgroundColor: []
}],
// These labels appear in the legend and in the tooltips when hovering different arcs
labels: [],
},
options: {
title: { display: true, text: 'Habitats' },
legend: { display: false },
responsive: true,
maintainAspectRatio: false
}
};
var chart;
var carhabStyle = {
"Feuillus en ilot":[0,140,77],
"Chenes decidus":[0,77,46],
"Chenes sempervirents":[102,128,64],
"Hetres":[0,255,128],
"Chataignier":[64,255,38],
"Robinier":[145,86,51],
"Autre feuillu pur":[175,202,89],
"Melange de feuillus":[0,217,47],
"Coniferes en ilot":[128,128,255],
"Pin maritime pur":[191,38,255],
"Pin sylvestre ":[153,38,255],
"Pin laricio ou pin noir":[77,51,255],
"Pin d'Alep pur":[255,26,255],
"Pin à crochets ou pin cembro":[115,77,230],
"Autre pin":[166,102,255],
"Melange de pins purs":[217,153,255],
"Sapin ou epicea":[26,230,230],
"Meleze":[77,128,255],
"Douglas":[51,153,255],
"Autre conifere autre que pin":[89,255,255],
"Melange d'autres coniferes autres que pins":[1,146,159],
"Melange de coniferes":[64,77,255],
"Melange de feuillus prep et coniferes":[255,102,51],
"Melange de conifères prep et feuillu":[255,64,51],
"Peupleraie":[255,255,0],
"Mineral non vegetalise":[191,191,191],
"Mineral vegetalise":[178,178,178],
"Pelouse":[214,227,188],
"Herbace haut":[75,172,198],
"Prairie":[170,255,0],
"Prairie fauchee":[155,187,89],
"Prairie paturee":[0,176,80],
"arbustif frutice fourre dense":[229,184,183],
"arbustif frutice fourre mixte":[214,138,188],
"Forestier pionnier":[102,153,0],
"Foret mature":[0,102,0],
"Plantation":[148,138,84],
"Aquatique":[84,141,212],
"Pre-bois":[168,112,0],
"Cultures permanentes indeterminees":[255,230,191],
"vergers":[255,0,255],
"Vignes":[95,73,122],
"Cultures annuelles":[255,255,153],
"Prairie temporaire":[152,230,0]
}
for (var i in carhabStyle) {
config.data.datasets[0].data.push(0);
config.data.datasets[0].backgroundColor.push(ol.color.asString(carhabStyle[i]));
config.data.labels.push(i);
}
function drawChart(codes) {
stat.className = 'visible';
var data = [];
for (var i in carhabStyle) {
data.push(codes[i]||0);
}
config.data.datasets[0].data = data;
if (chart) {
chart.update();
} else {
var ctx = stat.getContext('2d');
chart = new Chart(ctx, config);
}
}
var commune = new ol.layer.Vector({
title: 'Commune',
source: new ol.source.Vector()
});
map.addLayer(commune)
map.on('click', function(e) {
if (mode!=='com') {
if (mode==='clip') {
circle.setCenter(e.coordinate);
calculate();
}
return;
}
var coord = ol.proj.transform(e.coordinate, map.getView().getProjection(), 'EPSG:4326');
commune.getSource().clear();
$('.fa-spinner').show();
$.ajax({
url: 'https://geo.api.gouv.fr/communes?lat='+coord[1]+'&lon='+coord[0]+'&fields=&format=geojson&geometry=contour',
success: function(resp) {
var format = new ol.format.GeoJSON();
var features = format.readFeatures(resp, {featureProjection: map.getView().getProjection(), dataProjection: 'EPSG:4326' });
commune.getSource().addFeatures(features);
$('.fa-spinner').hide();
$('#loading').show();
setTimeout(function() {
calculate(true);
$('#loading').hide();
}, 200);
}
})
});
var mode = 'map';
function setMode(k) {
mode = k;
switch (mode) {
case 'clip': {
clip.setActive(true);
break;
}
default: {
clip.setActive(false);
break;
}
}
commune.getSource().clear();
calculate(false);
}
var tip = new ol.Overlay.Tooltip();
map.addOverlay(tip);
var hover = new ol.interaction.Hover({ layers: [carhab], cursor: 'pointer', offsetBox: 5 });
map.addInteraction(hover);
hover.on(['enter', 'leave'], function(e) {
if (e.feature) {
tip.setInfo(e.feature.get('physio'));
} else {
tip.setInfo();
}
})
</script>
</body>
</html>