欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

微信小程序canvas拖拽、截圖組件功能

 更新時間:2018年09月04日 10:47:28   作者:jasondu  
這篇文章主要介紹了微信小程序canvas拖拽、截圖組件功能,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下

先看下微信小程序canvas拖拽功能

組件地址

github.com/jasondu/wx-… readme近期補上

實現(xiàn)效果

如何實現(xiàn)

  1. 使用canvas
  2. 使用movable-view標(biāo)簽

由于movable-view無法實現(xiàn)旋轉(zhuǎn),所以選擇使用canvas

需要解決的問題

  • 如何將多個元素渲染到canvas上
  • 如何知道手指在元素上、如果多個元素重疊如何知道哪個元素在最上層
  • 如何實現(xiàn)拖拽元素
  • 如何縮放、旋轉(zhuǎn)、刪除元素

看起來挺簡單的嘛,就把上面這幾個問題解決了,就可以實現(xiàn)功能了;接下來我們一一解決。

如何將多個元素渲染到canvas上

定義一個DragGraph類,傳入元素的各種屬性(坐標(biāo)、尺寸…)實例化后推入一個 渲染數(shù)組 里,然后再循環(huán)這個數(shù)組調(diào)用實例中的渲染方法,這樣就可以把多個元素渲染到canvas上了。

如何知道手指在元素上、如果多個元素重疊如何知道哪個元素在最上層

在DragGraph類中定義了判斷點擊位置的方法,我們在canvas上綁定touchstart事件,將手指的坐標(biāo)傳入上面的方法,我們就可以知道手指是點擊到元素本身,還是刪除圖標(biāo)或者變換大小的圖標(biāo)上了,這個方法具體怎么判斷后面會講解。

通過循環(huán) 渲染數(shù)組 判斷是非點擊到哪個元素到,如果點擊中了多個元素,也就是多個元素重疊,那第一個元素就是最上層的元素啦。

###如何實現(xiàn)拖拽元素

通過上面我們可以判斷手指是否在元素上,當(dāng)touchstart事件觸發(fā)時我們記錄當(dāng)前的手指坐標(biāo),當(dāng)touchmove事件觸發(fā)時,我們也知道這時的坐標(biāo),兩個坐標(biāo)取差值,就可以得出元素位移的距離啦,修改這個元素實例的x和y,再重新循環(huán)渲染 渲染數(shù)組 就可以實現(xiàn)拖拽的功能。

如何縮放、旋轉(zhuǎn)、刪除元素

這一步相對比較難一點,我會通過示意圖跟大家講解。

我們先講縮放和旋轉(zhuǎn)

通過touchstart和touchmove我們可以獲得旋轉(zhuǎn)前的旋轉(zhuǎn)后的坐標(biāo),圖中的線A為元素的中點和旋轉(zhuǎn)前點的連線;線B為元素中點和旋轉(zhuǎn)后點的連線;我們只需要求A和B兩條線的夾角就可以知道元素旋轉(zhuǎn)的角度??s放尺寸為A和B兩條線長度之差。

計算旋轉(zhuǎn)角度的代碼如下:

const centerX = (this.x + this.w) / 2; // 中點坐標(biāo)
const centerY = (this.y + this.h) / 2; // 中點坐標(biāo)
const diffXBefore = px - centerX;  // 旋轉(zhuǎn)前坐標(biāo)
const diffYBefore = py - centerY;  // 旋轉(zhuǎn)前坐標(biāo)
const diffXAfter = x - centerX;   // 旋轉(zhuǎn)后坐標(biāo)
const diffYAfter = y - centerY;   // 旋轉(zhuǎn)后坐標(biāo)
const angleBefore = Math.atan2(diffYBefore, diffXBefore) / Math.PI * 180;
const angleAfter = Math.atan2(diffYAfter, diffXAfter) / Math.PI * 180;
// 旋轉(zhuǎn)的角度
this.rotate = currentGraph.rotate + angleAfter - angleBefore;

計算縮放尺寸的代碼如下:

// 放大 或 縮小
this.x = currentGraph.x - (x - px);
this.y = currentGraph.y - (x - px);

下面介紹下小程序canvas截圖組件

