canvas做静态图片波动

Posted 晚星@

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了canvas做静态图片波动相关的知识,希望对你有一定的参考价值。

用到的技术css, js,canvas, svg
第三方库TweenMax


本人对svg不是很会,也是找的相关的信息,这里提供一个好用的学习网站mdn

先来看看实现效果

说下实现这种效果的原理,首先在最下面有张图片,然后在图片上面创建了一个画布,这个画布可以自己手动去画,当然如果你没有此需求你可以设置成一张固定的图片(这里主要用的css是mask-image,不知道的小伙伴可以去搜下)他会把你画布中的你绘制的区域拿出来,然后咱代码下方有个svg是把这块区域弄完波纹,但是不是动态的,所以这时候用到了TimelineMax这是一个提供动画的库,类似于css动画但是比那个要丰富,就弄成了上图效果。我试过不用TimelineMax用定时器来模拟波纹,但是很丑,不推荐用。

html

<section class="bg"></section>
  <main id="sketch">
    <canvas id="canvas" data-img=""></canvas>
    <div class="mask">
      <div id="maskInner" class="mask-inner"></div>
    </div>
  </main>
  <img src="" class="img1"></img>
  <section class="button_container">
    <button class="button">清除画布</button>
    <button class="button"><input class="input" type="file" id="upload">切换图片</button>
  </section>
  <svg xlmns="http://www.w3.org/2000/svg" version="1.1" style="display: none;">
    <filter id="heat" filterUnits="objectBoundingBox" x="0" y="0" width="100%" height="100%">
      <feTurbulence id="heatturb" type="fractalNoise" numOctaves="1" seed="2" />
      <feDisplacementMap xChannelSelector="G" yChannelSelector="B" scale="22" in="SourceGraphic" />
    </filter>
  </svg>

css

* 
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;


body, html 
  height: 100%;
  overflow: hidden;


