需求:移動端,做如下圖片的一個海報,可以長按保存,其中標題文字,說明文字,logo圖片,二維碼(動態生成二維碼)圖片,都是可變元素,其余部分是一張圖片!
我的canvas學習筆記gitlab
如果前端來做,首先,我想到的就是利用canvas繪制出來,然后,轉換成img,放在頁面中,這樣用戶就可以通過長按保存功能,保存圖片了!
思路步驟以及遇到的坑
- 使用Konva庫繪制canvas,繪制文字(可以繪制在同一個組上);
- 先生成二維碼圖片,再將二維碼圖片繪制到層上;
- 繪制logo圖片和背景圖片;
- canvas正確設置寬高屬性單位必須是px、百分比適配;
HTML
<div id="wrapper"><div id="container"></div></div>
文字繪制方法封裝
// @param: data 數組(因為可能有多個文字)
function TextTitle(data){
this._init(data);
}
TextTitle.prototype = {
_init: function(data){
this.data = data;
// 新建文字組
this.textGroup = new Konva.Group({
x: 0,y: 0
})
var self = this;
this.data.forEach(function(item,index){
var x = item.x === 0 ? 0 : (item.x || 1);
var y = item.y === 0 ? 0 : (item.y || 1);
var txt = new Konva.Text({
x: x,y: y,
text: item.text,
width: item.width,
height: item.height,
fontSize: item.fontSize || 16,
fontStyle: item.fontStyle || 'normal',
fontFamily: item.fontFamily || 'Arial',
align: item.align || 'left',
fill: item.fill || '#000',
});
self.textGroup.add(txt);
})
},
addToGroupOrLayer: function(arg){
arg.add(this.textGroup);
}
}
整個圖片繪制
// 創建舞台
var stage = new Konva.Stage({
container: 'container', // 需要存放舞台的dom容器
width: 621/2, // 設置全屏
height: 974/2
});
// 創建層
var layer = new Konva.Layer(); // 創建一個層
// stage.add(layer); // 把層添加到舞台(這里寫在了最后)
// 中心點坐標
// var cenX = stage.width()/2; // 注意Konva獲取數據都是用方法獲取值
// var cenY = stage.height()/2;
// 創建一個組存放文字
var group = new Konva.Group({
x: 0,y: 0
})
// 繪制文字數據
var dataObj = [
{ // 創建標題的文字
x: 0,
y: 30,
width: stage.width(),
align: 'center',
text: "活動名稱",
fontSize: 26,
fontStyle: 'bold',
fill: 'white'
},
{ // 創建活動說明文字
x: 0,
y: 66,
width: stage.width(),
align: 'center',
text: '最終解釋權歸門店所有',
fontSize: 16,
fill: 'white'
}
];
var text = new TextTitle(dataObj);
// 繪制二維碼
// 創建二維碼圖片,先轉成img,再繪制到canvas中,然后將img移除
var divEle = document.createElement("div");
var divattr = document.createAttribute("id");
divattr.value = "temp";
divEle.setAttributeNode(divattr);
document.getElementById("wrapper").appendChild(divEle);
new QRCode(document.getElementById("temp"), {
text: window.location.href, // 首頁鏈接
width: 72, //生成的二維碼的寬度
height: 72, //生成的二維碼的高度
colorDark : "#000000", // 生成的二維碼的深色部分
colorLight : "#ffffff", //生成二維碼的淺色部分
correctLevel : QRCode.CorrectLevel.H
});
var qrcodeImg = $('#temp img')[0];
// 繪制logo,背景的圖片
var imgBig = new Image();
imgBig.src = "base64圖片";
// 將繪制方法都寫在圖片onload內部
imgBig.onload = function(){
var kImage = new Konva.Image({
image: imgBig,
x: 0,
y: 0,
width: stage.width(),
height: stage.height()
});
group.add(kImage);
// 添加二維碼圖片
var qrCodeImage = new Konva.Image({
image: qrcodeImg,
x: 204,
y: 366,
width: 72,
height: 72
});
group.add(qrCodeImage);
layer.add(group);
text.addToGroupOrLayer(layer);
layer.draw();
stage.add(layer); // 把層添加到舞台
// 繪制完二維碼后將標簽刪除
var temp = document.getElementById("temp");
document.getElementById('wrapper').removeChild(temp);
// 使用canvas.toDataURL()方法,將canvas生成base64
var dataURL = stage.toDataURL();
var actulImg = new Image();
actulImg.src = dataURL;
actulImg.onload = function(){ // 生成后刪除canvas
var konvajs = document.getElementsByClassName('konvajs-content')[0];
document.getElementById('container').removeChild(konvajs);
document.getElementById('container').appendChild(actulImg);
}
}
使用的是canvas.toDataURL()方法,出現跨域問題
報錯信息:
Konva error: Unable to get data URL. Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
翻譯:Konva錯誤:無法獲取數據URL。未能對“htmlcanvaseelement”執行“toDataURL”:無法導出受污染的畫布。
整個報錯信息的原因就是,使用canvas.toDataURL()方法,出現跨域問題了。
因為很多情況下都會使用CDN存儲的圖片,在這里使用本地圖片還是不現實,所以,需要解決這個問題。
解決辦法嘗試:
- img設置img.crossOrigin = "anonymous"是沒用的;
- URL.createObjectURL和URL.revokeObjectURL也是轉換圖片格式的方式,自測沒寫通;
- 將圖片轉換成base64使用(這里需要借助后端配合了),如果使用這種辦法,出現某個圖片或者二維碼圖片未顯示出來,可能是繪制順序出錯。
使用base64圖片方式,在PC模擬器上效果顯示是符合的,那么我們用微信瀏覽器試試吧!
問題又出現了:
- 生成的canvas不虛,img圖片太虛虛虛虛虛虛虛......導致根本沒辦法使用;
- 生成的二維碼不見了,safari瀏覽器可以顯示出二維碼,偶發性如果第一次進入,點擊顯示的按鈕,safair整張圖片都不顯示了,應該是未生成就顯示了;
后續再開發再更新!!!

使用html2canvas.js實現頁面截圖(生成海報效果)
生成海報功能最終使用的是html2canvas.js庫實現的,不過過程中也有些兼容性問題需要解決,下面是生成海報方法:
createIMG () { //一鍵生成圖片
window.scrollTo(0, 0); // 解決部分手機生成圖片大片白邊
var _this = this;
// 海報布局,將布局好的結構進行canvas轉換,再將canvas轉換成圖片
var targetDom = document.getElementById("pic_wrapper_page");
html2canvas( targetDom,
{
useCORS: true,
height: targetDom.offsetHeight-2,// 解決部分手機生成圖片部分白邊
width: targetDom.offsetWidth-2,
}).then(function(canvas) {
var image = canvas.toDataURL("image/png");
_this.pic_src = image // 最終生成的圖片
});
}
