最近看到一个挺有趣的H5,主要效果就是通过不断的放缩来展示画中画,网上找了一下并没有这方面的实现代码,故决定原创一下,并分享出来

主要的思路就是通过canvas不断的写入图片,考虑到每一层的图片的位置和大小不一样,于是通过最外层的图片来尺寸和位置来控制里面的图片,然后通过循环写入canvas的方式实现最终的效果。

需要注意的是使用canvas写入图片需要预加载图片,通过回调函数来写入,同时,由于图片加载需要一定的时候,所以一般的H5会有一个加载的过程,我也加上了一个回调函数来处理加载图片以后其他的操作,比如隐藏加载页面等操作。

此项目已经放到码云上了,传送门,第一次分享项目,共勉之。

主要代码如下:
let $ = require('jquery');
let tools = require('./utils.js');
$.fn.longPress = function() {
let timeout = undefined;
let start;
let beginHandel, endHandel;
let length = arguments.length;
beginHandel = arguments[0];
if (length = 2) {
endHandel = arguments[1];
}
$(this).on('touchstart', function(e) {
e.preventDefault();
timeout = setTimeout(beginHandel, 500);
});
$(this).on('touchend', function(e) {
e.preventDefault();
tools.execCB(endHandel);
clearTimeout(timeout);
});
};
let TWEEN = require('@tweenjs/tween.js');
(function(global, factory) {
if (typeof define === 'function' && define.amd) {
define(function() {
return factory(global, global.document);
})
} else if (typeof module !== 'undefined' && module.exports) {
module.exports = factory(global, global.document);
} else {
global.Pip = factory(global, global.document);
}
}(typeof window !== 'undefined' ? window : this, function(window, document) { 'use strict'
//常量
const CW = $(window).width();
const CH = $(window).height();
let container = $('#pip'); let Pip = function(options) {
let _this = this;
this.defaultOps = {
model: 'bts',
duration: 1000,
}
if (typeof options == 'object') {
Object.keys(options).map(function(key) {
_this.defaultOps[key] = options[key];
})
}
//创建canvas
let canvas = document.createElement('canvas');
let length = _this.defaultOps.content.length;
canvas.width = CW;
canvas.height = CH;
_this.defaultOps.context = canvas.getContext('2d');
container.append(canvas); };
Pip.prototype.start = function(cb) {
let opts = this.defaultOps;
let ctx = opts.context;
let content = opts.content;
let length = content.length;
let model = opts.model;
let beginStatus = {};
let endStatus = {};
let i = 0; if (ctx) {
// 加载所有的图片
loadimages(content, function(images) {
//去掉加载提示页面
tools.execCB(cb) // 总时间
let duration = opts.duration;
let timestamp1 = 0
let timestamp2 = 0 // 补间动画
let tween = null
// 初始化状态
if (model == 'stb') {
i = length - 2;
let width = CW;
let height = CH;
let left = 0;
let top = 0; for (let k = i + 1; k >= 0; k--) {
if (k !== i + 1) {
left = left + width * content[length - 1 - k].left;
top = top + height * content[length - 1 - k].top;
width = width * content[length - 1 - k].width;
height = height * content[length - 1 - k].height;
}
let image = images[length - 1 - k];
ctx.drawImage(image, left, top, width, height);
}
//定义开始和结束状态
endStatus = {
width: CW / content[length - 1 - i].width,
height: CH / content[length - 1 - i].height,
left: -CW / content[length - 1 - i].width * content[length - 1 - i].left,
top: -CH / content[length - 1 - i].height * content[length - 1 - i].top
}
beginStatus = {
width: CW,
height: CH,
left: 0,
top: 0
}
} else {
ctx.drawImage(images[length - 1 - i], 0, 0, container.width(), container.height());
//定义开始和结束状态
beginStatus = {
width: CW / content[length - 1 - i].width,
height: CH / content[length - 1 - i].height,
left: -CW / content[length - 1 - i].width * content[length - 1 - i].left,
top: -CH / content[length - 1 - i].height * content[length - 1 - i].top
}
endStatus = {
width: CW,
height: CH,
left: 0,
top: 0
} } function go() {
tween = new TWEEN.Tween(beginStatus)
.to(endStatus, duration)
.onUpdate(function() {
let _this = this;
ctx.clearRect(0, 0, container.width(), container.height());
let width = _this.width;
let height = _this.height;
let left = _this.left;
let top = _this.top; for (let k = i + 1; k >= 0; k--) {
if (k !== i + 1) {
left = left + width * content[length - 1 - k].left;
top = top + height * content[length - 1 - k].top;
width = width * content[length - 1 - k].width;
height = height * content[length - 1 - k].height;
}
let image = images[length - 1 - k];
ctx.drawImage(image, left, top, width, height)
}
})
.onComplete(function() {
if (model == 'bts') {
i++;
} else {
i--;
}
if (i > length - 2 || i < 0) {
if (model == 'bts') {
i--;
model = 'stb';
endStatus = {
width: CW / content[length - 1 - i].width,
height: CH / content[length - 1 - i].height,
left: -CW / content[length - 1 - i].width * content[length - 1 - i].left,
top: -CH / content[length - 1 - i].height * content[length - 1 - i].top
};
beginStatus = {
width: CW,
height: CH,
left: 0,
top: 0
};
} else {
i++;
model = 'bts';
beginStatus = {
width: CW / content[length - 1 - i].width,
height: CH / content[length - 1 - i].height,
left: -CW / content[length - 1 - i].width * content[length - 1 - i].left,
top: -CH / content[length - 1 - i].height * content[length - 1 - i].top
};
endStatus = {
width: CW,
height: CH,
left: 0,
top: 0
};
}
return;
}
//定义开始和结束状态
if (model == 'bts') {
beginStatus = {
width: CW / content[length - 1 - i].width,
height: CH / content[length - 1 - i].height,
left: -CW / content[length - 1 - i].width * content[length - 1 - i].left,
top: -CH / content[length - 1 - i].height * content[length - 1 - i].top
};
endStatus = {
width: CW,
height: CH,
left: 0,
top: 0
};
} else {
endStatus = {
width: CW / content[length - 1 - i].width,
height: CH / content[length - 1 - i].height,
left: -CW / content[length - 1 - i].width * content[length - 1 - i].left,
top: -CH / content[length - 1 - i].height * content[length - 1 - i].top
};
beginStatus = {
width: CW,
height: CH,
left: 0,
top: 0
}; } duration = opts.duration;
go();
})
.onStop(function() {
timestamp2 = new Date().getTime()
duration = duration - (timestamp2 - timestamp1)
if (duration < 0) {
duration = 0
}
})
.onStart(function() {
timestamp1 = new Date().getTime()
})
.start() requestAnimationFrame(animate) function animate() {
TWEEN.update()
requestAnimationFrame(animate)
}
} container.longPress(function() {
go()
}, function() {
if (tween) {
tween.stop()
}
})
})
} else {
console.log("context is not defined")
return
} function loadimages(content, cb) {
let images = [];
let num = 0;
let length = content.length;
for (let c in content) {
images[c] = new Image();
images[c].onload = function() {
if (num === length) {
num = 0;
tools.execCB(cb, images)
}
}
images[c].src = content[length - 1 - num].src;
num++;
}
}
};
return Pip
}));
用法如下:
var pip = new Pip({
content: [{
src: require('../src/images/2.jpg'),
top: 0,
left: 0,
width: 1,
height: 1
}, {
src: require('../src/images/3.png'),
top: .1,
left: .05,
width: .08,
height: .08
}, {
src: require('../src/images/4.jpg'),
top: .4,
left: .6,
width: .08,
height: .08
}, {
src: require('../src/images/5.jpg'),
top: .4,
left: .6,
width: .08,
height: .08
}, {
src: require('../src/images/6.jpg'),
top: .9,
left: .4,
width: .08,
height: .08
}, {
src: require('../src/images/7.jpg'),
top: .1,
left: .05,
width: .08,
height: .08
}, {
src: require('../src/images/8.jpg'),
top: .4,
left: .6,
width: .08,
height: .08
}, {
src: require('../src/images/9.jpg'),
top: .1,
left: .05,
width: .08,
height: .08
}, {
src: require('../src/images/4.jpg'),
top: .4,
left: .6,
width: .08,
height: .08
}, {
src: require('../src/images/5.jpg'),
top: .4,
left: .6,
width: .08,
height: .08
}, {
src: require('../src/images/6.jpg'),
top: .9,
left: .4,
width: .08,
height: .08
}],
model: 'stb',
});
pip.start(function() {
//此处加载完图片以后隐藏遮罩
$('.mask').hide();
});

