html5最重要的更新之一:增加了canvas,开始支持矢量绘画,目前浏览器支持比较好的是canvas的2d接口,3d有点遥远,通过canvas,我们可以在web设计中实现很炫的效果,从理论上来讲,大部分的flash动画特效都有办法使用canvas实现,当然实现的成本还是过高了。今天明河向各位讲解个canvas相关的实战教程:jquery+canvas实现html5幻灯片。 关于html5的canvas有个非常经典的教程,你不得不看:来自opera中国的《HTML 5 canvas —— 基本语法》。 canvas内容太丰富了,想要通过一篇文章都讲解到,难免流于浅谈则止,所以这篇教程只让大家了解canvas的drawImage接口。 也许你会疑惑,html早就有插入图片的标签了,在canvas中插入图像有意义吗?明河的回答是:有!canvas的图像是可以实现像素级的操作!
1.原理简述
这篇教程的难点在于切换图片时先提高图片的对比度,然后再予以渐隐(由于使用canvas,请勿在IE下查看demo)。提高图片的对比度用的是photoshop的对比度算法,当然这个算法的细节大家无需纠结,明河只是希望通过这篇教程大家能够大致了解canvas的图像处理方面的技巧。 排除这个对比度处理,其他的jquery代码其实难度不高,明河特意加了翔实的中文注释,只要你有耐心,我相信你一定看的懂。
2.开始构建个用于幻灯片的图片列表
-
<!-- 幻灯片 START -->
-
<div id="slideshow">
-
<ul class="slides">
-
<li><img src="img/photos/1.jpg" width="620" height="320" alt="照片1" /></li>
-
<li><img src="img/photos/2.jpg" width="620" height="320" alt="照片2" /></li>
-
<li><img src="img/photos/3.jpg" width="620" height="320" alt="照片3" /></li>
-
<li><img src="img/photos/4.jpg" width="620" height="320" alt="照片4" /></li>
-
</ul>
-
<span class="arrow previous"></span>
-
<span class="arrow next"></span>
-
</div>
-
<!-- 幻灯片 END -->
非常简单的结构,除了图片列表外,当然还免不了上一张、下一张的箭头。样式不是本文的重点,这里略过。
3.在页面加载结束后加载初始化幻灯片
-
$(window).load(function(){})
这里可能朋友们有疑惑:为啥不用$(function(){}),不是更简单? 之所以使用$(window).load()而不使用更简洁的$(),是因为我们需要确保图片全部加载完成,而不是DOM加载完成,还有个原因canvas还是很耗资源的。
4.判断浏览器是否支持canvas
-
//测试浏览器是否支持canvas
-
var supportCanvas = 'getContext' in document.createElement('canvas');
这一步很重要哦,当用户的浏览器不支持canvas,我们需要另外一种降级处理。
5.遍历每张图片
-
//遍历每张图片
-
$('#slideshow img').each(function(){
-
//第一张图片时先设置下幻灯片的宽高(将图片的宽高缓存起来,供其他代码调用)
-
if(!slideshow.width){
-
slideshow.width = this.width;
-
slideshow.height = this.height;
-
}
-
//在图片之前产生canvas
-
createCanvasOverlay(this);
-
});
这里有二步操作:
-
将图片尺寸写入缓存变量slideshow,供日后调用
-
执行createCanvasOverlay()函数,插入canvas
6.创造canvas对像
-
/**
-
* 创造canvas对像
-
* @param {Object} image 图片
-
*/
-
function createCanvasOverlay(image){
-
//创建canvas元素
-
var canvas = document.createElement('canvas'),
-
//获取2d canvas上下文(如果不支持canvas,这个对象是不存在的)
-
canvasContext = canvas.getContext("2d");
-
-
// 设置canvas的宽度和高度
-
canvas.width = slideshow.width;
-
canvas.height = slideshow.height;
-
//在canvas内绘制一张图片
-
canvasContext.drawImage(image,0,0);
-
//获取canvas图片像素数据,这非常重要
-
var imageData = canvasContext.getImageData(0,0,canvas.width,canvas.height),
-
data = imageData.data;
-
-
// Loop through all the pixels in the imageData array, and modify
-
// the red, green, and blue color values.
-
//遍历所有的像素并修改红色、绿色、蓝色通道的值,这是整个教程中最难的部分,如果没理解没关系,但希望通过这一个操作,让各位直观的感受canvas像素级操作的强大
-
for(var i = 0,z=data.length;i<z;i++){
-
data[i] = ((data[i] < 128) ? (2*data[i]*data[i] / 255) : (255 - 2 * (255 - data[i]) * (255 - data[i]) / 255));
-
data[++i] = ((data[i] < 128) ? (2*data[i]*data[i] / 255) : (255 - 2 * (255 - data[i]) * (255 - data[i]) /255));
-
data[++i] = ((data[i] < 128) ? (2*data[i]*data[i] / 255) : (255 - 2 * (255 - data[i]) * (255 - data[i]) /255));
-
//为了更好的说明,这里明河加入颜色反转效果,可以把上面的代码去掉,换成下面的试下
-
/*data[i] = 255 - data[i];
-
data[++i] = 255 - data[++i];
-
data[++i] = 255 - data[++i];*/
-
++i;
-
}
-
-
//重新应用下像素数据,后面二个参数是x\y坐标值
-
canvasContext.putImageData(imageData,0,0);
-
//将canvas插入到图片前面
-
image.parentNode.insertBefore(canvas,image);
-
}
这是教程代码的关键部分。我们一步一步来看。
1)创建个canvas元素
-
//创建canvas元素
-
var canvas = document.createElement('canvas'),
-
//获取2d canvas上下文(如果不支持canvas,这个对象是不存在的)
-
canvasContext = canvas.getContext("2d");
-
-
// 设置canvas的宽度和高度
-
canvas.width = slideshow.width;
-
canvas.height = slideshow.height;
设置canvas的尺寸等于图片尺寸,正好遮住图片,当切换图片时,先出现canvas(canvas的图片是修改过的高对比度的图片)。最后我们输出的节点如下: 想要使用canvas的API,请先获取2d canvas上下文,这非常重要,所有基于canvas的操作都基于getContext(“2d”)。
2)向canvas内插入图片
-
//在canvas内绘制一张图片
-
canvasContext.drawImage(image,0,0);
严重推荐阅读:http://kb.operachina.com/node/190#insertingimages。 drawImage方法允许在 canvas 中插入图像,共有九个参数(恐怖吧…常用的是前面三个):
-
图片对象
-
x轴坐标
-
y轴坐标
-
图像宽度
-
图像高度
之前说过,在canvas中插入图像的优势,在于可以实现像素级的操作,比如这里我们要加强图像的对比度。
3)获取canvas图片像素数据
-
//获取canvas图片像素数据,这非常重要
-
var imageData = canvasContext.getImageData(0,0,canvas.width,canvas.height),
-
data = imageData.data;
getImageData方法,将获取canvas图片像素数据,此对象有个data数组,用于存放像素数据。getImageData共有四个参数:x坐标、y坐标、宽度、高度。
4)强化图像对比度
这段代码有点复杂,特别是对比度强化处理
-
//遍历所有的像素并修改红色、绿色、蓝色通道的值,这是整个教程中最难的部分,如果没理解没关系,但希望通过这一个操作,让各位直观的感受canvas像素级操作的强大
-
for(var i = 0,z=data.length;i<z;i++){
-
data[i] = ((data[i] < 128) ? (2*data[i]*data[i] / 255) : (255 - 2 * (255 - data[i]) * (255 - data[i]) / 255));
-
data[++i] = ((data[i] < 128) ? (2*data[i]*data[i] / 255) : (255 - 2 * (255 - data[i]) * (255 - data[i]) /255));
-
data[++i] = ((data[i] < 128) ? (2*data[i]*data[i] / 255) : (255 - 2 * (255 - data[i]) * (255 - data[i]) /255));
-
++i;
-
}
来着photoshop强化对比度的算法,如果这个算法没弄明白,没关系,只要记得有这样的用法即可。简单说明下原理:强化对比度,实际是处理红(data[i])、绿(data[i+1])、蓝(data[i+2])三个通道数据,大部分对图像像素数据,更准确的将应该是矩阵的处理,实际上都是对三个通道的处理。 说真的,这个算法内部细节的含义,明河也不清楚,欢迎讨论。
5)重新输出图像像素
-
//重新应用下像素数据,后面二个参数是x\y坐标值
-
canvasContext.putImageData(imageData,0,0);
6)将canvas插入到DOM中
-
//将canvas插入到图片前面
-
image.parentNode.insertBefore(canvas,image);
7.监听箭头切换幻灯片事件
-
$('#slideshow .arrow').click(function(){
-
var li = slides.eq(current),
-
canvas = li.find('canvas'),
-
nextIndex = 0;
-
-
//下一张
-
if($(this).hasClass('next')){
-
nextIndex = current >= slides.length-1 ? 0 : current+1;
-
}
-
//上一张
-
else {
-
nextIndex = current <= 0 ? slides.length-1 : current-1;
-
}
-
-
var next = slides.eq(nextIndex);
-
//支持canvas的情况
-
if(supportCanvas){
-
//渐现canvas
-
canvas.fadeIn(function(){
-
//显示下个容器
-
next.show();
-
current = nextIndex;
-
//隐藏当前图片容器,并移除激活样式,给新出现的图片容器加上激活样式
-
li.fadeOut(function(){
-
li.removeClass('slideActive');
-
canvas.hide();
-
next.addClass('slideActive');
-
});
-
});
-
}
-
else {
-
//如果浏览器不支持canvas只做简单的显隐处理
-
current=nextIndex;
-
next.addClass('slideActive').show();
-
li.removeClass('slideActive').hide();
-
}
-
});
这代码相当简单多了。这里有个推荐学习的技巧,将next和prev方法合并,其实不管是next还是prev方法执行的动作都是类似的,我们根据按钮是否带有“next”样式来判断是上一张还是下一张。
-
//下一张
-
if($(this).hasClass('next')){
-
nextIndex = current >= slides.length-1 ? 0 : current+1;
-
}
-
//上一张
-
else {
-
nextIndex = current <= 0 ? slides.length-1 : current-1;
-
}
8.轮播幻灯片
轮播幻灯片,实际上是定时触发next(下一张箭头)的click事件。
-
var timeOut = null;
-
-
$('#slideshow .arrow').click(function(e,simulated){
-
//点击箭头,清除定时器
-
if(!simulated){
-
clearTimeout(timeOut);
-
}
-
});
-
-
(function autoAdvance(){
-
//触发箭头点击事件,当第二个参数为false时,清理定时器
-
$('#slideshow .next').trigger('click',[true]);
-
//5秒定时轮放
-
timeOut = setTimeout(autoAdvance,5000);
-
})();
代码请看autoadvance.js。这里有个很有意思的jquery技巧,触发事件,并给事件传递自定义参数。
-
$('#slideshow .arrow').click(function(e,simulated){
-
-
});
-
$('#slideshow .next').trigger('click',[true]);
trigger接受第二个参数,并且是数组类型,分别对应事件方法的第二至N个参数,比如这里的true对应simulated,事件内部根据simulated值做相应的处理。html5最重要的更新之一:增加了canvas,开始支持矢量绘画,目前浏览器支持比较好的是canvas的2d接口,3d有点遥远,通过canvas,我们可以在web设计中实现很炫的效果,从理论上来讲,大部分的flash动画特效都有办法使用canvas实现,当然实现的成本还是过高了。今天明河向各位讲解个canvas相关的实战教程:jquery+canvas实现html5幻灯片。
关于html5的canvas有个非常经典的教程,你不得不看:来自opera中国的《HTML 5 canvas —— 基本语法》。 canvas内容太丰富了,想要通过一篇文章都讲解到,难免流于浅谈则止,所以这篇教程只让大家了解canvas的drawImage接口。 也许你会疑惑,html早就有插入图片的标签了,在canvas中插入图像有意义吗?明河的回答是:有!canvas的图像是可以实现像素级的操作!
1.原理简述
这篇教程的难点在于切换图片时先提高图片的对比度,然后再予以渐隐(由于使用canvas,请勿在IE下查看demo)。提高图片的对比度用的是photoshop的对比度算法,当然这个算法的细节大家无需纠结,明河只是希望通过这篇教程大家能够大致了解canvas的图像处理方面的技巧。 排除这个对比度处理,其他的jquery代码其实难度不高,明河特意加了翔实的中文注释,只要你有耐心,我相信你一定看的懂。
2.开始构建个用于幻灯片的图片列表
-
<!-- 幻灯片 START -->
-
<div id="slideshow">
-
<ul class="slides">
-
<li><img src="img/photos/1.jpg" width="620" height="320" alt="照片1" /></li>
-
<li><img src="img/photos/2.jpg" width="620" height="320" alt="照片2" /></li>
-
<li><img src="img/photos/3.jpg" width="620" height="320" alt="照片3" /></li>
-
<li><img src="img/photos/4.jpg" width="620" height="320" alt="照片4" /></li>
-
</ul>
-
<span class="arrow previous"></span>
-
<span class="arrow next"></span>
-
</div>
-
<!-- 幻灯片 END -->
非常简单的结构,除了图片列表外,当然还免不了上一张、下一张的箭头。样式不是本文的重点,这里略过。
3.在页面加载结束后加载初始化幻灯片
-
$(window).load(function(){})
这里可能朋友们有疑惑:为啥不用$(function(){}),不是更简单? 之所以使用$(window).load()而不使用更简洁的$(),是因为我们需要确保图片全部加载完成,而不是DOM加载完成,还有个原因canvas还是很耗资源的。
4.判断浏览器是否支持canvas
-
//测试浏览器是否支持canvas
-
var supportCanvas = 'getContext' in document.createElement('canvas');
这一步很重要哦,当用户的浏览器不支持canvas,我们需要另外一种降级处理。
5.遍历每张图片
-
//遍历每张图片
-
$('#slideshow img').each(function(){
-
//第一张图片时先设置下幻灯片的宽高(将图片的宽高缓存起来,供其他代码调用)
-
if(!slideshow.width){
-
slideshow.width = this.width;
-
slideshow.height = this.height;
-
}
-
//在图片之前产生canvas
-
createCanvasOverlay(this);
-
});
这里有二步操作:
-
将图片尺寸写入缓存变量slideshow,供日后调用
-
执行createCanvasOverlay()函数,插入canvas
6.创造canvas对像
-
/**
-
* 创造canvas对像
-
* @param {Object} image 图片
-
*/
-
function createCanvasOverlay(image){
-
//创建canvas元素
-
var canvas = document.createElement('canvas'),
-
//获取2d canvas上下文(如果不支持canvas,这个对象是不存在的)
-
canvasContext = canvas.getContext("2d");
-
-
// 设置canvas的宽度和高度
-
canvas.width = slideshow.width;
-
canvas.height = slideshow.height;
-
//在canvas内绘制一张图片
-
canvasContext.drawImage(image,0,0);
-
//获取canvas图片像素数据,这非常重要
-
var imageData = canvasContext.getImageData(0,0,canvas.width,canvas.height),
-
data = imageData.data;
-
-
// Loop through all the pixels in the imageData array, and modify
-
// the red, green, and blue color values.
-
//遍历所有的像素并修改红色、绿色、蓝色通道的值,这是整个教程中最难的部分,如果没理解没关系,但希望通过这一个操作,让各位直观的感受canvas像素级操作的强大
-
for(var i = 0,z=data.length;i<z;i++){
-
data[i] = ((data[i] < 128) ? (2*data[i]*data[i] / 255) : (255 - 2 * (255 - data[i]) * (255 - data[i]) / 255));
-
data[++i] = ((data[i] < 128) ? (2*data[i]*data[i] / 255) : (255 - 2 * (255 - data[i]) * (255 - data[i]) /255));
-
data[++i] = ((data[i] < 128) ? (2*data[i]*data[i] / 255) : (255 - 2 * (255 - data[i]) * (255 - data[i]) /255));
-
//为了更好的说明,这里明河加入颜色反转效果,可以把上面的代码去掉,换成下面的试下
-
/*data[i] = 255 - data[i];
-
data[++i] = 255 - data[++i];
-
data[++i] = 255 - data[++i];*/
-
++i;
-
}
-
-
//重新应用下像素数据,后面二个参数是x\y坐标值
-
canvasContext.putImageData(imageData,0,0);
-
//将canvas插入到图片前面
-
image.parentNode.insertBefore(canvas,image);
-
}
这是教程代码的关键部分。我们一步一步来看。
1)创建个canvas元素
-
//创建canvas元素
-
var canvas = document.createElement('canvas'),
-
//获取2d canvas上下文(如果不支持canvas,这个对象是不存在的)
-
canvasContext = canvas.getContext("2d");
-
-
// 设置canvas的宽度和高度
-
canvas.width = slideshow.width;
-
canvas.height = slideshow.height;
设置canvas的尺寸等于图片尺寸,正好遮住图片,当切换图片时,先出现canvas(canvas的图片是修改过的高对比度的图片)。最后我们输出的节点如下: 想要使用canvas的API,请先获取2d canvas上下文,这非常重要,所有基于canvas的操作都基于getContext(“2d”)。
2)向canvas内插入图片
-
//在canvas内绘制一张图片
-
canvasContext.drawImage(image,0,0);
严重推荐阅读:http://kb.operachina.com/node/190#insertingimages。 drawImage方法允许在 canvas 中插入图像,共有九个参数(恐怖吧…常用的是前面三个):
-
图片对象
-
x轴坐标
-
y轴坐标
-
图像宽度
-
图像高度
之前说过,在canvas中插入图像的优势,在于可以实现像素级的操作,比如这里我们要加强图像的对比度。
3)获取canvas图片像素数据
-
//获取canvas图片像素数据,这非常重要
-
var imageData = canvasContext.getImageData(0,0,canvas.width,canvas.height),
-
data = imageData.data;
getImageData方法,将获取canvas图片像素数据,此对象有个data数组,用于存放像素数据。getImageData共有四个参数:x坐标、y坐标、宽度、高度。
4)强化图像对比度
这段代码有点复杂,特别是对比度强化处理
-
//遍历所有的像素并修改红色、绿色、蓝色通道的值,这是整个教程中最难的部分,如果没理解没关系,但希望通过这一个操作,让各位直观的感受canvas像素级操作的强大
-
for(var i = 0,z=data.length;i<z;i++){
-
data[i] = ((data[i] < 128) ? (2*data[i]*data[i] / 255) : (255 - 2 * (255 - data[i]) * (255 - data[i]) / 255));
-
data[++i] = ((data[i] < 128) ? (2*data[i]*data[i] / 255) : (255 - 2 * (255 - data[i]) * (255 - data[i]) /255));
-
data[++i] = ((data[i] < 128) ? (2*data[i]*data[i] / 255) : (255 - 2 * (255 - data[i]) * (255 - data[i]) /255));
-
++i;
-
}
来着photoshop强化对比度的算法,如果这个算法没弄明白,没关系,只要记得有这样的用法即可。简单说明下原理:强化对比度,实际是处理红(data[i])、绿(data[i+1])、蓝(data[i+2])三个通道数据,大部分对图像像素数据,更准确的将应该是矩阵的处理,实际上都是对三个通道的处理。 说真的,这个算法内部细节的含义,明河也不清楚,欢迎讨论。
5)重新输出图像像素
-
//重新应用下像素数据,后面二个参数是x\y坐标值
-
canvasContext.putImageData(imageData,0,0);
6)将canvas插入到DOM中
-
//将canvas插入到图片前面
-
image.parentNode.insertBefore(canvas,image);
7.监听箭头切换幻灯片事件
-
$('#slideshow .arrow').click(function(){
-
var li = slides.eq(current),
-
canvas = li.find('canvas'),
-
nextIndex = 0;
-
-
//下一张
-
if($(this).hasClass('next')){
-
nextIndex = current >= slides.length-1 ? 0 : current+1;
-
}
-
//上一张
-
else {
-
nextIndex = current <= 0 ? slides.length-1 : current-1;
-
}
-
-
var next = slides.eq(nextIndex);
-
//支持canvas的情况
-
if(supportCanvas){
-
//渐现canvas
-
canvas.fadeIn(function(){
-
//显示下个容器
-
next.show();
-
current = nextIndex;
-
//隐藏当前图片容器,并移除激活样式,给新出现的图片容器加上激活样式
-
li.fadeOut(function(){
-
li.removeClass('slideActive');
-
canvas.hide();
-
next.addClass('slideActive');
-
});
-
});
-
}
-
else {
-
//如果浏览器不支持canvas只做简单的显隐处理
-
current=nextIndex;
-
next.addClass('slideActive').show();
-
li.removeClass('slideActive').hide();
-
}
-
});
这代码相当简单多了。这里有个推荐学习的技巧,将next和prev方法合并,其实不管是next还是prev方法执行的动作都是类似的,我们根据按钮是否带有“next”样式来判断是上一张还是下一张。
-
//下一张
-
if($(this).hasClass('next')){
-
nextIndex = current >= slides.length-1 ? 0 : current+1;
-
}
-
//上一张
-
else {
-
nextIndex = current <= 0 ? slides.length-1 : current-1;
-
}
8.轮播幻灯片
轮播幻灯片,实际上是定时触发next(下一张箭头)的click事件。
-
var timeOut = null;
-
-
$('#slideshow .arrow').click(function(e,simulated){
-
//点击箭头,清除定时器
-
if(!simulated){
-
clearTimeout(timeOut);
-
}
-
});
-
-
(function autoAdvance(){
-
//触发箭头点击事件,当第二个参数为false时,清理定时器
-
$('#slideshow .next').trigger('click',[true]);
-
//5秒定时轮放
-
timeOut = setTimeout(autoAdvance,5000);
-
})();
代码请看autoadvance.js。这里有个很有意思的jquery技巧,触发事件,并给事件传递自定义参数。
-
$('#slideshow .arrow').click(function(e,simulated){
-
-
});
-
$('#slideshow .next').trigger('click',[true]);
trigger接受第二个参数,并且是数组类型,分别对应事件方法的第二至N个参数,比如这里的true对应simulated,事件内部根据simulated值做相应的处理。