Built with blockbuilder.org
HexCut
This file contains 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 |
This file contains 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> | |
<head> | |
<meta charset="utf-8"> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<style> | |
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } | |
</style> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"> </script> | |
</head> | |
<body> | |
<script> | |
function onLevelChange() { | |
var val = $('#levelRange').val(); | |
$('#levelLabel').text(val) | |
$('#triCount').text(val * val) | |
updateField(+val); | |
} | |
</script> | |
<div style="text-align: center"> | |
A visualisation of triangle cuts inspired by | |
CodeForces <a href="http://codeforces.com/problemset/problem/559/A" > Gerald's Hexagon Problem </a> | |
</div> | |
<div class="svgHolder" id="svgHolder"> | |
<svg> | |
<defs> | |
<pattern id="crosshatch" patternUnits="userSpaceOnUse" | |
width="30" height="30" | |
> | |
<image xlink:href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPSc4JyBoZWlnaHQ9JzgnPgogIDxyZWN0IHdpZHRoPSc4JyBoZWlnaHQ9JzgnIGZpbGw9JyNmZmYnLz4KICA8cGF0aCBkPSdNMCAwTDggOFpNOCAwTDAgOFonIHN0cm9rZS13aWR0aD0nMC41JyBzdHJva2U9JyNhYWEnLz4KPC9zdmc+Cg==" | |
x="0" y="0" width="30" height="30" > </image> | |
</pattern> | |
</defs> | |
</svg> | |
</div> | |
<div class="row" style="width: 300px; margin:auto"> | |
<table style="width:100%"> | |
<tr> | |
<td style="width:100px">Levels: <span id="levelLabel"> 1</span></td> | |
<td style="width:100px; text-align:center">Count: <span id="triCount">xx</span></td> | |
<td style="width:80px; text-align:right;"> Cut size: </td> | |
<td style="width:30px;"><span id="cutCount">--</span></td> | |
</tr> | |
</table> | |
<input type="range" id="levelRange" | |
value="4" min="1" max="30" | |
step="1" oninput="onLevelChange()" | |
style="width:100%" | |
> | |
</div> | |
<script> | |
var width = 960; | |
var legendWidth = 120; | |
var height = 400; | |
var lineLength = 150; | |
var fontSize = 30; | |
var lineStroke = 0.4; | |
var trianglesSelection = undefined; | |
var strokeColor = 'black'; | |
var linesCount = -1; | |
var a = height; | |
var TR_H = a * Math.sqrt(3) / 2; | |
var svg = d3.select("#svgHolder svg") | |
.attr("width", width) | |
.attr("height", height) | |
var traiglesGroup = svg.append('g'); | |
var trianglesElems = {} | |
var trianglePath = d3.path(); | |
trianglePath.moveTo(0, 0); | |
trianglePath.lineTo(a / 2, TR_H); | |
trianglePath.lineTo(-a / 2, TR_H); | |
trianglePath.closePath(); | |
function triangle(selection) { | |
var g = selection.append("g") | |
g | |
.append('path') | |
.attr("d", trianglePath.toString()) | |
.attr("stroke", strokeColor) | |
.attr("stroke-alignment", 'center') | |
.attr("fill", "white") | |
.attr('transform', function(d) { | |
if(d.col % 2 == 1) { | |
return `translate(0, ${TR_H}), rotate(-180)`; | |
} else { | |
return '' | |
} | |
}) | |
.attr("stroke-width", function(d) { | |
if(d.col % 2 == 1) { | |
return 0 | |
} | |
return linesCount * lineStroke; | |
}) | |
g | |
.append('text') | |
.text((d, i) => (i + 1)) | |
//.text((d, i) => (d.gow)) | |
.attr('font-size', () => fontSize * (1 + Math.log(linesCount))) | |
.attr('text-anchor', 'middle') | |
.attr('y', function(d) { | |
if(d.col % 2 == 1) { | |
return TR_H / 2.2; | |
} | |
return TR_H / 1.2; | |
}) | |
.attr('fill', '#ddd') | |
g | |
.attr('transform', function(d, i) { | |
var x = -d.row * a / 2 + d.col * a / 2; | |
var y = d.row * TR_H; | |
return `translate(${x}, ${y})`; | |
}); | |
// TODO: move | |
g | |
.on("mouseover", showCut) | |
.on("mouseout", hideCut) | |
} | |
function triangleUpdate(selection) { | |
selection | |
.select('path') | |
.attr("stroke-width", function(d) { | |
if(d.col % 2 == 1) { | |
return 0 | |
} | |
return linesCount * lineStroke; | |
}) | |
selection | |
.select('text') | |
.attr('font-size', () => fontSize * (1 + Math.log(linesCount))) | |
} | |
function getTrArr(lines) { | |
var res = []; | |
var lineCount = 1; | |
for(var line = 0; line < lines; line++) { | |
for(var i = 0; i < lineCount; i++) { | |
res.push({ row: line, col: i }) | |
} | |
lineCount += 2; | |
} | |
lineCount = lines * 2 - 1; | |
var bottomLeft = res.length - lineCount; | |
var bottomRight = res.length - 1; | |
cursor = bottomLeft; | |
curlineCount = 1; | |
for(var line = 0; line < lines; line++) { | |
var inCursor = cursor; | |
lineCount = lines * 2 - 1; | |
for(var i = 0; i < curlineCount; i++) { | |
res[inCursor].gow = line; | |
if(i % 2 == 0) { | |
inCursor--; | |
} else { | |
inCursor -= lineCount - 1; | |
lineCount -= 2; | |
} | |
} | |
cursor += 2; | |
curlineCount += 2; | |
} | |
cursor = bottomRight; | |
curlineCount = 1; | |
for(var line = 0; line < lines; line++) { | |
var inCursor = cursor; | |
lineCount = lines * 2 - 1; | |
for(var i = 0; i < curlineCount; i++) { | |
res[inCursor].bow = line; | |
if(i % 2 == 0) { | |
inCursor++; | |
} else { | |
inCursor -= lineCount - 1; | |
lineCount -= 2; | |
} | |
} | |
cursor -= 2; | |
curlineCount += 2; | |
} | |
return res; | |
} | |
function updateField(lc) { | |
linesCount = lc; | |
var l = 4 * linesCount; | |
console.log(linesCount); | |
svg.select("#crosshatch") | |
.attr('height', l) | |
.attr('width', l); | |
svg.select("#crosshatch image") | |
.attr('width', l) | |
.attr('height', l) | |
var data = getTrArr(linesCount); | |
//traiglesGroup.selectAll('g').remove(); | |
var selection = trianglesSelection = traiglesGroup.selectAll('g') | |
.data(data) | |
selection.enter().call(triangle) | |
selection.call(triangleUpdate) | |
selection.exit().remove(); | |
traiglesGroup.attr( | |
'transform', `translate(${width / 2}, 20), scale(${1 / linesCount})` | |
) | |
} | |
function showCut(d) { | |
var filter = undefined; | |
if(d.row < d.gow && d.row < d.bow) { | |
filter = t => t.row <= d.row; | |
} | |
if(d.bow < d.row && d.bow < d.gow) { | |
filter = t => t.bow <= d.bow; | |
} | |
if(d.gow < d.row && d.gow < d.bow) { | |
filter = t => t.gow <= d.gow; | |
} | |
if(!filter) { | |
return; | |
} | |
var filtered = traiglesGroup | |
.selectAll('g') | |
.filter(filter) | |
$("#cutCount").text(filtered.size()); | |
filtered | |
.selectAll('path') | |
.attr("fill", "url(#crosshatch)") | |
filtered | |
.selectAll('text') | |
.attr('fill', '#aaa') | |
} | |
function hideCut(d) { | |
$("#cutCount").text('--'); | |
traiglesGroup | |
.selectAll('path') | |
.attr('fill', 'white') | |
traiglesGroup | |
.selectAll('text') | |
.attr('fill', '#ddd') | |
} | |
onLevelChange(); | |
</script> | |
</body> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment