HTML для графики и анимации

Сложность: Продвинутый

Графика и анимация в HTML

Использование Canvas, SVG и CSS анимаций для создания визуальных эффектов.

1. Интерактивный Canvas

<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>HTML Графика и Анимация</title>
    <style>
        body {
            margin: 0;
            padding: 20px;
            background: linear-gradient(45deg, #1a2a6c, #b21f1f, #fdbb2d);
            background-size: 400% 400%;
            animation: gradientBG 15s ease infinite;
            font-family: Arial, sans-serif;
            color: white;
            min-height: 100vh;
        }
        
        @keyframes gradientBG {
            0% { background-position: 0% 50%; }
            50% { background-position: 100% 50%; }
            100% { background-position: 0% 50%; }
        }
        
        .container {
            max-width: 1200px;
            margin: 0 auto;
        }
        
        .section {
            background: rgba(255, 255, 255, 0.1);
            backdrop-filter: blur(10px);
            border-radius: 15px;
            padding: 30px;
            margin-bottom: 30px;
            border: 1px solid rgba(255, 255, 255, 0.2);
        }
        
        h1, h2 {
            text-align: center;
            margin-bottom: 30px;
            text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
        }
        
        .canvas-container {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 20px;
            margin-bottom: 30px;
        }
        
        canvas {
            background: rgba(0, 0, 0, 0.3);
            border-radius: 10px;
            border: 2px solid rgba(255, 255, 255, 0.3);
            cursor: crosshair;
        }
        
        .controls {
            display: flex;
            gap: 10px;
            margin-bottom: 15px;
            flex-wrap: wrap;
        }
        
        button {
            background: rgba(255, 255, 255, 0.2);
            border: 1px solid rgba(255, 255, 255, 0.3);
            color: white;
            padding: 10px 20px;
            border-radius: 5px;
            cursor: pointer;
            transition: all 0.3s ease;
        }
        
        button:hover {
            background: rgba(255, 255, 255, 0.3);
            transform: translateY(-2px);
        }
        
        .svg-section {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 20px;
            margin-top: 30px;
        }
        
        .svg-item {
            background: rgba(255, 255, 255, 0.1);
            padding: 20px;
            border-radius: 10px;
            text-align: center;
        }
        
        .animation-demo {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
            gap: 20px;
            margin-top: 30px;
        }
        
        .animated-box {
            width: 100%;
            height: 150px;
            background: linear-gradient(45deg, #ff6b6b, #ffa726);
            border-radius: 10px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-weight: bold;
            font-size: 18px;
        }
        
        /* Анимации */
        .bounce { animation: bounce 2s infinite; }
        .pulse { animation: pulse 2s infinite; }
        .rotate { animation: rotate 3s linear infinite; }
        .slide { animation: slide 4s ease-in-out infinite; }
        
        @keyframes bounce {
            0%, 20%, 50%, 80%, 100% { transform: translateY(0); }
            40% { transform: translateY(-30px); }
            60% { transform: translateY(-15px); }
        }
        
        @keyframes pulse {
            0% { transform: scale(1); }
            50% { transform: scale(1.1); }
            100% { transform: scale(1); }
        }
        
        @keyframes rotate {
            from { transform: rotate(0deg); }
            to { transform: rotate(360deg); }
        }
        
        @keyframes slide {
            0%, 100% { transform: translateX(0); }
            50% { transform: translateX(50px); }
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>? HTML Графика и Анимация</h1>
        
        <!-- Canvas Section -->
        <section class="section">
            <h2>?️ Интерактивный Canvas</h2>
            
            <div class="canvas-container">
                <div>
                    <h3>Рисовалка</h3>
                    <div class="controls">
                        <button onclick="clearCanvas()">Очистить</button>
                        <button onclick="changeColor("#ff6b6b")" style="background: #ff6b6b;">Красный</button>
                        <button onclick="changeColor("#4ecdc4")" style="background: #4ecdc4;">Бирюзовый</button>
                        <button onclick="changeColor("#45b7d1")" style="background: #45b7d1;">Синий</button>
                        <button onclick="changeBrushSize(2)">Тонкая</button>
                        <button onclick="changeBrushSize(10)">Толстая</button>
                    </div>
                    <canvas id="drawingCanvas" width="500" height="400"></canvas>
                </div>
                
                <div>
                    <h3>Анимация частиц</h3>
                    <div class="controls">
                        <button onclick="toggleParticles()" id="toggleParticles">Старт</button>
                        <button onclick="changeParticleCount(50)">Мало</button>
                        <button onclick="changeParticleCount(200)">Средне</button>
                        <button onclick="changeParticleCount(500)">Много</button>
                    </div>
                    <canvas id="particleCanvas" width="500" height="400"></canvas>
                </div>
            </div>
        </section>
        
        <!-- SVG Section -->
        <section class="section">
            <h2>? SVG Графика</h2>
            <div class="svg-section">
                <div class="svg-item">
                    <svg width="150" height="150" viewBox="0 0 100 100">
                        <circle cx="50" cy="50" r="40" fill="#ff6b6b" />
                        <circle cx="50" cy="50" r="30" fill="#4ecdc4" />
                        <circle cx="50" cy="50" r="20" fill="#45b7d1" />
                        <circle cx="50" cy="50" r="10" fill="#96ceb4" />
                    </svg>
                    <p>Концентрические круги</p>
                </div>
                
                <div class="svg-item">
                    <svg width="150" height="150" viewBox="0 0 100 100">
                        <polygon points="50,10 90,90 10,90" fill="#ffa726" />
                        <polygon points="50,30 70,70 30,70" fill="#ffca28" />
                        <polygon points="50,50 60,60 40,60" fill="#ffee58" />
                    </svg>
                    <p>Вложенные треугольники</p>
                </div>
                
                <div class="svg-item">
                    <svg width="150" height="150" viewBox="0 0 100 100">
                        <rect x="10" y="10" width="80" height="80" rx="15" fill="#ab47bc" />
                        <rect x="20" y="20" width="60" height="60" rx="10" fill="#ce93d8" />
                        <rect x="30" y="30" width="40" height="40" rx="5" fill="#e1bee7" />
                    </svg>
                    <p>Скругленные прямоугольники</p>
                </div>
                
                <div class="svg-item">
                    <svg width="150" height="150" viewBox="0 0 100 100">
                        <defs>
                            <linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="100%">
                                <stop offset="0%" style="stop-color:#ff4081;stop-opacity:1" />
                                <stop offset="100%" style="stop-color:#7b1fa2;stop-opacity:1" />
                            </linearGradient>
                        </defs>
                        <ellipse cx="50" cy="50" rx="45" ry="30" fill="url(#grad1)" />
                        <text x="50" y="55" text-anchor="middle" fill="white" font-size="12">Эллипс</text>
                    </svg>
                    <p>Градиентный эллипс</p>
                </div>
            </div>
        </section>
        
        <!-- CSS Animations Section -->
        <section class="section">
            <h2>✨ CSS Анимации</h2>
            <div class="animation-demo">
                <div>
                    <div class="animated-box bounce">BOUNCE</div>
                    <p style="text-align: center; margin-top: 10px;">Прыгающая анимация</p>
                </div>
                
                <div>
                    <div class="animated-box pulse">PULSE</div>
                    <p style="text-align: center; margin-top: 10px;">Пульсирующая анимация</p>
                </div>
                
                <div>
                    <div class="animated-box rotate">ROTATE</div>
                    <p style="text-align: center; margin-top: 10px;">Вращающаяся анимация</p>
                </div>
                
                <div>
                    <div class="animated-box slide">SLIDE</div>
                    <p style="text-align: center; margin-top: 10px;">Скользящая анимация</p>
                </div>
            </div>
        </section>
    </div>

    <script>
        // Canvas Drawing
        const drawingCanvas = document.getElementById("drawingCanvas");
        const ctx = drawingCanvas.getContext("2d");
        let isDrawing = false;
        let lastX = 0;
        let lastY = 0;
        let hue = 0;
        let brushSize = 5;
        let direction = true;

        drawingCanvas.addEventListener("mousedown", startDrawing);
        drawingCanvas.addEventListener("mousemove", draw);
        drawingCanvas.addEventListener("mouseup", stopDrawing);
        drawingCanvas.addEventListener("mouseout", stopDrawing);

        function startDrawing(e) {
            isDrawing = true;
            [lastX, lastY] = [e.offsetX, e.offsetY];
        }

        function draw(e) {
            if (!isDrawing) return;
            
            ctx.strokeStyle = `hsl(${hue}, 100%, 50%)`;
            ctx.lineJoin = "round";
            ctx.lineCap = "round";
            ctx.lineWidth = brushSize;
            
            ctx.beginPath();
            ctx.moveTo(lastX, lastY);
            ctx.lineTo(e.offsetX, e.offsetY);
            ctx.stroke();
            
            [lastX, lastY] = [e.offsetX, e.offsetY];
            
            hue++;
            if (hue >= 360) hue = 0;
            
            if (brushSize >= 50 || brushSize <= 1) direction = !direction;
            if (direction) brushSize++;
            else brushSize--;
        }

        function stopDrawing() {
            isDrawing = false;
        }

        function clearCanvas() {
            ctx.clearRect(0, 0, drawingCanvas.width, drawingCanvas.height);
        }

        function changeColor(color) {
            ctx.strokeStyle = color;
        }

        function changeBrushSize(size) {
            brushSize = size;
        }

        // Particle System
        const particleCanvas = document.getElementById("particleCanvas");
        const pctx = particleCanvas.getContext("2d");
        let particles = [];
        let animationId = null;
        let particleCount = 100;

        class Particle {
            constructor() {
                this.x = Math.random() * particleCanvas.width;
                this.y = Math.random() * particleCanvas.height;
                this.size = Math.random() * 5 + 1;
                this.speedX = Math.random() * 3 - 1.5;
                this.speedY = Math.random() * 3 - 1.5;
                this.color = `hsl(${Math.random() * 360}, 50%, 50%)`;
            }
            
            update() {
                this.x += this.speedX;
                this.y += this.speedY;
                
                if (this.x > particleCanvas.width) this.x = 0;
                else if (this.x < 0) this.x = particleCanvas.width;
                
                if (this.y > particleCanvas.height) this.y = 0;
                else if (this.y < 0) this.y = particleCanvas.height;
            }
            
            draw() {
                pctx.fillStyle = this.color;
                pctx.beginPath();
                pctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
                pctx.fill();
            }
        }

        function initParticles() {
            particles = [];
            for (let i = 0; i < particleCount; i++) {
                particles.push(new Particle());
            }
        }

        function animateParticles() {
            pctx.clearRect(0, 0, particleCanvas.width, particleCanvas.height);
            
            for (let particle of particles) {
                particle.update();
                particle.draw();
            }
            
            // Соединение частиц линиями
            pctx.strokeStyle = "rgba(255, 255, 255, 0.1)";
            pctx.lineWidth = 1;
            
            for (let i = 0; i < particles.length; i++) {
                for (let j = i; j < particles.length; j++) {
                    const dx = particles[i].x - particles[j].x;
                    const dy = particles[i].y - particles[j].y;
                    const distance = Math.sqrt(dx * dx + dy * dy);
                    
                    if (distance < 100) {
                        pctx.beginPath();
                        pctx.moveTo(particles[i].x, particles[i].y);
                        pctx.lineTo(particles[j].x, particles[j].y);
                        pctx.stroke();
                    }
                }
            }
            
            animationId = requestAnimationFrame(animateParticles);
        }

        function toggleParticles() {
            const button = document.getElementById("toggleParticles");
            if (animationId) {
                cancelAnimationFrame(animationId);
                animationId = null;
                button.textContent = "Старт";
            } else {
                animateParticles();
                button.textContent = "Стоп";
            }
        }

        function changeParticleCount(count) {
            particleCount = count;
            initParticles();
            if (animationId) {
                cancelAnimationFrame(animationId);
                animateParticles();
            }
        }

        // Инициализация
        initParticles();
    </script>
</body>
</html>