/* ========================================================================== Purinto GmbH — Stückzahl-Achse Das Signature-Element: eine logarithmische Achse von 1 bis 100.000 Stück. Der Besucher wählt eine Stückzahl und sieht, welches Verfahren dafür das richtige ist — inklusive der ehrlichen Grenze, ab der Purinto mit Partnerbetrieben arbeitet statt selbst zu fertigen. ALLE fachlichen Eckwerte stehen in ZONEN. Wer die Grenzen ändern will, ändert sie hier — Achse, Beschriftung und Tafel ziehen automatisch nach. ========================================================================== */ (function () { "use strict"; var wurzel = document.querySelector("[data-achse]"); if (!wurzel) return; /* ---------------------------------------------------------------------- Fachliche Datenbasis — vor Livegang bestätigen. "bis" ist jeweils die obere Grenze der Zone in Stück. ---------------------------------------------------------------------- */ var MIN = 1; var MAX = 100000; var ZONEN = [ { id: "druck", bis: 100, kurz: "FDM · SLA", verfahren: "FDM oder SLA — direkt gedruckt", partner: false, werkzeug: "Kein Werkzeug nötig", lieferzeit: "1–5 Arbeitstage", stueckkosten: "Über die Menge konstant", anwendung: "Funktionsmuster, Passungs- und Einbauprüfungen, Vorrichtungen, Designfreigaben", hinweis: "In diesem Bereich fertigen wir direkt aus der CAD-Datei. Änderungen kosten nichts außer einem neuen Druck — genau richtig, solange die Konstruktion noch in Bewegung ist." }, { id: "bridge", bis: 1000, kurz: "Bridge Tooling", verfahren: "Bridge Tooling — SLA-gedruckter Formeinsatz", partner: false, werkzeug: "Gering — der Formeinsatz wird gedruckt, nicht gefräst", lieferzeit: "2–3 Wochen bis zum ersten Schuss", stueckkosten: "Deutlich unter dem Direktdruck", anwendung: "Vorserien, Markttests, Nullserien und Zulassungsmuster im späteren Serienwerkstoff", hinweis: "Hier liegt unser Schwerpunkt. Sie bekommen Teile im echten Serienwerkstoff mit Spritzguss-Eigenschaften, ohne vorher ein Stahlwerkzeug zu finanzieren." }, { id: "serie", bis: MAX, kurz: "Serienspritzguss", verfahren: "Serienspritzguss — Stahlwerkzeug", partner: true, werkzeug: "Hoch — Stahlwerkzeug als einmalige Investition", lieferzeit: "8–14 Wochen bis zum ersten Schuss", stueckkosten: "Am niedrigsten, sobald die Menge das Werkzeug trägt", anwendung: "Serienfertigung nach abgeschlossener Entwicklung", hinweis: "Ab hier ist ein Stahlwerkzeug wirtschaftlich. Das ist nicht unser Kerngeschäft — wir begleiten den Übergang und vermitteln an lokale Spritzgießer, mit denen wir zusammenarbeiten." } ]; var START = 40; // Stückzahl beim Laden der Seite /* ---------------------------------------------------------------------- Umrechnung zwischen Stückzahl und Position auf der Achse ---------------------------------------------------------------------- */ var SPANNE = Math.log10(MAX) - Math.log10(MIN); function wertZuAnteil(wert) { return (Math.log10(wert) - Math.log10(MIN)) / SPANNE; } function anteilZuWert(anteil) { return Math.pow(10, Math.log10(MIN) + anteil * SPANNE); } // Auf lesbare Stufen runden — "37 Stück" hilft niemandem bei "etwa 40". function runden(wert) { if (wert < 10) return Math.max(MIN, Math.round(wert)); if (wert < 100) return Math.round(wert / 5) * 5; if (wert < 1000) return Math.round(wert / 10) * 10; if (wert < 10000) return Math.round(wert / 100) * 100; return Math.round(wert / 1000) * 1000; } function zoneFuer(wert) { for (var i = 0; i < ZONEN.length; i++) { if (wert <= ZONEN[i].bis) return ZONEN[i]; } return ZONEN[ZONEN.length - 1]; } // Bewusst nicht toLocaleString: de-AT trennt Tausender mit einem schmalen // Leerzeichen ("100 000"), der übrige Seitentext schreibt "100.000". // Explizite Formatierung hält beides deckungsgleich. function formatieren(zahl) { return String(zahl).replace(/\B(?=(\d{3})+(?!\d))/g, "."); } /* ---------------------------------------------------------------------- Elemente ---------------------------------------------------------------------- */ var spur = wurzel.querySelector("[data-spur]"); var griff = wurzel.querySelector("[data-griff]"); var zonenElemente = wurzel.querySelectorAll("[data-zone]"); var ausgabe = document.querySelector("[data-ausgabe]"); var verfahrenAus = document.querySelector("[data-verfahren]"); var hinweisAus = document.querySelector("[data-hinweis]"); var werkzeugAus = document.querySelector("[data-werkzeug]"); var lieferzeitAus = document.querySelector("[data-lieferzeit]"); var stueckkostenAus = document.querySelector("[data-stueckkosten]"); var anwendungAus = document.querySelector("[data-anwendung]"); if (!spur || !griff) return; /* ---------------------------------------------------------------------- Zonenbreiten aus den Daten ableiten, damit geänderte Grenzen sofort auch optisch stimmen ---------------------------------------------------------------------- */ (function zonenAufbauen() { var vorher = 0; ZONEN.forEach(function (zone, i) { var ende = wertZuAnteil(zone.bis) * 100; var breite = ende - vorher; if (zonenElemente[i]) zonenElemente[i].style.width = breite + "%"; var flaeche = wurzel.querySelector('[data-flaeche="' + zone.id + '"]'); if (flaeche) { flaeche.style.left = vorher + "%"; flaeche.style.right = 100 - ende + "%"; } vorher = ende; }); // Skalenbeschriftungen aus derselben Umrechnung setzen, damit sie // exakt über den Zonengrenzen stehen. var skala = wurzel.querySelectorAll("[data-skala]"); Array.prototype.forEach.call(skala, function (el) { var wert = Number(el.getAttribute("data-skala")); if (!wert) return; el.style.left = wertZuAnteil(wert) * 100 + "%"; }); })(); /* ---------------------------------------------------------------------- Zustand setzen ---------------------------------------------------------------------- */ var aktuellerWert = START; function setzen(wert) { wert = Math.min(MAX, Math.max(MIN, runden(wert))); aktuellerWert = wert; var anteil = wertZuAnteil(wert); var zone = zoneFuer(wert); griff.style.left = anteil * 100 + "%"; griff.setAttribute("aria-valuenow", String(wert)); griff.setAttribute( "aria-valuetext", formatieren(wert) + " Stück, " + zone.verfahren ); Array.prototype.forEach.call(zonenElemente, function (el) { el.classList.toggle("ist-aktiv", el.getAttribute("data-zone") === zone.id); }); if (ausgabe) ausgabe.textContent = formatieren(wert); if (verfahrenAus) verfahrenAus.textContent = zone.verfahren; if (hinweisAus) hinweisAus.textContent = zone.hinweis; if (werkzeugAus) werkzeugAus.textContent = zone.werkzeug; if (lieferzeitAus) lieferzeitAus.textContent = zone.lieferzeit; if (stueckkostenAus) stueckkostenAus.textContent = zone.stueckkosten; if (anwendungAus) anwendungAus.textContent = zone.anwendung; } /* ---------------------------------------------------------------------- Zeigerbedienung ---------------------------------------------------------------------- */ function ausPosition(clientX) { var kasten = spur.getBoundingClientRect(); if (!kasten.width) return; var anteil = (clientX - kasten.left) / kasten.width; setzen(anteilZuWert(Math.min(1, Math.max(0, anteil)))); } var zieht = false; spur.addEventListener("pointerdown", function (e) { zieht = true; spur.setPointerCapture(e.pointerId); ausPosition(e.clientX); griff.focus(); e.preventDefault(); }); spur.addEventListener("pointermove", function (e) { if (zieht) ausPosition(e.clientX); }); var beenden = function (e) { if (!zieht) return; zieht = false; if (spur.hasPointerCapture && spur.hasPointerCapture(e.pointerId)) { spur.releasePointerCapture(e.pointerId); } }; spur.addEventListener("pointerup", beenden); spur.addEventListener("pointercancel", beenden); /* ---------------------------------------------------------------------- Tastaturbedienung — der Griff ist ein role="slider" ---------------------------------------------------------------------- */ var SCHRITT = 0.02; // Anteil der Gesamtachse pro Tastendruck griff.addEventListener("keydown", function (e) { var anteil = wertZuAnteil(aktuellerWert); var neu = null; switch (e.key) { case "ArrowRight": case "ArrowUp": neu = anteil + SCHRITT; break; case "ArrowLeft": case "ArrowDown": neu = anteil - SCHRITT; break; case "PageUp": neu = anteil + SCHRITT * 5; break; case "PageDown": neu = anteil - SCHRITT * 5; break; case "Home": neu = 0; break; case "End": neu = 1; break; default: return; } e.preventDefault(); setzen(anteilZuWert(Math.min(1, Math.max(0, neu)))); }); griff.setAttribute("aria-valuemin", String(MIN)); griff.setAttribute("aria-valuemax", String(MAX)); setzen(START); })();