tools:piano
Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen der Seite angezeigt.
| Nächste Überarbeitung | Vorherige Überarbeitung | ||
| tools:piano [29/03/2026 16:13] – angelegt Eric Weber | tools:piano [30/03/2026 15:32] (aktuell) – Eric Weber | ||
|---|---|---|---|
| Zeile 1: | Zeile 1: | ||
| < | < | ||
| - | <!-- | ||
| - | Interaktive Klaviatur mit Notenzeile | ||
| - | Einbindung in DokuWiki: Inhalt zwischen den <div id=" | ||
| - | Alle CSS-Stile sind auf #piano-app begrenzt und beeinflussen die restliche Seite nicht. | ||
| - | --> | ||
| - | |||
| <div id=" | <div id=" | ||
| Zeile 166: | Zeile 160: | ||
| /* --- Staff (Notenzeile) --- */ | /* --- Staff (Notenzeile) --- */ | ||
| + | #piano-app .pa-staff-outer { | ||
| + | margin-bottom: | ||
| + | } | ||
| + | |||
| + | #piano-app .pa-staff-resize-bar { | ||
| + | display: flex; | ||
| + | align-items: | ||
| + | justify-content: | ||
| + | margin-bottom: | ||
| + | } | ||
| + | |||
| + | #piano-app .pa-staff-label { | ||
| + | font-size: 0.7rem; | ||
| + | color: var(--pa-text-muted); | ||
| + | font-family: | ||
| + | } | ||
| + | |||
| + | #piano-app .pa-staff-size-wrap { | ||
| + | display: flex; | ||
| + | align-items: | ||
| + | gap: 6px; | ||
| + | } | ||
| + | |||
| + | #piano-app .pa-staff-size-wrap span { | ||
| + | font-size: 0.7rem; | ||
| + | color: var(--pa-text-muted); | ||
| + | } | ||
| + | |||
| + | #piano-app .pa-staff-size-wrap input[type=range] { | ||
| + | all: unset; | ||
| + | width: 90px; | ||
| + | height: 4px; | ||
| + | background: var(--pa-border); | ||
| + | border-radius: | ||
| + | cursor: pointer; | ||
| + | -webkit-appearance: | ||
| + | appearance: none; | ||
| + | } | ||
| + | |||
| + | #piano-app .pa-staff-size-wrap input[type=range]:: | ||
| + | -webkit-appearance: | ||
| + | width: 14px; | ||
| + | height: 14px; | ||
| + | border-radius: | ||
| + | background: var(--pa-gold); | ||
| + | cursor: pointer; | ||
| + | } | ||
| + | |||
| #piano-app .pa-staff-wrap { | #piano-app .pa-staff-wrap { | ||
| background: #fff; | background: #fff; | ||
| border-radius: | border-radius: | ||
| - | padding: | + | padding: |
| - | margin-bottom: | + | |
| overflow: hidden; | overflow: hidden; | ||
| position: relative; | position: relative; | ||
| + | display: flex; | ||
| + | align-items: | ||
| + | gap: 0; | ||
| + | transition: padding 0.1s; | ||
| } | } | ||
| - | #piano-app .pa-staff-label { | + | |
| - | | + | |
| - | | + | |
| - | margin-bottom: 6px; | + | |
| - | font-family: | + | align-items: |
| + | justify-content: | ||
| + | width: 52px; | ||
| + | height: 52px; | ||
| + | border-radius: | ||
| + | background: #f5f5f0; | ||
| + | border: 2px solid #ccc; | ||
| + | margin-right: 10px; | ||
| + | font-family: | ||
| + | color: #222; | ||
| + | line-height: 1; | ||
| + | /* font-size wird per JS gesetzt */ | ||
| } | } | ||
| #piano-app svg.pa-staff-svg { | #piano-app svg.pa-staff-svg { | ||
| - | | + | height: auto; /* Höhe dynamisch */ |
| - | width: | + | min-height: 60px; |
| - | | + | } |
| + | |||
| + | /* --- Oktaven-Scrollbar (sichtbar auf allen Geräten) --- */ | ||
| + | #piano-app .pa-octave-bar { | ||
| + | | ||
| + | align-items: | ||
| + | gap: 10px; | ||
| + | padding: 6px 10px 2px; | ||
| + | background: var(--pa-surface); | ||
| + | border-bottom: | ||
| + | border-radius: | ||
| + | } | ||
| + | |||
| + | #piano-app .pa-octave-bar span { | ||
| + | font-size: 0.72rem; | ||
| + | color: var(--pa-text-muted); | ||
| + | white-space: | ||
| + | } | ||
| + | |||
| + | #piano-app .pa-octave-bar input[type=range] { | ||
| + | all: unset; | ||
| + | flex: 1; | ||
| + | height: 6px; | ||
| + | background: var(--pa-border); | ||
| + | border-radius: | ||
| + | cursor: pointer; | ||
| + | -webkit-appearance: | ||
| + | appearance: none; | ||
| + | } | ||
| + | |||
| + | #piano-app .pa-octave-bar input[type=range]:: | ||
| + | -webkit-appearance: | ||
| + | width: | ||
| + | height: 22px; | ||
| + | border-radius: | ||
| + | | ||
| + | cursor: pointer; | ||
| + | border: 3px solid #fff; | ||
| + | box-shadow: 0 1px 4px rgba(0, | ||
| + | } | ||
| + | |||
| + | #piano-app .pa-octave-bar input[type=range]:: | ||
| + | width: 22px; | ||
| + | height: 22px; | ||
| + | border-radius: | ||
| + | background: var(--pa-accent); | ||
| + | cursor: pointer; | ||
| + | border: 3px solid #fff; | ||
| } | } | ||
| - | /* --- Piano Container | + | /* --- Piano Container --- */ |
| #piano-app .pa-piano-outer { | #piano-app .pa-piano-outer { | ||
| position: relative; | position: relative; | ||
| Zeile 195: | Zeile 298: | ||
| border: 1px solid var(--pa-border); | border: 1px solid var(--pa-border); | ||
| width: 100%; | width: 100%; | ||
| + | overflow: hidden; | ||
| } | } | ||
| Zeile 201: | Zeile 305: | ||
| overflow-y: hidden; | overflow-y: hidden; | ||
| padding: 10px 10px 14px; | padding: 10px 10px 14px; | ||
| + | /* Scrollbar ausblenden – Navigation nur via Slider */ | ||
| + | scrollbar-width: | ||
| + | -ms-overflow-style: | ||
| + | } | ||
| + | |||
| + | #piano-app .pa-piano-scroll:: | ||
| + | display: none; | ||
| } | } | ||
| Zeile 290: | Zeile 401: | ||
| <link rel=" | <link rel=" | ||
| - | <h1 class=" | + | <h1 class=" |
| + | < | ||
| <!-- Controls --> | <!-- Controls --> | ||
| Zeile 312: | Zeile 424: | ||
| <!-- Staff --> | <!-- Staff --> | ||
| - | <div class=" | + | <div class=" |
| - | <div class=" | + | |
| - | <svg class=" | + | |
| + | <div class=" | ||
| + | < | ||
| + | <input type=" | ||
| + | | ||
| + | | ||
| + | | ||
| + | <div class=" | ||
| + | <div class=" | ||
| + | | ||
| + | viewBox=" | ||
| + | </div> | ||
| </ | </ | ||
| <!-- Piano --> | <!-- Piano --> | ||
| <div class=" | <div class=" | ||
| - | <div class=" | + | |
| + | < | ||
| + | <input type=" | ||
| + | | ||
| + | < | ||
| + | </ | ||
| + | | ||
| <div class=" | <div class=" | ||
| </ | </ | ||
| Zeile 444: | Zeile 573: | ||
| const totalWidth = whiteKeys.length * WHITE_W; | const totalWidth = whiteKeys.length * WHITE_W; | ||
| keysContainer.style.width = totalWidth + ' | keysContainer.style.width = totalWidth + ' | ||
| + | // Beim Start ganz nach rechts scrollen (hohe Töne sichtbar) | ||
| + | setTimeout(() => { | ||
| + | const scrollEl = document.getElementById(' | ||
| + | scrollEl.scrollLeft = scrollEl.scrollWidth; | ||
| + | }, 0); | ||
| // Weiße Tasten | // Weiße Tasten | ||
| Zeile 517: | Zeile 651: | ||
| let currentVoice = ' | let currentVoice = ' | ||
| - | // SVG-Koordinaten des Notensystems | + | // SVG viewBox: "0 0 600 80" |
| - | // Notenlinien beginnen bei x=CLEF_WIDTH, | + | // Notenlinien: x von 0 bis 600, zentriert vertikal |
| - | | + | const STAFF_X1 |
| - | const STAFF_LEFT | + | const STAFF_X2 |
| - | const STAFF_RIGHT | + | const STAFF_TOP |
| - | const STAFF_TOP = 20; // y der 1. (obersten) Notenlinie | + | const LINE_DIST |
| - | const LINE_DIST = 12; // Abstand zwischen | + | |
| - | function staffY(i) { // i=0 oben, i=4 unten | + | function staffY(i) { return STAFF_TOP + i * LINE_DIST; } // i=0 oben … 4 unten |
| - | return STAFF_TOP + i * LINE_DIST; | + | |
| - | } | + | |
| // ------------------------------------------------------- | // ------------------------------------------------------- | ||
| // Diatonische Stufenberechnung | // Diatonische Stufenberechnung | ||
| - | // | + | // Kreuz: Stammton = nächst |
| - | // Jeder MIDI-Ton bekommt eine " | + | // Be: Stammton = nächst |
| - | // Stufe 0 = unterste Notenlinie des jeweiligen Schlüssels | + | |
| - | // Stufe 1 = erster Zwischenraum, | + | |
| - | // | + | |
| - | // Für ♯-Tasten gilt: | + | |
| - | // Für ♭-Tasten gilt: Stammton = nächster | + | |
| - | // | + | |
| - | // Violinschlüssel: | + | |
| - | // Bassschlüssel: | + | |
| // ------------------------------------------------------- | // ------------------------------------------------------- | ||
| - | |||
| - | // Chromatisch → diatonische Stufe innerhalb einer Oktave (C=0 … H=6) | ||
| - | // Für Kreuz: wir runden AB (z.B. Cis → 0 wie C) | ||
| - | // Für Be: wir runden AUF (z.B. Des → 1 wie D) | ||
| function chromaToDia(chroma, | function chromaToDia(chroma, | ||
| - | | + | const sharp = [0, |
| - | // Ohne Vorzeichen-Logik: | + | const flat |
| - | // Chromatisch: | + | return useFlat ? flat[chroma] : sharp[chroma]; |
| - | // 1,3,6,8,10 sind alteriert | + | |
| - | | + | |
| - | const diaMapFlat | + | |
| - | return useFlat ? diaMapFlat[chroma] : diaMap[chroma]; | + | |
| } | } | ||
| - | |||
| function midiToDiaGlobal(midi, | function midiToDiaGlobal(midi, | ||
| - | | + | |
| - | const chroma = midi % 12; | + | |
| - | return oct * 7 + chromaToDia(chroma, useFlat); | + | |
| } | } | ||
| - | |||
| function midiToDiatonicStep(midi, | function midiToDiatonicStep(midi, | ||
| const useFlat = (currentAccidental === ' | const useFlat = (currentAccidental === ' | ||
| - | | + | const ref = (clef === ' |
| - | const violinMidi = 64; // E4 – unterste Linie Violinschlüssel | + | |
| - | | + | |
| return midiToDiaGlobal(midi, | return midiToDiaGlobal(midi, | ||
| } | } | ||
| - | |||
| function stepToY(step) { | function stepToY(step) { | ||
| - | // step 0 = unterste Linie = staffY(4) | ||
| - | // step 2 = zweite Linie von unten = staffY(3), usw. | ||
| return staffY(4) - step * (LINE_DIST / 2); | return staffY(4) - step * (LINE_DIST / 2); | ||
| } | } | ||
| - | + | | |
| - | | + | |
| return [1, | return [1, | ||
| } | } | ||
| // ------------------------------------------------------- | // ------------------------------------------------------- | ||
| - | // Notenlinien | + | // Schlüssel-Badge aktualisieren (kein SVG-Pfad mehr!) |
| + | // ------------------------------------------------------- | ||
| + | function updateClefBadge(clef) { | ||
| + | const badge = document.getElementById(' | ||
| + | if (clef === ' | ||
| + | badge.textContent = ' | ||
| + | badge.style.fontSize = ' | ||
| + | badge.style.paddingBottom = ' | ||
| + | } else { | ||
| + | badge.textContent = ' | ||
| + | badge.style.fontSize = ' | ||
| + | badge.style.paddingBottom = ' | ||
| + | } | ||
| + | } | ||
| + | |||
| + | // ------------------------------------------------------- | ||
| + | // Notenzeile | ||
| // ------------------------------------------------------- | // ------------------------------------------------------- | ||
| function drawStaff(svg) { | function drawStaff(svg) { | ||
| Zeile 588: | Zeile 709: | ||
| const y = staffY(i); | const y = staffY(i); | ||
| const line = document.createElementNS(' | const line = document.createElementNS(' | ||
| - | line.setAttribute(' | + | line.setAttribute(' |
| - | | + | line.setAttribute(' |
| - | line.setAttribute(' | + | line.setAttribute(' |
| - | | + | |
| - | line.setAttribute(' | + | |
| - | | + | |
| svg.appendChild(line); | svg.appendChild(line); | ||
| } | } | ||
| } | } | ||
| - | // ------------------------------------------------------- | ||
| - | // Schlüssel zeichnen – beide als SVG-Pfade, exakt auf den Linien | ||
| - | // ------------------------------------------------------- | ||
| - | function drawClef(svg, | ||
| - | if (clef === ' | ||
| - | // Violinschlüssel: | ||
| - | // - Die geschwungene Spirale umschließt die 2. Linie von unten (= G-Linie = staffY(3)) | ||
| - | // - Der Bogen reicht von über staffY(0) bis unter staffY(4) | ||
| - | // Wir zeichnen einen stilisierten, | ||
| - | const gL = staffY(3); // G-Linie (2. von unten) | ||
| - | const top = staffY(0) - 6; | ||
| - | const bot = staffY(4) + 8; | ||
| - | const mx = 28; // x-Mitte des Schlüssels | ||
| - | |||
| - | const g = document.createElementNS(' | ||
| - | // Hauptlinie (senkrechter Strich) | ||
| - | const stem = document.createElementNS(' | ||
| - | stem.setAttribute(' | ||
| - | stem.setAttribute(' | ||
| - | stem.setAttribute(' | ||
| - | g.appendChild(stem); | ||
| - | |||
| - | // Obere Schlaufe (umschlingt G-Linie) | ||
| - | const loop = document.createElementNS(' | ||
| - | const d = [ | ||
| - | `M ${mx} ${gL + 8}`, | ||
| - | `C ${mx-18} ${gL+8}, ${mx-18} ${gL-14}, ${mx} ${gL-14}`, | ||
| - | `C ${mx+12} ${gL-14}, ${mx+14} ${gL+2}, ${mx+6} | ||
| - | `C ${mx+0} | ||
| - | ].join(' | ||
| - | loop.setAttribute(' | ||
| - | loop.setAttribute(' | ||
| - | loop.setAttribute(' | ||
| - | loop.setAttribute(' | ||
| - | loop.setAttribute(' | ||
| - | loop.setAttribute(' | ||
| - | g.appendChild(loop); | ||
| - | |||
| - | // Unterer Schweif | ||
| - | const tail = document.createElementNS(' | ||
| - | const dt = [ | ||
| - | `M ${mx} ${gL + 10}`, | ||
| - | `C ${mx+2} ${gL+22}, ${mx+16} ${gL+22}, ${mx+14} ${bot - 4}`, | ||
| - | `C ${mx+12} ${bot+2}, ${mx-4} ${bot+4}, ${mx-6} ${bot-2}` | ||
| - | ].join(' | ||
| - | tail.setAttribute(' | ||
| - | tail.setAttribute(' | ||
| - | tail.setAttribute(' | ||
| - | tail.setAttribute(' | ||
| - | tail.setAttribute(' | ||
| - | g.appendChild(tail); | ||
| - | |||
| - | svg.appendChild(g); | ||
| - | |||
| - | } else { | ||
| - | // Bassschlüssel: | ||
| - | // - Ausgangspunkt (Kehle / " | ||
| - | // - Die zwei Punkte umschließen die F-Linie: einer darüber, einer darunter | ||
| - | // - Der Schweif läuft von staffY(1) nach unten bis ca. staffY(4) | ||
| - | const fY = staffY(1); | ||
| - | const g = document.createElementNS(' | ||
| - | const mx = 22; // x-Mittelpunkt | ||
| - | |||
| - | // Geschwungener Bogen: startet auf der F-Linie, biegt nach rechts-oben, | ||
| - | // dann nach rechts-unten und endet im Schweif | ||
| - | const path = document.createElementNS(' | ||
| - | const d = [ | ||
| - | `M ${mx} ${fY}`, | ||
| - | // Aufwärtsbogen zur oberen Rundung (bleibt INNERHALB des Systems) | ||
| - | `C ${mx+2} | ||
| - | // Bogen nach unten-rechts in die Mitte | ||
| - | `C ${mx+20} ${fY + LINE_DIST*0.8}, | ||
| - | // Schweif nach unten-links bis unterste Linie | ||
| - | `C ${mx} ${fY + LINE_DIST*2.6}, | ||
| - | ].join(' | ||
| - | path.setAttribute(' | ||
| - | path.setAttribute(' | ||
| - | path.setAttribute(' | ||
| - | path.setAttribute(' | ||
| - | path.setAttribute(' | ||
| - | path.setAttribute(' | ||
| - | g.appendChild(path); | ||
| - | |||
| - | // Zwei Punkte: oberhalb und unterhalb der F-Linie (staffY(1)) | ||
| - | const dotX = mx + 26; | ||
| - | const gap = LINE_DIST * 0.55; | ||
| - | [fY - gap, fY + gap].forEach(function(dy) { | ||
| - | const dot = document.createElementNS(' | ||
| - | dot.setAttribute(' | ||
| - | dot.setAttribute(' | ||
| - | dot.setAttribute(' | ||
| - | dot.setAttribute(' | ||
| - | g.appendChild(dot); | ||
| - | }); | ||
| - | |||
| - | svg.appendChild(g); | ||
| - | } | ||
| - | } | ||
| - | |||
| - | // ------------------------------------------------------- | ||
| - | // Note zeichnen | ||
| - | // ------------------------------------------------------- | ||
| function drawNote(midi) { | function drawNote(midi) { | ||
| - | const svg = document.getElementById(' | + | const svg = document.getElementById(' |
| const clef = currentVoice === ' | const clef = currentVoice === ' | ||
| drawStaff(svg); | drawStaff(svg); | ||
| - | drawClef(svg, | ||
| if (midi == null) return; | if (midi == null) return; | ||
| const step = midiToDiatonicStep(midi, | const step = midiToDiatonicStep(midi, | ||
| - | const noteX = STAFF_LEFT + (STAFF_RIGHT - STAFF_LEFT) | + | const noteX = STAFF_X2 |
| const noteY = stepToY(step); | const noteY = stepToY(step); | ||
| const rx = 7, ry = 5; | const rx = 7, ry = 5; | ||
| - | // Hilfslinien unterhalb | + | // Hilfslinien unterhalb (step < 0, nur gerade Stufen = Linien) |
| for (let s = -2; s >= step; s -= 2) { | for (let s = -2; s >= step; s -= 2) { | ||
| - | const ly = stepToY(s); | + | const hl = document.createElementNS(' |
| - | const aux = document.createElementNS(' | + | |
| - | | + | |
| - | | + | |
| - | | + | svg.appendChild(hl); |
| - | svg.appendChild(aux); | + | |
| } | } | ||
| - | // Hilfslinien oberhalb | + | // Hilfslinien oberhalb (step > 8) |
| for (let s = 10; s <= step; s += 2) { | for (let s = 10; s <= step; s += 2) { | ||
| - | const ly = stepToY(s); | + | const hl = document.createElementNS(' |
| - | const aux = document.createElementNS(' | + | |
| - | | + | |
| - | | + | |
| - | | + | svg.appendChild(hl); |
| - | svg.appendChild(aux); | + | |
| } | } | ||
| // Notenkopf | // Notenkopf | ||
| const ellipse = document.createElementNS(' | const ellipse = document.createElementNS(' | ||
| - | ellipse.setAttribute(' | + | ellipse.setAttribute(' |
| - | | + | ellipse.setAttribute(' |
| - | ellipse.setAttribute(' | + | |
| - | | + | |
| ellipse.setAttribute(' | ellipse.setAttribute(' | ||
| - | ellipse.setAttribute(' | + | ellipse.setAttribute(' |
| svg.appendChild(ellipse); | svg.appendChild(ellipse); | ||
| - | // Hals (Notenhals | + | // Notenhals |
| - | const stemUp | + | const stemUp = step < 4; |
| - | const stemX | + | const stemX = stemUp ? noteX + rx - 1 : noteX - rx + 1; |
| - | const stemY1 | + | const stem |
| - | const stemY2 | + | |
| - | const stem = document.createElementNS(' | + | |
| stem.setAttribute(' | stem.setAttribute(' | ||
| - | stem.setAttribute(' | + | stem.setAttribute(' |
| + | | ||
| stem.setAttribute(' | stem.setAttribute(' | ||
| svg.appendChild(stem); | svg.appendChild(stem); | ||
| Zeile 755: | Zeile 765: | ||
| // Vorzeichen | // Vorzeichen | ||
| if (isAltered(midi)) { | if (isAltered(midi)) { | ||
| - | const accText | + | const acc = document.createElementNS(' |
| - | | + | |
| - | accText.setAttribute(' | + | |
| - | | + | |
| - | | + | |
| - | | + | |
| - | | + | svg.appendChild(acc); |
| - | svg.appendChild(accText); | + | |
| } | } | ||
| - | // Notenname | + | // Notenname-Label |
| - | const label = document.createElementNS(' | + | const lbl = document.createElementNS(' |
| - | | + | |
| - | label.setAttribute(' | + | |
| - | | + | |
| - | | + | |
| - | | + | |
| - | | + | svg.appendChild(lbl); |
| - | svg.appendChild(label); | + | |
| } | } | ||
| Zeile 780: | Zeile 788: | ||
| const svg = document.getElementById(' | const svg = document.getElementById(' | ||
| drawStaff(svg); | drawStaff(svg); | ||
| - | | + | |
| })(); | })(); | ||
| Zeile 790: | Zeile 798: | ||
| document.getElementById(' | document.getElementById(' | ||
| document.getElementById(' | document.getElementById(' | ||
| + | const clef = voice === ' | ||
| document.getElementById(' | document.getElementById(' | ||
| - | voice === ' | + | voice === ' |
| - | | + | |
| - | | + | |
| - | + | ||
| - | | + | |
| - | drawStaff(svg); | + | |
| - | drawClef(svg, | + | |
| - | // letzte Note neu zeichnen | + | |
| if (lastPlayedMidi != null) drawNote(lastPlayedMidi); | if (lastPlayedMidi != null) drawNote(lastPlayedMidi); | ||
| + | else drawStaff(document.getElementById(' | ||
| }; | }; | ||
| Zeile 809: | Zeile 813: | ||
| document.getElementById(' | document.getElementById(' | ||
| document.getElementById(' | document.getElementById(' | ||
| - | // Tastenbeschriftungen neu rendern | ||
| buildKeyboard(); | buildKeyboard(); | ||
| - | // letzte Note neu zeichnen | ||
| if (lastPlayedMidi != null) drawNote(lastPlayedMidi); | if (lastPlayedMidi != null) drawNote(lastPlayedMidi); | ||
| }; | }; | ||
| + | |||
| // ===================================================== | // ===================================================== | ||
| + | // 5c. Notenzeilen-Größe anpassen | ||
| + | // ===================================================== | ||
| + | window.paResizeStaff = function(val) { | ||
| + | const wrap = document.getElementById(' | ||
| + | const svg = document.getElementById(' | ||
| + | const badge = document.getElementById(' | ||
| + | // Skalierungsfaktor (100 = Standard) | ||
| + | const scale = val / 100; | ||
| + | // Padding anpassen | ||
| + | const padding = Math.round(16 * scale); | ||
| + | wrap.style.padding = padding + 'px 20px'; | ||
| + | // SVG-Höhe skalieren (Basis: 80px) | ||
| + | const svgHeight = Math.round(80 * scale); | ||
| + | svg.style.height = svgHeight + ' | ||
| + | // Badge-Größe anpassen | ||
| + | const bSize = Math.round(52 * scale); | ||
| + | badge.style.width = bSize + ' | ||
| + | badge.style.height = bSize + ' | ||
| + | badge.style.fontSize = Math.round(bSize * 0.73) + ' | ||
| + | }; | ||
| + | |||
| + | // ===================================================== | ||
| + | // 5d. Klaviatur-Scroll per Slider (Oktaven-Navigation) | ||
| + | // ===================================================== | ||
| + | window.paScrollPiano = function(val) { | ||
| + | const scrollEl = document.getElementById(' | ||
| + | const maxScroll = scrollEl.scrollWidth - scrollEl.clientWidth; | ||
| + | scrollEl.scrollLeft = Math.round((1 - val / 100) * maxScroll); | ||
| + | }; | ||
| + | |||
| + | // Slider-Position beim natürlichen Scrollen (Maus/ | ||
| + | document.getElementById(' | ||
| + | const scrollEl = this; | ||
| + | const maxScroll = scrollEl.scrollWidth - scrollEl.clientWidth; | ||
| + | if (maxScroll <= 0) return; | ||
| + | const pct = Math.round((1 - scrollEl.scrollLeft / maxScroll) * 100); | ||
| + | document.getElementById(' | ||
| + | }); | ||
| window.paToggleFullscreen = function() { | window.paToggleFullscreen = function() { | ||
| const app = document.getElementById(' | const app = document.getElementById(' | ||
| Zeile 838: | Zeile 879: | ||
| </ | </ | ||
| </ | </ | ||
| + | |||
| </ | </ | ||
tools/piano.1774793632.txt.gz · Zuletzt geändert: von Eric Weber
