block by NPashaP 56731e158e74344e660e

Nails And Strings

Full Screen

String art in D3.

index.html

<!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="//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>

sArt.js

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

string designs.js

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
    }
];