引言:手風琴特效是比較常見的,我之前沒有見過用canvas寫的,就自己上手寫了一個,拿出來分享一下,這其中處理圖片的切換花了我不少時間,
效果如下

實作思路
1.排放好圖片,最前面的那張圖片顯示全部,其他圖片放到兩側只顯示20像素的邊,剩余部分依次擺放放到畫布外,
2.繪制幾個相對應的方形,每個方形大小跟對應的圖片顯示在畫布中的大小一樣,這些方形用來控制滑鼠的移入事件,
3.滑鼠移入以后,切換圖片,執行手風琴特效,
繪制圖片
分二次處理是為了讓展示的圖片處于陣列的后面,不會被遮蓋,
//繪制選項圖片
Accordion.prototype.drawImage=function(){
var image,img,rect,x=0,sx=0,sy=0,sWidth=600,sHeight=360,dx=0,dy=0,dWidth=600,dHeight=360,w=this.dis,width=0,color;
var curr=this.currImgIndex,imageWidth = this.imageWidth;
var n = curr-1;
//分二次處理是為了讓展示的圖片處于陣列的后面,不會被遮蓋
for(var i=curr;i>=1;i--){
if(i==curr){
dx = n*w;
}else{
dx = (i-1)*w-imageWidth+w;
}
image = this.imgObj[i];
img = new _.ImageDraw({image:image,sx:sx,sy:sy,sWidth:sWidth,sHeight:sHeight, dx:dx, dy:dy ,dWidth:dWidth,dHeight:dHeight});
img.id=i;
this.renderArr.push(img);
this.imgArr.unshift(img);//這里用unshift 保證順序
}
for(var i=curr+1;i<=this.count;i++){
dx = (i-1)*w+this.imageWidth-w;
image = this.imgObj[i];
img = new _.ImageDraw({image:image,sx:sx,sy:sy,sWidth:sWidth,sHeight:sHeight, dx:dx, dy:dy ,dWidth:dWidth,dHeight:dHeight});
img.id=i;
this.renderArr.push(img);
this.imgArr.push(img);
}
}
此時效果

加入方形
依次擺放好就行,顯示的那張圖片寬度取到圖片的寬度一樣為600.
//創建幾個方形和圖片一一對應,用來處理滑鼠移入的動作
for(var i=1;i<=this.count;i++){
x=(i-1)*w;
if(i>curr){
x+= sWidth-w;
}
if(i==curr){
width=sWidth;
}else{
width=20;
}
color=_.getRandomColor();
rect = new _.Rect({
x:x,
y:0,
width:width,
height:sHeight,
stroke:true,
strokeStyle:color
})
if(i==curr){
rect.curr=true;//當前展示圖片
}
rect.index=i;//方形索引-對應圖片下標
this.renderArr.push(rect);
this.rectArr.push(rect);
}
效果如下:

