最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時間:2018年09月04日 11:39:17   作者:剪下一縷愁絲  
這篇文章主要介紹了微信小程序內拖動圖片實現(xiàn)移動、放大、旋轉的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

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

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

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

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

wx.drawCanvas(object) 繪制

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

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

我的具體實現(xiàn)思路是這樣的:

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

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

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

itemList: [{
      id: 1,
      image: '1.png',//圖片地址
      top: 100,//初始圖片的位置 
      left: 100,
      x: 155, //初始圓心位置,可再downImg之后又寬高和初始的圖片位置得出
      y: 155,
      scale: 1,//縮放比例 1為不縮放
      angle: 0,//旋轉角度
      active: false //判定點擊狀態(tài)
    }, {
      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事件里拿到的坐標,作為老坐標。這樣就可以實現(xiàn)圖片的滑動。

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

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

WraptouchStart: function (e) {
    for (let i = 0; i < items.length; i++) { //旋轉數(shù)據(jù)找到點擊的
      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.圖片的旋轉和縮放,因為圖片上已經(jīng)有了touch事件,所以解決辦法采用常規(guī)的在圖片的一角添加一個控件解決這個問題,控件大致如圖:

左邊控件是刪除按鈕,右邊控件則是手指按著旋轉切縮放圖片的控件,綁定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
    })
  }

頁面上是這樣寫的:

<!-- *************操作區(qū)域************* -->
    <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>
<!-- **************操作區(qū)域************ -->

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

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

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

/*
 *參數(shù)1和2為圖片圓心坐標
 *參數(shù)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中,圖片不能是網(wǎng)絡路徑,所以需要下載): 【18/6/22】

tpDownload: function(data, isDownload) { //data為組件的參數(shù),isDownload判斷是否為https網(wǎng)絡圖片來判斷是否需要下載
    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用到的代碼 (繪圖是通過保存按鈕觸發(fā))

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為可移動區(qū)的寬度
    prop值為canvas內背景的寬度與可移動區(qū)域的寬度的比,如一致,則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)
    })
  }

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

相關文章

  • JavaScript設計模式之代理模式介紹

    JavaScript設計模式之代理模式介紹

    這篇文章主要介紹了JavaScript設計模式之代理模式介紹,代理模式顧名思義就是用一個類來代替另一個類來執(zhí)行方法功能,需要的朋友可以參考下
    2014-12-12
  • javascript 多種搜索引擎集成的頁面實現(xiàn)代碼

    javascript 多種搜索引擎集成的頁面實現(xiàn)代碼

    這個頁面是為了方便自己同時使用多種搜索引擎(呵呵我用其作默認主頁),在IE5/IE6/FireFox下均運行正常,效果如下圖
    2010-01-01
  • [分享]一個非常漂亮的進度滾動條

    [分享]一個非常漂亮的進度滾動條

    [分享]一個非常漂亮的進度滾動條...
    2007-02-02
  • element-plus默認菜單打開步驟

    element-plus默認菜單打開步驟

    在 Vue 3 中使用 Element Plus 的 <el-menu> 組件時,默認情況下菜單項是關閉狀態(tài)的,如果你想讓某個菜單項默認處于展開狀態(tài),你可以通過設置菜單項的 default-active 屬性來實現(xiàn),這篇文章主要介紹了element-plus默認菜單打開,需要的朋友可以參考下
    2024-08-08
  • Code Review 方法論與實踐總結梳理

    Code Review 方法論與實踐總結梳理

    這篇文章主要為大家介紹了Code Review 方法論與實踐總結梳理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-02-02
  • 如何在wxml中直接寫js代碼(wxs)

    如何在wxml中直接寫js代碼(wxs)

    這篇文章主要介紹了如何在wxml中直接寫js代碼(wxs),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-11-11
  • 解析如何利用iframe標簽以及js制作時鐘

    解析如何利用iframe標簽以及js制作時鐘

    本文對如何利用iframe標簽以及js制作時鐘進行了全面解析,分步說明,條理清晰,感興趣的朋友可以看下
    2016-12-12
  • 用director.js實現(xiàn)前端路由使用實例

    用director.js實現(xiàn)前端路由使用實例

    本篇文章主要介紹了director.js實現(xiàn)前端路由,在不刷新的情況下,利用“#”號組織不同的URL路徑,并根據(jù)不同的URL路徑進行不同的方法調用。有興趣的了解一下。
    2017-01-01
  • 怎么理解wx.navigateTo的events參數(shù)使用詳情

    怎么理解wx.navigateTo的events參數(shù)使用詳情

    這篇文章主要介紹了怎么理解wx.navigateTo的events參數(shù)使用詳情,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-05-05
  • javascript 極速 隱藏/顯示萬行表格列只需 60毫秒

    javascript 極速 隱藏/顯示萬行表格列只需 60毫秒

    隱藏表格列 這種方式的效率極低。例如,隱藏一個千行表格的某列,在我的筆記本(P4 M 1.4G,768M內存)上執(zhí)行需要約 4000毫秒的時間,令人無法忍受。
    2009-03-03

最新評論

田东县| 临朐县| 济南市| 陇南市| 玉树县| 沂水县| 承德市| 平塘县| 龙陵县| 奉贤区| 贵州省| 揭阳市| 胶南市| 龙南县| 顺平县| 台安县| 大冶市| 韶关市| 星座| 黄浦区| 临漳县| 嘉鱼县| 临湘市| 馆陶县| 敖汉旗| 桐城市| 长兴县| 韶山市| 永新县| 射阳县| 昆山市| 芮城县| 遂昌县| 洞头县| 武邑县| 广平县| 资源县| 芦溪县| 庄河市| 合江县| 海安县|