/** * csv_to_geojson.ts * * Convertir un fichier CSV en GeoJSON * * Utilisation: * * npx ts-node csv_to_geojson.ts -d etalab_data/panneaux -f panneaux_limite_de_vitesse_fr_panoramax_detections.csv --latColumn 'GPSLatitude' --lonColumn 'GPSLongitude' -h * */ import fs from 'fs'; import path from 'path'; import csvParser from 'csv-parser'; import minimist from 'minimist'; import { Feature, FeatureCollection, Point } from 'geojson'; interface Options { dir: string; file: string; latColumn: string; lonColumn: string; hasHeaders: boolean; } let counter = 0; function csvToGeoJSON(options: Options): FeatureCollection { const { dir, file, latColumn, lonColumn, hasHeaders } = options; console.log(`options latColumn: ${latColumn}`); console.log(`options lonColumn: ${lonColumn}`); const filePath = path.join(dir, file); const features: Feature[] = []; let geoJSON: FeatureCollection = { type: 'FeatureCollection', features, }; let headers: string[] = []; let headersFound = false; let limitOffset = 100; console.log(`hasHeaders: ${hasHeaders}`); fs.createReadStream(filePath) .pipe(csvParser({ headers: hasHeaders })) .on('data', (row) => { counter++; if (!headersFound && hasHeaders) { let keys = Object.keys(row); keys.forEach((key) => { headers.push(row[key]); }); headersFound = true; console.log(`headers: ${headers}`); } if (counter > limitOffset) { return; } if (headers.indexOf(latColumn)) { console.log(`latColumn: ${latColumn}`); console.log(`headers latColumn: ${headers.indexOf(latColumn)}`); console.log(`headers.indexOf(latColumn): `, headers.indexOf(latColumn)); console.log('row', row); const lat = parseFloat(row['_' + headers.indexOf(latColumn)]); const lon = parseFloat(row['_' + headers.indexOf(lonColumn)]); // Si pas d'entêtes, utiliser des noms de colonnes génériques if (!hasHeaders) { const properties: { [key: string]: any } = {}; Object.keys(row).forEach((key, index) => { properties[headers[index]] = row[key]; }); row = properties; } else { let keys = Object.keys(row); // Utiliser les entêtes comme noms de propriétés const properties: { [key: string]: any } = {}; headers.forEach((header, index) => { properties[header] = row['_' + index]; }); row = properties; } // filtrer la ligne du header si présente if (hasHeaders && counter > 1 || !hasHeaders || counter > limitOffset) { features.push({ type: 'Feature', geometry: { type: 'Point', coordinates: [lon, lat], }, properties: row, }); } } else { console.log('!!! no latColumn', row); } }) .on('end', () => { geoJSON = { type: 'FeatureCollection', features, }; fs.writeFileSync(`${dir}/${file}.geojson`, JSON.stringify(geoJSON, null, 2)); console.log(`GeoJSON créé avec succès : ${file}.geojson`); }); console.log(`geoJSON lines: ${counter}`); return geoJSON; } const args = minimist(process.argv.slice(2), { alias: { dir: 'd', file: 'f', latColumn: 'lat', lonColumn: 'lon', hasHeaders: 'h', }, default: { hasHeaders: true, }, }); function checkFile(args: Options) { let filePath = path.join(args.dir, args.file); let lineCount = 0; // Vérifier si le fichier existe if (!fs.existsSync(filePath)) { throw new Error(`Le fichier CSV ${filePath} n'existe pas`); } else { console.log(`Le fichier CSV ${filePath} existe`); } fs.createReadStream(filePath) .on('data', () => { lineCount++; }) .on('end', () => { console.log(`Nombre de lignes dans le fichier CSV : ${Math.floor(lineCount)}`); }); } console.log(`args: `, args); checkFile(args); csvToGeoJSON(args);