Sélectionner une page


CustoCursors_featured

Les curseurs personnalisés étaient certainement une énorme tendance dans le développement Web en 2018. Dans le didacticiel suivant, nous verrons comment créer un curseur circulaire bruyant magnétique pour les éléments de navigation, comme indiqué dans Démo 4. Nous utiliserons Paper.js Avec Bruit simplex.

L'effet de curseur personnalisé que nous allons créer dans ce tutoriel
L’effet de curseur personnalisé que nous allons créer dans ce tutoriel

Le balisage du curseur

Le balisage du curseur est divisé en deux éléments. Un facile

pour le petit point blanc et un Élément pour dessiner le cercle bruyant rouge avec Paper.js.


<body class="tutorial">
  <main class="page">
    <div class="page__inner">
      
      <!-- The cursor elements --> 
      <div class="cursor cursor--small"></div>
      <canvas class="cursor cursor--canvas" resize></canvas>
      
    </div>
  </main>
</body>

Couleurs de base et mise en page

Pour donner à notre démo la couleur et la mise en page, définissons quelques styles de base.

body.tutorial {
  --color-text: #fff;
  --color-bg: #171717;
  --color-link: #ff0000;
  background-color: var(--color-bg);
}
.page {
  position: absolute;
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}
.page__inner {
  display: flex;
  justify-content: center;
  width: 100%;
}

Les styles de curseur de base

Fondamentalement, les deux éléments du curseur ont une position fixe. Nous nous ajustons pour être exactement à la pointe du pointeur de la souris La gauche et au dessus du petit curseur. Le canevas remplit simplement toute la fenêtre.

.cursor {
  position: fixed;
  left: 0;
  top: 0;
  pointer-events: none;
}
.cursor--small {
  width: 5px;
  height: 5px;
  left: -2.5px;
  top: -2.5px;
  border-radius: 50%;
  z-index: 11000;
  background: var(--color-text);
}
.cursor--canvas {
  width: 100vw;
  height: 100vh;
  z-index: 12000;
}

Les éléments de lien

Par souci de simplicité, nous ne prendrons qu’un élément de lien contenant un symbole SVG que nous pourrons ensuite animer lors du survol.

<nav class="nav">
 <a href="https://tympanus.net/codrops/2019/01/31/custom-cursor-effects/#" class="link">
  <svg class="settings-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
   <g class="settings-icon__group settings-icon__group--1">
     <line class="settings-icon__line" x1="79.69" y1="16.2" x2="79.69" y2="83.8"/>
     <rect class="settings-icon__rect" x="73.59" y="31.88" width="12.19" height="12.19"/>
    </g>
   <g class="settings-icon__group settings-icon__group--2">
     <line class="settings-icon__line" x1="50.41" y1="16.2" x2="50.41" y2="83.8"/>
     <rect class="settings-icon__rect" x="44.31" y="54.33" width="12.19" height="12.19"/>
   </g>
   <g class="settings-icon__group settings-icon__group--3">
     <line class="settings-icon__line" x1="20.31" y1="16.2" x2="20.31" y2="83.8"/>
     <rect class="settings-icon__rect" x="14.22" y="26.97" width="12.19" height="12.19"/>
   </g>
  </svg>
 </a>
 <!-- you can add more links here -->
</nav>

Les styles de navigation et de lien

Ici, nous définissons quelques styles de navigation, leurs éléments et les transitions en survol.

.nav {
  display: flex;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);  
}
.link {
  display: flex;
  width: 75px;
  height: 75px;
  margin: 0 5px;
  justify-content: center;
  align-items: center;
}
.settings-icon {
  display: block;
  width: 40px;
  height: 40px;
}
.settings-icon__line {
  stroke: var(--color-text);
  stroke-width: 5px;
  transition: all 0.2s ease 0.05s;
}
.settings-icon__rect {
  stroke: var(--color-text);
  fill: var(--color-bg);
  stroke-width: 5px;
  transition: all 0.2s ease 0.05s;
}
.link:hover .settings-icon__line,
.link:hover .settings-icon__rect {
  stroke: var(--color-link);
  transition: all 0.2s ease 0.05s;
}
.link:hover .settings-icon__group--1 .settings-icon__rect {
  transform: translateY(20px);
}
.link:hover .settings-icon__group--2 .settings-icon__rect {
  transform: translateY(-20px);
}
.link:hover .settings-icon__group--3 .settings-icon__rect {
  transform: translateY(25px);
} 
Voici à quoi devrait ressembler le résultat maintenant.
Voici à quoi devrait ressembler le résultat maintenant.

