Fractal Clock code

function render({ slots: ___SLOTS___ }) {
		return `<canvas id="fractal"></canvas>
<span id="date"></span>

<script>
  const LENGTH = 120;
  const LENGHT_FACTOR = 0.85;
  const WIDTH_FACTOR = 0.85;
  const OPACITY_FACTOR = 0.68;
  const LINE_WIDTH = 5;
  const LINE_OPACITY = 1;

  const dateElement = document.getElementById("date");
  const canvas = document.getElementById("fractal");
  const parent = canvas.parentNode;

  const width = parent.offsetWidth;
  const height = parent.offsetHeight;

  canvas.width = width;
  canvas.height = height;

  const ctx = canvas.getContext("2d");

  const drawLine = (x, y, len, angle, lineWidth, lineOpacity, dateAngles) => {
    ctx.lineWidth = lineWidth;
    ctx.globalAlpha = lineOpacity;

    ctx.beginPath();
    ctx.save();

    ctx.translate(x, y);
    ctx.rotate((angle * Math.PI) / 180);
    ctx.moveTo(0, 0);
    ctx.lineTo(0, -len);
    ctx.stroke();

    if (len > 20 && lineWidth > 1 && lineOpacity > 0.035) {
      drawLine(
        0,
        -len,
        len * LENGHT_FACTOR,
        dateAngles.minutes - 90,
        lineWidth * WIDTH_FACTOR,
        lineOpacity * OPACITY_FACTOR,
        dateAngles,
      );
      drawLine(
        0,
        -len,
        len * LENGHT_FACTOR,
        dateAngles.seconds - 90,
        lineWidth * WIDTH_FACTOR,
        lineOpacity * OPACITY_FACTOR,
        dateAngles,
      );
    }
    ctx.restore();
  };

  const getAnglesFromDate = (date) => {
    const hours_ = date.getHours() % 12;
    const minutes_ = date.getMinutes();
    const seconds_ = date.getSeconds();
    const milliseconds_ = date.getMilliseconds();

    const hours =
      (hours_ +
        minutes_ / 60 +
        seconds_ / 60 / 60 +
        milliseconds_ / 60 / 60 / 1000) *
      30;
    const minutes = (minutes_ + seconds_ / 60 + milliseconds_ / 60 / 1000) * 6;
    const seconds = (seconds_ + milliseconds_ / 1000) * 6;
    return { hours, minutes, seconds };
  };

  const drawDate = (date) => {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    const dateAngles = getAnglesFromDate(date);
    const { hours, minutes, seconds } = dateAngles;

    if (document.documentElement.classList.contains("dark")) {
      ctx.strokeStyle = "#e7e5e4";
    } else {
      ctx.strokeStyle = "#121212";
    }

    drawLine(
      Math.floor(canvas.width / 2),
      Math.floor(canvas.height / 2),
      LENGTH,
      hours,
      LINE_WIDTH,
      LINE_OPACITY,
      dateAngles,
    );
    drawLine(
      Math.floor(canvas.width / 2),
      Math.floor(canvas.height / 2),
      LENGTH,
      minutes,
      LINE_WIDTH,
      LINE_OPACITY,
      dateAngles,
    );
    drawLine(
      Math.floor(canvas.width / 2),
      Math.floor(canvas.height / 2),
      LENGTH,
      seconds,
      LINE_WIDTH,
      LINE_OPACITY,
      dateAngles,
    );
  };

  const animate = () => {
    const date = new Date();
    dateElement.innerHTML = date
      .toISOString()
      .replace("T", " ")
      .substring(0, date.toISOString().length - 1);
    drawDate(date);
    requestAnimationFrame(animate);
  };
  requestAnimationFrame(animate);

  window.addEventListener("resize", () => {
    canvas.width = window.innerWidth;
    canvas.height = canvas.parentNode.offsetHeight;
  });
</script>
`
	}

Fractal Clock

Los fractales son figuras geométricas que pueden ser divididas en fragmentos, cada uno de los cuales es una copia a distinta escala de la figura anterior. Una característica clave de estos es la autosimilitud, lo que significa que, sin importar cuánto ampliemos la figura, seguiremos viendo la misma estructura repetida una y otra vez.

En la práctica estos son útiles en diferentes áreas, tanto para estudios biológicos (Crecimiento de tejidos, organización celular), captura de frecuencias de radio, técnicas de compresión (audio y vídeo), entre otros.

Fractal clock es la representación artística de un reloj convencional de doce horas que utiliza principios de geometría fractal para mostrar la hora actual de manera visual. En lugar de las clásicas manecillas, cada una se despliega como una estructura fractal que se ramifica a si misma, con submanecillas que indican los minutos y los segundos de la misma forma.

La paradoja de los fractales

Una de las propiedades más asombrosas de algunos de los fractales es que pueden tener áreas finitas, pero perímetros infinitos. Lo que contradice la intuición geométrica clásica. Veamos un caso simple: el Triángulo de Sierpinski.

En general, este fractal parte de un triángulo equilátero inicial con lados de longitud 1 (por comodidad), se unen los puntos medios de cada lado y se extrae el triángulo central interno.

triangulo-sierpinski.png

A simple vista, y sin entrar en formulaciones matemáticas, podemos ver que a medida que ocurren nn iteraciones del patrón, el área negra del triángulo es cada vez menor, por lo que podemos decir que el área es cada vez más pequeña. Con el perímetro sucede lo contrario, cada vez hay más líneas entre medio de los triángulos haciendo que este tienda a infinito. Veamos cada caso.

El perímetro infinito

Para el caso del perímetro, el borde o las líneas que componen la figura, son cada vez más. Es decir, en la primer iteración (simplemente un triángulo), el área es la suma de sus lados:

P=3l=3P = 3*l = 3

Para la segunda iteración, ahora debemos sumar el perímetro formato por el triángulo interno. El lado de cada triángulo ahora es l/2l/2, por lo que su perímetro es 3×(l/2)3 \times (l/2) y, cómo tenemos 3 triángulos, el perímetro de la segunda iteración es:

P=(3×l2)×3P = (3 \times \frac{l}{2}) \times 3

O, lo que es lo mismo:

P=(l2)×32=4.5P = \Big(\frac{l}{2}\Big) \times 3^2 = 4.5

Si definimos a nn cómo la cantidad de iteraciones que se realizó sobre el patrón, podemos definir una generalización, en dónde por cada nueva iteración vemos que el perímetro es más grande:

limnPn=(ln)×3n=\lim_{n\to\infty}P_n = \Big(\frac{l}{n}\Big) \times 3^n = \infty

El área finita

El caso de los triángulos de Sierpinsky, es particular y fácil de demostrar dado que su área tiende a cero, pero lo correcto sería decir que tienen “área finita”.

Digamos que AA es el área del triángulo “base”, es decir, en la primer iteración. Cada iteración genera tres nuevos triángulos iguales quitando uno del medio, o sea 3/43/4 del área total:

A1=A034A_1 = A_0 \frac{3}{4}

En la siguiente iteración cada uno de los triángulos (más chicos) tiene, nuevamente 3/43/4 del área que los generó:

A2=A134=A0×34×34A_2 = A_1 \frac{3}{4} = A_0 \times \frac{3}{4} \times \frac{3}{4}

Podemos expresar una generalización del área para nn iteraciones:

An=(34)nA0A_n = \Big( \frac{3}{4} \Big)^n A_0

Finalmente, si la cantidad de iteraciones es infinita (n=n = \infty), veremos que el área, para el caso de los triángulos de Sierpinsky tiende a 0.

A=limnAn=A0limn(34)n=0A_{\infty} = \lim_{n \to \infty} A_n = A_0 \lim_{n \to \infty}\Big( \frac{3}{4} \Big)^n = 0

Resulta sorprendente pensar que un perímetro prácticamente infinito pueda contener un área nula. También resulta interesante ver la dimensionalidad de un fractal, pero ya excede la intención de este post, igualmente éste artículo de Wikipedia desarrolla el concepto de “Dimensionalidad fractal”.