Skip to content

Commit

Permalink
Merge pull request #7 from marks/master
Browse files Browse the repository at this point in the history
Bring vizwit/marks:master into marks:dev
  • Loading branch information
marks committed Jan 23, 2016
2 parents 22f73af + 84148ed commit e240a82
Show file tree
Hide file tree
Showing 27 changed files with 629 additions and 403 deletions.
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ An interactive data visualization tool. VizWit uses a [JSON config file](https:/
interactive charts that cross-filter one another. It currently supports data hosted in a Socrata Open Data portal, which includes
cities such as [Philadelphia](http://opendataphilly.org), [Chicago](https://data.cityofchicago.org/), [San Francisco](https://data.sfgov.org/)
and many others. However, interactions with Socrata have been [abstracted](src/scripts/collections/socrata.js) to allow
for other data providers to be written (in theory).
for [other data providers](https://github.com/timwis/vizwit/wiki/Adding-a-provider) to be written.

[![screencast](http://i.imgur.com/4gTXNFK.gif)](http://vizw.it/?gist=51db593dc0537d1a3f05)

Expand Down Expand Up @@ -60,16 +60,17 @@ layout is generated by Gridstack. The application is compiled using Browserify.
# How it works
[vizwit.js](src/scripts/vizwit.js) is the primary chart-generating module. It takes a `container` selector and a `config` object and
uses them to initialize a view (bar chart, map, table, etc.). The views are passed a `collection` and a `filteredCollection`, which are
identical and allow the view to query the data provider (Socrata). Views generate the chart/map/table/etc. and listen for user interactions
identical and allow the view to query the data provider. Views generate the chart/map/table/etc. and listen for user interactions
on them. On an interaction, the view triggers the global event object with the filter (ie. `state=PA`), and all views that use the same
dataset receive the event and use their `filteredCollection` to query the data provider with the filter passed through the event. By
using a separate collection, VizWit can show the "filtered value" and the "original value" side-by-side.

The actual entry point is either [layout.js](src/scripts/layout.js) or [embed.js](src/scripts/embed.js). layout.js fetches a gist, reads
its configuration, and creates a layout on the page. Then for each chart in the configuration, it calls `init()` from vizwit.js as
described above. embed.js simply finds the parent container of the `<script>` tag that was embedded, and calls `init()` from vizwit.js
inside of it. This way of embedding allows the VizWit library to only be loaded once on the page with as many charts embedded in any
element ([example](http://vizw.it/embed-demo.html)).
The actual entry point is either [vizwit-loader.js](src/scripts/vizwit-loader.js) or [vizwit-embed.js](src/scripts/vizwit-embed.js).
vizwit-loader.js fetches a gist or local file, reads its configuration, and passes it to [layout.js](src/scripts/layout.js] to create a
layout on the page. Then for each chart in the configuration, layout.js calls `init()` from vizwit.js as described above. vizwit-embed.js
simply finds the parent container of the `<script>` tag that was embedded, and calls `init()` from vizwit.js inside of it. This way of
embedding allows the VizWit library to only be loaded once on the page with as many charts embedded in any element
([example](http://vizw.it/embed-demo.html)).

# Development
* After cloning the repo, use `npm install` to install dependencies
Expand Down
19 changes: 13 additions & 6 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,28 @@ var dir = {
}

gulp.task('build', ['clean'], function () {
gulp.start('scripts', 'styles', 'html', 'cname')
gulp.start('scripts', 'styles', 'data', 'html', 'cname')
})

gulp.task('watch', ['clean'], function () {
gulp.start('scripts-watch', 'styles', 'html', 'cname')
gulp.start('scripts-watch', 'styles', 'data', 'html', 'cname')
gulp.watch(dir.dev + 'styles/*css', ['styles'])
gulp.watch(dir.dev + '*.html', ['html'])
})

gulp.task('scripts', function () {
return mergeStream(
scripts(dir.dev + 'scripts/layout.js', 'layout.js'),
scripts(dir.dev + 'scripts/embed.js', 'embed.js')
scripts(dir.dev + 'scripts/vizwit-loader.js', 'vizwit-loader.js'),
scripts(dir.dev + 'scripts/vizwit-embed.js', 'vizwit-embed.js'),
scripts(dir.dev + 'scripts/vizwit-editor.js', 'vizwit-editor.js')
)
})

gulp.task('scripts-watch', function () {
return mergeStream(
scripts(dir.dev + 'scripts/layout.js', 'layout.js', true),
scripts(dir.dev + 'scripts/embed.js', 'embed.js', true)
scripts(dir.dev + 'scripts/vizwit-loader.js', 'vizwit-loader.js', true),
scripts(dir.dev + 'scripts/vizwit-embed.js', 'vizwit-embed.js', true),
scripts(dir.dev + 'scripts/vizwit-editor.js', 'vizwit-editor.js', true)
)
})

Expand All @@ -52,6 +54,11 @@ gulp.task('styles', function () {
.pipe(gulp.dest(dir.prod + 'styles/'))
})

gulp.task('data', function () {
return gulp.src(dir.dev + 'data/*.json')
.pipe(gulp.dest(dir.prod + 'data/'))
})

gulp.task('clean', function (cb) {
return del(dir.prod, cb)
})
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,20 @@
"amcharts3": "amcharts/amcharts3",
"backbone": "^1.2.2",
"backbone.modal": "^1.1.5",
"bluebird": "^3.1.1",
"bootstrap": "^3.3.5",
"brace": "^0.7.0",
"chroma-js": "^1.1.1",
"clipboard": "^1.4.2",
"datatables": "https://github.com/DataTables/DataTables/archive/1.10.9.tar.gz",
"gridstack": "^0.2.3",
"jquery": "^2.1.4",
"leaflet": "^0.7.7",
"leaflet-choropleth": "^1.0.3",
"moment": "^2.10.6",
"numbro": "^1.3.3",
"soda-js": "socrata/soda-js",
"spin.js": "^2.3.2",
"split.js": "^1.0.6",
"underscore": "^1.8.3"
},
"devDependencies": {
Expand Down
File renamed without changes.
33 changes: 33 additions & 0 deletions src/editor.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>VizWit Editor</title>

<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Arimo:400,700,400italic">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.9/css/dataTables.bootstrap.min.css">
<link rel="stylesheet" href="https://api.mapbox.com/mapbox.js/v2.2.1/mapbox.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/backbone.modal/1.1.5/backbone.modal-min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/backbone.modal/1.1.5/backbone.modal.theme-min.css">
<link rel="stylesheet" href="styles/main.css">
<link rel="stylesheet" href="styles/editor.css">
</head>
<body>
<div class="row">
<div id="editor" class="split"></div>
<div id="preview" class="split">
<div class="header-container">
<div class="container-fluid" id="page-header"></div>
</div>

<div class="container-fluid">
<div id="page-content"></div>
</div>
</div>
</div>

<script src="scripts/vizwit-editor.js"></script>
</body>
</html>
3 changes: 1 addition & 2 deletions src/embed-demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.9/css/dataTables.bootstrap.min.css">
<link rel="stylesheet" href="https://api.mapbox.com/mapbox.js/v2.2.1/mapbox.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/gridstack.js/0.2.3/gridstack.min.css">
<link rel="stylesheet" href="styles/main.css">

<link rel="canonical" href="">
Expand Down Expand Up @@ -74,6 +73,6 @@ <h1>Hello, world!</h1>
</div>
</div>

<script src="scripts/embed.js"></script>
<script src="scripts/vizwit-embed.js"></script>
</body>
</html>
3 changes: 1 addition & 2 deletions src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.9/css/dataTables.bootstrap.min.css">
<link rel="stylesheet" href="https://api.mapbox.com/mapbox.js/v2.2.1/mapbox.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/gridstack.js/0.2.3/gridstack.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/backbone.modal/1.1.5/backbone.modal-min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/backbone.modal/1.1.5/backbone.modal.theme-min.css">
<link rel="stylesheet" href="styles/main.css">
Expand Down Expand Up @@ -42,6 +41,6 @@
<div class="grid-stack grid-stack-12" id="page-content"></div>
</div>

<script src="scripts/layout.js"></script>
<script src="scripts/vizwit-loader.js"></script>
</body>
</html>
4 changes: 4 additions & 0 deletions src/scripts/collections/basefields.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// A stub here for future proofing
var Backbone = require('backbone')

module.exports = Backbone.Collection
44 changes: 28 additions & 16 deletions src/scripts/collections/baseprovider.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/
var Backbone = require('backbone')
var _ = require('underscore')
var BaseFields = require('./basefields')

var model = Backbone.Model.extend({
idAttribute: 'label'
Expand All @@ -15,29 +16,37 @@ var enclose = function (val) {
module.exports = Backbone.Collection.extend({
model: model,
initialize: function (models, options) {
this.options = options || {}
if (!this.options.triggerField) this.options.triggerField = this.options.groupBy
if (!this.options.baseFilters) this.options.baseFilters = []
if (!this.options.filters) this.options.filters = {}
options = options || {}
this.config = options.config || {}
if (!this.config.triggerField) this.config.triggerField = this.config.groupBy
if (!this.config.baseFilters) this.config.baseFilters = []
if (!this.config.filters) this.config.filters = {}

this.fieldsCache = options.fieldsCache || {}
// Check if fieldsCache already has a collection for this dataset, otherwise create one
if (!this.fieldsCache[this.config.dataset]) {
this.fieldsCache[this.config.dataset] = new this.fieldsCollection(null, this.config) // eslint-disable-line
}
},
fieldsCollection: BaseFields,
setFilter: function (filter) {
if (filter.expression) {
this.options.filters[filter.field] = filter
this.config.filters[filter.field] = filter
} else {
delete this.options.filters[filter.field]
delete this.config.filters[filter.field]
}
},
getFilters: function (key) {
var filters = this.options.filters
var filters = this.config.filters

if (key) {
return filters[key]
}
// If dontFilterSelf enabled, remove the filter this collection's triggerField
// (don't do this if key provided since that's usually done to see if a filter is set
// rather than to perform an actual filter query)
if (!_.isEmpty(filters) && this.options.dontFilterSelf) {
filters = _.omit(filters, this.options.triggerField)
if (!_.isEmpty(filters) && this.config.dontFilterSelf) {
filters = _.omit(filters, this.config.triggerField)
}

return _.values(filters)
Expand Down Expand Up @@ -70,25 +79,28 @@ module.exports = Backbone.Collection.extend({
}
},
getDataset: function () {
return this.options.dataset
return this.config.dataset
},
getTriggerField: function () {
return this.options.triggerField
return this.config.triggerField
},
getChannel: function () {
return this.config.dataset + '.filter'
},
setSearch: function (newValue) {
this.options.search = newValue
this.config.search = newValue
},
setDontFilterSelf: function (newValue) {
this.options.dontFilterSelf = newValue
this.config.dontFilterSelf = newValue
},
setOrder: function (newValue) {
this.options.order = newValue
this.config.order = newValue
},
setOffset: function (newValue) {
this.options.offset = newValue
this.config.offset = newValue
},
setLimit: function (newValue) {
this.options.limit = newValue
this.config.limit = newValue
},
unsetRecordCount: function () {
this.recordCount = null
Expand Down
15 changes: 6 additions & 9 deletions src/scripts/collections/socrata-fields.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
var Backbone = require('backbone')
var BaseFields = require('./basefields')

var model = Backbone.Model.extend({
idAttribute: 'data'
})

module.exports = Backbone.Collection.extend({
module.exports = BaseFields.extend({
typeMap: {
calendar_date: 'date',
number: 'num',
Expand All @@ -14,27 +15,23 @@ module.exports = Backbone.Collection.extend({
model: model,
comparator: 'position',
initialize: function (models, options) {
this.options = options || {}
this.config = options || {}
},
url: function () {
return [
'https://',
this.options.domain,
this.config.domain,
'/api',
'/views',
'/' + this.options.dataset,
'/' + this.config.dataset,
'.json'
].join('')
},
parse: function (response) {
return response.columns.map(function (row, key) {
var titleForRow = row.name
if(!_.isEmpty(row.description)){
titleForRow += ' <span class="fa fa-info-circle" data-toggle="tooltip" data-placement="top" title="'+row.description+'"></span>'
}
return {
data: row.fieldName,
title: titleForRow,
title: row.name,
type: this.typeMap[row.renderTypeName] || this.typeMap.default,
defaultContent: '',
description: row.description
Expand Down
Loading

0 comments on commit e240a82

Please sign in to comment.