微信小程序 实现报表(表格)双指缩放功能

实现前提要景:

1.本次实现双指缩放 是用css3中的scale配合translate 实现
2.小程序 不支持动态改变scale的大小 即使在写在行内样式中也不生效(在调试中不生效)故需借助小程序自己的API animation动画函数进行实现动态scale 和translate实现
3.zoom在其实也能实现 但是在小程序调试中也不生效
4.了解小程序 touchMove 属性 (双指缩放监听)
5.报表缩放时 需要保持长宽不变 即报表始终要占满手机屏幕 (造成用户进行双指缩放 感官上只是字体大小进行缩放) 所以要根据缩放程度 动态计算长宽 以及平移距离
6.在实际的平移过程中translate的值也会乘上你的scale中的参数。
所以在对scale之后的元素通过平移来实现到达某个位置时,translate中的参数为:实际平移值/scale的倍数。
具体事例:缩放和平移的影响
7.了解小程序createSelectorQuery boundingClientRect 函数 我们需要借助它 记录当前报表的长宽 方便后续进行缩放计算(不同的用户 手机宽高不同 不能写死宽高)

<view class="wx_table"  animation="{{animation}}" capture-bind:touchmove="touchMove" catch:touchend="touchEnd" style=" height:{{scaleHeight + '%'}} ;width:{{scaleWidth + '%'}}; " >
    <view class="table_top">
        <view class="table_header" style="left: {{footerScrollLeft}}px">
                <view class="th" style = "{{item.minWidth ? 'width:'+item.minWidth+';':'flex:1;'}}" wx:for="{{columns}}" wx:key="index">
                    {{item.label}}
                </view>
        </view>
    </view>
    <scroll-view class="table_center"  scroll-x scroll-y  bindscroll='handleInit' enhanced="{{true}}" bounces="{{fasle}}" lower-threshold="10" bindscrolltolower="hadlePaging">
        <view style="display: inline-block" class="content" wx:if="{{tableDate.length}}">
            <view class="tr {{index % 2 == 0 ? 'bgc' : '' }}" wx:for="{{tableDate}}" wx:for-item="date" wx:key="index">
                <view class="td " style = "{{column.minWidth ? 'width:'+column.minWidth+';':'flex:1;'}}"  wx:for="{{columns}}" wx:for-item="column" wx:for-index="columnIndex" wx:key="columnIndex">
                    {{table.formaTableDate(date,column.columnKey)}}
                </view>
            </view>
        </view>
        <view  style="display: inline-block" class="content" wx:if="{{!tableDate.length}}">
            <view class="tr">
                <view class="td " style = "width : {{column.minWidth?column.minWidth:'calc(350vmin / 7.5)'}}"  wx:for="{{columns}}" wx:for-item="column" wx:for-index="columnIndex" wx:key="columnIndex">
                </view>
            </view>

            <view class="no_content">
                <view>暂无记录</view>
            </view>
        </view>

    </scroll-view>
    <view class="table_bottom" wx:if="{{showFooter && tableDate.length}}">
        <view class="table_footer" style="left: {{footerScrollLeft}}px">
                <view class="td" style = "{{item.minWidth ? 'width:'+item.minWidth+';':'flex:1;'}}"  wx:for="{{columns}}" wx:key="index">
                   {{index==0? '共' + sumArray[index] + '项': sumArray[index]}}
                </view>

        </view>
    </view>
</view>




<wxs module="table">
  module.exports = {
    formaTableDate: function (date,columnKey) {
        if(columnKey.indexOf('.')) {
            var key = ''
            columnArray = columnKey.split('.')
            for(var index = 0; index < columnArray.length; index++) {
                var element = columnArray[index];
                if(!key) {
                     key = date[element]
                }else {
                    key = key[element]
                }
            }
            return key;
        } else {
             return date[columnKey];
        }
     
    }
  }
</wxs>

