<svg 
  viewBox="0 0 1000 1000" 
  width="1000" 
  height="1000" 
  role="img"
>
  <title>
    A geometric pattern composed of nested circles and squiggly lines.
    Inspired by Legends of Zelda: Tears of the Kingdom
  </title>
  
  <text text-anchor="middle" y="500" x="500" style="font-size: 2em; font-family: sans-serif;">Tap anywhere on the SVG canvas to add circle groups</text>

  <g class="pattern">
    <!-- 
      Our graphics code goes here 
    -->
  </g>
</svg>
html, body {
  display: grid;
  place-items: center;
  min-height: 100%;
  background-color: #eee;
}

svg {
  background: #fff;
  max-width: 90vw;
  max-height: 90vh;
  width: auto;
  height: auto;
}

.filled-circle {
  fill: #fff;
}

.stroked-circle {
  fill: none;
  stroke: #999;
  stroke-width: 10;
}
import { randomInt } from 'https://unpkg.com/randomness-helpers@0.0.1/dist/index.js';

function circle({ x, y, r, className }) {
  return `
    <circle 
      cx="${x}" 
      cy="${y}" 
      r="${r}" 
      class="${className}"
    />
  `;
}

function circleGroup({x, y, r }) {
  // We'll store all our circles in an array.
  const circles = [];

  // First, draw a circle with a white background but no border.
  // This will hide any elements behind the circle.
  circles.push(circle({ x, y, r, className: 'filled-circle' }));

  // Decide how much space to put between our circles.
  const gap = 20;

  // Draw a number of circles, making each one smaller than the last
  // until we hit a radius of 0.
  let circleSize = r;
  while(circleSize > 0) {
    circles.push(circle({ x, y, r: circleSize, className: 'stroked-circle' }));
    circleSize -= gap;
  }

  // Return all our circles as a single string;
  return circles.join('');
}

const patternEl =  document.querySelector('.pattern');
const svgEl =  document.querySelector('svg');


svgEl.addEventListener('click', (e) => {
  const { x, y } = getClickOnSvg(e);
  
  patternEl.innerHTML += circleGroup({
    x, 
    y,
    r: randomInt(100, 400),
  });
});

function getClickOnSvg(e) {
  let pt = DOMPoint.fromPoint(svgEl); 
  pt.x = e.clientX;
  pt.y = e.clientY;

    // The cursor point, translated into svg coordinates
  return  pt.matrixTransform(svgEl.getScreenCTM().inverse());
}

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.