我是编程新手,我一直在研究 O'Reilly 交互式数据可视化书中的示例。
现在,我正致力于按州对电动汽车 5 年的数据进行可视化。每个州的颜色会根据特定年份注册的电动汽车数量而变化。
问题 :
每次我点击下拉菜单中的 year
时,它都会在它下面创建另一个 map svg。我怎样才能让它在同一个(现有的) map svg 上重新渲染数据?
背景:
我有定义 svg 尺寸的全局变量。我也有两个功能:
drawMap
有一个 year 参数并构建 svg,将数据从 csv 加载到 us_map.json
,并创建所有状态边界。 clickEventMap
将事件监听器附加到每个年份按钮,然后调用 drawMap
函数传递与按钮上的年份匹配的年份。最后,我调用 drawMap(2013)
使页面默认为 2013 年数据,然后调用 clickEventMap()
。 到目前为止我尝试过的:
我
console.log(year)
在 d3 color.domain
方法之后,正确的年份在那时被存储为年份变量。此外,如果我在调用
drawMap()
时手动更改参数,我可以成功更改现有 map 上呈现的数据。我的代码:
var w = 1200;
var h = 800;
var barpadding = 1;
var drawMap = function(year) {
var svg = d3.select("body")
.append("svg")
.attr("height", h)
.attr("width", w);
var projection = d3.geo.albersUsa()
.translate([w/2, h/2])
.scale([1600]);
var path = d3.geo.path()
.projection(projection);
var color = d3.scale.quantize()
.range(["rgb(237, 248, 233)", "rgb(186, 228, 179)", "rgb(116,196,118)", "rgb(49, 163, 84)", "rgb(0, 109, 44)"]);
color.domain([
d3.min(data, function(d) {return d["electric_vehicles_" + year];}),
d3.max(data, function(d) { return d["electric_vehicles_" + year];})
]);
console.log(year);
d3.json("us-states.json", function(json) {
for (var i = 0; i < data.length; i ++) {
var dataState = data[i].state;
var dataValue = parseFloat(data[i]["electric_vehicles_" + year]);
for (var j = 0; j < json.features.length; j++) {
var jsonState = json.features[j].properties.name;
if (dataState === jsonState) {
json.features[j].properties.value = dataValue;
break;
}
}
}
var stateView = function() {
console.log("State clicked.");
location.href="/states/1";
svg.selectAll("path")
.data(json.features)
.enter()
.append("path")
.attr("d", path)
.style("fill", function(d) {
var value = d.properties.value;
if (value) {
return color(value);
}
else {
return "#ccc";
}
})
.on("mouseover", function(d, i) {
d3.select(this)
.style("fill-opacity", 0.5);
})
.on("mouseout", function(d, i) {
d3.selectAll("path")
.style("fill-opacity", 1);
})
.on("click", function() {
stateView();
});
});
});
};
var clickEventMap = function() {
$("#map2013").on("click", function() {
// var year = 2013;
drawMap(2013);
});
$("#map2012").on("click", function() {
// var year = 2012;
drawMap(2012);
});
$("#map2011").on("click", function() {
// var year = 2011;
drawMap(2011);
});
$("#map2010").on("click", function() {
// var year = 2010;
drawMap(2010);
});
$("#map2009").on("click", function() {
// var year = 2009;
drawMap(2009);
});
};
drawMap(2013);
clickEventMap();
感谢您的输入。
最佳答案
您的主要问题是您在 drawMap
函数中做了太多事情。里面的很多东西只需要做一次,而不是每次你切换几年。这就是为什么你会得到多张 map 。每次调用 drawMap
时,此代码都会创建一个新的 svg
var svg = d3.select("body")
.append("svg")
.attr("height", h)
.attr("width", w);
如果你只是把它移出
drawMap
函数,你只会得到一个 svg。每次绘制 map 时,您也会获得“us-states.json”文件。这在技术上可能会起作用,但会导致许多您真正不需要的缓慢网络请求。只需在页面加载时发出一次请求。这是对您的代码的一个相当大的重组更改,因为基本上之后的所有内容都需要从回调中调用。
最后,进行这些更改后,您需要更改绘制状态的代码,以使它们正确更新。现在,您可以在“输入”选择上执行所有操作,这只会在新路径上运行。由于您将编辑现有路径,因此您的代码需要看起来更像这样:
var paths = svg.selectAll("path")
.data(json.features)
.enter()
.append("path")
.attr("d", path)
.on("mouseover", function(d, i) {
d3.select(this)
.style("fill-opacity", 0.5);
})
.on("mouseout", function(d, i) {
d3.selectAll("path")
.style("fill-opacity", 1);
})
.on("click", function() {
stateView();
});
paths.style("fill", function(d) {
var value = d.properties.value;
if (value) {
return color(value);
} else {
return "#ccc";
}
});
Mike Bostocks 的文章 Thinking with Joins 和 Three Little Circles 都是了解 d3 更新的重要资源。
基本上,只需考虑一下您只需要做一次的事情,以及每次单击新的一年时需要更改的内容(更新您的色标并为每个州设置填充样式)。尝试将发生过的所有事情都提取到 init 函数中,并使
drawMap
函数保持较小。关于javascript - D3 - 在美国 map 上呈现多年值(value)的州数据,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36897494/