Efecto linterna con objetos
Usamos la propiedad shadow de CSS y el evento de movimiento del ratón
Solución
Vamos a colocar en la página un bloque div (pizarra) relleno con texto (el socorrido lorem ipsum ), pero este texto no se verá porque estará oculto bajo un manto negro.
Ese manto negro proviene de otro bloque div (linterna), redondo, con sombra muy ancha que oculta el bloque pizarra, pero con una zona central por que se ve el texto de pizarra
Un click del ratón coge la linterna y la arrastra por toda la pizarra y otro click la suelta.
<body>
<div class="pizarra" id="pizarra">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec vitae consequat erat, id luctus mi. Maecenas metus magna, tristique a fringilla nec, blandit sit amet ex. In quis elit pellentesque, facilisis nisl mollis, tempor augue. Maecenas vel consectetur mauris. Vivamus feugiat metus tempus libero ornare, non ornare tortor efficitur.
</p>
<img src="/imgs/playa.png" style="margin:0 auto; width: 100%" alt="">
<div class="linterna" id="linterna"></div>
</div>
</body>
<script>
class Linterna{
constructor(cont, id, radio){
this.fondo = document.getElementById(cont);
this.luz = document.getElementById(id);
this.radio = radio+"px";
this.encendida = false;
this.fondo.addEventListener('mousedown', this);
}
handleEvent(ev){
switch (ev.type){
case "mousedown":
this.toggle(ev);
break;
case "mousemove":
this.mover(ev);
}
}
toggle(ev){
if(this.encendida){
this.encendida = false;
this.luz.style.width = "0px";
this.luz.style.height= "0px";
this.fondo.removeEventListener("mousemove", this);
}else{
this.encendida = true;
this.luz.style.width = this.radio;
this.luz.style.height= this.radio;
this.fondo.addEventListener("mousemove", this);
this.luz.style.cursor = 'none';
this.mover(ev);
}
}
mover(ev){
let pX = ev.clientX - this.luz.clientWidth/2 - this.fondo.offsetLeft;
let pY = ev.clientY - this.luz.clientHeight/2 - this.fondo.offsetTop;
this.luz.style.left = pX + "px";
this.luz.style.top = pY + "px";
}
}
let linterna = new Linterna('pizarra','linterna', 80);
</script>
<style>
.linterna {
position: absolute;
width: 0px;
height: 0px;
box-shadow: 0 0 0 99999px rgb(0, 0, 0);
border-radius: 50%;
}
.pizarra{
display: block;
position: relative;
overflow: hidden;
width: 40vw;
height: 80vh;
margin: 0 auto;
cursor: grab;
}
</style>
Explicación
Para implementar esta linterna usamos un objeto que abarca la pizarra y el foco de la linterna que va revelando su contenido: alumbrándola.
El objeto tiene como propiedades el radio del foco y si está encendida o apagada, y los bloques del DOM que forman la pizarra y el foco. Al construir el objeto se le asigna un evento mousedown para encender o apagar la linterna (toggle).
El control del evento sobre la pizarra se gestiona mediante el propio objeto, fíjate en el segundo argumento del addEventListener para que esto funcione el objeto debe tener un método eventHandler.
El método eventHandler comprueba el evento que recibe:
- Si es un mousedown toca encender/apagar la linterna (toggle)
- Si es mouse move simplemente mueve el foco (mover)
Encender la linterna (al hacer click en el área de la pizarra) significa que el foco se vea, eso se consigue poniéndole su tamaño (propiedad radio) y apagarla es ponerle a 0, tanto el alto como el ancho.
Para mover el foco con el ratón usamos el evento mousemove cuya función gestora mira la posición del cursor en la ventana y calcula a partir de ella la posición la del bloque foco:
La posición del cursor es relativa a la ventana del navegador, le restamos la posición del bloque pizarra para referirla a éste y luego el radio para poner el centro del foco donde esté el cursor.
Ya ya está, el resto son los estilos CSS que puedes modificar para cambiar el aspecto, solo debes respetar el color de la sombra que no debe ser transparente, puedes ponerle un ligera transparencia o cambiarle color...