Skip to content

Instantly share code, notes, and snippets.

@pm5
Last active May 20, 2024 13:50
Show Gist options
  • Save pm5/11a7caa748e4458420f0 to your computer and use it in GitHub Desktop.
Save pm5/11a7caa748e4458420f0 to your computer and use it in GitHub Desktop.
Distribution of questions on wethepeople.tw

Distribution of questions on wethepeople.tw

[
{"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":["交通運輸","基礎建設","通訊","其他"]}
]
<!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