Experiment in creating regular grids from circular paths, step 1: General concept and reference grids.
Created
November 19, 2016 14:37
-
-
Save mootari/56039eed3e606fc97562034ad5f71637 to your computer and use it in GitHub Desktop.
Squaring the circle, part 1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
license: mit | |
height: 500 | |
scrolling: yes |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<style> | |
html, body, div, svg { | |
margin: 0; | |
padding: 0; | |
box-sizing: border-box; | |
} | |
html, body, #app { | |
width: 100%; | |
height: 100%; | |
position: relative; | |
} | |
body { | |
overflow: hidden; | |
} | |
.line { | |
fill: none; | |
} | |
@media print { | |
.dg { display: none } | |
} | |
</style> | |
</head> | |
<body> | |
<div id="app"></div> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.3.0/d3.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script> | |
<script src="script.js"></script> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function() { | |
var config = { | |
sides: 4, | |
increase: 2, | |
radius: 30, | |
steps: 10, | |
size: 15, | |
opacity: .2, | |
drawLines: true | |
}; | |
var app = d3.select('#app'); | |
var bbox = app.node().getBoundingClientRect(); | |
var w = bbox.width; | |
var h = bbox.height; | |
var stage = app.append('svg').append('g'); | |
resize(w, h); | |
gui(); | |
update(); | |
d3.select(window).on('resize', function() { | |
bbox = app.node().getBoundingClientRect(); | |
w = bbox.width; | |
h = bbox.height; | |
resize(w, h); | |
}); | |
function resize(width, height) { | |
d3.select(stage.node().parentNode) | |
.attr('width', width) | |
.attr('height', height); | |
stage.attr('transform', 'translate(' + (width / 2) + ' ' + (height / 2) + ')'); | |
} | |
function gui() { | |
var delayUpdate = delayCallback(update, 20, 3); | |
var ui = new dat.GUI(); | |
ui.add(config, 'sides').min(3).max(10).step(1).onChange(delayUpdate); | |
ui.add(config, 'increase').min(0).max(3).step(1).onChange(delayUpdate); | |
ui.add(config, 'steps').min(1).max(30).step(1).onChange(delayUpdate); | |
ui.add(config, 'radius').min(1).max(300).step(1).onChange(delayUpdate); | |
ui.add(config, 'size').min(1).max(300).step(1).onChange(delayUpdate); | |
ui.add(config, 'opacity').min(0).max(1).step(.001).onChange(delayUpdate); | |
ui.add(config, 'drawLines').onChange(delayUpdate); | |
} | |
function delayCallback(callback, delay, skipMax) { | |
function run() { | |
skipped = toId = 0; | |
callback(); | |
} | |
var toId = skipped = 0; | |
return function() { | |
if(!toId || skipped < skipMax) { | |
skipped++; | |
clearTimeout(toId); | |
toId = setTimeout(run, delay); | |
} | |
}; | |
} | |
function getPoints(sides, segments, radius, angleOffset) { | |
function segmentLine(p1, p2, segments) { | |
var points = []; | |
var dx = (p2[0] - p1[0]) / segments; | |
var dy = (p2[1] - p1[1]) / segments; | |
for(var i = 1; i < segments; i++) { | |
points.push([ | |
p1[0] + dx * i, | |
p1[1] + dy * i | |
]); | |
} | |
return points; | |
} | |
var points = [], corners = []; | |
var aSegment = Math.PI * 2 / sides; | |
var i, a; | |
for(i = 0; i < sides; i++) { | |
a = aSegment * i + angleOffset; | |
corners.push([ | |
Math.cos(a) * radius, | |
Math.sin(a) * radius | |
]); | |
} | |
var p1, p2; | |
for(i = 0; i < corners.length; i++) { | |
p1 = corners[i]; | |
p2 = corners[(i + 1) % corners.length]; | |
points.push(p1); | |
points = points.concat(segmentLine(p1, p2, segments)); | |
} | |
return points; | |
} | |
function points(sides, steps, increase, radius) { | |
var offset = Math.PI / 2 - Math.PI / sides; | |
return d3.range(steps).map(function(v, i) { | |
return getPoints(sides, (i + 1) * increase, (i + 1) * radius, offset); | |
}); | |
} | |
function renderCenter(parent, size, opacity) { | |
var center = parent.selectAll('.center').data([null]); | |
center.enter() | |
.append('circle') | |
.attr('class', 'center') | |
.attr('cx', 0) | |
.attr('cy', 0) | |
.merge(center) | |
.attr('r', size / 2) | |
.attr('fill', 'rgba(0,0,0,' + opacity + ')'); | |
} | |
function renderPoints(points, parent, size, dotOpacity, drawLines) { | |
function renderLine(d) { | |
var p = d3.select(this).selectAll('.line').data(drawLines ? [d] : []); | |
p.exit().remove(); | |
p.enter() | |
.append('path') | |
.attr('class', 'line') | |
.merge(p) | |
.attr('stroke', 'black') | |
.attr('d', function(d) { | |
return 'M' + d.map(function(d) { | |
return d.join(','); | |
}).join('L') + 'Z'; | |
}); | |
} | |
var group = parent.selectAll('.step').data(points); | |
group.exit().remove(); | |
group = group.enter() | |
.append('g') | |
.attr('class', 'step') | |
.merge(group) | |
.each(renderLine); | |
var dot = group.selectAll('.dot') | |
.data(function(d) { return d; }); | |
dot.exit().remove(); | |
dot | |
.enter() | |
.append('circle') | |
.attr('class', 'dot') | |
.merge(dot) | |
.attr('r', size / 2) | |
.attr('cx', function(d) { return d[0]; }) | |
.attr('cy', function(d) { return d[1]; }) | |
.attr('fill', 'rgba(0,0,0,' + dotOpacity + ')'); | |
} | |
function update() { | |
renderCenter(stage, config.size, config.opacity); | |
var p = points(config.sides, config.steps, config.increase, config.radius); | |
renderPoints(p, stage, config.size, config.opacity, config.drawLines); | |
} | |
}()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment