add test and split codebase

This commit is contained in:
Tykayn 2024-12-17 11:53:02 +01:00 committed by tykayn
parent 0614feaa03
commit be0ea5263c
8 changed files with 6928 additions and 117 deletions

11
babel.config.cjs Normal file
View File

@ -0,0 +1,11 @@
module.exports = {
presets: [
[
'@babel/preset-env',
{
targets:
{ node: 'current' }
}
]
],
}

40
js/color-utils.js Normal file
View File

@ -0,0 +1,40 @@
import utils from "./utils.js"
let unknown_color = '#c0b1b1' // color for unknown power output of the station
const colors = [
'#36423d',
'#4e8a8d',
'#2999b3',
'#1782dd',
'#2900ff',
'#8000ff',
]
const error_color = '#ff1414'
// 2024-12-16: au delà d'une valeur de 400kW on peut dire qu'il existe une erreur de saisie, nous n'avons pas de chargeur de 1800kW en production.
const max_out_legit_power = 400
const colorUtils = {
/**
* trouver une couleur correspondant
*/
getColor : (feature) =>{
let outputPower = utils.guessOutputPowerFromFeature(feature)
feature.properties.tags.has_output_of_irve_specified = outputPower
if (outputPower) {
if(outputPower> max_out_legit_power){
return error_color;
}
let index = Math.min(Math.floor(outputPower / 10), colors.length - 1)
return colors[index]
}
// autrement, sans puissance max trouvée, on met la couleur des indéfinis
return unknown_color
},
}
export default colorUtils

7
js/config.js Normal file
View File

@ -0,0 +1,7 @@
const config = {
osmMention:'&copy; <a href="https://openstreetmap.org/copyright">OpenStreetMap</a> contributors',
showHighPower : true,
overrideQuery : true,
initialZoom : 12
}
export default config

View File

