I’m relatively new with JavaScript and D3. I’m trying to visualize data in a d3 map using my own TopoJson file (it could be false, but thats not the issue). Right now, my program is not able to fetch the local json and tsv (Failed to fetch error on debug consol). I ideas, how i can modify the code, so that i can use the local files? Thanks for your help!!
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
var abgleichpostcode = new Map();
var path = d3.geoPath();
var x = d3.scaleLinear().domain([1, 7]).rangeRound([600, 860]);
var color = d3.scaleThreshold().domain(d3.range(1, 7)).range(d3.schemeYlOrRd[7]);
var legendX = width - 100;
var legendY = height - 145;
var legendBg = svg.append("rect")
.attr("class", "legendBg")
.attr("rx", 5)
.attr("ry", 5)
.attr("x", legendX)
.attr("y", legendY - 20)
.attr("fill", "lightsteelblue")
.style("opacity", 0.9)
.attr("width", 95)
.attr("height", 160);
var legend = svg.selectAll(".legend")
.data(color.range().map(function(d) {
d = color.invertExtent(d);
if (d[0] == null) d[0] = x.domain()[0];
if (d[1] == null) d[1] = x.domain()[1];
return d;
}))
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(" + (legendX + 8) + "," + ((legendY + 8) + i * 20) + ")"; });
legend.append("rect")
.attr("width", 20)
.attr("height", 20)
.style("fill", function(d) { return color(d[0]); });
legend.append("text")
.attr("x", 26)
.attr("y", 10)
.attr("dy", ".35em")
.text(function(d) { return Math.round(d[0]); });
svg.append("text")
.attr("class", "label")
.attr("x", legendX + 48)
.attr("y", legendY)
.text("Population");
var cachedData = {}; // Cache for loaded data
var cachedTopoJSON;
function loadMapData(monthIndex) {
var date = new Date(2022, 8); // Start in September 2022
date.setMonth(date.getMonth() + Number(monthIndex));
var year = date.getFullYear();
var month = date.getMonth() + 1; // getMonth() returns 0-11
var file = "abgleichpostcode" + year + (month < 10 ? '0' : '') + month + ".tsv";
if (cachedData[file]) {
updateMapWithData(cachedData[file]);
} else {
d3.tsv(file).then((data) => {
cachedData[file] = data;
updateMapWithData(data);
}).catch(error => {
console.error("Error loading file:", file, error);
updateMapWithData([]);
});
}
}
function updateMapWithData(data) {
abgleichpostcode.clear();
data.forEach(d => { abgleichpostcode.set(d.zip, +d.rate); }); // Use d.zip instead of d.id
if (cachedTopoJSON) {
ready(cachedTopoJSON);
} else {
d3.json("ersterVersuch.json").then(us => { // Load ersterVersuch.json
cachedTopoJSON = us;
ready(us);
}).catch(error => {
console.error("Error loading ersterVersuch.json:", error);
});
}
}
function ready(us) {
console.log("TopoJSON loaded:", us);
var zipCodes = svg.selectAll(".zipCodes path").data(topojson.feature(us, us.objects.zip_codes_for_the_usa).features);
zipCodes.exit().remove();
zipCodes.enter().append("path")
.merge(zipCodes)
.attr("fill", function(d) {
var rate = abgleichpostcode.get(d.properties.zip); // Use d.properties.zip
return rate !== undefined ? color(d.rate = rate) : "#ccc"; // Default color for missing data
})
.attr("d", path)
.on("mouseover", function(event, d) {
d3.select(this).attr("fill", "white"); // Change color on mouseover
})
.on("mouseout", function(event, d) {
d3.select(this).attr("fill", function(d) {
var rate = abgleichpostcode.get(d.properties.zip); // Use d.properties.zip
return rate !== undefined ? color(d.rate = rate) : "#ccc"; // Reset to original color
});
})
.append("title")
.text(function(d) {
return d.rate !== undefined ? d.rate + "%" : "No data";
});
console.log("Map drawn with ZIP codes");
}
function updateMap(monthIndex) {
var date = new Date(2022, 8); // Start in September 2022
date.setMonth(date.getMonth() + Number(monthIndex));
var year = date.getFullYear();
var monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
var month = monthNames[date.getMonth()];
document.getElementById("selected-month").innerText = month + " " + year;
loadMapData(monthIndex);
}
let interval;
let running = false;
function autoSlide() {
if (running) return; // Prevent multiple starts
running = true;
let slider = document.getElementById("month-slider");
let max = parseInt(slider.max);
let min = parseInt(slider.min);
let step = parseInt(slider.step);
function slide() {
let value = parseInt(slider.value);
value += step;
if (value > max) {
value = min;
}
slider.value = value;
updateMap(value);
}
interval = setInterval(slide, 800); // Faster speed
}
function stopSlide() {
clearInterval(interval);
running = false;
}
document.getElementById("start-button").addEventListener("click", autoSlide);
document.getElementById("stop-button").addEventListener("click", stopSlide);
updateMap(0); // Initialize the first map update
The Json file has the following format:
{"type":"Topology","objects":{"zip_codes_for_the_usa":{"type":"GeometryCollection","geometries":[{"type":"Polygon","properties":{"name":"MT MEADOWS AREA","zip":"00012","state":"CA"},"arcs":[[0,1,2]]},{"type":"Polygon","properties":{"name":"WEST PIMA COUNTY","zip":"00014","state":"AZ"},"arcs":[[3,4,5,6,7]]},{"type":"Polygon","properties":{"name":"CORONADO NTL FOREST","zip":"00015","state":"AZ"},"arcs":[[8,9,10,11,12,13,14,15,16,17,18]]},...
I tried this, but this didnt work either:
function updateMapWithData(data) {
abgleichpostcode.clear();
data.forEach(d => { abgleichpostcode.set(d.zip, +d.rate); });
if (cachedTopoJSON) {
ready(cachedTopoJSON);
} else {
fetch("ersterVersuch.json") // Fetch-Befehl zum Laden der JSON-Datei
.then(response => response.text()) // Die Datei als Text laden
.then(text => {
var us = JSON.parse(text); // JSON-Text in ein JavaScript-Objekt umwandeln
cachedTopoJSON = us;
ready(us);
})
.catch(error => {
console.error("Error loading ersterVersuch.json:", error);
});
}
}
Carmen Zoller is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.