最近做一個小程序的過程中,需要用到截圖功能,網(wǎng)上搜了一下,發(fā)現(xiàn)沒有符合要求的,就自己搞了個組件,方便復(fù)用。

目前功能很簡單,傳入寬高和圖片路徑即可,寬高是為了計算截圖的比例,只支持縮放和移動。

實現(xiàn)思路是:

1.模擬一個截取框;

2.移動圖片位置,縮放圖片;

3.獲取圖片在其中的位置(left,top,width,height);

4.使用canvas繪制圖片,然后截取就ok了。

其中第二步的縮放圖片比較麻煩,縮放中心點以及平滑縮放

以下是我的實現(xiàn)方式

wxml:

<!--component/picPro/picPro.wxml-->
<scroll-view class='body' hidden="{{hidden}}">
<view class='flex-column flex-between full-height full-width' bindtouchstart="touchstart" bindtouchmove="touchmove" bindtouchend="touchend">
<view class='bg_dark out_item'></view>
<view class='flex-row main flex-between' style='height:{{(windowWidth - margin.left - margin.right)/ratio + "px"}}'>
<view class='bg_dark main_item full-height' style='width:{{margin.left + "px"}}'></view>
<view class='inner relative full-width' id='showArea'>
<image class='absolute img' src='{{src}}' style="width:{{img.width}}px;height:{{img.height}}px;left:{{img.left}}px;top:{{img.top}}px;"></image>
<canvas canvas-id='imgCanvas' class='absolute img_canvas full-height full-width' />
<view class='absolute inner_item left_top'></view>
<view class='absolute inner_item right_top'></view>
<view class='absolute inner_item right_bottom'></view>
<view class='absolute inner_item left_bottom'></view>
</view>
<view class='bg_dark main_item full-height' style='width:{{margin.right + "px"}}'></view>
</view>
<view class='bg_dark out_item flex-column flex-end'>
 <view class='flex-around text_white text_bg'>
<view catchtap='outputImg' data-type='1'><text>重新上傳</text></view>
<view catchtap='getImg'><text>選擇圖片</text></view>
</view> 
</view>
<!-- -->
<view class='absolute full-width full-height bg_black'></view>
</view>
</scroll-view>

wxss:(其中引入了一個公共樣式,關(guān)于flex布局的,看樣式名也能猜到)

/* component/picPro/picPro.wxss */
@import '../../resource/style/flex.wxss';
.body{
 position: fixed;
 top: 0;
 right: 0;
 bottom: 0;
 left: 0;
}
.text_white{
 color: white;
}
.main{
}
.out_item{
 width: 100%;
 height: 100%;
 flex: 1;
}
.bg_dark{
 background-color: rgba(0, 0, 0, 0.85)
}
.main_item{
 width: 15px;
}
.inner{
 outline: 3rpx solid white;
 background-color: rgba(0, 0, 0, 0.12);
 box-shadow: 0 0 4px rgba(0, 0, 0, 0.5) inset;
}
.inner_item{
 width: 8px;
 height: 8px;
}
.inner_item.left_top{
 border-left: 3px solid white;
 border-top: 3px solid white;
 left: -3px;
 top: -3px;
}
.inner_item.right_top{
 border-right: 3px solid white;
 border-top: 3px solid white;
 right: -3px;
 top: -3px;
}
.inner_item.right_bottom{
 border-right: 3px solid white;
 border-bottom: 3px solid white;
 right: -3px;
 bottom: -3px;
}
.inner_item.left_bottom{
 border-left: 3px solid white;
 border-bottom: 3px solid white;
 left: -3px;
 bottom: -3px;
}
.img{
 z-index: -1;
}
.bg_black{
 background-color:black;
 z-index: -2; 
}
.text_bg{
 padding-bottom: 2em;
 font-size: 0.9em;
}
.img_canvas{
 opacity: 0.5;
}
.newImg{
 z-index: 2
}

js:

// component/picPro/picPro.js
const state = {
 // 可用區(qū)域body
 window: { width: 0, height: 0 },
 // 原始圖片信息
 originImg: { width: 0, height: 0 },
 // 第一次圖片縮放信息
 firstScaleImg: { width: 0, height: 0 },
 // 截取區(qū)域信息
 interArea: { width: 0, height: 0 },
 // 單手觸摸位置
 touchLast: { x: 0, y: 0 },
 // 滑動距離
 touchMove: { x: 0, y: 0 },
 // 滑動離開時圖片狀態(tài)
 moveImgState: {
  width: 0,
  height: 0,
  top: 0,
  left: 0,
 },
 // 雙手觸摸位置
 touchList: [{ x: 0, y: 0 }, { x: 0, y: 0 }],
 // 圖片縮放比例
 scale: 1,
}
Component({
 /**
  * 組件的屬性列表
  */
 properties: {
  //寬(非實際值)
  width: {
   type: Number,
   value: 600
  },
  //高
  height: {
   type: Number,
   value: 300
  },
  //圖片路徑
  src: {
   type: String,
   value: ""
  },
  //顯示隱藏
  hidden: {
   type: Boolean,
   value: false
  },
  //截取框的信息
  margin: {
   type: Object,
   value: {
    left: 15,
    right: 15,
    top: 200,
    bottom: 200,
   }
  }
 },

 ready() {
  this.initialize();
  // const canvas = wx.createCanvasContext('imgCanvas', this);
  // canvas.draw(false, () => { console.log('ccc') }, this);
 },

 /**
  * 組件的初始數(shù)據(jù)
  */
 data: {
  touchRange: 8,
  img: {
   width: 0,
   height: 0,
   top: 0,
   left: 0,
  },
  canvas: {},
  ratio: 0,
  originImg: {
   width: 0,
   height: 0
  }
 },

 /**
  * 組件的方法列表
  */
 methods: {
  touchstart(e) {
   // console.log("touchstart", e);

  },
  touchmove(e) {
   if (e.touches.length === 1) { this.singleSlip(e.touches[0]) } else {
    this.doubleSlip(e.touches)
   }
  },
  touchend(e) {
   // console.log("touchend", e);
   const x = 0, y = 0;
   state.touchLast = { x, y };
   state.touchMove = { x, y };
   state.touchList = [{ x, y }, { x, y }];
   state.moveImgState = this.data.img;
   // console.log(this.data.img);
  },
  // 單手滑動操作
  singleSlip(e) {
   const { clientX: x, clientY: y } = e;
   const that = this;
   if (state.touchLast.x && state.touchLast.y) {
    state.touchMove = { x: x - state.touchLast.x, y: y - state.touchLast.y };
    state.touchLast = { x, y };
    const move = (_x = false, _y = false) => {
     const bottom = that.data.img.height + that.data.img.top;
     const right = that.data.img.width + that.data.img.left;
     const h = state.interArea.height;
     const w = state.interArea.width;
     const param = {};
     if (_x) {
      if (right > w && that.data.img.left < 0) {
       param.left = that.data.img.left + state.touchMove.x * 0.1
      } else if (right <= w && state.touchMove.x > 0) {
       param.left = that.data.img.left + state.touchMove.x * 0.1
      } else if (that.data.img.left >= 0 && state.touchMove.x < 0) {
       param.left = that.data.img.left + state.touchMove.x * 0.1
      }
     };
     if (_y) {
      if (bottom > h && that.data.img.top < 0) {
       param.top = that.data.img.top + state.touchMove.y * 0.1
      } else if (bottom <= h && state.touchMove.y > 0) {
       param.top = that.data.img.top + state.touchMove.y * 0.1
      } else if (that.data.img.top >= 0 && state.touchMove.y < 0) {
       param.top = that.data.img.top + state.touchMove.y * 0.1
      }
     };
     // console.log(param);
     that.setImgPos(param)
    };
    if (state.scale == 1) {
     if (that.data.img.width == state.interArea.width) {
      move(false, true)
     } else {
      move(true, false)
     }
    } else {
     move(true, true)
    }
   } else {
    state.touchLast = { x, y }
   }
  },
  // 雙手縮放操作
  doubleSlip(e) {
   const that = this;
   const { clientX: x0, clientY: y0 } = e[0];
   const { clientX: x1, clientY: y1 } = e[1];
   if (state.touchList[0].x && state.touchList[0].y) {
    let changeScale = (Math.sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0)) - Math.sqrt((state.touchList[1].x - state.touchList[0].x) * (state.touchList[1].x - state.touchList[0].x) + (state.touchList[1].y - state.touchList[0].y) * (state.touchList[1].y - state.touchList[0].y))) * 0.0005;
    changeScale = changeScale >= 1.5 ? 1.5 : (changeScale <= -1 ? -1 : changeScale);
    state.scale = that.data.img.width / state.firstScaleImg.width < 1 ? 1 : (state.scale > 2.5 ? 2.5 : 1 + changeScale);
    let width = state.firstScaleImg.width * (state.scale - 1) + state.moveImgState.width;
    width = width < state.firstScaleImg.width ? state.firstScaleImg.width : width;
    let height = state.firstScaleImg.height * (state.scale - 1) + state.moveImgState.height;
    height = height < state.firstScaleImg.height ? state.firstScaleImg.height : height;
    let left = width * (1 - state.scale) / 4 + state.moveImgState.left;
    left = left * (-1) > width - state.interArea.width ? state.interArea.width - width: left > 0 ? 0 : left;
    let top = height * (1 - state.scale) / 4 + state.moveImgState.top;
    top = top * (-1) > height - state.interArea.height ?state.interArea.height - height : top > 0 ? 0 : top;
    const setImgObj = { width, height, left, top };
    that.setImgPos(setImgObj)
   } else {
    state.touchList = [{ x: x0, y: y0 }, { x: x1, y: y1 }]
   }
  },
  // 獲取可用區(qū)域?qū)捀?
  getScreenInfo() {
   const that = this;
   return new Promise((resolve, reject) => {
    wx.getSystemInfo({
     success: function (res) {
      const { windowHeight, windowWidth } = res;
      state.window = { windowHeight, windowWidth };
      that.setData({ windowHeight, windowWidth })
      // console.log(state.window);
      resolve(res);
     },
    })
   })
  },
  setShowArea() {
   const that = this;
   const w = state.window.windowWidth - that.data.margin.left - that.data.margin.right;
   const h = (that.data.height / that.data.width) * w;
  },
  outputImg() {
   this.setData({
    hidden: true,
   })
  },
  getImgInfo(path) {
   return new Promise((resolve, reject) => {
    wx.getImageInfo({
     src: path,
     success(res) {
      console.log(res);
      resolve(res);
     },
     fail(err) {
      reject(err)
     }
    })
   })
  },
  // 設(shè)置圖片
  setImgPos({ width, height, top, left }) {
   width = width || this.data.img.width;
   height = height || this.data.img.height;
   top = top || this.data.img.top;
   left = left || this.data.img.left
   this.setData({
    img: { width, height, top, left }
   })
  },
  // 初始化圖片位置大小
  initialize() {
   const that = this;
   const ratio = that.data.width / that.data.height;
   this.getScreenInfo().then(res => {
    console.log(res);
    state.interArea = { width: res.windowWidth - that.data.margin.left - that.data.margin.right + 2, height: (res.windowWidth - that.data.margin.left - that.data.margin.right) / ratio };
    console.log("interArea", state.interArea)
    that.getImgInfo(that.data.src).then(imgInfo => {
     const { width, height } = imgInfo;
     const imgRatio = width / height;
     state.originImg = { width, height };
     that.setData({
      ratio: ratio
     });
     if (imgRatio > ratio) {
      that.setImgPos({
       height: state.interArea.height,
       width: state.interArea.height * imgRatio
      })
     } else {
      that.setImgPos({
       height: state.interArea.width / imgRatio,
       width: state.interArea.width,
      })
     };
     state.firstScaleImg = { width: that.data.img.width, height: that.data.img.height }
    });
   });
  },
  // 截圖
  getImg(){
   const that = this;
   // console.log('dudu', that.data.img);
   const canvas = wx.createCanvasContext('imgCanvas', this);
   const {width,height,left,top} = that.data.img;
   const saveImg = ()=>{
    console.log('開始截取圖片');
    wx.canvasToTempFilePath({
     canvasId:"imgCanvas",
     success(res){
      // console.log(res);
      that.setData({
       hidden:true,
       // src:""
      });
      that.triggerEvent("putimg", { imgUrl: res.tempFilePath},{});
     },
     fail(err){
      console.log(err)
     }
    },that)
   };
   canvas.drawImage(that.data.src, left, top, width, height);
   canvas.draw(false, () => { saveImg() }, that)
  }
 }
})

