Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 32 additions & 8 deletions static/css/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,14 @@ button.link-button:focus {
}

#scatter-container {
width: 890px;
height: 425px;
width: 100%;
max-width: 890px;
height: 425px; /* Fallback for browsers predating aspect-ratio; see setScatterViewBox in decorate.js, which sets a precise aspect-ratio once the chart's real dimensions are known. */
position: relative;
overflow-x: auto;
}

#scatter-bg,
#scatter-bg,
#scatter-chart {
width: 100%;
height: 100%;
Expand All @@ -105,6 +107,13 @@ button.link-button:focus {
left: 0;
}

#scatter-chart > svg,
#svg-bg {
display: block;
width: 100%;
height: auto;
}

#scatter-chart {
z-index: 10;
}
Expand Down Expand Up @@ -187,6 +196,20 @@ button.link-button:focus {


/* Maps and charts */

/* Scale the scatter plot and map's own SVGs to fit their container
(viewBox is added at render time, see congress.js/voteCharts.js)
instead of overflowing it. Deliberately scoped to just these two --
applying this to every .dc-chart also shrank small sidebar charts
like #party-chart, which don't have a too-wide-for-mobile problem and
were previously rendered at native (legible) size regardless of their
column width. */
#map-chart > svg {
display: block;
width: 100%;
height: auto;
}

