Skip to content

Instantly share code, notes, and snippets.

@timelyportfolio
Forked from christophermanning/README.md
Last active September 8, 2015 14:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save timelyportfolio/cd961c10a861d1d084a8 to your computer and use it in GitHub Desktop.
Save timelyportfolio/cd961c10a861d1d084a8 to your computer and use it in GitHub Desktop.
Random Walk USA
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/dat-gui/0.5/dat.gui.min.js"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>
<script>
width = Math.max(window.innerWidth, 960)
height = Math.max(window.innerHeight, 500)
config = {"theta": 1, "density" : 10, "scale": 25, "careful": true, "smooth": true};
gui = new dat.GUI({width: 130});
var examples = gui.addFolder('Examples');
examples.open()
config.Sketch = function(){
config["theta"] = 1
config["density"] = 10
config["scale"] = 25
config["careful"] = true
config["smooth"] = true
draw()
}
examples.add(config, "Sketch")
config.Geom = function(){
config["theta"] = 90
config["density"] = 10
config["scale"] = 25
config["careful"] = true
config["smooth"] = true
draw()
}
examples.add(config, "Geom")
config.Squares = function(){
config["theta"] = 90
config["density"] = 30
config["scale"] = 5
config["careful"] = true
config["smooth"] = false
draw()
}
examples.add(config, "Squares")
config.Triangles = function(){
config["theta"] = 60
config["density"] = 1
config["scale"] = 25
config["careful"] = false
config["smooth"] = false
draw()
}
examples.add(config, "Triangles")
config.Random = function(){
gui.__folders.Settings.__controllers.forEach(function(c){
if(typeof(c.__select) != 'undefined') {
c.setValue(c.__select[Math.floor(Math.random()*(c.__select.length-1))].value)
} else {
if(typeof c.initialValue == "boolean") {
c.setValue(Math.round(Math.random()) == true)
} else if(typeof c.initialValue == "number") {
c.setValue(Math.floor(Math.random() * c.__max) + c.__min)
}
}
})
draw()
}
examples.add(config, "Random")
var settings = gui.addFolder('Settings');
thetaChanger = settings.add(config, "theta", 1, 180).step(1).listen()
thetaChanger.onChange(function(value) {
draw()
});
scaleChanger = settings.add(config, "scale", 1, 25).step(1).listen()
scaleChanger.onChange(function(value) {
draw()
});
densityChanger = settings.add(config, "density", 1, 50).listen()
densityChanger.onChange(function(value) {
draw()
});
carefulChanger = settings.add(config, "careful").listen()
carefulChanger.onChange(function(value) {
draw()
});
smoothChanger = settings.add(config, "smooth").listen()
smoothChanger.onChange(function(value) {
draw()
});
config.redraw = function(){
draw()
}
settings.add(config, "redraw")
var zoom = d3.behavior.zoom()
.scale(config["theta"])
.scaleExtent([1, 180])
.on("zoom", function(d,i) {
config["theta"] = Math.floor(d3.event.scale)
draw()
});
var projection = d3.geo.albersUsa()
.scale(1000)
.translate([(width-100) / 2, (height-25) / 2]);
var path = d3.geo.path()
.projection(projection);
canvas = d3.select("body").append("canvas")
.attr("width", width)
.attr("height", height)
.call(zoom)
context = canvas.node().getContext("2d")
color = d3.scale.category20()
line = d3.svg.line()
.interpolate(config["interpolation"])
.tension(config["tension"])
.x(function(d, i) { return d.xo })
.y(function(d, i) { return d.yo })
function pointInPolygon(point, polygon) {
for (var n = polygon.length, i = 0, j = n - 1, x = point[0], y = point[1], inside = false; i < n; j = i++) {
var xi = polygon[i][0], yi = polygon[i][1],
xj = polygon[j][0], yj = polygon[j][1];
if ((yi > y ^ yj > y) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi)) inside = !inside;
}
return inside;
}
function randInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min
}
d3.json('us.json', function(error, us) {
us_json = us
us_json.objects.states.geometries = us_json.objects.states.geometries.filter(function(d) { return d.id < 60 })
states = topojson.feature(us_json, us_json.objects.states).features,
neighbors = topojson.neighbors(us_json.objects.states.geometries);
draw()
})
function draw(){
context.clearRect(0, 0, width, height)
context.lineJoin = 'round'
for (var i0 = 0; i0 < states.length; i0++) {
d = states[i0]
context.beginPath()
context.strokeStyle = states[i0].color ? states[i0].color : states[i0].color = color(states[i0].colorIndex = d3.max(neighbors[i0], function(n) { return states[n].colorIndex; }) + 1 | 0)
for(var i1=0; i1<d.geometry.coordinates.length; i1++) {
if(d.geometry.type=="MultiPolygon") {
p = d.geometry.coordinates[i1][0]
}else{
p = d.geometry.coordinates[i1]
}
d2 = {type: "Feature", properties: {}, geometry: {type: "Polygon", coordinates: [p]}}
centroid = path.centroid(d2)
area = path.area(d2)
// skip small lands unless they're AK or HI
if(area<100 && d.id != 2 && d.id != 15) continue
last = {xo: centroid[0], yo: centroid[1], pip: true}
context.moveTo(last.xo, last.yo)
strokes = area*(config["density"]*.01)
for(var i2=0;i2<(strokes < 4 ? 4 : strokes);i2++){
xo = last.xo
yo = last.yo
if(last.pip) {
// random angle that's a multiple of theta
r = randInt(1, 360/config["theta"])
angle = r * config["theta"]
theta = angle * (Math.PI/180)
} else {
// if we're outside of the polygon, turn towards the centroid
dx = centroid[0] - xo
dy = centroid[1] - yo
theta = Math.atan2(dy, dx)
thetaDeg = theta * (180/Math.PI)
// random angle towards the centroid clamped to theta
randAngle = randInt(thetaDeg - 90, thetaDeg + 90)
angle = Math.floor(randAngle/config["theta"])*config["theta"]
theta = Math.PI * (angle/180)
}
scale = Math.sqrt(area) < config["scale"] ? Math.sqrt(area) : config["scale"]
xo += Math.cos(theta)*scale
yo += Math.sin(theta)*scale
pip = pointInPolygon(projection.invert([xo, yo]), d2.geometry.coordinates[0])
last = {xo: xo, yo: yo, pip: pip}
if(pip || i2==0 || !(pip || config["careful"])) context.lineTo(last.xo, last.yo)
if(!config["smooth"]) context.moveTo(last.xo, last.yo)
}
}
context.stroke()
}
}
</script>
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment