Skip to content

Commit

Permalink
Merge remote-tracking branch 'timwis/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
Mark Silverberg committed Jan 23, 2016
2 parents 87468bf + c67e8a4 commit 487b6a7
Show file tree
Hide file tree
Showing 21 changed files with 407 additions and 261 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
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,18 @@
"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>
3 changes: 3 additions & 0 deletions src/scripts/collections/baseprovider.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ module.exports = Backbone.Collection.extend({
getTriggerField: function () {
return this.config.triggerField
},
getChannel: function () {
return this.config.dataset + '.filter'
},
setSearch: function (newValue) {
this.config.search = newValue
},
Expand Down
3 changes: 2 additions & 1 deletion src/scripts/collections/socrata-fields.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ module.exports = BaseFields.extend({
data: row.fieldName,
title: row.name,
type: this.typeMap[row.renderTypeName] || this.typeMap.default,
defaultContent: ''
defaultContent: '',
description: row.description
}
}, this)
}
Expand Down
3 changes: 3 additions & 0 deletions src/scripts/config/providers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
socrata: require('../collections/socrata')
}
113 changes: 46 additions & 67 deletions src/scripts/layout.js
Original file line number Diff line number Diff line change
@@ -1,88 +1,67 @@
/* global global */
var $ = global.jQuery = require('jquery')
var _ = global._ = require('underscore')
var $ = require('jquery')
var _ = require('underscore')
var Backbone = require('backbone')
var deparam = require('node-jquery-deparam')
require('gridstack/dist/gridstack')

var Header = require('./views/header')
var vizwit = require('./vizwit')
var Gist = require('./collections/gist')

var vent = _.clone(Backbone.Events)
var fieldsCache = {}

var params = window.location.search.substr(1) ? deparam(window.location.search.substr(1)) : {}
module.exports = function (config, options) {
options = options || {}
if (!config.version || config.version !== '2') console.error('Wrong config version')

// If no gist specified, redirect to homepage
var redirect = function () { window.location.replace('http://vizwit.io') }
if (!params.gist) {
redirect()
}

// Fetch gist
(new Gist(null, {id: params.gist})).fetch({
success: function (collection, response, options) {
if (!collection.length) return console.error('No files in gist', params.gist)
// Render header
if (config.header) {
var header = new Header(config.header)
$(options.headerSelector).empty().append(header.render().el)

// If a file was provided, use that one; otherwise use the first file in the gist
var model = params.file && collection.get(params.file) ? collection.get(params.file) : collection.at(0)
var config = JSON.parse(model.get('content'))
// Update <title> tag
if (config.header.title) {
var originalTitle = $('title').text()
$('title').text(config.header.title + ' - ' + originalTitle)
}
}

if (!config.version || config.version !== '2') return redirect()
var container = $(options.contentSelector)
var heightInterval = 60 // from gridstack.js
var current = {x: null, y: null}
var row

// Render header
if (config.header) {
var header = new Header(config.header)
$('#page-header').append(header.render().el)
container.empty()

// Update <title> tag
if (config.header.title) {
var originalTitle = $('title').text()
$('title').text(config.header.title + ' - ' + originalTitle)
}
config.cards.forEach(function (config) {
// If y suggests we're on a new row (including the first item), create a new row
if (config.y !== current.y) {
row = $('<div class="row"></div>')
container.append(row)
current.y = config.y
current.x = 0
}

var container = $('#page-content')
var heightInterval = 60 // from gridstack.js
var current = {x: null, y: null}
var row

config.cards.forEach(function (config) {
// If y suggests we're on a new row (including the first item), create a new row
if (config.y !== current.y) {
row = $('<div class="row"></div>')
container.append(row)
current.y = config.y
current.x = 0
}
var column = $('<div/>')

var column = $('<div/>')
// Add width class
column.addClass('col-sm-' + config.width)

// Add width class
column.addClass('col-sm-' + config.width)

// If x is not the same as our current x position, add offset class
if (config.x !== current.x) {
column.addClass('col-sm-offset-' + (config.x - current.x))
}
// Set height of new div
column.css('min-height', config.height * heightInterval)
// If x is not the same as our current x position, add offset class
if (config.x !== current.x) {
column.addClass('col-sm-offset-' + (config.x - current.x))
}
// Set height of new div
column.css('min-height', config.height * heightInterval)

// Increment current.x to new starting position
current.x += config.width
// Increment current.x to new starting position
current.x += config.width

// Add the div to the current row
row.append(column)
// Add the div to the current row
row.append(column)

// Initialize vizwit on new div
vizwit.init(column, config.vizwit, {
vent: vent,
fieldsCache: fieldsCache
})
// Initialize vizwit on new div
vizwit.init(column, config.vizwit, {
vent: vent,
fieldsCache: fieldsCache
})
},
error: function () {
console.error('Error fetching gist', params.gist)
}
})
})
}
3 changes: 0 additions & 3 deletions src/scripts/providers.js

This file was deleted.

49 changes: 49 additions & 0 deletions src/scripts/views/config/pie.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
module.exports = {
type: 'pie',
theme: 'light',
titleField: 'label',
valueField: 'value',
pulledField: 'pulled',
innerRadius: '40%',
groupPercent: 1,
balloonFunction: function (item, formattedText) {
var content = '<b>' + item.title + '</b><br>' +
'Total: ' + item.value.toLocaleString() + ' (' + parseFloat(item.percents.toFixed(2)) + '%)'
if (item.dataContext.filteredValue !== undefined) {
content += '<br>Filtered Amount: ' + (+item.dataContext.filteredValue).toLocaleString()
}
return content
},
labelFunction: function (item, formattedText) {
return item.title.length > 15 ? item.title.substr(0, 15) + '…' : item.title
},
balloon: {},
autoMargins: false,
marginTop: 0,
marginBottom: 0,
marginLeft: 0,
marginRight: 0,
pullOutRadius: '10%',
pullOutOnlyOne: true,
labelRadius: 1,
pieAlpha: 0.8,
hideLabelsPercent: 5,
creditsPosition: 'bottom-right',
startDuration: 0,
addClassNames: true,
responsive: {
enabled: true,
addDefaultRules: false,
rules: [
{
maxWidth: 450,
overrides: {
pullOutRadius: '10%',
titles: {
enabled: false
}
}
}
]
}
}
Loading

0 comments on commit 487b6a7

Please sign in to comment.