苹果图标的豁口是怎么做出来的

小程序:将图形的右侧处理成被咬一口的形状

在一次需求中想要实现一个效果:有3个圆形的头像,其中中间的头像比两边的要大一些距离两边大概10px左右,两边的头像在挨着中间头像的那边需要凹一个弧坑出来,弧度就是中间圆的弧度,并且间距的颜色需要随着背景变化而变化。
效果如下:
处理完的效果

想到的几种方法

1 使用与背景相同颜色的圆形盖住头像

这种可以在背景不变的情况下使用,不符合现在需求

2 让ui出一个弧坑透明的头像

这个可以在头像为固定少数种类的情况下使用,较为方便

3 使用canvas将图像弧坑位置的像素全部变透明
这个貌似还比较符合

大致原理:
计算canvas中每个像素距离中间圆的圆心距离是否大于pointR,大于则将此像素设为透明
这其中有个两个坑
1,
ctxLeft.drawImage("/img/timg.jpg", 0, 0, 100, 100)
ctxLeft.draw();
这两个方法是将图片输入到canvas中,但是网络地址可能有问题
而且在这两个方法之后如果直接wx.canvasPutImageData可能获取到的data值为0的数组

2,wx.canvasPutImageData
这个方法不能并行,只能使用setTimeout方法将第二个延迟几毫秒,可能图片越大需要延迟的时间越长

// html
 <view class='test-container'>
    <canvas canvas-id="canvasLeft" class="canvas"></canvas>
    <view class="test-centerCircle">中间的圆</view>
    <canvas canvas-id="canvasRight" class="canvas"></canvas>
 </view>

 <view class='test-container'>
    <canvas canvas-id="canvasLeftOut" class="canvas"></canvas>
    <view class="test-centerCircle">中间的圆</view>
    <canvas canvas-id="canvasRightOut" class="canvas"></canvas>
 </view>
// css
 canvas {
  width: 100px;
  height: 100px;
  border-radius: 50%;
  overflow: hidden;
}

page{
  background-color: blue
}

.test-container {
  display: flex;
  flex-direction: row;
  align-items: flex-end;
}

.test-centerCircle {
  width: 150px;
  height: 150px;
  border-radius: 50%;
  background-color: pink;
  text-align: center;
  line-height: 150px;
}
// js
  const cfg = {
      x: 0,
      y: 0,
      width: 100,
      height: 100,
    }

// 后三个值决定被咬的缺口位置大小   const pointX = -20, pointY = 50, pointR = 50;
// !!!!这是重点,对你有用请关注下吧
function convertToGrayscale(data, pointX, pointY, pointR ) {
  for(let y = 0 ; y < 100 ; y++ ){
    for (let x = 0; x < 100; x++) {
      let index = y*400+x*4
      if (InCircle(x, y)){
        changeNull(data,index)
      }
    }
  }

// 像素是否在圆内
  function InCircle(x, y) {
    return Math.sqrt(Math.pow(pointX - x, 2) + Math.pow(pointY - y, 2)) < pointR
  }
/**
* 将这个像素的色值改为透明
* canvasGetImageData的success(res)方法中的res.data是个数组,每4位代表一个像素的颜色,格式为“rgba“
*/
  function changeNull(data, index){
    // g = (data[index] * 0.3 + data[index + 1] * 0.59 + data[index + 2] * 0.11)
    for(let i =0 ; i < 4 ; i++ ){ 
      data[index+i] = 0
    }
  }
  return data
}

Page({
  onReady() {
  },
  onLoad() {
    this.openAndDraw();
  },

  openAndDraw() {
    const ctxLeft = wx.createCanvasContext('canvasLeft', this);
    ctxLeft.drawImage("/img/timg.jpg", 0, 0, 100, 100)
    ctxLeft.draw();
    const ctxRight = wx.createCanvasContext('canvasRight', this);
    ctxRight.drawImage("/img/timg.jpg", 0, 0, 100, 100)
    ctxRight.draw();

    setTimeout(() => {
      wx.canvasGetImageData({
        canvasId: 'canvasLeft',
        ...cfg,
        success: (res) => {
          console.log(res)
          const data = convertToGrayscale(res.data, 150, 30, 75)
          wx.canvasPutImageData({
            canvasId: 'canvasLeftOut',
            data,
            ...cfg,
            success: (res) => {
              console.log(res)
            },
            fail: (err) => {
              console.error(err)
            }
          })
        },
        fail: (err) => {
          console.error(err)
        }
      });
      
    }, 100);

    setTimeout(()=>{
      wx.canvasGetImageData({
        canvasId: 'canvasRight',
        ...cfg,
        success: (res) => {
          console.log(res)
          const data = convertToGrayscale(res.data, -50, 30, 75)
          wx.canvasPutImageData({
            canvasId: 'canvasRightOut',
            data,
            ...cfg,
            success: (res) => {
              console.log(res)
            },
            fail: (err) => {
              console.error(err)
            }
          })
        },
        fail: (err) => {
          console.error(err)
        }
      })
    },140);

  }
})
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值