Data retrieval for station meta and 2015 station data.

master
ben-burlingham 10 years ago
parent 4575df5e59
commit 86f4cafca5
  1. 4
      .gitignore
  2. 39
      california.js
  3. 14
      data/map.json
  4. 155
      gradients-v1.js
  5. 184
      gradients-v2.js
  6. 29
      index.html
  7. 47
      scrape.js
  8. 47
      server/downloader.js
  9. 68
      server/meteorological.js
  10. 132
      server/stations.js
  11. 111
      view/mesh.js
  12. 13
      view/meshface.js
  13. 11
      view/meshseed.js
  14. 102
      view/svg.js

4
.gitignore vendored

@ -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);
}
}());

@ -61,27 +61,44 @@
<body>
<script src="d3.min.js"></script>
<script src="view/meshface.js"></script>
<script src="view/meshseed.js"></script>
<script src="view/mesh.js"></script>
<script src="view/svg.js"></script>
NEXT:
<a href="http://bl.ocks.org/mbostock/4699541" target="_blank">http://bl.ocks.org/mbostock/4699541</a>
<a href="http://bl.ocks.org/mbostock/6123708" target="_blank">http://bl.ocks.org/mbostock/6123708</a>
<!-- <script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script> -->
<!-- <script src="//d3js.org/topojson.v1.min.js"></script> -->
<!-- <script src="gradients-v1.js"></script> -->
<!-- <script src="gradients-v2.js"></script> -->
<!-- <script src="california.js"></script> -->
<script src="gradients-v3.js"></script>
<!-- <script src="gradients-v3.js"></script> -->
<!-- <script src="gradients-v4.js"></script> -->
<!--
46026: 37.755 N 122.839 W (37°45'18" N 122°50'21" W)
http://www.ndbc.noaa.gov/data/realtime2/46026.txt
http://www.ndbc.noaa.gov/data/realtime2/ANVC1.txt
http://www.ndbc.noaa.gov/maps/San_Francisco.shtml
http://www.ndbc.noaa.gov/view_text_file.php?filename=46022h2014.txt.gz&dir=data/historical/stdmet/
DISCUSS:
Opacity solution lacks saturation and transition alignment
Gradient evolution
- Opacity solution lacks saturation and transition alignment (omit?)
- Composite solution overly complex and lacks transition alignment
- Square mesh OK, causes diamond-shaped artifacts
- Triangle mesh?
gourand / phong?
Delaunay / Voronoi
Mesh gradients / coon mesh
Mesh gradients / coon mesh (http://www.svgopen.org/2011/papers/18-Advanced_Gradients_for_SVG/)
feImage
Don't discuss triangle gradient attempts.
ogr2ogr -f GeoJSON -clipsrc -114 32.5 -125 43 -where "name IN ('California', 'Oregon', 'Nevada', 'Idaho')" california.geojson states.shp
http://dvisvgm.bplaced.net/Gradients
@ -89,5 +106,7 @@ http://www.gdal.org/ogr_sql.html
http://www.sarasafavi.com/intro-to-ogr-part-i-exploring-data.html
-->
<h3>ETL Stage</h3>
</body>
</html>

@ -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();
},
};