.dc-chart g.row text {
fill: black;
}
Expand Down Expand Up @@ -269,11 +292,11 @@ line.cutline {

.tooltip > .tooltip-inner { opacity: 0.9; }
.tooltip > .tooltip-arrow { opacity: 0.9; }
.left-tooltip + .tooltip > .tooltip-inner { text-align:left; min-width:400px;}
.left-tooltip + .tooltip > .tooltip-inner { text-align:left; width:400px; max-width:calc(100vw - 40px); }

#memberList
{
min-width: 800px;
min-width: 0;
}

ul#memberList.geography
Expand Down Expand Up @@ -549,7 +572,7 @@ span.party_header { padding-right: 20px; }
.roster_header { padding-bottom: 20px; }
.roster_header h4 { display:inline; }
#memberList { columns: auto 4; list-style-type: none; overflow: auto; width: 100%; margin-bottom: 60px; }
#memberTextList { margin-bottom: 40px; }
#memberTextList { margin-bottom: 40px; overflow-x: auto; }
.save_icon { margin-left: 5px; font-size: 22px; vertical-align: middle; cursor: pointer; }
#scatter-container { margin: 0 auto 10px auto; }
#filterName { float: right; }
Expand All @@ -568,7 +591,7 @@ span.party_header { padding-right: 20px; }
#geoMap h4 { float: left; clear: none; vertical-align: middle; }
#geoMap .glyphicon-save { margin-left: 5px; font-size: 18px; vertical-align: middle; cursor: pointer; }
#geoMap .noteText { margin-left: 5px; width: 22px; vertical-align: middle; }
#geoMap #map-chart { margin-top: 10px; padding: 10px; vertical-align: bottom; }
#geoMap #map-chart { display: block; margin-top: 10px; padding: 10px; vertical-align: bottom; }
#geoMap #map-chart #zoomIn { position: absolute; left: 25px; top: 40px; width: 30px; height: 30px; }
#geoMap #map-chart #zoomOut { position: absolute; left: 25px; top: 80px; width: 30px; height: 30px; }
#geoMap #map-chart #suppressMapControls { display: none; }
Expand All @@ -586,6 +609,7 @@ span.party_header { padding-right: 20px; }
#selectionFilterBar #sparse-selection { display: none; }
.sortHeader { text-align:middle; padding-top: 3px; }
.voteHeader { font-size: 19px; float: left; padding-right: 30px; text-align: middle; }
.voteListScroll { overflow-x: auto; }
#voteList { margin-top: 15px; width: 100%; min-width: 1100px; }

/* voteTable.js picks 1-4 columns based on how many members are listed
Expand Down Expand Up @@ -704,7 +728,7 @@ h5.congSelector small { padding-left: 10px; }
.bottomPad { padding-bottom: 20px; }
.member_flag { width: 20px; vertical-align: middle; }
.personSearch { padding-top: 10px; padding-bottom: 10px; clear: both; }
.loadVotes { float: right; padding-top: 12px; min-width: 400px; width: 400px; }
.loadVotes { float: right; padding-top: 12px; width: 400px; max-width: 100%; }
.member_vote_load {
position: fixed;
top: 50%;
Expand Down
1 change: 1 addition & 0 deletions static/js/congress.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ function nomPlot()
dc.filterAll();
dc.renderAll();
decorateNominate(nominateScatterChart, resultCache);
setScatterViewBox(nominateScatterChart);

// Make brush box appear on click
var scb = nominateScatterChart.select(".brush");
Expand Down
29 changes: 29 additions & 0 deletions static/js/decorate.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,35 @@
var isDoingSelect=0;
var delayUpdateToolip;

// Give the scatter plot's SVG a viewBox matching its configured drawing
// area, so CSS (#scatter-chart > svg in base.css) can scale the whole
// thing to fit its container instead of overflowing it. decorateNominate's
// own layout (axes, margins, heatmap) is computed directly from the
// chart's width()/height(), so those are exactly its true content bounds
// -- call this after decorateNominate() has run so the viewBox covers the
// decoration too, not just the scatter points dc.js draws on its own.
function setScatterViewBox(chart) {
var svg = chart.svg();
if (!svg || !svg.node() || svg.attr("viewBox")) return;
svg.attr("viewBox", "0 0 " + chart.width() + " " + chart.height())
.attr("preserveAspectRatio", "xMidYMid meet");

// #scatter-container has a fixed height (see base.css) as a fallback
// for browsers without aspect-ratio support. Once we know the chart's
// real width/height, size the container to match that ratio instead,
// so a narrow phone doesn't get a chart that's shrunk to fit its width
// while the container underneath stays at the fixed desktop height,
// leaving a large gap before whatever follows the chart on the page.
var container = document.getElementById("scatter-container");
if (container) {
// aspect-ratio has no effect unless height is allowed to be
// computed from it -- base.css sets a fixed height as a fallback,
// so it has to be relaxed to auto here for the ratio to apply.
container.style.height = "auto";
container.style.aspectRatio = chart.width() + " / " + chart.height();
}
}

/*
Add sponsor circle
*/
Expand Down
31 changes: 31 additions & 0 deletions static/js/voteCharts.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,34 @@ var nominateScatterChart = dc.scatterPlot("#scatter-chart");
var globalPartyDimension = null;
var globalData;

// Give the map's SVG a viewBox matching its actual rendered content
// (the union of all drawn path geometry) rather than mapChart's
// configured width()/height() -- the geo projection doesn't exactly fill
// that nominal canvas (it's inset a bit and slightly overflows the
// right/bottom edges), so using width()/height() directly clipped the
// map's right edge while leaving a blank margin on the left. Call this
// once the map's paths are actually in the DOM.
function setMapContentViewBox(chart, padding) {
var svg = chart.svg();
if (!svg || !svg.node() || svg.attr("viewBox")) return;
padding = (padding === undefined) ? 4 : padding;
var minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
svg.node().querySelectorAll("path").forEach(function(el) {
var b;
try { b = el.getBBox(); } catch(e) { return; }
if (b.width === 0 && b.height === 0) return;
minX = Math.min(minX, b.x);
minY = Math.min(minY, b.y);
maxX = Math.max(maxX, b.x + b.width);
maxY = Math.max(maxY, b.y + b.height);
});
if (!isFinite(minX)) return;
svg.attr("viewBox",
(minX - padding) + " " + (minY - padding) + " " +
(maxX - minX + 2 * padding) + " " + (maxY - minY + 2 * padding))
.attr("preserveAspectRatio", "xMidYMid meet");
}

// Makes the bootstrap tooltip run for votes from before states were contiguous.
$(document).ready(function(){$('[data-toggle="tooltip"]').tooltip();});

Expand Down Expand Up @@ -565,7 +593,9 @@ function drawWidgets(error, data, geodata, usaboundaries)
// We are done defining everything, now let's just run our ancillary functions.
dc.renderAll();
d3.select("div#geoMap > span#map-chart > svg").select("g.layer0").select("g").select("path").attr("opacity", 0.3).attr("stroke", "#666666");
if(!failedMapLoad) setMapContentViewBox(mapChart);
decorateNominate(nominateScatterChart, data);
setScatterViewBox(nominateScatterChart);
addSponsorCircle(nominateScatterChart);
if(!failedMapLoad) mapChart.on("filtered", pollFilters);
votePartyChart.on("filtered", pollFilters);
Expand Down Expand Up @@ -626,5 +656,6 @@ function doFullFilterReset()
dc.redrawAll();
// Re-apply our decoration hack.
decorateNominate(nominateScatterChart, globalData);
setScatterViewBox(nominateScatterChart);
//updateVoteChart();
}
10 changes: 6 additions & 4 deletions views/congress.tpl
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
% STATIC_URL = "/static/"
% import random
% cache_breaker = random.randint(10000, 99999)
% rcSuffix = lambda n: "%d%s" % (n,"tsnrhtdd"[(n//10%10!=1)*(n%10<4)*n%10::4])
% rebase('base.tpl', title='Congress View', extra_css=['map.css', 'scatter.css'], extra_js=["/static/js/libs/saveSvgAsPng.js", "/static/js/libs/jquery.tablesorter.min.js", "/static/js/libs/localStorage.js"])
% include('header.tpl')
Expand Down Expand Up @@ -115,7 +117,7 @@ var tabular_view = 0;
<script type="text/javascript" src="{{ STATIC_URL }}js/libs/crossfilter.min.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/libs/dc.min.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/libs/d3.tip.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/colorMap.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/decorate.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/congress.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/memberTable.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/colorMap.js?t={{cache_breaker}}"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/decorate.js?t={{cache_breaker}}"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/congress.js?t={{cache_breaker}}"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/memberTable.js?t={{cache_breaker}}"></script>
20 changes: 12 additions & 8 deletions views/vote.tpl
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
% STATIC_URL = "/static/"
% import random
% cache_breaker = random.randint(10000, 99999)
% rebase('base.tpl', title=plot_title, extra_css=["map.css","scatter.css", "bootstrap-slider.css"], extra_js=["/static/js/libs/saveSvgAsPng.js", "/static/js/libs/bootstrap-slider.min.js", "/static/js/libs/sticky-kit.min.js", "/static/js/stateMeta.js"])
% include('header.tpl')

Expand Down Expand Up @@ -130,7 +132,9 @@
<button type="button" class="link-button" onclick="javascript:outVotes('prob');return false;">Vote Probability</button>)
</div>
</div>
<div id="voteList"></div>
<div class="voteListScroll">
<div id="voteList"></div>
</div>
</div>
</div>
</div>
Expand Down Expand Up @@ -164,10 +168,10 @@ var nomBeta = {{ nom_beta }};
<script type="text/javascript" src="{{ STATIC_URL }}js/libs/crossfilter.min.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/libs/dc.min.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/libs/topojson.min.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/mapPanZoom.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/decorate.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/colorMap.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/voteCharts.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/voteTable.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/voteFilterbar.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/nominateHeatMap.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/mapPanZoom.js?t={{cache_breaker}}"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/decorate.js?t={{cache_breaker}}"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/colorMap.js?t={{cache_breaker}}"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/voteCharts.js?t={{cache_breaker}}"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/voteTable.js?t={{cache_breaker}}"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/voteFilterbar.js?t={{cache_breaker}}"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/nominateHeatMap.js?t={{cache_breaker}}"></script>