@ -4,12 +4,12 @@
* lister les bornes trouvées dans la page
* @type {boolean}
*/
import config from './config.js'
import utils from './utils.js'
import colorUtils from "./color-utils.js"
let showHighPower = true
const overrideQuery = true
const initialZoom = 12
const osmMention = '&copy; <a href="https://openstreetmap.org/copyright">OpenStreetMap</a> contributors'
let unknown_color = '#c0b1b1' // color for unknown power output of the station
console.log('config', config)
let geojsondata;
// serveurs de tuiles: https://wiki.openstreetmap.org/wiki/Tile_servers
// https://stamen-tiles.a.ssl.fastly.net/toner/{z}/{x}/{y}.png
@ -21,28 +21,7 @@ const tileServer_stamen = 'https://a.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png
// Créer la carte centrée sur Rouen
// Liste des 20 villes les plus peuplées de France avec leurs coordonnées géographiques
let cities = [
{ name: 'Paris', coords: [48.8566, 2.3522] },
{ name: 'Marseille', coords: [43.2965, 5.3698] },
{ name: 'Lyon', coords: [45.7640, 4.8357] },
{ name: 'Toulouse', coords: [43.6042, 1.4437] },
{ name: 'Nice', coords: [43.7101, 7.2620] },
{ name: 'Nantes', coords: [47.2184, -1.5536] },
{ name: 'Strasbourg', coords: [48.5831, 7.7521] },
{ name: 'Montpellier', coords: [43.6167, 3.8742] },
{ name: 'Bordeaux', coords: [44.8378, -0.5792] },
{ name: 'Lille', coords: [50.6293, 3.1466] },
{ name: 'Rennes', coords: [48.1120, -1.6823] },
{ name: 'Toulon', coords: [43.1230, 5.9291] },
{ name: 'Le Havre', coords: [49.4943, 0.1079] },
{ name: 'Saint-Etienne', coords: [45.4380, 4.3841] },
{ name: 'Grenoble', coords: [45.1667, 5.7295] },
{ name: 'Rouen', coords: [49.4431, 1.0820] },
{ name: 'Dijon', coords: [47.3221, 5.0446] },
{ name: 'Angers', coords: [47.4786, -0.5551] },
{ name: 'Nîmes', coords: [43.8366, 4.3623] },
{ name: 'Reims', coords: [49.2500, 4.0333] }
]
// Initialisation de la carte avec la vue centrée sur la ville choisie
@ -52,9 +31,9 @@ let map = L.map('map');
function setRandomView(){
console.log('set random view')
// Choix au hasard d'une ville parmi la liste
let randomCity = cities[Math.floor(Math.random() * cities.length)]
let randomCity = utils.cities[Math.floor(Math.random() * utils.cities.length)]
console.log('randomCity', randomCity)
map = map.setView(randomCity.coords, initialZoom)
map = map.setView(randomCity.coords, config.initialZoom)
}
function setCoordinatesOfLeafletMapFromQueryParameters() {
// Récupère les paramètres de l'URL
@ -85,32 +64,30 @@ function updateURLWithMapCoordinatesAndZoom() {
// Construit l'URL avec les paramètres de coordonnées et de zoom
const url = `#coords=1&lat=${center.lat}&lng=${center.lng}&zoom=${zoom}`;
console.log('updateURLWithMapCoordinatesAndZoom url', url)
// console.log('updateURLWithMapCoordinatesAndZoom url', url)
// Met à jour l'URL de la page
history.replaceState(null, null, url);
}
var osm = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: osmMention+'&copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors'
attribution: config.osmMention+'&copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors'
})
var cycle = L.tileLayer('https://{s}.tile.opencyclemap.org/{z}/{x}/{y}.png', {
attribution: osmMention+'&copy; <a href="https://www.opencyclemap.org/">OpenCycleMap</a> contributors'
attribution: config.osmMention+'&copy; <a href="https://www.opencyclemap.org/">OpenCycleMap</a> contributors'
})
var transport = L.tileLayer('https://{s}.tile.thunderforest.com/transport/{z}/{x}/{y}.png', {
attribution: osmMention
attribution: config.osmMention
})
let tileGrey =
L.tileLayer(tileServer, {
attribution: osmMention
attribution: config.osmMention
})
let stamen =
L.tileLayer(tileServer_stamen, {
attribution: osmMention
attribution: config.osmMention
})
var baseLayers = {
'Grey': tileGrey,
@ -132,7 +109,7 @@ function buildOverpassApiUrl (map, overpassQuery) {
let bounds = map.getBounds().getSouth() + ',' + map.getBounds().getWest() + ',' + map.getBounds().getNorth() + ',' + map.getBounds().getEast()
let resultUrl, query = ''
if (overrideQuery) {
if (config.overrideQuery) {
query = `?data=[out:json][timeout:15];(
node[amenity=charging_station](${bounds});
);out body geom;`
@ -195,86 +172,11 @@ function supprimerMarqueurs (map) {
})
}
const colors = [
'#36423d',
'#4e8a8d',
'#2999b3',
'#1782dd',
'#2900ff',
'#8000ff',
]
function guessOutputPowerFromFeature (feature) {
let outputPower = 0
let power = 0
if (feature.properties && feature.properties.tags) {
/**
* fouiller dans les tags les valeurs explicites de puissance déclarée.
* Deviner aussi les puissances non déclarées:
* - type 2 présent, max 43kW
* - type Chademo présent, max 63kW
* https://forum.openstreetmap.fr/t/bornes-de-recharges-et-puissance-chargeurs-quel-est-votre-avis/27828
*
*/
let found_type_2 = false
let found_type_chademo = false
for (var tag in feature.properties.tags) {
if (tag.indexOf('type2') !== -1) {
// console.log('tag type2', tag)
found_type_2 = true
power = 43
}
if (tag.indexOf('chademo') !== -1) {
found_type_chademo = true
// console.log('tag chademo', tag)
power = 63
}
let value = feature.properties.tags[tag]
if (value && tag.toLowerCase().indexOf('output') !== -1) {
// console.log('tag contient output', tag, value)
value = '' + value
if (value.replace) {
value = value.replace(' ')
value = value.replace('kW', '')
}
let power = parseInt(value)
// deviner les types de prises présents
// if (power) {
// console.log('power', power)
// console.log('outputPower', outputPower)
// }
if (power > outputPower) {
outputPower = power
// console.log('power', power)
}
}
}
}
feature.properties.outputPower = outputPower
return outputPower
}
// 2024-12-16: au delà d'une valeur de 400kW on peut dire qu'il existe une erreur de saisie, nous n'avons pas de chargeur de 1800kW en production.
const max_out_legit_power = 400
const error_color = 'red'
function getColor (feature) {
let outputPower = guessOutputPowerFromFeature(feature)
feature.properties.tags.has_output_of_irve_specified = outputPower
if (outputPower) {
if(outputPower> max_out_legit_power){
return error_color;
}
let index = Math.min(Math.floor(outputPower / 10), colors.length - 1)
return colors[index]
}
// autrement, sans puissance max trouvée, on met la couleur des indéfinis
return unknown_color
}
let coef_reduction_bars = 0.8
@ -320,7 +222,7 @@ function displayStatsFromGeoJson (resultAsGeojson) {
found_type2 = true
}
})
let outputPower = guessOutputPowerFromFeature(feature)
let outputPower = utils.guessOutputPowerFromFeature(feature)
if (found_type2_combo) {
count_found_type2combo++
}
@ -383,7 +285,7 @@ ${count_estimated_type2combo} (${calculerPourcentage(count_estimated_type2combo,
$('#bars_power').html(bar_powers)
}
let geojsondata
function bindEventsOnJosmRemote () {
let josm_remote_buttons = $(`.josm`)
@ -467,8 +369,8 @@ function displayPointsFromApi (points) {
popupContent += '</div>'
layer.bindPopup(popupContent)
let outPowerGuessed = guessOutputPowerFromFeature(feature)
let color = getColor(feature)
let outPowerGuessed = utils.guessOutputPowerFromFeature(feature)
let color = colorUtils.getColor(feature)
let displayOutPowerGuessed = '? kW'
if (outPowerGuessed) {
displayOutPowerGuessed = outPowerGuessed + ' kW max'

85
js/utils.js Normal file
View File

@ -0,0 +1,85 @@
const utils = {
/**
* fouiller dans les tags les valeurs explicites de puissance déclarée.
* Deviner aussi les puissances non déclarées:
* - type 2 présent, max 43kW
* - type Chademo présent, max 63kW
* https://forum.openstreetmap.fr/t/bornes-de-recharges-et-puissance-chargeurs-quel-est-votre-avis/27828
*
* @param feature
* @returns {number}
*/
guessOutputPowerFromFeature: (feature) => {
let outputPower = 0
let power = 0
if (feature.properties && feature.properties.tags) {
let found_type_2 = false
let found_type_chademo = false
for (var tag in feature.properties.tags) {
if (tag.indexOf('type2') !== -1) {
// console.log('tag type2', tag)
found_type_2 = true
power = 43
}
if (tag.indexOf('chademo') !== -1) {
found_type_chademo = true
// console.log('tag chademo', tag)
power = 63
}
let value = feature.properties.tags[tag]
if (value && tag.toLowerCase().indexOf('output') !== -1) {
// console.log('tag contient output', tag, value)
value = '' + value
if (value.replace) {
value = value.replace(' ')
value = value.replace('kW', '')
}
let power = parseInt(value)
// deviner les types de prises présents
// if (power) {
// console.log('power', power)
// console.log('outputPower', outputPower)
// }
if (power > outputPower) {
outputPower = power
// console.log('power', power)
}
}
}
}
feature.properties.outputPower = outputPower
return outputPower
},
/**
* villes les plus peuplées de France
*/
cities: [
{ name: 'Paris', coords: [48.8566, 2.3522] },
{ name: 'Marseille', coords: [43.2965, 5.3698] },
{ name: 'Lyon', coords: [45.7640, 4.8357] },
{ name: 'Toulouse', coords: [43.6042, 1.4437] },
{ name: 'Nice', coords: [43.7101, 7.2620] },
{ name: 'Nantes', coords: [47.2184, -1.5536] },
{ name: 'Strasbourg', coords: [48.5831, 7.7521] },
{ name: 'Montpellier', coords: [43.6167, 3.8742] },
{ name: 'Bordeaux', coords: [44.8378, -0.5792] },
{ name: 'Lille', coords: [50.6293, 3.1466] },
{ name: 'Rennes', coords: [48.1120, -1.6823] },
{ name: 'Toulon', coords: [43.1230, 5.9291] },
{ name: 'Le Havre', coords: [49.4943, 0.1079] },
{ name: 'Saint-Etienne', coords: [45.4380, 4.3841] },
{ name: 'Grenoble', coords: [45.1667, 5.7295] },
{ name: 'Rouen', coords: [49.4431, 1.0820] },
{ name: 'Dijon', coords: [47.3221, 5.0446] },
{ name: 'Angers', coords: [47.4786, -0.5551] },
{ name: 'Nîmes', coords: [43.8366, 4.3623] },
{ name: 'Reims', coords: [49.2500, 4.0333] }
]
}
export default utils

6687
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

34
package.json Normal file
View File

@ -0,0 +1,34 @@
{
"name": "libre-charge-map",
"version": "0.5.0",
"description": "Un visualisateur coloré de stations de recharge pour véhicules électriques selon les données OSM.",
"main": "index.js",
"devDependencies": {
"@babel/preset-env": "^7.14.4",
"@testing-library/dom": "^7.31.0",
"@testing-library/jest-dom": "^5.12.0",
"@testing-library/user-event": "^13.1.9",
"babel-jest": "^27.0.2",
"jest": "^27.0.3",
"jest-html-reporter": "^3.4.1"
},
"scripts": {
"test": "jest"
},
"jest": {
"transform": {
"^.+\\.[t|j]sx?$": "babel-jest"
},
"rootDir": "tests",
"moduleFileExtensions": [
"js",
"mjs",
"cjs",
"jsx",
"ts",
"tsx",
"json",
"node"
]
}
}

45
tests/main.test.js Normal file
View File

@ -0,0 +1,45 @@
import utils from '../js/utils'
import colorUtils from '../js/color-utils'
describe('testing on features', () => {
const featureWithOutput = {
properties: {
tags: {
'socket:type2:output': '30 kW'
}
}
}
const featureWithBadOutput = {
properties: {
tags: {
'socket:type2:output': '50000'
}
}
}
const featureWithoutOutput = {
properties: {
tags: {
'socket:type2': '2'
}
}
}
describe('testing outputPower', () => {
it('finds max outputpower when existing', () => {
let outputFound = utils.guessOutputPowerFromFeature(featureWithOutput)
expect(outputFound).toEqual(30)
})
})
describe('testing corresponding color', () => {
it('finds undefined color', () => {
let color = colorUtils.getColor(featureWithoutOutput)
expect(color).toEqual('#c0b1b1')
})
it('finds bad color', () => {
let color = colorUtils.getColor(featureWithBadOutput)
expect(color).toEqual('#ff1414')
})
})
})