I created a code that use a csv file that is imported into the project folder so that it can display the markers for each data point, while making marker clusters and layers. My code works great, but my boss would like me to add a function so that he could add a csv file himself on the interface. I figured out another code so that he can add a csv file and display the markers, but I don’t know how to apply it to the code I already have so that the layers and marker subgroups still work. Can someone please help me? I’m an engineering intern with some coding experience but not enough to really know what I’m doing on this project and would really appreciate any and all help. Thank you.
Here’s my original code that works great and I want to keep, just with the added CSV file uploaded feature:
<!DOCTYPE html>
<html>
<head>
<title>leaflet-map-csv</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="style.css">
<link rel="stylesheet" href="https://unpkg.com/leaflet-control-geocoder/dist/Control.Geocoder.css" />
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster/dist/MarkerCluster.css" />
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster/dist/MarkerCluster.Default.css" />
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.2/leaflet.draw.css" />
<style>
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
}
</style>
</head>
<body>
<div id="map"></div>
<!-- PLUG INS-->
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
<script src="https://unpkg.com/leaflet.markercluster/dist/leaflet.markercluster.js"></script>
<script src="https://unpkg.com/leaflet.featuregroup.subgroup/dist/leaflet.featuregroup.subgroup-src.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.3.0/papaparse.min.js"></script>
<script src="https://unpkg.com/leaflet-control-geocoder/dist/Control.Geocoder.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.2/leaflet.draw.js"></script>
<script>
var map = L.map('map', {
center: [34.098907, -118.327759], // where the map zooms in to
zoom: 9 // can zoom from 0-18
});
//these are the map layers. this can be changed from choosing tiles from a website like: https://leaflet-extras.github.io/leaflet-providers/preview/
var light = L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', {
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>, © <a href="https://carto.com/attribution">CARTO</a>'
}).addTo(map);
var terrain = L.tileLayer('https://stamen-tiles.a.ssl.fastly.net/terrain/{z}/{x}/{y}.png', {
attribution: 'Map tiles by <a href="http://stamen.com">Stamen Design</a>, under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. Data by <a href="http://openstreetmap.org">OpenStreetMap</a>, under <a href="http://www.openstreetmap.org/copyright">ODbL</a>.'
});
var googleSat = L.tileLayer('http://{s}.google.com/vt/lyrs=s&x={x}&y={y}&z={z}', {
maxZoom: 20,
subdomains: ['mt0', 'mt1', 'mt2', 'mt3']
});
//this just create sthe link from the layer titles to the variable
var baseLayers = {
"Carto Light Basemap": light,
"Stamen Terrain Basemap": terrain,
"Satellite Basemap": googleSat
};
//THIS IS THE SEARCH FUNCTION
var geocoder = L.Control.geocoder()
.on('markgeocode', function (event) {
var center = event.geocode.center;
L.marker(center).addTo(map);
map.setView(center, 13);
//L.circle(center, 900).addTo(map); this creates a radius everytime you search
})
.addTo(map);
//this creates the toolbar to be able to draw on the map
var drawnFeatures = new L.FeatureGroup();
map.addLayer(drawnFeatures);
var drawControl = new L.Control.Draw({
edit:
{
featureGroup: drawnFeatures,
remove: true
},
draw: {
polygon:
{
shapeOptions:
{
color: 'red'
}
},
polyline:
{
shapeOptions:
{
color: 'green'
}
},
rect:
{
shapeOptions:
{
color: 'purple'
}
},
circle:
{
shapeOptions:
{
color: 'blue'
}
},
marker: false // follow this format if you don't want a certain shape
}
});
map.addControl(drawControl);
//this allows the drawings to be created, saved, and edited
map.on("draw:created", function (e) {
var type = e.layerType;
var layer = e.layer;
drawnFeatures.addLayer(layer);
});
map.on("draw:edited", function (e) {
var layers = e.layers;
layers.eachLayer(function (layer) {
});
});
var controlLayers = L.control.layers(baseLayers);
var engineerLayers = {}; // Create an object to hold the engineer marker cluster groups
//this retrieves the file
$.get('practice.csv', function (csvString) {
var data = Papa.parse(csvString, {
header: true,
dynamicTyping: true
}).data;
var parentGroup = L.markerClusterGroup();
for (var i in data) {
var row = data[i];
var engineer = row.Engineer;
if (!(engineer in engineerLayers)) {
// Each overlay that should actually be a part of MCG
// should be made as a Subgroup, with the MCG as their parent
engineerLayers[engineer] = L.featureGroup.subGroup(parentGroup, []);
controlLayers.addOverlay(engineerLayers[engineer], engineer);
}
var marker = L.circleMarker([row.Latitude, row.Longitude], {
radius: 10,
stroke: true,
color: getColor(engineer),
opacity: 1,
weight: 1,
fill: true,
fillColor: getColor(engineer),
fillOpacity: 0.5
}).bindPopup('Plan File: ' + row.PFN + '</br>' + 'Engineer: ' + row.Engineer + '</br>' + ' Date Received: ' + row.Date_Received + '</br>' + 'Status: ' + row.Status);
// Add the marker only to its overlay
marker.addTo(engineerLayers[engineer]);
}
map.addLayer(parentGroup);
controlLayers.addTo(map);
});
// Must change these if engineers ever change
function getColor(engineer) {
switch (engineer) {
case 'Mike':
return 'green';
case 'Salar':
return 'blue';
case 'Diego':
return 'purple';
case 'Saul':
return 'orange';
case 'Chan':
return 'red';
default:
return 'black';
}
}
//****IF YOU ARE GETTING AN UNDEFINED LAYER, MAKE SURE TO GET RID OF ANY EXTRA SPACE IN THE CSV FILE
</script>
</body>
</html>
Here’s the code I have written to allow the user to upload the csv file and then to print the data
<!DOCTYPE html>
<html>
<head>
<title>Leaflet Map with CSV Marker Data</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet.css" />
<style>
/* Add some styling to the map container */
#map {
height: 400px;
width: 100%;
}
</style>
</head>
<body>
<input type="file" id="csvFileUpload">
<div id="map"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
// Initialize Leaflet map
var map = L.map('map').setView([0, 0], 2);
// Add the tile layer (e.g., OpenStreetMap)
var light = L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', {
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>, © <a href="https://carto.com/attribution">CARTO</a>'
}).addTo(map);
var baseLayers = {
"Carto Light Basemap": light,
};
var controlLayers = L.control.layers(baseLayers);
// Listen for file upload changes
$('#csvFileUpload').change(function (e) {
var file = e.target.files[0];
var reader = new FileReader();
// Read file contents
reader.onload = function (e) {
var csv = e.target.result;
var markers = parseCSV(csv);
// Add markers to the map
markers.forEach(function (marker) {
L.marker([marker.Latitude, marker.Longitude]).addTo(map)
.bindPopup(marker.title);
});
};
reader.readAsText(file);
});
// Parse CSV data into an array of objects
function parseCSV(csv) {
var lines = csv.split("n");
var result = [];
var headers = lines[0].split(",");
// Iterate through each line (excluding header) and create marker objects
for (var i = 1; i < lines.length; i++) {
var obj = {};
var currentLine = lines[i].split(",");
// Populate marker object with latitude, longitude, and title
for (var j = 0; j < headers.length; j++) {
obj[headers[j]] = currentLine[j];
}
result.push(obj);
}
return result;
}
</script>
</body>
</html>