亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 課堂 > 小程序 > 正文

微信小程序內拖動圖片實現移動、放大、旋轉的方法

2020-03-21 16:10:50
字體:
來源:轉載
供稿:網友

屏幕就像是數學上的坐標軸,且在第四象限,以屏幕左上角為圓點,X軸向右為正向左為負,Y軸向下為正向上為負(這點和數學上相反的)以圓點為基點畫個距離圓點上下50寬高100的矩形來演示canvas基本用法

微信小程序這里提供了兩個API

wx.createContext() 創建并返回繪圖上下文context對象

  • getActions 獲取當前context上存儲的繪圖動作,對應wx.drawCanvas(object)中的actions
  • clearActions 清空當前的存儲繪圖動作

wx.drawCanvas(object) 繪制

  • canvasId 畫布標識,傳入的cavas-id,這里的標識可以為Number,也可以是String
  • actions 繪圖動作數組,由wx.createContext創建的context,調用getActions方法導出繪圖動作數組。

最近接到一個任務,在微信小程序內拖動圖片組件實現移動、放大、旋轉,并記錄這些圖片的移動位置,放大比例,旋轉角度,在一個畫布上生成一張圖片,最后保存到手機相冊。

我的具體實現思路是這樣的:

 一共三個功能,可以先把功能分為圖片 拖動 和圖片 旋轉縮放 , 把圖片的縮放和旋轉做在了一起。

1.圖片移動:可移動的圖片肯定是要動態生成的,所以不能寫死,應該是個數組,具備很多的屬性。

例如:(并不是我項目的真實數據)

