Last active
May 20, 2024 13:50
-
-
Save pm5/11a7caa748e4458420f0 to your computer and use it in GitHub Desktop.
Distribution of questions on wethepeople.tw
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[ | |
{"group_name":"居住", | |
"group_category":["居住","社會住宅","都市更新","土地"]}, | |
{"group_name":"環境", | |
"group_category":["環境","國土安全和賑災","自然資源","核能","能源","氣候變化","農業","土地"]}, | |
{"group_name":"人權", | |
"group_category":["人權","公民權利和自由","婦女","家庭","性別","移民","消費者保護","刑事司法和執法"]}, | |
{"group_name":"制度改革", | |
"group_category":["制度改革","開放政府","創新"]}, | |
{"group_name":"教育", | |
"group_category":["教育","科學與技術"]}, | |
{"group_name":"國防/兩岸", | |
"group_category":["國防","外交政策","兩岸"]}, | |
{"group_name":"勞工", | |
"group_category":["勞工"]}, | |
{"group_name":"經濟/財稅", | |
"group_category":["經濟","創造就業機會","預算和稅收"]}, | |
{"group_name":"社會/醫療", | |
"group_category":["社會保障","醫療","身心障礙","老年人照顧","藝術與人文","運動休閒","貧窮"]}, | |
{"group_name":"其他", | |
"group_category":["交通運輸","基礎建設","通訊","其他"]} | |
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"/> | |
<title>Distribution of questions on wethepeople.tw</title> | |
<script src="//d3js.org/d3.v3.min.js"></script> | |
<script src="//cdn.firebase.com/v0/firebase.js"></script> | |
</head> | |
<body> | |
<div id="chart"></div> | |
<script> | |
function chart() { | |
var width = 800, | |
height = 400, | |
margin = { top: 20, right: 30, bottom: 120, left: 30 }; | |
var firebase = new Firebase('https://askkkkk.firebaseio.com/'); | |
var xScale = d3.scale.linear().range([0, width]); | |
var yScale = d3.scale.linear().range([0, height]); | |
yScale.revert = function () { | |
return yScale.copy().range([yScale.range()[1], yScale.range()[0]]); | |
}; | |
var yAxis = d3.svg.axis() | |
.orient("left") | |
.ticks(10); | |
var xPosition = { | |
start: function (d, i) { return xScale(i) + xScale(1) * 0.25; }, | |
middle: function (d, i) { return xScale(i) + xScale(1) * 0.5; }, | |
end: function (d, i) { return xScale(i) + xScale(1) * 0.75; }, | |
width: function (d, i) { return xScale(1) * 0.5; } | |
}; | |
var yPosition = { | |
totalHeight: function (d) { return yScale(d.total); }, | |
collectingHeight: function (d) { return yScale(d.collecting); }, | |
collectingStart: function (d) { return yPosition.barStart(d) + yPosition.passedHeight(d); }, | |
passedHeight: function (d) { return yScale(d.passed); }, | |
passedStart: function (d) { return yPosition.barStart(d); }, | |
endedHeight: function (d) { return yScale(d.ended); }, | |
endedStart: function (d) { return yPosition.barStart(d) + yPosition.passedHeight(d) + yPosition.collectingHeight(d); }, | |
barStart: function (d) { return height - yScale(d.total); }, | |
textStart: function () { return height + 12; }, | |
}; | |
function yLabel(selection) { | |
return selection.append("text") | |
.text("提案數"); | |
} | |
function dateLabel(selection) { | |
var d = new Date(); | |
return selection.append("text") | |
.text(d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate()); | |
} | |
function askkk_tooltip(selection) { | |
var tooltip = selection.append("div") | |
.attr("class", "tooltip hidden"); | |
tooltip.show = function (d, i) { | |
tooltip.html("<h4>" + d.name + "</h4>\n<p>已通過:" + d.passed + "<br>集氣中:" + d.collecting + "<br>已結束:" + d.ended + "<br>總數:" + d.total + "</p>") | |
.style("left", margin.left + xPosition.end(d, i) + "px") | |
.style("top", height - 120 + "px") | |
.classed("hidden", false); | |
} | |
tooltip.hide = function (d, i) { | |
tooltip.classed("hidden", true); | |
} | |
return tooltip; | |
} | |
function draw(selection) { | |
var svg = selection.append("svg") | |
.attr("width", width + margin.left + margin.right) | |
.attr("height", height + margin.top + margin.bottom) | |
.append("g") | |
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
var tooltip = askkk_tooltip(selection); | |
d3.json("categories.json", function (categories) { | |
var catData = {}; | |
categories.forEach(function (group) { | |
group.group_category.forEach(function (cat) { | |
catData[cat] = { | |
passed: 0, | |
ended: 0, | |
collecting: 0 | |
}; | |
}); | |
}); | |
function loadQuestion(snap) { | |
if (! snap.val().category) { | |
return; | |
} | |
if (snap.val().state.passed) { | |
snap.val().category.forEach(function (cat) { | |
catData[cat].passed++; | |
}); | |
} else if (snap.val().state.ended) { | |
snap.val().category.forEach(function (cat) { | |
catData[cat].ended++; | |
}); | |
} else { | |
snap.val().category.forEach(function (cat) { | |
catData[cat].collecting++; | |
}); | |
} | |
} | |
function exportData() { | |
var data = []; | |
for (var cat in catData) { | |
data.push({ | |
name: cat, | |
total: catData[cat].collecting + catData[cat].passed + catData[cat].ended, | |
collecting: catData[cat].collecting, | |
passed: catData[cat].passed, | |
ended: catData[cat].ended, | |
}); | |
} | |
return data.sort(function (a, b) { return b.total - a.total; }); | |
} | |
firebase.child('questions').on('child_added', loadQuestion); | |
firebase.child('questions').once('value', function (snap) { | |
var data = exportData(); | |
xScale.domain([0, data.length]); | |
yScale.domain([0, d3.max(data, function (d) { return d.total; }) * 1.2]); | |
yAxis.scale(yScale.revert()); | |
var bar = svg.selectAll("g.bar") | |
.data(data) | |
.enter().append("g") | |
.attr("class", "bar") | |
.attr("transform", function (d, i) { return "translate(" + xPosition.start(d, i) + ",0)"; }) | |
.on("mouseover", tooltip.show) | |
.on("mouseout", tooltip.hide); | |
bar.append("rect") | |
.attr("class", "passed") | |
.attr("width", xPosition.width) | |
.attr("height", yPosition.passedHeight) | |
.attr("y", yPosition.passedStart); | |
bar.append("rect") | |
.attr("class", "collecting") | |
.attr("width", xPosition.width) | |
.attr("height", yPosition.collectingHeight) | |
.attr("y", yPosition.collectingStart); | |
bar.append("rect") | |
.attr("class", "ended") | |
.attr("width", xPosition.width) | |
.attr("height", yPosition.endedHeight) | |
.attr("y", yPosition.endedStart); | |
bar.append("text") | |
.text(function (d) { return d.name; }) | |
.attr("transform", function (d, i) { return "translate(" + (xPosition.width() * 0.5 - 4) + "," + yPosition.textStart(d, i) + ")rotate(70)"; }); | |
svg.append("g") | |
.attr("class", "y axis") | |
.call(yAxis); | |
svg.append("g") | |
.attr("class", "y label") | |
.attr("transform", "translate(6,8)rotate(90)") | |
.call(yLabel); | |
svg.append("g") | |
.attr("class", "date label") | |
.attr("transform", "translate(" + (width - 40) + ",12)") | |
.call(dateLabel); | |
}); | |
}); | |
} | |
draw.width = function (value) { | |
if (!arguments.length) return width; | |
width = value; | |
return draw; | |
} | |
draw.height = function (value) { | |
if (!arguments.length) return value; | |
height = value; | |
return draw; | |
} | |
return draw; | |
} | |
var chart = chart(); | |
d3.select("#chart") | |
.call(chart); | |
</script> | |
<style> | |
#chart g.bar rect { | |
shape-rendering: crispEdges; | |
} | |
#chart g.bar rect.passed { | |
fill: #43a2ca; | |
} | |
#chart g.bar rect.collecting { | |
fill: #a8ddb5; | |
} | |
#chart g.bar rect.ended { | |
fill: darkgray; | |
} | |
#chart g.bar text { | |
text-anchor: start; | |
} | |
#chart .axis text, | |
#chart .label text { | |
font: 10px sans-serif; | |
} | |
.axis path, | |
.axis line { | |
fill: none; | |
stroke: #000; | |
shape-rendering: crispEdges; | |
} | |
.x.axis path { | |
display: none; | |
} | |
.tooltip { | |
position: absolute; | |
width: 180px; | |
height: auto; | |
padding: 10px; | |
background-color: white; | |
-webkit-border-radius: 10px; | |
-moz-border-radius: 10px; | |
border-radius: 10px; | |
-webkit-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4); | |
-moz-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4); | |
box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4); | |
pointer-events: none; | |
} | |
.tooltip.hidden { | |
display: none; | |
} | |
.tooltip p { | |
margin: 0; | |
font-family: sans-serif; | |
font-size: 16px; | |
line-height: 20px; | |
} | |
</style> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment