Как сделать анимацию прозрачных кругов сначала они маленькие потом большие и исчезают

Рейтинг: 0Ответов: 2Опубликовано: 10.06.2023

Как можно сделать сначала виден весь сайт потом запускается анимация по кнопке (это без разницы) на весь экран спускается фон быстро, и постепенно в рандомном порядке и месте появляются круги без фона за ними виден сайт и увеличиваются в размере, после чего пропадают ну или так скажем соединяются в большой один исчезает, и все сайт виден. Есть зарисовка идеи, черный фон это как бы сайт введите сюда описание изображения

Ответы

▲ 2

Маска реализована через clipPath - внешний контур - прямоугольник, внутренние - круги. Так сделан опускающийся занавес и появления кругов на нём. Группа g отвечает за изменение масштаба в конце.

const createElement = (parent_, tag) => {
    const element = document.createElementNS(
        'http://www.w3.org/2000/svg',
        tag
    );
    parent_.appendChild(element);
    return element;
}

const svg = createElement(document.body, 'svg');
svg.style.position = 'fixed';
svg.style.left = 0;
svg.style.top = 0;
svg.style.width = '100%';
svg.style.height = '100%';

const g = createElement(svg, 'g');

const clipPath = createElement(g, 'clipPath');
clipPath.setAttribute('id', 'clipPath');

const path = createElement(clipPath, 'path');
path.setAttribute('clip-rule', 'evenodd');

const setPath = (w, h, r, holes) => {
    const shapes = [`M 0 0 H ${w} V ${h} H -${w} z`];
    for (const [x, y] of holes) {
        const hole = `
            M ${x - r} ${y}
            a ${r} ${r} 0 1 0 ${2 * r} 0
            a ${r} ${r} 0 1 0 ${-2 * r} 0
            z
        `;
        shapes.push(hole);
    }
    path.setAttribute('d', shapes.join(' '));
};
setPath(200, 300, 20, []);

const rect = createElement(g, 'rect');
rect.setAttribute('width', '100%');
rect.setAttribute('height', '100%');
rect.setAttribute('clip-path', 'url(#clipPath)');

const shuffle = a => {
    for (let i = 1; i < a.length; ++i) {
        const j = Math.floor(Math.random() * (i + 1));  // random in [0, i]
        [a[i], a[j]] = [a[j], a[i]];  // swap a[i] <-> a[j]
    }
};

const slide = next => {
    const start = performance.now() / 1000;
    const step = () => {
        const t = performance.now() / 1000 - start;
        const w = svg.clientWidth;
        const h = Math.min(300 * t, svg.clientHeight);
        setPath(w, h, 20, []);
        window.requestAnimationFrame(
            (h < svg.clientHeight) ? step : next
        );
    };
    window.requestAnimationFrame(step);
};

const holes = next => {
    const start = performance.now() / 1000;
    const r = 25;
    const d = 2 * r;
    const w = Math.floor(svg.clientWidth  / d);
    const h = Math.floor(svg.clientHeight / d);
    const points = [];
    for (let i = 0; i < h; ++i) {
        for (let j = 0; j < w; ++j) {
            points.push([r + j * d, r + i * d]);
        }
    }
    shuffle(points);
    points.splice(Math.floor(points.length * 3 / 4));
    const step = () => {
        const t = performance.now() / 1000 - start;
        const n = Math.min(points.length, Math.floor(20 * t));
        setPath(svg.clientWidth, svg.clientHeight, r, points.slice(0, n));
        window.requestAnimationFrame(
            (n < points.length) ? step : next(r, points[0])
        );
    };
    window.requestAnimationFrame(step);
};

const dist = (p1, p2) => {
    const dx = p1[0] - p2[0];
    const dy = p1[1] - p2[1];
    return Math.sqrt(dx * dx + dy * dy);
};

const zoom = (radius, center) => () => {
    const start = performance.now() / 1000;
    const w = svg.clientWidth ;
    const h = svg.clientHeight;
    const corners = [[0, 0], [w, 0], [0, h], [w, h]];
    const maxDist = Math.max(...corners.map(p => dist(center, p)));
    const maxScale = maxDist / radius;
    const step = () => {
        const t = performance.now() / 1000 - start;
        const s = Math.exp(t * t);
        const tx = (1 - s) * center[0];
        const ty = (1 - s) * center[1];
        g.setAttribute('transform', `translate(${tx}, ${ty}) scale(${s})`);
        if (s < maxScale) {
            window.requestAnimationFrame(step);
        } else {
            console.log('done');
        }
    };
    window.requestAnimationFrame(step);
};

slide(() => holes(zoom));
An example of the Lorem ipsum placeholder text on a green and white webpage.
Using Lorem ipsum to focus attention on graphic elements in a webpage design proposal
One of the earliest examples of the Lorem ipsum placeholder text on 1960s advertising.

In publishing and graphic design, Lorem ipsum is a placeholder text commonly used to demonstrate the visual form of a document or a typeface without relying on meaningful content. Lorem ipsum may be used as a placeholder before final copy is available. It is also used to temporarily replace text in a process called greeking, which allows designers to consider the form of a webpage or publication, without the meaning of the text influencing the design.

Lorem ipsum is typically a corrupted version of De finibus bonorum et malorum, a 1st-century BC text by the Roman statesman and philosopher Cicero, with words altered, added, and removed to make it nonsensical and improper Latin. The first two words themselves are a truncation of 'dolorem ipsum' ('pain itself').

▲ 0

Может быть кому пригодится тут сделал сброс стилей по завершению анимации и разные размеры кругов в зависимости от размера экрана

const container = document.getElementById("animation-container");

const createElement = (parent_, tag) => {
  const element = document.createElementNS("http://www.w3.org/2000/svg", tag);
  parent_.appendChild(element);
  return element;
};

const svg = createElement(container, "svg");

const g = createElement(svg, "g");
g.setAttribute("transform", "");

const clipPath = createElement(g, "clipPath");
clipPath.setAttribute("id", "clipPath");

const path = createElement(clipPath, "path");
path.setAttribute("clip-rule", "evenodd");

const setPath = (w, h, r, holes) => {
  const shapes = [`M 0 0 H ${w} V ${h} H -${w} z`];
  for (const [x, y] of holes) {
    const hole = `
      M ${x - r} ${y}
      a ${r} ${r} 0 1 0 ${2 * r} 0
      a ${r} ${r} 0 1 0 ${-2 * r} 0
      z
    `;
    shapes.push(hole);
  }
  path.setAttribute("d", shapes.join(" "));
};

const rect = createElement(g, "rect");
rect.setAttribute("width", "100%");
rect.setAttribute("height", "100%");
rect.setAttribute("clip-path", "url(#clipPath)");
rect.setAttribute("fill", "#c9fd5b");

const shuffle = (a) => {
  for (let i = 1; i < a.length; ++i) {
    const j = Math.floor(Math.random() * (i + 1)); // random in [0, i]
    [a[i], a[j]] = [a[j], a[i]]; // swap a[i] <-> a[j]
  }
};

const slide = (next) => {
  const start = performance.now() / 1000;
  const step = () => {
    const t = performance.now() / 1000 - start;
    const w = svg.clientWidth;
    const h = Math.min(2000 * t, svg.clientHeight);
    setPath(w, h, 20, []);
    window.requestAnimationFrame(h < svg.clientHeight ? step : next);
    
  };
  window.requestAnimationFrame(step);
};

const holes = (next) => {
  const start = performance.now() / 1000;
  let r;
  if (window.innerWidth < 600) {
    r = 40;
  } else if (window.innerWidth < 1200) {
    r = 60;
  } else if (window.innerWidth < 1920) {
    r = 90;
  } else {
    r = 100;
  }
  const d = 2 * r;
  const w = Math.floor(svg.clientWidth / d);
  const h = Math.floor(svg.clientHeight / d);
  const points = [];
  for (let i = 0; i < h; ++i) {
    for (let j = 0; j < w; ++j) {
      points.push([r + j * d, r + i * d]);
    }
  }
  shuffle(points);
  points.splice(Math.floor((points.length * 3) / 4));
  const step = () => {
    const t = performance.now() / 1000 - start;
    const n = Math.min(points.length, Math.floor(20 * t));
    setPath(svg.clientWidth, svg.clientHeight, r, points.slice(0, n));
    window.requestAnimationFrame(n < points.length ? step : next(r, points[0]));
  };
  window.requestAnimationFrame(step);
};

const dist = (p1, p2) => {
  const dx = p1[0] - p2[0];
  const dy = p1[1] - p2[1];
  return Math.sqrt(dx * dx + dy * dy);
};

const zoom = (radius, center) => () => {
  const start = performance.now() / 1000;
  const w = svg.clientWidth;
  const h = svg.clientHeight;
  const corners = [[0, 0], [w, 0], [0, h], [w, h]];
  const maxDist = Math.max(...corners.map((p) => dist(center, p)));
  const maxScale = maxDist / radius;
  const step = () => {
    const t = performance.now() / 1000 - start;
    const s = Math.exp(t * t);
    const tx = (1 - s) * center[0];
    const ty = (1 - s) * center[1];
    g.style.transform = `translate(${tx}px, ${ty}px) scale(${s})`;
    if (s < maxScale) {
      window.requestAnimationFrame(step);
    } else {
      svg.style.position = "absolute";
      // удаление стиля через 5 секунд после окончания анимации
      setTimeout(() => {
        g.removeAttribute("style");
      }, 300);
      setTimeout(() => { 
        g.removeAttribute("style"); 
      path.setAttribute("d", ""); }, 300); 
    }
  };
  window.requestAnimationFrame(step);
};

let isAnimationRunning = false;
let secondClick = false;

const resetAnimation = () => {
  clearAnimation();
  resetTransform();
  isAnimationRunning = false;
  secondClick = false;
  g.setAttribute("transform", "");
  rect.setAttribute("fill", "#c9fd5b");
};

const clearAnimation = () => {
  while (svg.lastChild) {
    svg.removeChild(svg.lastChild);
  }
  resetTransform();
  svg.style.position = "relative";
};

const toggleAnimation = () => {
  if (!isAnimationRunning) {
    svg.style.position = "fixed";
    svg.style.left = 0;
    svg.style.top = 0;
    svg.style.width = "100%";
    svg.style.height = "100%";
    slide(() => holes(zoom))(null, [svg.clientWidth / 2, svg.clientHeight / 2]);
    isAnimationRunning = true;
  } else if (!secondClick) {
    resetAnimation();
    secondClick = true;
  } else {
    resetAnimation();
    svg.style.position = "fixed";
    svg.style.left = 0;
    svg.style.top = 0;
    svg.style.width = "100%";
    svg.style.height = "100%";
    slide(() => holes(zoom))(null, [svg.clientWidth / 2, svg.clientHeight / 2]);
    secondClick = false;
  }
};

svg.addEventListener("animationend", resetAnimation);

document.getElementById("switch").addEventListener("click", toggleAnimation);