css/canvas小效果 -- 初入秘境

386 阅读5分钟

一、canvas实现水滴扩散效果

<canvas id="myCanvas" width="800" height="800" style="border:1px solid #c3c3c3;"> 
     Your browser does not support the canvas element. 
</canvas>	

  		var canvas = document.getElementById("canvas");
		var context = canvas.getContext("2d");

		// 保存图片路径的数组
		var urlArr = ["https://image-static.segmentfault.com/186/861/1868615973-5b87dbe4c8e85_articlex",
		    "https://image-static.segmentfault.com/374/956/3749561513-5b87dbe6a9436"];
		// imgArr 保存加载后的图片的数组,imgArr中保存的是真实的图片
		// loadImg 函数用来加载 urlArr 中所有的图片

		// 并返回一个保存所有图片的数组
		var imgArr = loadImg(urlArr);
		// flag 用来限制 点击事件,一张图片只会产生一次效果
		var flag = false;


		function loadImg(urlArr) {
		    var index = 0;
		    var res = [];
		    // 每次给 load 函数传入一个图片路径,来加载图片
		    load(urlArr[index]);

		    function load(url) {
		        // 如果 index 等于 urlArr.length,
		        // 表示加载完 全部图片了,就结束 load函数
		        if (index == urlArr.length) {
		            // 加载完全部图片,调用 init 函数
		            init();
		            return;
		        }

		        var img = new Image();
		        img.src = url;
		        // 不管当前图片是否加载成功,都要加载下一张图片
		        img.onload = next;
		        img.onerror = function () {
		            console.log(res[index] + "加载失败");
		            next();
		        }
		        // next 用来加载下一张图片
		        function next() {
		            // 把加载后的图片,保存到 res 中
		            res[index] = img;
		            load(urlArr[++index])
		        }
		    }
		    // 最后返回保存所有真实图片的数组
		    return res;
		}

		function init() {
		    // 先在canvas上画黑白的图片,然后再设置背景是彩色的图片
		    // 避免先显示出彩色图片,再显示出黑白的图片
		    context.globalCompositeOperation = "source-over";
		    context.drawImage(imgArr[0], 0, 0, 400, 250);
		    canvas.style.background = 'url(https://image-static.segmentfault.com/374/956/3749561513-5b87dbe6a9436)';
		    canvas.style.backgroundSize = "100% 100%";

		    // flag 是 true 时,鼠标点击才有水滴扩散的效果
		    flag = true;
		    // canvas 绑定点击事件,点击时产生水滴扩散效果
		    canvas.onclick = diffusion;
		}

		// width 表示 不规则形状的图片的尺寸
		var width = 0;
		// speed 表示扩散效果的速度
		var speed = 8;
		// diffusion 函数根据鼠标坐标,产生效果
		function diffusion(e) {
		    console.log(222, e)
		    if (flag) {
		        flag = false;
		        context.globalCompositeOperation = "destination-out";
		        window.requestAnimationFrame(draw);
		        // 根据鼠标坐标,画扩散效果
		        function draw() {
		            // 这里不一定需要是 1800 ,但必须是一个足够大的数,可以扩散出整张背景图
		            if (width > 1800) {
		                flag = true;
		                return;
		            }
		            width += speed;
		            // 获取鼠标相对于 canvas 的坐标
		            var x = e.layerX;
		            var y = e.layerY;

		            // 画不规则形状的图片,逐渐增大图片尺寸
		            context.drawImage(imgArr[1], x - (width / 2), y - (width / 2), width, width);
		            window.requestAnimationFrame(draw);
		        }
		    }
		}

二、刮刮卡效果

代码连接:codepen.io/FEWY/pen/BO…

