Small knowledge, big challenge! This paper is participating in theEssentials for programmers”Creative activities

preface

If the eye has not become like the sun, it cannot see the sun;

The mind is the same, itself if not the United States will not see the United States.

— plotinus

introduce

In this issue, we will use canvas to make an interesting effect of eyeball watching the mouse position, that is, no matter where you swipe, the eyeball will stare at where you are, whether it makes you feel crispy. Take a look at the effect first:

The effect is particularly simple to achieve, we will start from the basic structure, eye class, eye movement

start

1. Basic structure

We used Vite for the build, first putting a canvas element and then using the Module mode to introduce the main logic so that subsequent modules could be loaded in.

<canvas id="canvas"></canvas>
<script type="module" src="./app.js"></script>
Copy the code

Here is the structure of the main logic:

/*app.js*/
import Eye from "./js/eye"

class Application {
  constructor() {
    this.canvas = null;
    this.ctx = null;
    this.w = 0;
    this.h = 0;
    this.eyeList = []
    this.init();
  }
  init() {
    this.canvas = document.getElementById("canvas");
    this.ctx = this.canvas.getContext("2d");
    window.addEventListener("resize".this.reset.bind(this));
    this.reset();
    this.render();
    this.step();
  }
  reset() {
    this.eyeList.length = 0;
    this.w = this.canvas.width = this.ctx.width = window.innerWidth;
    this.h = this.canvas.height = this.ctx.height = window.innerHeight;
    this.render()
  }
  render() {
    const {w, h, ctx, eyeList} = this;
    let size = 48;
    for (let i = 1; i < Math.ceil(w / 160); i++) {
      for (let j = 1; j < Math.ceil(w / 160); j++) {
        let eye = new Eye({
          x: -size + i * 160.y: -size + j * 160, size }).render(ctx); eyeList.push(eye); }}}step() {
    requestAnimationFrame(this.step.bind(this));
    const {ctx, w, h, eyeList} = this;
    ctx.clearRect(0.0, w, h);
    eyeList.forEach(eye= >{ eye.draw(); }}})window.onload = new Application();
Copy the code

We’ve done a few things here:

  • Gets the canvas and spreads it all over the screen during initialization
  • Bind the reset event to reset the canvas whenever the screen changes
  • Iterate over instantiated eye classes in render, arrange them on canvas with eyeList, and draw them in real time through step

Now the interface should directly report the error, because we haven’t written the eyeball class, but now we expect it to have size, the size of the eyeball radius, x coordinate, y coordinate at least to ensure that these basic parameters can be passed in.

2. The eye

/*eye.js*/
class Eye {
  constructor(options) {
    this.x = 0;             // X coordinates
    this.y = 0;             // Y coordinates
    this.size = 48.// Eyeball radius
    this.scale = 1;         // Scale
    this.cx = 0;            // The center offset of the x axis
    this.cy = 0;            // The center offset of the y axis
    Object.assign(this, options)
    return this;
  }
  render(ctx) {
    if(! ctx)throw new Error("context is undefined.");
    this.ctx = ctx;
    return this;
  }
  draw(){
    this.drawSphere();
    this.drawCenter();
  }
  drawSphere() {
    // Draw the eyeball
    const {ctx, x, y, scale, size} = this;
    ctx.save()
    ctx.translate(x, y);
    ctx.scale(scale, scale)
    ctx.beginPath();
    ctx.lineCap = "round";
    ctx.lineWidth = 5;
    ctx.strokeStyle = "# 000000";
    ctx.fillStyle = "#FFFFFF";
    ctx.arc(0.0, size, 0.2 * Math.PI)
    ctx.fill();
    ctx.stroke()
    ctx.restore();
  }
  drawCenter() {
    // Draw the eye
    const {ctx, x, y, scale, size,cx,cy} = this;
    ctx.save()
    ctx.translate(x+cx, y+cy);
    ctx.scale(scale, scale)
    ctx.beginPath();
    ctx.fillStyle = "# 000000";
    ctx.arc(0.0, size * 0.5.0.2 * Math.PI) ctx.fill(); ctx.stroke() ctx.restore(); }}export default Eye;
Copy the code

The eye class is very simple, we just put the black and white two circles together on the line of the eye drawing. Of course, the eye has to move, so the black ball we did a single offset overlay.

Now our interface looks like this:

Dumb, like a bunch of Mr. Bobo, because they don’t have any interactive feedback ~

3. Eye movement

To make the eye move we need to do two things, register a mouse movement event on the canvas.

/*app.js*/
init() {
    // ...
    this.canvas.addEventListener("mousemove".this.onMouseMove.bind(this), false)
    // ...
}
Copy the code

This is the most important step!!

/*app.js*/
 onMouseMove(e) {
     const {clientX, clientY} = e;
     this.eyeList.forEach(eye= > {
         const {x, y, size} = eye;
         let dx = x - clientX;
         let dy = y - clientY;
         let angle = Math.atan2(dy, dx)+Math.PI;
         eye.cx = Math.cos(angle) * (size/2-5);
         eye.cy = Math.sin(angle) * (size/2-5); })}Copy the code

We take the current mouse position, iterate over each eyeball instance, calculate the Angle we should turn by the difference between their coordinates and the mouse position, and add an offset to it.

So here we have it, online demo

thinking

In fact, the effect is similar to writing a virtual joystick article, if you want to read it in the column.

We can do a lot of creative things like this with a grin or a direct turn of the animal or plant, but again, you can’t do anything but think of it. Let’s go together