使用canvas实现画中画效果的H5的更多相关文章

  1. 使用Canvas实现动画效果 | DKlogs -- 设计 | 生活

    使用Canvas实现动画效果 | DKlogs -- 设计 | 生活 使用Canvas实现动画效果

  2. canvas实现倒计时效果示例(vue组件内编写)

    前言: 此事例是在vue组件中,使用canvas实现倒计时动画的效果.其实,实现效果的逻辑跟vue没有关系,只要读懂canvas如何实现效果的这部分逻辑就可以了 canvas动画的原理:利用定时器,给 ...

  3. 原生js实现canvas气泡冒泡效果

    说明: 本文章主要分为ES5和ES6两个版本 ES5版本是早期版本,后面用ES6重写优化的,建议使用ES6版本. 1, 原生js实现canvas气泡冒泡效果的插件,api丰富,使用简单2, 只需引入J ...

  4. canvas/CSS仪表盘效果

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  5. 基于canvas与原生JS的H5动画引擎

    前一段时间项目组里有一些H5动画的需求,由于没有专业的前端人员,便交由我这个做后台的研究相关的H5动画技术. 通过初步调研,H5动画的实现大概有以下几种方式: 1.基于css实现 这种方式比较简单易学 ...

  6. canvas弹动效果

    弹动效果,用物体与目标的距离乘上系数再累加至速度上,让物体呈加速度运动,再让速度乘与摩擦力系数,让物体最终停止运动 代码如下所示 var canvas = document.getElementByI ...

  7. 用Canvas制作剪纸效果

    在做剪纸效果之前,先介绍剪纸效果运用到的一些知识: 1.阴影: 在Canvas之中进行绘制时,可以通过修改绘图环境中的如下4个属性值来指定阴影效果: shadowColor:CSS格式的颜色字串.默认 ...

  8. HTML5之Canvas时钟(网页效果--每日一更)

    今天,带来的是使用HTML5中Canvas标签实现的动态时钟效果. 话不多说,先看效果:亲,请点击这里 众所周知,Canvas标签是HTML5中的灵魂,HTML5 Canvas是屏幕上的一个由Java ...

  9. 【HTML5】Canvas 实现放大镜效果

    图片放大镜 效果 在线演示    源码 原理 首先选择图片的一块区域,然后将这块区域放大,然后再绘制到原先的图片上,保证两块区域的中心点一致, 如下图所示: 初始化 <canvas id=&qu ...