<canvas id="canvas" width="400px" height="250px"></canvas>

   var canvas = document.getElementById("canvas");
	var context = canvas.getContext("2d");
	// canvas的宽度
	var width = 400;
	// canvas的高度
	var height = 250;

	init()

	function init() {
	    // 先在canvas上画一个灰色的矩形
	    context.fillStyle = '#ddd';
	    context.fillRect(0, 0, width, height);
	    // 设置canvas的背景为一张图片
	    canvas.style.background =
	        'url("https://www.kkkk1000.com/images/globalCompositeOperation/bg3.jpg") no-repeat center';
	    canvas.style.backgroundSize = "100% 100%";

	    // 设置画的线的宽度			
	    context.lineWidth = 35;
	    // 设置线交汇时,是圆角的
	    context.lineJoin = "round";
	}



	canvas.addEventListener('mousedown', mouseDown, false);
	canvas.addEventListener('mousemove', mouseMove, false);
	canvas.addEventListener('mouseup', mouseUp, false);

	/* 如果需要移动端也可以生效,
	需要绑定touchstart、touchmove、touchend 事件,并且获取触摸点的坐标
	*/
	//canvas.addEventListener('touchstart', mouseDown, false);
	//canvas.addEventListener('touchmove', mouseMove, false);
	//canvas.addEventListener('touchend', mouseUp, false);


	// 判断是否可以画线
	var isDrawing;
	// 保存开始画线时,线的起点的X坐标
	var startX = 0;
	// 保存开始画线时,线的起点的Y坐标
	var startY = 0;

	// 按下鼠标按钮时,调用mouseDown
	function mouseDown(e) {
	    isDrawing = true;
	    // 保存鼠标点击时 X坐标为,画线时,线的起点的X坐标
	    startX = e.layerX;
	    // 保存鼠标点击时 Y坐标为,画线时,线的起点的Y坐标
	    startY = e.layerY;

	    /* 移动端使用下面的方法 获取 startX 和 startY
	    startX = e.touches[0].clientX;
	    startY = e.touches[0].clientY;
	    */
	}

	// 鼠标移动时,调用mouseDown
	function mouseMove(e) {
	    if (isDrawing) {
	        // 获取鼠标相对于 canvas 的坐标
	        var x = e.layerX;
	        var y = e.layerY;

	        /* 移动端使用下面的方法 获取 x 和 y
	        var x = e.touches[0].clientX;
	        var y = e.touches[0].clientY;
	        */
	        context.globalCompositeOperation = "destination-out";

	        // 开始画线
	        context.beginPath();
	        // 起点坐标为 startX 和 startY
	        context.moveTo(startX, startY);
	        // 结束的坐标为这次移动时的坐标
	        context.lineTo(x, y);
	        context.closePath();
	        context.stroke();

	        // 设置这次移动结束时的坐标,为下次开始画线时的坐标
	        startX = x;
	        startY = y;
	    }
	}

	// 松开鼠标按钮时,调用的事件
	function mouseUp(e) {
	    // isDrawing 为false时,不可以画线
	    isDrawing = false;
	    // 获取图片像素信息
	    var data = context.getImageData(0, 0, width, height).data;
	    console.log("图片像素信息", data);
	    var length = data.length;
	    var k = 0;

	    // 如果一个像素是透明的(值都是0),k就+1
	    for (var i = 0; i < length - 3; i += 4) {
	        if (data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 0 && data[i + 3] == 0) {
	            k++;
	        }
	    }

	    // 当k > width*height*0.2 时,
	    // 也就是说有20%的面积是透明的时,就把整个canvas的背景显示出来
	    if (k > width * height * 0.2) {
	        context.fillStyle = "blue";
	        context.fillRect(0, 0, width, height);
	    }
	}

三、翻牌动画

//css
/* The properties in this rule are only necessary for the 'flip' transition.
 * We need specify the perspective to create a projection matrix. This will add
 * some depth as the element flips. The depth number represents the distance of
 * the viewer from the z-plane. According to the CSS3 spec, 1000 is a moderate
 * value.
 */
