先上效果圖:
wxml:
<view class='canvas-box'>
<canvas canvas-id='canvas' style='width:{{windowW}}px;height:{{windowH}}px;' wx:if="{{hideCanvas}}"></canvas>
</view>
wxss:
.canvas-box{
position: fixed;
left: 10000px;
}
js:
const { roundRect, roundImage, drawTextOverflow } = require("../../utils/util.js");
let rpx; //寬度%比 適配手機寬度
let xh; //高寬比 適配手機高度
page({
data: {
windowW: '', //設備寬高
windowH: '',
canvasQr: '', //二維碼圖片
canvasDetail: '', //詳情項目圖片地址
clip_left: '',//左偏移值,
clip_top: '', //上偏移值
clip_width: '',//截取寬度,截取高度
clip_height: '',
hideCanvas:false, //canvas的隱藏
detailData: {}, //我的數據,自行改動
}
_downImg:function(e){
wx.getSystemInfo({
success: function(res) {
rpx = res.windowWidth / 375;
xh = res.windowHeight / res.windowWidth
_this.setData({
windowW: res.windowWidth,
windowH: res.windowHeight,
scrollerHeight: res.windowHeight - (res.windowWidth / 750) * 120
})
}
});
console.log(e)
//這裏是我調的接口得到的動態圖片,你們根據自己要求去改
this.wxFileImg(e.detail.codeUrl);
wx.showLoading({
title: '正在生成圖片中',
mask: true
})
this.setData({
hideCanvas:true,
})
},
//網絡圖片轉臨時
wxFileImg: function (codeUrl) {
let _this = this;
wx.downloadFile({
url: codeUrl,
success: function (resQrFile) {
_this.setData({
canvasQr: resQrFile.tempFilePath
})
wx.downloadFile({
url: _this.data.detailData.logo,
success: function (resDetailFile) {
wx.getImageInfo({
src: resDetailFile.tempFilePath,
success(resDetailInfo) {
let img_width = resDetailInfo.width,
img_height = resDetailInfo.height;
//左偏移值,上偏移值,截取寬度,截取高度
let clip_left, clip_top, clip_width, clip_height;
clip_height = img_width ;
if (clip_height > img_height) {
clip_height = img_height;
clip_width = clip_height;
clip_left = (img_width - clip_width) / 2;
clip_top = 0;
} else {
clip_left = 0;
clip_top = (img_height - clip_height) / 2;
clip_width = img_width;
}
_this.setData({
canvasDetail: resDetailFile.tempFilePath,
clip_left,
clip_top,
clip_width,
clip_height
})
let canvas = wx.createCanvasContext('canvas');
_this.canvasdraw(canvas);
}
})
}
})
}
})
},
canvasdraw: function (canvas) {
let _this = this;
let windowW = _this.data.windowW;
let windowH = _this.data.windowH;
let canvasQr = _this.data.canvasQr;
let canvasDetail = _this.data.canvasDetail;
let clip_left = _this.data.clip_left;
let clip_top = _this.data.clip_top;
let clip_width = _this.data.clip_width;
let clip_height = _this.data.clip_height;
let detailData = _this.data.detailData;
// 整畫布
canvas.setFillStyle('#EFEFEF');
canvas.fillRect(0, 0, windowW, windowH);
canvas.draw(true);
// 主畫布
console.log(xh)
// 由於手機的高寬比不同,適配主畫布的高度,可以根據自己的畫布要求自行調整
if (xh > 1.9) {
roundRect(canvas, 15 * rpx, 100 * rpx, windowW * 0.92, windowH * 0.65, 10 * rpx, '#FFFFFF');
} else if (xh > 1.8) {
roundRect(canvas, 15 * rpx, 80 * rpx, windowW * 0.92, windowH * 0.75, 10 * rpx, '#FFFFFF');
}else{
roundRect(canvas, 15 * rpx, 80 * rpx, windowW * 0.92, windowH * 0.8, 10 * rpx, '#FFFFFF');
}
//詳情圖片
roundImage(canvas, 10 * rpx, canvasDetail, clip_left, clip_top, clip_width, clip_height, 15 * rpx, 30 * rpx, 345 * rpx, 245 * rpx, '#ffffff');
//遮擋圖片圓角
roundRect(canvas, 15 * rpx, 210 * rpx, windowW * 0.92, 90 * rpx, 10 * rpx, '#FFFFFF');
// 項目名稱 2行展示
drawTextOverflow(canvas, detailData.title, 305 * rpx, 2, 24, "#333", 28, 35 * rpx, 260 * rpx);
// 項目價格
canvas.setFontSize(20);
canvas.fillStyle = "#DD2534";
canvas.setTextAlign('left');
//文字加粗
canvas.fillText(detailData.priceText, 35 * rpx, 319.5 * rpx);
canvas.fillText(detailData.priceText, 34.5 * rpx, 320 * rpx);
// 項目區域
canvas.setFontSize(16);
canvas.fillStyle = "#666666";
canvas.setTextAlign('left');
canvas.fillText(detailData.district, 35 * rpx, 350 * rpx);
// 項目面積
canvas.setFontSize(16);
canvas.fillStyle = "#666666";
canvas.setTextAlign('left');
canvas.fillText(detailData.landAreaText || detailData.houseSizeText, 35 * rpx, 380 * rpx);
//二維碼
canvas.drawImage(canvasQr, 35 * rpx, 410 * rpx, 100 * rpx, 100 * rpx);
//名字
canvas.setFontSize(16);
canvas.fillStyle = "#333333";
canvas.setTextAlign('left');
canvas.fillText(detailData.userName, 155 * rpx, 445 * rpx);
// 線
canvas.beginPath();
canvas.setLineWidth(0.1);
canvas.setFillStyle('#EFEFEF');
canvas.moveTo(155 * rpx, 460 * rpx);
canvas.lineTo(325 * rpx, 460 * rpx);
canvas.stroke();
// 提示
canvas.setFontSize(16);
canvas.fillStyle = "#999999";
canvas.setTextAlign('left');
canvas.fillText('微信長按或掃一掃打開', 155 * rpx, 490 * rpx);
canvas.draw(true, setTimeout(function () {
_this.daochu()
}, 1000));
},
//整個畫布圖片
daochu: function () {
let _this = this;
let windowW = _this.data.windowW;
let windowH = _this.data.windowH;
wx.canvasToTempFilePath({
x: 0,
y: 0,
width: windowW,
height: windowH,
destWidth: windowW * 3, //3倍像素 更清晰
destHeight: windowH * 3,
canvasId: 'canvas',
success: function (res) {
// console.log(res)
wx.hideLoading();
wx.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success(res) {
}
})
wx.previewImage({
urls: [res.tempFilePath],
})
_this.setData({
hideCanvas: false
})
},
fail:function(err){
wx.hideLoading();
// console.log(err)
}
})
},
})
util.js
/**
* canvas繪製圓角矩形
* @param {Object} context - canvas組件的繪圖上下文
* @param {Number} x - 矩形的x座標
* @param {Number} y - 矩形的y座標
* @param {Number} w - 矩形的寬度
* @param {Number} h - 矩形的高度
* @param {Number} r - 矩形的圓角半徑
* @param {String} [c = 'transparent'] - 矩形的填充色
*/
const roundRect = (context, x, y, w, h, r, c = 'transparent') => {
if (w < 2 * r) {
r = w / 2;
}
if (h < 2 * r) {
r = h / 2;
}
context.beginPath();
context.fillStyle = c;
context.arc(x + r, y + r, r, Math.PI, Math.PI * 1.5);
context.moveTo(x + r, y);
context.lineTo(x + w - r, y);
context.lineTo(x + w, y + r);
context.arc(x + w - r, y + r, r, Math.PI * 1.5, Math.PI * 2);
context.lineTo(x + w, y + h - r);
context.lineTo(x + w - r, y + h);
context.arc(x + w - r, y + h - r, r, 0, Math.PI * 0.5);
context.lineTo(x + r, y + h);
context.lineTo(x, y + h - r);
context.arc(x + r, y + h - r, r, Math.PI * 0.5, Math.PI);
context.lineTo(x, y + r);
context.lineTo(x + r, y);
context.fill();
context.closePath();
};
/**
* canvas繪製圓角圖片
* @param {Object} context - canvas組件的繪圖上下文
* @param {Number} r - 圓角半徑
* @param {String} path - 圖片地址
* @param {Number} sx - 源圖像的矩形選擇框的左上角 x 座標
* @param {Number} sy - 源圖像的矩形選擇框的左上角 y 座標
* @param {Number} sWidth - 源圖像的矩形選擇框的寬度
* @param {Number} sHeight - 源圖像的矩形選擇框的高度
* @param {Number} dx - 圖像的左上角在目標 canvas 上 x 軸的位置
* @param {Number} dy - 圖像的左上角在目標 canvas 上 y 軸的位置
* @param {Number} dWidth - 在目標畫布上繪製圖像的寬度,允許對繪製的圖像進行縮放
* @param {Number} dHeight - 在目標畫布上繪製圖像的高度,允許對繪製的圖像進行縮放
* @param {String} c - 矩形的填充色
*/
const roundImage = (context, r, path, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight, c) => {
context.save();
roundRect(context, dx, dy, dWidth, dHeight, r, c);
context.fill();
context.clip();
context.drawImage(path, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
context.restore();
};
/**
* 繪製圓形圖片
* @param {Object} context - canvas組件的繪圖上下文
* @param {String} path - 圖片地址
* @param {Number} x - 圖片的x座標
* @param {Number} y - 圖片的y座標
* @param {Number} r - 圖片的半徑
*/
const circleImage = (context, path, x, y, r) => {
let d = 2 * r;
let cx = x + r;
let cy = y + r;
context.save();
context.beginPath();
context.arc(cx, cy, r, 0, 2 * Math.PI);
context.fill();
context.clip();
context.drawImage(path, x, y, d, d);
context.restore();
};
/**
* canvas多行文本溢出
* @param {Object} context - canvas組件的繪圖上下文
* @param {String} text - 文本內容
* @param {Number} maxWidth - 文本最大寬度
* @param {Number} maxRow - 文本最多顯示行數
* @param {Number} fontSize - 字體樣式
* @param {String} color - 文本顏色
* @param {Number} lineHeight - 文本行高
* @param {Number} x - 文本的x座標
* @param {Number} y - 文本的y座標
*/
const drawTextOverflow = (context, text, maxWidth, maxRow, fontSize, color, lineHeight, x, y) => {
let arr = [];
let temp = '';
let row = [];
text = text.replace(/[\r\n]/g, ''); // 去除回車換行符
arr = text.split('');
context.setFontSize(fontSize); // 注意:一定要先設置字號,否則會出現文本變形
context.fillStyle = color;
if (context.measureText(text).width <= maxWidth) {
row.push(text);
} else {
for (let i = 0; i < arr.length; i++) {
// 超出最大行數且字符有剩餘,添加...
if (row.length == maxRow && i < arr.length - 1) {
row[row.length - 1] += '...';
break;
}
// 字符換行計算
if (context.measureText(temp).width < maxWidth) {
temp += arr[i];
// 遍歷到最後一位字符
if (i === arr.length - 1) {
row.push(temp);
}
} else {
i--; // 防止字符丟失
row.push(temp);
temp = '';
}
}
}
// 繪製文本
for (let i = 0; i < row.length; i++) {
context.fillText(row[i], x, y + i * lineHeight, maxWidth);
}
return row.length * lineHeight; // 返回文本高度
};