legislature-tracker
legislature-tracker copied to clipboard
An application that pulls in Open States data and combines with editorial expertise to create a live view into a state legislature session.
State Legislature/Bill Tracker
Using editorial expertise and the Sunlight Lab's Open States API, this application creates a curated view of what is going on in a state's legislature session.
It combines data from Open States and editorial data collected with Google Docs. You can see some examples at minnpost.github.io/legislature-tracker.
Examples out in the wild
- MinnPost 2013 Tracker
- New York World 2013 Tracker
- Code for Miama FL Tracker
- Missouri Tracker via St. Louis Beacon and St. Louis Public Radio.
- Oklahoma Tracker from OK Policy.
Installation and configuration
This is a frontend application. It is meant to be used as a library; it is not suggested that you fork this repository unless you need to fix a bug or alter the code. It is recommended that you install the code with Bower:
bower install legislature-tracker
Include the relevant .js
and .css
files found in the dist
folder in your HTML page. The .libs.js
is included for convenience but you can include the dependencies from the bower
folder as well. The application also supports module loading with RequireJS, AMD, or Browserify.
Initialize the tracker with the following:
var app = new LT({
el: '.container-for-leg-tracker',
OSKey: 'open-states-key-here',
eKey: 'google-spreadsheet-key-here',
state: 'MN',
session: '2013-2014',
// more options see below ...
});
Options
When creating a new Legislature Tracker object, you can set the following options. All default options are in js/app.js
.
Required options
The following are required for the application to work correctly
-
el
: The element selector that will hold the application. This can be a CSS selector or jQuery object. -
state
: The two character state code as used by Open States. -
session
: The session key as used on Open States, like'2013-2014'
. -
OSKey
: Your Open States API Key. You can get one at services.sunlightlabs.com. -
eKey
: Your Google Spreadsheet identifier. Be sure to publish your spreadsheet (File -> Publish to the web) to make it available via the Google Spreadsheet API.
Common options
The following are common options you may want to override.
-
conferenceBill
: This should be true or false whether to enable the handling of conference bills. A conference bill is a third bill (other than the primary or companion) that is used often when the two bills are diverging significantly. -
recentImage
: The name of the image file to use for the recent category. Make blank to not have an image for the recent category. -
recentChangeThreshold
: The number of days to determine if a bill will be put in the recent category. The default is7
days. -
imagePath
: The place to find images. This path is simply prepended to images and should have a trailing slash. For instance'https://example.com/images/'
, or'./images/'
. To customize images, the ideal is to copy the images found incss/images/
to your new directory and add or replace images as needed.
Hook options
These are functions that are called during processing to allow for you to override data and other functionality. Do note that if you alter certain data, you may break things.
osBillParse
: A function that is called when parsing open states bill data. It passes the data at the pointer after it has been fetched from Open States and after the model parsing, but before it is loaded into the model. For, instance, this adds text names to sources:
osBillParse: function(billData, app) {
billData.sources = _.map(billData.sources, function(s, si) {
s.text = 'SOURCE [' + si + ']';
return s;
});
return billData;
},
Label translations
To override the naming of certain things, like labels, you can update the the translations config object. The wordTranslations
is just another options; the following are the defaults:
wordTranslations: {
chamber: {
'upper': 'Senate',
'lower': 'House'
},
partyAbbr: {
'Democratic-Farmer-Labor': 'DFL',
'Democratic': 'D',
'Republican': 'R'
},
sponsors: {
'Primary sponsors': 'Primary sponsors',
'primary sponsors': 'primary sponsors',
'Primary sponsor': 'Primary sponsor',
'primary sponsor': 'primary sponsor',
'Co-sponsors': 'Co-sponsors',
'co-sponsors': 'co-sponsors',
'Co-sponsor': 'Co-sponsor',
'co-sponsor': 'co-sponsor'
}
},
Advanced options
These options are set the same as basic options, but their default setting will work fine for most users.
-
chamberLabel
: Whenfalse
, the default, the label for the primary and companion bills will be Primary and Companion, respectively. When set totrue
the labels will be based on the bill's chambers. -
legImageProxy
: If you want to proxy images from Open States, use an URL prefix, like'http://proxy.com/?url='
. For instance MinnPost made this custom proxy. -
maxBills
: By default,30
; the maximum number of bills that will be loaded from your Google Spreadsheet. Since each bill requires a call to OpenStates, your app may become slow if you raise this (especially on slow connections and/or older browsers). -
tabletopOptions
: An object to override any of the Tabletop.js options. -
fieldTranslations
: An object that translates the field names coming in from Tabletop into the field names that the Legislature Tracker expects them as. Seejs/app.js
for defaults. -
aggregateURL
: An API JSON feed to get some aggregate bill counts. This is specific to MinnPost (MN) and is NOT fully supported at the moment. -
billNumberFormat
: A regex for detecting if a bill number is valid for your state. The default,/[A-Z]+ [1-9][0-9]*/
works well for most states, matching bill numbers likeH 1234
,S 1234
orSB 1234
. -
substituteMatch
: Some legislatures will substitute the companion bill, meaning it gets dropped and the primary bill is only used. This option sets the regular expression to match actions to determine if it substituted. Define asfalse
to turn off completely. -
detectCompanionBill
: A function or a regular expression to parse OpenStates' companion bill IDs into a bill number for automatically pairing bills with their companions in the other chamber. For regex, it will use the first match group. The default regex,/([A-Z]+ [1-9][0-9]*)$/
, will find valid bills at the end of the string. If false, Legislature Tracker will not attempt to find companion bills. -
stickMenu
: True or false whether the top menu will stick to the window when scrolling. Default istrue
. -
scollFocus
: True or false whether the window will scroll to the top of the application when a new page is loaded. Default istrue
. -
scollFocusOffset
: The number of pixels to offset when scroll focus is called; a negative number is more towards the top of the page. Default is-15
. -
scollFocusTime
: The amount in milliseconds that animation to scroll focus takes. Default is500
.
Google spreadsheets setup
The name and letter case of the columns and worksheets are important. See this spreadsheet for an example. There are options to change the column name mapping, but this is not well supported yet.
First make sure you have 3 sheets with the following columns:
-
Categories
-
category_id
: the identifier that will be used in URL linking. Should be something likesocial_issues
. -
title
: The text title. -
short_title
: Used for the top menu list. If none is given, the first word from the category title will be used. -
description
: The full description. Feel free to use HTML here, but do note that the content will be wrapped in a paragragh tag. -
links
: Links field, see below. -
image
: Name of image for the category. By default, these pull from the images directory, which is configurable in theimagePath
option. Or if you use a full URL, starting withhttp
it will use that directly.
-
-
Bills
-
bill
: The primary bill name, likeSF 789
. This should be formatted likeA 1234
with a space between the letter/chamber-appreviation and the number which should have no leading zeros. -
companion_bill
-
conference_bill
-
categories
: Category IDs separated by commas. -
title
-
description
: Descriptions get split up when in the category list view and have a "more details" link. By default, this is based on the number of words. To handle longer texts with HTML, you can use<!-- break -->
to define that break point. Also note that is no description is given, then the application will use the primary bill summary which may or may not be useful and significant. -
links
: Links field, see below.
-
-
Events
: Events are custom events like the stalling of a bill or committee that would otherwise not show up in the data from Open States. This shows up as part of the overall editorial bill information below the description.-
bill
: The primary bill ID. -
date
: A date in a format like'YYYY-MM-DD'
-
chamber
: This should beupper
orlower
. -
description
: A short description for the event. Feel free to use HTML here for things like links.
-
Link field formatting
There are a few fields that are a list of links. You should use this format so that they are parsed correctly. Do note that the parser is pretty rudimentary so don't expect much.
"Link text title|http://www.example.com/123", "Another link text title|http://www.example.com/154"
Changing the look
All styling is provided with CSS. The CSS with the application is a bit specific, so be sure to know how CSS specificity works. If you must, you can override the output as well.
Overriding templates
You can override the HTML templates that are used in the application and change wording as well as any HTML output. Templates are using Ractive. You can see the current templates in the js/templates/
directory. The templates are managed in the LT.LT.templates
object. It is suggested to copy the template and then make alterations from there. For instance:
LT.templates['template-ebill'] = 'Your template content here';
How does your legislature work?
The Open States data is very good structured data about bills, but it is basic data that does not account for the subtleties of how legislatures work.
The Legislature tracker tries to take these subtleties into account, but may not be good enough for your legislature. Please open an issue in the queue to discuss how to address other use cases. This is currently handling the following:
- Companion bills can be manually designated, or if not provided, the system will try to read the Open States companion bill that is designated.
- When both primary and companion bills pass, but there are difference to reconcile, there is often a conference bill.
- Sometimes a companion bill will get substituted, meaning it gets dropped and the primary bill is only used.
- Some legislatures will not assign a bill right away even though it is known that it is being discussed. If there is no primary bill provided, a bill will be "stubbed" out in the interface.
Development
Prerequisites
All commands are assumed to be on the command line, often called the Terminal, unless otherwise noted. The following will install technologies needed for the other steps and will only needed to be run once on your computer so there is a good chance you already have these technologies on your computer.
- Install Git.
- On a Mac, install Homebrew, then do:
brew install git
- On a Mac, install Homebrew, then do:
- Install NodeJS.
- On a Mac, do:
brew install node
- On a Mac, do:
- Install Grunt:
npm install -g grunt-cli
- Install Bower:
npm install -g bower
- Install Ruby, though it is probably already installed on your system.
- Install Bundler:
gem install bundler
- Install Sass:
gem install sass
- On a Mac do:
sudo gem install sass
- On a Mac do:
- Install Compass:
gem install compass
- On a Mac do:
sudo gem install compass
- On a Mac do:
Get code and install packages
Get the code for this project and install the necessary dependency libraries and packages.
- Check out this code with Git:
git clone https://github.com/MinnPost/legislature-tracker.git
- Go into the code directory:
cd legislature-tracker
- Install NodeJS packages:
npm install
- Install Bower components:
bower install
Running
- Run:
grunt server
- This will run a local webserver for development and you can view the application in your web browser at http://localhost:8136.
- Utilize
examples/example.html
for development, whileexamples/example-dev.html
is used for the deployed version, andindex-build.html
is used to test the build before deployment. - The server runs
grunt watch
which will watch for linting JS files and compiling SASS. If you have your own webserver, feel free to use that with just this command.
Building
Built versions will only be regularly committed for tagged releases.
- Uses grunt which depends on Node. To install:
npm install -g grunt-cli && npm install
- (for specific version) Update version in:
package.json
- Run:
grunt
- (for specific version) Tag release with appropriate version:
git tag 0.1.1
Architecture
The basic idea of the application is pulling together editorial knowledge about bills and combining it with Open States data about the bills to create a focused and useful interface to keep track of the important activities of a legislature session.
OS
prefixes refer to Open States data, while E
or e
prefixes refer to editorial data and objects.
Each editorial (or meta) bill refers to one or more Open States (or actual) bill.
Cross-browser compatibility
The goal of this project is to be compatible with all major modern browsers including IE8.
Caching
To ensure that both memory and network usage is minimized, there is some basic caching happening.
For model instances, we wrap the creation of models in the following method:
LT.getModel('ModelName', 'identifying_attribute', attributes)
For fetching models we wrap fetchings so that it only happens once:
LT.fetchModel(model));
// Returns a jQuery promise object
Google Spreadsheets
This application uses Tabletop.js to read in data from Google Spreadsheets. Due to the fact that Google does not guarantee up time or ability to handle requests, it is good practice to cache the outputs for production. Tabletop has some recent additions to handle proxy via saving the outputs to a place like S3, as well as more traditional proxy like gs-proxy. Use the tabletopOptions
option to set any of the tabletop options.
Attribution
- Some icons provided by The Noun Project:
- Congress by Martha Ormiston; Energy by NDSTR
- GayMarriage by MaurizioFusillo
- Education by Thibault Geffroy
- Time by Richard de Vos
- Capital by Jonathan Keating
- Paper by Tom Schott
- Bank by Ilaria Baggio
- Group by Alexandra Coscovelnita
- Check mark by Spencer Cohen
- Back by John Chapman.
About Us
MinnData, the MinnPost data team, is Alan, Tom, and Kaeti and all the awesome contributors to open source projects we utilize. See our work at minnpost.com/data.
.--.
`. \
\ \
. \
: .
| .
| :
| |
..._ ___ | |
`."".`''''""--..___ | |
,-\ \ ""-...__ _____________/ |
/ ` " ' `"""""""" .
\ L
(> \
/ \
\_ ___..---. L
`--' '. \
. \_
_/`. `.._
.' -. `.
/ __.-Y /''''''-...___,...--------.._ |
/ _." | / ' . \ '---..._ |
/ / / / _,. ' ,/ | |
\_,' _.' / /'' _,-' _| |
' / `-----'' / |
`...-' `...-'