// pages/template/table/table.js
Component({
  properties: {
    columns: { 
      type: Array,
    },
     tableDate : {
      type: Array,
     },
     showFooter : {
      type: Boolean,
      value : true
     },
     sumArray : {
      type: Array,
      value : new Array(15).fill('--')
     }
  },
  data: {
    //  距左边的距离
    footerScrollLeft  : 0,
    scale : 1,
    scaleHeight : '100',
    scaleWidth : '100',
    distance : '',
    Xcenter : 0,  //  进来会计算 表格的X轴的长度  即Width
    Ycenter : 0,//  进来会计算 表格的Y轴的长度  即 Height
    animation:{}

  },
  methods :{
    // 双指缩放  监听双指触压屏幕事件
    touchMove(e) {
      const touches = e.touches   //  touches 数组 当双指的时候 该数组有两个对象 
      // pageX  pageY 为当前手指距X轴 Y轴的距离
      const { pageX: onePageX, pageY: onePageY } = touches[0]
      // distance 双指之间直线距离  第一次进入页面  默认为0
      const {scale, distance: oldDistance,} = this.data

      if (touches.length === 2) { 
        const { pageX: twoPageX, pageY: twoPageY } = touches[1]
        // distance  勾股定理 计算双指之间直线距离
        let distance = Math.sqrt((twoPageX - onePageX) ** 2 + (twoPageY - onePageY) ** 2)

        this.data.distance = distance
        // 通过双指直线距离的变化 对缩放倍数进行计算
        let NewScale = (scale * (distance / (oldDistance || distance)))

        this.handleAlintest(NewScale)
      }

    },
    // 双指离开
    touchEnd(e) {
      this.setData({
        distance : 0
      })
    },
    handleAlintest(newScale) {
      const {scale,Xcenter,Ycenter} = this.data
      if(newScale) {
        //  判断表格缩放  表格缩放scale  默认是根据中心焦点进行缩放 所以我们需要平移还原原来位置 平移也是根据中心焦点平移
        //  当scale 和平移同时用的时候 平移过程中translate的值会乘上scale中的参数 所以translate中的参数为:实际平移值/scale的倍数
        // 不仅要回到初始位置 还需要将X  Y 长度扩大  即原点也会进行变更  所以translate中的参数为:实际平移值/scale的倍数/scale的倍数
        // 缩
        if (scale >= newScale ) {
          let alin = newScale < 0.4 ? 0.4 : newScale
          // 缩放的同时 对其进行平移
          this.animation.scale(alin).translate(- (((Xcenter / 2 - (Xcenter * alin /2)) / alin)) / alin,- (((Ycenter / 2 - (Ycenter * alin /2) )/ alin))  / alin).step()
          this.setData({  
            animation: this.animation.export() ,
            scale: alin,  //输出动画  
            scaleHeight: (1 / alin ) * 100,
            scaleWidth:(1 / alin) * 100,
          })
        } else {  // 放
          let alin = newScale > 2 ? 2 : newScale
          this.animation.scale(alin).translate(- (((Xcenter / 2 - (Xcenter * alin /2)) / alin)) / alin,- (((Ycenter / 2 - (Ycenter * alin /2) )/ alin))  / alin).step()
          this.setData({
              scale: alin,
              animation: this.animation.export() ,
              scale: alin,  //输出动画  
              scaleHeight: (1 / alin ) * 100,
              scaleWidth:(1 / alin) * 100,
            })
        }
      }
      
    },
    //  调整表头表尾的位置
    handleInit(e) {
        this.setData({
          footerScrollLeft : -(e.detail.scrollLeft)
        })
    },
    hadlePaging(e) {
      if(e.detail.direction == 'bottom') {
        this.triggerEvent('parent')
      }
    }
  },
  lifetimes: {
    attached: function() {  
    },
    ready() {
      this.animation = wx.createAnimation({
        timingFunction:'step-start',
        duration : 0
      })
      
      let query = this.createSelectorQuery();
      console.log(query);
      let that = this;
      query.select('.wx_table').boundingClientRect(function (rect) {
        console.log(rect,'====>');
        that.setData({
          Xcenter : rect.width ,
          Ycenter : rect.height,
        })

        that.handleAlintest(.5)
      }).exec();
    },
    detached: function() {
      // 在组件实例被从页面节点树移除时执行
    },
  },

})
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
实现微信小程序中图片的双指缩放,可以使用小程序自带的 `<canvas>` 组件。具体步骤如下: 1. 在 WXML 文件中添加 `<canvas>` 组件,并设置宽高和 ID: ```html <canvas canvas-id="myCanvas" style="width: 100%; height: 100%;"></canvas> ``` 2. 在 JS 文件中获取 `<canvas>` 组件的上下文,并加载图片: ```javascript const ctx = wx.createCanvasContext('myCanvas'); const img = new Image(); img.src = '图片地址'; img.onload = function () { ctx.drawImage(img, 0, 0, canvasWidth, canvasHeight); } ``` 3. 监听 `<canvas>` 组件的 touch 事件,实现双指缩放: ```javascript let distance = 0; // 初始距离 let scale = 1; // 初始缩放比例 wx.createSelectorQuery().select('#myCanvas').fields({ node: true, size: true, }).exec((res) => { const canvas = res[0].node; // 获取 canvas 节点 const canvasWidth = res[0].width; // 获取 canvas 宽度 const canvasHeight = res[0].height; // 获取 canvas 高度 canvas.addEventListener('touchstart', (e) => { if (e.touches.length >= 2) { const x1 = e.touches[0].clientX; const y1 = e.touches[0].clientY; const x2 = e.touches[1].clientX; const y2 = e.touches[1].clientY; distance = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)); // 计算初始距离 } }); canvas.addEventListener('touchmove', (e) => { if (e.touches.length >= 2) { const x1 = e.touches[0].clientX; const y1 = e.touches[0].clientY; const x2 = e.touches[1].clientX; const y2 = e.touches[1].clientY; const newDistance = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)); // 计算新距离 const delta = newDistance - distance; // 计算距离差 scale += delta / 100; // 根据距离差更新缩放比例 distance = newDistance; // 更新距离 ctx.drawImage(img, 0, 0, canvasWidth * scale, canvasHeight * scale); // 根据新的缩放比例绘制图片 ctx.draw(); } }); }); ``` 在 touchstart 事件中记录双指触摸的初始距离,然后在 touchmove 事件中根据双指移动的距离差更新缩放比例,并重新绘制图片。最后调用 `ctx.draw()` 方法将画布内容绘制到屏幕上。 需要注意的是,在 touchmove 事件中需要使用 `ctx.drawImage()` 方法重新绘制图片,并传入新的宽高参数,这里的宽高需要根据当前的缩放比例计算得出。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值