Y compris le papier et SimplexNoise

Comme mentionné précédemment, nous devons nous impliquer Paper.js. Pour animer le cercle bruyant dont nous avons besoin Bruit simplex En outre.

<script src="https://cdnjs.cloudflare.com/ajax/libs/paper.js/0.12.0/paper-core.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/simplex-noise/2.4.0/simplex-noise.min.js"></script>

Masquer le curseur système

Puisque nous créons notre propre curseur, nous devons nous assurer que le curseur système n’apparaît pas dans l’état normal et lors du déplacement des liens.

.page, .page a {
 cursor: none;
}

Animer le petit pointeur du curseur

Pour des performances fluides, nous utilisons une boucle requestAnimationFrame ().

// set the starting position of the cursor outside of the screen
let clientX = -100;
let clientY = -100;
const innerCursor = document.querySelector(".cursor--small");

const initCursor = () => {
  // add listener to track the current mouse position
  document.addEventListener("mousemove", e => {
    clientX = e.clientX;
    clientY = e.clientY;
  });
  
  // transform the innerCursor to the current mouse position
  // use requestAnimationFrame() for smooth performance
  const render = () => {
    innerCursor.style.transform = `translate(${clientX}px, ${clientY}px)`;
    // if you are already using TweenMax in your project, you might as well
    // use TweenMax.set() instead
    // TweenMax.set(innerCursor, {
    //   x: clientX,
    //   y: clientY
    // });
    
    requestAnimationFrame(render);
  };
  requestAnimationFrame(render);
};

initCursor();

Mise en place du cercle sur toile

Ce qui suit est la base du cercle rouge du curseur. Pour déplacer le cercle rouge, nous utilisons une technique appelée interpolation linéaire.

let lastX = 0;
let lastY = 0;
let isStuck = false;
let showCursor = false;
let group, stuckX, stuckY, fillOuterCursor;

const initCanvas = () => {
  const canvas = document.querySelector(".cursor--canvas");
  const shapeBounds = {
    width: 75,
    height: 75
  };
  paper.setup(canvas);
  const strokeColor = "rgba(255, 0, 0, 0.5)";
  const strokeWidth = 1;
  const segments = 8;
  const radius = 15;
  
  // we'll need these later for the noisy circle
  const noiseScale = 150; // speed
  const noiseRange = 4; // range of distortion
  let isNoisy = false; // state
  
  // the base shape for the noisy circle
  const polygon = new paper.Path.RegularPolygon(
    new paper.Point(0, 0),
    segments,
    radius
  );
  polygon.strokeColor = strokeColor;
  polygon.strokeWidth = strokeWidth;
  polygon.smooth();
  group = new paper.Group([polygon]);
  group.applyMatrix = false;
  
  const noiseObjects = polygon.segments.map(() => new SimplexNoise());
  let bigCoordinates = [];
  
  // function for linear interpolation of values
  const lerp = (a, b, n) => {
    return (1 - n) * a + n * b;
  };
  
  // function to map a value from one range to another range
  const map = (value, in_min, in_max, out_min, out_max) => {
    return (
      ((value - in_min) * (out_max - out_min)) / (in_max - in_min) + out_min
    );
  };
  
  // the draw loop of Paper.js 
  // (60fps with requestAnimationFrame under the hood)
  paper.view.onFrame = event => {
    // using linear interpolation, the circle will move 0.2 (20%)
    // of the distance between its current position and the mouse
    // coordinates per Frame
    lastX = lerp(lastX, clientX, 0.2);
    lastY = lerp(lastY, clientY, 0.2);
    group.position = new paper.Point(lastX, lastY);
  }
}

initCanvas();
Déplacer le curseur
Le curseur personnalisé vole déjà autour de l’écran.

Faire face aux limbes

const initHovers = () => {

  // find the center of the link element and set stuckX and stuckY
  // these are needed to set the position of the noisy circle
  const handleMouseEnter = e => {
    const navItem = e.currentTarget;
    const navItemBox = navItem.getBoundingClientRect();
    stuckX = Math.round(navItemBox.left + navItemBox.width / 2);
    stuckY = Math.round(navItemBox.top + navItemBox.height / 2);
    isStuck = true;
  };
  
  // reset isStuck on mouseLeave
  const handleMouseLeave = () => {
    isStuck = false;
  };
  
  // add event listeners to all items
  const linkItems = document.querySelectorAll(".link");
  linkItems.forEach(item => {
    item.addEventListener("mouseenter", handleMouseEnter);
    item.addEventListener("mouseleave", handleMouseLeave);
  });
};

initHovers();

Rendre le cercle «magnétique» et «fort»

L’extrait suivant est la version étendue de la méthode paper.view.onFrame mentionnée ci-dessus.

// the draw loop of Paper.js
// (60fps with requestAnimationFrame under the hood)
paper.view.onFrame = event => {
  // using linear interpolation, the circle will move 0.2 (20%)
  // of the distance between its current position and the mouse
  // coordinates per Frame
  if (!isStuck) {
    // move circle around normally
    lastX = lerp(lastX, clientX, 0.2);
    lastY = lerp(lastY, clientY, 0.2);
    group.position = new paper.Point(lastX, lastY);
  } else if (isStuck) {
    // fixed position on a nav item
    lastX = lerp(lastX, stuckX, 0.2);
    lastY = lerp(lastY, stuckY, 0.2);
    group.position = new paper.Point(lastX, lastY);
  }
  
  if (isStuck && polygon.bounds.width < shapeBounds.width) { 
    // scale up the shape 
    polygon.scale(1.08);
  } else if (!isStuck && polygon.bounds.width > 30) {
    // remove noise
    if (isNoisy) {
      polygon.segments.forEach((segment, i) => {
        segment.point.set(bigCoordinates[i][0], bigCoordinates[i][1]);
      });
      isNoisy = false;
      bigCoordinates = [];
    }
    // scale down the shape
    const scaleDown = 0.92;
    polygon.scale(scaleDown);
  }
  
  // while stuck and big, apply simplex noise
  if (isStuck && polygon.bounds.width >= shapeBounds.width) {
    isNoisy = true;
    // first get coordinates of large circle
    if (bigCoordinates.length === 0) {
      polygon.segments.forEach((segment, i) => {
        bigCoordinates[i] = [segment.point.x, segment.point.y];
      });
    }
    
    // loop over all points of the polygon
    polygon.segments.forEach((segment, i) => {
      
      // get new noise value
      // we divide event.count by noiseScale to get a very smooth value
      const noiseX = noiseObjects[i].noise2D(event.count / noiseScale, 0);
      const noiseY = noiseObjects[i].noise2D(event.count / noiseScale, 1);
      
      // map the noise value to our defined range
      const distortionX = map(noiseX, -1, 1, -noiseRange, noiseRange);
      const distortionY = map(noiseY, -1, 1, -noiseRange, noiseRange);
      
      // apply distortion to coordinates
      const newX = bigCoordinates[i][0] + distortionX;
      const newY = bigCoordinates[i][1] + distortionY;
      
      // set new (noisy) coodrindate of point
      segment.point.set(newX, newY);
    });
    
  }
  polygon.smooth();
};
Survolez Perlin
Et voilà, nous avons notre effet circulaire doux et fort.

Remarques générales

J’espère que vous avez apprécié ce didacticiel et que vous vous amusez à jouer avec dans vos propres projets. Bien sûr, ce n’est qu’un point de départ et vous pouvez devenir plus fou avec des animations, des formes, des couleurs, etc. Si vous avez des questions, veuillez contacter étendre ou Tirez-moi sur un tweet!

Références et crédits

Création d’une animation de vague avec Three.js
Résumé des sites Web inspirants n ° 1





Source link

Recent Posts