APIを用いてjson形式にしたRSSをd3.jsに読み込みforceモデルを出力したい
現在こちらのサイト様( http://qiita.com/tag1216/items/b7f846af66db30b8c393 ),( http://bl.ocks.org/mbostock/4062045 )を参考にしながらjson形式で読み込んだRSSをforceモデルで表示させようとしておりますが、上手くいかない状況です。
var url = "https://ajax.googleapis.com/ajax/services/feed/load?v=1.0&q=http://feeds.feedburner.com/hatena/b/hotentry&num=-1";
var proxy_url = "http://allow-any-origin.appspot.com/" + encodeURIComponent(url);
var WIDTH = 800,
HEIGHT = 800,
TAG_IMAGE = 16,
ITEM_IMAGE_SIZE = 8,
APPEND_INTERVAL = 250;
var tags = [];
var items = [];
var nodes = [];
var links = [];
var svg = d3.select("body").append("svg")
.attr("width", WIDTH)
.attr("height", HEIGHT);
var force = d3.layout.force()
.size([WIDTH, HEIGHT])
.nodes(nodes)
.links(links)
.charge(0)
.linkDistance(20)
.linkStrength(1)
.gravity(0.3)
.start();
var itemNode = svg.selectAll(".item-node");
var tagNode = svg.selectAll(".tag-node");
var link = svg.selectAll(".link")
force.on("tick", function() {
link.attr("x1", function(d) {
return d.source.x;
})
.attr("y1", function(d) {
return d.source.y;
})
.attr("x2", function(d) {
return d.target.x;
})
.attr("y2", function(d) {
return d.target.y;
});
itemNode.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
tagNode.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
});
/*//データ読み込み*/
d3.json(proxy_url, function(error, json) {
if (error) {
return console.warn(error);
}
/*コンソールにタイトル、リンク、カテゴリを表示*/
var feeds = json.responseData.feed;
for (var i = 0; i < feeds.entries.length; i++) {
title = feeds.entries[i].title;
link = feeds.entries[i].link;
tags = feeds.entries[i].categories;
console.log(title);
console.log(link);
console.log(tags);
};
var index = 0;
var timer = setInterval(function() {
try {
if (json.length <= index) {
clearInterval(timer);
showMessage("");
return;
}
showMessage("データ追加中(" + (index + 1) + "/" + json.length + ")...");
appendItem(json[index++])
} catch (e) {
showMessage(e);
clearInterval(timer);
}
}, APPEND_INTERVAL);
});
/*//メッセージ*/
function showMessage(text) {
d3.select(".message").text(text);
}
/*//投稿をノードとして追加*/
function appendItem(item) {
items.push(item);
nodes.push(item);
item.tags.forEach(function(tag) {
var name = "___" + tag.name;
if (!(name in tags)) {
tags[name] = tag;
tags[name].count = 0;
nodes.push(tags[name]);
}
tags[name].count++;
links.push({
source: nodes.indexOf(item),
target: nodes.indexOf(tags[name])
});
});
restart();
}
/*forceレイアウトの再描画*/
function restart() {
itemNode = itemNode.data(json);
tagNode = tagNode.data(d3.values(tags));
drawItemNode();
drawTagNode();
drawLink();
force
.nodes(nodes)
.links(links)
.charge(function(d) {
//反発力を 投稿数の多いタグ > 投稿数の少ないタグ > 投稿ノード にする
return d.count ? -(d.count * 200) : -100;
});
force.start();
}
/* 投稿ノードの描画*/
function drawItemNode() {
var g = itemNode.enter().append("g")
.attr("class", "node item")
.call(force.drag);
var a = g.append("a")
.attr("xlink:href", function(d) {
return d.link;
})
.attr("target", "_blank");
a.append("circle")
.attr("r", ITEM_IMAGE_SIZE);
a.append("image")
.attr("xlink:href", function(d) {
var imgCheck = entry.content.match(/<img.+?src="\/\/(.+?\/images\?q=.+?)\"/);
if (igCheck) {
var eimg = "http://" + imgCheck;
} else {
eimg = "http://design-ec.com/d/e_others_50/l_e_others_500.png";
}
return eimg
})
.attr({
x: -ITEM_IMAGE_SIZE / 2,
y: -ITEM_IMAGE_SIZE / 2,
width: ITEM_IMAGE_SIZE,
height: ITEM_IMAGE_SIZE
});
g.append("title")
.text(function(d) {
return d.title;
});
}
/*タグノードの描画*/
function drawTagNode() {
var g = tagNode.enter().insert("g", ".item")
.attr("class", "node tag")
.call(force.drag);
var a = g.append("a")
.attr("xlink:href", function(d) {
return "b.hatena.ne.jp/hotentry/" + d.categories;
})
.attr("target", "_blank");
a.append("image")
.attr("xlink:href", function(d) {
return d.icon_url == "/icons/medium/missing.png" ? "http://qiita.com/icons/medium/missing.png" : d.icon_url;
});
a.append("rect");
a.append("text")
.attr("class", "shadow");
a.append("text")
.attr("class", "text");
tagNode.selectAll("text")
.attr("text-anchor", "middle")
.text(function(d) {
return d.name;
});
tagNode.each(function(d) {
var size = ~~(TAG_IMAGE_SIZE * Math.sqrt(d.count));
d3.select(this).select("image")
.attr({
x: -size / 2,
y: -size / 2,
width: size,
height: size
});
d3.select(this).select("rect")
.attr({
x: -size / 2,
y: -size / 2,
width: size,
height: size
});
d3.select(this).selectAll("text")
.attr("dy", size / 2 + 10);
});
/* リンクの描写*/
function drawLink() {
link = link.data(links);
link.enter().insert("line", ".tag")
.attr("class", "link");
}
};
<!DOCTYPE html>
<meta charset="utf-8">
<title>はてなブックマーク新着記事を表示</title>
<style>
svg {
border: solid 1px;
}
.item image {
opacity: .7;
}
.item circle {
fill: #fff;
fill-opacity: .7;
stroke-width: .5px;
stroke: #60c90d;
stroke-opacity: .7;
}
.tag image {
opacity: .9;
}
.tag rect {
fill-opacity: 0;
stroke-width: 1px;
stroke: #0f6faf;
stroke-opacity: .9;
}
.tag text {
pointer-events: none;
font-size: 8px;
}
.tag .shadow {
stroke: #fff;
stroke-width: 3px;
stroke-opacity: .7;
}
.link {
stroke: #aaa;
stroke-width: 2px;
opacity: .3;
}
</style>
<html>
<!-- <head>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script type="text/javascript">
var url = "https://ajax.googleapis.com/ajax/services/feed/load?v=1.0&q=http://feeds.feedburner.com/hatena/b/hotentry&num=-1";
var proxy_url = "http://allow-any-origin.appspot.com/" + encodeURIComponent(url);
d3.json(proxy_url, function(error, json) {
if (error) {
return console.warn(error);
}
var feeds = json.responseData.feed;
for(var i =0;i < feeds.entries.length;i++){
title = feeds.entries[i].title;
link = feeds.entries[i].link;
tags = feeds.entries[i].categories;
console.log(title);
console.log(link);
console.log(tags);
};
});
</script> -->
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="message"></div>
<script src="hatena.js"></script>
</body>
</html>
上記のスニペットに書いているjsファイルを"hatena.js"として保存し、htmlを実行した場合
TypeError: Cannot read property 'tags' of undefined
というエラーが表示されます。
参照しているRSS( http://feeds.feedburner.com/hatena/b/hotentry/ )上にはtagという情報がないため代替としてsubjectというもので代用しようと思ったのですが指定の仕方がわかりませんでした。
イメージとしては記事のサムネイルが上記サイト様の投稿ノードの部分に入り、タグノードにカテゴリーを表示させるプログラムが作りたいと考えています。
コンソールには記事のタイトル、リンク、カテゴリーが表示されるため正しくRSSは読み込めていると思います。
スニペット上でhtmlからjsファイルを開く方法が分からなく、不恰好な形での質問になってしまい申し訳ありません。
お力添えの方よろしくお願い致します。