.viewport-flip {
    -webkit-perspective: 1000;
    perspective: 1000;
    position: absolute;
}
.flip {
    -webkit-backface-visibility: hidden;
    -webkit-transform: translateX(0); /* Needed to work around an iOS 3.1 bug that causes listview thumbs to disappear when -webkit-visibility:hidden is used. */
    backface-visibility: hidden;/*backface-visibility 属性定义当元素不面向屏幕时是否可见*/
    transform: translateX(0);
}
.flip.out {
    -webkit-transform: rotateY(-90deg) scale(.9);
    -webkit-animation-name: flipouttoleft;
    -webkit-animation-duration: 175ms;
    transform: rotateY(-90deg) scale(.9);
    animation-name: flipouttoleft;
    animation-duration: 175ms;
}
.flip.in {
    -webkit-animation-name: flipintoright;
    -webkit-animation-duration: 225ms;
    animation-name: flipintoright;
    animation-duration: 225ms;
}
.flip.out.reverse {
    -webkit-transform: rotateY(90deg) scale(.9);
    -webkit-animation-name: flipouttoright;
    transform: rotateY(90deg) scale(.9);
    animation-name: flipouttoright;
}
.flip.in.reverse {
    -webkit-animation-name: flipintoleft;
    animation-name: flipintoleft;
}
@-webkit-keyframes flipouttoleft {
    from { -webkit-transform: rotateY(0); }
    to { -webkit-transform: rotateY(-90deg) scale(.9); }
}
@keyframes flipouttoleft {
    from { transform: rotateY(0); }
    to { transform: rotateY(-90deg) scale(.9); }
}
@-webkit-keyframes flipouttoright {
    from { -webkit-transform: rotateY(0) ; }
    to { -webkit-transform: rotateY(90deg) scale(.9); }
}
@keyframes flipouttoright {
    from { transform: rotateY(0); }
    to { transform: rotateY(90deg) scale(.9); }
}
@-webkit-keyframes flipintoleft {
    from { -webkit-transform: rotateY(-90deg) scale(.9); }
    to { -webkit-transform: rotateY(0); }
}
@keyframes flipintoleft {
    from { transform: rotateY(-90deg) scale(.9); }
    to { transform: rotateY(0); }
}
@-webkit-keyframes flipintoright {
    from { -webkit-transform: rotateY(90deg) scale(.9); }
    to { -webkit-transform: rotateY(0); }
}
@keyframes flipintoright {
    from { transform: rotateY(90deg) scale(.9); }
    to { transform: rotateY(0); }
}

//html

<div id="box" class="box viewport-flip" title="点击翻面">
    <a href="/" class="list flip out"><img src="http://image.zhangxinxu.com/image/blog/201210/puke-k.png" alt="纸牌正面"></a>
    <a href="/" class="list flip"><img src="http://image.zhangxinxu.com/image/blog/201210/puke-back.png" alt="纸牌背面"></a>
</div>

//js

// 在前面显示的元素,隐藏在后面的元素
var eleBack = null, eleFront = null,
    // 纸牌元素们 
    eleList = $(".list");

// 确定前面与后面元素
var funBackOrFront = function() {
    eleList.each(function() {
        if ($(this).hasClass("out")) {
            eleBack = $(this);
        } else {
            eleFront = $(this);
        }
    });
};
funBackOrFront();


$("#box").bind("click", function() {
    // 切换的顺序如下
    // 1. 当前在前显示的元素翻转90度隐藏, 动画时间225毫秒
    // 2. 结束后,之前显示在后面的元素逆向90度翻转显示在前
    // 3. 完成翻面效果
    eleFront.addClass("out").removeClass("in");
    setTimeout(function() {
        eleBack.addClass("in").removeClass("out");
        // 重新确定正反元素
        funBackOrFront();
    }, 225);
    return false;
});

效果连接:www.zhangxinxu.com/study/20121…

翻牌效果二

//html

<div class="row">
   <!--翻纸牌效果  -->
   <div class="col-1-of-3">
      <div class="card">
         <div class="card__side card__side--front-1">
	    <a href="#">
	       <img src="img/fanmian.jpg">
	    </a>
	  </div>
	  <div class="card__side card__side--back card__side--back-1">
	     <a href="#">
		<img src="img/zhengmian.jpg">
	     </a>
	   </div>
	</div>
     </div>
     <!--翻纸牌效果  -->
     <!--翻纸牌效果  -->
     <div class="col-1-of-3">      <div class="card">
         <div class="card__side card__side--front-1">
	    <a href="#">
	       <img src="img/fanmian.jpg">
	    </a>
	  </div>
	  <div class="card__side card__side--back card__side--back-1">
	     <a href="#">
		<img src="img/zhengmian.jpg">
	     </a>
	   </div>
	</div>
     </div>
     <!--翻纸牌效果  -->
  <!--翻纸牌效果  -->
     <div class="col-1-of-3">      <div class="card">
         <div class="card__side card__side--front-1">
	    <a href="#">
	       <img src="img/fanmian.jpg">
	    </a>
	  </div>
	  <div class="card__side card__side--back card__side--back-1">
	     <a href="#">
		<img src="img/zhengmian.jpg">
	     </a>
	   </div>
	</div>
     </div>
     <!--翻纸牌效果  -->