此時繪制的幾個方形顯示在圖片上面了,需要修改繪制順序,讓方形先生成即可,
//繪制選項圖片
Accordion.prototype.drawImage=function(){
var image,img,rect,x=0,sx=0,sy=0,sWidth=600,sHeight=360,dx=0,dy=0,dWidth=600,dHeight=360,w=this.dis,width=0,color;
var curr=this.currImgIndex,imageWidth = this.imageWidth;
var n = curr-1;
//創建幾個方形和圖片一一對應,用來處理滑鼠移入的動作
for(var i=1;i<=this.count;i++){
x=(i-1)*w;
if(i>curr){
x+= sWidth-w;
}
if(i==curr){
width=sWidth;
}else{
width=20;
}
color=_.getRandomColor();
rect = new _.Rect({
x:x,
y:0,
width:width,
height:sHeight,
stroke:true,
strokeStyle:color
})
if(i==curr){
rect.curr=true;//當前展示圖片
}
rect.index=i;//方形索引-對應圖片下標
this.renderArr.push(rect);
this.rectArr.push(rect);
}
//分二次處理是為了讓展示的圖片處于陣列的后面,不會被遮蓋
for(var i=curr;i>=1;i--){
if(i==curr){
dx = n*w;
}else{
dx = (i-1)*w-imageWidth+w;
}
image = this.imgObj[i];
img = new _.ImageDraw({image:image,sx:sx,sy:sy,sWidth:sWidth,sHeight:sHeight, dx:dx, dy:dy ,dWidth:dWidth,dHeight:dHeight});
img.id=i;
this.renderArr.push(img);
this.imgArr.unshift(img);//這里用unshift 保證順序
}
for(var i=curr+1;i<=this.count;i++){
dx = (i-1)*w+this.imageWidth-w;
image = this.imgObj[i];
img = new _.ImageDraw({image:image,sx:sx,sy:sy,sWidth:sWidth,sHeight:sHeight, dx:dx, dy:dy ,dWidth:dWidth,dHeight:dHeight});
img.id=i;
this.renderArr.push(img);
this.imgArr.push(img);
}
}
加入滑鼠移入事件
- 滑鼠移入后,滑鼠的坐標處于哪個方形范圍內,那對應的圖片就要顯示出來;
- 根據當前選擇的方形與之前顯示的圖片位置比較,可以確定圖片的運動方形(向左邊 or 向右),以及需要運動圖片物件,
- 開啟定時任務,來執行這些圖片的運動,運動的時候要重新排序,處理好圖片與圖片的遮蔽關系,不然會出現被其他圖片遮罩的效果,我在這里也費了不少時間去處理,
- 在已經顯示的圖片上移動滑鼠和圖片正在做運動的時候,是不會再次觸發定時任務的,
- 運動完成后,清除定時任務,重新設定相關引數即可!
滑鼠移入事件
//滑鼠移動事件
Accordion.prototype.mouseMove=function(e){
var that=this,catchIndex=0,currFlag=false,item;
if(that.catchFlag) return;//如果處理捕獲狀態,直接回傳
var pos = _.getOffset(e);//獲取滑鼠位置
for(var i=0;i<that.rectArr.length;i++){
item = that.rectArr[i];
if(item.isPoint(pos)){
if(that.currImgIndex==item.index){//當前顯示的圖片上移動,無效處理
currFlag=true;
}else{//需要執行圖片手風琴效果
catchIndex = item.index;
that.catchFlag=true;
currFlag=false;
}
break;
}
}
if(!catchIndex || currFlag) return;
that.move(catchIndex);
}
圖片移動的邏輯處理函式
//圖片移動的邏輯處理函式
Accordion.prototype.move=function(index){
var curr=this.currImgIndex,total=0;;
var moveArr=[],dir=1;
_.each(this.rectArr,function(item){
if(index<curr){//判斷好往左還是往右,設定dir
if(item.index>=index && item.index<=curr){//往右移動
moveArr.push(item);
}
}else{
if(item.index>=curr && item.index<=index){//往左移動
moveArr.push(item);
dir=-1;
}
}
})
//執行排序
this.sort(index,dir);
//開啟定時任務
var timmer = setInterval(doMove.bind(this),20);
//執行移動的函式
function doMove(){
var that=this,dis=10*dir;
if(total>=580){//移動到位后
clearInterval(timmer);//清除定時器
timmer=null;
that.catchFlag=false;//更改捕獲狀態
that.currImgIndex=index;//設定當前顯示圖的下標
_.each(moveArr,function(item){//設定flag為false
item.flag=false;
})
return;
}
_.each(moveArr,function(item){
if(dir>0){
//對方形控制的處理
if(item.index==index){
item.width+=dis;
}else {
if(item.index==curr){
item.width+=-dis;
}
item.x+=dis;
}
if(item.index<curr && item.index!=index){
if(!item.flag){//表示圖要先向右移動580,因為處于最左邊
that.imgArr[item.index-1].dx+=580;
item.flag=true;
}
}
//對圖片移動處理
that.imgArr[item.index-1].dx+=dis;
}else{
//對方形控制的處理
if(item.index==curr){
item.width+=dis;
}else {
if(item.index==index){
item.width+=-dis;
}
item.x+=dis;
}
if(item.index>curr && item.index!=index){
if(!item.flag){//表示圖要先向做移動580,因為處于最右邊,超過了畫布的范圍
that.imgArr[item.index-1].dx+=-580;
item.flag=true;
}
}
//對圖片移動處理
that.imgArr[item.index-1].dx+=dis;
}
})
total+=10; //不管往左往右total都是遞增
that.render();
}
}
排序函式
//排好序,否則圖片會相互遮蓋
Accordion.prototype.sort=function(index,dir){
var arr=this.renderArr;
var n=6;
if(dir<0){//向左移動
//左邊的圖放到陣列前面
for(var i=index-1;i>=1;i--){
arr[n++] = this.imgArr[i-1];
}
//當前顯示的圖片放在中間
arr[n++]=this.imgArr[index-1];
//右邊的圖放到陣列后面
for(var i=index+1;i<=this.count;i++){
arr[n++] = this.imgArr[i-1];
}
}else{//向右移動
//右邊的圖放到陣列前面
for(var i=index+1;i<=this.count;i++){
arr[n++] = this.imgArr[i-1];
}
//當前顯示的圖片放在中間
arr[n++]=this.imgArr[index-1];
//左邊的圖放到陣列后面
for(var i=index-1;i>=1;i--){
arr[n++] = this.imgArr[i-1];
}
}
}
最終效果就跟文章開頭的一樣,
原始碼下載
方式1:少量積分,下載代碼
方式2:關注下方公眾號,回復 126 下載代碼

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/274127.html
標籤:其他
上一篇:如何修改植物大戰僵尸的關卡和金幣
