From 091b2222bcfe616b4a4d6033ee0803ebc830ab80 Mon Sep 17 00:00:00 2001 From: mmcw-dev <hi@mmcwilliams.com> Date: Wed, 27 Dec 2017 20:05:51 -0500 Subject: [PATCH] Add an overlap flag which will add or remove extra flaps of material to attach to an adjacent side. --- README.md | 4 +- docs/index.html | 14 +++- example/index.html | 181 +++++++++++++++++++++++++++++++++++++++++++++ src/bellows.js | 181 ++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 357 insertions(+), 23 deletions(-) create mode 100644 example/index.html diff --git a/README.md b/README.md index a05cbf3..fa2a8aa 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,9 @@ const bellows = require('bellows') | [options.backOH] | <code>Integer</code> | Back outer height of bellows in pixels | | [options.maxLength] | <code>Integer</code> | Maximum length of bellows in pixels | | [options.align] | <code>Integer</code> | Vertical alignment adjustment in pixels | -| [options.parts] | <code>Integer</code> | Number of parts to split pattern into: 1, 2, or 4 returns {String} Base64 encoded png data | +| [options.parts] | <code>Integer</code> | Number of parts to split pattern into: 1, 2, or 4 | +| [options.key] | <code>Boolean</code> | Print key on page | +| [options.overlap] | <code>Boolean</code> | Add overlapping flap between parts returns {String} Base64 encoded png data | **Example** ```js diff --git a/docs/index.html b/docs/index.html index f30407e..f7c3788 100644 --- a/docs/index.html +++ b/docs/index.html @@ -105,6 +105,10 @@ input{ <label for="key">Show Key</label> <input name="key" type="checkbox" checked /> </div> + <div> + <label for="overlap">Add Overlapping Tab</label> + <input name="overlap" type="checkbox" checked /> + </div> </div> </form> <div> @@ -112,8 +116,8 @@ input{ <button id="download" onclick="download();">Download</button> </div> <img id="img" /> -<!--<script src="../src/bellows.js"> </script>--> -<script src="https://rawgit.com/sixteenmillimeter/bellows/master/src/bellows.js"> +<script src="../src/bellows.js"> </script> +<!--<script src="https://rawgit.com/sixteenmillimeter/bellows/master/src/bellows.js">--> </script> <script> 'use script' @@ -144,7 +148,8 @@ input{ const maxLength = Math.round($('maxLength').value * MM); - const key = $('key').checked + const key = $('key').checked; + const overlap = $('overlap').checked; const align = Math.round($('align').value); let parts = Math.round($('parts').value); @@ -171,7 +176,8 @@ input{ maxLength : maxLength, parts : parts, align : align, - key : key + key : key, + overlap : overlap } ); document.getElementById('img').setAttribute('src', B); diff --git a/example/index.html b/example/index.html new file mode 100644 index 0000000..054f1c9 --- /dev/null +++ b/example/index.html @@ -0,0 +1,181 @@ +<!doctype html> +<html> +<head> +<title>Bellows Browser Example</title> +<style> +form{ + clear: both; +} +form:after{ + display: block; + content: " "; +} +label{ + width: 150px; + display: inline-block; +} +form > div { + width: 400px; + float: left; + margin: 20px 0; +} +img{ + width: 100%; + height: auto; + border: 1px solid #000; +} +button{ + margin: 10px 20px; +} +input{ + margin-top: 10px; +} +</style> +</head> +<body> +<h1> + Bellows Pattern Generator +</h1> +<div> + <a href="https://github.com/sixteenmillimeter/bellows">View Source</a> +</div> +<form onsubmit="return false;"> + <div> + <div> + <label for="backOW">Back Outer Width</label> + <input name="backOW" type="number" value="50" /> mm + </div> + <div> + <label for="backIW">Back Inner Width</label> + <input name="backIW" type="number" value="40" /> mm + </div> + <div> + <label for="backOH">Back Outer Height</label> + <input name="backOH" type="number" value="50" /> mm + </div> + <div> + <label for="backIH">Back Inner Height</label> + <input name="backIH" type="number" value="40" /> mm + </div> + </div> + <div> + <div> + <label for="frontOW">Front Outer Width</label> + <input name="frontOW" type="number" value="50" /> mm + </div> + <div> + <label for="frontIW">Front Inner Width</label> + <input name="frontIW" type="number" value="40" /> mm + </div> + <div> + <label for="frontOH">Front Outer Height</label> + <input name="frontOH" type="number" value="50" /> mm + </div> + <div> + <label for="frontIH">Front Inner Height</label> + <input name="frontIH" type="number" value="40" /> mm + </div> + </div> + <div> + <div> + <label for="pageW">Sheet Width</label> + <input name="pageW" type="number" value="8.5" /> in + </div> + <div> + <label for="pageH">Sheet Height</label> + <input name="pageH" type="number" value="11" /> in + </div> + <div> + <label for="dpi">DPI</label> + <input name="dpi" type="number" value="300" /> + </div> + <div> + <label for="maxLength">Maximum Length</label> + <input name="maxLength" type="number" value="200" /> mm + </div> + <div> + <label for="parts">Seperate Parts</label> + <input name="parts" type="number" value="1" min="1" max="4" /> 1, 2, or 4 + </div> + <div> + <label for="align">Adjust Alignment</label> + <input name="align" type="number" value="0" min="0" /> + </div> + </div> +</form> +<div> + <button id="refresh" onclick="refresh();">Refresh</button> + <button id="download" onclick="download();">Download</button> +</div> +<img id="img" /> +<script src="../src/bellows.js"> </script> +<script> + 'use script' + const $ = function (select) { + return document.querySelector(`[name="${select}"]`) + } + let B + function refresh () { + + const IN = 25.4 + const DPI = $('dpi').value + const MM = DPI / IN + + const pageW = Math.round($('pageW').value * DPI); + const pageH = Math.round($('pageH').value * DPI); + + const backOW = Math.round($('backOW').value * MM); + const backIW = Math.round($('backIW').value * MM); + + const backOH = Math.round($('backOH').value * MM); + const backIH = Math.round($('backIH').value * MM); + + const frontOW = Math.round($('frontOW').value * MM); + const frontIW = Math.round($('frontIW').value * MM); + + const frontOH = Math.round($('frontOH').value * MM); + const frontIH = Math.round($('frontIH').value * MM); + + const maxLength = Math.round($('maxLength').value * MM); + + const align = Math.round($('align').value); + let parts = Math.round($('parts').value); + + if (parts === 3 || parts > 4) { + parts = 1 + } + + B = bellows( + { + dpi : DPI, + + pageW : pageW, + pageH : pageH, + + backOW : backOW, + backIW : backIW, + backOH : backOH, + backIH : backIH, + frontOW : frontOW, + frontIW : frontIW, + frontOH : frontOH, + frontIH : frontIH, + + maxLength : maxLength, + parts : parts, + align : align + } + ); + document.getElementById('img').setAttribute('src', B); + } + function download () { + const a = document.createElement('a'); + a.href = B; + a.download = 'bellows.png'; + + a.click(); + } + refresh() +</script> +</body> +</html \ No newline at end of file diff --git a/src/bellows.js b/src/bellows.js index 1176006..8a9cc01 100644 --- a/src/bellows.js +++ b/src/bellows.js @@ -76,6 +76,8 @@ function taper (back, front, length, pos) { * @param {Integer} [options.maxLength] Maximum length of bellows in pixels * @param {Integer} [options.align] Vertical alignment adjustment in pixels * @param {Integer} [options.parts] Number of parts to split pattern into: 1, 2, or 4 + * @param {Boolean} [options.key] Print key on page + * @param {Boolean} [options.overlap] Add overlapping flap between parts * * returns {String} Base64 encoded png data * @@ -113,6 +115,7 @@ function bellows (options = {}) { let centerY = Math.round(pageH / 2) let key = (typeof options.key !== 'undefined' && options.key === false) ? false : true + let over = (typeof options.overlap !== 'undefined' && options.overlap === false) ? false : true let fold = (frontOW - frontIW) / 2 let folds = Math.floor(maxLength / fold) @@ -156,8 +159,18 @@ function bellows (options = {}) { if (side === 1 || parts === 4 || (parts === 2 && side === 3)) { line(ctx, BLACK, [X, Y], [X + frontOffset, Y + length]) } - if (parts === 4) { + if (parts === 4 && !over) { line(ctx, BLACK, [X + backOW, Y], [X + backOW - frontOffset, Y + length]) + for (let i = 1; i < folds; i++) { + if (i % 2 === 0) { + if (backIW !== frontIW) { + t = taper(backIW, frontIW, length, i * fold) + } else { + t = 0 + } + line(ctx, BLACK, [foldIN + backIW - t, Y + (i * fold)], [foldIN + backIW - t + ((backOW - backIW) / 2), Y + (i * fold)]) + } + } } //inner //line(ctx, BLACK, [X + ((backOW - backIW) / 2), Y], [X + ((backOW - backIW) / 2) + frontOffset, Y + length]) @@ -198,7 +211,11 @@ function bellows (options = {}) { t = 0 t2 = 0 } - dash(ctx, BLUE, dpi, [foldIN + t, Y + i * fold ], [foldIN - ((backOW - backIW) / 2) + t2, (Y + (i + 1) * fold) ]) + if (side === 1 || parts > 1) { + line(ctx, BLACK, [foldIN + t, Y + i * fold ], [foldIN - ((backOW - backIW) / 2) + t2, (Y + (i + 1) * fold) ]) + } else { + dash(ctx, BLUE, dpi, [foldIN + t, Y + i * fold ], [foldIN - ((backOW - backIW) / 2) + t2, (Y + (i + 1) * fold) ]) + } } else { if (backIW !== frontIW) { t = taper(backIW, frontIW, length, i * fold) @@ -207,7 +224,11 @@ function bellows (options = {}) { t = 0 t2 = 0 } - dash(ctx, BLUE, dpi, [foldOUT + t, Y + i * fold ], [foldIN + t2, (Y + (i + 1) * fold) ]) + if (side === 1 || parts > 1) { + line(ctx, BLACK, [foldOUT + t, Y + i * fold ], [foldIN + t2, (Y + (i + 1) * fold) ]) + } else { + dash(ctx, BLUE, dpi, [foldOUT + t, Y + i * fold ], [foldIN + t2, (Y + (i + 1) * fold) ]) + } } // } @@ -250,8 +271,20 @@ function bellows (options = {}) { if (parts === 4) { line(ctx, BLACK, [X, Y], [X + frontOffset, Y + length]) } - if (parts !== 1 || side === 4) { + if ((parts !== 1 || side === 4) && !over) { line(ctx, BLACK, [X + backOH, Y], [X + backOH - frontOffset, Y + length]) + //cut marks + for (let i = 1; i < folds; i++) { + if (i % 2 !== 0) { + if (backIH !== frontIH) { + t = taper(backIH, frontIH, length, i * fold) + } else { + t = 0 + } + line(ctx, BLACK, [foldIN + backIH - t, Y + (i * fold)], [foldIN + backIH - t + ((backOH - backIH) / 2), Y + (i * fold)]) + } + } + } //inner //line(ctx, BLACK, [X + ((backOH - backIH) / 2), Y], [X + ((backOH - backIH) / 2) + frontOffset, Y + length]) @@ -278,7 +311,7 @@ function bellows (options = {}) { } else { t = 0 } - //fold in + //fold i dash(ctx, RED, dpi, [foldOUT + t, Y + (i * fold)], [foldOUT + backOH - t, Y + (i * fold)]) } } @@ -293,7 +326,12 @@ function bellows (options = {}) { t = 0 t2 = 0 } - dash(ctx, BLUE, dpi, [foldIN + t, Y + i * fold ], [foldIN - ((backOH - backIH) / 2) + t2, (Y + (i + 1) * fold) ]) + if (parts === 4){ + line(ctx, BLACK, [foldIN + t, Y + i * fold ], [foldIN - ((backOH - backIH) / 2) + t2, (Y + (i + 1) * fold) ]) + } else { + dash(ctx, BLUE, dpi, [foldIN + t, Y + i * fold ], [foldIN - ((backOH - backIH) / 2) + t2, (Y + (i + 1) * fold) ]) + } + } else { if (backIH !== frontIH) { t = taper(backIH, frontIH, length, i * fold) @@ -302,7 +340,11 @@ function bellows (options = {}) { t = 0 t2 = 0 } - dash(ctx, BLUE, dpi, [foldOUT + t, Y + i * fold ], [foldIN + t2, (Y + (i + 1) * fold) ]) + if (parts === 4) { + line(ctx, BLACK, [foldOUT + t, Y + i * fold ], [foldIN + t2, (Y + (i + 1) * fold) ]) + } else { + dash(ctx, BLUE, dpi, [foldOUT + t, Y + i * fold ], [foldIN + t2, (Y + (i + 1) * fold) ]) + } } // } @@ -331,15 +373,90 @@ function bellows (options = {}) { } function overlap (side) { - const frontOffset = Math.round((backOW - frontOW) / 2) - - const X = -backOW / 2 - const Y = -length / 2 - - let foldIN = X + ((backOW - backIW) / 2) //inside - let foldOUT = X //outside + const Y = -length / 2 + let X + let frontOffset + let foldIN + let foldOUT let t let t2 + + let backO + let backI + let frontO + let frontI + + if (side % 2 === 0) { + X = -backOH / 2 + foldIN = X + ((backOH - backIH) / 2) + frontOffset = Math.round((backOH - frontOH) / 2) + backI = backIH + backO = backOH + frontI = frontIH + frontO = frontOH + } else { + X = -backOW / 2 + foldIN = X + ((backOW - backIW) / 2) + frontOffset = Math.round((backOW - frontOW) / 2) + + backI = backIW + backO = backOW + frontI = frontIW + frontO = frontOW + } + + foldOUT = X + //sides + if (side === 1 || parts === 4 || (parts === 2 && side === 3)) { + //line(ctx, BLACK, [X, Y], [X + frontOffset, Y + length]) + } + line(ctx, BLACK, [X + (backO * 0.3) + ((backO - backI) / 2), Y], [foldOUT + (backO * 0.3) + ((backO - backI) / 2), Y + length]) + + //top + line(ctx, BLACK, [X, Y], [X + (backO * 0.3) + ((backO - backI) / 2), Y]) + //bottom + line(ctx, BLACK, [X + frontOffset, Y + length], [foldOUT + (backO * 0.3) + ((backO - backI) / 2), Y + length]) + + //fold lines + for (let i = 1; i < folds; i++) { + if (side % 2 === 0) { + if (i % 2 === 0) { + if (backI !== frontI) { + t = taper(backI, frontI, length, i * fold) + } else { + t = 0 + } + //fold out + dash(ctx, BLUE, dpi, [foldIN + t, Y + (i * fold)], [foldIN + (backO * 0.3), Y + (i * fold)]) + } else { + if (backO !== frontO) { + t = taper(backO, frontO, length, i * fold) + } else { + t = 0 + } + //fold in + dash(ctx, RED, dpi, [foldOUT + t, Y + (i * fold)], [foldOUT + (backO * 0.3) + ((backO - backI) / 2), Y + (i * fold)]) + } + } else { + if (i % 2 !== 0) { + if (backI !== frontI) { + t = taper(backI, frontI, length, i * fold) + } else { + t = 0 + } + //fold out + dash(ctx, BLUE, dpi, [foldIN + t, Y + (i * fold)], [foldIN + (backO * 0.3), Y + (i * fold)]) + } else { + if (backO !== frontO) { + t = taper(backO, frontO, length, i * fold) + } else { + t = 0 + } + //fold in + dash(ctx, RED, dpi, [foldOUT + t, Y + (i * fold)], [foldOUT + (backO * 0.3) + ((backO - backI) / 2), Y + (i * fold)]) + } + } + } } if (key) { @@ -365,7 +482,14 @@ function bellows (options = {}) { sideW(1) if (parts === 4) { - ctx.translate(backOH - backIH + (0.2 * backOW), 0) + if (over) { + ctx.translate((backOW / 2) + (backOH / 2) - ( ((backOW - frontIW) + (backOH - frontIH)) / 4 ), align) + ctx.rotate((angleW + angleH) / 2) + overlap(1) + ctx.rotate(-(angleW + angleH) / 2) + ctx.translate(-(backOW / 2) - (backOH / 2) + ( ((backOW - frontIW) + (backOH - frontIH)) / 4), -align) + } + ctx.translate(backOW - backIW + (0.3 * backOW), 0) } ctx.translate((backOW / 2) + (backOH / 2) - (((backOW - frontIW) + (backOH - frontIH)) / 4), align) @@ -373,21 +497,42 @@ function bellows (options = {}) { sideH(2) if (parts === 4 || parts === 2) { - ctx.translate(backOW - backIW, 0) + if (over) { + ctx.translate((backOW / 2) + (backOH / 2) - ( ((backOW - frontIW) + (backOH - frontIH)) / 4 ), align) + ctx.rotate((angleW + angleH) / 2) + overlap(2) + ctx.rotate(-(angleW + angleH) / 2) + ctx.translate(-(backOW / 2) - (backOH / 2) + ( ((backOW - frontIW) + (backOH - frontIH)) / 4), -align) + } + ctx.translate(backOH - backIH + (0.3 * backOH), 0) } ctx.translate((backOW / 2) + (backOH / 2) - (((backOW - frontIW) + (backOH - frontIH)) / 4), align) ctx.rotate((angleW + angleH) / 2) sideW(3) - if (parts === 4) { - ctx.translate(backOH - backIH, 0) + if (parts === 4) { + if (over) { + ctx.translate((backOW / 2) + (backOH / 2) - ( ((backOW - frontIW) + (backOH - frontIH)) / 4 ), align) + ctx.rotate((angleW + angleH) / 2) + overlap(3) + ctx.rotate(-(angleW + angleH) / 2) + ctx.translate(-(backOW / 2) - (backOH / 2) + ( ((backOW - frontIW) + (backOH - frontIH)) / 4), -align) + } + ctx.translate(backOW - backIW + (0.3 * backOW), 0) } ctx.translate((backOW / 2) + (backOH / 2) - (((backOW - frontIW) + (backOH - frontIH)) / 4), align) ctx.rotate((angleW + angleH) / 2) sideH(4) + + if (over) { + ctx.translate((backOW / 2) + (backOH / 2) - (((backOW - frontIW) + (backOH - frontIH)) / 4), align) + ctx.rotate((angleW + angleH) / 2) + overlap(4) + } + return canvas.toDataURL() }