File size: 4,505 Bytes
19a0974
16c3ef4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6660f26
16c3ef4
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/* Coffermap national page. © 2026 CyberMax. All rights reserved. */
(function () {
  'use strict';
  var $ = function (id) { return document.getElementById(id); };
  var esc = function (s) { return String(s == null ? '' : s).replace(/[&<>"']/g, function (c) { return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]; }); };
  var states = [], counties = [], names = {}, sortS = { k: 'contracts', d: true }, sortC = { k: 'contracts', d: true }, shown = 100;

  function tab(t) { $('tab-s').classList.toggle('on', t === 's'); $('tab-c').classList.toggle('on', t === 'c'); $('p-s').hidden = t !== 's'; $('p-c').hidden = t !== 'c'; }
  $('tab-s').onclick = function () { tab('s'); };
  $('tab-c').onclick = function () { tab('c'); renderC(); };

  function renderS() {
    var max = Math.max.apply(null, states.map(function (s) { return s.contracts; }));
    $('st').tBodies[0].innerHTML = FF.sortBy(states, sortS.k, sortS.d).map(function (s) {
      return '<tr><td><a href="state/' + s.state.toLowerCase() + '.html">' + esc(s.name) + '</a><div class="bar" style="width:' + Math.max(1, Math.round(100 * s.contracts / max)) + '%"></div></td><td class="num">' + FF.money(s.contracts) + '</td><td class="num">' + FF.money(s.grants) + '</td><td class="num">' + (s.perCapita == null ? '' : FF.dollars(s.perCapita)) + '</td><td class="num">' + (s.population || 0).toLocaleString('en-US') + '</td></tr>';
    }).join('');
  }
  function current() { return FF.sortBy(FF.filterCounties(counties, $('q').value, $('fst').value), sortC.k, sortC.d); }
  function renderC() {
    var list = current();
    $('ccount').textContent = list.length.toLocaleString('en-US') + ' counties' + (list.length > shown ? ' · showing ' + shown : '');
    $('ct').tBodies[0].innerHTML = list.slice(0, shown).map(function (c) {
      return '<tr><td><a href="state/' + c.state.toLowerCase() + '.html">' + esc(c.county) + '</a></td><td>' + esc(c.state) + '</td><td class="num">' + FF.money(c.contracts) + '</td><td class="num">' + FF.money(c.grants) + '</td><td class="num">' + (c.perCapita == null ? '' : FF.dollars(c.perCapita)) + '</td></tr>';
    }).join('');
    $('more').hidden = list.length <= shown;
  }
  function sorter(tableId, state, render) {
    document.querySelectorAll('#' + tableId + ' th[data-k]').forEach(function (th) {
      th.style.cursor = 'pointer';
      th.onclick = function () { var k = th.dataset.k; state.d = state.k === k ? !state.d : k !== 'name' && k !== 'county' && k !== 'state'; state.k = k; render(); };
    });
  }
  sorter('st', sortS, renderS);
  sorter('ct', sortC, renderC);
  ['q', 'fst'].forEach(function (id) { $(id).addEventListener('input', function () { shown = 100; renderC(); }); });
  $('more').onclick = function () { shown += 200; renderC(); };
  $('csv').onclick = function () {
    var rows = current().map(function (c) { return { fips: c.fips, county: c.county, state: c.state, contracts_usd: c.contracts, grants_usd: c.grants, population: c.population }; });
    var a = document.createElement('a');
    a.href = URL.createObjectURL(new Blob([FF.toCsv(rows, ['fips', 'county', 'state', 'contracts_usd', 'grants_usd', 'population'])], { type: 'text/csv' }));
    a.download = 'coffermap-counties.csv'; document.body.appendChild(a); a.click(); a.remove();
  };

  fetch('data.json').then(function (r) { return r.json(); }).then(function (d) {
    states = d.states.map(FF.state); counties = d.counties.map(FF.county);
    states.forEach(function (s) { names[s.state] = s.name; });
    var m = d.meta;
    $('built').textContent = 'Fiscal year ' + m.fiscal_year + ' (' + m.window.start_date + ' to ' + m.window.end_date + '), built ' + m.built + '.';
    $('stats').innerHTML = [[FF.money(m.contracts_usd), 'federal contracts, FY' + m.fiscal_year], [FF.money(m.grants_usd), 'federal grants, FY' + m.fiscal_year], [m.counties.toLocaleString('en-US'), 'counties with awards'], [m.top_county, 'top county for contract dollars']]
      .map(function (s) { return '<div class="stat"><b>' + esc(s[0]) + '</b><span>' + esc(s[1]) + '</span></div>'; }).join('');
    $('fst').innerHTML = '<option value="">All states</option>' + FF.sortBy(states, 'name').map(function (s) { return '<option value="' + s.state + '">' + esc(s.name) + '</option>'; }).join('');
    renderS();
    if (location.hash === '#counties') { tab('c'); renderC(); }
  }).catch(function () { $('stats').innerHTML = '<p class="msg bad">Could not load the data. Reload the page.</p>'; });
})();