随机推荐

  1. 02- 画文字和图片-------------之前写的那个微博项目,可以试试用画图片的方式来处理,这样应该比UILabel 代码少点,一会试试

    1.画图片 - (void)drawRect:(CGRect)rect { // Drawing code UIImage *image = [UIImage imageNamed:@"pa ...

  2. 大话CNN

    这几年深度学习快速发展,在图像识别.语音识别.物体识别等各种场景上取得了巨大的成功,例如AlphaGo击败世界围棋冠军,iPhone X内置了人脸识别解锁功能等等,很多AI产品在世界上引起了很大的轰动 ...

  3. 规范抢先看!微信小程序的官方设计指南和建议

    基于微信小程序轻快的特点,我们(微信官方)拟定了小程序界面设计指南和建议. 设计指南建立在充分尊重用户知情权与操作权的基础之上.旨在微信生态体系内,建立友好.高效.一致的用户体验,同时最大程度适应和支 ...

  4. SqlServer——系统函数

    1) CASE CASE有两种使用形式:一种是简单的CASE函数,另一种是搜索型的CASE函数. [1]简单的 CASE 函数 Format: CASE input_expression WHEN w ...

  5. LoadRunner11学习记录七 -- 负载生成器、事务&集合点顺序、HTML&URL录制

    1.什么情况下用到负载生成器? 当需要使用多台测试机对同一服务器同时压力测试时,需要配置负载生成器. 2.LoadRunner中事务和集合点的放置顺序问题 1)事务放在集合点前面 这时事务的时间包含了 ...

  6. LoadRunner11学习记录六 -- 服务器分析

    LoadRunner运行时,怎么利用服务器的一些参数进行分析: 1.内存分析方法 内存分析方法主要是用于判断系统有无遇到内存瓶颈,是否需要通过增加内存等手段提高系统性能表现.主要计数器包括Memory ...

  7. yii2项目实战-访问控制过滤器ACF讲解

    作者:白狼 出处:http://www.manks.top/document/yii2-filter-control.html 本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明 ...

  8. C# 进程Process基本的操作说明

    public int CallPhoneExe(string arg) //arg为进程的命令行参数 { WaitHandle[] waits =new WaitHandle[2]; //定义两个Wa ...

  9. Spring框架总结(六)

    注解 注解方式可以简化spring的IOC容器的配置! 使用注解步骤: 1)先引入context名称空间 xmlns:context="http://www.springframework. ...

  10. Linux查询系统信息命令

    Linux查看系统信息是比较基础的知识,所以这个应该都需要掌握,命令和解释如下: #uname -a           查看操作系统.内核.CPU信息 #head -n 1 /etc/issue   ...