MediaWiki:Common.js: Unterschied zwischen den Versionen

Keine Bearbeitungszusammenfassung
Markierung: Zurückgesetzt
Keine Bearbeitungszusammenfassung
Markierung: Manuelle Zurücksetzung
Zeile 1.234: Zeile 1.234:
   }
   }


})();
/* ============================================================
  ADOS – Feuerwerk mit Raketen + Explosion (sichtbar, ES5)
  - dauerhaft
  - kein Abdunkeln (kein schwarzer Schleier)
  - Raketen mit Trail, Explosion deutlich
  ============================================================ */
(function () {
  'use strict';
  // true = nur 31.12/01.01, false = immer
  var onlyOnNewYears = false;
  // Debug in Konsole
  var DEBUG = false;
  function isNewYears() {
    var d = new Date();
    var m = d.getMonth() + 1;
    var day = d.getDate();
    return (m === 12 && day === 31) || (m === 1 && day === 1);
  }
  if (onlyOnNewYears && !isNewYears()) return;
  function log() {
    if (!DEBUG || !window.console) return;
    try { console.log.apply(console, arguments); } catch (e) {}
  }
  // Canvas anlegen
  function createCanvas() {
    // falls schon existiert (z.B. nach Reload), entfernen
    var old = document.getElementById('ados-fireworks-canvas');
    if (old && old.parentNode) old.parentNode.removeChild(old);
    var c = document.createElement('canvas');
    c.id = 'ados-fireworks-canvas';
    c.style.position = 'fixed';
    c.style.left = '0';
    c.style.top = '0';
    c.style.width = '100%';
    c.style.height = '100%';
    c.style.pointerEvents = 'none';
    c.style.zIndex = '9999';
    c.style.opacity = '1';
    document.body.appendChild(c);
    return c;
  }
  function fitCanvas(c) {
    var dpr = window.devicePixelRatio || 1;
    c.width = Math.floor(window.innerWidth * dpr);
    c.height = Math.floor(window.innerHeight * dpr);
    var ctx = c.getContext('2d');
    // Koordinaten in CSS-Pixeln nutzen
    ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    // Optional: additiver Look für „Glow“
    ctx.globalCompositeOperation = 'lighter';
    return ctx;
  }
  function rand(min, max) { return min + Math.random() * (max - min); }
  function clamp(v, a, b) { return Math.max(a, Math.min(b, v)); }
  var canvas, ctx;
  var rockets = [];
  var particles = [];
  var last = 0;
  var running = true;
  // ---- Rocket Spawn ----
  function spawnRocket() {
    var w = window.innerWidth;
    var h = window.innerHeight;
    var x = rand(60, w - 60);
    var y = h + rand(20, 120);
    // Explosionshöhe
    var targetY = rand(h * 0.12, h * 0.50);
    // Start-Geschwindigkeit nach oben (negativ)
    var vy = rand(-14.0, -18.0);
    var vx = rand(-1.8, 1.8);
    // „Glow“-Farbe (gold/weiß)
    var r = Math.floor(rand(220, 255));
    var g = Math.floor(rand(170, 240));
    var b = Math.floor(rand(80, 170));
    rockets.push({
      x: x,
      y: y,
      vx: vx,
      vy: vy,
      targetY: targetY,
      age: 0,
      life: rand(2200, 3200),
      r: r, g: g, b: b,
      trail: [] // Liste von Punkten für Spur
    });
  }
  // ---- Explosion ----
  function explode(x, y) {
    var count = Math.floor(rand(70, 140));
    var i;
    log('[Fireworks] explode @', x, y, 'count', count);
    for (i = 0; i < count; i++) {
      var angle = rand(0, Math.PI * 2);
      var speed = rand(2.5, 7.5);
      // knalligere Farben
      var rr = Math.floor(rand(120, 255));
      var gg = Math.floor(rand(80, 240));
      var bb = Math.floor(rand(120, 255));
      // etwas „Gold“-Bias
      if (Math.random() < 0.40) {
        rr = Math.floor(rand(220, 255));
        gg = Math.floor(rand(150, 230));
        bb = Math.floor(rand(30, 120));
      }
      particles.push({
        x: x,
        y: y,
        vx: Math.cos(angle) * speed,
        vy: Math.sin(angle) * speed,
        age: 0,
        life: rand(900, 1600),
        size: rand(1.8, 3.8),
        r: rr, g: gg, b: bb
      });
    }
  }
  // ---- Frame ----
  function tick(ts) {
    if (!running) return;
    if (!last) last = ts;
    var dt = ts - last;
    last = ts;
    var w = window.innerWidth;
    var h = window.innerHeight;
    // KEIN Abdunkeln: wir „faden“ mit transparenter WEISS-Schicht minimal.
    // Dadurch gibt es einen soften Trail-Effekt, aber keinen dunklen Schleier.
    // (Wenn du absolut gar keinen Trail willst: ctx.clearRect(...) statt fillRect)
    ctx.globalCompositeOperation = 'source-over';
    ctx.fillStyle = 'rgba(255,255,255,0.10)'; // kleiner Wert = weniger „Aufhellen“
    ctx.fillRect(0, 0, w, h);
    // Glow wieder aktivieren
    ctx.globalCompositeOperation = 'lighter';
    // --- Rockets ---
    var i, r;
    for (i = rockets.length - 1; i >= 0; i--) {
      r = rockets[i];
      r.age += dt;
      // Trail-Punkt speichern
      r.trail.push({ x: r.x, y: r.y });
      if (r.trail.length > 18) r.trail.shift();
      // Physik: Gravity zieht runter (vy wird weniger negativ)
      r.vy += 0.010 * (dt / 16); // stärker, damit es natürlicher wirkt
      r.x += r.vx * (dt / 16);
      r.y += r.vy * (dt / 16);
      // Explodieren, wenn Zielhöhe erreicht
      if (r.y <= r.targetY) {
        explode(r.x, r.y);
        rockets.splice(i, 1);
        continue;
      }
      // Sicherheit
      if (r.age >= r.life || r.y < -200 || r.x < -200 || r.x > w + 200) {
        rockets.splice(i, 1);
        continue;
      }
      // Trail zeichnen
      ctx.beginPath();
      ctx.lineWidth = 3.2;
      ctx.strokeStyle = 'rgba(' + r.r + ',' + r.g + ',' + r.b + ',0.35)';
      var t;
      for (t = 0; t < r.trail.length; t++) {
        var pt = r.trail[t];
        if (t === 0) ctx.moveTo(pt.x, pt.y);
        else ctx.lineTo(pt.x, pt.y);
      }
      ctx.stroke();
      // Rocket-Kopf (hell)
      ctx.beginPath();
      ctx.fillStyle = 'rgba(' + r.r + ',' + r.g + ',' + r.b + ',1)';
      ctx.arc(r.x, r.y, 3.0, 0, Math.PI * 2, false);
      ctx.fill();
    }
    // --- Particles ---
    var p;
    for (i = particles.length - 1; i >= 0; i--) {
      p = particles[i];
      p.age += dt;
      if (p.age >= p.life) {
        particles.splice(i, 1);
        continue;
      }
      // Bewegung
      p.vy += 0.020 * (dt / 16);
      p.vx *= Math.pow(0.985, dt / 16);
      p.vy *= Math.pow(0.985, dt / 16);
      p.x += p.vx * (dt / 16);
      p.y += p.vy * (dt / 16);
      var alpha = clamp(1 - (p.age / p.life), 0, 1);
      ctx.beginPath();
      ctx.fillStyle = 'rgba(' + p.r + ',' + p.g + ',' + p.b + ',' + alpha + ')';
      ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2, false);
      ctx.fill();
    }
    requestAnimationFrame(tick);
  }
  // ---- Spawner ----
  function scheduleRockets() {
    function loop() {
      if (!running) return;
      // 1–3 Raketen pro Tick
      spawnRocket();
      if (Math.random() < 0.55) spawnRocket();
      if (Math.random() < 0.20) spawnRocket();
      // Frequenz (kleiner = mehr Feuerwerk)
      setTimeout(loop, Math.floor(rand(650, 1200)));
    }
    loop();
  }
  function init() {
    canvas = createCanvas();
    ctx = fitCanvas(canvas);
    window.addEventListener('resize', function () {
      if (!canvas) return;
      ctx = fitCanvas(canvas);
    });
    log('[Fireworks] init');
    scheduleRockets();
    requestAnimationFrame(tick);
  }
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', init, false);
  } else {
    init();
  }
})();
})();