function generateSVG(grid) { // Размер ячейки для каждого кружка (в пикселях) - как в первой версии const cellSize = 22.5; // Радиус кружка const radius = 10; // Ширина обводки для кружков const strokeWidth = 2; // Ширина и высота SVG const width = grid[0].length * cellSize; const height = grid.length * cellSize; // Начало SVG let svg = ``; // Проходим по 2D массиву (true - закрашенный, false - пустой) for (let row = 0; row < grid.length; row++) { for (let col = 0; col < grid[row].length; col++) { // Центр кружка const cx = col * cellSize + cellSize / 2; const cy = row * cellSize + cellSize / 2; // Длина окружности для stroke-dasharray const circumference = 2 * Math.PI * radius; // Направление: шахматное (чётная сумма row+col - по часовой, нечётная - против) const isClockwise = (row + col) % 2 === 0; const initialOffset = isClockwise ? circumference : -circumference; // Квадрат для финальной анимации, начальный rx=ry=radius, opacity=0 const squareSize = 2 * radius; const squareX = cx - radius; const squareY = cy - radius; svg += ``; if (grid[row][col]) { // true - закрашенный // Закрашенный кружок: дуга без заливки, затем внутренний чёрный кружок svg += ``; // Внутренний кружок для расширения и заполнения чёрным из центра, начальный r=0 svg += ``; } else { // false - пустой // Пустой кружок: только дуга без заливки svg += ``; } } } // Конец SVG svg += ''; return svg; } // Функция для замены первого SVG на странице и запуска анимации function replaceAndAnimate(grid) { const svgString = generateSVG(grid); const existingSVG = document.querySelector('svg'); if (existingSVG) { existingSVG.outerHTML = svgString; // Теперь запускаем анимацию animateCircles(grid); } else { console.log('SVG не найден на странице'); } } // Функция анимации через JS function animateCircles(grid) { const radius = 10; const arcDur = 500; // Длительность рисования дуги (мс) const arcDelayStep = 100; // Задержка между кружками (мс) const fillDur = 500; // Длительность расширения внутреннего (мс) const fillDelayStep = 100; // Задержка для расширения (мс) const squareDur = 2000; // Длительность превращения в квадрат (мс) // Центр сетки const centerRow = Math.floor(grid.length / 2); const centerCol = Math.floor(grid[0].length / 2); // Максимальная задержка для первого этапа (рисование дуг) const maxDelayFirst = (grid.length + grid[0].length - 2) * arcDelayStep; // Анимация рисования дуг для всех кружков for (let row = 0; row < grid.length; row++) { for (let col = 0; col < grid[row].length; col++) { const delay = (row + col) * arcDelayStep; const circle = document.getElementById(`circle_${row}_${col}`); if (circle) { const isClockwise = (row + col) % 2 === 0; setTimeout(() => { animateDashOffset(circle, isClockwise, 2 * Math.PI * radius, arcDur); }, delay); } } } // Анимация расширения для закрашенных после первого этапа setTimeout(() => { for (let row = 0; row < grid.length; row++) { for (let col = 0; col < grid[row].length; col++) { if (grid[row][col]) { // true - закрашенный const distance = Math.sqrt((row - centerRow) ** 2 + (col - centerCol) ** 2); const delay = distance * fillDelayStep; const innerCircle = document.getElementById(`inner_${row}_${col}`); if (innerCircle) { setTimeout(() => { animateRadius(innerCircle, 0, radius, fillDur); }, delay); } } } } // Финальная анимация превращения в квадраты после расширения const maxDelaySecond = Math.max(...grid.flatMap((row, r) => row.map((_, c) => Math.sqrt((r - centerRow) ** 2 + (c - centerCol) ** 2)))) * fillDelayStep; setTimeout(() => { for (let row = 0; row < grid.length; row++) { for (let col = 0; col < grid[row].length; col++) { const circle = document.getElementById(`circle_${row}_${col}`); const square = document.getElementById(`square_${row}_${col}`); if (grid[row][col]) { // Только для закрашенных animateToSquare(circle, square, radius, squareDur); } else { // Для незакрашенных - плавное исчезновение animateFadeOut(circle, squareDur); } } } }, maxDelaySecond + fillDur); }, maxDelayFirst + arcDur); } // Вспомогательная функция для анимации stroke-dashoffset (рисование дуги) function animateDashOffset(element, isClockwise, circumference, duration) { const startTime = performance.now(); const from = isClockwise ? circumference : -circumference; const to = 0; const step = () => { const elapsed = performance.now() - startTime; const progress = Math.min(elapsed / duration, 1); const currentOffset = from + (to - from) * progress; element.setAttribute('stroke-dashoffset', currentOffset); if (progress < 1) { requestAnimationFrame(step); } }; requestAnimationFrame(step); } // Вспомогательная функция для плавной анимации радиуса function animateRadius(element, from, to, duration) { const startTime = performance.now(); const step = () => { const elapsed = performance.now() - startTime; const progress = Math.min(elapsed / duration, 1); const currentRadius = from + (to - from) * progress; element.setAttribute('r', currentRadius); if (progress < 1) { requestAnimationFrame(step); } }; requestAnimationFrame(step); } // Вспомогательная функция для плавного превращения в квадрат (теперь с border-radius эффектом) function animateToSquare(circle, square, radius, duration) { const startTime = performance.now(); const step = () => { const elapsed = performance.now() - startTime; const progress = Math.min(elapsed / duration, 1); const currentRxRy = radius * (1 - progress); const currentOpacity = progress; // opacity от 0 до 1 square.setAttribute('rx', currentRxRy); square.setAttribute('ry', currentRxRy); square.setAttribute('opacity', currentOpacity); // Скрываем круг, устанавливая opacity=0 circle.setAttribute('opacity', 1 - progress); if (progress < 1) { requestAnimationFrame(step); } }; requestAnimationFrame(step); } // Вспомогательная функция для плавного исчезновения круга function animateFadeOut(element, duration) { const startTime = performance.now(); const step = () => { const elapsed = performance.now() - startTime; const progress = Math.min(elapsed / duration, 1); const currentOpacity = 1 - progress; // opacity от 1 до 0 element.setAttribute('opacity', currentOpacity); if (progress < 1) { requestAnimationFrame(step); } }; requestAnimationFrame(step); } // Пример использования: replaceAndAnimate([[true, true, true, true, true, true, true, false, true, false, false, false, false, false, false, false, false, false, false, true, true, false, false, false, true, false, true, false, false, false, true, true, true, true, true, true, true], [true, false, false, false, false, false, true, false, false, false, true, false, false, true, true, true, true, true, false, false, true, true, false, true, true, false, false, false, true, false, true, false, false, false, false, false, true], [true, false, true, true, true, false, true, false, true, true, true, true, false, true, true, false, false, true, true, false, false, false, true, true, true, false, true, true, false, false, true, false, true, true, true, false, true], [true, false, true, true, true, false, true, false, true, false, false, false, true, true, false, false, false, false, true, false, true, false, false, true, true, true, false, false, true, false, true, false, true, true, true, false, true], [true, false, true, true, true, false, true, false, false, true, false, false, false, true, true, true, false, false, true, false, true, false, false, false, true, true, false, true, true, false, true, false, true, true, true, false, true], [true, false, false, false, false, false, true, false, true, false, false, true, false, false, false, true, true, false, false, true, false, true, false, false, true, true, true, true, false, false, true, false, false, false, false, false, true], [true, true, true, true, true, true, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, true, true, true, true, true, true], [false, false, false, false, false, false, false, false, true, false, false, true, true, true, true, false, true, true, false, false, false, true, false, true, false, false, true, true, true, false, false, false, false, false, false, false, false], [false, true, false, true, false, true, true, true, true, true, false, false, true, false, false, true, true, false, false, true, false, false, true, true, true, false, false, false, true, true, true, true, false, true, true, false, true], [true, false, false, false, false, false, false, true, true, false, false, true, true, true, false, false, true, true, false, true, true, false, true, true, true, true, true, true, true, false, false, true, false, false, true, true, false], [true, false, false, false, true, false, true, false, false, false, true, false, true, true, false, false, true, false, true, false, false, true, true, true, true, false, false, true, false, true, false, false, true, false, true, true, false], [false, true, false, true, true, false, false, true, true, false, true, true, false, true, true, true, false, false, false, true, true, false, false, true, true, true, false, false, true, false, false, true, true, false, true, false, true], [false, true, false, true, true, true, true, true, true, true, false, true, true, true, false, true, true, true, false, true, true, false, false, true, true, true, false, true, true, true, true, true, true, false, true, true, false], [true, false, false, false, true, true, false, true, false, false, true, false, false, true, false, false, false, true, true, false, false, false, true, false, true, false, false, true, false, true, true, false, false, true, false, false, false], [true, true, true, false, false, true, true, true, true, false, false, true, true, false, false, false, false, true, true, false, false, true, false, true, true, false, false, true, true, true, true, true, false, false, true, true, true], [true, false, true, true, true, true, false, true, true, false, true, false, false, false, true, true, false, true, false, true, true, false, false, true, true, true, true, false, true, false, false, true, false, false, false, false, false], [false, true, false, false, false, true, true, false, true, true, true, false, false, false, false, true, false, true, false, false, false, false, true, true, true, true, true, true, true, false, true, true, true, false, true, false, true], [false, false, true, true, false, false, false, true, true, false, false, false, true, false, false, true, false, false, true, false, false, true, false, false, true, false, false, true, false, true, false, false, false, false, true, false, false], [true, true, true, true, false, false, true, true, true, true, false, false, false, true, true, true, true, false, false, false, true, false, true, true, true, true, false, false, false, true, false, false, false, false, false, true, true], [false, true, false, false, true, true, false, false, false, true, false, false, false, true, true, true, true, true, true, false, false, true, false, false, true, true, false, true, true, true, true, true, true, false, false, false, false], [true, false, true, false, false, false, true, false, false, true, false, false, false, false, false, false, true, true, true, true, true, false, true, false, true, false, true, false, true, false, false, false, true, false, true, false, false], [false, true, true, false, true, false, false, true, false, true, false, true, true, false, false, false, true, false, false, false, true, false, false, true, true, false, false, false, false, true, false, false, false, true, false, false, false], [true, false, true, false, true, true, true, false, true, true, true, false, false, false, true, false, true, true, false, true, true, true, true, true, true, false, false, false, false, true, false, true, true, true, false, false, true], [false, false, false, true, true, false, false, true, true, false, true, true, false, false, false, false, false, true, false, true, true, false, false, true, true, false, true, true, true, false, true, false, false, true, false, true, false], [true, false, false, true, false, false, true, false, false, true, false, true, true, false, true, true, true, true, true, true, false, false, false, true, false, false, false, true, false, true, false, false, true, true, true, false, true], [false, false, false, true, true, false, false, true, true, false, false, true, true, true, false, true, true, true, false, false, true, true, true, true, false, true, false, true, true, true, false, true, true, true, true, false, false], [true, false, false, true, true, false, true, true, false, true, false, true, false, false, false, false, true, false, true, false, false, false, true, true, false, true, true, false, false, false, false, false, true, true, true, true, true], [false, true, false, false, false, false, false, false, true, true, false, true, true, true, true, true, false, false, false, false, false, true, true, true, false, true, true, true, false, false, true, false, true, true, false, false, false], [true, true, true, true, false, false, true, false, false, true, true, true, true, true, false, true, false, false, true, true, true, false, false, false, true, false, false, false, true, true, true, true, true, true, false, false, true], [false, false, false, false, false, false, false, false, true, false, true, false, false, false, false, true, false, false, true, true, true, true, true, true, true, false, false, false, true, false, false, false, true, false, false, false, false], [true, true, true, true, true, true, true, false, true, true, false, true, true, true, false, false, true, true, true, true, false, false, true, false, true, true, false, false, true, false, true, false, true, true, true, true, false], [true, false, false, false, false, false, true, false, true, true, true, false, true, false, true, true, true, false, false, false, false, true, false, false, false, true, false, true, true, false, false, false, true, false, true, true, true], [true, false, true, true, true, false, true, false, false, true, false, true, false, true, true, true, true, true, true, false, false, false, true, true, false, false, true, false, true, true, true, true, true, false, false, false, false], [true, false, true, true, true, false, true, false, true, true, true, true, true, true, true, false, false, true, true, true, true, false, true, true, false, true, false, false, false, true, false, true, false, true, false, true, false], [true, false, true, true, true, false, true, false, false, true, false, false, true, false, true, false, false, true, true, false, true, true, true, false, false, true, true, false, false, false, false, false, false, true, false, false, true], [true, false, false, false, false, false, true, false, true, true, true, true, false, true, true, true, true, false, false, false, false, false, false, false, false, true, false, true, false, true, true, true, false, true, false, false, false], [true, true, true, true, true, true, true, false, false, true, true, false, false, false, false, true, false, false, true, true, true, false, false, false, false, false, true, true, false, false, false, true, false, true, true, true, true]]);