|
var DtouchTile = { |
|
width: 200, |
|
height: 200, |
|
|
|
init: function(code){ |
|
format = d3.format(",d"); |
|
var pack = d3.layout.pack() |
|
.size([this.width - 4, this.height - 4]) |
|
/* return can be d.size */ |
|
.value(function(d) { return 1; }); |
|
|
|
var mark = d3.select("#chart") |
|
.append("div") |
|
.attr("class","marker"); |
|
|
|
mark.append("h2") |
|
.text(code); |
|
|
|
var vis = mark.append("svg:svg") |
|
.attr("width", this.width) |
|
.attr("height", this.height) |
|
.attr("class", "pack"); |
|
|
|
var visg = vis.append("g") |
|
.attr("transform", "translate(2, 2)"); |
|
|
|
var json = makejson(code); |
|
|
|
var circles = []; |
|
var vertices = []; |
|
var big_vertices = []; |
|
var hull = []; |
|
var big_hull = []; |
|
var casing =[]; |
|
|
|
var node = vis.data([json]).selectAll("g.node") |
|
.data(pack.nodes) |
|
.enter().append("g") |
|
.attr("class", function(d) |
|
{ return d.depth==0 ? "root node" : |
|
(d.children ? "node" : "leaf node"); }) |
|
.attr("transform", function(d) |
|
{ if (d.depth==1){ |
|
circles.push( {'x': d.x,'y': d.y,'r': d.r}); }; |
|
return "translate(" + d.x + "," + d.y + ")"; }); |
|
node.append("circle") |
|
.transition() |
|
.duration(1000) |
|
.attr("r", function(d) |
|
{ return d.r - d.depth*4; }); |
|
|
|
circles.map( function(c) { |
|
/* Use a radius and big radius to form |
|
two convex hulls */ |
|
r = c.r+4; |
|
br = c.r+20; |
|
segs = 16; |
|
for (var i = 0; i<segs; i++) |
|
{ |
|
th = 2*i*Math.PI/segs; |
|
x = c.x + Math.sin(th)*r; |
|
y = c.y + Math.cos(th)*r; |
|
vertices.push([x,y]); |
|
bx = c.x + Math.sin(th) * br; |
|
by = c.y + Math.cos(th) * br; |
|
big_vertices.push([bx,by]); |
|
} }); |
|
|
|
hull = d3.geom.hull(vertices); |
|
big_hull = d3.geom.hull(big_vertices); |
|
for (var i = 0; i< big_hull.length; i++) |
|
{ |
|
/*make the bezier control points from the large hull and the points from the small */ |
|
casing.push([big_hull[i][0],big_hull[i][1], |
|
hull[i][0],hull[i][1]]); |
|
} |
|
|
|
visg.selectAll("path") |
|
.data([hull]) |
|
.attr("d", function(d) { |
|
curves = d |
|
return "M" + curves.join("S") + "Z"; }) |
|
.enter().insert("path") |
|
.attr("d", function(d) { |
|
return "M" + casing.join("S") + "Z"; }); |
|
}, |
|
|
|
remove: function() { |
|
d3.selectAll(".marker") |
|
.remove(); |
|
} |
|
}; |
|
|
|
|
|
// Code like "1:1:3" |
|
function makejson(code) |
|
{ |
|
var list = code.split(':').map( function(region) { |
|
blobs = []; |
|
parseInt(region).times(function() { |
|
blobs.push({"size":1});}); |
|
return {"children": blobs }; |
|
}); |
|
|
|
return { "children": list }; |
|
} |
|
|
|
|
|
// sign: -1 || 1 |
|
function scroll(sign) |
|
{ |
|
var chart = d3.select("#chart"); |
|
chart.transition() |
|
.duration(333) |
|
.ease('quad-in-out') |
|
.style("left", function(){ |
|
var liml = 634; |
|
var limr = -6600; |
|
var pos = parseInt(chart.style("left")) + (sign*451); |
|
if (pos >= liml) |
|
{pos = liml;} |
|
else if (pos <= limr) |
|
{pos = limr;} |
|
|
|
return pos+"px";}); |
|
} |
|
|
|
|
|
//Basic setup |
|
function setup() |
|
{ |
|
//Scroll |
|
$('left').observe('click',function(){ scroll(1); }); |
|
$('right').observe('click',function(){ scroll(-1);}); |
|
|
|
$('min_regions', 'max_regions', 'empty_regions', |
|
'validation_regions', 'validation_num', |
|
'max_blobs', 'checksum').invoke('observe', |
|
'change',schedule_update); |
|
schedule_update(); |
|
} |
|
|
|
var timer; |
|
|
|
function schedule_update() |
|
{ |
|
clearTimeout(timer); |
|
timer=setTimeout("update()",500); |
|
} |
|
|
|
function update() |
|
{ |
|
var minr = parseInt($('min_regions').value); |
|
var maxr = parseInt($('max_regions').value); |
|
var empty = parseInt($('empty_regions').value); |
|
var fixed = parseInt($('validation_regions').value); |
|
var fixnum = parseInt($('validation_num').value); |
|
var blobs = parseInt($('max_blobs').value); |
|
var chksum = parseInt($('checksum').value); |
|
|
|
var codelist = listcodes(minr,maxr,empty,fixed, |
|
fixnum,blobs,chksum); |
|
$('count').update(codelist.length); |
|
drawmarkers(codelist); |
|
} |
|
|
|
function listcodes(minr,maxr,empty,fixed,fixnum,blobs,chksum) |
|
{ |
|
var codes = []; |
|
for (var regions = minr; regions <= maxr; regions++){ |
|
codes = codes.concat(listcodes_with_regions(regions-fixed,empty,fixed,fixnum,blobs,chksum)); |
|
} |
|
return codes; |
|
} |
|
|
|
function listcodes_with_regions(regions,empty,fixed,fixnum,blobs,chksum) |
|
{ |
|
var start = (empty>0)?0:1; |
|
//calculate without checksum first |
|
allcombs = combinations(start,blobs,regions); |
|
validation = []; |
|
//make the validation part |
|
fixed.times(function() |
|
{ validation.push(fixnum); }); |
|
|
|
allcombs = allcombs.map( function(comb){ |
|
return validation.concat(comb).sort(); |
|
}); |
|
|
|
//select valid checksum |
|
allcombs = allcombs.select( function(code){ |
|
return code.reduceRight(function(prev,cur){return prev+cur;}) % chksum == 0}); |
|
//reject too many empties |
|
allcombs = allcombs.select( function(code){ |
|
return code[empty] != 0}); |
|
return allcombs; |
|
} |
|
|
|
//return a list of combination lists |
|
function combinations(from,to,len) |
|
{ |
|
if (len<=0) return([]); |
|
var list = []; |
|
for (var i=from; i<=to; i++) |
|
{ |
|
var shortllist = combinations(i,to,len-1); |
|
if (shortllist.length==0) |
|
{ |
|
list.push([i]); |
|
} |
|
else |
|
{ |
|
shortllist.each(function(shortl){ |
|
ananswer = [i].concat(shortl); |
|
list.push(ananswer); |
|
}); |
|
} |
|
} |
|
return(list); |
|
} |
|
|
|
function stringformat(codearray) |
|
{ |
|
return codearray.join(':'); |
|
} |
|
|
|
function drawmarkers(codelist) |
|
{ |
|
|
|
DtouchTile.remove(); |
|
codelist.each(function(code){ |
|
codename = stringformat(code); |
|
DtouchTile.init(codename); |
|
}); |
|
} |
|
|
|
setup(); |
|
|