{"id":7977,"date":"2026-07-03T08:52:04","date_gmt":"2026-07-03T08:52:04","guid":{"rendered":"https:\/\/bg-filtration.de\/?p=7977"},"modified":"2026-07-10T08:30:56","modified_gmt":"2026-07-10T08:30:56","slug":"takma-filtre-hesaplamasi","status":"publish","type":"post","link":"https:\/\/bg-filtration.de\/tr\/einbaufilter-berechnung\/","title":{"rendered":"Dahili filtre hesaplamas\u0131"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"7977\" class=\"elementor elementor-7977\" data-elementor-post-type=\"post\">\n\t\t\t\t<div class=\"elementor-element elementor-element-a4be578 e-con-full e-flex e-con e-parent\" data-id=\"a4be578\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-0abbbb5 elementor-widget elementor-widget-html\" data-id=\"0abbbb5\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<!DOCTYPE html>\r\n<html lang=\"de\">\r\n<head>\r\n<meta charset=\"UTF-8\">\r\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n<title>Einbaufilter-Auslegung | bg filtration<\/title>\r\n<style>\r\n* { box-sizing: border-box; margin: 0; padding: 0; }\r\nbody { font-family: 'Segoe UI', Arial, sans-serif; background: #f0f4f8; color: #1a2233; min-height: 100vh; padding: 18px; }\r\nh1 { font-size: 1.2rem; font-weight: 700; color: #004f9e; margin-bottom: 3px; }\r\n.sub { font-size: 0.74rem; color: #5a6a80; margin-bottom: 14px; }\r\n.layout { display: flex; gap: 14px; flex-wrap: wrap; }\r\n.panel { background: #ffffff; border-radius: 10px; padding: 15px; border: 1px solid #d0d8e8; }\r\n.controls { min-width: 255px; flex: 0 0 255px; }\r\n.right { flex: 1; min-width: 520px; }\r\nlabel { display: block; font-size: 0.7rem; color: #4a5a72; margin-bottom: 3px; margin-top: 11px; text-transform: uppercase; letter-spacing: 0.06em; }\r\nlabel:first-child { margin-top: 0; }\r\ninput[type=number] { width: 100%; padding: 7px 10px; border-radius: 6px; border: 1px solid #b8c8dc; background: #f8fafc; color: #1a2233; font-size: 0.88rem; outline: none; }\r\ninput[type=number]:focus { border-color: #004f9e; }\r\n.rg { display: flex; gap: 5px; margin-top: 2px; }\r\n.rb { flex: 1; padding: 7px 4px; border-radius: 6px; border: 1px solid #b8c8dc; background: #f0f4f8; color: #4a5a72; font-size: 0.8rem; cursor: pointer; text-align: center; transition: all 0.15s; user-select: none; }\r\n.rb.on { background: #d6e8f8; border-color: #004f9e; color: #004f9e; font-weight: 700; }\r\n.btn { width: 100%; margin-top: 14px; padding: 10px; border-radius: 7px; border: none; background: #004f9e; color: #fff; font-size: 0.9rem; font-weight: 700; cursor: pointer; }\r\n.btn:hover { background: #0066cc; }\r\n.sep { height: 1px; background: #d0d8e8; margin: 11px 0; }\r\n.cards { display: flex; flex-direction: column; gap: 7px; margin-bottom: 12px; }\r\n.card { border-radius: 7px; padding: 10px 12px; border: 1px solid #d0d8e8; background: #f8fafc; }\r\n.card.C { border-left: 3px solid #1a8a4a; }\r\n.card.M { border-left: 3px solid #b86000; }\r\n.card.X { border-left: 3px solid #c0001a; background: #fff5f5; }\r\n.ch { display: flex; align-items: center; gap: 7px; margin-bottom: 4px; }\r\n.badge { font-size: 0.65rem; font-weight: 700; padding: 2px 7px; border-radius: 20px; text-transform: uppercase; }\r\n.bg { background: #e8f5ee; color: #1a8a4a; border: 1px solid #1a8a4a; }\r\n.by { background: #fff3e0; color: #b86000; border: 1px solid #b86000; }\r\n.br { background: #ffeaea; color: #c0001a; border: 1px solid #c0001a; }\r\n.ct { font-size: 0.84rem; font-weight: 700; color: #1a2233; }\r\n.cb { font-size: 0.77rem; color: #4a5a72; line-height: 1.55; }\r\n.cb strong { color: #1a2233; }\r\n.nb { background: #fff8e0; border: 1px solid #c8a000; border-radius: 5px; padding: 6px 9px; font-size: 0.73rem; color: #7a5000; margin-top: 4px; }\r\n.nb::before { content: \"\u26a0 \"; }\r\n.srow { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 12px; }\r\n.sblk { flex: 1; min-width: 240px; }\r\n.slbl { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.07em; color: #004f9e; margin-bottom: 5px; padding-bottom: 4px; border-bottom: 1px solid #d0d8e8; display: flex; justify-content: space-between; align-items: center; }\r\ncanvas { display: block; width: 100%; border-radius: 7px; background: #f8fafc; border: 1px solid #c8d4e8; }\r\n\/* Wrapper around each canvas: holds the real (translatable) text labels that are\r\n   overlaid on top of the drawing. container-type\/cqw lets the labels scale\r\n   exactly with the canvas regardless of its rendered size. *\/\r\n.cwrap { position: relative; container-type: inline-size; }\r\n.clabels { position: absolute; inset: 0; pointer-events: none; overflow: hidden; }\r\n.clabels span { position: absolute; white-space: nowrap; font-family: 'Segoe UI', Arial, sans-serif; line-height: 1; }\r\n.bexp { padding: 4px 10px; border-radius: 5px; border: 1px solid #b8c8dc; background: #d6e8f8; color: #004f9e; font-size: 0.72rem; font-weight: 600; cursor: pointer; }\r\n.bexp:hover { background: #b8d4f0; }\r\n.inf { font-size: 0.68rem; color: #5a6a80; line-height: 1.5; margin-top: 9px; }\r\n.inf strong { color: #2a4a6a; }\r\n.empty { text-align: center; padding: 30px; color: #8a9ab8; font-size: 0.83rem; }\r\n<\/style>\r\n<\/head>\r\n<body>\r\n<h1>Einbaufilter-Auslegung<\/h1>\r\n<div class=\"sub\">Totalabscheider mit Filteranbau \u00b7 bg filtration GmbH \u00b7 Draufsicht Schnitt<\/div>\r\n<div class=\"layout\">\r\n  <div class=\"panel controls\">\r\n    <label>Abscheider-Au\u00dfendurchmesser (mm)<\/label>\r\n    <input type=\"number\" id=\"d\" value=\"800\" min=\"300\" max=\"3000\" step=\"50\">\r\n    <label>Elementgruppe<\/label>\r\n    <div class=\"rg\">\r\n      <div class=\"rb on\" id=\"gt\" onclick=\"setG('t')\">Taschen<\/div>\r\n      <div class=\"rb\" id=\"gp\" onclick=\"setG('p')\">Platten<\/div>\r\n    <\/div>\r\n    <div class=\"sep\"><\/div>\r\n    <label>Abstand Schlitzplatte \u2192 Abscheider, konservativ (mm)<\/label>\r\n    <input type=\"number\" id=\"sp\" value=\"50\" min=\"0\" max=\"500\" step=\"10\">\r\n    <label>Abstand Schlitzplatte \u2192 Abscheider, maximal (mm)<\/label>\r\n    <input type=\"number\" id=\"spmax\" value=\"150\" min=\"0\" max=\"500\" step=\"10\">\r\n    <label>Abstand Geh\u00e4usewand \u2192 \u00e4u\u00dferstes Element (mm)<\/label>\r\n    <input type=\"number\" id=\"sw\" value=\"80\" min=\"10\" max=\"300\" step=\"5\">\r\n    <button class=\"btn\" onclick=\"calc()\">\u25b6 Berechnen<\/button>\r\n    <div class=\"sep\"><\/div>\r\n    <div class=\"inf\">\r\n      <strong>Raster:<\/strong> 105 mm Mitte-zu-Mitte<br>\r\n      <strong>Ungerade:<\/strong> 1 Element in Mitte, dann \u00b1105 mm<br>\r\n      <strong>Gerade:<\/strong> erstes Element bei \u00b152,5 mm<br>\r\n      <strong>L\u00e4ngen:<\/strong> Elemente weiter au\u00dfen ggf. k\u00fcrzer (Kreisbegrenzung)<br>\r\n      <strong>Schlitzplatte:<\/strong> konservativ 50 mm \/ maximal 100 mm unterhalb Abscheider<br>\r\n      <strong>Max. Schlitzplatten-Breite:<\/strong> 0,9 \u00d7 D\r\n    <\/div>\r\n  <\/div>\r\n  <div class=\"right\">\r\n    <div class=\"panel\">\r\n      <div style=\"font-size:0.7rem;text-transform:uppercase;letter-spacing:.07em;color:#004f9e;margin-bottom:9px;padding-bottom:5px;border-bottom:1px solid #d0d8e8\">Auslegungsergebnis<\/div>\r\n      <div class=\"cards\" id=\"cards\"><div class=\"empty\">Durchmesser eingeben und berechnen<\/div><\/div>\r\n      <div class=\"srow\">\r\n        <div class=\"sblk\">\r\n          <div class=\"slbl\"><span style=\"color:#1a8a4a\">\u2713 Konservativ<\/span><button class=\"bexp\" onclick=\"expPNG('c')\">\u2b07 PNG<\/button><\/div>\r\n          <div class=\"cwrap\">\r\n            <canvas id=\"cc\" width=\"1200\" height=\"1500\" style=\"width:100%;height:auto;\"><\/canvas>\r\n            <div class=\"clabels\" id=\"cl-c\"><\/div>\r\n          <\/div>\r\n        <\/div>\r\n        <div class=\"sblk\">\r\n          <div class=\"slbl\"><span style=\"color:#b86000\">\u26a0 Maximal<\/span><button class=\"bexp\" onclick=\"expPNG('m')\">\u2b07 PNG<\/button><\/div>\r\n          <div class=\"cwrap\">\r\n            <canvas id=\"cm\" width=\"1200\" height=\"1500\" style=\"width:100%;height:auto;\"><\/canvas>\r\n            <div class=\"clabels\" id=\"cl-m\"><\/div>\r\n          <\/div>\r\n        <\/div>\r\n      <\/div>\r\n    <\/div>\r\n  <\/div>\r\n<\/div>\r\n<script>\r\nconst PITCH = 105;\r\nlet grp = 't';\r\nconst ELEMS = {\r\n  t: [{l:750,a:.75},{l:850,a:.85},{l:1100,a:1.1},{l:1250,a:1.25},{l:1600,a:1.6},{l:2100,a:2.1}],\r\n  p: [{l:600,a:1.3},{l:800,a:1.8},{l:1000,a:2.3},{l:1200,a:2.8}]\r\n};\r\n\/\/ \u2500\u2500 Translatable text used inside the technical drawings (canvases) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\/\/ These are the only strings that are drawn as \"graphics\" rather than plain\r\n\/\/ HTML, so TranslatePress can't reach them unless they exist as real DOM text.\r\n\/\/ They are rendered as HTML labels overlaid on the canvas (see addLabel()) and\r\n\/\/ are baked back into the exported PNG at export time (see expPNG()). Edit the\r\n\/\/ values here to change the wording; TranslatePress can translate the labels\r\n\/\/ directly on the page since they are now normal text nodes.\r\nconst TXT = {\r\n  labelConservative: 'Konservativ',\r\n  labelMaximal: 'Maximal',\r\n  noElementsPossible: 'Keine Elemente m\u00f6glich',\r\n  slitPlateFlange: 'Schlitzplatte \/ Flansch',\r\n  mm: 'mm',\r\n  diameterPrefix: '\u00d8',\r\n  elementsShort: 'El.',\r\n  areaUnit: 'm\u00b2',\r\n  slitPlateDistanceLabel: 'Schlitzpl.-Abstand:'\r\n};\r\nlet RES = null;\r\nfunction setG(g) {\r\n  grp = g;\r\n  document.getElementById('gt').classList.toggle('on', g==='t');\r\n  document.getElementById('gp').classList.toggle('on', g==='p');\r\n}\r\n\/\/ Positions of n elements (offsets from vessel center, mm)\r\nfunction positions(n) {\r\n  const p = [];\r\n  if (n % 2 === 1) { for (let i=0;i<n;i++) p.push((i - Math.floor(n\/2)) * PITCH); }\r\n  else             { for (let i=0;i<n;i++) p.push((i - n\/2 + 0.5) * PITCH); }\r\n  return p;\r\n}\r\n\/\/ Geometry:\r\n\/\/ - Vessel circle: center at (cx, cy), radius R\r\n\/\/ - Schlitzplatte: spMm BELOW the bottom of the circle (outside the vessel)\r\n\/\/   Elements start at schlitzplatte and go upward into the vessel\r\n\/\/ - Element at lateral offset x from center:\r\n\/\/   - starts at schlitzplatte (= R + spMm below center)\r\n\/\/   - tip must not go above: cy - sqrt(R\u00b2-x\u00b2)  (top of circle at that x)\r\n\/\/   - available length = (R + spMm) + sqrt(R\u00b2-x\u00b2) - gapMm\r\n\/\/     where gapMm = required clearance from tip to back wall\r\nfunction maxAvailLen(xMm, R, spMm, gapMm) {\r\n  const ax = Math.abs(xMm);\r\n  if (ax >= R) return 0;\r\n  const chord = Math.sqrt(R*R - ax*ax);\r\n  return R + spMm + chord - gapMm;\r\n}\r\nfunction bestElem(xMm, R, spMm, gapMm) {\r\n  const avail = maxAvailLen(xMm, R, spMm, gapMm);\r\n  if (avail <= 0) return null;\r\n  const sorted = [...ELEMS[grp]].sort((a,b) => b.l - a.l);\r\n  for (const e of sorted) { if (e.l <= avail) return e; }\r\n  return null;\r\n}\r\n\/\/ Count how many elements fit laterally AND have at least one element type fitting\r\nfunction countFit(R, spMm, gapMm, maxHW) {\r\n  let n = 0;\r\n  for (let try_n = 1; try_n <= 15; try_n++) {\r\n    const pos = positions(try_n);\r\n    const outer = Math.max(...pos.map(Math.abs));\r\n    if (outer > maxHW) break;\r\n    if (!bestElem(outer, R, spMm, gapMm)) break;\r\n    n = try_n;\r\n  }\r\n  return n;\r\n}\r\nfunction calc() {\r\n  const D      = parseFloat(document.getElementById('d').value);\r\n  const R      = D \/ 2;\r\n  const spStd  = parseFloat(document.getElementById('sp').value);   \/\/ conservative: schlitzplatte offset from circle bottom\r\n  const spMax  = parseFloat(document.getElementById('spmax').value); \/\/ maximal: larger offset = longer elements\r\n  const swMm   = parseFloat(document.getElementById('sw').value);   \/\/ side wall gap (always respected)\r\n  const gapMm  = 40;  \/\/ internal minimum back-wall clearance (always enforced, not shown as input)\r\n  const maxW   = 0.9 * D;  \/\/ max schlitzplatte width\r\n  \/\/ Max half-width from lateral constraint: outermost element <= R - swMm\r\n  \/\/ AND schlitzplatte half-width (= outerX + swMm) <= maxW\/2\r\n  const maxHW_lateral = R - swMm;\r\n  const maxHW_plate   = maxW \/ 2 - swMm;\r\n  const maxHW = Math.min(maxHW_lateral, maxHW_plate);\r\n  const nC = countFit(R, spStd, gapMm, maxHW);\r\n  const nM = countFit(R, spMax, gapMm, maxHW);\r\n  function build(n, spMm) {\r\n    return positions(n).map(x => ({ x, el: bestElem(x, R, spMm, gapMm) }));\r\n  }\r\n  const aC = build(nC, spStd);\r\n  const aM = build(nM, spMax);\r\n  const areaC = aC.reduce((s,a) => s + (a.el ? a.el.a : 0), 0);\r\n  const areaM = aM.reduce((s,a) => s + (a.el ? a.el.a : 0), 0);\r\n  const needsAdj = nM > nC || areaM > areaC;\r\n  \/\/ Compute actual minimum back gap: element whose tip is closest to back wall\r\n  function minBackGapElem(assign, spMm) {\r\n    let minGap = Infinity, minElem = null;\r\n    assign.filter(a=>a.el).forEach(a => {\r\n      const dxMm = Math.abs(a.x);\r\n      const chordMm = dxMm < R ? Math.sqrt(R*R - dxMm*dxMm) : 0;\r\n      const gap = R + spMm + chordMm - a.el.l;\r\n      if (gap < minGap) { minGap = gap; minElem = a; }\r\n    });\r\n    return { gap: Math.round(minGap), elem: minElem };\r\n  }\r\n  const bgC = minBackGapElem(aC, spStd);\r\n  const bgM = minBackGapElem(aM, spMax);\r\n  const backGapC = bgC.gap;\r\n  const backGapM = bgM.gap;\r\n  RES = { D, R, spStd, spMax, swMm, nC, nM, aC, aM, areaC, areaM, needsAdj, maxW, backGapC, backGapM };\r\n  renderCards();\r\n  drawSketch('c');\r\n  drawSketch('m');\r\n}\r\nfunction mixStr(assign) {\r\n  const cnt = {};\r\n  assign.forEach(a => { if (a.el) { const k = a.el.l+'mm'; cnt[k] = (cnt[k]||0)+1; } });\r\n  return Object.entries(cnt).map(([k,v]) => v+'\u00d7 '+k).join(', ') || '\u2013';\r\n}\r\nfunction renderCards() {\r\n  const r = RES;\r\n  let h = '';\r\n  if (r.nC === 0) {\r\n    h += `<div class=\"card X\"><div class=\"ch\"><span class=\"badge br\">\u2717 Nicht m\u00f6glich<\/span><span class=\"ct\">Konservativ: 0 Elemente<\/span><\/div><div class=\"cb\">Kein Element passt mit den gew\u00e4hlten Abst\u00e4nden.<\/div><\/div>`;\r\n  } else {\r\n    h += `<div class=\"card C\"><div class=\"ch\"><span class=\"badge bg\">\u2713 Konservativ<\/span><span class=\"ct\">${r.nC} Elemente \u00b7 ${r.areaC.toFixed(2)} m\u00b2 Filterfl\u00e4che<\/span><\/div>\r\n    <div class=\"cb\">Belegung: <strong>${mixStr(r.aC)}<\/strong><br>\r\n    Schlitzplatten-Abstand: <strong>${r.spStd} mm<\/strong> \u00b7 R\u00fcckwandabstand (min.): <strong>${r.backGapC} mm<\/strong><br>\r\n    \u2192 Kein Anpassungsbedarf am Anbau.<\/div><\/div>`;\r\n  }\r\n  if (r.nM === 0) {\r\n    h += `<div class=\"card X\"><div class=\"ch\"><span class=\"badge br\">\u2717 Nicht m\u00f6glich<\/span><span class=\"ct\">Maximal: 0 Elemente<\/span><\/div><div class=\"cb\">Kein Element passt.<\/div><\/div>`;\r\n  } else {\r\n    const same = r.nM === r.nC && Math.abs(r.areaM - r.areaC) < 0.01;\r\n    let note = '';\r\n    if (same) note = `<div class=\"nb\">Identisch mit konservativer Auslegung \u2014 kein Gewinn durch Anpassung.<\/div>`;\r\n    else note = `<div class=\"nb\">Anbau um ${r.spMax - r.spStd} mm weiter nach unten versetzt (Schlitzplatten-Abstand ${r.spMax} mm statt ${r.spStd} mm). Pr\u00fcfen ob geometrisch m\u00f6glich!<\/div>`;\r\n    const bc = same ? 'by' : 'by';\r\n    const bl = same ? '= Identisch' : '\u26a0 Mit Anpassung';\r\n    h += `<div class=\"card M\"><div class=\"ch\"><span class=\"badge ${bc}\">${bl}<\/span><span class=\"ct\">${r.nM} Elemente \u00b7 ${r.areaM.toFixed(2)} m\u00b2 Filterfl\u00e4che<\/span><\/div>\r\n    <div class=\"cb\">Belegung: <strong>${mixStr(r.aM)}<\/strong><br>\r\n    Schlitzplatten-Abstand: <strong>${r.spMax} mm<\/strong> \u00b7 R\u00fcckwandabstand (min.): <strong>${r.backGapM} mm<\/strong>${note}<\/div><\/div>`;\r\n  }\r\n  document.getElementById('cards').innerHTML = h;\r\n}\r\n\/\/ \u2500\u2500 Text labels overlaid on a canvas \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\/\/ Instead of burning text into the canvas bitmap (which no translation plugin\r\n\/\/ can read), every label drawn on the technical drawing is created as a real\r\n\/\/ HTML <span> positioned on top of the canvas. Position\/size are expressed in\r\n\/\/ \"cqw\" (container query width) units so they scale exactly with the canvas\r\n\/\/ regardless of its rendered width \u2014 1 canvas coordinate unit is always\r\n\/\/ (1\/1200*100)cqw, matching the canvas's fixed 1200\u00d71500 internal resolution.\r\n\/\/ The original coordinate\/style values are also stored as data-* attributes so\r\n\/\/ expPNG() can re-draw the (possibly translated) text back into the exported\r\n\/\/ PNG, keeping the exported image identical in content to the original.\r\nfunction addLabel(container, text, x, y, opts = {}) {\r\n  const { fontPx = 24, bold = false, color = '#1a2233', align = 'center', rotate = 0 } = opts;\r\n  const span = document.createElement('span');\r\n  span.textContent = text;\r\n  span.dataset.x = x;\r\n  span.dataset.y = y;\r\n  span.dataset.align = align;\r\n  span.dataset.fontPx = fontPx;\r\n  span.dataset.bold = bold ? '1' : '0';\r\n  span.dataset.color = color;\r\n  span.dataset.rotate = rotate;\r\n  span.style.left = (x \/ 1200 * 100) + 'cqw';\r\n  span.style.top = (y \/ 1200 * 100) + 'cqw';\r\n  span.style.fontSize = (fontPx \/ 1200 * 100) + 'cqw';\r\n  span.style.fontWeight = bold ? '700' : '400';\r\n  span.style.color = color;\r\n  const tx = align === 'left' ? '0%' : align === 'right' ? '-100%' : '-50%';\r\n  let transform = `translate(${tx}, -50%)`;\r\n  if (rotate) transform += ` rotate(${rotate}deg)`;\r\n  span.style.transform = transform;\r\n  container.appendChild(span);\r\n  return span;\r\n}\r\n\/\/ \u2500\u2500 Draw sketch \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\nfunction drawSketch(mode) {\r\n  const r = RES;\r\n  const cvs = document.getElementById(mode === 'c' ? 'cc' : 'cm');\r\n  const ctx = cvs.getContext('2d');\r\n  const W = cvs.width;\r\n  const H = cvs.height;\r\n  const labelsEl = document.getElementById(mode === 'c' ? 'cl-c' : 'cl-m');\r\n  labelsEl.innerHTML = '';\r\n  ctx.clearRect(0, 0, W, H);\r\n  ctx.fillStyle = '#f8fafc';\r\n  ctx.fillRect(0, 0, W, H);\r\n  const assign = mode === 'c' ? r.aC : r.aM;\r\n  const n      = mode === 'c' ? r.nC : r.nM;\r\n  const col    = mode === 'c' ? '#3ab87a' : '#e8a83a';\r\n  const lbl    = mode === 'c' ? TXT.labelConservative : TXT.labelMaximal;\r\n  const spMm   = mode === 'c' ? r.spStd : r.spMax;\r\n  const gapMm  = r.gapMm;\r\n  if (n === 0) {\r\n    addLabel(labelsEl, TXT.noElementsPossible, W\/2, H\/2, { fontPx: 13, color: '#8a9ab8', align: 'center' });\r\n    return;\r\n  }\r\n  \/\/ \u2500\u2500 Scale & layout \u2500\u2500\r\n  \/\/ spMm = distance from BOTTOM OF CIRCLE to schlitzplatte (outside the circle)\r\n  const totalH_mm = r.D + spMm + 20;\r\n  const totalW_mm = r.D;\r\n  const padTop = 160, padBot = 220, padSide = 150;\r\n  const avW = W - padSide*2;\r\n  const avH = H - padTop - padBot;\r\n  const scale = Math.min(avW \/ totalW_mm, avH \/ totalH_mm);\r\n  const Rpx = r.R * scale;\r\n  const spPx = spMm * scale; \/\/ gap from circle bottom to schlitzplatte in pixels\r\n  \/\/ Circle center\r\n  const cx = W \/ 2;\r\n  const cy = padTop + Rpx;\r\n  \/\/ Schlitzplatte y: BELOW the bottom of the circle by spMm\r\n  const schlitzY = cy + Rpx + spPx;\r\n  \/\/ \u2500\u2500 Vessel circle (red) \u2500\u2500\r\n  ctx.beginPath();\r\n  ctx.arc(cx, cy, Rpx, 0, Math.PI*2);\r\n  ctx.fillStyle = 'rgba(220,230,245,0.85)';\r\n  ctx.fill();\r\n  ctx.strokeStyle = '#e84040';\r\n  ctx.lineWidth = 7.5;\r\n  ctx.stroke();\r\n  \/\/ \u2500\u2500 Center cross (faint) \u2500\u2500\r\n  ctx.strokeStyle = '#c0cce0'; ctx.lineWidth = 3; ctx.setLineDash([12,15]);\r\n  ctx.beginPath(); ctx.moveTo(cx-Rpx, cy); ctx.lineTo(cx+Rpx, cy); ctx.stroke();\r\n  ctx.beginPath(); ctx.moveTo(cx, cy-Rpx); ctx.lineTo(cx, cy+Rpx); ctx.stroke();\r\n  ctx.setLineDash([]);\r\n  \/\/ \u2500\u2500 Anbau side walls \u2500\u2500\r\n  \/\/ Width: outermost element center + swMm on each side\r\n  const outerX_mm = n > 0 ? Math.max(...assign.map(a => Math.abs(a.x))) : 0;\r\n  const halfBoxW_mm = outerX_mm + r.swMm;\r\n  const halfBoxW_px = halfBoxW_mm * scale;\r\n  const boxLeft  = cx - halfBoxW_px;\r\n  const boxRight = cx + halfBoxW_px;\r\n  \/\/ Side walls go from schlitzplatte corner UP to where they meet the circle (lower arc)\r\n  \/\/ schlitzplatte is spPx BELOW the bottom of the circle, so the walls are outside the circle\r\n  \/\/ They connect schlitzplatte corner \u2192 circle tangent point (lower half)\r\n  \/\/ Circle lower intersection at x = boxLeft: y = cy + sqrt(R\u00b2-dx\u00b2)  (if inside circle)\r\n  \/\/ If boxLeft is outside circle (|dx| >= R), wall goes straight up to circle bottom (cy+Rpx)\r\n  function circleBottomY(wallX) {\r\n    const dxPx = Math.abs(wallX - cx);\r\n    if (dxPx >= Rpx) return cy + Rpx; \/\/ outside circle: connect to bottom\r\n    return cy + Math.sqrt(Rpx*Rpx - dxPx*dxPx);\r\n  }\r\n  const leftWallTopY  = circleBottomY(boxLeft);\r\n  const rightWallTopY = circleBottomY(boxRight);\r\n  \/\/ Draw left wall: from schlitzplatte corner diagonally up to circle\r\n  ctx.beginPath();\r\n  ctx.moveTo(boxLeft, schlitzY);\r\n  ctx.lineTo(boxLeft, leftWallTopY);\r\n  ctx.strokeStyle = '#e84040';\r\n  ctx.lineWidth = 6;\r\n  ctx.stroke();\r\n  \/\/ Draw right wall\r\n  ctx.beginPath();\r\n  ctx.moveTo(boxRight, schlitzY);\r\n  ctx.lineTo(boxRight, rightWallTopY);\r\n  ctx.strokeStyle = '#e84040';\r\n  ctx.lineWidth = 6;\r\n  ctx.stroke();\r\n  \/\/ \u2500\u2500 Schlitzplatte (bottom horizontal bar) \u2500\u2500\r\n  ctx.beginPath();\r\n  ctx.moveTo(boxLeft, schlitzY);\r\n  ctx.lineTo(boxRight, schlitzY);\r\n  ctx.strokeStyle = '#e84040';\r\n  ctx.lineWidth = 6;\r\n  ctx.stroke();\r\n  \/\/ Label\r\n  addLabel(labelsEl, TXT.slitPlateFlange, cx, schlitzY + 55, { fontPx: 27, bold: true, color: '#8a0012', align: 'center' });\r\n  \/\/ \u2500\u2500 spMm annotation (circle bottom to schlitzplatte) \u2500\u2500\r\n  \/\/ Place to the right of the right wall, outside the drawing\r\n  const spDimX = boxRight + 60;\r\n  ctx.beginPath();\r\n  ctx.moveTo(spDimX, cy + Rpx);   \/\/ circle bottom\r\n  ctx.lineTo(spDimX, schlitzY);   \/\/ schlitzplatte\r\n  ctx.strokeStyle = '#1a2233'; ctx.lineWidth = 3; ctx.setLineDash([6,9]); ctx.stroke(); ctx.setLineDash([]);\r\n  htick(ctx, spDimX, cy + Rpx, '#1a2233');\r\n  htick(ctx, spDimX, schlitzY, '#1a2233');\r\n  \/\/ Text: always to the right of the dim line, horizontally, at midpoint\r\n  const spMidY = (cy + Rpx + schlitzY) \/ 2;\r\n  addLabel(labelsEl, spMm + ' ' + TXT.mm, spDimX + 15, spMidY + 9, { fontPx: 24, color: '#1a2233', align: 'left' });\r\n  \/\/ \u2500\u2500 Side-wall gap annotation (LEFT side) \u2500\u2500\r\n  const leftElemPx = cx - outerX_mm * scale;\r\n  const swDimY = schlitzY - 50;\r\n  ctx.beginPath();\r\n  ctx.moveTo(leftElemPx, swDimY);\r\n  ctx.lineTo(boxLeft, swDimY);\r\n  ctx.strokeStyle = '#1a2233'; ctx.lineWidth = 3; ctx.setLineDash([6,6]); ctx.stroke(); ctx.setLineDash([]);\r\n  vtick(ctx, leftElemPx, swDimY, '#1a2233');\r\n  vtick(ctx, boxLeft, swDimY, '#1a2233');\r\n  addLabel(labelsEl, r.swMm + ' ' + TXT.mm, (leftElemPx + boxLeft)\/2, swDimY - 12, { fontPx: 24, color: '#1a2233', align: 'center' });\r\n  \/\/ \u2500\u2500 Filter elements \u2500\u2500\r\n  assign.forEach(({ x, el }) => {\r\n    if (!el) return;\r\n    const ex = cx + x * scale;\r\n    const startY = schlitzY;\r\n    const endY   = schlitzY - el.l * scale;\r\n    ctx.beginPath();\r\n    ctx.moveTo(ex, startY);\r\n    ctx.lineTo(ex, endY);\r\n    ctx.strokeStyle = col;\r\n    ctx.lineWidth = 6.6;\r\n    ctx.stroke();\r\n    dot(ctx, ex, startY, col, 9);\r\n    dot(ctx, ex, endY,   col, 9);\r\n  });\r\n  \/\/ \u2500\u2500 Element length dimensions \u2500\u2500\r\n  \/\/ Rule: for each unique length, pick the FIRST element to the RIGHT of center (x > 0).\r\n  \/\/ If no element with that length is right of center, pick the one closest to center.\r\n  \/\/ Dim line sits directly next to that element (fixed offset), stacked with 84px spacing.\r\n  const byLen = {};\r\n  assign.filter(a=>a.el).forEach(a => {\r\n    const k = a.el.l;\r\n    const existing = byLen[k];\r\n    if (!existing) { byLen[k] = a; return; }\r\n    \/\/ Prefer first right of center (smallest positive x), else closest to center\r\n    const aRightOfCenter = a.x > 0;\r\n    const exRightOfCenter = existing.x > 0;\r\n    if (aRightOfCenter && !exRightOfCenter) { byLen[k] = a; return; }\r\n    if (!aRightOfCenter && exRightOfCenter) return;\r\n    \/\/ Both same side: pick smallest |x| (closest to center)\r\n    if (Math.abs(a.x) < Math.abs(existing.x)) byLen[k] = a;\r\n  });\r\n  const sortedLens = Object.values(byLen).sort((a,b) => b.el.l - a.el.l); \/\/ longest first\r\n  const DIM_OFFSET = 18; \/\/ px right of the element line \u2014 same for every dim\r\n  sortedLens.forEach((a, i) => {\r\n    const ex = cx + a.x * scale;\r\n    const sY = schlitzY;\r\n    const eY = schlitzY - a.el.l * scale;\r\n    const dx = ex + DIM_OFFSET; \/\/ always same offset from its own element\r\n    ctx.beginPath(); ctx.moveTo(dx, sY); ctx.lineTo(dx, eY);\r\n    ctx.strokeStyle = col; ctx.lineWidth = 3; ctx.setLineDash([9,9]); ctx.stroke(); ctx.setLineDash([]);\r\n    htick(ctx, dx, sY, col); htick(ctx, dx, eY, col);\r\n    addLabel(labelsEl, a.el.l + ' ' + TXT.mm, dx + 33, (sY + eY) \/ 2, { fontPx: 27, bold: true, color: col, align: 'center', rotate: -90 });\r\n  });\r\n  \/\/ \u2500\u2500 Actual back gap: at element with minimum gap (tip closest to back wall) \u2500\u2500\r\n  let minGapPx = Infinity, minGapElem = null;\r\n  assign.filter(a=>a.el).forEach(a => {\r\n    const dxPx = Math.abs(a.x) * scale;\r\n    const bwY = dxPx < Rpx ? cy - Math.sqrt(Rpx*Rpx - dxPx*dxPx) : schlitzY;\r\n    const tipY_ = schlitzY - a.el.l * scale;\r\n    const gPx = tipY_ - bwY;\r\n    if (gPx < minGapPx) { minGapPx = gPx; minGapElem = a; }\r\n  });\r\n  if (minGapElem) {\r\n    \/\/ Place annotation to the left of this element\r\n    const ex = cx + minGapElem.x * scale;\r\n    const tipY = schlitzY - minGapElem.el.l * scale;\r\n    const dxPx = Math.abs(minGapElem.x) * scale;\r\n    const backWallY = dxPx < Rpx ? cy - Math.sqrt(Rpx*Rpx - dxPx*dxPx) : tipY;\r\n    const actualGapMm = Math.round((tipY - backWallY) \/ scale);\r\n    const gapX = ex - 14;\r\n    ctx.beginPath(); ctx.moveTo(gapX, tipY); ctx.lineTo(gapX, backWallY);\r\n    ctx.strokeStyle = '#1a2233'; ctx.lineWidth = 3; ctx.setLineDash([6,6]); ctx.stroke(); ctx.setLineDash([]);\r\n    htick(ctx, gapX, tipY, '#1a2233');\r\n    htick(ctx, gapX, backWallY, '#1a2233');\r\n    addLabel(labelsEl, actualGapMm + ' ' + TXT.mm, gapX - 33, (tipY + backWallY) \/ 2, { fontPx: 24, color: '#1a2233', align: 'center', rotate: -90 });\r\n  }\r\n  \/\/ \u2500\u2500 Pitch dimension: LEFT side, between two leftmost adjacent elements, at mid-height \u2500\u2500\r\n  \/\/ Placed left of center to never conflict with right-side length dims\r\n  if (assign.length >= 2) {\r\n    const sorted = [...assign].sort((a,b) => a.x - b.x);\r\n    \/\/ Use the leftmost pair\r\n    const pair = [sorted[0], sorted[1]];\r\n    const p0x = cx + pair[0].x * scale;\r\n    const p1x = cx + pair[1].x * scale;\r\n    const shortEl = pair[0].el && pair[1].el\r\n      ? (pair[0].el.l < pair[1].el.l ? pair[0].el : pair[1].el)\r\n      : (pair[0].el || pair[1].el);\r\n    const elMidY = shortEl ? schlitzY - shortEl.l * scale * 0.5 : cy;\r\n    ctx.beginPath(); ctx.moveTo(p0x, elMidY); ctx.lineTo(p1x, elMidY);\r\n    ctx.strokeStyle = 'rgba(0,0,0,.45)'; ctx.lineWidth = 3; ctx.setLineDash([6,9]); ctx.stroke(); ctx.setLineDash([]);\r\n    vtick(ctx, p0x, elMidY, 'rgba(0,0,0,.45)');\r\n    vtick(ctx, p1x, elMidY, 'rgba(0,0,0,.45)');\r\n    addLabel(labelsEl, PITCH + ' ' + TXT.mm, (p0x+p1x)\/2, elMidY - 12, { fontPx: 24, color: '#1a2233', align: 'center' });\r\n  }\r\n  \/\/ \u2500\u2500 Diameter annotation below \u2500\u2500\r\n  const dY = schlitzY + 100;\r\n  ctx.beginPath(); ctx.moveTo(cx-Rpx, dY); ctx.lineTo(cx+Rpx, dY);\r\n  ctx.strokeStyle = '#1a2233'; ctx.lineWidth = 3; ctx.setLineDash([9,9]); ctx.stroke(); ctx.setLineDash([]);\r\n  arrowTip(ctx, cx-Rpx, dY, 1, '#1a2233');\r\n  arrowTip(ctx, cx+Rpx, dY, -1, '#1a2233');\r\n  addLabel(labelsEl, TXT.diameterPrefix + ' ' + r.D + ' ' + TXT.mm, cx, dY + 45, { fontPx: 30, bold: true, color: '#1a2233', align: 'center' });\r\n  \/\/ \u2500\u2500 Top label \u2500\u2500\r\n  const totalArea = assign.reduce((s,a) => s + (a.el ? a.el.a : 0), 0);\r\n  addLabel(labelsEl, lbl + ': ' + n + ' ' + TXT.elementsShort + ' \u00b7 ' + totalArea.toFixed(2) + ' ' + TXT.areaUnit, 18, 54, { fontPx: 30, bold: true, color: col, align: 'left' });\r\n  addLabel(labelsEl, TXT.slitPlateDistanceLabel + ' ' + spMm + ' ' + TXT.mm, 18, 96, { fontPx: 27, color: '#4a5a72', align: 'left' });\r\n}\r\nfunction dot(ctx, x, y, col, r) {\r\n  ctx.beginPath(); ctx.arc(x, y, r, 0, Math.PI*2); ctx.fillStyle = col; ctx.fill();\r\n}\r\nfunction vtick(ctx, x, y, col) { \/\/ vertical tick\r\n  ctx.beginPath(); ctx.moveTo(x, y-12); ctx.lineTo(x, y+12); ctx.strokeStyle = col; ctx.lineWidth = 2; ctx.stroke();\r\n}\r\nfunction htick(ctx, x, y, col) { \/\/ horizontal tick\r\n  ctx.beginPath(); ctx.moveTo(x-12, y); ctx.lineTo(x+12, y); ctx.strokeStyle = col; ctx.lineWidth = 2; ctx.stroke();\r\n}\r\nfunction arrowTip(ctx, x, y, dir, col) {\r\n  ctx.beginPath();\r\n  ctx.moveTo(x, y); ctx.lineTo(x + dir*24, y-12);\r\n  ctx.moveTo(x, y); ctx.lineTo(x + dir*24, y+12);\r\n  ctx.strokeStyle = col; ctx.lineWidth = 4; ctx.stroke();\r\n}\r\n\/\/ expPNG bakes the current (on-screen, possibly TranslatePress-translated) text\r\n\/\/ labels back into a copy of the canvas before exporting, so the downloaded PNG\r\n\/\/ still contains every dimension\/label exactly like before \u2014 nothing about the\r\n\/\/ exported file changes, only where the text lives while on the page.\r\nfunction expPNG(mode) {\r\n  if (!RES) return;\r\n  const cvs = document.getElementById(mode === 'c' ? 'cc' : 'cm');\r\n  const n = mode === 'c' ? RES.nC : RES.nM;\r\n  const labelsEl = document.getElementById(mode === 'c' ? 'cl-c' : 'cl-m');\r\n  const out = document.createElement('canvas');\r\n  out.width = cvs.width;\r\n  out.height = cvs.height;\r\n  const octx = out.getContext('2d');\r\n  octx.drawImage(cvs, 0, 0);\r\n  labelsEl.querySelectorAll('span').forEach(span => {\r\n    const x = parseFloat(span.dataset.x);\r\n    const y = parseFloat(span.dataset.y);\r\n    const align = span.dataset.align || 'center';\r\n    const fontPx = parseFloat(span.dataset.fontPx) || 24;\r\n    const bold = span.dataset.bold === '1';\r\n    const color = span.dataset.color || '#1a2233';\r\n    const rotate = parseFloat(span.dataset.rotate) || 0;\r\n    octx.save();\r\n    octx.translate(x, y);\r\n    if (rotate) octx.rotate(rotate * Math.PI \/ 180);\r\n    octx.fillStyle = color;\r\n    octx.font = (bold ? 'bold ' : '') + fontPx + 'px Segoe UI,Arial';\r\n    octx.textAlign = align;\r\n    octx.textBaseline = 'alphabetic';\r\n    octx.fillText(span.textContent, 0, 0);\r\n    octx.restore();\r\n  });\r\n  const lnk = document.createElement('a');\r\n  lnk.download = `Filterauslegung_D${RES.D}mm_${n}El_${mode==='c'?'konservativ':'maximal'}.png`;\r\n  lnk.href = out.toDataURL('image\/png');\r\n  lnk.click();\r\n}\r\nwindow.addEventListener('load', calc);\r\ndocument.getElementById('d').addEventListener('keydown', e => { if (e.key==='Enter') calc(); });\r\n<\/script>\r\n<\/body>\r\n<\/html>\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-4758916 e-con-full elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-parent\" data-id=\"4758916\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-c7b374e elementor-widget elementor-widget-html\" data-id=\"c7b374e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<!DOCTYPE html>\n<html lang=\"de\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>Einbaufilter-Auslegung | bg filtration<\/title>\n<style>\n* { box-sizing: border-box; margin: 0; padding: 0; }\nbody { font-family: 'Segoe UI', Arial, sans-serif; background: #f0f4f8; color: #1a2233; min-height: 100vh; padding: 18px; }\nh1 { font-size: 1.2rem; font-weight: 700; color: #004f9e; margin-bottom: 3px; }\n.sub { font-size: 0.74rem; color: #5a6a80; margin-bottom: 14px; }\n.layout { display: flex; gap: 14px; flex-wrap: wrap; }\n.panel { background: #ffffff; border-radius: 10px; padding: 15px; border: 1px solid #d0d8e8; }\n.controls { min-width: 255px; flex: 0 0 255px; }\n.right { flex: 1; min-width: 520px; }\nlabel { display: block; font-size: 0.7rem; color: #4a5a72; margin-bottom: 3px; margin-top: 11px; text-transform: uppercase; letter-spacing: 0.06em; }\nlabel:first-child { margin-top: 0; }\ninput[type=number] { width: 100%; padding: 7px 10px; border-radius: 6px; border: 1px solid #b8c8dc; background: #f8fafc; color: #1a2233; font-size: 0.88rem; outline: none; }\ninput[type=number]:focus { border-color: #004f9e; }\n.rg { display: flex; gap: 5px; margin-top: 2px; }\n.rb { flex: 1; padding: 7px 4px; border-radius: 6px; border: 1px solid #b8c8dc; background: #f0f4f8; color: #4a5a72; font-size: 0.8rem; cursor: pointer; text-align: center; transition: all 0.15s; user-select: none; }\n.rb.on { background: #d6e8f8; border-color: #004f9e; color: #004f9e; font-weight: 700; }\n.btn { width: 100%; margin-top: 14px; padding: 10px; border-radius: 7px; border: none; background: #004f9e; color: #fff; font-size: 0.9rem; font-weight: 700; cursor: pointer; }\n.btn:hover { background: #0066cc; }\n.sep { height: 1px; background: #d0d8e8; margin: 11px 0; }\n.cards { display: flex; flex-direction: column; gap: 7px; margin-bottom: 12px; }\n.card { border-radius: 7px; padding: 10px 12px; border: 1px solid #d0d8e8; background: #f8fafc; }\n.card.C { border-left: 3px solid #1a8a4a; }\n.card.M { border-left: 3px solid #b86000; }\n.card.X { border-left: 3px solid #c0001a; background: #fff5f5; }\n.ch { display: flex; align-items: center; gap: 7px; margin-bottom: 4px; }\n.badge { font-size: 0.65rem; font-weight: 700; padding: 2px 7px; border-radius: 20px; text-transform: uppercase; }\n.bg { background: #e8f5ee; color: #1a8a4a; border: 1px solid #1a8a4a; }\n.by { background: #fff3e0; color: #b86000; border: 1px solid #b86000; }\n.br { background: #ffeaea; color: #c0001a; border: 1px solid #c0001a; }\n.ct { font-size: 0.84rem; font-weight: 700; color: #1a2233; }\n.cb { font-size: 0.77rem; color: #4a5a72; line-height: 1.55; }\n.cb strong { color: #1a2233; }\n.nb { background: #fff8e0; border: 1px solid #c8a000; border-radius: 5px; padding: 6px 9px; font-size: 0.73rem; color: #7a5000; margin-top: 4px; }\n.nb::before { content: \"\u26a0 \"; }\n.srow { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 12px; }\n.sblk { flex: 1; min-width: 240px; }\n.slbl { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.07em; color: #004f9e; margin-bottom: 5px; padding-bottom: 4px; border-bottom: 1px solid #d0d8e8; display: flex; justify-content: space-between; align-items: center; }\ncanvas { display: block; width: 100%; border-radius: 7px; background: #f8fafc; border: 1px solid #c8d4e8; }\n.bexp { padding: 4px 10px; border-radius: 5px; border: 1px solid #b8c8dc; background: #d6e8f8; color: #004f9e; font-size: 0.72rem; font-weight: 600; cursor: pointer; }\n.bexp:hover { background: #b8d4f0; }\n.inf { font-size: 0.68rem; color: #5a6a80; line-height: 1.5; margin-top: 9px; }\n.inf strong { color: #2a4a6a; }\n.empty { text-align: center; padding: 30px; color: #8a9ab8; font-size: 0.83rem; }\n<\/style>\n<\/head>\n<body>\n<h1>Einbaufilter-Auslegung<\/h1>\n<div class=\"sub\">Totalabscheider mit Filteranbau \u00b7 bg filtration GmbH \u00b7 Draufsicht Schnitt<\/div>\n<div class=\"layout\">\n  <div class=\"panel controls\">\n    <label>Abscheider-Au\u00dfendurchmesser (mm)<\/label>\n    <input type=\"number\" id=\"d\" value=\"800\" min=\"300\" max=\"3000\" step=\"50\">\n\n    <label>Elementgruppe<\/label>\n    <div class=\"rg\">\n      <div class=\"rb on\" id=\"gt\" onclick=\"setG('t')\">Taschen<\/div>\n      <div class=\"rb\" id=\"gp\" onclick=\"setG('p')\">Platten<\/div>\n    <\/div>\n\n    <div class=\"sep\"><\/div>\n\n    <label>Abstand Schlitzplatte \u2192 Abscheider, konservativ (mm)<\/label>\n    <input type=\"number\" id=\"sp\" value=\"50\" min=\"0\" max=\"500\" step=\"10\">\n\n    <label>Abstand Schlitzplatte \u2192 Abscheider, maximal (mm)<\/label>\n    <input type=\"number\" id=\"spmax\" value=\"150\" min=\"0\" max=\"500\" step=\"10\">\n\n    <label>Abstand Geh\u00e4usewand \u2192 \u00e4u\u00dferstes Element (mm)<\/label>\n    <input type=\"number\" id=\"sw\" value=\"80\" min=\"10\" max=\"300\" step=\"5\">\n\n\n\n    <button class=\"btn\" onclick=\"calc()\">\u25b6 Berechnen<\/button>\n\n    <div class=\"sep\"><\/div>\n    <div class=\"inf\">\n      <strong>Raster:<\/strong> 105 mm Mitte-zu-Mitte<br>\n      <strong>Ungerade:<\/strong> 1 Element in Mitte, dann \u00b1105 mm<br>\n      <strong>Gerade:<\/strong> erstes Element bei \u00b152,5 mm<br>\n      <strong>L\u00e4ngen:<\/strong> Elemente weiter au\u00dfen ggf. k\u00fcrzer (Kreisbegrenzung)<br>\n      <strong>Schlitzplatte:<\/strong> konservativ 50 mm \/ maximal 100 mm unterhalb Abscheider<br>\n      <strong>Max. Schlitzplatten-Breite:<\/strong> 0,9 \u00d7 D\n    <\/div>\n  <\/div>\n\n  <div class=\"right\">\n    <div class=\"panel\">\n      <div style=\"font-size:0.7rem;text-transform:uppercase;letter-spacing:.07em;color:#004f9e;margin-bottom:9px;padding-bottom:5px;border-bottom:1px solid #d0d8e8\">Auslegungsergebnis<\/div>\n      <div class=\"cards\" id=\"cards\"><div class=\"empty\">Durchmesser eingeben und berechnen<\/div><\/div>\n      <div class=\"srow\">\n        <div class=\"sblk\">\n          <div class=\"slbl\"><span style=\"color:#1a8a4a\">\u2713 Konservativ<\/span><button class=\"bexp\" onclick=\"expPNG('c')\">\u2b07 PNG<\/button><\/div>\n          <canvas id=\"cc\" width=\"1200\" height=\"1500\" style=\"width:100%;height:auto;\"><\/canvas>\n        <\/div>\n        <div class=\"sblk\">\n          <div class=\"slbl\"><span style=\"color:#b86000\">\u26a0 Maximal<\/span><button class=\"bexp\" onclick=\"expPNG('m')\">\u2b07 PNG<\/button><\/div>\n          <canvas id=\"cm\" width=\"1200\" height=\"1500\" style=\"width:100%;height:auto;\"><\/canvas>\n        <\/div>\n      <\/div>\n    <\/div>\n  <\/div>\n<\/div>\n\n<script>\nconst PITCH = 105;\nlet grp = 't';\nconst ELEMS = {\n  t: [{l:750,a:.75},{l:850,a:.85},{l:1100,a:1.1},{l:1250,a:1.25},{l:1600,a:1.6},{l:2100,a:2.1}],\n  p: [{l:600,a:1.3},{l:800,a:1.8},{l:1000,a:2.3},{l:1200,a:2.8}]\n};\nlet RES = null;\n\nfunction setG(g) {\n  grp = g;\n  document.getElementById('gt').classList.toggle('on', g==='t');\n  document.getElementById('gp').classList.toggle('on', g==='p');\n}\n\n\/\/ Positions of n elements (offsets from vessel center, mm)\nfunction positions(n) {\n  const p = [];\n  if (n % 2 === 1) { for (let i=0;i<n;i++) p.push((i - Math.floor(n\/2)) * PITCH); }\n  else             { for (let i=0;i<n;i++) p.push((i - n\/2 + 0.5) * PITCH); }\n  return p;\n}\n\n\/\/ Geometry:\n\/\/ - Vessel circle: center at (cx, cy), radius R\n\/\/ - Schlitzplatte: spMm BELOW the bottom of the circle (outside the vessel)\n\/\/   Elements start at schlitzplatte and go upward into the vessel\n\/\/ - Element at lateral offset x from center:\n\/\/   - starts at schlitzplatte (= R + spMm below center)\n\/\/   - tip must not go above: cy - sqrt(R\u00b2-x\u00b2)  (top of circle at that x)\n\/\/   - available length = (R + spMm) + sqrt(R\u00b2-x\u00b2) - gapMm\n\/\/     where gapMm = required clearance from tip to back wall\n\nfunction maxAvailLen(xMm, R, spMm, gapMm) {\n  const ax = Math.abs(xMm);\n  if (ax >= R) return 0;\n  const chord = Math.sqrt(R*R - ax*ax);\n  return R + spMm + chord - gapMm;\n}\n\nfunction bestElem(xMm, R, spMm, gapMm) {\n  const avail = maxAvailLen(xMm, R, spMm, gapMm);\n  if (avail <= 0) return null;\n  const sorted = [...ELEMS[grp]].sort((a,b) => b.l - a.l);\n  for (const e of sorted) { if (e.l <= avail) return e; }\n  return null;\n}\n\n\/\/ Count how many elements fit laterally AND have at least one element type fitting\nfunction countFit(R, spMm, gapMm, maxHW) {\n  let n = 0;\n  for (let try_n = 1; try_n <= 60; try_n++) {\n    const pos = positions(try_n);\n    const outer = Math.max(...pos.map(Math.abs));\n    if (outer > maxHW) break;\n    if (!bestElem(outer, R, spMm, gapMm)) break;\n    n = try_n;\n  }\n  return n;\n}\n\nfunction calc() {\n  const D      = parseFloat(document.getElementById('d').value);\n  const R      = D \/ 2;\n  const spStd  = parseFloat(document.getElementById('sp').value);   \/\/ conservative: schlitzplatte offset from circle bottom\n  const spMax  = parseFloat(document.getElementById('spmax').value); \/\/ maximal: larger offset = longer elements\n  const swMm   = parseFloat(document.getElementById('sw').value);   \/\/ side wall gap (always respected)\n  const gapMm  = 40;  \/\/ internal minimum back-wall clearance (always enforced, not shown as input)\n  const maxW   = 0.9 * D;  \/\/ max schlitzplatte width\n\n  \/\/ Max half-width from lateral constraint: outermost element <= R - swMm\n  \/\/ AND schlitzplatte half-width (= outerX + swMm) <= maxW\/2\n  const maxHW_lateral = R - swMm;\n  const maxHW_plate   = maxW \/ 2 - swMm;\n  const maxHW = Math.min(maxHW_lateral, maxHW_plate);\n\n  const nC = countFit(R, spStd, gapMm, maxHW);\n  const nM = countFit(R, spMax, gapMm, maxHW);\n\n  function build(n, spMm) {\n    return positions(n).map(x => ({ x, el: bestElem(x, R, spMm, gapMm) }));\n  }\n\n  const aC = build(nC, spStd);\n  const aM = build(nM, spMax);\n\n  const areaC = aC.reduce((s,a) => s + (a.el ? a.el.a : 0), 0);\n  const areaM = aM.reduce((s,a) => s + (a.el ? a.el.a : 0), 0);\n\n  const needsAdj = nM > nC || areaM > areaC;\n\n  \/\/ Compute actual minimum back gap: element whose tip is closest to back wall\n  function minBackGapElem(assign, spMm) {\n    let minGap = Infinity, minElem = null;\n    assign.filter(a=>a.el).forEach(a => {\n      const dxMm = Math.abs(a.x);\n      const chordMm = dxMm < R ? Math.sqrt(R*R - dxMm*dxMm) : 0;\n      const gap = R + spMm + chordMm - a.el.l;\n      if (gap < minGap) { minGap = gap; minElem = a; }\n    });\n    return { gap: Math.round(minGap), elem: minElem };\n  }\n  const bgC = minBackGapElem(aC, spStd);\n  const bgM = minBackGapElem(aM, spMax);\n  const backGapC = bgC.gap;\n  const backGapM = bgM.gap;\n\n  RES = { D, R, spStd, spMax, swMm, nC, nM, aC, aM, areaC, areaM, needsAdj, maxW, backGapC, backGapM };\n\n  renderCards();\n  drawSketch('c');\n  drawSketch('m');\n}\n\nfunction mixStr(assign) {\n  const cnt = {};\n  assign.forEach(a => { if (a.el) { const k = a.el.l+'mm'; cnt[k] = (cnt[k]||0)+1; } });\n  return Object.entries(cnt).map(([k,v]) => v+'\u00d7 '+k).join(', ') || '\u2013';\n}\n\nfunction renderCards() {\n  const r = RES;\n  let h = '';\n\n  if (r.nC === 0) {\n    h += `<div class=\"card X\"><div class=\"ch\"><span class=\"badge br\">\u2717 Nicht m\u00f6glich<\/span><span class=\"ct\">Konservativ: 0 Elemente<\/span><\/div><div class=\"cb\">Kein Element passt mit den gew\u00e4hlten Abst\u00e4nden.<\/div><\/div>`;\n  } else {\n    h += `<div class=\"card C\"><div class=\"ch\"><span class=\"badge bg\">\u2713 Konservativ<\/span><span class=\"ct\">${r.nC} Elemente \u00b7 ${r.areaC.toFixed(2)} m\u00b2 Filterfl\u00e4che<\/span><\/div>\n    <div class=\"cb\">Belegung: <strong>${mixStr(r.aC)}<\/strong><br>\n    Schlitzplatten-Abstand: <strong>${r.spStd} mm<\/strong> \u00b7 R\u00fcckwandabstand (min.): <strong>${r.backGapC} mm<\/strong><br>\n    \u2192 Kein Anpassungsbedarf am Anbau.<\/div><\/div>`;\n  }\n\n  if (r.nM === 0) {\n    h += `<div class=\"card X\"><div class=\"ch\"><span class=\"badge br\">\u2717 Nicht m\u00f6glich<\/span><span class=\"ct\">Maximal: 0 Elemente<\/span><\/div><div class=\"cb\">Kein Element passt.<\/div><\/div>`;\n  } else {\n    const same = r.nM === r.nC && Math.abs(r.areaM - r.areaC) < 0.01;\n    let note = '';\n    if (same) note = `<div class=\"nb\">Identisch mit konservativer Auslegung \u2014 kein Gewinn durch Anpassung.<\/div>`;\n    else note = `<div class=\"nb\">Anbau um ${r.spMax - r.spStd} mm weiter nach unten versetzt (Schlitzplatten-Abstand ${r.spMax} mm statt ${r.spStd} mm). Pr\u00fcfen ob geometrisch m\u00f6glich!<\/div>`;\n    const bc = same ? 'by' : 'by';\n    const bl = same ? '= Identisch' : '\u26a0 Mit Anpassung';\n    h += `<div class=\"card M\"><div class=\"ch\"><span class=\"badge ${bc}\">${bl}<\/span><span class=\"ct\">${r.nM} Elemente \u00b7 ${r.areaM.toFixed(2)} m\u00b2 Filterfl\u00e4che<\/span><\/div>\n    <div class=\"cb\">Belegung: <strong>${mixStr(r.aM)}<\/strong><br>\n    Schlitzplatten-Abstand: <strong>${r.spMax} mm<\/strong> \u00b7 R\u00fcckwandabstand (min.): <strong>${r.backGapM} mm<\/strong>${note}<\/div><\/div>`;\n  }\n  document.getElementById('cards').innerHTML = h;\n}\n\n\/\/ \u2500\u2500 Draw sketch \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nfunction drawSketch(mode) {\n  const r = RES;\n  const cvs = document.getElementById(mode === 'c' ? 'cc' : 'cm');\n  const ctx = cvs.getContext('2d');\n\n  const W = cvs.width;\n  const H = cvs.height;\n  ctx.clearRect(0, 0, W, H);\n  ctx.fillStyle = '#f8fafc';\n  ctx.fillRect(0, 0, W, H);\n\n  const assign = mode === 'c' ? r.aC : r.aM;\n  const n      = mode === 'c' ? r.nC : r.nM;\n  const col    = mode === 'c' ? '#3ab87a' : '#e8a83a';\n  const lbl    = mode === 'c' ? 'Konservativ' : 'Maximal';\n  const spMm   = mode === 'c' ? r.spStd : r.spMax;\n  const gapMm  = r.gapMm;\n\n  if (n === 0) {\n    ctx.fillStyle = '#8a9ab8'; ctx.font = '13px Segoe UI,Arial'; ctx.textAlign = 'center';\n    ctx.fillText('Keine Elemente m\u00f6glich', W\/2, H\/2); return;\n  }\n\n  \/\/ \u2500\u2500 Scale & layout \u2500\u2500\n  \/\/ spMm = distance from BOTTOM OF CIRCLE to schlitzplatte (outside the circle)\n  const totalH_mm = r.D + spMm + 20;\n  const totalW_mm = r.D;\n\n  const padTop = 160, padBot = 220, padSide = 150;\n  const avW = W - padSide*2;\n  const avH = H - padTop - padBot;\n  const scale = Math.min(avW \/ totalW_mm, avH \/ totalH_mm);\n  const Rpx = r.R * scale;\n  const spPx = spMm * scale; \/\/ gap from circle bottom to schlitzplatte in pixels\n\n  \/\/ Circle center\n  const cx = W \/ 2;\n  const cy = padTop + Rpx;\n\n  \/\/ Schlitzplatte y: BELOW the bottom of the circle by spMm\n  const schlitzY = cy + Rpx + spPx;\n\n  \/\/ \u2500\u2500 Vessel circle (red) \u2500\u2500\n  ctx.beginPath();\n  ctx.arc(cx, cy, Rpx, 0, Math.PI*2);\n  ctx.fillStyle = 'rgba(220,230,245,0.85)';\n  ctx.fill();\n  ctx.strokeStyle = '#e84040';\n  ctx.lineWidth = 7.5;\n  ctx.stroke();\n\n  \/\/ \u2500\u2500 Center cross (faint) \u2500\u2500\n  ctx.strokeStyle = '#c0cce0'; ctx.lineWidth = 3; ctx.setLineDash([12,15]);\n  ctx.beginPath(); ctx.moveTo(cx-Rpx, cy); ctx.lineTo(cx+Rpx, cy); ctx.stroke();\n  ctx.beginPath(); ctx.moveTo(cx, cy-Rpx); ctx.lineTo(cx, cy+Rpx); ctx.stroke();\n  ctx.setLineDash([]);\n\n  \/\/ \u2500\u2500 Anbau side walls \u2500\u2500\n  \/\/ Width: outermost element center + swMm on each side\n  const outerX_mm = n > 0 ? Math.max(...assign.map(a => Math.abs(a.x))) : 0;\n  const halfBoxW_mm = outerX_mm + r.swMm;\n  const halfBoxW_px = halfBoxW_mm * scale;\n\n  const boxLeft  = cx - halfBoxW_px;\n  const boxRight = cx + halfBoxW_px;\n\n  \/\/ Side walls go from schlitzplatte corner UP to where they meet the circle (lower arc)\n  \/\/ schlitzplatte is spPx BELOW the bottom of the circle, so the walls are outside the circle\n  \/\/ They connect schlitzplatte corner \u2192 circle tangent point (lower half)\n  \/\/ Circle lower intersection at x = boxLeft: y = cy + sqrt(R\u00b2-dx\u00b2)  (if inside circle)\n  \/\/ If boxLeft is outside circle (|dx| >= R), wall goes straight up to circle bottom (cy+Rpx)\n  function circleBottomY(wallX) {\n    const dxPx = Math.abs(wallX - cx);\n    if (dxPx >= Rpx) return cy + Rpx; \/\/ outside circle: connect to bottom\n    return cy + Math.sqrt(Rpx*Rpx - dxPx*dxPx);\n  }\n\n  const leftWallTopY  = circleBottomY(boxLeft);\n  const rightWallTopY = circleBottomY(boxRight);\n\n  \/\/ Draw left wall: from schlitzplatte corner diagonally up to circle\n  ctx.beginPath();\n  ctx.moveTo(boxLeft, schlitzY);\n  ctx.lineTo(boxLeft, leftWallTopY);\n  ctx.strokeStyle = '#e84040';\n  ctx.lineWidth = 6;\n  ctx.stroke();\n\n  \/\/ Draw right wall\n  ctx.beginPath();\n  ctx.moveTo(boxRight, schlitzY);\n  ctx.lineTo(boxRight, rightWallTopY);\n  ctx.strokeStyle = '#e84040';\n  ctx.lineWidth = 6;\n  ctx.stroke();\n\n  \/\/ \u2500\u2500 Schlitzplatte (bottom horizontal bar) \u2500\u2500\n  ctx.beginPath();\n  ctx.moveTo(boxLeft, schlitzY);\n  ctx.lineTo(boxRight, schlitzY);\n  ctx.strokeStyle = '#e84040';\n  ctx.lineWidth = 6;\n  ctx.stroke();\n\n  \/\/ Label\n  ctx.fillStyle = '#8a0012';\n  ctx.font = 'bold 27px Segoe UI,Arial';\n  ctx.textAlign = 'center';\n  ctx.fillText('Schlitzplatte \/ Flansch', cx, schlitzY + 55);\n\n  \/\/ \u2500\u2500 spMm annotation (circle bottom to schlitzplatte) \u2500\u2500\n  \/\/ Place to the right of the right wall, outside the drawing\n  const spDimX = boxRight + 60;\n  ctx.beginPath();\n  ctx.moveTo(spDimX, cy + Rpx);   \/\/ circle bottom\n  ctx.lineTo(spDimX, schlitzY);   \/\/ schlitzplatte\n  ctx.strokeStyle = '#1a2233'; ctx.lineWidth = 3; ctx.setLineDash([6,9]); ctx.stroke(); ctx.setLineDash([]);\n  htick(ctx, spDimX, cy + Rpx, '#1a2233');\n  htick(ctx, spDimX, schlitzY, '#1a2233');\n  \/\/ Text: always to the right of the dim line, horizontally, at midpoint\n  const spMidY = (cy + Rpx + schlitzY) \/ 2;\n  ctx.fillStyle = '#1a2233'; ctx.font = '24px Segoe UI,Arial'; ctx.textAlign = 'left';\n  ctx.fillText(spMm + ' mm', spDimX + 15, spMidY + 9);\n\n  \/\/ \u2500\u2500 Side-wall gap annotation (LEFT side) \u2500\u2500\n  const leftElemPx = cx - outerX_mm * scale;\n  const swDimY = schlitzY - 50;\n  ctx.beginPath();\n  ctx.moveTo(leftElemPx, swDimY);\n  ctx.lineTo(boxLeft, swDimY);\n  ctx.strokeStyle = '#1a2233'; ctx.lineWidth = 3; ctx.setLineDash([6,6]); ctx.stroke(); ctx.setLineDash([]);\n  vtick(ctx, leftElemPx, swDimY, '#1a2233');\n  vtick(ctx, boxLeft, swDimY, '#1a2233');\n  ctx.fillStyle = '#1a2233'; ctx.font = '24px Segoe UI,Arial'; ctx.textAlign = 'center';\n  ctx.fillText(r.swMm + ' mm', (leftElemPx + boxLeft)\/2, swDimY - 12);\n\n  \/\/ \u2500\u2500 Filter elements \u2500\u2500\n  assign.forEach(({ x, el }) => {\n    if (!el) return;\n    const ex = cx + x * scale;\n    const startY = schlitzY;\n    const endY   = schlitzY - el.l * scale;\n\n    ctx.beginPath();\n    ctx.moveTo(ex, startY);\n    ctx.lineTo(ex, endY);\n    ctx.strokeStyle = col;\n    ctx.lineWidth = 6.6;\n    ctx.stroke();\n\n    dot(ctx, ex, startY, col, 9);\n    dot(ctx, ex, endY,   col, 9);\n  });\n\n  \/\/ \u2500\u2500 Element length dimensions \u2500\u2500\n  \/\/ Rule: for each unique length, pick the FIRST element to the RIGHT of center (x > 0).\n  \/\/ If no element with that length is right of center, pick the one closest to center.\n  \/\/ Dim line sits directly next to that element (fixed offset), stacked with 84px spacing.\n  const byLen = {};\n  assign.filter(a=>a.el).forEach(a => {\n    const k = a.el.l;\n    const existing = byLen[k];\n    if (!existing) { byLen[k] = a; return; }\n    \/\/ Prefer first right of center (smallest positive x), else closest to center\n    const aRightOfCenter = a.x > 0;\n    const exRightOfCenter = existing.x > 0;\n    if (aRightOfCenter && !exRightOfCenter) { byLen[k] = a; return; }\n    if (!aRightOfCenter && exRightOfCenter) return;\n    \/\/ Both same side: pick smallest |x| (closest to center)\n    if (Math.abs(a.x) < Math.abs(existing.x)) byLen[k] = a;\n  });\n  const sortedLens = Object.values(byLen).sort((a,b) => b.el.l - a.el.l); \/\/ longest first\n  const DIM_OFFSET = 18; \/\/ px right of the element line \u2014 same for every dim\n  sortedLens.forEach((a, i) => {\n    const ex = cx + a.x * scale;\n    const sY = schlitzY;\n    const eY = schlitzY - a.el.l * scale;\n    const dx = ex + DIM_OFFSET; \/\/ always same offset from its own element\n    ctx.beginPath(); ctx.moveTo(dx, sY); ctx.lineTo(dx, eY);\n    ctx.strokeStyle = col; ctx.lineWidth = 3; ctx.setLineDash([9,9]); ctx.stroke(); ctx.setLineDash([]);\n    htick(ctx, dx, sY, col); htick(ctx, dx, eY, col);\n    ctx.save();\n    ctx.translate(dx + 33, (sY + eY) \/ 2);\n    ctx.rotate(-Math.PI \/ 2);\n    ctx.fillStyle = col; ctx.font = 'bold 27px Segoe UI,Arial'; ctx.textAlign = 'center';\n    ctx.fillText(a.el.l + ' mm', 0, 0);\n    ctx.restore();\n  });\n\n  \/\/ \u2500\u2500 Actual back gap: at element with minimum gap (tip closest to back wall) \u2500\u2500\n  let minGapPx = Infinity, minGapElem = null;\n  assign.filter(a=>a.el).forEach(a => {\n    const dxPx = Math.abs(a.x) * scale;\n    const bwY = dxPx < Rpx ? cy - Math.sqrt(Rpx*Rpx - dxPx*dxPx) : schlitzY;\n    const tipY_ = schlitzY - a.el.l * scale;\n    const gPx = tipY_ - bwY;\n    if (gPx < minGapPx) { minGapPx = gPx; minGapElem = a; }\n  });\n  if (minGapElem) {\n    \/\/ Place annotation to the left of this element\n    const ex = cx + minGapElem.x * scale;\n    const tipY = schlitzY - minGapElem.el.l * scale;\n    const dxPx = Math.abs(minGapElem.x) * scale;\n    const backWallY = dxPx < Rpx ? cy - Math.sqrt(Rpx*Rpx - dxPx*dxPx) : tipY;\n    const actualGapMm = Math.round((tipY - backWallY) \/ scale);\n    const gapPx = tipY - backWallY;\n    const gapX = ex - 14;\n    ctx.beginPath(); ctx.moveTo(gapX, tipY); ctx.lineTo(gapX, backWallY);\n    ctx.strokeStyle = '#1a2233'; ctx.lineWidth = 3; ctx.setLineDash([6,6]); ctx.stroke(); ctx.setLineDash([]);\n    htick(ctx, gapX, tipY, '#1a2233');\n    htick(ctx, gapX, backWallY, '#1a2233');\n    ctx.save();\n    ctx.translate(gapX - 33, (tipY + backWallY) \/ 2);\n    ctx.rotate(-Math.PI \/ 2);\n    ctx.fillStyle = '#1a2233'; ctx.font = '24px Segoe UI,Arial'; ctx.textAlign = 'center';\n    ctx.fillText(actualGapMm + ' mm', 0, 0);\n    ctx.restore();\n  }\n\n  \/\/ \u2500\u2500 Pitch dimension: LEFT side, between two leftmost adjacent elements, at mid-height \u2500\u2500\n  \/\/ Placed left of center to never conflict with right-side length dims\n  if (assign.length >= 2) {\n    const sorted = [...assign].sort((a,b) => a.x - b.x);\n    \/\/ Use the leftmost pair\n    const pair = [sorted[0], sorted[1]];\n    const p0x = cx + pair[0].x * scale;\n    const p1x = cx + pair[1].x * scale;\n    const shortEl = pair[0].el && pair[1].el\n      ? (pair[0].el.l < pair[1].el.l ? pair[0].el : pair[1].el)\n      : (pair[0].el || pair[1].el);\n    const elMidY = shortEl ? schlitzY - shortEl.l * scale * 0.5 : cy;\n    ctx.beginPath(); ctx.moveTo(p0x, elMidY); ctx.lineTo(p1x, elMidY);\n    ctx.strokeStyle = 'rgba(0,0,0,.45)'; ctx.lineWidth = 3; ctx.setLineDash([6,9]); ctx.stroke(); ctx.setLineDash([]);\n    vtick(ctx, p0x, elMidY, 'rgba(0,0,0,.45)');\n    vtick(ctx, p1x, elMidY, 'rgba(0,0,0,.45)');\n    ctx.fillStyle = '#1a2233'; ctx.font = '24px Segoe UI,Arial'; ctx.textAlign = 'center';\n    ctx.fillText('105 mm', (p0x+p1x)\/2, elMidY - 12);\n  }\n\n  \/\/ \u2500\u2500 Diameter annotation below \u2500\u2500\n  const dY = schlitzY + 100;\n  ctx.beginPath(); ctx.moveTo(cx-Rpx, dY); ctx.lineTo(cx+Rpx, dY);\n  ctx.strokeStyle = '#1a2233'; ctx.lineWidth = 3; ctx.setLineDash([9,9]); ctx.stroke(); ctx.setLineDash([]);\n  arrowTip(ctx, cx-Rpx, dY, 1, '#1a2233');\n  arrowTip(ctx, cx+Rpx, dY, -1, '#1a2233');\n  ctx.fillStyle = '#1a2233'; ctx.font = 'bold 30px Segoe UI,Arial'; ctx.textAlign = 'center';\n  ctx.fillText('\u00d8 ' + r.D + ' mm', cx, dY + 45);\n\n  \/\/ \u2500\u2500 Top label \u2500\u2500\n  const totalArea = assign.reduce((s,a) => s + (a.el ? a.el.a : 0), 0);\n  ctx.fillStyle = col; ctx.font = 'bold 30px Segoe UI,Arial'; ctx.textAlign = 'left';\n  ctx.fillText(lbl + ': ' + n + ' El. \u00b7 ' + totalArea.toFixed(2) + ' m\u00b2', 18, 54);\n  ctx.fillStyle = '#4a5a72'; ctx.font = '27px Segoe UI,Arial';\n  ctx.fillText('Schlitzpl.-Abstand: ' + spMm + ' mm', 18, 96);\n}\n\nfunction dot(ctx, x, y, col, r) {\n  ctx.beginPath(); ctx.arc(x, y, r, 0, Math.PI*2); ctx.fillStyle = col; ctx.fill();\n}\nfunction vtick(ctx, x, y, col) { \/\/ vertical tick\n  ctx.beginPath(); ctx.moveTo(x, y-12); ctx.lineTo(x, y+12); ctx.strokeStyle = col; ctx.lineWidth = 2; ctx.stroke();\n}\nfunction htick(ctx, x, y, col) { \/\/ horizontal tick\n  ctx.beginPath(); ctx.moveTo(x-12, y); ctx.lineTo(x+12, y); ctx.strokeStyle = col; ctx.lineWidth = 2; ctx.stroke();\n}\nfunction arrowTip(ctx, x, y, dir, col) {\n  ctx.beginPath();\n  ctx.moveTo(x, y); ctx.lineTo(x + dir*24, y-12);\n  ctx.moveTo(x, y); ctx.lineTo(x + dir*24, y+12);\n  ctx.strokeStyle = col; ctx.lineWidth = 4; ctx.stroke();\n}\n\nfunction expPNG(mode) {\n  if (!RES) return;\n  const cvs = document.getElementById(mode === 'c' ? 'cc' : 'cm');\n  const n = mode === 'c' ? RES.nC : RES.nM;\n  const lnk = document.createElement('a');\n  lnk.download = `Filterauslegung_D${RES.D}mm_${n}El_${mode==='c'?'konservativ':'maximal'}.png`;\n  lnk.href = cvs.toDataURL('image\/png');\n  lnk.click();\n}\n\nwindow.addEventListener('load', calc);\ndocument.getElementById('d').addEventListener('keydown', e => { if (e.key==='Enter') calc(); });\n<\/script>\n<\/body>\n<\/html>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Einbaufilter-Auslegung | bg filtration Einbaufilter-Auslegung Totalabscheider mit Filteranbau \u00b7 bg filtration GmbH \u00b7 Draufsicht Schnitt Abscheider-Au\u00dfendurchmesser (mm) Elementgruppe Taschen Platten Abstand Schlitzplatte \u2192 Abscheider, konservativ (mm) Abstand Schlitzplatte \u2192 Abscheider, maximal (mm) Abstand Geh\u00e4usewand \u2192 \u00e4u\u00dferstes Element (mm) \u25b6 Berechnen Raster: 105 mm Mitte-zu-Mitte Ungerade: 1 Element in Mitte, dann \u00b1105 mm Gerade: erstes Element [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-7977","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v28.1 (Yoast SEO v28.1) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Einbaufilter-Berechnung - bg-filtration<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/bg-filtration.de\/tr\/takma-filtre-hesaplamasi\/\" \/>\n<meta property=\"og:locale\" content=\"tr_TR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Einbaufilter-Berechnung\" \/>\n<meta property=\"og:description\" content=\"Einbaufilter-Auslegung | bg filtration Einbaufilter-Auslegung Totalabscheider mit Filteranbau \u00b7 bg filtration GmbH \u00b7 Draufsicht Schnitt Abscheider-Au\u00dfendurchmesser (mm) Elementgruppe Taschen Platten Abstand Schlitzplatte \u2192 Abscheider, konservativ (mm) Abstand Schlitzplatte \u2192 Abscheider, maximal (mm) Abstand Geh\u00e4usewand \u2192 \u00e4u\u00dferstes Element (mm) \u25b6 Berechnen Raster: 105 mm Mitte-zu-Mitte Ungerade: 1 Element in Mitte, dann \u00b1105 mm Gerade: erstes Element [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/bg-filtration.de\/tr\/takma-filtre-hesaplamasi\/\" \/>\n<meta property=\"og:site_name\" content=\"bg-filtration\" \/>\n<meta property=\"article:published_time\" content=\"2026-07-03T08:52:04+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-07-10T08:30:56+00:00\" \/>\n<meta name=\"author\" content=\"admin\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Yazan:\" \/>\n\t<meta name=\"twitter:data1\" content=\"admin\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tahmini okuma s\u00fcresi\" \/>\n\t<meta name=\"twitter:data2\" content=\"30 dakika\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/bg-filtration.de\\\/einbaufilter-berechnung\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/bg-filtration.de\\\/einbaufilter-berechnung\\\/\"},\"author\":{\"name\":\"admin\",\"@id\":\"https:\\\/\\\/bg-filtration.de\\\/#\\\/schema\\\/person\\\/bc6d2254a2a5e3ef61a7ac7fb14f2620\"},\"headline\":\"Einbaufilter-Berechnung\",\"datePublished\":\"2026-07-03T08:52:04+00:00\",\"dateModified\":\"2026-07-10T08:30:56+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/bg-filtration.de\\\/einbaufilter-berechnung\\\/\"},\"wordCount\":159,\"publisher\":{\"@id\":\"https:\\\/\\\/bg-filtration.de\\\/#organization\"},\"articleSection\":[\"Uncategorized\"],\"inLanguage\":\"tr\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/bg-filtration.de\\\/einbaufilter-berechnung\\\/\",\"url\":\"https:\\\/\\\/bg-filtration.de\\\/einbaufilter-berechnung\\\/\",\"name\":\"Einbaufilter-Berechnung - bg-filtration\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/bg-filtration.de\\\/#website\"},\"datePublished\":\"2026-07-03T08:52:04+00:00\",\"dateModified\":\"2026-07-10T08:30:56+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/bg-filtration.de\\\/einbaufilter-berechnung\\\/#breadcrumb\"},\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/bg-filtration.de\\\/einbaufilter-berechnung\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/bg-filtration.de\\\/einbaufilter-berechnung\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Start\",\"item\":\"https:\\\/\\\/bg-filtration.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Einbaufilter-Berechnung\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/bg-filtration.de\\\/#website\",\"url\":\"https:\\\/\\\/bg-filtration.de\\\/\",\"name\":\"bg-filtration\",\"description\":\"Industrielle Filtersysteme\",\"publisher\":{\"@id\":\"https:\\\/\\\/bg-filtration.de\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/bg-filtration.de\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"tr\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/bg-filtration.de\\\/#organization\",\"name\":\"bg filtration gmbh\",\"url\":\"https:\\\/\\\/bg-filtration.de\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"tr\",\"@id\":\"https:\\\/\\\/bg-filtration.de\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/bg-filtration.de\\\/wp-content\\\/uploads\\\/2025\\\/11\\\/bg-filtration-logo.svg\",\"contentUrl\":\"https:\\\/\\\/bg-filtration.de\\\/wp-content\\\/uploads\\\/2025\\\/11\\\/bg-filtration-logo.svg\",\"width\":713,\"height\":155,\"caption\":\"bg filtration gmbh\"},\"image\":{\"@id\":\"https:\\\/\\\/bg-filtration.de\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.linkedin.com\\\/company\\\/bg-filtration-gmbh\"],\"description\":\"Als Hersteller industrieller Filtersysteme realisieren wir f\u00fcr zahlreiche Branchen L\u00f6sungen zur sicheren Abscheidung von Staub, Sch\u00fcttg\u00fctern, Aerosolen und explosionsf\u00e4higen Stoffen. Individuell ausgelegt auf Ihre Anwendung - f\u00fcr saubere Prozesse und maximale Sicherheit.\",\"email\":\"info@bg-filtration.de\",\"telephone\":\"+49 7159 8069-0\",\"legalName\":\"bg filtration gmbh\",\"foundingDate\":\"1971-01-01\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/bg-filtration.de\\\/#\\\/schema\\\/person\\\/bc6d2254a2a5e3ef61a7ac7fb14f2620\",\"name\":\"admin\",\"sameAs\":[\"https:\\\/\\\/bg-filtration.de\"],\"url\":\"https:\\\/\\\/bg-filtration.de\\\/tr\\\/author\\\/admin\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Entegre Filtre Hesaplamas\u0131 - bg-filtration","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/bg-filtration.de\/tr\/takma-filtre-hesaplamasi\/","og_locale":"tr_TR","og_type":"article","og_title":"Einbaufilter-Berechnung","og_description":"Einbaufilter-Auslegung | bg filtration Einbaufilter-Auslegung Totalabscheider mit Filteranbau \u00b7 bg filtration GmbH \u00b7 Draufsicht Schnitt Abscheider-Au\u00dfendurchmesser (mm) Elementgruppe Taschen Platten Abstand Schlitzplatte \u2192 Abscheider, konservativ (mm) Abstand Schlitzplatte \u2192 Abscheider, maximal (mm) Abstand Geh\u00e4usewand \u2192 \u00e4u\u00dferstes Element (mm) \u25b6 Berechnen Raster: 105 mm Mitte-zu-Mitte Ungerade: 1 Element in Mitte, dann \u00b1105 mm Gerade: erstes Element [&hellip;]","og_url":"https:\/\/bg-filtration.de\/tr\/takma-filtre-hesaplamasi\/","og_site_name":"bg-filtration","article_published_time":"2026-07-03T08:52:04+00:00","article_modified_time":"2026-07-10T08:30:56+00:00","author":"admin","twitter_card":"summary_large_image","twitter_misc":{"Yazan:":"admin","Tahmini okuma s\u00fcresi":"30 dakika"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/bg-filtration.de\/einbaufilter-berechnung\/#article","isPartOf":{"@id":"https:\/\/bg-filtration.de\/einbaufilter-berechnung\/"},"author":{"name":"admin","@id":"https:\/\/bg-filtration.de\/#\/schema\/person\/bc6d2254a2a5e3ef61a7ac7fb14f2620"},"headline":"Einbaufilter-Berechnung","datePublished":"2026-07-03T08:52:04+00:00","dateModified":"2026-07-10T08:30:56+00:00","mainEntityOfPage":{"@id":"https:\/\/bg-filtration.de\/einbaufilter-berechnung\/"},"wordCount":159,"publisher":{"@id":"https:\/\/bg-filtration.de\/#organization"},"articleSection":["Uncategorized"],"inLanguage":"tr"},{"@type":"WebPage","@id":"https:\/\/bg-filtration.de\/einbaufilter-berechnung\/","url":"https:\/\/bg-filtration.de\/einbaufilter-berechnung\/","name":"Entegre Filtre Hesaplamas\u0131 - bg-filtration","isPartOf":{"@id":"https:\/\/bg-filtration.de\/#website"},"datePublished":"2026-07-03T08:52:04+00:00","dateModified":"2026-07-10T08:30:56+00:00","breadcrumb":{"@id":"https:\/\/bg-filtration.de\/einbaufilter-berechnung\/#breadcrumb"},"inLanguage":"tr","potentialAction":[{"@type":"ReadAction","target":["https:\/\/bg-filtration.de\/einbaufilter-berechnung\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/bg-filtration.de\/einbaufilter-berechnung\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Start","item":"https:\/\/bg-filtration.de\/"},{"@type":"ListItem","position":2,"name":"Einbaufilter-Berechnung"}]},{"@type":"WebSite","@id":"https:\/\/bg-filtration.de\/#website","url":"https:\/\/bg-filtration.de\/","name":"bg-filtreleme","description":"End\u00fcstriyel Filtre Sistemleri","publisher":{"@id":"https:\/\/bg-filtration.de\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/bg-filtration.de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"tr"},{"@type":"Organization","@id":"https:\/\/bg-filtration.de\/#organization","name":"bg filtration gmbh","url":"https:\/\/bg-filtration.de\/","logo":{"@type":"ImageObject","inLanguage":"tr","@id":"https:\/\/bg-filtration.de\/#\/schema\/logo\/image\/","url":"https:\/\/bg-filtration.de\/wp-content\/uploads\/2025\/11\/bg-filtration-logo.svg","contentUrl":"https:\/\/bg-filtration.de\/wp-content\/uploads\/2025\/11\/bg-filtration-logo.svg","width":713,"height":155,"caption":"bg filtration gmbh"},"image":{"@id":"https:\/\/bg-filtration.de\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.linkedin.com\/company\/bg-filtration-gmbh"],"description":"End\u00fcstriyel filtre sistemleri \u00fcreticisi olarak, toz, d\u00f6kme malzemeler, aerosoller ve patlay\u0131c\u0131 maddelerin g\u00fcvenli bir \u015fekilde ayr\u0131lmas\u0131 i\u00e7in say\u0131s\u0131z sekt\u00f6rde \u00e7\u00f6z\u00fcmler sunmaktay\u0131z. Uygulaman\u0131za \u00f6zel olarak tasarlanm\u0131\u015f - temiz prosesler ve maksimum g\u00fcvenlik i\u00e7in.","email":"info@bg-filtration.de","telephone":"+49 7159 8069-0","legalName":"bg filtration gmbh","foundingDate":"1971-01-01"},{"@type":"Person","@id":"https:\/\/bg-filtration.de\/#\/schema\/person\/bc6d2254a2a5e3ef61a7ac7fb14f2620","name":"y\u00f6netici","sameAs":["https:\/\/bg-filtration.de"],"url":"https:\/\/bg-filtration.de\/tr\/author\/admin\/"}]}},"_links":{"self":[{"href":"https:\/\/bg-filtration.de\/tr\/wp-json\/wp\/v2\/posts\/7977","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bg-filtration.de\/tr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bg-filtration.de\/tr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bg-filtration.de\/tr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/bg-filtration.de\/tr\/wp-json\/wp\/v2\/comments?post=7977"}],"version-history":[{"count":40,"href":"https:\/\/bg-filtration.de\/tr\/wp-json\/wp\/v2\/posts\/7977\/revisions"}],"predecessor-version":[{"id":8073,"href":"https:\/\/bg-filtration.de\/tr\/wp-json\/wp\/v2\/posts\/7977\/revisions\/8073"}],"wp:attachment":[{"href":"https:\/\/bg-filtration.de\/tr\/wp-json\/wp\/v2\/media?parent=7977"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bg-filtration.de\/tr\/wp-json\/wp\/v2\/categories?post=7977"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bg-filtration.de\/tr\/wp-json\/wp\/v2\/tags?post=7977"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}