const radiusCalculation = (val, coeff) => {
return (val / Math.PI) ** 0.5 * coeff;
};
const vectorLayerSource = new ol.source.Vector({
url: 'departements-france-2017.json',
format: new ol.format.GeoJSON()
});
const fillCircle = new ol.style.Fill({
color: 'rgba(125, 125, 125, 0.6)'
});
const strokeCircle = new ol.style.Stroke({
color: '#ffffff',
width: 1
});
const styleProportionalCircle = (feature, resolution) => {
const extent = feature.getGeometry().getExtent();
const center = ol.extent.getCenter(extent);
const geom = new ol.geom.Point(center);
return new ol.style.Style({
geometry: geom,
image: new ol.style.Circle({
stroke: strokeCircle,
fill: fillCircle,
radius: radiusCalculation(feature.get('pop_tot'), 0.02)
}),
zIndex: feature.get('rank')
});
};
const vectorLayer = new ol.layer.Vector({
source: vectorLayerSource,
style: styleProportionalCircle,
renderMode: 'image'
});
const rasterLayer = new ol.layer.Tile({
opacity: 0.4,
source: new ol.source.XYZ({
url: 'https://{a-c}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png',
attributions:
'© Openstreetmap France | © OpenStreetMap'
})
});
const map = new ol.Map({
layers: [rasterLayer, vectorLayer],
controls: ol.control.defaults({
attributionOptions: {
collapsed: false
}
}),
target: 'map',
view: new ol.View({
center: ol.proj.fromLonLat([2.21298, 46.44362]),
zoom: 6
})
});
const popupElement = document.getElementById('popup');
var popup = new ol.Overlay({
element: popupElement
});
map.addOverlay(popup);
const intlNumberFormat = new Intl.NumberFormat('fr-FR');
var displayFeatureInfo = (pixel, coordinate) => {
var feature = map.forEachFeatureAtPixel(pixel, feature => feature);
if (feature) {
const formated = intlNumberFormat.format(feature.get('pop_tot'));
popupElement.innerHTML = `Département:
${feature.get('NOM_DEP')} (${feature.get('INSEE_DEP')})
Population totale:
${formated} habitants (rang ${feature.get('rank')})`;
popup.setPosition(coordinate);
popupElement.style.display = '';
} else {
popupElement.innerHTML = '';
popupElement.style.display = 'none';
}
};
map.on('pointermove', e => {
if (e.dragging) {
popupElement.style.display = 'none';
return;
}
displayFeatureInfo(e.pixel, e.coordinate);
});
const onChangeListener = vectorLayerSource.on('change', async e => {
if (vectorLayerSource.getState() == 'ready') {
ol.Observable.unByKey(onChangeListener);
const response = await fetch('population-insee-2015.csv');
const text = await response.text();
const data = Papa.parse(text, {
header: true
});
const sortedData = data.data
.slice(0)
.filter(ds => ds.code_dept.length < 3)
.sort((a, b) => Number(b.pop_totale) - Number(a.pop_totale))
.map((ds, i) => {
ds.rank = i + 1;
return ds;
});
const hashTable = sortedData.reduce((acc, curr) => {
acc[curr.code_dept] = {
pop_totale: Number(curr.pop_totale),
rank: curr.rank
};
return acc;
}, {});
vectorLayerSource.forEachFeature(feature => {
var codeDept = feature.get('INSEE_DEP');
feature.set('pop_tot', hashTable[codeDept].pop_totale);
feature.set('rank', hashTable[codeDept].rank);
});
generateLegend(vectorLayerSource.getFeatures());
}
});
const generateLegend = features => {
const vals = features.map(el => el.get('pop_tot'));
const max = Math.max(...vals);
const min = Math.min(...vals);
const canvas = document.getElementById('canvas');
var vectorContext = ol.render.toContext(canvas.getContext('2d'), {
size: [140, 80]
});
[min, (min + max) / 3, max]
.slice(0)
.reverse()
.forEach(val => {
const radius = radiusCalculation(val, 0.02);
const text = new ol.style.Text({
offsetX: 60,
offsetY: -radius,
text: `${intlNumberFormat.format(val.toFixed(0))} habs`
});
const newStyle = new ol.style.Style({
image: new ol.style.Circle({
stroke: new ol.style.Stroke({
color: '#ffffff',
width: 1
}),
fill: fillCircle,
radius: radius
}),
text: text
});
vectorContext.setStyle(newStyle);
vectorContext.drawGeometry(new ol.geom.Point([30, 60 - (2 + radius)]));
});
};