Skip to content

Commit

Permalink
category chart, and filter
Browse files Browse the repository at this point in the history
  • Loading branch information
nielinjie committed Apr 20, 2014
1 parent e98d3ae commit 3abeab7
Show file tree
Hide file tree
Showing 8 changed files with 252 additions and 1 deletion.
2 changes: 1 addition & 1 deletion _config.yml
Expand Up @@ -50,7 +50,7 @@ titlecase: true # Converts page and post titles to titlecase

# list each of the sidebar modules you want to include, in the order you want them to appear.
# To add custom asides, create files in /source/_includes/custom/asides/ and add them to the list like 'custom/asides/custom_aside_name.html'
default_asides: [custom/asides/about.html,asides/recent_posts.html, custom/asides/category_list.html]
default_asides: [custom/asides/about.html,asides/recent_posts.html, custom/asides/category.html]

# Each layout uses the default asides, but they can have their own asides instead. Simply uncomment the lines below
# and add an array with the asides you want to use.
Expand Down
5 changes: 5 additions & 0 deletions sass/custom/_fonts.scss
Expand Up @@ -18,3 +18,8 @@ $header-subtitle-font-family: "Futura", sans-serif;
#tag-cloud a {
margin:5px;
}


#blog-filtered h1 {
font-size: 1.5em;
}
153 changes: 153 additions & 0 deletions source/_includes/custom/asides/category.html
@@ -0,0 +1,153 @@
<style>

.link {
stroke: #000;
stroke-width: 1.5px;
}

.node circle{
cursor: pointer;
fill: #ccc;
stroke: #000;
stroke-width: 1.5px;

}

.node circle.hover {
fill:#DDD
}
.node circle.selected{
fill:#EEE
}

.d3-tip {
padding:5px;
border: 1px solid #bfbfbf;
}



</style>
<section class="category-svg">

</section>
<script type="text/javascript" charset="utf-8">

var width = 250,
height = 250;

var force = d3.layout.force()
.charge(-150)
.size([width, height])
.on("tick", tick);


var svg = d3.select(".category-svg").append("svg")
.attr("width", width)
.attr("height", height);

var link = svg.selectAll(".link"),
node = svg.selectAll(".node");

function categories(){
return _(window.site.posts).chain()
.map(function(p){return p.categories})
.flatten().value()
}

function nodes(){
return _(categories()).chain().countBy(_.identity).map(function(v,k){
return {name:k,count:v}
}).sortBy(function(n){return n.count}).reverse().value()
}
function bothCategories(post,c1,c2){
return _([c1,c2]).all(function (c){
return _(post.categories).contains(c)
})
}

function relations(){
var cs=_(categories()).uniq()
var couple=[]
for (a in cs) {
for (b in cs){
couple.push([cs[a],cs[b]])
}}
return _(couple).map(function(c){
return [c,_(window.site.posts).chain().filter(function(p){return bothCategories(p,c[0],c[1])}).size().value()]
})
}
var ns=nodes()

var graph={
nodes:ns
,
links:_(relations()).chain().map(function(p){
return {
target:_(ns).find(function(n){return n.name==p[0][0]}),
source:_(ns).find(function(n){return n.name==p[0][1]}),
postCount:p[1]
}
}).filter(function(l){
return l.postCount>0
}).value()
}

var max=_(graph.nodes).chain().pluck("count").max().value()
var scale=d3.scale.linear()
.domain([1, max])
.range([10,30]);

var relationScale=d3.scale.linear()
.domain([_(graph.links).chain().pluck("postCount").max().value(),1])
.range([10,40])

force
.nodes(graph.nodes)
.linkDistance(function(l){return relationScale(l.postCount)})
.links(graph.links)
.start();

link = link.data(graph.links)
.enter().append("line")
.attr("class", "link");
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([0, 0])
.html(function(d) {
return d.name
})
node = node.data(graph.nodes)
.enter().append("g")
.attr("class", "node")
.on("mouseover", tip.show
)
.on("mouseout", tip.hide
)
node.append("circle").attr("r", function(n){return scale(n.count)})
.on("mouseover", function(){
d3.select(this).classed("selected",true)
})
.on("mouseout", function(){
d3.select(this).classed("selected",false)
})
.on("click",function(c){
var url="/blog/filter/filter.html"
window.location.href=buildUrl(url,{filterName:"category",filterValue:c.name,filterDes:"Category: "+c.name})
})
node.call(tip)

function tick() {
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; });

node
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")"; });
}



</script>
7 changes: 7 additions & 0 deletions source/_includes/custom/head.html
Expand Up @@ -6,3 +6,10 @@

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js" type="text/javascript"></script>

<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>

<script src="/javascripts/underscore-min.js" charset="utf-8"></script>
<script src="/javascripts/queryString.js" charset="utf-8"></script>
<script src="/site.json.js" charset="utf-8"></script>
38 changes: 38 additions & 0 deletions source/blog/filter/filter.html
@@ -0,0 +1,38 @@
---
layout: page
title: Blog Archive
footer: false
---

<div id="blog-filtered">

</div>
<script type="text/javascript" charset="utf-8">
function filter(){
window.filter={
name:getParameterByName("filterName"),
value:getParameterByName("filterValue"),
des:getParameterByName("filterDes")
}
if(window.filter.name=="category"){
return _(window.site.posts).filter(function(p){
return _(p.categories).contains(window.filter.value)
})
}

}
function article(post){
var art=$("<article/>")
art.append($("<h1/>").append($("<a/>").attr("href",post.url).text(post.title)))
return art
}
function update(){
$("#blog-filtered").empty()
var posts=filter()
_(posts).each(function(p){
$("#blog-filtered").append(article(p))
})
$("h1.entry-title").text(window.filter.des)
}
update()
</script>
18 changes: 18 additions & 0 deletions source/javascripts/queryString.js
@@ -0,0 +1,18 @@
function getParameterByName(name) {
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
results = regex.exec(location.search);
return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}
function buildUrl(url, parameters){
var qs = "";
for(var key in parameters) {
var value = parameters[key];
qs += encodeURIComponent(key) + "=" + encodeURIComponent(value) + "&";
}
if (qs.length > 0){
qs = qs.substring(0, qs.length-1); //chop off last "&"
url = url + "?" + qs;
}
return url;
}

0 comments on commit 3abeab7

Please sign in to comment.