parent
4575df5e59
commit
86f4cafca5
14 changed files with 498 additions and 458 deletions
@ -1 +1,3 @@ |
||||
natural-earth |
||||
experiments |
||||
d3.min.js |
||||
node_modules |
||||
|
@ -1,39 +0,0 @@ |
||||
var file = 'natural-earth/california.geojson'; |
||||
|
||||
d3.json(file, function(error, mapJson) { |
||||
|
||||
var projection = |
||||
d3.geo.mercator() |
||||
.center([-122, 38]) |
||||
.scale(1960) |
||||
.translate([w / 2, h / 2]); |
||||
|
||||
var path = d3.geo.path().projection(projection); |
||||
|
||||
svg.selectAll('.subunit') |
||||
.data(mapJson.features) |
||||
.enter().append('path') |
||||
.attr('d', path) |
||||
.attr('stroke', 'lime'); |
||||
|
||||
var buoys = []; |
||||
buoys.push(projection([-122.634, 37.786])); |
||||
buoys.push(projection([-122.839, 37.755])); |
||||
buoys.push(projection([-122.977, 37.996])); |
||||
|
||||
svg.selectAll('.buoy') |
||||
.data(buoys) |
||||
.enter().append('circle') |
||||
.attr('cx', function(d) { return d[0]; }) |
||||
.attr('cy', function(d) { return d[1]; }) |
||||
.attr('r', 5) |
||||
.attr('fill', 'crimson'); |
||||
}); |
||||
|
||||
var w = 450; |
||||
var h = 450; |
||||
|
||||
var svg = d3.select("body").append("svg") |
||||
.attr("style", "border:1px solid lime") |
||||
.attr("width", w) |
||||
.attr("height", h); |
File diff suppressed because one or more lines are too long
@ -1,155 +0,0 @@ |
||||
'use strict'; |
||||
|
||||
/** |
||||
* |
||||
*/ |
||||
function Point(x, y, name, hex) { |
||||
if (typeof x !== typeof 1) { |
||||
throw new Error("x = " + x + " must be of type 'number'; it is currently of type '" + (typeof x) + "'."); |
||||
} |
||||
|
||||
if (typeof y !== typeof 1) { |
||||
throw new Error("y = " + y + " must be of type 'number'; it is currently of type '" + (typeof y) + "'."); |
||||
} |
||||
|
||||
if (x < 0 || y < 0) { |
||||
throw new Error("X and Y must be greater than 0."); |
||||
} |
||||
|
||||
this.x = x; |
||||
this.y = y; |
||||
this.name = name; |
||||
this.hex = hex; |
||||
} |
||||
|
||||
/** |
||||
* |
||||
*/ |
||||
function Triangle(a, b, c) { |
||||
if (!(a instanceof Point) || !(b instanceof Point) || !(c instanceof Point)) { |
||||
throw new Error("All three arguments must be of type Point."); |
||||
} |
||||
|
||||
this.a = a; |
||||
this.b = b; |
||||
this.c = c; |
||||
} |
||||
|
||||
/** |
||||
* |
||||
*/ |
||||
Triangle.prototype = { |
||||
/** |
||||
* |
||||
*/ |
||||
findMidpoint: function(p1, p2) { |
||||
var minX = Math.min(p1.x, p2.x); |
||||
var maxX = Math.max(p1.x, p2.x); |
||||
var minY = Math.min(p1.y, p2.y); |
||||
var maxY = Math.max(p1.y, p2.y); |
||||
|
||||
var midX = minX + ((maxX - minX) / 2); |
||||
var midY = minY + ((maxY - minY) / 2); |
||||
|
||||
return new Point(midX, midY); |
||||
}, |
||||
|
||||
/** |
||||
* |
||||
*/ |
||||
buildGradient: function(p) { |
||||
var opp1, opp2; |
||||
|
||||
if (p === this.a) { |
||||
opp1 = this.b; |
||||
opp2 = this.c; |
||||
} |
||||
|
||||
if (p === this.b) { |
||||
opp1 = this.a; |
||||
opp2 = this.c; |
||||
} |
||||
|
||||
if (p === this.c) { |
||||
opp1 = this.a; |
||||
opp2 = this.b; |
||||
} |
||||
|
||||
var fill = d3.select(document.createElementNS(d3.ns.prefix.svg, "linearGradient")) |
||||
.attr("gradientUnits", "userSpaceOnUse") |
||||
.attr("id", `fill${p.name}`) |
||||
.attr("x1", p.x) |
||||
.attr("y1", p.y) |
||||
.attr("x2", this.findMidpoint(opp1, opp2).x) |
||||
.attr("y2", this.findMidpoint(opp1, opp2).y) |
||||
|
||||
fill.append("stop") |
||||
.attr("offset", "0%") |
||||
.attr("stop-color", p.hex) |
||||
|
||||
fill.append("stop") |
||||
.attr("offset", "100%") |
||||
.attr("stop-color", "#fff") |
||||
.attr("stop-opacity", "0") |
||||
|
||||
return function() { |
||||
return fill.node(); |
||||
}; |
||||
}, |
||||
|
||||
/** |
||||
* |
||||
*/ |
||||
buildPath: function(p) { |
||||
var path = d3.select(document.createElementNS(d3.ns.prefix.svg, "path")) |
||||
.attr("d", `M${this.a.x},${this.a.y} L${this.b.x},${this.b.y} L${this.c.x},${this.c.y} Z`) |
||||
.attr("fill", `url(#fill${p.name})`) |
||||
|
||||
return function() { |
||||
return path.node(); |
||||
}; |
||||
} |
||||
}; |
||||
|
||||
/** |
||||
* |
||||
*/ |
||||
(function() { |
||||
var svg = d3.select("body").append("svg") |
||||
.attr("width", 500) |
||||
.attr("height", 500); |
||||
|
||||
var defs = svg.append("defs"); |
||||
|
||||
var points = [ |
||||
[ |
||||
new Point(100, 0, 'A1', '#f00'), |
||||
new Point(200, 200, 'B1', '#0f0'), |
||||
new Point(0, 200, 'C1', '#00f') |
||||
], |
||||
|
||||
[ |
||||
new Point(100, 0, 'A2', '#f00'), |
||||
new Point(200, 200, 'B2', '#0f0'), |
||||
new Point(300, 0, 'C2', '#00f') |
||||
], |
||||
|
||||
[ |
||||
new Point(300, 300, 'A3', '#f00'), |
||||
new Point(300, 0, 'C3', '#00f'), |
||||
new Point(200, 200, 'B3', '#0f0'), |
||||
], |
||||
]; |
||||
|
||||
for (var i = 0, len = points.length; i < len; i++) { |
||||
var T = new Triangle(points[i][0], points[i][1], points[i][2]); |
||||
|
||||
defs.append(T.buildGradient(points[i][0])); |
||||
defs.append(T.buildGradient(points[i][1])); |
||||
defs.append(T.buildGradient(points[i][2])); |
||||
|
||||
svg.append(T.buildPath(points[i][0])); |
||||
svg.append(T.buildPath(points[i][1])); |
||||
svg.append(T.buildPath(points[i][2])); |
||||
} |
||||
}()); |
@ -1,184 +0,0 @@ |
||||
'use strict'; |
||||
|
||||
/** |
||||
* |
||||
*/ |
||||
function Point(x, y, hex) { |
||||
if (typeof x !== typeof 1) { |
||||
throw new Error("x = " + x + " must be of type 'number'; it is currently of type '" + (typeof x) + "'."); |
||||
} |
||||
|
||||
if (typeof y !== typeof 1) { |
||||
throw new Error("y = " + y + " must be of type 'number'; it is currently of type '" + (typeof y) + "'."); |
||||
} |
||||
|
||||
if (x < 0 || y < 0) { |
||||
throw new Error("X and Y must be greater than 0."); |
||||
} |
||||
|
||||
this.x = x; |
||||
this.y = y; |
||||
this.hex = hex; |
||||
} |
||||
|
||||
/** |
||||
* |
||||
*/ |
||||
function Triangle(p1, p2, p3) { |
||||
if (!(p1 instanceof Point) || !(p2 instanceof Point) || !(p3 instanceof Point)) { |
||||
throw new Error("All three arguments must be of type Point."); |
||||
} |
||||
|
||||
this.vertexA = p1; |
||||
this.vertexB = p2; |
||||
this.vertexC = p3; |
||||
|
||||
// Midpoints on each edge.
|
||||
this.midpointAB = this.findMidpoint(this.vertexA, this.vertexB); |
||||
this.midpointAC = this.findMidpoint(this.vertexA, this.vertexC); |
||||
this.midpointBC = this.findMidpoint(this.vertexB, this.vertexC); |
||||
|
||||
// Midpoints of segments between midpoints.
|
||||
this.midpointABAC = this.findMidpoint(this.midpointAB, this.midpointAC); |
||||
this.midpointABBC = this.findMidpoint(this.midpointAB, this.midpointBC); |
||||
this.midpointACBC = this.findMidpoint(this.midpointAC, this.midpointBC); |
||||
|
||||
// Paths created from a vertex and the midpoints on its two adjacent edges.
|
||||
this.subpathA = [this.vertexA, this.midpointAB, this.midpointAC]; |
||||
this.subpathB = [this.vertexB, this.midpointAB, this.midpointBC]; |
||||
this.subpathC = [this.vertexC, this.midpointAC, this.midpointBC]; |
||||
} |
||||
|
||||
/** |
||||
* |
||||
*/ |
||||
Triangle.prototype = { |
||||
/** |
||||
* |
||||
*/ |
||||
findMidpoint: function(p1, p2) { |
||||
var minX = Math.min(p1.x, p2.x); |
||||
var maxX = Math.max(p1.x, p2.x); |
||||
var minY = Math.min(p1.y, p2.y); |
||||
var maxY = Math.max(p1.y, p2.y); |
||||
|
||||
var midX = minX + ((maxX - minX) / 2); |
||||
var midY = minY + ((maxY - minY) / 2); |
||||
|
||||
return new Point(midX, midY); |
||||
}, |
||||
|
||||
|
||||
/** |
||||
* |
||||
*/ |
||||
buildPath: function(p1, p2, p3, fill) { |
||||
var path = d3.select(document.createElementNS(d3.ns.prefix.svg, "path")) |
||||
.attr("d", `M${p1.x},${p1.y} L${p2.x},${p2.y} L${p3.x},${p3.y} Z`) |
||||
// .attr("stroke", "#000")
|
||||
|
||||
var hex = /^#[\da-f]{3}$|^#[\da-f]{6}$/i; |
||||
|
||||
if (fill !== undefined) { |
||||
if (fill.match(hex)) { |
||||
path.attr("fill", fill).attr("stroke", fill); |
||||
} |
||||
else { |
||||
path.attr("fill", `url(#${fill})`) |
||||
// .attr("stroke", `url(#${fill})`);
|
||||
} |
||||
} |
||||
|
||||
return function() { |
||||
return path.node(); |
||||
}; |
||||
}, |
||||
|
||||
/** |
||||
* |
||||
*/ |
||||
buildGradient: function(p1, p2, id, hex) { |
||||
var fill = d3.select(document.createElementNS(d3.ns.prefix.svg, "linearGradient")) |
||||
.attr("gradientUnits", "userSpaceOnUse") |
||||
.attr("id", id) |
||||
.attr("x1", p1.x) |
||||
.attr("y1", p1.y) |
||||
.attr("x2", p2.x) |
||||
.attr("y2", p2.y) |
||||
|
||||
fill.append("stop") |
||||
.attr("offset", "0%") |
||||
.attr("stop-color", hex) |
||||
|
||||
fill.append("stop") |
||||
.attr("offset", "100%") |
||||
.attr("stop-color", "#fff") |
||||
.attr("stop-opacity", "0") |
||||
|
||||
return function() { |
||||
return fill.node(); |
||||
}; |
||||
}, |
||||
}; |
||||
|
||||
/** |
||||
* |
||||
*/ |
||||
(function() { |
||||
var svg = d3.select("body").append("svg") |
||||
.attr("width", 500) |
||||
.attr("height", 500); |
||||
|
||||
var defs = svg.append("defs"); |
||||
|
||||
var points = [ |
||||
[ |
||||
new Point(100, 0, '#f00'), |
||||
new Point(200, 200, '#0f0'), |
||||
new Point(0, 300, '#00f') |
||||
] |
||||
|
||||
// [
|
||||
// new Point(100, 0, '#f00'),
|
||||
// new Point(200, 200, '#0f0'),
|
||||
// new Point(300, 0, '#00f')
|
||||
// ],
|
||||
|
||||
// [
|
||||
// new Point(300, 300, '#f00'),
|
||||
// new Point(200, 200, '#0f0'),
|
||||
// new Point(300, 0, '#00f')
|
||||
// ],
|
||||
]; |
||||
|
||||
var subpathA; |
||||
var subpathB; |
||||
var subpathC; |
||||
var subpathM1; |
||||
var subpathM2; |
||||
var subpathM3; |
||||
|
||||
for (var i = 0, len = points.length; i < len; i++) { |
||||
var T = new Triangle(points[i][0], points[i][1], points[i][2]); |
||||
|
||||
subpathA = T.buildPath(T.subpathA[0], T.subpathA[1], T.subpathA[2], points[i][0].hex); |
||||
subpathB = T.buildPath(T.subpathB[0], T.subpathB[1], T.subpathB[2], points[i][1].hex); |
||||
subpathC = T.buildPath(T.subpathC[0], T.subpathC[1], T.subpathC[2], points[i][2].hex); |
||||
|
||||
defs.append(T.buildGradient(T.midpointACBC, T.midpointBC, `fill-${i}-0`, points[i][0].hex)); |
||||
defs.append(T.buildGradient(T.midpointABBC, T.midpointAC, `fill-${i}-1`, points[i][1].hex)); |
||||
defs.append(T.buildGradient(T.midpointABAC, T.midpointAB, `fill-${i}-2`, points[i][2].hex)); |
||||
|
||||
subpathM1 = T.buildPath(T.midpointAB, T.midpointAC, T.midpointBC, `fill-${i}-0`); |
||||
subpathM2 = T.buildPath(T.midpointAB, T.midpointAC, T.midpointBC, `fill-${i}-1`); |
||||
subpathM3 = T.buildPath(T.midpointAB, T.midpointAC, T.midpointBC, `fill-${i}-2`); |
||||
|
||||
svg.append(subpathA); |
||||
svg.append(subpathB); |
||||
svg.append(subpathC); |
||||
|
||||
svg.append(subpathM1); |
||||
svg.append(subpathM2); |
||||
svg.append(subpathM3); |
||||
} |
||||
}()); |
@ -0,0 +1,47 @@ |
||||
var stations = require('./server/stations.js'); |
||||
var meteo = require('./server/meteorological.js'); |
||||
var Promise = require('es6-promise').Promise; |
||||
var chalk = require('chalk'); |
||||
|
||||
//===== Weather data scraper
|
||||
// var date = new Date();
|
||||
|
||||
var len = stations.stations.length; |
||||
|
||||
//===== Meteorological data scraping - careful!
|
||||
(function scrapeMeteo(currentStation) { |
||||
if (currentStation !== 0) { |
||||
console.log(chalk.cyan('=== Finished.\n')); |
||||
} |
||||
|
||||
if (currentStation >= len) { |
||||
// if (currentStation > 1) {
|
||||
return; |
||||
} |
||||
|
||||
var arr = []; |
||||
|
||||
console.log(chalk.cyan('\n=== (' + currentStation + ') Starting ' + stations.stations[currentStation])); |
||||
|
||||
// Monthly files
|
||||
// for (var m = 0; m < 12; m++) {
|
||||
// arr.push(meteo.getInconsistent(stations.stations[currentStation], m, 2015));
|
||||
// arr.push(meteo.getMonth(stations.stations[currentStation], m));
|
||||
// }
|
||||
|
||||
// TODO refactor to above format
|
||||
// TODO refactor station requests into promises format
|
||||
// for (var year = 1982; year < date.getFullYear() - 1; year++) {
|
||||
// getYear(stationIDs[i], year);
|
||||
// }
|
||||
|
||||
// getCurrent(stationIDs[i]);
|
||||
|
||||
// Wait for all to resolve, then recurse.
|
||||
Promise.all(arr).then(scrapeMeteo.bind(null, currentStation + 1)); |
||||
|
||||
})(0); |
||||
|
||||
//===== Station data scraping - shouldn't need to change often.
|
||||
// stations.downloadAllMetadata();
|
||||
// stations.parseAllMetadata();
|
@ -0,0 +1,47 @@ |
||||
'use strict' |
||||
|
||||
var http = require('http'); |
||||
var fs = require('fs'); |
||||
var Promise = require('es6-promise').Promise; |
||||
|
||||
module.exports = { |
||||
|
||||
downloadedCount: 0, |
||||
|
||||
downloadedSize: 0, |
||||
|
||||
/** |
||||
* |
||||
*/ |
||||
mkdir: function(path) { |
||||
try { |
||||
fs.mkdirSync(path); |
||||
} catch(e) { |
||||
if (e.code !== 'EEXIST'){ |
||||
console.log(e); |
||||
} |
||||
} |
||||
}, |
||||
|
||||
/** |
||||
* |
||||
*/ |
||||
download: function(url, filename) { |
||||
return new Promise(function(resolve, reject) { |
||||
var file = fs.createWriteStream(filename); |
||||
|
||||
http.get(url, function(response) { |
||||
var pipe = response.pipe(file); |
||||
|
||||
pipe.on('finish', function() { |
||||
module.exports.downloadedSize += pipe.bytesWritten; |
||||
module.exports.downloadedCount++; |
||||
|
||||
console.log(url + ' --> ' + filename + ' --> ' + pipe.bytesWritten + ' bytes | ' + module.exports.downloadedSize + ' bytes total | ' + module.exports.downloadedCount + ' file(s)'); |
||||
|
||||
resolve(pipe.bytesWritten); |
||||
}); |
||||
}); |
||||
}); |
||||
} |
||||
}; |
@ -0,0 +1,68 @@ |
||||
'use strict' |
||||
|
||||
var downloader = require('./downloader.js'); |
||||
var dir = 'data/meteorological/' |
||||
var Promise = require('es6-promise').Promise; |
||||
|
||||
module.exports = { |
||||
months: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], |
||||
|
||||
/** |
||||
* |
||||
*/ |
||||
getYear: function(buoy, yyyy) { |
||||
var filename = buoy + 'h' + yyyy + '.txt'; |
||||
|
||||
var url = 'http://www.ndbc.noaa.gov/view_text_file.php?'+ |
||||
'filename=' + filename + '.gz&dir=data/historical/stdmet/'; |
||||
|
||||
return downloader.download(url, dir + filename); |
||||
}, |
||||
|
||||
/** |
||||
* |
||||
*/ |
||||
getMonth: function(buoy, m, yyyy) { |
||||
var month = m + 1; |
||||
month = (month == 10 ? 'a' : month); |
||||
month = (month == 11 ? 'b' : month); |
||||
month = (month == 12 ? 'c' : month); |
||||
|
||||
var filename = buoy + month.toString() + yyyy + '.txt'; |
||||
|
||||
var url = 'http://www.ndbc.noaa.gov/view_text_file.php?' + |
||||
'filename=' + filename + '.gz&dir=data/stdmet/' + this.months[m] + '/'; |
||||
|
||||
var path = dir + buoy + '/'; |
||||
downloader.mkdir(path); |
||||
return downloader.download(url, path + filename); |
||||
}, |
||||
|
||||
/** |
||||
* |
||||
*/ |
||||
getCurrent: function(buoy) { |
||||
var filename = buoy + '.txt'; |
||||
|
||||
var url = 'http://www.ndbc.noaa.gov/data/realtime2/' + filename; |
||||
|
||||
return downloader.download(url, dir + filename); |
||||
}, |
||||
|
||||
/** |
||||
* |
||||
*/ |
||||
getInconsistent: function(buoy, m) { |
||||
var url = 'http://www.ndbc.noaa.gov/data/stdmet/' + this.months[m] + '/' + buoy + '.txt'; |
||||
|
||||
var month = m + 1; |
||||
month = (month == 10 ? 'a' : month); |
||||
month = (month == 11 ? 'b' : month); |
||||
month = (month == 12 ? 'c' : month); |
||||
|
||||
var path = dir + buoy + '/'; |
||||
downloader.mkdir(path); |
||||
|
||||
return downloader.download(url, path + buoy.toString() + month + '2015-newest.txt'); |
||||
} |
||||
}; |
@ -0,0 +1,132 @@ |
||||
'use strict' |
||||
|
||||
var fs = require('fs'); |
||||
var downloader = require('./downloader'); |
||||
var xml2js = require ('xml2js'); |
||||
var dir = 'data/stations/'; |
||||
|
||||
module.exports = { |
||||
/** |
||||
* Add station IDs here, A-Z 0-9 |
||||
*/ |
||||
stations: [ |
||||
'ANVC1', |
||||
'BDXC1', |
||||
'CECC1', |
||||
'CPXC1', |
||||
'HBYC1', |
||||
'ICAC1', |
||||
'NTBC1', |
||||
'PRYC1', |
||||
'PTGC1', |
||||
'46011', |
||||
'46012', |
||||
'46013', |
||||
'46014', |
||||
'46022', |
||||
'46025', |
||||
'46027', |
||||
'46028', |
||||
'46042', |
||||
'46053', |
||||
'46054', |
||||
'46092', |
||||
'46213', |
||||
'46214', |
||||
'46215', |
||||
'46216', |
||||
'46217', |
||||
'46221', |
||||
'46223', |
||||
'46225', |
||||
'46232', |
||||
'46234', |
||||
'46237', |
||||
'46239', |
||||
'46240', |
||||
'46242', |
||||
'46244', |
||||
'46253', |
||||
'46254', |
||||
'46256', |
||||
'46257' |
||||
], |
||||
|
||||
/** |
||||
* Downloads each station's data XML. |
||||
*/ |
||||
downloadAllMetadata: function() { |
||||
var len = this.stations.length; |
||||
var url; |
||||
|
||||
for (var i = 0; i < len; i++) { |
||||
url = 'http://www.ndbc.noaa.gov/get_observation_as_xml.php?station=' + this.stations[i]; |
||||
downloader.download(url, dir + this.stations[i] + '.txt'); |
||||
} |
||||
}, |
||||
|
||||
/** |
||||
* |
||||
*/ |
||||
parseAllMetadata: function() { |
||||
function done() { |
||||
if (data.length === len) { |
||||
fs.writeFile(outfile, data.join('\n'), function(err) { |
||||
if (err) { |
||||
throw new Error(err) |
||||
} |
||||
|
||||
console.log('Station data written to ' + outfile); |
||||
}); |
||||
} |
||||
}; |
||||
|
||||
function next() { |
||||
// Wait for other concurrent files to finish.
|
||||
if (count !== data.length) { |
||||
return; |
||||
} |
||||
|
||||
var concurrent = 3; |
||||
var tmp; |
||||
|
||||
for (var i = 0; i < concurrent; i++) { |
||||
tmp = count + i; |
||||
|
||||
if (tmp === len) { |
||||
break; |
||||
} |
||||
|
||||
// console.log(tmp + "(" + count + ")" + " reading " + dir + module.exports.stations[tmp] + '.txt');
|
||||
fs.readFile(dir + module.exports.stations[tmp] + '.txt', 'utf8', thenParse); |
||||
} |
||||
|
||||
count += concurrent; |
||||
}; |
||||
|
||||
function thenParse(err, xml) { |
||||
if (err) { |
||||
throw new Error(err) |
||||
} |
||||
|
||||
xml2js.parseString(xml, thenReport); |
||||
}; |
||||
|
||||
function thenReport(err, json) { |
||||
if (err) { |
||||
throw new Error(err) |
||||
} |
||||
|
||||
data.push(JSON.stringify(json.observation.$)); |
||||
next(); |
||||
done(); |
||||
}; |
||||
|
||||
var outfile = 'data-stations.json'; |
||||
var len = module.exports.stations.length; |
||||
var count = 0; |
||||
var data = []; |
||||
|
||||
next(); |
||||
}, |
||||
}; |
@ -0,0 +1,13 @@ |
||||
'use strict'; |
||||
|
||||
/** |
||||
* |
||||
*/ |
||||
function MeshFace(id, x, y, side) { |
||||
this.id = id; |
||||
this.x = x; |
||||
this.y = y; |
||||
this.side = side; |
||||
this.fill = '#fff'; |
||||
this.colors = []; |
||||
}; |
@ -0,0 +1,11 @@ |
||||
'use strict'; |
||||
|
||||
/** |
||||
* |
||||
*/ |
||||
function MeshSeed(x, y, fill, weight) { |
||||
this.x = x; |
||||
this.y = y; |
||||
this.fill = fill; |
||||
this.weight = weight; |
||||
}; |
@ -0,0 +1,102 @@ |
||||
'use strict'; |
||||
|
||||
(function() { |
||||
var mapFile = 'data/map.json'; |
||||
var stationsFile = 'data/stations.json'; |
||||
|
||||
var w = 450; |
||||
var h = 450; |
||||
var s = 25; |
||||
|
||||
var svg = d3.select("body").append("svg") |
||||
.attr("style", "border:1px solid lime") |
||||
.attr("width", w) |
||||
.attr("height", h); |
||||
|
||||
var projection = d3.geo.mercator() |
||||
.center([-122, 38]) |
||||
.scale(1960) |
||||
.translate([w / 2, h / 2]); |
||||
|
||||
/** |
||||
* |
||||
*/ |
||||
function drawMap() { |
||||
d3.json(mapFile, function(error, json) { |
||||
var path = d3.geo.path().projection(projection); |
||||
|
||||
svg.selectAll('.subunit') |
||||
.data(json.features) |
||||
.enter().append('path') |
||||
.attr('d', path) |
||||
.attr('stroke', 'lime'); |
||||
}); |
||||
}; |
||||
|
||||
/** |
||||
* |
||||
*/ |
||||
function drawStations() { |
||||
function randomColor() { |
||||
var hexes = ['#ff0000', '#ffff00', '#ff00ff', '#00ffff', '#0000ff', '#00ff00']; |
||||
var random = Math.floor(Math.random() * hexes.length); |
||||
return hexes[random]; |
||||
}; |
||||
|
||||
d3.json(stationsFile, function(error, json) { |
||||
var tmp; |
||||
var zzz = -1; |
||||
|
||||
json.stations.forEach(function(station) { |
||||
// console.log(station);
|
||||
|
||||
tmp = projection([station.lon, station.lat]); |
||||
station.x = tmp[0]; |
||||
station.y = tmp[1]; |
||||
|
||||
if (zzz === -1) { |
||||
zzz = 0 |
||||
mesh.addSeed(new MeshSeed(tmp[0], tmp[1], randomColor(), mesh.seedWeight), faces); |
||||
} |
||||
}); |
||||
|
||||
drawMesh(); |
||||
|
||||
svg.selectAll('.station') |
||||
.data(json.stations) |
||||
.enter().append('circle') |
||||
.attr('cx', function(d) { return d.x; }) |
||||
.attr('cy', function(d) { return d.y; }) |
||||
.attr('r', 5) |
||||
.attr('fill', 'crimson'); |
||||
}); |
||||
}; |
||||
|
||||
/** |
||||
* |
||||
*/ |
||||
function drawMesh() { |
||||
mesh.calculateFills(faces); |
||||
|
||||
svg.selectAll('rect') |
||||
.data(faces) |
||||
.enter() |
||||
.append('rect') |
||||
.attr('id', function(d) { return d.id; }) |
||||
.attr('x', function(d) { return d.x; }) |
||||
.attr('y', function(d) { return d.y; }) |
||||
.attr('width', function(d) { return d.side; }) |
||||
.attr('height', function(d) { return d.side; }) |
||||
.attr('fill', function(d) { return d.fill; }) |
||||
// .attr('stroke', '#aaa')
|
||||
|
||||
drawMap(); |
||||
}; |
||||
|
||||
var mesh = new Mesh(w, h, s); |
||||
var faces = mesh.initFaces(w, h, s); |
||||
|
||||
// TODO update to promise chain
|
||||
// TODO add render type to mesh
|
||||
drawStations(); |
||||
})(); |
Loading…
Reference in new issue