引用的時候除了寬高路徑以外,需要wx:if;如果不卸載組件,會出現(xiàn)只能截一次的bug

因為小程序里面沒有類似vue中catch的觀測數(shù)據(jù)變化的東西,也不想為了個組件專門去搞一個,就用這種方式代替了,嘻嘻,好敷衍。。

總結(jié)

以上所述是小編給大家介紹的微信小程序canvas拖拽、截圖組件功能,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!

相關(guān)文章

  • JS中call apply bind函數(shù)手寫實現(xiàn)demo

    JS中call apply bind函數(shù)手寫實現(xiàn)demo

    這篇文章主要為大家介紹了JS中call apply bind函數(shù)手寫實現(xiàn)demo,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • 原生js實現(xiàn)圖片輪播特效

    原生js實現(xiàn)圖片輪播特效

    這篇文章主要介紹了原生js實現(xiàn)圖片輪播特效,適合用于商品展示,實現(xiàn)最簡單的廣告輪播效果,感興趣的小伙伴們可以參考一下
    2015-12-12
  • 只出現(xiàn)一次的提示信息(js+cookies)

    只出現(xiàn)一次的提示信息(js+cookies)

    只顯示一次的提示信息,刷新一頁面或第二次來到這個頁面,就不會再彈出提示窗口了,用在網(wǎng)頁上是想當(dāng)實用的吧,因為很多人都不希望經(jīng)常彈出什么窗口,本效果因此會提升用戶體驗,讓用戶喜歡你的網(wǎng)頁
    2013-03-03
  • 基于JavaScript實現(xiàn)永遠(yuǎn)加載不滿的進(jìn)度條

    基于JavaScript實現(xiàn)永遠(yuǎn)加載不滿的進(jìn)度條

    各位開發(fā)大佬,平時肯定見到過這種進(jìn)度條吧,一直在加載,但等了好久都是在99%,那如何用JavaScript實現(xiàn)這一效果呢,下面就來和大家詳細(xì)講講
    2023-04-04
  • js計算精度問題小結(jié)

    js計算精度問題小結(jié)

    js計算精度問題小結(jié),需要的朋友可以參考一下
    2013-04-04
  • layui: layer.open加載窗體時出現(xiàn)遮罩層的解決方法

    layui: layer.open加載窗體時出現(xiàn)遮罩層的解決方法

    今天小編就為大家分享一篇layui: layer.open加載窗體時出現(xiàn)遮罩層的解決方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-09-09
  • JavaScript Uploadify文件上傳實例

    JavaScript Uploadify文件上傳實例

    這篇文章主要為大家詳細(xì)介紹了Uploadify文件上傳小實例,一個簡單的jsp上傳小功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-02-02
  • JSON 對象未定義錯誤的解決方法

    JSON 對象未定義錯誤的解決方法

    下面小編就為大家?guī)硪黄狫SON 對象未定義錯誤的解決方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-09-09
  • 微信小程序?qū)崿F(xiàn)即時通信聊天功能的實例代碼

    微信小程序?qū)崿F(xiàn)即時通信聊天功能的實例代碼

    這篇文章主要介紹了微信小程序?qū)崿F(xiàn)即時通信聊天功能的實例代碼,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-08-08
  • JavaScript構(gòu)造函數(shù)舉例詳解

    JavaScript構(gòu)造函數(shù)舉例詳解

    Javascript構(gòu)造函數(shù)是非常強大的,它可能也是Javascript能被充分利用的特點之一,文中通過實例代碼介紹的非常詳細(xì),這篇文章主要給大家介紹了關(guān)于JavaScript構(gòu)造函數(shù)的相關(guān)資料,需要的朋友可以參考下
    2023-04-04

最新評論