效果图
web
* {margin: 0;padding: 0;}.container {position: relative;width: 328px;height: 328px;margin: 100px auto;}.container img {position: absolute;width: 328px;height: 328px;}#canvas {position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);z-index: 1;}.img-shape-bg {position: absolute;top: 0;left: 50%;width: 284px;height: 284px;transform: translateX(-50%) scale(1.4);opacity: .05;}
<div class="container"><img src="icosphere_red@2x.png" alt=""><canvas id="canvas" width="140" height="140"></canvas><!-- 加一层背景模糊,优化背景色 --><view class="img-shape-bg" style="background-image: radial-gradient( circle, red 50%, transparent, transparent)"></view></div>
function mergeImages() {// 创建一个画布const canvas = document.getElementById("canvas");const context = canvas.getContext("2d");const overlay = new Image();// 蒙层及样版图片overlay.src = "mask@2x.png";overlay.onload = function () {context.drawImage(overlay, 0, 0, 140, 140);const template = new Image();template.src = "1.png";template.onload = function (res) {let width = height = 140let realWidth = template.widthlet realHeight = template.heightlet imgRatio = realWidth / realHeightlet sw = 0, sh = 0, sx = 0, sy = 0;let canvasRatio = width / height// 图片不变形if(imgRatio <= canvasRatio) {sw = realWidthsh = sw / canvasRatiosx = 0sy = (realHeight - sh) / 2} else { sh = realHeightsw = sh * canvasRatiosx = (realWidth - sw) / 2 sy = 0} // 仅在新形状和目标画布重叠的地方绘制新形状。其他的都是透明的context.globalCompositeOperation = "source-in";context.drawImage(template, sx, sy, sw, sh, 0, 0, 140, 140);};};}mergeImages()
miniprogram
.note-top-shape {box-sizing: border-box;position: relative;width: 284rpx;height: 284rpx;margin: auto;.img-shape-main {position: absolute;top: 50%;left: 50%;transform: translate(-50%, -52%);width: 120rpx;height: 120rpx;z-index: 2;}.img-shape {position: relative;z-index: 1;}.img-shape-bg {position: absolute;top: 0;left: 50%;width: 284rpx;height: 284rpx;transform: translateX(-50%) scale(1.5);opacity: .05;}}
// 水晶<view class="note-top-shape"><image class="img-shape" src="{{ baseImageUrl }}{{ kindShape }}" mode="aspectFit" lazy-load="false" style="width: 284rpx;height: 284rpx;" binderror="" bindload="" />// canvas 在上面显示,因为canvas在小程序中层级太高,所以需要转化为image src展示<canvas type="2d" id="canvas_{{listItem.id}}" style="position: fixed;top: -9999px;left: -9999px;width: 240rpx;height: 240rpx;"></canvas><block><image class="img-shape-main" src="{{ imgPath }}" mode="aspectFit" lazy-load="false" binderror="" bindload=""></image></block>// 加一层背景模糊<view class="img-shape-bg" style="background-image: radial-gradient( ellipse at top, {{ listItem.style }} 50%, transparent, transparent)"></view></view>
Component({properties: {listItem: {type: Object,default: {//shape: 0,//style: red,}}},observers: {'listItem': function(item) {let shape = item.shapevar shapeImage = ''switch (shape) {case '0':shapeImage = 'pyramid'breakcase '1':shapeImage = 'cube'breakcase '2':shapeImage = 'diamond'breakcase '3':shapeImage = 'hexsphere'breakcase '4':shapeImage = 'icosphere'break}// 水晶图片是根据接口数据显示的let src = `shape/${shapeImage}_${item.style}@2x.png`this.setData({kindShape: src})}},data: {imgPath: ''},attached() {let item = this.data.listItemthis.mergeImagesMiniProgram(item.id, '/assets/images/mask@2x.png', item.photos[0])},methods: {mergeImagesMiniProgram(id, maskPath, filePath) {let that = thislet query = wx.createSelectorQuery().in(this)query.select(`#canvas_${id}`).fields({ node: true, size: true }).exec((rescanvas) => {let canvas = rescanvas[0].nodelet ctx = canvas.getContext('2d')const overlay = canvas.createImage()overlay.src = maskPathlet width = canvas.width = 120let height = canvas.height = 120let canvasRatio = width / heightoverlay.onload = function () {ctx.drawImage(overlay, 0, 0, width, height)const template = canvas.createImage()template.src = filePathtemplate.onload = function () {let realWidth = template.widthlet realHeight = template.height// coverlet imgRatio = realWidth / realHeightlet sw = 0, sh = 0, sx = 0, sy = 0;if(imgRatio <= canvasRatio) {sw = realWidthsh = sw / canvasRatiosx = 0sy = (realHeight - sh) / 2} else { sh = realHeightsw = sh * canvasRatiosx = (realWidth - sw) / 2 sy = 0} // ctx.globalCompositeOperation = "destination-in";ctx.globalCompositeOperation = "source-in";ctx.drawImage(template, sx, sy, sw, sh, 0, 0, width, height)// ctx.drawImage(template, 0, 0, width, height);wx.canvasToTempFilePath({canvas,width: width,height: height,destWidth: width * app.globalData.pixelRatio,destHeight: height * app.globalData.pixelRatio,success: async function(res) {let filePath = res.tempFilePath;that.setData({imgPath: filePath})},fail: function (res) {}})}}})}
})
素材图片
水晶
蒙层
我不叫胖虎
有需要可+qq:2091545890
参考文档-canvas drawImage绘图实现contain和cover的效果
参考文档-CanvasRenderingContext2D