!(function(){ var tPrs = d3.timeParse("%Y年%m月%d日"); var dateStart = new Date(1889, 1, 1); var dateEnd = new Date(2019, 1, 1); var index = { election: 0, wareki: 1, event: 2, seats: "比較第一党議席率", vote: "投票率" }; var chartMargin = { top: 60, left: 40, bottom: 120, right: 20 }; d3 .queue() .defer(d3.tsv, "election.tsv") .defer(d3.tsv, "wareki.tsv") .defer(d3.tsv, "event.tsv") .awaitAll(main); function main(error, data) { data[index.election].forEach(castNumber); data[index.wareki].forEach(castNumber); data[index.event].forEach(castNumber); data[index.election].forEach(castElectionData); data[index.wareki].forEach(castDate); data[index.event].forEach(castDate); var stage = d3.select("#stage").datum(data); var addVotePinhead = createPinhead(index.vote); var addSeatsPinhead = createPinhead(index.seats); stage .call(initStage) .call(initScale) .call(addLegend) .call(addYAxis) .call(addXAxis) .call(addPinNeck) .call(addVotePinhead) .call(addSeatsPinhead) .call(addWareki) .call(addPointEvent) .call(addRangeEvent) .call(addAdministration) .call(addZoom); } function castNumber(d) { Object.keys(d).forEach(function(key) { if (!isNaN(+d[key])) d[key] = +d[key]; }); } function castDate(d) { d.sdate = tPrs(d.sdate); d.edate = tPrs(d.edate); } function castElectionData(d) { var dateObje = tPrs(d["投票年"] + d["投票日"]); var adminEndDate = tPrs(d["任期満了西暦"] + d["任期満了日"]); d.sdate = dateObje; d.edate = adminEndDate ? adminEndDate : null; } function initStage(_selection) { var svg = _selection.append("svg"); var clipRect = svg .append("defs") .append("clipPath") .attr("id", "clip") .append("rect"); var legendLayer = svg.append("g").classed("legendLayer", true); var axisLayer = svg.append("g").classed("axisLayer", true); var charLayer = svg.append("g").classed("chartLayer", true); var parentNode = _selection.node(); var parentWidth = parentNode.clientWidth; var parentHeight = parentNode.clientHeight; var chartWidth = parentWidth - (chartMargin.left + chartMargin.right); var chartHeight = parentHeight - (chartMargin.top + chartMargin.bottom); svg.attr("width", parentWidth).attr("height", parentHeight); clipRect.attr("width", chartWidth).attr("height", parentHeight); axisLayer .attr("width", chartWidth) .attr("height", chartHeight) .attr( "transform", "translate(" + [chartMargin.left, chartMargin.top] + ")" ); charLayer .attr("width", chartWidth) .attr("height", chartHeight) .attr("transform", "translate(" + [chartMargin.left, chartMargin.top] + ")") .attr("clip-path", "url(#clip)"); } function initScale(_selection) { var chartWidth = _selection.select(".chartLayer").attr("width"); var chartHeight = _selection.select(".chartLayer").attr("height"); var xScale = d3 .scaleTime() .domain([dateStart, dateEnd]) .range([0, chartWidth]); var yScale = d3 .scaleLinear() .domain([0, 100]) .range([chartHeight, 0]); _selection._xScale = xScale; _selection._yScale = yScale; } function addLegend(_selection) { var legendLayer = _selection.select(".legendLayer"); var g = legendLayer .selectAll("g") .data([index.vote, index.seats]) .enter() .append("g") .attr("transform", function(d, i) { return ( "translate(" + [chartMargin.left + i * 80, chartMargin.top / 2] + ")" ); }); g .append("circle") .attr("r", 5.5) .attr("y", -4) .attr("class", function(d) { return d; }); g .append("text") .attr("class", "legendLabel") .attr("dominant-baseline", "middle") .attr("x", 6 + 3) .text(function(d) { return d; }); } function addZoom(_selection) { var xScale = _selection._xScale; var yScale = _selection._yScale; var chartWidth = _selection.select(".chartLayer").attr("width"); var zoom = d3 .zoom() .scaleExtent([1, 32]) .on("zoom", zoomed); zoom .translateExtent([[0, 0], [chartWidth, 0]]) .extent([[0, 0], [chartWidth, 0]]); _selection .select("svg") .call(zoom) .transition() .duration(1500) .call( zoom.transform, d3.zoomIdentity .scale(chartWidth / (xScale(dateEnd) - xScale(dateStart))) .translate(xScale(dateStart), 0) ); function zoomed() { var t = d3.event.transform; var xt = t.rescaleX(xScale); _selection._xScale = xt; _selection._update(); } } function addXAxis(_selection) { var axisLayer = _selection.select(".axisLayer"); var g = axisLayer.append("g").attr("class", "axis--x"); var height = axisLayer.attr("height"); _selection._xAxis = d3.axisTop(_selection._xScale); g.attr("transform", "translate(" + [0, 0] + ")"); g.call(_selection._xAxis); g.selectAll(".domain").style("display", "none"); var update = function() { var t = d3.event.transform; var tFmt = d3.timeFormat("%Y-%m"); if (t.k < 30) tFmt = d3.timeFormat("%Y"); _selection._xAxis.scale(_selection._xScale).tickFormat(function(d) { return tFmt(d); }); g.call(_selection._xAxis); }; bindUpdate(_selection, update); } function addYAxis(_selection) { var axisLayer = _selection.select(".axisLayer"); var g = axisLayer.append("g").attr("class", "axis--y"); var width = axisLayer.attr("width"); _selection._yAxis = d3 .axisLeft(_selection._yScale) .tickSizeOuter(0) .tickSizeInner(-width) .tickValues([30, 50, 70]) .tickFormat(function(d) { return d + "%"; }); g.attr("transform", "translate(" + [0, 0] + ")"); g.call(_selection._yAxis); g.selectAll(".domain").style("display", "none"); } function createPinhead(_index) { return function(_selection) { var data = _selection.datum(); var election = data[index.election]; var chartLayer = _selection.select(".chartLayer"); var pinChart = chartLayer.selectAll(".pinChart").data([election]); var enterPinChart = pinChart .enter() .append("g") .classed("pinChart", true); var g = d3 .select(".pinChart") .append("g") .attr("class", "heads " + _index); var chartHeight = chartLayer.attr("height"); var yProp = function(d) { return _selection._yScale(d[_index]); }; var hFn = function(d) { return chartHeight - yProp(d); }; var yFn = function(d) { return yProp(d); }; var neckWidth = 1; var selectHeads = g.selectAll("circle").data(function(d) { return d; }); var enterHeads = selectHeads.enter().append("circle"); //.style("opacity", 0); var heads = selectHeads .merge(enterHeads) .attr("r", 6) .attr("cy", yFn); heads .transition() .duration(1000) .delay(function(d, i) { return i * 100; }) .style("opacity", 1); var update = function() { heads.attr("cx", function(d) { return _selection._xScale(d.sdate); }); }; bindUpdate(_selection, update); }; } function addPinNeck(_selection) { var data = _selection.datum(); var election = data[index.election]; var chartLayer = _selection.select(".chartLayer"); var pinChart = chartLayer.selectAll(".pinChart").data([election]); var enterPinChart = pinChart .enter() .append("g") .classed("pinChart", true); d3 .select(".pinChart") .append("g") .attr("class", "necks"); var neckWidth = 1; var chartHeight = chartLayer.attr("height"); var voteProp = function(d) { return +_selection._yScale(d[index.vote]); }; var seatsProp = function(d) { return +_selection._yScale(d[index.seats]); }; var yFn = function(d) { var extent = d3.extent([voteProp(d), seatsProp(d)]); return extent[0]; }; var hFn = function(d) { var extent = d3.extent([voteProp(d), seatsProp(d)]); return extent[1] - extent[0]; }; var selectNecks = pinChart .merge(enterPinChart) .select(".necks") .selectAll(".neck") .data(function(d) { return d; }); var enterNecks = selectNecks .enter() .append("rect") .attr("class", "neck"); //.style("opacity", 0); var necks = selectNecks .merge(enterNecks) .attr("width", neckWidth) .attr("height", hFn) .attr("y", yFn); necks .transition() .duration(1000) .delay(function(d, i) { return i * 100; }) .style("opacity", 1); var update = function() { necks.attr("x", function(d) { return _selection._xScale(d.sdate) - neckWidth / 2; }); }; bindUpdate(_selection, update); } function addWareki(_selection) { var chartLayer = _selection.select(".chartLayer"); var chartHeight = chartLayer.attr("height"); var chartWidth = chartLayer.attr("width"); var Y = 0; var data = _selection.datum(); var wareki = data[index.wareki]; var chartLayer = _selection.select(".chartLayer"); var g = chartLayer.append("g").attr("class", "warekiLayer"); var line = g .selectAll(".warekiLine") .data(wareki) .enter() .append("path") .attr("class", "warekiLine") .attr("stroke", "black") .attr("fill", "none"); var pathGen = function(d) { var sx = _selection._xScale(d.sdate); var ex = d.edate == null ? chartWidth : _selection._xScale(d.edate); var str = "M "; str += [sx, Y].join(" "); str += "L "; str += [ex, Y].join(" "); if (d.edate) { str += "L "; str += [ex, Y + 12].join(" "); } return str; }; var label = g .selectAll(".warekiLabel") .data(wareki) .enter() .append("text") .attr("class", "warekiLabel") .attr("text-anchor", "middle") .attr("y", 12); var labelGen = function(d) { var sx = _selection._xScale(d.sdate); return "translate(" + [sx, Y] + ")"; }; var labelDx = function(d) { var sx = _selection._xScale(d.sdate); var ex = d.edate == null ? chartWidth : _selection._xScale(d.edate); var center = (ex - sx) / 2; return center; }; var update = function() { line.attr("d", pathGen); label .attr("transform", labelGen) .attr("x", labelDx) .text(function(d) { return d["name"]; }); }; bindUpdate(_selection, update); } function addPointEvent(_selection) { var chartLayer = _selection.select(".chartLayer"); var Y = chartLayer.attr("height") ; var data = _selection.datum(); var event = data[index.event]; var eventPoint = event.filter(function(d) { return d.edate == null; }); var g = chartLayer.append("g").attr("class", "pointEventLayer"); var circle = g .selectAll(".pointEventLayer") .data(eventPoint) .enter() .append("circle") .attr("class", "eventCircle") .attr("r", 2) .attr("cy", function(d) { return d.paragraph; }); var circleGen = function(d) { var sx = _selection._xScale(d.sdate); return "translate(" + [sx, Y] + ")"; }; var label = g .selectAll(".eventiLabel") .data(eventPoint) .enter() .append("text") .attr("class", "eventLabel") .attr("dominant-baseline", "middle") .attr("text-anchor", "start") .attr("x", 6) .attr("y", function(d, i) { return d.paragraph; }); var labelGen = function(d) { var sx = _selection._xScale(d.sdate); return "translate(" + [sx, Y] + ")"; }; var update = function() { circle.attr("transform", circleGen); label.attr("transform", labelGen).text(function(d) { return d["event"]; }); }; bindUpdate(_selection, update); } function addRangeEvent(_selection) { var chartLayer = _selection.select(".chartLayer"); var Y = chartLayer.attr("height") - 42; var data = _selection.datum(); var event = data[index.event]; var eventRange = event.filter(function(d) { return d.edate != null; }); var g = chartLayer.append("g").attr("class", "rangeEventLayer"); var line = g .selectAll(".warekiLine") .data(eventRange) .enter() .append("path") .attr("class", "warekiLine") .attr("stroke", "black") .attr("fill", "none"); var pathGen = function(d, i) { var sx = _selection._xScale(d.sdate); var ex = _selection._xScale(d.edate); var str = "M "; var y = Y + d.paragraph; str += [sx, y].join(" "); str += "L "; str += [ex, y].join(" "); return str; }; var sCircle = g .selectAll(".eventSCircle") .data(eventRange) .enter() .append("circle") .attr("class", "eventSCircle") .attr("r", 2); var eCircle = g .selectAll(".eventECircle") .data(eventRange) .enter() .append("circle") .attr("class", "eventECircle") .attr("r", 2); var sCircleGen = function(d) { var sx = _selection._xScale(d.sdate); var y = Y + d.paragraph; return "translate(" + [sx, y] + ")"; }; var eCircleGen = function(d, i) { var sx = _selection._xScale(d.edate); var y = Y + d.paragraph; return "translate(" + [sx, y] + ")"; }; var label = g .selectAll(".eventLabel") .data(eventRange) .enter() .append("text") .attr("class", "eventLabel") .attr("text-anchor", "middle") .attr("y", 12); var labelGen = function(d, i) { var sx = _selection._xScale(d.sdate); var y = Y + d.paragraph; return "translate(" + [sx, y] + ")"; }; var labelDx = function(d) { var sx = _selection._xScale(d.sdate); var ex = _selection._xScale(d.edate); var center = (ex - sx) / 2; return center; }; var update = function() { line.attr("d", pathGen); sCircle.attr("transform", sCircleGen); eCircle.attr("transform", eCircleGen); label .attr("transform", labelGen) .attr("x", labelDx) .text(function(d) { return d["event"]; }); }; bindUpdate(_selection, update); } function addAdministration(_selection) { var chartLayer = _selection.select(".chartLayer"); var Y = chartLayer.attr("height") - 60; var data = _selection.datum(); var election = data[index.election]; var g = chartLayer.append("g").attr("class", "adminLayer"); var line = g .selectAll(".adminLine") .data(election) .enter() .append("path") .attr("class", "adminLine") .attr("stroke", "black") .attr("fill", "none"); var pathGen = function(d) { var sx = _selection._xScale(d.sdate); var ex = _selection._xScale(d.edate); var str = "M "; str += [sx, Y - 10].join(" "); str += "L "; str += [sx, Y].join(" "); str += "L "; str += [ex, Y].join(" "); str += "L "; str += [ex, Y - 10].join(" "); return str; }; var label = g .selectAll(".adminLabel") .data(election) .enter() .append("text") .attr("class", "adminLabel") .attr("text-anchor", "middle") .attr("y", 12); var labelGen = function(d) { var sx = _selection._xScale(d.sdate); return "translate(" + [sx, Y] + ")"; }; var labelDx = function(d) { var sx = _selection._xScale(d.sdate); var ex = _selection._xScale(d.edate); var center = (ex - sx) / 2; return center; }; var update = function() { var t = d3.event.transform; line.attr("d", pathGen); label .attr("transform", labelGen) .attr("x", labelDx) .text(function(d) { if (t.k > 3) return d["内閣"]; }); }; bindUpdate(_selection, update); } function bindUpdate(_selection, update) { if (!_selection._updateFanctions) _selection._updateFanctions = []; _selection._updateFanctions.push(update); _selection._update = function(data) { _selection._updateFanctions.forEach(function(f) { f(data); }); }; } }());