</div>

//css

/* body {  -webkit-box-sizing: border-box;          box-sizing: border-box;} */
.row {
    width: 1200px;
    margin: 0 auto;
}
.card {
    -webkit-perspective: 150rem;
    perspective: 150rem;
    -moz-perspective: 150rem;
    position: relative;
    height: 366px;
}
.card__side {
    height: 366px;
    -webkit-transition: all 0.8s ease;
    transition: all 0.8s ease;
    position: absolute;
    top: 0;
    left: 0;
    width: 238px;
    -webkit-backface-visibility: hidden;
    backface-visibility: hidden;
    border-radius: 10px;
    overflow: hidden;
    -webkit-box-shadow: 0 1.5rem 4rem rgba(0, 0, 0, 0.15);
    box-shadow: 0 1.5rem 4rem rgba(0, 0, 0, 0.15);
}
.card__side--back {
    -webkit-transform: rotateY(180deg);
    transform: rotateY(180deg);
}
.card:hover .card__side--front-1 {
    -webkit-transform: rotateY(-180deg);
    transform: rotateY(-180deg);
}
.card:hover .card__side--back {
    -webkit-transform: rotateY(0);
    transform: rotateY(0);
}
.row .col-1-of-3 {
    width:238px;
    float: left;
    margin:31px;
}

效果地址:www.bootstrapmb.com/item/6120/p…

洗牌效果

//html

<div class="container">
  <div class="card card-one">1111</div>
  <div class="card card-two">222</div>
  <div class="card card-three">3333</div>
</div>

//css

@keyframes rotate-one {
    10% {
        transform: translate(200px, 0px);
        z-index: 5;
        background:#ff0000
    }
   20% {
        transform: translate(-200px, 0px);
        z-index: 3;
       background:#ff0000

    }
   30% {
        transform: translate(100px, 0px);
        z-index: 4;
       background:#ff0000
      
    }
  40% {
        transform: translate(100px, 0px);
        z-index: 3;
      background:#ff0000

    }
  50% {
        transform: translate(-100px, 0px);
        z-index: 5;
      background:#ff0000

    }
   60% {
        transform: translate(0px, 0px);
        z-index: 3;
       background:#ff0000

    }
   70% {
        transform: translate(-100px, 0px);
        z-index: 4;
       background:#ff0000

    }
  80% {
        transform: translate(0px, 0px);
        z-index: 4;
      background:#ff0000

    }
  90% {
        transform: translate(100px, 0px);
        z-index: 5;
      background:#ff0000

    }
   100% {
        transform: translate(0px, 0px);
        z-index: 3;
       background:#ff0000

    }
    
} 
@keyframes rotate-two {
    10% {
        transform: translate(0px, 0px);
        z-index: 3;
    }
   20% {
        transform: translate(0px, 0px);
        z-index: 5;
    }
  30% {
        transform: translate(-100px, 0px);
        z-index: 4;
    }
   40% {
        transform: translate(-100px, 0px);
        z-index: 5;
    }
  50% {
        transform: translate(100px, 0px);
        z-index: 3;
    }
   60% {
        transform: translate(200px, 0px);
        z-index: 5;
    }
  70% {
        transform: translate(-100px, 0px);
        z-index: 4;
    }
   80% {
        transform: translate(-100px, 0px);
        z-index: 4;
    }
  90% {
        transform: translate(-100px, 0px);
        z-index: 3;
    }
   100% {
        transform: translate(200px, 0px);
        z-index: 5;
    }
    
} 
@keyframes rotate-three {
    10% {
        transform: translate(-200px, 0px);
        z-index: 4;
    }
   20% {
        transform: translate(200px, 0px);
        z-index: 5;
    }
  30% {
        transform: translate(0px, 0px);
        z-index: 4;
    }
  40% {
        transform: translate(100px, 0px);
        z-index: 4;
    }
    50% {
        transform: translate(0px, 0px);
        z-index: 4;
    }
   60% {
        transform: translate(-200px, 0px);
        z-index: 5;
    }
  70% {
        transform: translate(0px, 0px);
        z-index: 4;
    }
  80% {
        transform: translate(100px, 0px);
        z-index: 4;
    }
  90% {
        transform: translate(0px, 0px);
        z-index: 4;
    }
   100% {
        transform: translate(-200px, 0px);
        z-index: 5;
    }
} 

