首页 > 解决方案 > 悬停时更改画布内的图像

问题描述

我想在悬停状态下替换画布内的图像。棘手的部分是图像漂浮在它们的容器内。

问题

当移动项目悬停在画布内时如何运行函数。

我试过的

首先,我使用mouseentermousemoveonmousemove函数来捕获悬停的项目。

当前问题

即使我可以在悬停状态下捕获项目,它也无法正常工作。有时,当您在画布上移动光标时,即使光标超出其边界,它仍会记录一个项目。

笔记

在当前版本中,没有不同的图像可以交换,我只是想先获取元素。唯一的变化(悬停状态)将是项目的背景颜色,所以我尝试使用内联 SVG(以轻松更改填充属性),但内联 SVG 元素没有显示在 Firefox 上并且在 Safari 上被扭曲。因此,我回到使用图像。

代码片段

悬停代码在init函数内部。我没有简化代码以防万一您想查看整个结构,对不起质量!

( function( $ ){

'use strict';

const bouncer = {
  // Canvas element
  // 
  canvas: '',

  // Context (of canvas)
  // 
  ctx: '',

  speed_m: 1, // Speed constant to multiply
  speed_a: 2, // Speed constant to add 
  speed_r: 1.5, // Rotating speed

  // Array of bouncing objects
  // 
  items: [],


  init: function() {
    const self = window.kpBouncer;
    
    self.canvas = $( '#canvas' )[0];
    self.ctx = canvas.getContext('2d')

    self.canvas.width = $( '#canvas' ).width();
    self.canvas.height = $( '#canvas' ).height();

    self.canvas.addEventListener( 'click', self.canvas_click, false );
    self.canvas.onmousemove = function( ev ) {
      const mouse_x = ev.layerX;
      const mouse_y = ev.layerY;

      const item_hovered = self.items.find(function( item ) {
        const left = ( item.x - item.width );
        const right = ( item.x + item.width );
        const top = ( item.y - item.height );
        const bottom = ( item.y + item.height );

        if ( mouse_x < left ) {
          return false; }
        if ( mouse_x > right ) {
          return false; }
        if ( mouse_y < top ) {
          return false; }
        if ( mouse_y > bottom ) {
          return false; }

        return item;

      });
      
      if ( !item_hovered ) {
          return; }
    
      console.log( 'Hovered sticker is: ', item_hovered.id );
    }

    self.items = [];

    $( '.rotating-icon:not([disabled])' ).each( function( idx, el ) {
      const id = $( el ).prop( 'id' );
      const link = $( el ).data( 'link' );

      const w = $( el ).data( 'w' );
      const h = $( el ).data( 'h' );
      
      const x = self.random( w, ( self.canvas.width - w ) );
      const y = self.random( h, ( self.canvas.height - h ) );
      
      const item = {
        id: id,
        el: el,
        width: w,
        height: h,
        rotate: 0,
        link: ( link || '' ),
        x: x,
        y: y,
        vel_x: (Math.random() * self.speed_m + self.speed_a) * (Math.floor(Math.random() * self.speed_m) || -1),
        vel_y: (Math.random() * self.speed_m + self.speed_a) * (Math.floor(Math.random() * self.speed_m) || -1)
      };

      self.items.push( item );
    });
    
    console.log( 'Items: ', self.items );

    window.requestAnimationFrame( self.update );

  },

  draw: function() {
    const self = window.kpBouncer;

    self.ctx.clearRect( 0, 0, self.canvas.width, self.canvas.height );

    self.items.map( function( item ) {
      const axis_x = ( item.x + .5 * item.width );
      const axis_y = ( item.y + .5 * item.height );
      self.ctx.save();
      self.ctx.translate( axis_x, axis_y );
      // self.ctx.rotate( item.rotate * Math.PI / 180 );
      self.ctx.translate( -axis_x, -axis_y );
      self.ctx.drawImage( item.el, item.x, item.y, item.width, item.height ); 
      self.ctx.restore();
    });

  },

  update: function() {
    const self = window.kpBouncer;

    window.requestAnimationFrame( self.update );

    self.items = self.items.map( function( item ) {
      // bottom bound / floor
      if (item.y + item.height >= self.canvas.height) {
        item.vel_y = -item.vel_y;
        item.y = self.canvas.height - item.height;
      }
      // top bound / ceiling
      if (item.y <= 0) {
        item.vel_y = -item.vel_y;
        item.y = 0;
      }

      // left bound
      if (item.x <= 0) {
        item.vel_x = -item.vel_x;
        item.x = 0;
      }
      // right bound
      if (item.x + item.width >= self.canvas.width) {
        item.vel_x = -item.vel_x;
        item.x = self.canvas.width - item.width;
      }

      // update item position
      item.x += item.vel_x;
      item.y += item.vel_y;

      let rotate = ( self.speed_r + item.rotate );
      if ( ( rotate < 0 ) || ( rotate > 359 ) ) {
        rotate = 0; }
      item.rotate = rotate;

      return item;

    });

    self.draw();

  },


  canvas_click: function( ev ) {
    const self = window.kpBouncer;

    const mouse_x = ev.layerX;
    const mouse_y = ev.layerY;

    const item_clicked = self.items.find(function( item ) {
      const left = ( item.x - item.width );
      const right = ( item.x + item.width );
      const top = ( item.y - item.height );
      const bottom = ( item.y + item.height );

      if ( mouse_x < left ) {
        return false; }
      if ( mouse_x > right ) {
        return false; }
      if ( mouse_y < top ) {
        return false; }
      if ( mouse_y > bottom ) {
        return false; }

      return item;

    });

    if ( !item_clicked ) {
      return; }

    const link = ( item_clicked.link || '' );
    if ( link.length < 0 ) {
      return; }
    if ( !( link.startsWith( 'http' ) ) ) {
      return; }

    window.open( link, '_blank' );

  },
  
  canvas_hover: function( ev ) {
    const self = window.kpBouncer;
    
    // TODO: tidy up and place hover codes here
    // 
  },

  resize: function() {
    const self = window.kpBouncer;

    self.canvas.width = $( '#canvas' ).width();
    self.canvas.height = $( '#canvas' ).height();
  },


  random: function( min, max ) {
    const self = window.kpBouncer;

    min = Math.ceil( min );
    max = Math.floor( max );

    return ( Math.floor( Math.random() * ( max - min + 1 ) ) + min );
  },

  random_bool: function() {
    const self = window.kpBouncer;

    const rand = self.random( 0, 1 );
    return ( 0 === rand );
  }
}

$(window).resize(function(){
  bouncer.resize();
});

$( document ).ready( function() {

  window.kpBouncer = bouncer;

  bouncer.init();
});

// $(document).ready(function(){});
// $(window).resize(function(){});
// $(window).scroll(function(){});

} )( jQuery );
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

main {
  position: relative;

  width: 100vw;
  height: 84vh;

  background-color: red;
}

#canvas-box {
  width: 100%;
  height: 100%;
}

canvas {
  position: absolute;
  top: 0;
  left: 0;

  width: 100%;
  height: 100%;
}

#item-vault {
  position: absolute;
  top: 0;
  left: 0;
  width: 1px;
  height: 1px;
  opacity: 0;
  overflow: hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<main>
  <div id="canvas-box">
    <canvas id="canvas"></canvas>
  </div>

  <div id="item-vault">
    <img 
      id="rw-cv-icon"
      class="cv-icon rotating-icon"
      src="https://uploads-ssl.webflow.com/60113be6489384599d9170bc/605b1211304c53283a43c330_Sticker---CV---112x78.png"
      data-w="112"
      data-h="68"
      data-link="https://google.com/"
      alt="CV Icon">

    <img 
      id="rw-about-icon"
      class="about-icon rotating-icon"
      src="https://uploads-ssl.webflow.com/60113be6489384599d9170bc/605b121159d1b8b27d7447df_Sticker---About---162x76.png"
      data-w="162"
      data-h="76"
      data-link="https://stackoverflow.com/"
      alt="About Icon">

    <img 
      id="rw-book-icon"
      class="book-icon rotating-icon"
      src="https://uploads-ssl.webflow.com/60113be6489384599d9170bc/605b12112d6624062f346a1a_Sticker---Book---153x68.png"
      data-w="153"
      data-h="68"
      data-link="https://google.com"
      alt="Book Icon">
  </div>
</main>

标签: javascriptjquerycanvashtml5-canvas

解决方案


推荐阅读