body 
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: #121212;
  background: -webkit-linear-gradient(to bottom, #434343, #121212);
  background: linear-gradient(to bottom, #434343, #121212);

.bg 
  position: fixed;
  top: -50%;
  left: -50%;
  right: -50%;
  bottom: -50%;
  width: 200%;
  height: 200vh;
  background: transparent url('../images/noise.png') repeat 0 0;
  background-repeat: repeat;
  animation: bg-animation .2s infinite;
  opacity: .9;
  visibility: visible;

@keyframes bg-animation 
  0%  transform: translate(0,0) 
  10%  transform: translate(-5%,-5%) 
  20%  transform: translate(-10%,5%) 
  30%  transform: translate(5%,-10%) 
  40%  transform: translate(-5%,15%) 
  50%  transform: translate(-10%,5%) 
  60%  transform: translate(15%,0) 
  70%  transform: translate(0,10%) 
  80%  transform: translate(-15%,0) 
  90%  transform: translate(10%,5%) 
  100%  transform: translate(5%,0) 


main 
  cursor: -webkit-grab;
  cursor: grab;
  width: 960px;
  height: 540px;
  flex-shrink: 0;
  background-image: url('../images/bg.jpg');
  background-size: cover;
  background-position: 100% 50%;
  position: relative;
  border-radius: 16px;
  overflow: hidden;
  box-shadow: 1px 1px 10px rgba(0, 0, 0, .5);
  border: 1px groove rgba(255, 255, 255, .2);
  top: -50px;


canvas 
  opacity: 0;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;


.mask 
  display: none;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  mask-mode: luminance;
  -webkit-mask-size: 100% 100%;
          mask-size: 100% 100%;
  -webkit-backdrop-filter: hard-light;
          backdrop-filter: hard-light;
  -webkit-mask-image: url('../images/mask.png');
  -moz-mask-image: url('../images/mask.png');
  mask-image: url('../images/mask.png');


.mask-inner 
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: url('../images/bg.jpg') 0% 0% repeat;
  background-size: cover;
  background-position: 100% 50%;
  filter: url(#heat);
  -webkit-mask-image: url('../images/mask.png');
  -moz-mask-image: url('../images/mask.png');
  mask-image: url('../images/mask.png')


.button_container 
  margin: 40px auto;
  position: fixed;
  bottom: 0;


.button 
  height: 40px;
  width: 200px;
  position: relative;
  -webkit-font-smoothing: antialiased;
  background: #FFFFFF;
  border-radius: 12px;
  border: none;
  outline: none;
  -webkit-appearance: none;
  color: #000000;
  border-radius: 8px;
  text-align: center;
  font-size: 18px;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  overflow: hidden;
  margin-bottom: 12px;
  box-shadow: 0 1px 0 hsl(200,5%,80%),
              0 2px 0 hsl(200,5%,75%),
              0 3px 0 hsl(200,5%,70%),
              0 4px 0 hsl(200,5%,66%),
              0 5px 0 hsl(200,5%,64%),
              0 6px 0 hsl(200,5%,62%),
              0 7px 0 hsl(200,5%,61%),
              0 8px 0 hsl(200,5%,60%),
              0 0 5px rgba(0,0,0,.05),
            0 1px 3px rgba(0,0,0,.2),
            0 3px 5px rgba(0,0,0,.2),
            0 5px 8px rgba(0,0,0,.2);

.button:hover 
  background: #EFEFEF;

.button:first-child 
  margin-right: 24px;

.button .input 
  position: absolute;
  left: 0;
  top: 0;
  -webkit-appearance: none;
  display: inline-block;
  height: 100%;
  width: 100%;
  background: transparent;
  opacity: 0;
  cursor: pointer;

js

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var sketch = document.getElementById('sketch');
var sketchStyle = window.getComputedStyle(sketch);
var mouse =  x: 0, y: 0 ;

canvas.width = parseInt(sketchStyle.getPropertyValue('width'));
canvas.height = parseInt(sketchStyle.getPropertyValue('height'));

canvas.addEventListener('mousemove', e => 
  mouse.x = e.pageX - canvas.getBoundingClientRect().left;
  mouse.y = e.pageY - canvas.getBoundingClientRect().top;
, false);

ctx.lineWidth = 40;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.strokeStyle = 'black';

canvas.addEventListener('mousedown', () => 
  ctx.beginPath();
  ctx.moveTo(mouse.x, mouse.y);
  canvas.addEventListener('mousemove', onPaint, false);
, false);

canvas.addEventListener('mouseup', () => 
  canvas.removeEventListener('mousemove', onPaint, false);
, false);

var onPaint = () => 
  ctx.lineTo(mouse.x, mouse.y);
  ctx.stroke();
  var url = canvas.toDataURL();
  document.querySelectorAll('div').forEach(item => 
    item.style.cssText += `
      display: initial;
      -webkit-mask-image: url($url);
      mask-image: url($url);
    `;
  );
;

document.querySelectorAll('div').forEach(item => 
  item.style.cssText += `
    display: initial;
  `;
);

var timeline = new TimelineMax(
  repeat: -1,
  yoyo: true
),
feTurb = document.querySelector('#heatturb');

timeline.add(
  new TweenMax.to(feTurb, 8, 
    onUpdate: function () 
      var bfX = this.progress() * 0.01 + 0.025,
        bfY = this.progress() * 0.003 + 0.01,
        bfStr = bfX.toString() + ' ' + bfY.toString();
      feTurb.setAttribute('baseFrequency', bfStr);
    
  ),
0);


function clear() 
  document.querySelectorAll('div').forEach(item => 
    item.style.cssText += `
      display: none;
      -webkit-mask-image: none;
      mask-image: none;
    `;
  );


document.querySelectorAll('.button').forEach(item => 
  item.addEventListener('click', () => 
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    clear();
  )
);

document.getElementById('upload').onchange = function () 
  var imageFile = this.files[0];
  var newImg = window.URL.createObjectURL(imageFile);
  clear();
  document.getElementById('sketch').style.cssText += `
    background: url($newImg);
    background-size: cover;
    background-position: center;
  `;
  document.getElementById('maskInner').style.cssText += `
    background: url($newImg);
    background-size: cover;
    background-position: center;
  `;
;

以上是关于canvas做静态图片波动的主要内容,如果未能解决你的问题,请参考以下文章

canvas做静态图片波动

canvas水波纹效果

一步一步教大家用canvas做 图片滑动解锁

关于H5-canvas游戏开发初谈

canvas简单实现纯色背景图片抠图

canvas简单实现纯色背景图片抠图