body {
    background-color: #2c3e50;
}
.container {
    position: absolute;
    width: 300px;
    height: 100px;
    top: 50%;
    left: 50%;
    margin: -50px;
    display: flex;
}
.card{
  position:relative;
  display: inline-flex;
  width: 100px;
  height: 100%;
}
.card-one{
  background: #ff0000;
  animation: rotate-one 2.5s 1;
  animation-timing-function: ease-in;
}
.card-two{
  background: #00ff00;
  animation: rotate-two 2.5s 1;
  animation-timing-function: ease-in;
}
.card-three{
  background: #0000ff;
  animation: rotate-three  2.5s 1;
  animation-timing-function: ease-in;
}

四、抽奖转盘动画

html

<div class="g-wrap">
	<div class='u-cards J_cards'>
		<div class="card-box">
			<img src="./static/images/card1.png">			
		</div>
		<div class="card-box">
			<img src="./static/images/card2.png">			
		</div>
		<div class="card-box">
			<img src="./static/images/card3.png">			
		</div>
		<div class="card-box">
			<img src="./static/images/card4.png">			
		</div>
		<div class="card-box">
			<img src="./static/images/card5.png">			
		</div>
	</div>
</div>

css

html, body{
	width: 100%;
	height: 100%;
	margin: 0;
	background: linear-gradient(#22a29d, #0d6964)
}
.g-wrap{
	width: 100%;
	height: 100%;
	display: flex;
	justify-content: center;
	align-items: center;
	flex-direction: column

}
.card-box{
    display: inline-block;
    position:relative;
}
.card-box.card-normal:after {
    position: absolute;
    left: 7px;
    top: 1px;
    display: block;
    width: 193px;
    height: 263px;
    content: '';
    transition: all 0.5s ease;
    border-radius: 7px;
    box-shadow: 0 3px 10px 5px #3cdad4;
}
.card-box.card-mask:after{
    position: absolute;
    left: 7px;
    top: 1px;
    display: block;
    width: 193px;
    height: 263px;
    background-color: rgba(0, 0, 0, 0.3);
    content: '';
    transition: all 0.5s ease;
    border-radius: 7px;
}
.card-box.card-checked:after{
    position: absolute;
    left: 7px;
    top: 1px;
    display: block;
    width: 193px;
    height: 263px;
    content: '';
    transition: all 0.5s ease;
    border-radius: 7px;
    box-shadow: 0 0 8px 8px #f9f5e9;
}

.gf-ft {
    margin-top: 20px;
    text-align: center;
}

.gf-btn {
    display: inline-block;
    background: linear-gradient(to top, #d46a33, #ce4f1f);
    line-height: 64px;
    border-radius: 32px;
    font-size: 26px;
    letter-spacing: 3px;
    color: #f9dc9f;
    padding: 0px 70px;
    box-shadow: 0 5px 20px #f9dc9f;
}

js

$(function(){
       // 当前位置(每执行一次,会加1,也可理解当前执行次数
	var lotteryNum = 0;
    var startTimeout = 100;// 初始定时器时长
		scrollTimeout = null;
	var _circleTimes = 3,// 需要转几轮
		_breakTime = 10,// 每次增加的时长
		_allNum = 5;// 总共有几个奖品
	function lottery(id, callback){
              // id 为后端传回来的用户抽到的奖品,_stepNum 为动画总共执行多少次。		var _stepNum = _allNum * _circleTimes + id;
		
		$('.J_cards .card-box').removeClass('card-normal').removeClass('card-checked').addClass('card-mask');
		$('.card-box' + (lotteryNum % _allNum)).removeClass('card-mask').addClass('card-checked');
		scrollTimeout = setTimeout(function(){
			lottery(id, callback);
		}, startTimeout+_breakTime);
		lotteryNum++;
		startTimeout+=_breakTime;
               //停止动画
		if(lotteryNum >=_stepNum){
			clearTimeout(scrollTimeout);
			lotteryNum = 0;
			startTimeout = 100;
			if(callback){
				callback();
			}
		}
	}
	
	$('.J_getGf').on('click', getGift);
	function getGift(){
		//    ģ��齱
		var giftId = Math.floor(Math.random() * 5);
		lottery(giftId, function(){});
	}
})

效果连接:lujinming1.github.io/lottery/