Last active
December 17, 2015 00:39
-
-
Save darthmall/5522747 to your computer and use it in GitHub Desktop.
AppJS data explorer.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var app = module.exports = require('appjs'); | |
var sqlite3 = require('sqlite3').verbose(); | |
// Store a reference to the objects generated from the SQLite database in bins. | |
// This seems to prevent the application from crashing, probably by ensuring | |
// these objects aren't deallocated. | |
var bins, db; | |
function density(cutoff, unoccupied, callback) { | |
function tallyBin(err, results) { | |
function tally(bin) { | |
return function (err, results) { | |
if (err) { | |
console.log(err); | |
callback(err); | |
return; | |
} | |
var total = 0, area = 0, | |
percentiles = []; | |
for (var i = 0; i <= 100; i += 5) { | |
percentiles.push({ | |
'percentile': i / 100, | |
'delta': Infinity, | |
'density': 0 | |
}); | |
} | |
results = results.map(function (row) { | |
total += row.area; | |
return { | |
'area' : row.area, | |
'density' : row.density > cutoff ? 0 : row.density | |
}; | |
}).sort(function (a, b) { return a.density - b.density; }); | |
results.forEach(function (row) { | |
area += row.area; | |
var p = area / total; | |
percentiles.forEach(function (d) { | |
var delta = Math.abs(d.percentile - p); | |
if (delta <= d.delta) { | |
d.delta = delta; | |
d.density = row.density; | |
} | |
}); | |
}); | |
console.log(bin + ': done'); | |
// Store a reference to the calculated values to ensure they won't be | |
// dereferenced later. | |
bins[bin] = percentiles; | |
// Callback into the front-end JavaScript running in Chromium to pass | |
// the calculated percentiles for this bin. | |
callback(err, bin, percentiles); | |
}; | |
} | |
if (err) { | |
console.log(err); | |
callback(err); | |
return; | |
} | |
results.forEach(function (row) { | |
if (unoccupied) { | |
db.all('SELECT area, density FROM livestock WHERE bin = ? AND density > 0 AND density <= ?', | |
[row.bin, cutoff], tally(row.bin)); | |
} else { | |
db.all('SELECT area, density FROM livestock WHERE bin = ?', [row.bin], | |
tally(row.bin)); | |
} | |
}); | |
} | |
bins = {}; | |
if (!db) { | |
db = new sqlite3.Database('livestock.db', function (err) { | |
console.log(err || 'Database opened'); | |
if (!err) { | |
db.all('SELECT DISTINCT bin FROM livestock', tallyBin); | |
} else { | |
callback(err); | |
} | |
}); | |
} else { | |
db.all('SELECT DISTINCT bin FROM livestock', tallyBin); | |
} | |
} | |
app.serveFilesFrom(__dirname + '/content'); | |
var menubar = app.createMenu([{ | |
label:'&File', | |
submenu:[ | |
{ | |
label:'E&xit', | |
action: function(){ | |
window.close(); | |
} | |
} | |
] | |
},{ | |
label:'&Window', | |
submenu:[ | |
{ | |
label:'Fullscreen', | |
action:function(item) { | |
window.frame.fullscreen(); | |
console.log(item.label+" called."); | |
} | |
}, | |
{ | |
label:'Minimize', | |
action:function(){ | |
window.frame.minimize(); | |
} | |
}, | |
{ | |
label:'Maximize', | |
action:function(){ | |
window.frame.maximize(); | |
} | |
},{ | |
label:''//separator | |
},{ | |
label:'Restore', | |
action:function(){ | |
window.frame.restore(); | |
} | |
} | |
] | |
}]); | |
menubar.on('select',function(item){ | |
console.log("menu item "+item.label+" clicked"); | |
}); | |
var window = app.createWindow({ | |
width : 640, | |
height : 460, | |
icons : __dirname + '/content/icons', | |
name : 'Biomass Densities' | |
}); | |
window.on('create', function(){ | |
console.log("Window Created"); | |
window.frame.show(); | |
window.frame.center(); | |
window.frame.setMenuBar(menubar); | |
}); | |
window.on('ready', function(){ | |
console.log("Window Ready"); | |
window.process = process; | |
window.module = module; | |
window.density = density; | |
window.stdout = console.log; | |
function F12(e){ return e.keyIdentifier === 'F12' } | |
function Command_Option_J(e){ return e.keyCode === 74 && e.metaKey && e.altKey } | |
window.addEventListener('keydown', function(e){ | |
if (F12(e) || Command_Option_J(e)) { | |
window.frame.openDevTools(); | |
} | |
}); | |
}); | |
window.on('close', function(){ | |
console.log("Window Closed"); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html> | |
<head> | |
<title>Biomass Density</title> | |
<link rel="stylesheet" href="style.css"> | |
</head> | |
<body> | |
<form class="controls"> | |
<label for="cutoff">Cutoff density</label> | |
<div class="slider"> | |
<input id="cutoff-slider" name="cutoff" type="range" min="0" max="10" value="3" step="0.01" /> | |
<input id="cutoff-value" name="cutoff" type="text" value="3.0" size="4" maxlength="4" /> | |
</div> | |
<input id="unoccupied" name="unoccupied" type="checkbox" /> | |
<label for="unoccupied">Include unoccuped pasture</label> | |
<button id="export">Export</button> | |
</form> | |
<script src="d3.v3.min.js"></script> | |
<script src="main.js"></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
addEventListener('app-ready', function () { | |
function update(err, bin, percentiles) { | |
if (err) { | |
window.alert(err); | |
return; | |
} | |
console.log(bin); | |
// bins[bin] = JSON.parse(percentiles); | |
// var lines = svg.selectAll('.bin') | |
// .data(bins, function (d) { return d.bin; }); | |
// lines.enter().append('path') | |
// .attr('class', 'bin') | |
// .attr('d', function (d) { return line(d.density); }); | |
} | |
var cutoff = document.getElementById('cutoff-value'); | |
var margin = {top: 20, right: 10, bottom: 20, left: 10}; | |
var width = 640 - margin.left - margin.right, | |
height = 460 - margin.top - margin.bottom; | |
var svg = d3.select('body').append('svg') | |
.attr('width', width + margin.left + margin.right) | |
.attr('height', height + margin.top + margin.bottom) | |
.append('g') | |
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); | |
var x = d3.scale.linear().range([0, width]).domain([0, 1]), | |
y = d3.scale.linear().range([height, 0]).domain([0, cutoff.value]); | |
var line = d3.svg.line() | |
.x(function (d) { return x(d.percentile); }) | |
.y(function (d) { return y(d.density); }); | |
var bins = {}; | |
slider(document.getElementsByClassName('slider')); | |
density(cutoff.value, false, update); | |
function slider(selection) { | |
function onSliderChange(input) { | |
return function (e) { | |
input.value = e.target.value = precision(e.target.value, 2); | |
y.domain([0, input.value]); | |
density(input.value, false, update); | |
}; | |
} | |
var i = selection.length; | |
while (--i >= 0) { | |
var range = selection[i].children[0], | |
input = selection[i].children[1]; | |
range.addEventListener('change', onSliderChange(input)); | |
input.addEventListener('change', onSliderChange(range)); | |
} | |
return selection; | |
} | |
function precision(value, decimals) { | |
return Math.round(value * Math.pow(10, decimals)) / Math.pow(10, decimals); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment