<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Production Entry - Exact Nesting</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
/* ---------------- BASE ---------------- */
body{ font-family:'Segoe UI',sans-serif; background:#f4f6f9; margin:0; padding-bottom:80px }
h2{ background:#1a73e8; color:#fff; text-align:center; padding:10px; margin:0; font-size:15px }
.container{padding:10px}
.box{ background:#fff; border-radius:6px; padding:10px; margin-bottom:10px; box-shadow:0 2px 5px rgba(0,0,0,.08) }
h3 { margin: 5px 0; font-size: 13px; color: #1a73e8; border-bottom: 1px solid #eee; }

/* ---------------- FORM ---------------- */
label{ font-weight:600; font-size:11px; margin-bottom:2px; display:block; }
input{ width:100%; height:28px; padding:4px 6px; font-size:11px; border:1px solid #cfd4dc; border-radius:4px; box-sizing:border-box; }
input[readonly]{background:#f5f6f8}

/* ---------------- GRID ---------------- */
.row{ display:grid; gap:6px; margin-bottom:8px; }
@media(min-width:900px){ .row-4{grid-template-columns:repeat(4,1fr)} }
@media(max-width:899px){ .row-4{grid-template-columns:repeat(2,1fr)} }

/* ---------------- BUTTON ---------------- */
button{ padding:8px; font-size:12px; border:none; border-radius:4px; cursor:pointer }
.btn-save{ background:#1a73e8; color:#fff; width:100% }
.btn-add { background:#28a745; color:#fff; width:100%; height:28px; }

/* ---------------- CANVAS & TABLE ---------------- */
.sticky{ position:fixed; bottom:0; width:100%; background:#fff; padding:8px; box-shadow:0 -2px 5px rgba(0,0,0,.1); box-sizing:border-box; }
table{ width:100%; border-collapse:collapse; font-size:11px; margin-top:5px; }
th,td{ border:1px solid #ddd; padding:6px; text-align:center }
th{ background:#f1f3f6 }
canvas { max-width:100%; height:auto; display:block; margin:10px auto; border:1px solid #ccc; background:#fff; }
</style>
</head>

<body>

<h2>Production Entry</h2>

<div class="container">
  <div class="box">
    
    <h3>1. Sheet Dimensions</h3>
    <div class="row row-4">
      <div><label>Thickness (mm)</label><input type="number" id="sheetThk" step="0.01"></div>
      <div><label>Sheet Width (mm)</label><input type="number" id="sheetWid"></div>
      <div><label>Sheet Length (mm)</label><input type="number" id="sheetLen"></div>
      <div><label>No. of Sheets</label><input type="number" id="prodSheets"></div>
    </div>

    <h3>2. Part Details</h3>
    <div class="row row-4">
      <div><label>Blank Width (mm)</label><input type="number" id="width"></div>
      <div><label>Blank Length (mm)</label><input type="number" id="length1"></div>
      <div><label>Finish Wt (kg)</label><input type="number" id="FW" step="0.001"></div>
      <div><label>Pcs/Sheet</label><input type="number" id="calQty" readonly></div>
    </div>

    <div class="row row-4">
      <div><label>Production Qty</label><input type="number" id="prodQty" readonly></div>
      <div><label>Sheet Weight (kg)</label><input type="number" id="sheetWeight" readonly></div>
      <div><label>Scrap Weight (kg)</label><input type="number" id="scrapWeight" readonly></div>
    </div>
  </div>

  <div class="box">
    <h3>3. Offcut & Preview</h3>
    <canvas id="nestCanvas" width="600" height="350"></canvas>
  </div>
</div>



<script>
const num = x => isFinite(parseFloat(x)) ? parseFloat(x) : 0;
const INT = x => Math.floor(num(x));

const inputIds = ['sheetThk', 'sheetWid', 'sheetLen', 'prodSheets', 'width', 'length1', 'FW'];
inputIds.forEach(id => document.getElementById(id).addEventListener('input', runCalculations));

function runCalculations() {
    const sw = num(document.getElementById('sheetWid').value);
    const sl = num(document.getElementById('sheetLen').value);
    const pw = num(document.getElementById('width').value);
    const pl = num(document.getElementById('length1').value);
    const thk = num(document.getElementById('sheetThk').value);
    const sQty = num(document.getElementById('prodSheets').value);

    // 1. Pieces Per Sheet Logic (Exact as old)
    let n3 = sl, n4 = sw;
    if (n4 > n3) [n3, n4] = [n4, n3]; // Normalize Sheet

    // Orientation 1
    const A1 = INT(n3 / pw) * INT(n4 / pl);
    const remL1 = n3 - INT(n3 / pw) * pw;
    const remW1 = n4 - INT(n4 / pl) * pl;
    const part1_1 = INT(remL1 / pl) * INT(n4 / pw);
    const part1_2 = INT(remW1 / pw) * INT(n3 / pl);
    const total1 = A1 + Math.max(part1_1, part1_2);

    // Orientation 2
    const B1 = INT(n3 / pl) * INT(n4 / pw);
    const remL2 = n3 - INT(n3 / pl) * pl;
    const remW2 = n4 - INT(n4 / pw) * pw;
    const part2_1 = INT(remL2 / pw) * INT(n4 / pl);
    const part2_2 = INT(remW2 / pl) * INT(n3 / pw);
    const total2 = B1 + Math.max(part2_1, part2_2);

    const bestQty = Math.max(total1, total2);
    const useOrientation = (total1 >= total2) ? 1 : 2;

    document.getElementById('calQty').value = bestQty;
    document.getElementById('prodQty').value = bestQty * sQty;

    // 2. Weights
    const sWt = (thk * sw * sl * 7.86 * sQty) / 1000000;
    document.getElementById('sheetWeight').value = sWt.toFixed(3);
    const scrap = sWt - (num(document.getElementById('FW').value) * bestQty * sQty);
    document.getElementById('scrapWeight').value = scrap > 0 ? scrap.toFixed(3) : 0;

    drawNesting(useOrientation);
}

function drawNesting(orient) {
    const canvas = document.getElementById('nestCanvas');
    const ctx = canvas.getContext("2d");
    let sl = num(document.getElementById('sheetLen').value);
    let sw = num(document.getElementById('sheetWid').value);
    let pw = num(document.getElementById('width').value);
    let pl = num(document.getElementById('length1').value);

    ctx.clearRect(0, 0, canvas.width, canvas.height);
    if (!sl || !sw || !pw || !pl) return;

    if (sw > sl) [sl, sw] = [sw, sl]; // Always draw longer side horizontally
    if (orient === 2) [pw, pl] = [pl, pw]; // Swap part dims for Orientation 2

    const scale = Math.min((canvas.width - 40) / sl, (canvas.height - 40) / sw);
    const ox = 20, oy = 20;

    // Draw Sheet Border
    ctx.strokeStyle = "#333";
    ctx.lineWidth = 2;
    ctx.strokeRect(ox, oy, sl * scale, sw * scale);

    let count = 0;
    const cols = INT(sl / pw);
    const rows = INT(sw / pl);

    // Main Grid
    ctx.fillStyle = "#4caf50";
    ctx.strokeStyle = "#fff";
    for (let r = 0; r < rows; r++) {
        for (let c = 0; c < cols; c++) {
            ctx.fillRect(ox + c * pw * scale, oy + r * pl * scale, pw * scale, pl * scale);
            ctx.strokeRect(ox + c * pw * scale, oy + r * pl * scale, pw * scale, pl * scale);
            count++;
        }
    }

    // Remainder Rotated Parts (Blue)
    const usedL = cols * pw;
    const usedW = rows * pl;
    const remL = sl - usedL;
    const remW = sw - usedW;

    ctx.fillStyle = "#2196f3";
    // Check vertical strip on the right
    if (INT(remL / pl) * INT(sw / pw) > 0) {
        const rCols = INT(remL / pl);
        const rRows = INT(sw / pw);
        for (let r = 0; r < rRows; r++) {
            for (let c = 0; c < rCols; c++) {
                ctx.fillRect(ox + usedL * scale + c * pl * scale, oy + r * pw * scale, pl * scale, pw * scale);
                ctx.strokeRect(ox + usedL * scale + c * pl * scale, oy + r * pw * scale, pl * scale, pw * scale);
            }
        }
    } 
    // Check horizontal strip on bottom (if right strip wasn't better)
    else if (INT(remW / pw) * INT(sl / pl) > 0) {
        const bCols = INT(sl / pl);
        const bRows = INT(remW / pw);
        for (let r = 0; r < bRows; r++) {
            for (let c = 0; c < bCols; c++) {
                ctx.fillRect(ox + c * pl * scale, oy + usedW * scale + r * pw * scale, pl * scale, pw * scale);
                ctx.strokeRect(ox + c * pl * scale, oy + usedW * scale + r * pw * scale, pl * scale, pw * scale);
            }
        }
    }
}

window.onload = () => {
    document.getElementById('prodDate').value = new Date().toISOString().split('T')[0];
    document.getElementById('jobCard').value = "JC-" + Math.floor(Math.random()*99999);
};
</script>
</body>
</html>
				
			
Home
Account
0
Cart