Skip to content

Instantly share code, notes, and snippets.

@NPashaP
Last active August 29, 2015 14:08
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 NPashaP/56731e158e74344e660e to your computer and use it in GitHub Desktop.
Save NPashaP/56731e158e74344e660e to your computer and use it in GitHub Desktop.
Nails And Strings

String art in D3.

<!DOCTYPE html>
<meta charset="utf-8">
<style>
circle{
fill:#e0e0e0;
}
</style>
<body>
<section style="display:block;">
Design: <select onchange="changeArt(this)"></select>
</section>
<svg width="960" height="480">
<rect x="0" y="0" width="960" height="480"></rect>
<g id="strings"></g>
<g id="nails"></g>
</svg>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="sArt.js"> </script>
<script src="string designs.js"> </script>
<script>
function changeArt(t){
d3.select("#nails").html('');
d3.select("#strings").html('');
sArt(sA[t.options[t.selectedIndex].value]);
}
d3.select("select").selectAll("option")
.data(sA.map(function(d){ return d.name;}))
.enter().append("option").attr("value",function(d,i){ return i;})
.text(function(d){return d;});
sArt(sA[0]);
</script>
</body>
</html>
function sArt(s){
/* s should have the structure
{ name:,
nails:[{s:{x:,y:},e:{x:,y:},n:},...],
strings:[{n1:,n2:,se:,c:,th:},...],
nFlag:
}
where
name = name to identify the design,
nails = array of nail groups,
nails[i].s = coordinates of starting nail of i-th nail group,
nails[i].e = coordinates of ending nail of i-th nail group,
nails[i].n = number of nails in i-th nail group,
strings = array of strings,
strings[i].se = 0 if start nail is mapped to start nail of the groups,
strings[i].n1 = index of the first nail group in nails array for i-th string group,
strings[i].n2 = index of the second nail group in nails array for i-th string group,
strings[i].c = colour of strings for i-th string group,
strings[i].th = thickness for strings in i-th group,
nFlag = 0/1 flag to enable or disable the display of nails.
*/
function drawNails(sa){
sa.nails.forEach(function(d){
var nr = 2;// nail radius
var p = d3.range(0,d.n+1).map(function(i){
return {x:d.s.x+(i/d.n)*(d.e.x-d.s.x),y:d.s.y+(i/d.n)*(d.e.y-d.s.y)};
});
d3.select("#nails").append("g").selectAll("circle").data(p).enter().append("circle")
.attr("cx", function(d){ return d.x;}).attr("cy",function(d){ return d.y;})
.attr("r",nr);
});
}
function drawStrings(sa){
sa.strings.forEach(function(d){
var s1=sa.nails[d.n1].s;
var e1=sa.nails[d.n1].e;
var s2= d.se==0? sa.nails[d.n2].s : sa.nails[d.n2].e;
var e2= d.se==0? sa.nails[d.n2].e : sa.nails[d.n2].s;
//assume sa.nails[d.n1].n == sa.nails[d.n2].n;
var p = d3.range(0,sa.nails[d.n1].n+1).map(function(l){
return {x1: s1.x + (l/sa.nails[d.n1].n)*(e1.x-s1.x),
y1: s1.y + (l/sa.nails[d.n1].n)*(e1.y-s1.y),
x2: s2.x + (l/sa.nails[d.n1].n)*(e2.x-s2.x),
y2: s2.y + (l/sa.nails[d.n1].n)*(e2.y-s2.y),};
});
d3.select("#strings").append("g").selectAll("line").data(p).enter().append("line")
.attr("x1",function(t){return t.x1;}).attr("y1",function(t){return t.y1;})
.attr("x2",function(t){return t.x2;}).attr("y2",function(t){return t.y2;})
.style("stroke", function(){ return d.c}).style("stroke-width", function(){ return d.th;});
});
}
if(s.nFlag==undefined || s.nFlag==1) drawNails(s);
drawStrings(s);
}
var sA = [
(function(){
var a = d3.range(0,6).map(function(a){ return a*2*Math.PI/6;});
var r = 240, cx=480, cy=240, n=40;
var ret ={name:'Face',nails:[], strings:[],nFlag:0};
ret.nails=a.map(function(a){ return {s:{x:cx, y:cy}, e:{x:cx+r*Math.cos(a), y:cy-r*Math.sin(a)},n:n};});
ret.nails.push({s:ret.nails[0].e, e:ret.nails[1].e, n:n});
ret.nails.push({s:ret.nails[2].e, e:ret.nails[3].e, n:n});
ret.nails.push({s:ret.nails[4].e, e:ret.nails[5].e, n:n});
ret.strings=[
{n1:0, n2:6, se:0, c:"#ff0000", th:1},
{n1:6, n2:1, se:1, c:"#ffaa00", th:1},
{n1:1, n2:2, se:1, c:"#b2ff00", th:1},
{n1:2, n2:7, se:0, c:"#00ff00", th:1},
{n1:7, n2:3, se:1, c:"#00ffed", th:1},
{n1:3, n2:4, se:1, c:"#0050ff", th:1},
{n1:4, n2:8, se:0, c:"#7b00ff", th:1},
{n1:8, n2:5, se:1, c:"#ff00aa", th:1},
{n1:5, n2:0, se:1, c:"#ff004c", th:1}
];
return ret;
})(),{
name:'Stars',
nails:[
{s:{x:10, y:240},e:{x:140, y:240},n:30},
{s:{x:270, y:240},e:{x:400, y:240},n:30},
{s:{x:530, y:240},e:{x:660, y:240},n:30},
{s:{x:790, y:240},e:{x:920, y:240},n:30},
{s:{x:205, y:45},e:{x:205, y:175},n:30},
{s:{x:205, y:305},e:{x:205, y:435},n:30},
{s:{x:465, y:45},e:{x:465, y:175},n:30},
{s:{x:465, y:305},e:{x:465, y:435},n:30},
{s:{x:725, y:45},e:{x:725, y:175},n:30},
{s:{x:725, y:305},e:{x:725, y:435},n:30}
],
strings:[
{n1:0, n2:4, se:1, c:"#DDD379", th:1},
{n1:0, n2:5, se:0, c:"#DDD379", th:1},
{n1:0, n2:6, se:1, c:"#DDD379", th:1},
{n1:0, n2:7, se:0, c:"#DDD379", th:1},
{n1:1, n2:4, se:0, c:"#DDD379", th:1},
{n1:1, n2:5, se:1, c:"#DDD379", th:1},
{n1:1, n2:6, se:1, c:"#DDD379", th:1},
{n1:1, n2:7, se:0, c:"#DDD379", th:1},
{n1:1, n2:8, se:1, c:"#DDD379", th:1},
{n1:1, n2:9, se:0, c:"#DDD379", th:1},
{n1:2, n2:4, se:0, c:"#DDD379", th:1},
{n1:2, n2:5, se:1, c:"#DDD379", th:1},
{n1:2, n2:6, se:0, c:"#DDD379", th:1},
{n1:2, n2:7, se:1, c:"#DDD379", th:1},
{n1:2, n2:8, se:1, c:"#DDD379", th:1},
{n1:2, n2:9, se:0, c:"#DDD379", th:1},
{n1:3, n2:6, se:0, c:"#DDD379", th:1},
{n1:3, n2:7, se:1, c:"#DDD379", th:1},
{n1:3, n2:8, se:0, c:"#DDD379", th:1},
{n1:3, n2:9, se:1, c:"#DDD379", th:1}
],
nFlag:0
},{
name:'N',
nails:[
{s:{x:250, y:460},e:{x:250, y:20},n:40},
{s:{x:250, y:20},e:{x:710, y:460},n:40},
{s:{x:710, y:460},e:{x:710, y:20},n:40}
],
strings:[
{n1:0, n2:1, se:0, c:"#00ff87", th:2},
{n1:1, n2:2, se:0, c:"#008cff", th:2}
],
nFlag:0
},(function(){
var a = d3.range(0,6).map(function(a){ return a*2*Math.PI/6;});
var r = 260, cx=480, cy=240;
var ret ={name:'Twins',nails:[], strings:[],nFlag:0};
ret.nails=a.map(function(a){ return {s:{x:cx, y:cy}, e:{x:cx+r*Math.cos(a), y:cy-r*Math.sin(a)},n:40};});
ret.strings=[
{n1:0, n2:2, se:1, c:"yellow", th:1},
{n1:3, n2:5, se:1, c:"red", th:1},
{n1:0, n2:4, se:1, c:"yellow", th:1},
{n1:1, n2:3, se:1, c:"red", th:1}
];
return ret;
})(),{
name:'Rectangle',
nails:[
{s:{x:10, y:10},e:{x:950, y:10},n:60},
{s:{x:950, y:10},e:{x:950, y:470},n:60},
{s:{x:950, y:470},e:{x:30, y:470},n:60},
{s:{x:10, y:470},e:{x:10, y:10},n:60}
],
strings:[
{n1:0, n2:1, se:0, c:"#fff", th:1},
{n1:1, n2:2, se:0, c:"#fff", th:1},
{n1:2, n2:3, se:0, c:"#fff", th:1},
{n1:3, n2:0, se:0, c:"#fff", th:1}
],
nFlag:0
},{
name:'Square',
nails:[
{s:{x:240, y:10},e:{x:470, y:10},n:30},
{s:{x:470, y:10},e:{x:700, y:10},n:30},
{s:{x:700, y:10},e:{x:700, y:240},n:30},
{s:{x:700, y:240},e:{x:700, y:470},n:30},
{s:{x:700, y:470},e:{x:470, y:470},n:30},
{s:{x:470, y:470},e:{x:240, y:470},n:30},
{s:{x:240, y:470},e:{x:240, y:240},n:30},
{s:{x:240, y:240},e:{x:240, y:10},n:30},
{s:{x:240, y:240},e:{x:470, y:240},n:30},
{s:{x:470, y:10},e:{x:470, y:240},n:30},
{s:{x:700, y:240},e:{x:470, y:240},n:30},
{s:{x:470, y:470},e:{x:470, y:240},n:30}
],
strings:[
{n1:7, n2:0, se:0, c:"#ff4100", th:1},
{n1:1, n2:2, se:0, c:"#ff8e00", th:1},
{n1:3, n2:4, se:0, c:"#00b25c", th:1},
{n1:5, n2:6, se:0, c:"#0a67a3", th:1},
{n1:8, n2:9, se:1, c:"#ff6c39", th:1},
{n1:9, n2:10, se:1, c:"#ffa839", th:1},
{n1:10, n2:11, se:1, c:"#29b773", th:1},
{n1:11, n2:8, se:1, c:"#2e78a9", th:1}
],
nFlag:0
},{
name:'Square 2',
nails:[
{s:{x:240, y:10},e:{x:470, y:10},n:30},
{s:{x:470, y:10},e:{x:700, y:10},n:30},
{s:{x:700, y:10},e:{x:700, y:240},n:30},
{s:{x:700, y:240},e:{x:700, y:470},n:30},
{s:{x:700, y:470},e:{x:470, y:470},n:30},
{s:{x:470, y:470},e:{x:240, y:470},n:30},
{s:{x:240, y:470},e:{x:240, y:240},n:30},
{s:{x:240, y:240},e:{x:240, y:10},n:30},
{s:{x:240, y:240},e:{x:400, y:240},n:30},
{s:{x:470, y:10},e:{x:470, y:170},n:30},
{s:{x:700, y:240},e:{x:540, y:240},n:30},
{s:{x:470, y:470},e:{x:470, y:310},n:30}
],
strings:[
{n1:7, n2:0, se:0, c:"#ff4100", th:1},
{n1:1, n2:2, se:0, c:"#ff8e00", th:1},
{n1:3, n2:4, se:0, c:"#00b25c", th:1},
{n1:5, n2:6, se:0, c:"#0a67a3", th:1},
{n1:8, n2:9, se:1, c:"#ff6c39", th:1},
{n1:9, n2:10, se:1, c:"#ffa839", th:1},
{n1:10, n2:11, se:1, c:"#29b773", th:1},
{n1:11, n2:8, se:1, c:"#2e78a9", th:1}
],
nFlag:0
}
];
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment