2024-12-11 17:32:48 +01:00
/ * *
* rechercher les bornes de recharge ,
* afficher des cercles colorés selon la puissance max de la station
* lister les bornes trouvées dans la page
* @ type { boolean }
* /
2024-12-11 23:13:15 +01:00
let showHighPower = true
2024-10-17 15:01:47 +02:00
const overrideQuery = true
2024-11-26 21:31:43 +01:00
const initialZoom = 12
2024-10-17 15:01:47 +02:00
const osmMention = '© <a href="https://openstreetmap.org/copyright">OpenStreetMap</a> contributors'
2024-11-26 21:31:43 +01:00
let unknown _color = '#c0b1b1' // color for unknown power output of the station
2024-10-17 15:01:47 +02:00
// serveurs de tuiles: https://wiki.openstreetmap.org/wiki/Tile_servers
// https://stamen-tiles.a.ssl.fastly.net/toner/{z}/{x}/{y}.png
// https://a.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png
2024-10-18 00:47:01 +02:00
// https://tile.openstreetmap.org/{z}/{x}/{y}.png
// 'https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png'
2024-10-17 15:01:47 +02:00
const tileServer = 'https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png'
// Créer la carte centrée sur Rouen
var map = L . map ( 'map' ) . setView ( [ 49.4438 , 1.0993 ] , initialZoom )
// 'https://overpass-api.de/api/interpreter?data=[out:json][timeout:25];' +
// 'area(id:3600075628)->.searchArea;' +
// 'node[amenity=charging_station](area.searchArea);' +
// 'out body geom;'
L . tileLayer ( tileServer , {
maxZoom : 19 ,
attribution : osmMention ,
} ) . addTo ( map )
2024-12-11 23:13:15 +01:00
let filteredMarkers = L . layerGroup ( ) . addTo ( map )
2024-10-17 15:01:47 +02:00
function buildOverpassApiUrl ( map , overpassQuery ) {
var baseUrl = 'https://overpass-api.de/api/interpreter'
var bounds = map . getBounds ( ) . getSouth ( ) + ',' + map . getBounds ( ) . getWest ( ) + ',' + map . getBounds ( ) . getNorth ( ) + ',' + map . getBounds ( ) . getEast ( )
var resultUrl , query = ''
if ( overrideQuery ) {
query = ` ?data=[out:json][timeout:15];(
2024-12-11 17:32:48 +01:00
node [ amenity = charging _station ] ( $ { bounds } ) ;
) ; out body geom ; `
2024-10-17 15:01:47 +02:00
} else {
var nodeQuery = 'node[' + overpassQuery + '](' + bounds + ');'
var wayQuery = 'way[' + overpassQuery + '](' + bounds + ');'
var relationQuery = 'relation[' + overpassQuery + '](' + bounds + ');'
query = '?data=[out:json][timeout:15];(' + nodeQuery + wayQuery + relationQuery + ');out body geom;'
}
resultUrl = baseUrl + query
return resultUrl
}
2024-10-18 00:47:01 +02:00
const tags _to _display _in _popup = [
'name' ,
'capacity' ,
'date_start' ,
2024-10-17 15:01:47 +02:00
'charging_station:output' ,
2024-10-18 00:47:01 +02:00
'socket:type_2' ,
'socket:type2:output' ,
2024-10-17 15:01:47 +02:00
'socket:typee' ,
2024-10-18 00:47:01 +02:00
'socket:typee:output' ,
2024-10-17 15:01:47 +02:00
'socket:type2_combo' ,
2024-10-18 00:47:01 +02:00
'socket:type2_combo:output' ,
2024-10-17 15:01:47 +02:00
'socket:chademo' ,
'operator' , 'ref:EU:EVSE' ,
2024-10-18 00:33:25 +02:00
'network' ,
2024-10-18 00:47:01 +02:00
'opening_hours' ,
2024-10-17 15:01:47 +02:00
'contact' ,
2024-10-18 00:47:01 +02:00
'phone' ,
'contact:phone' ,
'website' ,
'contact:website' ,
'ref' ,
'fee' ,
'payment' ,
'payment:contactless' ,
'authentication:app' ,
'authentication:debit_card' ,
]
2024-10-17 15:01:47 +02:00
2024-10-18 00:33:25 +02:00
function supprimerMarqueurs ( map ) {
map . eachLayer ( ( layer ) => {
if ( layer instanceof L . Marker ) {
layer . remove ( )
}
} )
}
const colors = [
2024-11-26 21:31:43 +01:00
'#36423d' ,
'#4e8a8d' ,
'#2999b3' ,
'#1782dd' ,
'#2900ff' ,
2024-12-11 17:32:48 +01:00
'#8000ff' ,
2024-10-18 00:33:25 +02:00
]
2024-10-18 00:47:01 +02:00
2024-12-11 17:32:48 +01:00
function guessOutputPowerFromFeature ( feature ) {
2024-11-26 21:31:43 +01:00
let outputPower = 0
2024-10-18 00:33:25 +02:00
if ( feature . properties && feature . properties . tags ) {
2024-11-26 21:31:43 +01:00
/ * *
* fouiller dans les tags les valeurs explicites de puissance déclarée .
* Deviner aussi les puissances non déclarées :
2024-12-11 17:32:48 +01:00
* - type 2 présent , max 43 kW
* - type Chademo présent , max 63 kW
* https : //forum.openstreetmap.fr/t/bornes-de-recharges-et-puissance-chargeurs-quel-est-votre-avis/27828
2024-11-26 21:31:43 +01:00
*
* /
2024-12-11 17:32:48 +01:00
let found _type _2 = false
let found _type _chademo = false
2024-10-18 00:33:25 +02:00
for ( var tag in feature . properties . tags ) {
2024-12-11 17:32:48 +01:00
if ( tag . indexOf ( 'type2' ) !== - 1 ) {
2024-11-26 21:31:43 +01:00
// console.log('tag type2', tag)
2024-12-11 17:32:48 +01:00
found _type _2 = true
2024-11-26 21:31:43 +01:00
power = 43
}
2024-12-11 17:32:48 +01:00
if ( tag . indexOf ( 'chademo' ) !== - 1 ) {
found _type _chademo = true
2024-11-26 21:31:43 +01:00
console . log ( 'tag chademo' , tag )
power = 63
}
2024-10-18 00:33:25 +02:00
let value = feature . properties . tags [ tag ]
2024-10-18 00:47:01 +02:00
if ( value && tag . toLowerCase ( ) . indexOf ( 'output' ) !== - 1 ) {
2024-10-18 00:33:25 +02:00
console . log ( 'tag contient output' , tag , value )
2024-10-18 00:47:01 +02:00
value = '' + value
if ( value . replace ) {
2024-10-18 00:33:25 +02:00
value = value . replace ( ' ' )
value = value . replace ( 'kW' , '' )
}
var power = parseInt ( value )
2024-11-26 21:31:43 +01:00
// deviner les types de prises présents
2024-12-11 17:32:48 +01:00
if ( power ) {
console . log ( 'power' , power )
2024-11-26 21:31:43 +01:00
console . log ( 'outputPower' , outputPower )
}
2024-10-18 00:33:25 +02:00
if ( power > outputPower ) {
outputPower = power
console . log ( 'power' , power )
}
}
}
}
2024-12-11 23:13:15 +01:00
feature . properties . outputPower = outputPower
2024-12-11 17:32:48 +01:00
return outputPower
2024-11-26 21:31:43 +01:00
}
2024-10-18 00:47:01 +02:00
2024-11-26 21:31:43 +01:00
function getColor ( feature ) {
let outputPower = guessOutputPowerFromFeature ( feature )
2024-10-18 00:33:25 +02:00
feature . properties . tags . has _output _of _irve _specified = outputPower
2024-12-11 17:32:48 +01:00
if ( outputPower ) {
2024-11-26 21:31:43 +01:00
2024-12-11 17:32:48 +01:00
var index = Math . min ( Math . floor ( outputPower / 10 ) , colors . length - 1 )
console . log ( 'outputPower' , outputPower )
// console.log('colors[index]', colors[index])
return colors [ index ]
2024-11-26 21:31:43 +01:00
}
// autrement, sans puissance max trouvée, on met la couleur des indéfinis
return unknown _color
2024-10-18 00:33:25 +02:00
}
2024-12-11 23:13:15 +01:00
let coef _reduction _bars = 0.8
2024-10-17 15:01:47 +02:00
2024-12-11 23:13:15 +01:00
function calculerPourcentage ( partie , total , reduc ) {
if ( total === 0 ) {
return 'Division par zéro impossible'
}
let coef _reduction = 1
if ( reduc ) {
coef _reduction = coef _reduction _bars
}
return ( ( partie / total ) * 100 * coef _reduction ) . toFixed ( 1 )
}
function displayStatsFromGeoJson ( resultAsGeojson ) {
let count = resultAsGeojson . features . length
let count _station _output = 0
let count _ref _eu = 0
let output _more _than _300 = 0
let output _more _than _200 = 0
let output _more _than _100 = 0
let output _more _than _50 = 0
let count _station _outputoutput _between _1 _and _50 = 0
let count _output _unknown = 0
let count _estimated _type2combo = 0
let count _found _type2combo = 0
let count _found _type2 = 0
resultAsGeojson . features . map ( feature => {
let found _type2 _combo = false
// trouver si les tags présentent un type combo
let found _type2 = false
// trouver si les tags présentent un type 2
let keys _of _object = Object . keys ( feature . properties . tags )
keys _of _object . map ( tagKey => {
// console.log('tagKey', tagKey)
if ( tagKey . indexOf ( 'type2_combo' ) !== - 1 ) {
found _type2 _combo = true
console . log ( 'tagkey trouvé combo' , tagKey )
2024-12-11 17:32:48 +01:00
}
2024-12-11 23:13:15 +01:00
if ( tagKey . indexOf ( 'type2' ) !== - 1 ) {
found _type2 = true
2024-12-11 17:32:48 +01:00
}
} )
2024-12-11 23:13:15 +01:00
let outputPower = guessOutputPowerFromFeature ( feature )
if ( found _type2 _combo ) {
count _found _type2combo ++
}
if ( found _type2 ) {
count _found _type2 ++
}
if ( outputPower == 0 ) {
count _output _unknown ++
}
if ( outputPower >= 200 && ! found _type2 _combo ) {
/ * *
* si on trouve une puissance supérieure à 200 kW on peut partir du principe que la station dispose d ' une prise type _2 _combo à minima
* /
count _estimated _type2combo ++
}
if ( outputPower > 0 && outputPower < 50 ) {
count _station _outputoutput _between _1 _and _50 ++
}
if ( outputPower >= 50 && outputPower < 100 ) {
output _more _than _50 ++
} else if ( outputPower >= 100 && outputPower < 200 ) {
output _more _than _100 ++
} else if ( outputPower >= 200 && outputPower < 300 ) {
output _more _than _200 ++
} else if ( outputPower >= 300 ) {
feature . properties . puissance _haute = true
output _more _than _300 ++
}
if ( feature . properties . tags [ 'charging_station:output' ] ) {
count _station _output ++
}
if ( feature . properties . tags [ 'ref:EU:EVSE' ] ) {
count _ref _eu ++
}
} )
let bar _powers = ` <div class="bars-container">
< div class = "bar color-unknown" style = "width: ${calculerPourcentage(count_output_unknown, count, true)}%" > $ { count _output _unknown } < / d i v >
< div class = "bar color-power-lesser-than-50" style = "width: ${calculerPourcentage(count_station_outputoutput_between_1_and_50, count, true)}%" > $ { count _station _outputoutput _between _1 _and _50 } < / d i v >
< div class = "bar color-power-lesser-than-100" style = "width: ${calculerPourcentage(output_more_than_50, count, true)}%" > $ { output _more _than _50 } < / d i v >
< div class = "bar color-power-lesser-than-200" style = "width: ${calculerPourcentage(output_more_than_100, count, true)}%" > $ { output _more _than _100 } < / d i v >
< div class = "bar color-power-lesser-than-300" style = "width: ${calculerPourcentage(output_more_than_200, count, true)}%" > $ { output _more _than _200 } < / d i v >
< div class = "bar color-power-lesser-than-max" style = "width: ${calculerPourcentage(output_more_than_300, count, true)}%" > $ { output _more _than _300 } < / d i v >
< / d i v >
`
let stats _content = ` <div class="stats">
Statistiques des < strong > $ { count } < /strong> stations trouvées: <br/ >
$ { count _station _output } ( $ { calculerPourcentage ( count _station _output , count ) } % ) ont une info de puissance max délivrée < i > charging _station : output < /i>. <br/ >
$ { count _ref _eu } ( $ { calculerPourcentage ( count _ref _eu , count ) } % ) ont une référence européenne < i > ref : EU : EVSE < /i>. <br/ >
$ { count _output _unknown } ( $ { calculerPourcentage ( count _output _unknown , count ) } % ) ont une puissance max inconnue < i > * output * < /i>. <br/ >
$ { output _more _than _300 } ( $ { calculerPourcentage ( output _more _than _300 , count ) } % ) ont une puissance max supérieure à 300 kW < i > * output * < /i>. <br/ >
$ { output _more _than _200 } ( $ { calculerPourcentage ( output _more _than _200 , count ) } % ) ont une puissance max supérieure à 200 kW < i > * output * < /i>. <br/ >
$ { output _more _than _100 } ( $ { calculerPourcentage ( output _more _than _100 , count ) } % ) ont une puissance max supérieure à 100 kW < i > * output * < /i>. <br/ >
$ { output _more _than _50 } ( $ { calculerPourcentage ( output _more _than _50 , count ) } % ) ont une puissance max supérieure à 50 kW < i > * output * < /i>. <br/ >
$ { count _found _type2combo } ( $ { calculerPourcentage ( count _found _type2combo , count ) } % ) ont un prise combo définie < i > * type2 _combo * < /i>. <br/ >
$ { count _estimated _type2combo } ( $ { calculerPourcentage ( count _estimated _type2combo , count ) } % ) ont une prise combo présumée à partir de la puissance max trouvée mais non spécifiée < i > * type2 _combo * < /i>. <br/ > $ { count _found _type2 } ( $ { calculerPourcentage ( count _found _type2 , count ) } % ) ont un prise type2 définie < i > * type2 * < /i>. <br/ >
< / d i v > `
$ ( '#found_charging_stations' ) . html ( stats _content )
$ ( '#bars_power' ) . html ( bar _powers )
}
2024-12-11 17:32:48 +01:00
2024-12-11 23:13:15 +01:00
let geojsondata ;
2024-12-11 17:32:48 +01:00
2024-12-11 23:13:15 +01:00
function displayPointsFromApi ( points ) {
geojsondata = osmtogeojson ( points )
console . log ( 'resultAsGeojson' , geojsondata )
2024-12-11 17:32:48 +01:00
2024-12-11 23:13:15 +01:00
displayStatsFromGeoJson ( geojsondata )
var resultLayer = L . geoJson ( geojsondata , {
2024-10-17 15:01:47 +02:00
style : function ( feature ) {
return { color : '#f00' }
} ,
2024-12-11 23:13:15 +01:00
/ * *
* enlever les polygones , ne garder que les points
* @ param feature
* @ param layer
* @ returns { boolean }
* /
2024-10-17 15:01:47 +02:00
filter : function ( feature , layer ) {
var isPolygon = ( feature . geometry ) && ( feature . geometry . type !== undefined ) && ( feature . geometry . type === 'Polygon' )
if ( isPolygon ) {
feature . geometry . type = 'Point'
var polygonCenter = L . latLngBounds ( feature . geometry . coordinates [ 0 ] ) . getCenter ( )
feature . geometry . coordinates = [ polygonCenter . lat , polygonCenter . lng ]
}
return true
} ,
onzoomend : function ( event ) {
console . log ( 'event' , event )
} ,
onEachFeature : function ( feature , layer ) {
2024-12-11 23:13:15 +01:00
let popupContent = ''
2024-10-17 15:01:47 +02:00
// ne montrer que certains champs dans la popup
tags _to _display _in _popup . forEach ( function ( key ) {
if ( tags _to _display _in _popup . indexOf ( key ) ) {
let value = feature . properties . tags [ key ]
if ( value ) {
2024-12-11 17:32:48 +01:00
if ( value . indexOf ( 'http' ) !== - 1 ) {
value = '<a href="' + value + '">' + value + '</a>'
2024-11-26 21:31:43 +01:00
}
popupContent = popupContent + '<br/><strong class="popup-key">' + key + ' :</strong><span class="popup-value">' + value + '</span>'
2024-10-17 15:01:47 +02:00
}
}
} )
// popupContent = popupContent + '</dl>'
layer . bindPopup ( popupContent )
2024-11-26 21:31:43 +01:00
let outPowerGuessed = guessOutputPowerFromFeature ( feature )
let color = getColor ( feature )
2024-12-11 17:32:48 +01:00
let displayOutPowerGuessed = '? kW'
if ( outPowerGuessed ) {
displayOutPowerGuessed = outPowerGuessed + ' kW max'
2024-11-26 21:31:43 +01:00
}
2024-12-11 17:32:48 +01:00
if ( ! popupContent ) {
2024-12-11 23:13:15 +01:00
popupContent = ` <span class="no-data"> Aucune information renseignée, <a class="edit-button" href="https://www.openstreetmap.org/edit?editor=remote&node= ${ feature . properties . id } ">ajoutez la dans OpenStreetMap!</a></span> `
2024-11-26 21:31:43 +01:00
}
2024-12-11 23:13:15 +01:00
let html = ` <a class="edit-button" href="https://www.openstreetmap.org/edit?editor=id&node= ${ feature . properties . id } ">✏️</a><a class="edit-button" href="https://www.openstreetmap.org/edit?editor=remote&node= ${ feature . properties . id } ">JOSM</a> <span class="color-indication" style="background-color: ${ color } ;"> ${ displayOutPowerGuessed } </span><span class="popup-content"> ${ popupContent } </span> `
2024-11-26 21:31:43 +01:00
2024-12-11 17:32:48 +01:00
let radius = 20
2024-11-26 21:31:43 +01:00
if ( outPowerGuessed > 300 ) {
2024-10-18 00:47:01 +02:00
radius = 200
2024-12-11 17:32:48 +01:00
} else if ( outPowerGuessed > 200 ) {
2024-11-26 21:31:43 +01:00
radius = 250
2024-12-11 17:32:48 +01:00
} else if ( outPowerGuessed > 100 ) {
2024-11-26 21:31:43 +01:00
radius = 150
2024-12-11 17:32:48 +01:00
} else if ( outPowerGuessed > 50 ) {
2024-10-18 00:47:01 +02:00
radius = 100
2024-12-11 17:32:48 +01:00
} else if ( outPowerGuessed > 20 ) {
2024-11-26 21:31:43 +01:00
radius = 50
2024-12-11 17:32:48 +01:00
} else if ( outPowerGuessed > 7 ) {
2024-11-26 21:31:43 +01:00
radius = 20
}
2024-10-17 23:57:47 +02:00
let circle = L . circle ( layer . _latlng , {
2024-10-18 00:33:25 +02:00
color : color ,
fillColor : color ,
fillOpacity : 0.8 ,
radius : radius
} ) . addTo ( map )
2024-10-17 15:01:47 +02:00
2024-10-17 23:57:47 +02:00
circle . bindPopup ( html )
circle . on ( {
2024-10-17 15:01:47 +02:00
mouseover : function ( ) {
this . openPopup ( )
} ,
mouseout : function ( ) {
setTimeout ( ( ) => this . closePopup ( ) , 3000 )
} ,
click : function ( ) {
this . openPopup ( )
} ,
} )
} ,
} )
}
function makeCssClassFromTags ( tags ) {
console . log ( 'tags' , tags )
let tagKeys = Object . keys ( tags )
console . log ( 'tagKeys' , tagKeys )
if ( ! tags ) {
return ''
}
let listOfClasses = [ ]
tagKeys . forEach ( ( element ) => {
listOfClasses . push ( 'tag-' + element + '_' + tags [ element ] . replace ( ':' , '--' ) . replace ( ' ' , '-' ) )
} )
return listOfClasses . join ( ' ' )
}
function getIconFromTags ( tags ) {
let iconFileName = ''
// let iconFileName = 'icon_restaurant.png';
if ( tags [ 'man_made' ] ) {
iconFileName = 'fountain.png'
}
return iconFileName
}
2024-12-11 23:13:15 +01:00
// $('#toggleMinPower_50').on('click', toggleMinPower(50))
// $('#toggleMinPower_100').on('click', toggleMinPower(100))
// document.getElementById('toggleMinPower_300').addEventListener('click', toggleMinPower(showHighPower))
$ ( '#query-button' ) . on ( 'click' , function ( ) {
2024-10-18 00:33:25 +02:00
supprimerMarqueurs ( map )
2024-10-17 15:01:47 +02:00
loadOverpassQuery ( )
} )
2024-12-11 23:13:15 +01:00
function toggleMinPower ( showHighPower ) {
console . log ( 'toggle' , showHighPower )
showHighPower = ! showHighPower ;
addFilteredMarkers ( showHighPower ) ;
this . textContent = showHighPower ? "Montrer puissance haute" : "Montrer puissance normale" ;
}
function addFilteredMarkers ( showHighPower ) {
filteredMarkers . clearLayers ( ) // Supprimer les marqueurs existants
console . log ( 'addFilteredMarkers: clear des marqueurs fait' )
let counter = 0
geojsondata . features . forEach ( function ( feature ) {
if ( feature . properties . puissance _haute === showHighPower ) {
counter ++
var marker = L . marker ( feature . geometry . coordinates ) . bindPopup ( feature . properties . puissance _haute ? 'Puissance haute' : 'Puissance normale' )
filteredMarkers . addLayer ( marker )
}
} )
console . log ( 'addFilteredMarkers: ' , counter )
2024-12-11 17:32:48 +01:00
}
2024-10-17 15:01:47 +02:00
let isLoading = false
function loadOverpassQuery ( ) {
// ne pas charger si on recherche déjà
if ( ! isLoading ) {
isLoading = true
$ ( '#spinning_icon' ) . fadeIn ( )
var queryTextfieldValue = $ ( '#query-textfield' ) . val ( )
var overpassApiUrl = buildOverpassApiUrl ( map , queryTextfieldValue )
$ . get ( overpassApiUrl , function ( geoDataPointsFromApi ) {
displayPointsFromApi ( geoDataPointsFromApi )
$ ( '#spinning_icon' ) . fadeOut ( )
2024-10-18 00:33:25 +02:00
$ ( '#message-loading' ) . fadeOut ( )
2024-10-17 15:01:47 +02:00
isLoading = false
} ) // end of the getting from overpass API
}
}
$ ( '#spinning_icon' ) . hide ( )
2024-10-18 00:33:25 +02:00
$ ( '#message-loading' ) . hide ( )
2024-10-17 15:01:47 +02:00
loadOverpassQuery ( )