私は社会科学者であり、データ vis ワークのために Web プログラミングにますます興味を持っているので、この質問がばかげている場合は申し訳ありません。国レベルのデータを経時的に視覚化するポリマップの実装に取り組んでいます。json のテンポラル データと geojson の世界地図を読み込み、月ごとのエントリを繰り返す分位点クロロプレス マップを吐き出します。これの核心は、colorbrewer クラスを国 geojson オブジェクトにバインドする国フォーマット関数です (以下を参照)。これは、アニメーション部分の検索に機能します。問題は、現在表示されているデータの日付を表示するカスタム d3 レイヤーを使用していることです。アニメーションを停止して日付を選択するか、アニメーションが終わったら日付を選択するためのマウスオーバー コントロールとして機能します。これは、d3.scale() 関数を使用してマウス入力を目的の月のインデックスに一致する整数に丸める空の svg 要素を作成することによって行われます。ロード時に他のすべての計算をフロント ロードしたので、マウス オーバー時に発生するのは svg クラスの変更だけです (これは基本的に、Bostock の d3 ページでの Tom Carden の豊富な国の実装と同じです)。残念ながら、これでもブラウザはすぐに過負荷になります。私が完全に見逃しているこれを行う別の方法はありますか?私はgeojsonが初めてであることを認めているので、おそらくgeojsonオブジェクトのclass属性でクラスの配列を構築する方法はありますか? たくさんの助けに感謝します。
function foo(local, geojson){
for(var x=0;x<geojson.length;x++){
var n = geojson[x].data.properties.name;
n$(geojson[x].element)
.attr("class", geojson[x].data.formats[local])
.add("svg:title");
}
}
編集:以下の完全なスクリプトを追加しています。
<meta charset="utf-8">
<script src="scripts/d3.v3.js"></script>
<script src="scripts/polymaps.js"></script>
<script src="scripts/nns.js"></script>
<script>
//Polymaps namespace
var po = org.polymaps;
//Chart dimensions
var margin = {top: 20, right: 20, bottom: 20, left: 20};
var w = 960 - margin.right;
var h = 500 - margin.top - margin.bottom;
// Create the map object, add it to #map div
var map = po.map()
.container(d3.select("#map").append("svg:svg").attr("width", w + margin.left + margin.right).attr("height",h +margin.top + margin.bottom).node())
.center({lat: 28, lon: 0})
.zoom(1.85)
.zoomRange([1.5, 4.5])
.add(po.interact());
// Add the CloudMade image tiles as a base layer…
map.add(po.image()
.url(po.url("http://{S}tile.cloudmade.com"
+ "/1a1b06b230af4efdbb989ea99e9841af" // http://cloudmade.com/register
+ "/20760/256/{Z}/{X}/{Y}.png")
.hosts(["a.", "b.", "c.", ""])));
//Import contribution data
d3.json("assets/contributionsTCC1990-1991.json", function(data){
//find length of json data object and loop over it at interval
var dataLength = Object.keys(data).length;
//Create date key/value array using construtor
function date_array_constructor() {
var dateArray = {};
for(var i = 0; i < dataLength; i++) {
var d = i + 1;
dateArray[d] = data[i].date;
}
return dateArray;
}
var dateArray = date_array_constructor();
// Insert date label/control layer and add SVG elements that take on attributes determined by load function
var labelLayer = d3.select("#map svg").insert("svg:g");
map.add(po.geoJson()
.url("assets/world.json")
.tile(false)
.zoom(3)
.on("load", load));
map.container().setAttribute("class", "Blues");
map.add(po.compass()
.pan("none"));
function find_max(data, dataLength) {
var max = 0;
for(var i in data) {
if(data[i] > max) {
max = data[i] + 1;
}
}
return max;
}
function max_array_constructor(data, dataLength) {
var maxArray = {};
for(var i=0;i<dataLength;i++) {
var d = i+1;
maxArray[d] = find_max(data[i].contributions);
}
return maxArray;
}
var maxArray = max_array_constructor(data, dataLength);
function contribution_array_constructor(data, dataLength, tccName, feature) {
var contributions = {};
//iterate over date entries
for(var i=0;i<dataLength;i++) {
//contribution iterator
contributions[i+1] = 0;
for(x in data[i].contributions){
if(x == tccName) {
contributions[i+1] = data[i].contributions[x];
}
}
}
return contributions;
}
function format_array_constructor(data, dataLength, maxArray, feature) {
var formats = {};
// console.log(feature.data.contributions);
//iterate over date entries
for(var i=0;i<dataLength;i++) {
var percentile = feature.data.contributions[i+1] / maxArray[i+1];
if(percentile != 0){
var v = "q" + ((~~(percentile*7)) + 2) + "-" + 9;
}else{
var v = "countries";
}
formats[i+1] = v;
}
return formats;
}
///////////////////////////////
//load function
///////////////////////////////
function load(e) {
//Bind geojson and json
var geojson = e.features;
console.log(geojson);
geojson.dates = dateArray;
for(var x = 0; x < geojson.length; x++) {
// var tccID = geojson[x].data.id;
var tccName = geojson[x].data.properties.name;
geojson[x].data.contributions = contribution_array_constructor(data, dataLength, tccName, geojson[x]);
geojson[x].data.formats = format_array_constructor(data, dataLength, maxArray, geojson[x]);
}
//Insert date label
var dateLabel = labelLayer.append("text")
.attr("class", "date label")
.attr("text-anchor", "end")
.attr("x", w-670)
.attr("y", h )
.text(dateArray[1]);
//Add interactive overlay for date label
var box = dateLabel.node().getBBox();
var overlay = labelLayer.append("rect")
.attr("class", "overlay")
.attr("x", box.x)
.attr("y", box.y)
.attr("opacity",0)
.attr("width", box.width)
.attr("height", box.height)
.on("mouseover",enable_interaction);
function country_class_constructor(local, geojson){
for(var x=0;x<geojson.length;x++){
var n = geojson[x].data.properties.name;
n$(geojson[x].element)
.attr("class", geojson[x].data.formats[local])
.add("svg:title");
}
}
function foo(local, geojson){
for(var x=0;x<geojson.length;x++){
var n = geojson[x].data.properties.name;
n$(geojson[x].element)
.attr("class", geojson[x].data.formats[local])
.add("svg:title");
}
}
//incrementor function
function incrementor(local, geojson, dateArray) {
setTimeout(function() {
//set date label to current iteration
d3.transition(dateLabel).text(dateArray[local]);
//construct country classes
country_class_constructor(local, geojson);
// console.log(geojson);
}, 500*local);
}
///////////////////////////////
//Increment on load
///////////////////////////////
country_class_constructor(1, geojson)
for(var i=1; i< dataLength; i++) {
//Set incrementer as local variable
var local = i+1;
var timer = incrementor(local, geojson, dateArray);
}
///////////////////////////////
//interaction element
///////////////////////////////
function enable_interaction(){
var dateScale = d3.scale.linear()
.domain([1,Object.keys(dateArray).length])
.range([box.x + 10, box.x + box.width - 10])
.clamp(true);
timer = null;
overlay
.on("mouseover", mouse_over)
.on("mouseout",mouse_out)
.on("mousemove",mouse_move)
.on("touchmove",mouse_move);
function mouse_over() {
dateLabel.classed("active", true);
}
function mouse_out() {
dateLabel.classed("active", false);
}
function mouse_move() {
update_map(dateScale.invert(d3.mouse(this)[0]),data);
// displayYear(dateScale.invert(d3.mouse(this)[0]));
}
function update_map(userInput) {
var date = Math.floor(userInput);
d3.transition(dateLabel).text(dateArray[date]);
// console.log(date);
// country_class_constructor(date, geojson);
foo(date, geojson);
}
}
}
});
</script>
編集 2: JSON 形式を追加するのを忘れていました。2 か月間のデータについては、以下を参照してください。
[
{"date":"11/90",
"contributions":{
"Algeria":7,
"Argentina":39,
"Australia":41,
"Austria":967,
"Bangladesh":5,
"Belgium":4,
"Brazil":27,
"Canada":1002,
"Chile":7,
"China":5,
"Colombia":12,
"Czech Republic":6,
"Denmark":374,
"Ecuador":21,
"Fiji":719,
"Finland":992,
"France":525,
"Germany":13,
"Ghana":892,
"Hungary":15,
"India":40,
"Indonesia":5,
"Ireland":814,
"Italy":79,
"Jordan":6,
"Kenya":7,
"Malaysia":15,
"Nepal":851,
"Netherlands":15,
"New Zealand":22,
"Nigeria":2,
"Norway":924,
"Poland":165,
"Republic of the Congo":6,
"Russia":35,
"Senegal":4,
"Serbia":17,
"Spain":63,
"Sweden":738,
"Switzerland":5,
"Turkey":2,
"United Kingdom":769,
"United States":33,
"Uruguay":10,
"Venezuela":23,
"Zambia":6
}
},
{"date":"12/90",
"contributions":{
"Algeria":7,
"Argentina":39,
"Australia":41,
"Austria":967,
"Bangladesh":5,
"Belgium":4,
"Brazil":27,
"Canada":1002,
"Chile":7,
"China":5,
"Colombia":12,
"Czech Republic":6,
"Denmark":374,
"Ecuador":21,
"Fiji":719,
"Finland":992,
"France":525,
"Germany":13,
"Ghana":892,
"Hungary":15,
"India":40,
"Indonesia":5,
"Ireland":814,
"Italy":79,
"Jordan":6,
"Kenya":7,
"Malaysia":15,
"Nepal":851,
"Netherlands":15,
"New Zealand":22,
"Nigeria":2,
"Norway":924,
"Poland":165,
"Republic of the Congo":6,
"Russia":35,
"Senegal":4,
"Serbia":17,
"Spain":63,
"Sweden":738,
"Switzerland":5,
"Turkey":2,
"United Kingdom":769,
"United States":33,
"Uruguay":10,
"Venezuela":23,
"Zambia":6
}
}
]