我正在尝试结合两个教程/示例。 基本 choropleth 数据的动态更新
虽然我已经实现了来自人口普查 API 的数据更新并根据值更改地图颜色,但我无法将名称/值项添加到 SVG,这样如果您将鼠标悬停在map 它将显示 : 的工具提示。
从第一个示例中,我相信我需要的是:
.text(function(d) { return d.properties.name + ": " + data[pad(d.id)] + "%"; });
但是,当我添加它看起来像我应该去的地方时,我收到以下错误:
未捕获的类型错误:无法读取未定义的属性“名称”
这是我用来生成的代码:
function showData() {
acsData = document.getElementById('measure').value;
console.log('Gettting data for: ' + acsData);
var jsonRequest = 'http://api.census.gov/data/2011/acs5?key=<mykey>&get=' + acsData + ',NAME&for=county:*&in=state:*';
console.log(acsData);
var dataSet = [];
d3.json(jsonRequest, function (data) {
$.each(data, function (key, val) {
if (key > 0) {
var apiValue = parseInt(val[0], 10);
var apiState = val[2].toString();
var apiCounty = val[3].toString();
var elmentArray = [apiState, apiCounty, apiValue]
dataSet.push(elmentArray);
//console.log(elmentArray);
//console.log(dataSet.length);
}
});
var rateById = {};
var maxVal; var minVal; var maxFips, minFips, maxCounty, minCounty;
var vals = [];
dataSet.forEach(function (d) {
var fips = parseInt(d[0] + d[1], 10);
//console.log(fips);
if (fips !== 0 && fips.toString().substr(3) != '000') {
var val = parseFloat(d[2], 10);
if (val > maxVal || maxVal == null) { maxVal = val; maxFips = fips; }
if (val < minVal || minVal == null) { minVal = val; minFips = fips; }
rateById[fips] = +val;
vals.push(val);
}
});
countyFips.forEach(function (c) {
if (parseInt(c.StateFips + c.CountyFips) == maxFips) maxCounty = c.CountyName + ', ' + c.State;
if (parseInt(c.StateFips + c.CountyFips) == minFips) minCounty = c.CountyName + ', ' + c.State;
});
vals = vals.sort(d3.ascending);
quantize = d3.scale.quantile()
.domain(vals)
.range(d3.range(20).map(function (i) {
return color(i);
}));
mapSvg.select('g').selectAll('path')
.transition()
.duration(750)
.style("fill", function (d) {
return quantize(rateById[d.id]);
});
keySvg.select('g').remove();
var keysEnter = keySvg.append('g').selectAll('circle')
.data(d3.range(0, 21, 2))
.enter();
keysEnter
.append('circle')
.attr('cy', function (i) { return (i + 1) * 14; })
.attr('cx', 12)
.attr('r', 10)
.style('fill', color);
keysEnter
.append('text')
.attr('class', 'keyLabel')
.attr('y', function (i) { return ((i + 1) * 14) + 5; })
.attr('x', 26)
.text(function (i) {
var keyLabel;
if (i == 0) keyLabel = d3.round(minVal || 0, 1) + ' ' + minCounty;
if (i != 0 && i != 20) keyLabel = d3.round(quantize.quantiles()[i], 1);
if (i == 20) keyLabel = d3.round(maxVal || 0, 1) + ' ' + maxCounty;
return keyLabel;
});
});
}
var containerWidth = 640,
baseWidth = 960,
baseStrokeWidth = 1,
scaleFactor = containerWidth / baseWidth;
function prepareMap() {
mapSvg.append("g")
.attr("class", "counties")
.selectAll("path")
.data(topojson.object(us, us.objects.counties).geometries)
.enter().append("path")
.style("fill", function (d) { return '#ccc' })
.attr("d", path);
mapSvg.append("path")
.datum(topojson.mesh(us, us.objects.states, function (a, b) { return a.id !== b.id; }))
.attr("class", "states")
.attr("d", path)
.append("svg:title")
.text(function (d) { return d.properties.name + ": " + data[pad(d.id)] + "%"; });
}
function click(d) {
var x = 0,
y = 0,
k = 1;
if (d && centered !== d) {
var centroid = path.centroid(d);
x = -centroid[0] / 4;
y = -centroid[1] / 4;
k = 2;
centered = d;
} else {
centered = null;
}
mapSvg.selectAll("path")
.classed("active", centered && function (d) { return d === centered; });
mapSvg.selectAll('g').transition()
.duration(1000)
.attr("transform", "scale(" + k + ")translate(" + x + "," + y + ")")
.style("stroke-width", 1.5 / k + "px");
}
function ready(error, usData, countyFipsData) {
us = usData;
countyFips = countyFipsData;
prepareMap();
showData();
}