因
在一次需求中想要实现一个效果:有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);
}
})