mapFunc2 = (raw) => {
const width = 975;
const height = 610;
const margin = 35;
const data = raw.filter(d => d.NAME !== undefined && d.NAME > 1);
const projection = d3.geoAlbersUsa().scale(1300).translate([width / 2, height / 2]);
const path = d3.geoPath();
const svg = d3.create('svg')
.attr("viewBox", [-margin, -2 * margin, width + margin, height + 2.5 * margin]);
const statesBackground = svg
.append('path')
.attr('fill', '#ddd')
.attr('d', path(topojson.feature(us, us.objects.nation)));
const statesBorders = svg
.append('path')
.attr('fill', 'none')
.attr('stroke', '#fff')
.attr('stroke-linejoin', 'round')
.attr('stroke-linecap', 'round')
.attr('d', path(topojson.mesh(us, us.objects.states, (a, b) => a !== b)));
const stateCapitalElements = svg
.selectAll('g')
.data(data)
.join('g');
const scale = d3.scaleSqrt()
.domain([0, d3.max(data, d => d.Q2) || 1])
.range([2, 20]);
const capitalGroups = stateCapitalElements
.append('g')
.attr('transform', ({ INTPTLONG, INTPTLAT }) => {
const coords = projection([INTPTLONG, INTPTLAT]);
return coords ? `translate(${coords.join(",")})` : "translate(0,0)";
});
capitalGroups.append('circle')
.attr('stroke-opacity', 1)
.attr('stroke', 'steelblue')
.attr('opacity', 0.5)
.attr('fill', 'steelblue')
.attr('r', ({ Q2 }) => Q2 ? scale(Q2) : scale(1));
const tooltip = svg.append("g");
svg
.selectAll('g')
.on('touchmove mousemove', function(event, d) {
tooltip.call(
callout,
`${d.Q7}, ${d.Code}\nMedian salary: ${d3.format("($,")(d.Q2)}\nNo. respondents: ${d.NAME}`
);
tooltip.attr("transform", `translate(${d3.pointer(event, this)[0]},${d3.pointer(event, this)[1]+10})`);
d3.select(this).select('circle')
.attr("fill", "#ffc87c")
.attr('stroke', "#ffc87c")
})
.on("touchend mouseleave", function() {
tooltip.call(callout, null);
d3.select(this).select('circle')
.attr("fill", 'steelblue')
.attr('stroke', 'steelblue')
});
svg.append("text")
.attr("x", -margin)
.attr("y", -margin - 10)
.attr("text-anchor", "left")
.style("font-family", "Georgia")
.style("font-size", "18px")
.text('Median Salary by City');
svg.append("text")
.attr("x", -margin)
.attr("y", 10-margin)
.attr("text-anchor", "left")
.style("font-size", "14px")
.style("font-style", "italic")
.text('Cities with fewer than 2 respondents are not included');
svg.append("text")
.attr("x", width-3*margin)
.attr("y", -0.5*margin+3)
.attr("text-anchor", "left")
.style("font-family", "sans-serif")
.style("font-size", "0.7em")
.style("font-weight", "bold")
.text('$120,000');
svg.append("circle")
.attr("cx", width-4*margin)
.attr("cy", -0.5*margin)
.attr('stroke-opacity', 1)
.attr('stroke', 'steelblue')
.attr('opacity', 0.5)
.attr('fill', 'steelblue')
.attr('r', scale(120000));
svg.append("circle")
.attr("cx", width-4*margin-50)
.attr("cy", -0.5*margin)
.attr('stroke-opacity', 1)
.attr('stroke', 'steelblue')
.attr('opacity', 0.5)
.attr('fill', 'steelblue')
.attr('r', scale(90000));
svg.append("circle")
.attr("cx", width-4*margin-83)
.attr("cy", -0.5*margin)
.attr('stroke-opacity', 1)
.attr('stroke', 'steelblue')
.attr('opacity', 0.5)
.attr('fill', 'steelblue')
.attr('r', scale(60000));
svg.append("circle")
.attr("cx", width-4*margin-103)
.attr("cy", -0.5*margin)
.attr('stroke-opacity', 1)
.attr('stroke', 'steelblue')
.attr('opacity', 0.5)
.attr('fill', 'steelblue')
.attr('r', scale(30000));
svg.append("text")
.attr("x", width-4*margin-160)
.attr("y", -0.5*margin+3)
.attr("text-anchor", "left")
.style("font-family", "sans-serif")
.style("font-size", "0.7em")
.style("font-weight", "bold")
.text('$30,000');
return svg.node();
};