@ -3,42 +3,24 @@
/**
*
*/
function Mesh() {
// // Color seed coordinants
// this.seeds = [];
function Mesh(width, height, side) {
// Length of a side
this.side = 10;
// // How far a seed will extend its reach
this.seedWeight = 40;
//
this.width = 400;
this.height = 400;
var faces = this.initFaces(this.width, this.height, this.side);
this.side = side;
this.width = width;
this.height = height;
this.addSeed(new Seed(0, 0, '#ff0000', this.seedWeight), faces);
this.addSeed(new Seed(0, 39, '#0000ff', this.seedWeight), faces);
this.addSeed(new Seed(39, 0, '#00ff00', this.seedWeight), faces);
this.addSeed(new Seed(39, 39, '#ffff00', this.seedWeight), faces);
// How far a seed will extend its reach
this.seedWeight = 5;
this.calculateFills(faces);
// Color seed coordinants
// this.addSeed(new MeshSeed(0, 0, '#ff0000', this.seedWeight), faces);
// this.addSeed(new MeshSeed(0, this.height - 1, '#0000ff', this.seedWeight), faces);
// this.addSeed(new MeshSeed(this.width - 1, 0, '#00ff00', this.seedWeight), faces);
// this.addSeed(new MeshSeed(this.width - 1, this.height - 1, '#ffff00', this.seedWeight), faces);
var svg = d3.select("body").append("svg").attr('width', this.width).attr('height', this.height);
// this.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', 0)
// var svg = d3.select("body").append("svg").attr('width', this.width).attr('height', this.height);
// d3.select(id).attr('fill', seed.fill);
// for (var i = 0, len = seeds.length; i < len; i++) {
@ -46,28 +28,6 @@ function Mesh() {
// }
};
/**
*
*/
function Face(id, x, y, side) {
this.id = id;
this.x = x;
this.y = y;
this.side = side;
this.fill = '#fff';
this.colors = [];
};
/**
*
*/
function Seed(x, y, fill, weight) {
this.x = x;
this.y = y;
this.fill = fill;
this.weight = weight;
};
/**
*
*/
@ -82,7 +42,7 @@ Mesh.prototype = {
for (var w = 0; w < countW; w++) {
for (var h = 0; h < countH; h++) {
all.push(new Face(
all.push(new MeshFace(
`f-${w}-${h}-${all.length}`,
w * side,
h * side,
@ -99,7 +59,7 @@ Mesh.prototype = {
*/
calculateFills: function(faces) {
var len = faces.length;
var hexes;
var hexes, colors;
var populate = function(color) {
var arr = [];
@ -110,17 +70,18 @@ Mesh.prototype = {
};
for (var i = 0; i < len; i++) {
var hexes = [];
hexes = [];
for (var j = 0; j < faces[i].colors.length; j++) {
hexes = hexes.concat(populate(faces[i].colors[j]));
colors = faces[i].colors[j];
hexes = hexes.concat(populate(colors));
}
while (hexes.length < this.seedWeight) {
hexes.push('#ccccff');
hexes.push('#ffffff');
}
faces[i].fill = Compositor.averageHexCollection(hexes);
faces[i].fill = this.averageHexCollection(hexes);
}
},
@ -128,25 +89,34 @@ Mesh.prototype = {
*
*/
addSeed: function(seed, faces) {
var faceX = Math.floor(seed.x / this.side);
var faceY = Math.floor(seed.y / this.side);
var countX = this.width / this.side;
var countY = this.height / this.side;
var n = this.seedWeight;
var len = faces.length;
var delta, index, weight;
var countX = this.width / this.side;
var countY = this.height / this.side;
for (var x = (seed.x - n + 1); x < seed.x + n; x++) {
for (var x = (faceX - n + 1); x < faceX + n; x++) {
if (x < 0 || x >= countX) {
continue;
}
for (var y = (seed.y - n + 1); y < seed.y + n; y++) {
for (var y = (faceY - n + 1); y < faceY + n; y++) {
if (y < 0 || y >= countY) {
continue;
}
// Diamond shapes around source drop weighting incrementally.
delta = Math.abs(seed.x - x) + Math.abs(seed.y - y);
weight = Math.max(0, n - delta);
// Weights decrement outwards from source in a given shape:
// Diamonds:
// delta = Math.abs(faceX - x) + Math.abs(faceY - y);
// weight = Math.max(0, n - delta);
// Squares:
var weight = n - Math.max(Math.abs(faceX - x), Math.abs(faceY - y));
index = x * countY + y;
@ -156,12 +126,7 @@ Mesh.prototype = {
}
}
},
};
/**
*
*/
var Compositor = {
/**
*
*/
@ -205,7 +170,5 @@ var Compositor = {
var b = this.averageComponentCollection(allB);
return '#' + r + g + b;
},
}
};
var mesh = new Mesh();

@ -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…
Cancel
Save