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