add animated vector map, geo JSON translator, station long/lat data

This commit is contained in:
Cameron Beccario 2013-08-26 18:54:20 +09:00
parent fbf0db8e4f
commit 1cbd3c0f9b
12 changed files with 13177 additions and 96 deletions

134
api.js
View File

@ -17,22 +17,59 @@ exports.initialize = function(stationsTableSpec, samplesTableSpec) {
return this;
}
function prepare(value) {
return value;
// return JSON.stringify(value, null, ' ');
}
app.get('/about/stations', function(request, response) {
var schema = {};
stationsTable.columns.forEach(function(column) {
schema[column.name] = column.description;
});
response.send(schema);
response.type('json');
response.json(prepare(schema));
});
app.get('/stations', function(request, response) {
var stmt = db.selectAll(stationsTable);
when(db.execute(stmt)).then(
function(result) {
response.send(result.rows);
response.type('json');
response.json(prepare(result.rows));
},
function(error) {
response.send(error.message);
response.type('json');
response.json(prepare(error.message));
});
});
app.get('/stations/geo', function(request, response) {
var stmt = db.selectAll(stationsTable);
when(db.execute(stmt)).then(
function(result) {
var out = {
type: 'FeatureCollection',
features: result.rows.map(function(element) {
return {
type: 'Feature',
properties: {name: element.id.toString()},
geometry: {
type: 'Point',
coordinates: [
parseFloat(element.longitude),
parseFloat(element.latitude)
]
}
}
})
};
response.type('json');
response.json(prepare(out));
},
function(error) {
response.type('json');
response.json(prepare(error.message));
});
});
@ -41,7 +78,8 @@ app.get('/about/samples', function(request, response) {
samplesTable.columns.forEach(function(column) {
schema[column.name] = column.description;
});
response.send(schema);
response.type('json');
response.json(prepare(schema));
});
app.get('/samples/*', function(request, response) {
@ -78,7 +116,7 @@ app.get('/samples/*', function(request, response) {
function parseSampleTypePath() {
result.sampleType = next; // UNDONE: sample type validation -- must be one of no, no2, temp, etc.
result.stationId = args.shift(); // UNDONE: stationId validation -- must be numeric
return db.selectSamples(samplesTable, result);
return db.selectSamples(samplesTable, stationsTable, result);
}
function parseDatePath() {
@ -116,17 +154,97 @@ app.get('/samples/*', function(request, response) {
}
if (result.error) {
return response.send(result.error);
response.type('json');
return response.json(prepare(result.error));
}
when(db.execute(stmt)).then(
function(result) {
response.send(result.rows);
response.type('json');
response.json(prepare(result.rows));
},
function(error) {
response.send(error.message);
response.type('json');
response.json(prepare(error.message));
});
});
app.use(express.static(__dirname + '/public'));
var server = require('http').Server(app);
var io = require('socket.io').listen(server);
// listen for incoming connections from client
io.sockets.on('connection', function (socket) {
// start listening for coords
socket.on('send:coords', function (data) {
when(db.execute(db.selectAll(stationsTable))).then(
function(result) {
var coords = [];
result.rows.forEach(function(row) {
if (row.latitude && row.longitude) {
coords.push({lat: row.latitude, lng: row.longitude, acr: 0});
}
});
var data = {id: 'stations', active: true, coords: coords};
console.log('broadcast: ' + util.inspect(data, {depth:null}));
socket.broadcast.emit('load:coords', data);
},
console.error);
// broadcast your coordinates to everyone except you
socket.broadcast.emit('load:coords', data);
});
});
app.get('/wind/vectors', function(request, response) {
// var args = request.params[0].split(/\//);
// console.log('/points/* ' + util.inspect(args));
var constraints = {
date: {current: true, parts: [], zone: '+09:00'},
sampleType: null,
stationId: null,
error: null
};
var selected = db.selectSamples(samplesTable, stationsTable, constraints);
if (constraints.error) {
response.json(constraints.error);
return;
}
var respond = response.json.bind(response);
db.execute(selected).then(buildVectors).then(respond, respond);
});
function buildVectors(selectedSamples) {
console.log('building vectors...');
var d = when.defer();
db.execute(db.selectAll(stationsTable)).then(
function(selectedStations) {
var stations = {};
selectedStations.rows.forEach(function(element) {
stations[element.id] = [element.longitude, element.latitude];
});
var samples = [];
selectedSamples.rows.forEach(function(sample) {
if (sample.wv && sample.wd) {
var coords = stations[sample.stationId];
if (coords) {
samples.push([coords[0] * 1, coords[1] * 1, [sample.wd * 1, sample.wv * 1], sample.stationId]);
}
}
});
d.resolve(samples);
},
function(error) {
d.reject(error);
});
return d.promise;
}
app.listen(3000);
console.log('Listening on port 3000...');

10
db.js
View File

@ -191,12 +191,15 @@ function sampleTypeConstraint(constraints) {
* stationId: Number id of desired station, or null for all.
* @returns {{sql: string, args: Array}} an object {sql: x, args: y} representing a sample select statement.
*/
exports.selectSamples = function(tableSpec, constraints) {
exports.selectSamples = function(tableSpec, stationTableSpec, constraints) {
console.log(constraints);
var dateColumn = quoteName('date');
var idColumn = quoteName('id');
var stationIdColumn = quoteName('stationId');
var longitudeColumn = quoteName('longitude');
var latitudeColumn = quoteName('latitude');
var table = quoteName(tableSpec.name);
var stmt = 'SELECT ';
var stmt = tool.format('SELECT b.{0}, b.{1}, ', longitudeColumn, latitudeColumn);
// First, decide which columns to select.
if (constraints.sampleType && constraints.sampleType != 'all') {
@ -215,7 +218,8 @@ exports.selectSamples = function(tableSpec, constraints) {
}
// Next, constrain the results by date, station id, and sample type, where necessary.
stmt += tool.format('\nFROM {0} WHERE {1}', table, dateConstraint(constraints.date));
stmt += tool.format('\nFROM {0} a INNER JOIN {1} b ON a.{2} = b.{3}', table, quoteName(stationTableSpec.name), stationIdColumn, idColumn);
stmt += tool.format('\nWHERE {0}', dateConstraint(constraints.date));
var stationConstraint = stationIdConstraint(constraints);
if (stationConstraint) {
stmt += ' AND ' + stationConstraint;

30
ksj/bin/ksj Executable file
View File

@ -0,0 +1,30 @@
#!/usr/bin/env node
// ./ksj -c ../../scratch/N03-110331_13.xml tk.json
// ./ksj -t ./tk.json tk.geojson
// topojson -o tk.topojson tk.geojson
var fs = require('fs');
var when = require('when');
var ksj = require('../ksj');
function write(file, data) {
var d = when.defer();
fs.writeFile(file, data, function(error) {
if (error) {
return d.reject(error);
}
d.resolve(true);
});
return d.promise;
}
if (process.argv[2] === '-c') {
ksj.convertToJSON(process.argv[3]).then(write.bind(null, process.argv[4]));
}
else if (process.argv[2] === '-t') {
when(ksj.convertToGeoJSON(require(process.argv[3]))).then(write.bind(null, process.argv[4]));
}
else {
console.log('wrong.');
}

355
ksj/ksj.js Normal file
View File

@ -0,0 +1,355 @@
'use strict';
var _ = require('underscore');
var util = require('util');
var when = require('when');
var fs = require('fs');
var xml2js = require('xml2js');
/**
* Returns a promise for a simplified JSON representation of the specified KSJ xml file.
*
* @param sourceFile
* @returns {*}
*/
exports.convertToJSON = function(sourceFile) {
var d = when.defer();
fs.readFile(sourceFile, function(error, data) {
if (error) {
return d.reject(error);
}
console.log('Parsing...');
var parser = new xml2js.Parser();
parser.parseString(data, function(error, root) {
if (error) {
return d.reject(error);
}
console.log('Process Pass 1...');
var childCounts = pass1(root);
console.log('Process Pass 2...');
pass2(root, childCounts);
console.log('Process Pass 3...');
pass3(root);
console.log('Stringify...');
var result = JSON.stringify(root, null, ' ');
console.log('Converted.');
d.resolve(result);
});
});
return d.promise;
}
function removeNamespace(str) {
var i = str.indexOf(':');
return i < 0 ? str : str.substr(i + 1);
}
function removePrefix(str) {
var i = str.indexOf('.');
return i < 0 ? str : str.substr(i + 1);
}
function pass1(root) {
// removes namespaces
// removes prefixes
// calculates child counts to aid in collapsing arrays during pass 2
var childCounts = {};
function visitArray(ary, context) {
if (context) {
childCounts[context] = Math.max(childCounts[context] | 0, ary.length);
}
ary.forEach(function(element, i) {
ary[i] = visit(element);
});
return ary;
}
function visitObject(obj, context) {
_.keys(obj).forEach(function(rawKey) {
var simpleKey = removePrefix(removeNamespace(rawKey));
if (_.has(obj, simpleKey)) {
simpleKey = rawKey; // simplified key already exists, so use original key as-is.
}
obj[simpleKey] = visit(obj[rawKey], simpleKey);
if (simpleKey !== rawKey) {
delete obj[rawKey];
}
});
return obj;
}
function visit(value, context) {
if (_.isArray(value)) {
return visitArray(value, context);
}
if (_.isObject(value)) {
return visitObject(value, context);
}
return value;
}
visit(root);
return childCounts;
}
function pass2(root, childCounts) {
// removes redundant arrays where all instances contain just one child
// merges attributes ($) into owning object
function visitArray(ary, context) {
ary.forEach(function(element, i) {
ary[i] = visit(element);
});
return ary.length == 1 && childCounts[context] == 1 ? ary[0] : ary;
}
function visitObject(obj, context) {
var result = obj;
_.keys(obj).forEach(function(key) {
obj[key] = visit(obj[key], key);
});
// Move all properties from $ into owning object if they don't already exist. If afterwards $ is
// empty, then get rid of $.
var $ = obj.$;
if ($) {
result = {}; // create a new object to represent the union of the keys in obj and obj.$
_.keys($).forEach(function(key) {
if (_.has(obj, key)) {
return;
}
result[key] = $[key];
delete $[key];
});
if (_.size($) === 0) {
delete obj.$;
}
_.keys(obj).forEach(function(key) {
result[key] = obj[key];
});
}
return result;
}
function visit(value, context) {
if (_.isArray(value)) {
return visitArray(value, context);
}
if (_.isObject(value)) {
return visitObject(value, context);
}
return value;
}
visit(root);
}
function pass3(root) {
// simplifies deep objects to shallow objects
function visitArray(ary, context) {
ary.forEach(function(element, i) {
ary[i] = visit(element);
});
return ary;
}
function visitObject(obj, context) {
_.keys(obj).forEach(function(key) {
obj[key] = visit(obj[key], key);
});
var size = _.size(obj);
if (size === 2 && _.has(obj, 'dimension') && _.has(obj, 'coordinate')) {
// {"coordinate": "35.89 139.01", "dimension": "2"} ==> "35.89 139.01"
return obj.coordinate;
}
if (size === 1 && _.has(obj, 'idref')) {
// {"idref": "n00001"} ==> "n00001"
return obj.idref;
}
if (size === 1 && _.has(obj, 'DirectPosition') && context == 'position') {
// "position": {"DirectPosition": "35.89 139.01"} ==> "position": "35.89 139.01"
return obj.DirectPosition;
}
if (size === 1 && _.has(obj, 'point') && context == 'indirect') {
// "indirect": {"point": "n00001"} ==> "indirect": "n00001"
return obj.point;
}
return obj;
}
function visit(value, context) {
if (_.isArray(value)) {
return visitArray(value, context);
}
if (_.isObject(value)) {
return visitObject(value, context);
}
return value;
}
visit(root);
}
exports.convertToGeoJSON = function(root) {
var pointRefs = extractPointRefs(root);
var curves = extractCurves(root, pointRefs);
var surfaces = extractSurfaces(root);
var names = extractNames(root, surfaces);
var result = {
type: 'FeatureCollection',
features: buildFeatures(names, curves)
};
return JSON.stringify(result, null, ' ');
}
function asPoint(str) {
var point = str.split(' ').map(function(element) {
return parseFloat(element);
});
// [long, lat] expected, but data source is [lat, long], so swap.
var t = point[0];
point[0] = point[1];
point[1] = t;
return point;
}
function extractPointRefs(root) {
var refs = {};
var gmPoints = root.GI.dataset.object.AA01.OBJ.GM_Point;
gmPoints.forEach(function(element) {
refs[element.id] = asPoint(element.position);
});
return refs;
}
function extractSegment(segment, pointRefs) {
var gmPointArray = segment.GM_LineString.controlPoint.GM_PointArray.column;
return gmPointArray.map(function(element) {
var ref = element.indirect;
if (ref) {
return pointRefs[ref];
}
return asPoint(element.direct);
});
}
function extractCurves(root, pointRefs) {
var curves = {};
var gmCurves = root.GI.dataset.object.AA01.OBJ.GM_Curve;
gmCurves.forEach(function(element) {
var id = element.id;
curves[id] = {id: element.id, points: extractSegment(element.segment, pointRefs)};
});
return curves;
}
function extractCurveRefs(gmPolygon) {
return gmPolygon.map(function(element) {
var ref = element.boundary.GM_SurfaceBoundary.exterior.GM_Ring.generator;
if (ref.indexOf('_') === 0) {
ref = ref.substr(1);
}
return ref;
});
}
function extractSurfaces(root) {
var surfaces = {};
var gmSurfaces = root.GI.dataset.object.AA01.OBJ.GM_Surface;
gmSurfaces.forEach(function(element) {
var id = element.id;
surfaces[id] = {id: element.id, curves: extractCurveRefs(element.patch.GM_Polygon)};
});
return surfaces;
}
function scoalesce(x, y) {
if (x && x.length > 0) {
return x;
}
return y;
}
function extractNames(root, surfaces) {
var names = {};
var ec01 = root.GI.dataset.object.AA01.OBJ.EC01;
ec01.forEach(function(element) {
var id = element.AAC._;
var name = scoalesce(element.CN2, element.CON);
if (!id && name === '所属未定') {
id = 'pending';
}
var feature = names[id];
if (!feature) {
names[id] = feature = {id: id, name: name, curves: []};
}
surfaces[element.ARE].curves.forEach(function(element) {
feature.curves.push(element);
});
});
return names;
}
function isInBounds(point) {
var longitude = point[0];
var latitude = point[1];
return 138.90 < longitude && longitude < 139.95 &&
35.45 < latitude && latitude < 35.95;
}
function buildGeometry(curveRefs, curves) {
var allowedCurves = [];
curveRefs.forEach(function(id) {
var points = curves[id].points;
for (var i = 0; i < points.length; i++) {
if (!isInBounds(points[i])) {
return;
}
}
allowedCurves.push(id);
});
if (allowedCurves.length === 0) {
return null;
}
var multi = allowedCurves.length > 1;
var coordinates = [];
allowedCurves.forEach(function(id) {
var points = curves[id].points;
coordinates.push(multi ? [points] : points);
});
return multi ?
{type: 'MultiPolygon', coordinates: coordinates} :
{type: 'Polygon', coordinates: coordinates};
}
function buildFeature(n, curves) {
return {
type: 'Feature',
id: n.id,
properties: {name: n.name},
geometry: buildGeometry(n.curves, curves)
};
}
function buildFeatures(names, curves) {
var result = [];
_.values(names).forEach(function(element) {
var feature = buildFeature(element, curves);
if (feature.geometry) {
result.push(feature);
}
});
return result;
}

22
ksj/package.json Normal file
View File

@ -0,0 +1,22 @@
{
"name": "ksj",
"description": "国土数値情報 Transformer",
"version": "0.0.1",
"author": {
"name": "Cameron Beccario",
"email": "cambecc@nullschool.net"
},
"repository": {
"type": "git",
"url": "git://github.com/cambecc/air"
},
"engine": "node >= 0.10.12",
"dependencies": {
"underscore": "1.5.1",
"when": "2.2.1",
"xml2js": "0.2.8"
},
"devDependencies": {
"nodeunit": "nodeunit-0.8.1"
}
}

2841
public/canvg.js Executable file

File diff suppressed because it is too large Load Diff

8814
public/d3.v3.js vendored Normal file

File diff suppressed because it is too large Load Diff

414
public/index.html Normal file
View File

@ -0,0 +1,414 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
.tk-fill {
fill: #303030;
}
.tk-inboundary {
fill: none;
stroke: #505050;
stroke-width: 1.5;
stroke-dasharray: 2, 2;
stroke-linejoin: round;
}
.tk-outboundary {
fill: none;
stroke: #808080;
stroke-width: 1;
stroke-linejoin: round;
}
body {
background: #202020;
}
.station {
fill: #4986bc;
}
#pos {
fill: #3aff3a;
}
</style>
</head>
<body>
<div id="map" style="position: absolute;">
<svg id="map-svg"></svg>
</div>
<div id="mask" style="position: absolute; visibility: hidden;">
<svg id="mask-svg" style="position: absolute;"></svg>
<canvas id="mask-canvas" style="position: absolute;"></canvas>
</div>
<div id="field" style="position: absolute; z-index: 10;">
<canvas id="field-canvas" style="position: absolute;"></canvas>
</div>
<script src="topojson.v1.js"></script>
<script src="d3.v3.js"></script>
<script src="canvg.js"></script>
<script>
var width = 1200, height = 700;
// var width = 600, height = 350;
var π = Math.PI;
var projection = d3.geo.albers()
.rotate([-139.3, 0])
.center([0, 144.20])
.scale(80000);
// var projection = d3.geo.albers()
// .rotate([-139.75, 0])
// .center([0, 144.40])
// .scale(40000);
var path = d3.geo.path().projection(projection);
var mapSvg = d3.select("#map-svg").attr("width", width).attr("height", height);
var maskSvg = d3.select("#mask-svg").attr("width", width).attr("height", height);
var maskCanvas = d3.select("#mask-canvas").attr("width", width).attr("height", height)[0][0];
var fieldCanvas = d3.select("#field-canvas").attr("width", width).attr("height", height)[0][0];
d3.json("tk.topojson", function (error, tk) {
var datum = topojson.feature(tk, tk.objects.tk);
mapSvg.selectAll(".tk")
.data(datum.features)
.enter().append("path")
.attr("class", "tk-fill")
.attr("d", path);
mapSvg.append("path")
.datum(topojson.mesh(tk, tk.objects.tk, function (a, b) { return a !== b; }))
.attr("class", "tk-inboundary")
.attr("d", path);
mapSvg.append("path")
.datum(topojson.mesh(tk, tk.objects.tk, function(a, b) { return a === b; }))
.attr("class", "tk-outboundary")
.attr("d", path);
maskSvg.append("path")
.datum(topojson.mesh(tk, tk.objects.tk, function(a, b) { return a === b; }))
.attr("fill", "#fff")
.attr("stroke-width", "50")
.attr("stroke", "#fff")
.attr("stroke-linejoin", "round")
.attr("d", path);
canvg(maskCanvas, document.getElementById("mask").innerHTML.trim());
var maskCanvasContext = maskCanvas.getContext("2d");
var maskData = maskCanvasContext.getImageData(0, 0, maskCanvas.width, maskCanvas.height).data;
for (var x = maskCanvas.width - 1; x >= 0; x -= 1) {
var column = fieldMask[x] = [];
for (var y = maskCanvas.height - 1; y >= 0; y -= 1) {
var i = (y * maskCanvas.width + x) * 4;
column[y] = maskData[i] > 0;
}
}
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
var p = projection([position.coords.longitude, position.coords.latitude]);
var x = Math.round(p[0]);
var y = Math.round(p[1]);
if (0 <= x && x < width && 0 <= y && y < height) {
mapSvg.append("circle")
.attr("cx", x)
.attr("cy", y)
.attr("r", 3)
.attr("id", "pos");
}
},
console.error.bind(console),
{enableHighAccuracy: true});
}
d3.json("stations/geo", function(error, stations) {
path.pointRadius(1);
mapSvg.append("path")
.datum(stations)
.attr("class", "station")
.attr("d", path);
interpolateVectorField();
// interpolateScalarField('no2');
});
});
var done = false;
var fieldMask = [];
d3.select("#field-canvas").on("click", printCoord);
function printCoord() {
console.log(d3.mouse(this));
console.log(projection.invert(d3.mouse(this)));
done = true;
}
var particles = [];
var maxAge = 150;
function distance(x1, y1, x2, y2) {
var xd = Math.abs(x1 - x2);
var yd = Math.abs(y1 - y2);
return Math.sqrt(xd * xd + yd * yd);
}
function weight(x1, y1, x2, y2) {
var d = distance(x1, y1, x2, y2);
return 1 / (d * d);
}
function multiply(x, y) {
return x * y;
}
function add(x, y) {
return x + y;
}
function vectorScale(v, m) {
return [v[0], v[1] * m];
}
function vectorAdd(a, b) {
var ax = Math.cos(a[0]) * a[1];
var ay = Math.sin(a[0]) * a[1];
var bx = Math.cos(b[0]) * b[1];
var by = Math.sin(b[0]) * b[1];
var cx = ax + bx;
var cy = ay + by;
var r = Math.atan2(cy, cx);
var m = Math.sqrt(cx * cx + cy * cy);
if (!isFinite(r)) {
r = 0;
}
return [r, m];
}
function f(x, y, initial, data, scale, add) {
var n = initial;
var d = 0;
for (var i = 0; i < data.length; i++) {
var sample = data[i];
var value = sample[2];
var w = weight(x, y, sample[0], sample[1]);
if (w === Number.POSITIVE_INFINITY) {
return value;
}
var s = scale(value, w);
n = add(n, s);
d += w;
}
return scale(n, 1 / d);
}
var c = fieldCanvas;
var g = c.getContext('2d');
function interpolateScalarField(sampleType) {
// d3.json("samples/2013/8/23/11", function(error, samples) {
d3.json("samples/current", function(error, samples) {
var values = [];
samples.forEach(function(sample) {
if (sample[sampleType]) {
values.push([sample.longitude * 1, sample.latitude * 1, sample[sampleType] * 1]);
}
});
var field = [];
var min = Number.POSITIVE_INFINITY;
var max = Number.NEGATIVE_INFINITY;
for (var x = width; x >= 350; x--) {
field[x] = [];
for (var y = height; y >= 150; y--) {
var p = projection.invert([x, y]);
var v = f(p[0], p[1], 0, values, multiply, add);
field[x][y] = v;
if (v < min) {
min = v;
}
if (v > max) {
max = v;
}
}
}
processScalarField(field, min, max);
});
function processScalarField(field, min, max) {
var styles = [];
for (var i = 0; i < 255; i += 1) {
styles.push('rgba(' + i + ', ' + i + ', ' + i + ', 0.6)');
}
var range = max - min;
for (var x = 350; x < width; x+=1) {
for (var y = 150; y < height; y+=1) {
if (fieldMask[x][y]) {
var v = field[x][y];
var style = styles[Math.floor((v-min)/range * (styles.length-1))];
g.fillStyle = style;
g.fillRect(x, y, 1, 1);
}
}
}
}
}
function interpolateVectorField() {
// 2013年8月24日16時
// 2013年8月22日19時
// 2013年8月21日22時
// 2013年8月21日17時
// 2013年8月21日16時
// 2013年8月21日15時
// 2013年8月20日22時
// 2013年8月20日21時 -- and each preceding hour...
// 2013年8月19日16時
// 2013年8月18日17時
// d3.json("samples/2013/8/24/16", function(error, samples) {
// d3.json("samples/2013/8/22/19", function(error, samples) {
// d3.json("samples/2013/8/21/22", function(error, samples) {
// d3.json("samples/2013/8/21/16", function(error, samples) {
// d3.json("samples/2013/8/21/15", function(error, samples) {
// d3.json("samples/2013/8/20/22", function(error, samples) {
// d3.json("samples/2013/8/20/21", function(error, samples) {
// d3.json("samples/2013/8/20/20", function(error, samples) {
// d3.json("samples/2013/8/20/19", function(error, samples) {
// d3.json("samples/2013/8/20/18", function(error, samples) {
// d3.json("samples/2013/8/19/16", function(error, samples) {
// d3.json("samples/2013/8/18/17", function(error, samples) {
// d3.json("samples/2013/8/17/17", function(error, samples) {
d3.json("samples/2013/8/16/15", function(error, samples) {
// d3.json("samples/2013/8/12/19", function(error, samples) {
// d3.json("samples/current", function(error, samples) {
// Convert cardinal (north origin, clockwise) to radians (counter-clockwise)
var vectors = [];
samples.forEach(function(sample) {
if (sample.wd && sample.wv) {
var r = sample.wd / 180 * π;
vectors.push([
sample.longitude * 1,
sample.latitude * 1,
[Math.atan2(Math.cos(r), Math.sin(r)), sample.wv * 1]]);
}
});
var field = [];
for (var x = width-1; x >= 0; x--) {
var column = field[x] = [];
for (var y = height-1; y >= 0; y--) {
if (fieldMask[x][y]) {
var p = projection.invert([x, y]);
var v = f(p[0], p[1], [0, 0], vectors, vectorScale, vectorAdd);
var r = v[0];
var m = v[1];
column[y] = [Math.cos(r + π) * m, -Math.sin(r + π) * m, m];
}
}
}
processVectorField(field);
});
function randomPoint() {
var x;
var y;
do {
x = Math.random() * (width - 1);
y = Math.random() * (height - 1);
} while (!fieldMask[Math.round(x)][Math.round(y)]);
return [x, y];
}
function processVectorField(field) {
for (var i = 0; i < 5000; i++) {
var p = randomPoint();
particles.push({
x: p[0],
y: p[1],
age: Math.floor(Math.random() * maxAge)
});
}
var styles = [];
for (var j = 150; j < 255; j += 1) {
styles.push('rgba(' + j + ', ' + j + ', ' + j + ', 1)');
}
var max = 17;
var min = 0;
var range = max - min;
draw();
function draw() {
var prev = g.globalCompositeOperation;
g.fillStyle = 'rgba(0, 0, 0, 0.8)';
g.globalCompositeOperation = "destination-in";
g.fillRect(0, 0, c.width, c.height);
g.globalCompositeOperation = prev;
g.lineWidth = 1;
g.beginPath();
particles.forEach(function(particle) {
if (particle.age > maxAge) {
particle.age = 0;
var p = randomPoint();
particle.x = p[0];
particle.y = p[1];
}
// get vector at current location
var x = particle.x;
var y = particle.y;
var fx = Math.round(x);
var fy = Math.round(y);
if (fx < field.length && field[fx] && fy < field[fx].length && field[fx][fy]) {
if (fx < fieldMask.length && fy < fieldMask[fx].length && fieldMask[fx][fy]) {
var v = field[fx][fy];
var xt = x + v[0] * 0.4;
var yt = y + v[1] * 0.4;
var style = styles[Math.floor((Math.min(v[2], max) - min) / range * (styles.length - 1))];
// g.fillStyle = style;
// g.fillRect(Math.round(xt), Math.round(yt), 1, 1);
g.strokeStyle = style;
g.moveTo(Math.round(x), Math.round(y));
g.lineTo(Math.round(xt), Math.round(yt));
}
particle.x = xt;
particle.y = yt;
}
particle.age += 1;
});
g.stroke();
if (!done) {
setTimeout(draw, 40);
}
}
}
}
</script>
</body>
</html>

457
public/topojson.v1.js Normal file
View File

@ -0,0 +1,457 @@
/*
* Downloaded from http://d3js.org/topojson.v1.js, 2013-08-20 16:37
*/
topojson = (function() {
function merge(topology, arcs) {
var fragmentByStart = {},
fragmentByEnd = {};
arcs.forEach(function(i) {
var e = ends(i),
start = e[0],
end = e[1],
f, g;
if (f = fragmentByEnd[start]) {
delete fragmentByEnd[f.end];
f.push(i);
f.end = end;
if (g = fragmentByStart[end]) {
delete fragmentByStart[g.start];
var fg = g === f ? f : f.concat(g);
fragmentByStart[fg.start = f.start] = fragmentByEnd[fg.end = g.end] = fg;
} else if (g = fragmentByEnd[end]) {
delete fragmentByStart[g.start];
delete fragmentByEnd[g.end];
var fg = f.concat(g.map(function(i) { return ~i; }).reverse());
fragmentByStart[fg.start = f.start] = fragmentByEnd[fg.end = g.start] = fg;
} else {
fragmentByStart[f.start] = fragmentByEnd[f.end] = f;
}
} else if (f = fragmentByStart[end]) {
delete fragmentByStart[f.start];
f.unshift(i);
f.start = start;
if (g = fragmentByEnd[start]) {
delete fragmentByEnd[g.end];
var gf = g === f ? f : g.concat(f);
fragmentByStart[gf.start = g.start] = fragmentByEnd[gf.end = f.end] = gf;
} else if (g = fragmentByStart[start]) {
delete fragmentByStart[g.start];
delete fragmentByEnd[g.end];
var gf = g.map(function(i) { return ~i; }).reverse().concat(f);
fragmentByStart[gf.start = g.end] = fragmentByEnd[gf.end = f.end] = gf;
} else {
fragmentByStart[f.start] = fragmentByEnd[f.end] = f;
}
} else if (f = fragmentByStart[start]) {
delete fragmentByStart[f.start];
f.unshift(~i);
f.start = end;
if (g = fragmentByEnd[end]) {
delete fragmentByEnd[g.end];
var gf = g === f ? f : g.concat(f);
fragmentByStart[gf.start = g.start] = fragmentByEnd[gf.end = f.end] = gf;
} else if (g = fragmentByStart[end]) {
delete fragmentByStart[g.start];
delete fragmentByEnd[g.end];
var gf = g.map(function(i) { return ~i; }).reverse().concat(f);
fragmentByStart[gf.start = g.end] = fragmentByEnd[gf.end = f.end] = gf;
} else {
fragmentByStart[f.start] = fragmentByEnd[f.end] = f;
}
} else if (f = fragmentByEnd[end]) {
delete fragmentByEnd[f.end];
f.push(~i);
f.end = start;
if (g = fragmentByEnd[start]) {
delete fragmentByStart[g.start];
var fg = g === f ? f : f.concat(g);
fragmentByStart[fg.start = f.start] = fragmentByEnd[fg.end = g.end] = fg;
} else if (g = fragmentByStart[start]) {
delete fragmentByStart[g.start];
delete fragmentByEnd[g.end];
var fg = f.concat(g.map(function(i) { return ~i; }).reverse());
fragmentByStart[fg.start = f.start] = fragmentByEnd[fg.end = g.start] = fg;
} else {
fragmentByStart[f.start] = fragmentByEnd[f.end] = f;
}
} else {
f = [i];
fragmentByStart[f.start = start] = fragmentByEnd[f.end = end] = f;
}
});
function ends(i) {
var arc = topology.arcs[i], p0 = arc[0], p1 = [0, 0];
arc.forEach(function(dp) { p1[0] += dp[0], p1[1] += dp[1]; });
return [p0, p1];
}
var fragments = [];
for (var k in fragmentByEnd) fragments.push(fragmentByEnd[k]);
return fragments;
}
function mesh(topology, o, filter) {
var arcs = [];
if (arguments.length > 1) {
var geomsByArc = [],
geom;
function arc(i) {
if (i < 0) i = ~i;
(geomsByArc[i] || (geomsByArc[i] = [])).push(geom);
}
function line(arcs) {
arcs.forEach(arc);
}
function polygon(arcs) {
arcs.forEach(line);
}
function geometry(o) {
if (o.type === "GeometryCollection") o.geometries.forEach(geometry);
else if (o.type in geometryType) {
geom = o;
geometryType[o.type](o.arcs);
}
}
var geometryType = {
LineString: line,
MultiLineString: polygon,
Polygon: polygon,
MultiPolygon: function(arcs) { arcs.forEach(polygon); }
};
geometry(o);
geomsByArc.forEach(arguments.length < 3
? function(geoms, i) { arcs.push(i); }
: function(geoms, i) { if (filter(geoms[0], geoms[geoms.length - 1])) arcs.push(i); });
} else {
for (var i = 0, n = topology.arcs.length; i < n; ++i) arcs.push(i);
}
return object(topology, {type: "MultiLineString", arcs: merge(topology, arcs)});
}
function featureOrCollection(topology, o) {
return o.type === "GeometryCollection" ? {
type: "FeatureCollection",
features: o.geometries.map(function(o) { return feature(topology, o); })
} : feature(topology, o);
}
function feature(topology, o) {
var f = {
type: "Feature",
id: o.id,
properties: o.properties || {},
geometry: object(topology, o)
};
if (o.id == null) delete f.id;
return f;
}
function object(topology, o) {
var tf = topology.transform,
kx = tf.scale[0],
ky = tf.scale[1],
dx = tf.translate[0],
dy = tf.translate[1],
arcs = topology.arcs;
function arc(i, points) {
if (points.length) points.pop();
for (var a = arcs[i < 0 ? ~i : i], k = 0, n = a.length, x = 0, y = 0, p; k < n; ++k) {
points.push(p = a[k].slice());
p[0] = (x += p[0]) * kx + dx;
p[1] = (y += p[1]) * ky + dy;
}
if (i < 0) reverse(points, n);
}
function point(p) {
p = p.slice();
p[0] = p[0] * kx + dx;
p[1] = p[1] * ky + dy;
return p;
}
function line(arcs) {
var points = [];
for (var i = 0, n = arcs.length; i < n; ++i) arc(arcs[i], points);
if (points.length < 2) points.push(points[0].slice());
return points;
}
function ring(arcs) {
var points = line(arcs);
while (points.length < 4) points.push(points[0].slice());
return points;
}
function polygon(arcs) {
return arcs.map(ring);
}
function geometry(o) {
var t = o.type;
return t === "GeometryCollection" ? {type: t, geometries: o.geometries.map(geometry)}
: t in geometryType ? {type: t, coordinates: geometryType[t](o)}
: null;
}
var geometryType = {
Point: function(o) { return point(o.coordinates); },
MultiPoint: function(o) { return o.coordinates.map(point); },
LineString: function(o) { return line(o.arcs); },
MultiLineString: function(o) { return o.arcs.map(line); },
Polygon: function(o) { return polygon(o.arcs); },
MultiPolygon: function(o) { return o.arcs.map(polygon); }
};
return geometry(o);
}
function reverse(array, n) {
var t, j = array.length, i = j - n; while (i < --j) t = array[i], array[i++] = array[j], array[j] = t;
}
function bisect(a, x) {
var lo = 0, hi = a.length;
while (lo < hi) {
var mid = lo + hi >>> 1;
if (a[mid] < x) lo = mid + 1;
else hi = mid;
}
return lo;
}
function neighbors(objects) {
var indexesByArc = {}, // arc index -> array of object indexes
neighbors = objects.map(function() { return []; });
function line(arcs, i) {
arcs.forEach(function(a) {
if (a < 0) a = ~a;
var o = indexesByArc[a];
if (o) o.push(i);
else indexesByArc[a] = [i];
});
}
function polygon(arcs, i) {
arcs.forEach(function(arc) { line(arc, i); });
}
function geometry(o, i) {
if (o.type === "GeometryCollection") o.geometries.forEach(function(o) { geometry(o, i); });
else if (o.type in geometryType) geometryType[o.type](o.arcs, i);
}
var geometryType = {
LineString: line,
MultiLineString: polygon,
Polygon: polygon,
MultiPolygon: function(arcs, i) { arcs.forEach(function(arc) { polygon(arc, i); }); }
};
objects.forEach(geometry);
for (var i in indexesByArc) {
for (var indexes = indexesByArc[i], m = indexes.length, j = 0; j < m; ++j) {
for (var k = j + 1; k < m; ++k) {
var ij = indexes[j], ik = indexes[k], n;
if ((n = neighbors[ij])[i = bisect(n, ik)] !== ik) n.splice(i, 0, ik);
if ((n = neighbors[ik])[i = bisect(n, ij)] !== ij) n.splice(i, 0, ij);
}
}
}
return neighbors;
}
function presimplify(topology, triangleArea) {
var heap = minHeap(compareArea),
maxArea = 0,
triangle;
if (!triangleArea) triangleArea = cartesianArea;
topology.arcs.forEach(function(arc) {
var triangles = [];
arc.forEach(transformAbsolute(topology.transform));
for (var i = 1, n = arc.length - 1; i < n; ++i) {
triangle = arc.slice(i - 1, i + 2);
triangle[1][2] = triangleArea(triangle);
triangles.push(triangle);
heap.push(triangle);
}
// Always keep the arc endpoints!
arc[0][2] = arc[n][2] = Infinity;
for (var i = 0, n = triangles.length; i < n; ++i) {
triangle = triangles[i];
triangle.previous = triangles[i - 1];
triangle.next = triangles[i + 1];
}
});
while (triangle = heap.pop()) {
var previous = triangle.previous,
next = triangle.next;
// If the area of the current point is less than that of the previous point
// to be eliminated, use the latter's area instead. This ensures that the
// current point cannot be eliminated without eliminating previously-
// eliminated points.
if (triangle[1][2] < maxArea) triangle[1][2] = maxArea;
else maxArea = triangle[1][2];
if (previous) {
previous.next = next;
previous[2] = triangle[2];
update(previous);
}
if (next) {
next.previous = previous;
next[0] = triangle[0];
update(next);
}
}
topology.arcs.forEach(function(arc) {
arc.forEach(transformRelative(topology.transform));
});
function update(triangle) {
heap.remove(triangle);
triangle[1][2] = triangleArea(triangle);
heap.push(triangle);
}
return topology;
};
function cartesianArea(triangle) {
return Math.abs(
(triangle[0][0] - triangle[2][0]) * (triangle[1][1] - triangle[0][1])
- (triangle[0][0] - triangle[1][0]) * (triangle[2][1] - triangle[0][1])
);
}
function compareArea(a, b) {
return a[1][2] - b[1][2];
}
function minHeap(compare) {
var heap = {},
array = [];
heap.push = function() {
for (var i = 0, n = arguments.length; i < n; ++i) {
var object = arguments[i];
up(object.index = array.push(object) - 1);
}
return array.length;
};
heap.pop = function() {
var removed = array[0],
object = array.pop();
if (array.length) {
array[object.index = 0] = object;
down(0);
}
return removed;
};
heap.remove = function(removed) {
var i = removed.index,
object = array.pop();
if (i !== array.length) {
array[object.index = i] = object;
(compare(object, removed) < 0 ? up : down)(i);
}
return i;
};
function up(i) {
var object = array[i];
while (i > 0) {
var up = ((i + 1) >> 1) - 1,
parent = array[up];
if (compare(object, parent) >= 0) break;
array[parent.index = i] = parent;
array[object.index = i = up] = object;
}
}
function down(i) {
var object = array[i];
while (true) {
var right = (i + 1) << 1,
left = right - 1,
down = i,
child = array[down];
if (left < array.length && compare(array[left], child) < 0) child = array[down = left];
if (right < array.length && compare(array[right], child) < 0) child = array[down = right];
if (down === i) break;
array[child.index = i] = child;
array[object.index = i = down] = object;
}
}
return heap;
}
function transformAbsolute(transform) {
var x0 = 0,
y0 = 0,
kx = transform.scale[0],
ky = transform.scale[1],
dx = transform.translate[0],
dy = transform.translate[1];
return function(point) {
point[0] = (x0 += point[0]) * kx + dx;
point[1] = (y0 += point[1]) * ky + dy;
};
}
function transformRelative(transform) {
var x0 = 0,
y0 = 0,
kx = transform.scale[0],
ky = transform.scale[1],
dx = transform.translate[0],
dy = transform.translate[1];
return function(point) {
var x1 = (point[0] - dx) / kx | 0,
y1 = (point[1] - dy) / ky | 0;
point[0] = x1 - x0;
point[1] = y1 - y0;
x0 = x1;
y0 = y1;
};
}
return {
version: "1.3.0",
mesh: mesh,
feature: featureOrCollection,
neighbors: neighbors,
presimplify: presimplify
};
})();

View File

@ -18,7 +18,9 @@ var stationsTable = {
columns: [
{name: 'id', type: 'INTEGER', modifier: 'NOT NULL', description: 'station id'},
{name: 'name', type: 'TEXT', description: 'station name'},
{name: 'address', type: 'TEXT', description: 'station location'}
{name: 'address', type: 'TEXT', description: 'station location'},
{name: 'latitude', type: 'NUMERIC(9, 6)', description: 'latitude'},
{name: 'longitude', type: 'NUMERIC(9, 6)', description: 'longitude'}
],
primary: {name: 'stations_PK', columns: ['id']}
}
@ -207,7 +209,14 @@ function doStationDetails() {
statements.push(db.upsert(stationsTable, {id: stationNames[name], name: name}));
});
stationsData.forEach(function(station) {
statements.push(db.upsert(stationsTable, {id: station[0], name: station[1], address: station[2]}));
var row = {
id: station[0],
name: station[1],
address: station[2],
latitude: station[3],
longitude: station[4]
};
statements.push(db.upsert(stationsTable, row));
});
return persist(statements);
}
@ -241,5 +250,9 @@ function doP160Historical(hours) {
start()
.then(doP160.bind(undefined, null))
.then(doStationDetails)
.then(doP160Historical.bind(undefined, 0 /*9 * 24*/)) // up to nine days of historical data available
.then(doP160Historical.bind(undefined, 0/*9 * 24*/)) // up to nine days of historical data available
.then(null, console.error);
//setInterval(function update() {
// doP160(null).then(null, console.error);
//}, 10 * 60 * 1000); // update every ten minutes

View File

@ -1,84 +1,84 @@
[
[101, "千代田区神田司町", "千代田区神田司町2-2"],
[102, "中央区晴海", "中央区晴海3-6-1"],
[103, "港区高輪", "港区高輪1-6"],
[104, "国設東京新宿", "新宿区内藤町11"],
[105, "文京区本駒込", "文京区本駒込4-35-15"],
[106, "江東区大島", "江東区大島3-1-3"],
[107, "品川区豊町", "品川区豊町2-1-20"],
[108, "目黒区碑文谷", "目黒区碑文谷4-19-25"],
[109, "大田区東糀谷", "大田区東糀谷1-21-15"],
[110, "世田谷区世田谷", "世田谷区世田谷4-21-27"],
[111, "渋谷区字田川町", "渋谷区字田川町1-1"],
[112, "中野区若宮", "中野区若宮3-53"],
[113, "杉並区久我山", "杉並区久我山5-36-17"],
[114, "荒川区南千住", "荒川区南千住1-4-11"],
[115, "板橋区本町", "板橋区本町24-1"],
[116, "練馬区石神井町", "練馬区石神井町5-24地先"],
[117, "練馬区北町", "練馬区北町1-14-11"],
[118, "足立区西新井", "足立区西新井6-21-3"],
[119, "葛飾区鎌倉", "葛飾区鎌倉2-21-4"],
[120, "江戸川区鹿骨", "江戸川区鹿骨1-15-1"],
[122, "立川市泉町", "立川市泉町1156-9"],
[123, "武蔵野市関前", "武蔵野市関前3-2-20"],
[124, "青梅市東青梅", "青梅市東青梅1-11-1"],
[125, "府中市宮西町", "府中市宮西町2-24"],
[126, "調布市深大寺南町", "調布市深大寺南町4-16-23"],
[127, "町田市金森", "町田市金森1-22"],
[128, "小金井市本町", "小金井市本町6-6-3"],
[129, "小平市小川町", "小平市小川町2-1325"],
[130, "西東京市田無町", "西東京市田無町4-15-11"],
[131, "福生市本町", "福生市本町5"],
[132, "狛江市中和泉", "狛江市中和泉3-4-10"],
[133, "東大和市奈良橋", "東大和市奈良橋4-573"],
[134, "清瀬市上清戸", "清瀬市上清戸2-6-41"],
[135, "多摩市愛宕", "多摩市愛宕1-65-1"],
[136, "港区台場", "港区台場1-3-1"],
[137, "練馬区練馬", "練馬区練馬2-27-28"],
[138, "江戸川区春江町", "江戸川区春江町5-3-3"],
[139, "西東京市下保谷", "西東京市下保谷1-4"],
[140, "江戸川区南葛西", "江戸川区南葛西1-11-1"],
[141, "葛飾区水元公園", "葛飾区水元公園3-2"],
[142, "世田谷区成城", "世田谷区成城9-25-1"],
[143, "足立区綾瀬", "足立区綾瀬6-23"],
[144, "町田市能ケ谷", "町田市能ケ谷7-24-1"],
[145, "品川区八潮", "品川区八潮5-11-17"],
[146, "八王子市片倉町", "八王子市片倉町553"],
[148, "八王子市館町", "八王子市館町1097-66"],
[149, "八王子市大楽寺町", "八王子市大楽寺町419-1"],
[201, "日比谷交差点", "干代田区日比谷公園1-6"],
[206, "明治通り大関横丁", "台東区三輪2-5地先"],
[208, "京葉道路亀戸", "江東区亀戸7-42-17"],
[209, "三ツ目通り辰巳", "江東区辰巳1-9地先"],
[210, "北品川交差点", "品川区北品川3-11-22"],
[211, "中原口交差点", "品川区西五反田7-25-1"],
[212, "山手通り大坂橋", "目黒区青葉合3-6"],
[213, "環七通り柿の木坂", "目黒区柿の木坂1-1-4"],
[215, "環七通り松原橋", "大田区中馬込2-17地先"],
[216, "玉川通り上馬", "世田谷区上馬4-1-3"],
[217, "甲州街道大原", "渋谷区笹塚1-64-19"],
[224, "中山道大和町", "板椅区大和町14-12"],
[226, "日光街道梅島", "足立区中央本町1-17"],
[229, "五日市街道武蔵境", "武蔵野市関前5-21"],
[231, "新青梅街道東村山", "東村山市本町1-10先"],
[232, "甲州街道国立", "国立市谷保6208"],
[234, "環八通り八幡山", "世田谷区粕谷2-19"],
[236, "東京環状長岡", "西多摩郡瑞穂町長岡1-10"],
[237, "青梅街道柳沢", "西東京市柳沢2-18"],
[241, "第一京浜高輪", "港区高輪2-20"],
[242, "連雀通り下連雀", "三鷹市下連雀7-15-4"],
[243, "北本通り王子", "北区王子5-20先"],
[244, "水戸街道東向島", "墨田区東向島1-34-5"],
[245, "早稲田通り下井草", "杉並区下井草4-3-29"],
[246, "川崎街道百草園", "日野市落川946"],
[247, "小金井街道東久留米", "東久留米市中央町6-8-1"],
[248, "永代通り新川", "中央区新川1-3-1"],
[249, "新目白通り下落合", "新宿区下落合2-2地先"],
[250, "環七通り亀有", "葛飾区亀有2-75-1"],
[251, "甲州街道八木町", "八王子市八木町8"],
[252, "中原街道南千束", "大田区南千束1-33-1"],
[254, "春日通り大塚", "文京区大塚3-5-1"],
[255, "明治通り西巣鴨", "豊島区西巣鴨2-39-5"],
[256, "山手通り東中野", "中野区中央2-18-21"],
[257, "環八通り千鳥", "大田区千烏三町目3-31先"]
[101, "千代田区神田司町", "千代田区神田司町2-2", 35.692752, 139.768119],
[102, "中央区晴海", "中央区晴海3-6-1", 35.656316, 139.779176],
[103, "港区高輪", "港区高輪1-6", 35.642334, 139.73536],
[104, "国設東京新宿", "新宿区内藤町11", 35.687139, 139.710632],
[105, "文京区本駒込", "文京区本駒込4-35-15", 35.73338, 139.755093],
[106, "江東区大島", "江東区大島3-1-3", 35.689954, 139.82767],
[107, "品川区豊町", "品川区豊町2-1-20", 35.610754, 139.720987],
[108, "目黒区碑文谷", "目黒区碑文谷4-19-25", 35.619685, 139.682482],
[109, "大田区東糀谷", "大田区東糀谷1-21-15", 35.557402, 139.739667],
[110, "世田谷区世田谷", "世田谷区世田谷4-21-27", 35.645974, 139.6529],
[111, "渋谷区宇田川町", "渋谷区宇田川町1-1", 35.663934, 139.697942],
[112, "中野区若宮", "中野区若宮3-53", 35.719229, 139.641002],
[113, "杉並区久我山", "杉並区久我山5-36-17", 35.690483, 139.602224],
[114, "荒川区南千住", "荒川区南千住1-4-11", 35.73311, 139.789178],
[115, "板橋区本町", "板橋区本町24-1", 35.759573, 139.708153],
[116, "練馬区石神井町", "練馬区石神井町5-24地先", 35.737739, 139.599098],
[117, "練馬区北町", "練馬区北町1-14-11", 35.76534, 139.664243],
[118, "足立区西新井", "足立区西新井6-21-3", 35.780151, 139.776423],
[119, "葛飾区鎌倉", "葛飾区鎌倉2-21-4", 35.744475, 139.877474],
[120, "江戸川区鹿骨", "江戸川区鹿骨1-15-1", 35.708978, 139.885077],
[122, "立川市泉町", "立川市泉町1156-9", 35.714, 139.407887],
[123, "武蔵野市関前", "武蔵野市関前3-2-20", 35.71285, 139.556187],
[124, "青梅市東青梅", "青梅市東青梅1-11-1", 35.787854, 139.275848],
[125, "府中市宮西町", "府中市宮西町2-24", 35.669055, 139.478125],
[126, "調布市深大寺南町", "調布市深大寺南町4-16-23", 35.666414, 139.554582],
[127, "町田市金森", "町田市金森1-22", 35.535725, 139.450539],
[128, "小金井市本町", "小金井市本町6-6-3", 35.699474, 139.503048],
[129, "小平市小川町", "小平市小川町2-1325", 35.727776, 139.476591],
[130, "西東京市田無町", "西東京市田無町4-15-11", 35.728033, 139.534432],
[131, "福生市本町", "福生市本町5", 35.738429, 139.326945],
[132, "狛江市中和泉", "狛江市中和泉3-4-10", 35.635155, 139.570445],
[133, "東大和市奈良橋", "東大和市奈良橋4-573", 35.751654, 139.425794],
[134, "清瀬市上清戸", "清瀬市上清戸2-6-41", 35.779903, 139.521115],
[135, "多摩市愛宕", "多摩市愛宕1-65-1", 35.634933, 139.4325],
[136, "港区台場", "港区台場1-3-1", 35.632454, 139.778513],
[137, "練馬区練馬", "練馬区練馬2-27-28", 35.743023, 139.651975],
[138, "江戸川区春江町", "江戸川区春江町5-3-3", 35.681928, 139.877188],
[139, "西東京市下保谷", "西東京市下保谷1-4", 35.749968, 139.557974],
[140, "江戸川区南葛西", "江戸川区南葛西1-11-1", 35.653665, 139.870805],
[141, "葛飾区水元公園", "葛飾区水元公園3-2", 35.786401, 139.869274],
[142, "世田谷区成城", "世田谷区成城9-25-1", 35.651673, 139.595416],
[143, "足立区綾瀬", "足立区綾瀬6-23", 35.769878, 139.82582],
[144, "町田市能ケ谷", "町田市能ケ谷7-24-1", 35.591859, 139.481654],
[145, "品川区八潮", "品川区八潮5-11-17", 35.600814, 139.75275],
[146, "八王子市片倉町", "八王子市片倉町553", 35.64496, 139.339888],
[148, "八王子市館町", "八王子市館町1097-66", 35.627083, 139.28757],
[149, "八王子市大楽寺町", "八王子市大楽寺町419-1", 35.671391, 139.293068],
[201, "日比谷交差点", "千代田区日比谷公園1-6", 35.674834, 139.755746],
[206, "明治通り大関横丁", "台東区三輪2-5地先", 35.729258, 139.793295],
[208, "京葉道路亀戸", "江東区亀戸7-42-17", 35.696933, 139.835931],
[209, "三ツ目通り辰巳", "江東区辰巳1-9地先", 35.649816, 139.810412],
[210, "北品川交差点", "品川区北品川3-11-22", 35.616558, 139.740707],
[211, "中原口交差点", "品川区西五反田7-25-1", 35.620474, 139.71911],
[212, "山手通り大坂橋", "目黒区青葉台3-6", 35.652349, 139.69063],
[213, "環七通り柿の木坂", "目黒区柿の木坂1-1-4", 35.623241, 139.679121],
[215, "環七通り松原橋", "大田区中馬込2-17地先", 35.59621, 139.709849],
[216, "玉川通り上馬", "世田谷区上馬4-1-3", 35.635343, 139.663983],
[217, "甲州街道大原", "渋谷区笹塚1-64-19", 35.672572, 139.661566],
[224, "中山道大和町", "板橋区大和町14-12", 35.761, 139.705404],
[226, "日光街道梅島", "足立区中央本町1-17", 35.77489, 139.804383],
[229, "五日市街道武蔵境", "武蔵野市関前5-21", 35.711178, 139.538903],
[231, "新青梅街道東村山", "東村山市本町1-10先", 35.752694, 139.466065],
[232, "甲州街道国立", "国立市谷保6208", 35.682151, 139.43226],
[234, "環八通り八幡山", "世田谷区粕谷2-19", 35.665816, 139.613039],
[236, "東京環状長岡", "西多摩郡瑞穂町長岡1-10", 35.775556, 139.336048],
[237, "青梅街道柳沢", "西東京市柳沢2-18", 35.724919, 139.553215],
[241, "第一京浜高輪", "港区高輪2-20", 35.637514, 139.739849],
[242, "連雀通り下連雀", "三鷹市下連雀7-15-4", 35.692465, 139.560983],
[243, "北本通り王子", "北区王子5-20先", 35.766331, 139.735941],
[244, "水戸街道東向島", "墨田区東向島1-34-5", 35.720156, 139.815391],
[245, "早稲田通り下井草", "杉並区下井草4-3-29", 35.719475, 139.619868],
[246, "川崎街道百草園", "日野市落川946", 35.65615, 139.432919],
[247, "小金井街道東久留米", "東久留米市中央町6-8-1", 35.753456, 139.515847],
[248, "永代通り新川", "中央区新川1-3-1", 35.678908, 139.781678],
[249, "新目白通り下落合", "新宿区下落合2-2地先", 35.716683, 139.703896],
[250, "環七通り亀有", "葛飾区亀有2-75-1", 35.760885, 139.853105],
[251, "甲州街道八木町", "八王子市八木町8", 35.661655, 139.320121],
[252, "中原街道南千束", "大田区南千束1-33-1", 35.601843, 139.692894],
[254, "春日通り大塚", "文京区大塚3-5-1", 35.719327, 139.734729],
[255, "明治通り西巣鴨", "豊島区西巣鴨2-39-5", 35.741904, 139.726237],
[256, "山手通り東中野", "中野区中央2-18-21", 35.700383, 139.682466],
[257, "環八通り千鳥", "大田区千鳥三丁目3-31先", 35.573147, 139.686532]
]

13
test/test.js Normal file
View File

@ -0,0 +1,13 @@
'use strict';
var _ = require('underscore');
var util = require('util');
var when = require('when');
var d3 = require('d3');
var topojson = require('topojson');
var fs = require('fs');
var tool = require('../tool');
exports.testSomething = function(test) {
test.done();
}