mirror of
https://github.com/Viglino/ol-ext.git
synced 2026-01-18 17:11:52 +00:00
554 lines
17 KiB
JavaScript
554 lines
17 KiB
JavaScript
// Get operations select
|
|
var operations = $('#operations').remove().html();
|
|
|
|
// Permalink
|
|
var perma = new ol.control.Permalink();
|
|
if (perma.getUrlParam('embed')) {
|
|
$('body > a').hide();
|
|
$('.info').hide();
|
|
$('#map').css('top', 0);
|
|
$('.options').css('top', 0);
|
|
}
|
|
|
|
// Color input
|
|
var onChangeColor = function() {}
|
|
$('#color input').spectrum({
|
|
flat: true,
|
|
localStorageKey: 'spectrum',
|
|
showAlpha: false,
|
|
showPalette: true,
|
|
showInitial: true,
|
|
showInput: true,
|
|
chooseText: "choisir",
|
|
cancelText: "annuler",
|
|
preferredFormat: "hex3",
|
|
clickoutFiresChange: true,
|
|
change: function(color) {
|
|
onChangeColor(color.toHexString());
|
|
onChangeColor = function() {};
|
|
}
|
|
});
|
|
$('#color .sp-choose').click(function() {
|
|
onChangeColor($('#color input').val());
|
|
});
|
|
|
|
// The map
|
|
var map = new ol.Map({
|
|
target: 'map',
|
|
view: new ol.View ({
|
|
zoom: 15,
|
|
center: [261204.43490751847, 6250258.191535994]
|
|
}),
|
|
interactions: ol.interaction.defaults(),
|
|
// layers: [ new ol.layer.Geoportail('ORTHOIMAGERY.ORTHOPHOTOS')]
|
|
});
|
|
map.addControl(perma);
|
|
|
|
// Vector layer
|
|
var vlayer = new ol.layer.VectorTile({
|
|
title: "Plan IGN vecteur",
|
|
renderMode: 'hybrid',
|
|
source: new ol.source.VectorTile({
|
|
tilePixelRatio: 1,
|
|
tileGrid: ol.tilegrid.createXYZ({ maxZoom: 19 }),
|
|
format: new ol.format.MVT(),
|
|
projection: new ol.proj.Projection({code:"EPSG:3857"}),
|
|
//url: "https://vectortiles.ign.fr/rok4server/1.0.0/PLAN.IGN/{z}/{x}/{y}.pbf",
|
|
//url : "https://wxs.ign.fr/choisirgeoportail/geoportail/tms/1.0.0/PLAN.IGN/{z}/{x}/{y}.pbf",
|
|
url : "https://data.geopf.fr/tms/1.0.0/PLAN.IGN/{z}/{x}/{y}.pbf",
|
|
// url : "https://wxs.ign.fr/essentiels/geoportail/tms/1.0.0/PLAN.IGN/{z}/{x}/{y}.pbf",
|
|
// url: "https://vectortiles.ign.fr/rok4server/1.0.0/PLAN.IGN/{z}/{x}/{y}.pbf",
|
|
// url: "https://tiles.openfreemap.org/planet/20241002_001001_pt/{z}/{x}/{y}.pbf",
|
|
attributions: '<a href="https://geoservices.ign.fr/blog/2018/07/08/nouveautes_vecteur.html">© IGN-Géoportail</a>',
|
|
}),
|
|
declutter: true
|
|
});
|
|
map.addLayer(vlayer);
|
|
|
|
// Lecture du fichier de style
|
|
var currentStyle;
|
|
var config = {};
|
|
// IGN base style
|
|
var baseStyles = {};
|
|
|
|
ol.ext.Ajax.get({
|
|
//url: './styles/planign.json',
|
|
url: 'https://data.geopf.fr/annexes/ressources/vectorTiles/styles/PLAN.IGN/standard.json',
|
|
// url: 'https://wxs.ign.fr/an7nvfzojv5wa96dsga5nk8w/static/vectorTiles/styles/PLAN.IGN/classique.json',
|
|
// url: 'https://vectortiles.ign.fr/demonstrateur/styles/planign.json',
|
|
//url: 'http://calac-4.ign.fr/pyramide_ecran/style_mapbox.json',
|
|
// url: 'https://vectortiles.ign.fr/demonstrateur/styles/gris.json',
|
|
// url: 'https://vectortiles.ign.fr/demonstrateur/styles/muet.json',
|
|
// url: '../data/liberty.json',
|
|
success: function(style) {
|
|
/* add sens circu * /
|
|
style.layers.push(rdirect);
|
|
style.layers.push(rinvers);
|
|
/**/
|
|
currentStyle = $.extend(true, {}, style);
|
|
if (perma.getUrlParam('style')!=='0') olms.applyStyle(vlayer, style, 'plan_ign').then(function () {});
|
|
showLayers();
|
|
}
|
|
});
|
|
|
|
// Load base styles
|
|
['standard', 'gris', 'transparent', 'accentue', 'attenue', 'classique', 'epure'].forEach(function(s) {
|
|
var sel = document.getElementById('styles');
|
|
ol.ext.element.create('OPTION', {
|
|
value: s,
|
|
html: s,
|
|
parent: sel
|
|
})
|
|
ol.ext.Ajax.get({
|
|
//url: 'https://wxs.ign.fr/choisirgeoportail/static/vectorTiles/styles/PLAN.IGN/'+s+'.json',
|
|
url: 'https://data.geopf.fr/annexes/ressources/vectorTiles/styles/PLAN.IGN/'+s+'.json',
|
|
success: function(style) {
|
|
baseStyles[s] = style;
|
|
}
|
|
})
|
|
});
|
|
|
|
// Upload custom style
|
|
onChangeColor = function() {};
|
|
var drop = new ol.interaction.DropFile({ formatConstructors: ['none'] });
|
|
map.addInteraction(drop);
|
|
drop.on('loadend', function(e) {
|
|
try {
|
|
var json = JSON.parse(e.result);
|
|
reset();
|
|
setBaseStyle(json);
|
|
} catch(e) {
|
|
console.log(e)
|
|
/* ok */
|
|
}
|
|
})
|
|
|
|
// Set base style
|
|
function setBaseStyle(n) {
|
|
if (typeof(n) === 'string') currentStyle = $.extend(true, {}, baseStyles[n]);
|
|
else if (n.sprite) currentStyle = n;
|
|
else return;
|
|
$('#police select').val('Source Sans Pro').css('font-family', 'Source Sans Pro');
|
|
// reset config
|
|
for (var theme in config) {
|
|
for (var s in config[theme].style) {
|
|
config[theme].style[s].layers = [];
|
|
config[theme].style[s].savePaintColor = [];
|
|
}
|
|
}
|
|
currentStyle.layers.forEach(function(l) {
|
|
var source = l['source-layer'] || l.id;
|
|
var theme = source.split('_')[0];
|
|
console.log(source, theme)
|
|
if (!config[theme]) {
|
|
config[theme] = { style: {}}
|
|
}
|
|
if (!config[theme].style[source]) {
|
|
config[theme].style[source] = { layers: [] }
|
|
}
|
|
if (!l.layout) l.layout = {}
|
|
config[theme].style[source].layers.push(l);
|
|
config[theme].style[source].visible = l.layout.visibility!=='none';
|
|
$('.options input.'+source).prop('checked', l.layout.visibility!=='none')
|
|
// console.log(source,l.layout.visibility)
|
|
})
|
|
$('.options input.theme').each(function() {
|
|
var checked = $('ul input:checked', $(this).parent().parent())
|
|
$(this).attr('checked', checked.length>0);
|
|
})
|
|
applyStyle();
|
|
}
|
|
|
|
// Change font
|
|
function setFont(font0) {
|
|
$('#police select').css('font-family', font0);
|
|
currentStyle.layers.forEach(function(l) {
|
|
if (l.layout['text-font']) {
|
|
var italic = /Italic/.test(l.layout['text-font'][0]);
|
|
var bold = /Bold/.test(l.layout['text-font'][0]);
|
|
var font = font0.split(',');
|
|
if (italic) font[0] += ' Italic';
|
|
if (bold) font[0] += ' Bold';
|
|
l.layout['text-font'] = font;
|
|
}
|
|
})
|
|
applyStyle();
|
|
}
|
|
|
|
|
|
function getChromaColor(color) {
|
|
var c = color.hex()
|
|
if (c.length>7) {
|
|
c = color.css();
|
|
}
|
|
return c;
|
|
}
|
|
/** Apply current Style
|
|
*/
|
|
function applyStyle() {
|
|
for (var theme in config) {
|
|
var vis = config[theme].visible;
|
|
var color0 = config[theme].color;
|
|
for (var st in config[theme].style) {
|
|
var color = color0;
|
|
if (config[theme].useTheme) {
|
|
var th2 = st.split('_')[1];
|
|
if (config[th2]) {
|
|
color = config[th2].color;
|
|
}
|
|
}
|
|
style = config[theme].style[st];
|
|
if (!style.savePaintColor) style.savePaintColor = [];
|
|
style.layers.forEach(function(l, i) {
|
|
if (!l.layout) l.layout = {};
|
|
l.layout.visibility = (vis && style.visible) ? 'visible' : 'none';
|
|
['text-color', /*'text-halo-color',*/ 'fill-color', 'fill-outline-color', 'line-color', 'circle-color', 'circle-stroke-color', 'icon-color'].forEach(function(c) {
|
|
if (!l.paint || !l.paint[c]) return;
|
|
if (!style.savePaintColor[i]) style.savePaintColor[i] = {};
|
|
var savePaintColor = style.savePaintColor[i];
|
|
// Init
|
|
if (!savePaintColor[c]) {
|
|
if (l.paint[c] && l.paint[c].stops) savePaintColor[c] = $.extend(true, {}, l.paint[c]);
|
|
else savePaintColor[c] = l.paint[c];
|
|
}
|
|
// Reset
|
|
if (savePaintColor[c]) {
|
|
if (savePaintColor[c].stops) l.paint[c] = $.extend(true, {}, savePaintColor[c]);
|
|
else l.paint[c] = savePaintColor[c];
|
|
}
|
|
if (color && l.paint) {
|
|
switch(color) {
|
|
case 'brighten':
|
|
case 'darken':
|
|
case 'brighten2':
|
|
case 'darken2':
|
|
case 'saturate':
|
|
case 'desaturate':
|
|
case 'saturate2':
|
|
case 'desaturate2':
|
|
case 'gray': {
|
|
var opt = parseInt(color.replace(/([^0-9])/g,'')) || .5;
|
|
var operation = color.replace(/[0-9]$/, '');
|
|
if (color==='gray') {
|
|
console.log('gray')
|
|
opt = 4;
|
|
operation = 'desaturate';
|
|
}
|
|
// console.log(operation, opt, l.paint[c])
|
|
try {
|
|
if (l.paint[c].stops) {
|
|
l.paint[c].stops.forEach(function (s) {
|
|
if (!(/#ffffff/i.test(s[1]) && /^saturate/.test(operation))) {
|
|
s[1] = getChromaColor(chroma(s[1])[operation](opt));
|
|
}
|
|
// console.log('STOP:',s)
|
|
})
|
|
} else {
|
|
// bug on saturate white gets red
|
|
if (!(/#ffffff/i.test(l.paint[c]) && /^saturate/.test(operation))) {
|
|
l.paint[c] = getChromaColor(chroma(l.paint[c])[operation](opt));
|
|
}
|
|
}
|
|
} catch(e){};
|
|
break; //'#cccccc'; break;
|
|
}
|
|
case 'red':
|
|
case 'green':
|
|
case 'blue':
|
|
default: {
|
|
try {
|
|
if (l.paint[c].stops) {
|
|
l.paint[c].stops.forEach(function (s) {
|
|
s[1] = getChromaColor(chroma.mix(s[1],color));
|
|
})
|
|
} else {
|
|
l.paint[c] = getChromaColor(chroma.mix(l.paint[c],color));
|
|
}
|
|
} catch(e) {};
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
})
|
|
}
|
|
}
|
|
|
|
// trigger tile refresh by incrementing style id, see: https://github.com/openlayers/ol-mapbox-style/issues/959
|
|
try {
|
|
currentStyle["id"] = currentStyle["id"] + 1;
|
|
}
|
|
catch {
|
|
currentStyle["id"] = 0;
|
|
}
|
|
|
|
olms.applyStyle(vlayer, currentStyle, "plan_ign");
|
|
}
|
|
|
|
/** Show layers
|
|
*/
|
|
function showLayers() {
|
|
config = {};
|
|
var sources = {};
|
|
currentStyle.layers.forEach(function(l) {
|
|
var name = l['source-layer'];
|
|
if (name) {
|
|
var theme = name.split('_').shift();
|
|
if (!sources[theme]) sources[theme] = [];
|
|
if (!sources[theme][name]) sources[theme][name] = [];
|
|
sources[theme][name].push(l);
|
|
}
|
|
});
|
|
var ul = $('.options ul');
|
|
Object.keys(sources).forEach(function(s) {
|
|
config[s] = {
|
|
visible: true,
|
|
color: undefined,
|
|
style: {}
|
|
}
|
|
var li = $('<li>').addClass('collapse').appendTo(ul);
|
|
var label = $('<label>').text(s).appendTo(li);
|
|
$('<input type="checkbox">')
|
|
.addClass('theme')
|
|
.prop('checked', true)
|
|
.on('change', function() {
|
|
var vis = config[s].visible = $(this).prop('checked');
|
|
$('input', ul2).each(function() {
|
|
$(this).prop('disabled', !vis);//.change();
|
|
})
|
|
applyStyle()
|
|
})
|
|
.prependTo(label);
|
|
$('<i>').addClass('fa fa-carret-down')
|
|
.click(function() {
|
|
$(this).parent().toggleClass('collapse');
|
|
})
|
|
.appendTo(li);
|
|
$('<select>').html(operations)
|
|
.on('change', function(){
|
|
if ($(this).val()==='color') {
|
|
$('#color').show();
|
|
$("#color .sp-cancel").off();
|
|
$("#color .sp-cancel").on('click', function() { $('#color').hide(); })
|
|
$(this).val('color');
|
|
setTimeout(function() {
|
|
onChangeColor = function(c) {
|
|
config[s].color = c;
|
|
applyStyle();
|
|
$('#color').hide();
|
|
}
|
|
})
|
|
return;
|
|
} else {
|
|
config[s].color = $(this).val();
|
|
applyStyle();
|
|
}
|
|
})
|
|
.appendTo(li);
|
|
if (/toponyme/.test(s)) {
|
|
label = $('<label>').addClass('toponyme')
|
|
.html('couleur du thème')
|
|
.appendTo(li);
|
|
$('<input type="checkbox">')
|
|
.change(function() {
|
|
config[s].useTheme = $(this).prop('checked');
|
|
applyStyle();
|
|
})
|
|
.prependTo(label);
|
|
}
|
|
var ul2 = $("<ul>").appendTo(li);
|
|
Object.keys(sources[s]).forEach(function(i) {
|
|
var li = $('<li>').appendTo(ul2);
|
|
var source = sources[s][i][0];
|
|
var label = $('<label>').text(i.replace(/toponyme_|routier_|ocs_|hydro_|parcellaire_/, '')).attr('title', i).appendTo(li);
|
|
if (!source.layout) source.layout = { visibility: 'visible' }
|
|
config[s].style[i] = {
|
|
visible: source.layout.visibility!=='none',
|
|
layers: sources[s][i]
|
|
};
|
|
$('<input type="checkbox">')
|
|
.prop('checked', source.layout.visibility!=='hidden' ? 'checked':'')
|
|
.addClass(i)
|
|
.data('layer', i)
|
|
.on('change', function() {
|
|
config[s].style[i].visible = $(this).prop('checked');
|
|
applyStyle();
|
|
})
|
|
.prependTo(label);
|
|
});
|
|
});
|
|
}
|
|
|
|
// Selection
|
|
var selStyle = ol.style.Style.defaultStyle(true)
|
|
selStyle.push(new ol.style.Style({
|
|
image: new ol.style.Circle({
|
|
radius: 3,
|
|
fill: new ol.style.Fill({ color: '#f00' })
|
|
}),
|
|
geometry: function(f) {
|
|
return new ol.geom.Point(f.getGeometry().getFirstCoordinate())
|
|
}
|
|
}))
|
|
var select = new ol.layer.Vector({
|
|
source: new ol.source.Vector(),
|
|
style: selStyle
|
|
});
|
|
map.addLayer(select);
|
|
|
|
// Log properties
|
|
map.on('click', function() {
|
|
var f = select.getSource().getFeatures()[0];
|
|
if (f) console.log(f.getProperties())
|
|
})
|
|
|
|
// Show tooltip on hover
|
|
var tooltip = new ol.Overlay.Tooltip({ className: 'default', positioning: 'bottom-center' });
|
|
map.addOverlay(tooltip);
|
|
|
|
var hover = new ol.interaction.Hover({
|
|
cursor: "pointer",
|
|
layers: [vlayer]
|
|
});
|
|
hover.setActive(false);
|
|
map.addInteraction(hover);
|
|
function showPopup(b) {
|
|
tooltip.setInfo('');
|
|
hover.setActive(b);
|
|
}
|
|
hover.on("enter", function(e) {
|
|
var showGeom = $('#showSel').prop('checked');
|
|
// hover.setCursor("pointer");
|
|
var feature = e.feature;
|
|
if (select.getSource().getFeatures().length) select.getSource().clear();
|
|
var info = '';
|
|
if (feature && feature.get('layer')!=='fond_opaque') {
|
|
info = '<h2>'+feature.get('layer').replace(/_/g,' ')+'</h2>';
|
|
['symbo', 'nature', 'rond_point', 'sens_circu', 'texte', 'nom_desabrege', 'numero', 'hauteur'].forEach(function(a) {
|
|
if (feature.get(a)) info += '<br/>'+a.replace(/_/g,' ')+': '+feature.get(a);
|
|
})
|
|
}
|
|
tooltip.setInfo(info);
|
|
//console.log(feature.getProperties());
|
|
// Select feature
|
|
if (showGeom) {
|
|
var coords = [];
|
|
if (feature instanceof ol.Feature) {
|
|
select.getSource().addFeature(feature);
|
|
} else {
|
|
var c = feature.getFlatCoordinates();
|
|
for (var i=0; i<c.length; i+=2) {
|
|
coords.push ([c[i],c[i+1]]);
|
|
}
|
|
// console.log(feature.getType())
|
|
switch (feature.getType()) {
|
|
case 'Point': {
|
|
coords = coords.pop();
|
|
break;
|
|
}
|
|
case 'LineString' : {
|
|
coords = coords;
|
|
break;
|
|
}
|
|
case 'MultiLineString' :
|
|
case 'Polygon' : {
|
|
coords = [coords];
|
|
break;
|
|
}
|
|
}
|
|
var geom = new ol.geom[feature.getType()](coords)
|
|
var f2 = new ol.Feature(geom);
|
|
f2.setProperties(feature.getProperties())
|
|
select.getSource().addFeature(f2);
|
|
}
|
|
}
|
|
});
|
|
hover.on("leave", function(e) {
|
|
tooltip.setInfo('');
|
|
select.getSource().clear();
|
|
});
|
|
|
|
// Reset styles
|
|
function reset() {
|
|
$('.options input').prop('checked', true);
|
|
$('.options input').prop('disabled', false);
|
|
$('.options .toponyme input').prop('checked', false);
|
|
for (theme in config) {
|
|
config[theme].color = '';
|
|
config[theme].visible = true;
|
|
if (/toponyme/.test(theme)) config[theme].useTheme = false;
|
|
for (i in config[theme].style) {
|
|
config[theme].style[i].visible = true;
|
|
}
|
|
}
|
|
$('.options ul select').val('');
|
|
applyStyle();
|
|
}
|
|
|
|
/** [Debug] get layer style
|
|
* @param {string} lanyer layer name
|
|
*/
|
|
function getLayerStyle(layer) {
|
|
var styles = [];
|
|
currentStyle.layers.forEach(function(style) {
|
|
if (style['source-layer']===layer) {
|
|
styles.push(style);
|
|
}
|
|
})
|
|
return styles;
|
|
}
|
|
|
|
|
|
document.getElementById('save').addEventListener('click', save);
|
|
|
|
// Save to JSON file
|
|
function save(e) {
|
|
var style = Object.assign({}, currentStyle)
|
|
if (e.ctrlKey) {
|
|
style.layers = [];
|
|
currentStyle.layers.forEach(function(l) {
|
|
if (l.layout.visibility !== 'none') style.layers.push(l)
|
|
})
|
|
}
|
|
var data = JSON.stringify(style, null, ' ');
|
|
data = data.replace(/an7nvfzojv5wa96dsga5nk8w/g, 'essentiels')
|
|
var blob = new Blob([data], {type: 'text/plain;charset=utf-8'});
|
|
saveAs(blob, 'custom.json');
|
|
}
|
|
|
|
// Add sens de circulation
|
|
var sens = {
|
|
"id": "Routier - sens direct",
|
|
"type": "symbol",
|
|
"source": "plan_ign",
|
|
"source-layer": "routier_route",
|
|
"minzoom": 15,
|
|
"filter": [
|
|
"==",
|
|
"sens_circu",
|
|
"Sens direct"
|
|
],
|
|
"layout": {
|
|
"visibility": "visible",
|
|
"text-field": "→",
|
|
"symbol-placement": "line-center",
|
|
"text-size": 15,
|
|
"text-anchor": "center",
|
|
"text-offset": [0, -0.2],
|
|
"text-keep-upright": false,
|
|
"text-rotation-alignment":"map",
|
|
"text-pitch-alignment": "viewport",
|
|
},
|
|
"paint": {
|
|
"text-color": "#000000"
|
|
}
|
|
}
|
|
var rdirect = $.extend(true, {}, sens);
|
|
rdirect.id = 'Routier - sens direct';
|
|
rdirect.layout['text-field'] = '→';
|
|
rdirect.filter[2] = "Sens direct";
|
|
var rinvers = $.extend(true, {}, sens);
|
|
rinvers.id = 'Routier - sens inverse'
|
|
rinvers.layout['text-field'] = '←'
|
|
rinvers.filter[2] = "Sens inverse";
|