itemList: [{      id: 1,      image: '1.png',//圖片地址      top: 100,//初始圖片的位置       left: 100,      x: 155, //初始圓心位置,可再downImg之后又寬高和初始的圖片位置得出      y: 155,      scale: 1,//縮放比例 1為不縮放      angle: 0,//旋轉角度      active: false //判定點擊狀態    }, {      id: 2,      image: '2.png',      top: 50,      left: 50,      x: 155,      y: 155,      scale: 1,      angle: 0,      active: false

事件綁定圖片上或者圖片的父級,綁定bindtouchstart  bindtouchmove事件。再bindtouchstart事件里,獲取手指點擊的某一個圖片的點擊坐標,并記錄在這個圖片對象的屬性里面,在bindtouchmove事件里,移動的時候記錄移動后的坐標,并算出倆次滑動的距離差值,追加給圖片對象的left、top、x、y上,最后把本次滑動的坐標賦值給bindtouchmove事件里拿到的坐標,作為老坐標。這樣就可以實現圖片的滑動。

注:代碼里的 items  只是我定義的一個全局變量,是一個空數組,在onLoad函數里 items = this.data.itemLits; 

這樣就不會頻繁的去setData,我只需要處理items,處理完之后,再this.setData({itemLits:items })

WraptouchStart: function (e) {    for (let i = 0; i < items.length; i++) { //旋轉數據找到點擊的      items[i].active = false;      if (e.currentTarget.dataset.id == items[i].id) {        index = i;  //記錄下標        items[index].active = true; //開啟點擊屬性      }    }        items[index].lx = e.touches[0].clientX; // 記錄點擊時的坐標值    items[index].ly = e.touches[0].clientY;    this.setData({  //賦值       itemList: items    })  }  , WraptouchMove: function (e) {    //移動時的坐標值也寫圖片的屬性里    items[index]._lx = e.touches[0].clientX;    items[index]._ly = e.touches[0].clientY;        //追加改動值    items[index].left += items[index]._lx - items[index].lx; // x方向    items[index].top += items[index]._ly - items[index].ly;  // y方向    items[index].x += items[index]._lx - items[index].lx;    items[index].y += items[index]._ly - items[index].ly;        //把新的值賦給老的值    items[index].lx = e.touches[0].clientX;     items[index].ly = e.touches[0].clientY;    this.setData({//賦值就移動了      itemList: items    })  }

2.圖片的旋轉和縮放,因為圖片上已經有了touch事件,所以解決辦法采用常規的在圖片的一角添加一個控件解決這個問題,控件大致如圖:

微信小程序,拖動圖片,移動,放大,旋轉

左邊控件是刪除按鈕,右邊控件則是手指按著旋轉切縮放圖片的控件,綁定bindtouchstart  bindtouchmove事件。

index也是設置的全局變量。

// 觸摸開始事件 items是this.data.itemList的全局變量,便于賦值 所有的值都應給到對應的對象里  touchStart: function (e) {    //找到點擊的那個圖片對象,并記錄    for (let i = 0; i < items.length; i++) {      items[i].active = false;       if (e.currentTarget.dataset.id == items[i].id) {        console.log('e.currentTarget.dataset.id', e.currentTarget.dataset.id)        index = i;        console.log(items[index])        items[index].active = true;      }    }     //獲取作為移動前角度的坐標    items[index].tx = e.touches[0].clientX;    items[index].ty = e.touches[0].clientY;    //移動前的角度    items[index].anglePre = this.countDeg(items[index].x, items[index].y, items[index].tx, items[index].ty)    //獲取圖片半徑    items[index].r = this.getDistancs(items[index].x, items[index].y, items[index].left, items[index].top)  },  // 觸摸移動事件   touchMove: function (e) {    //記錄移動后的位置    items[index]._tx = e.touches[0].clientX;    items[index]._ty = e.touches[0].clientY;    //移動的點到圓心的距離 * 因為圓心的坐標是相對與父元素定位的 ,所有要減去父元素的OffsetLeft和OffsetTop來計算移動的點到圓心的距離    items[index].disPtoO = this.getDistancs(items[index].x, items[index].y, items[index]._tx - this.sysData.windowWidth * 0.125, items[index]._ty - 10)     items[index].scale = items[index].disPtoO / items[index].r; //手指滑動的點到圓心的距離與半徑的比值作為圖片的放大比例    items[index].oScale = 1 / items[index].scale;//圖片放大響應的右下角按鈕同比縮小     //移動后位置的角度    items[index].angleNext = this.countDeg(items[index].x, items[index].y, items[index]._tx, items[index]._ty)    //角度差    items[index].new_rotate = items[index].angleNext - items[index].anglePre;     //疊加的角度差    items[index].rotate += items[index].new_rotate;    items[index].angle = items[index].rotate; //賦值     //用過移動后的坐標賦值為移動前坐標    items[index].tx = e.touches[0].clientX;    items[index].ty = e.touches[0].clientY;    items[index].anglePre = this.countDeg(items[index].x, items[index].y, items[index].tx, items[index].ty)     //賦值setData渲染    this.setData({      itemList: items    })  }

頁面上是這樣寫的:

<!-- *************操作區域************* -->    <block wx:for="{{itemList}}" wx:key="{{item.id}}">      <!-- 圓心坐標 <text style='position:absolute;top:{{item.y}}px;left:{{item.x}}px;width:2px;height:2px;background-color:yellow;z-index:500'></text> -->      <view class='touchWrap' style='transform: scale({{item.scale}});top:{{item.top}}px;left:{{item.left}}px; '>        <view class='imgWrap {{item.active? "touchActive":""}}' style="transform: rotate({{item.angle}}deg);">          <image src='{{item.image}}' data-id='{{item.id}}' style='width:{{item.width}}px;height:{{item.height}}px;' bindtouchstart='WraptouchStart' bindload='loadImg' hidden='{{!item.isload}} bindtouchmove='WraptouchMove' bindtouchend='WraptouchEnd'></image>          <image class='x' src='../../images/x.png' style='transform: scale({{item.oScale}});transform-origin:center;' data-id='{{item.id}}' bindtap='deleteItem'></image>          <image class='o' src='../../images/o.png' style='transform: scale({{item.oScale}});transform-origin:center;' data-id='{{item.id}}' bindtouchstart='touchStart' bindtouchmove='touchMove' bindtouchend='touchEnd'></image>        </view>      </view>    </block><!-- **************操作區域************ -->

這樣一來就解決了微信小程序內拖動圖片實現移動、放大、旋轉的問題,操作也比較順滑,也耗費我近四天的時間才把我的小程序上線,代碼有點混亂,如果各位大佬有什么意見可以給我留言,我的小程序名字是:水逆轉運符文,以后會持續改進。

2018/5/7補充一條生成圖片時,組件的屬性:

微信小程序,拖動圖片,移動,放大,旋轉

我的失誤,忘了附上角度計算函數  countDeg :  

/* *參數1和2為圖片圓心坐標 *參數3和4為手點擊的坐標 *返回值為手點擊的坐標到圓心的角度 */  countDeg: function (cx, cy, pointer_x, pointer_y) {    var ox = pointer_x - cx;    var oy = pointer_y - cy;    var to = Math.abs(ox / oy);    var angle = Math.atan(to) / (2 * Math.PI) * 360;//鼠標相對于旋轉中心的角度    console.log("ox.oy:", ox, oy)    if (ox < 0 && oy < 0)//相對在左上角,第四象限,js中坐標系是從左上角開始的,這里的象限是正常坐標系     {      angle = -angle;    } else if (ox <= 0 && oy >= 0)//左下角,3象限     {      angle = -(180 - angle)    } else if (ox > 0 && oy < 0)//右上角,1象限     {      angle = angle;    } else if (ox > 0 && oy > 0)//右下角,2象限     {      angle = 180 - angle;    }     return angle;  }

計算觸摸點到圓心的距離:

getDistancs(cx, cy, pointer_x, pointer_y) {    var ox = pointer_x - cx;    var oy = pointer_y - cy;    return Math.sqrt(      ox * ox + oy * oy    );  }

點擊配件時的事件(因為再我測試在canvas中,圖片不能是網絡路徑,所以需要下載): 【18/6/22】

tpDownload: function(data, isDownload) { //data為組件的參數,isDownload判斷是否為https網絡圖片來判斷是否需要下載    if (yy < 0) { //改變生成圖片時的位置      speed = -speed    }    if (yy > 300) {      speed = -speed    }    yy += speed;    let _this = this;    let newTpdata = {};    newTpdata.id = data.id;    newTpdata.itemid = data.itemid;    newTpdata.top = 100 + yy;    newTpdata.left = 100;    newTpdata.width = _this.sysData.windowWidth / 4;    newTpdata.scale = 1;    newTpdata.angle = 0;    newTpdata.rotate = 0;    newTpdata.active = true;    for (let i = 0; i < items.length; i++) {      items[i].active = false;    }    if (isDownload) {      wx.downloadFile({        url: data.image,        success: res => {          newTpdata.image = res.tempFilePath;          items.push(newTpdata);          _this.setData({            itemList: items          })          wx.hideLoading();        }      })    } else {      newTpdata.image = data.image;      items.push(newTpdata);      _this.setData({        itemList: items      })      wx.hideLoading();    }  }

我的項目中生成canvas用到的代碼 (繪圖是通過保存按鈕觸發)

 

save: function() {    this.setData({      showCanvas: true,      canvasHeight: this.sysData.windowHeight * 0.85    })    let obj = this.data.item;    /*    canvasWidth值為canvas寬度;    this.data.canvasPre是占屏幕寬度的百分比(80)    */    let canvasWidth = this.sysData.windowWidth * this.data.canvasPre / 100; //    /*    num為canvas內背景圖占canvas的百分比,若全背景num =1    this.sysData.windowWidth * 0.75為可移動區的寬度    prop值為canvas內背景的寬度與可移動區域的寬度的比,如一致,則prop =1;    */    let prop = (canvasWidth * num) / (this.sysData.windowWidth * 0.75);    maskCanvas.save();    maskCanvas.beginPath();    //一張白圖    maskCanvas.setFillStyle('#fff');    maskCanvas.fillRect(0, 0, this.sysData.windowWidth, this.data.canvasHeight)    maskCanvas.closePath();    maskCanvas.stroke();    //圖頭像    let image = {      w: canvasWidth * num * 0.287,      h: canvasWidth * num * 0.287,      r: canvasWidth * num * 0.287 / 2    };    //畫背景 hCw 為 1.7781 背景圖的高寬比    maskCanvas.drawImage(obj.bgImg, canvasWidth * (1 - num) / 2, 10, canvasWidth * num, canvasWidth * num * hCw)    //畫底圖    maskCanvas.drawImage('../../images/xcx.png', canvasWidth * (1 - num) / 2, canvasWidth * num * hCw + 15, canvasWidth * num, this.data.canvasHeight * 0.15)    //畫原    maskCanvas.save();    maskCanvas.beginPath();    maskCanvas.arc(canvasWidth / 2, canvasWidth * num * hCw * obj.userTop / 100 + 10 + image.w / 2, image.r, 0, Math.PI * 2, false);    // maskCanvas.stroke()    maskCanvas.clip(); //截取    //畫頭像    maskCanvas.drawImage(obj.avatarUrl, (canvasWidth - image.w) / 2, canvasWidth * num * hCw * obj.userTop / 100 + 10, image.w, image.h)    maskCanvas.closePath();    maskCanvas.restore();    //繪制文字    maskCanvas.save();    maskCanvas.beginPath();    let fontSize = this.sysData.screenWidth / 375 * 15;    let textColor = obj.color || '#000';    maskCanvas.setFontSize(parseInt(fontSize) * prop)    maskCanvas.setFillStyle(textColor)    maskCanvas.setTextAlign('center')    maskCanvas.fillText(obj.nickName, canvasWidth / 2, obj.titleTop / 100 * canvasWidth * num * hCw + 10 * 0.9 * prop + fontSize * prop);    maskCanvas.closePath();    maskCanvas.stroke();    /**      * x     * y     * scale     * prop     * width     * height     *      */    //畫組件    items.forEach((currentValue,index)=>{      maskCanvas.save();      maskCanvas.translate(canvasWidth * (1 - num) / 2, 10);      maskCanvas.beginPath();      maskCanvas.translate(currentValue.x * prop, currentValue.y * prop); //圓心坐標      maskCanvas.rotate(currentValue.angle * Math.PI / 180); // 旋轉值      maskCanvas.translate(-(currentValue.width * currentValue.scale * prop / 2), -(currentValue.height * currentValue.scale * prop / 2))      maskCanvas.drawImage(currentValue.image, 0, 0, currentValue.width * currentValue.scale * prop, currentValue.height * currentValue.scale * prop);      maskCanvas.restore();    })    maskCanvas.draw(false, (e)=> {      wx.canvasToTempFilePath({        canvasId: 'maskCanvas',        success: res => {          this.setData({            canvasTemImg: res.tempFilePath          })        }      }, this)    })  }

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
北条麻妃久久精品| 亚洲a级在线播放观看| 欧美电影免费播放| 国产精品永久免费观看| 久久久欧美一区二区| 亚洲全黄一级网站| 国产成人福利夜色影视| 亚洲人成绝费网站色www| 岛国av一区二区在线在线观看| 日本久久久久久久久| 午夜精品国产精品大乳美女| 成人激情av在线| 久久噜噜噜精品国产亚洲综合| 亚洲国产日韩精品在线| 国产一区二区黑人欧美xxxx| 97**国产露脸精品国产| 91国产在线精品| 欧美视频在线看| 性色av一区二区三区红粉影视| 日韩动漫免费观看电视剧高清| 九九热这里只有在线精品视| 亚洲性69xxxbbb| 亚洲视频专区在线| 91系列在线播放| 久久久精品2019中文字幕神马| 91精品国产综合久久久久久久久| 上原亚衣av一区二区三区| 亚洲高清一区二| 亚洲一区二区中文字幕| 久久久国产精品亚洲一区| 91免费观看网站| 一个人看的www欧美| 久久久女人电视剧免费播放下载| 欧美视频在线免费看| 国产精品wwwwww| 欧美在线观看网站| 久久99久久99精品免观看粉嫩| 在线不卡国产精品| 亚洲精品一区二区网址| 国产成人jvid在线播放| 成人激情视频免费在线| 尤物九九久久国产精品的分类| 国产精品爱久久久久久久| 国产精品第10页| 欧美日韩国产一区在线| 欧美日韩精品在线视频| 国产成人精品久久二区二区| 国产精品一区二区女厕厕| 亚洲第一精品久久忘忧草社区| 日韩精品一区二区三区第95| 91精品国产91| 自拍亚洲一区欧美另类| 亚洲精品久久久久久久久久久久久| 亚洲精品美女网站| 欧美精品生活片| 国产精品麻豆va在线播放| 日韩在线小视频| 亚洲第一区第二区| 91精品国产成人| 国产精品免费久久久| 91午夜理伦私人影院| 国产日韩亚洲欧美| 国产成人精品视频在线观看| 欧美性色19p| 91国在线精品国内播放| 日韩美女毛茸茸| 亚洲精品一区二区久| 亚洲精品小视频| 国产综合福利在线| 亚洲美女久久久| 中文字幕综合一区| 国产精品电影久久久久电影网| 一区二区三区回区在观看免费视频| 一本久久综合亚洲鲁鲁| 国产精品91久久久| 91免费看国产| 日韩大胆人体377p| 91精品久久久久久久久久入口| 国产精品午夜一区二区欲梦| 亚洲成人三级在线| 亚洲精品一区二三区不卡| 欧美精品videos性欧美| 亚洲xxxx18| 欧洲日本亚洲国产区| 国产成人综合精品在线| 国产精品99久久久久久久久| 亚洲福利精品在线| 青草青草久热精品视频在线观看| 国产亚洲aⅴaaaaaa毛片| 97av在线视频免费播放| 色综合久久天天综线观看| 欧美精品亚州精品| 亚洲一区二区少妇| 激情亚洲一区二区三区四区| 久久久久久这里只有精品| 成人黄色免费看| 麻豆成人在线看| www.欧美三级电影.com| 亚洲欧美日本另类| 久久久久一本一区二区青青蜜月| 亚洲国产精品va在线| 国产丝袜一区视频在线观看| 久久99精品视频一区97| 日本亚洲欧美成人| 欧美日韩精品国产| 国产亚洲精品美女久久久久| 亚洲天堂av高清| 久久久免费观看视频| 久久艳片www.17c.com| 日韩av网站导航| 久久偷看各类女兵18女厕嘘嘘| 97精品国产91久久久久久| 成人免费在线视频网站| 亚洲人高潮女人毛茸茸| 亚洲人成在线一二| 国产精品免费在线免费| 国产精品伦子伦免费视频| 欧美另类在线播放| 欧美电影在线播放| 国产一区二区丝袜| 欧美在线免费视频| 国产精品爱久久久久久久| 一二美女精品欧洲| 久久精品99久久香蕉国产色戒| 26uuu另类亚洲欧美日本老年| 欧美猛男性生活免费| 日韩av高清不卡| 91精品在线观看视频| 国产午夜精品全部视频在线播放| 日本久久91av| 欧美成人剧情片在线观看| 亚洲欧洲国产精品| 精品国产一区久久久| 国产精品亚洲第一区| 欧美成在线观看| 91精品久久久久久久久久另类| 欧美日韩在线视频一区二区| 日韩高清a**址| 国产午夜精品美女视频明星a级| 亚洲女人被黑人巨大进入al| 国产在线精品成人一区二区三区| 奇米4444一区二区三区| 亚洲片国产一区一级在线观看| 亚洲欧美另类自拍| 92看片淫黄大片看国产片| 欧美激情二区三区| 精品免费在线视频| 日韩精品久久久久久久玫瑰园| 中文字幕久热精品视频在线| 最新国产精品亚洲| 国产激情久久久| 久久综合伊人77777蜜臀| 91极品女神在线| 亚洲国产精品久久久久秋霞蜜臀| 人人爽久久涩噜噜噜网站| 国产精品网红直播| 97av在线视频免费播放| 亚洲在线第一页| 成人精品视频99在线观看免费| 久久伊人免费视频| 国产精品白嫩美女在线观看| 久久综合88中文色鬼| 国产一区在线播放| 亚洲精品久久7777777|