需求
在開發過程中遇到這么一個需求,h5頁面需要將一個html dom轉化成圖片,便於用戶保存。
面向百度搜索第三方得 html2canvas 和 dom-to-image
兩者在寫這篇筆記之前在github上的星星數分別是
dom-to-image 4k ⭐️
html2canvas 13.7k ⭐️
兩者都有嘗試過,都有意想不到的bug,包括
- 部分手機有某些背景圖片無法展示,為空白
- iphone8 plus ios 11中根本不調用這個轉換方法,從而得不到想要的圖片。
等等
自己動手
思路
利用canvas的toDataURL來拿到canvas轉化的base64碼,來替換img的url, 也可以把圖片上傳到公司的服務器上,得到圖片的地址來進行下載,或作為參數來傳遞
那么canvas的繪制主要就是文本和圖片的繪制,文本繪制相對簡單,圖片繪制有一些注意點。
canvas 初始化
由於最后生成的圖片可能會模糊,可以盡量畫大一點畫布,可以按照設計圖來
<canvas id="canvas" width="750" height="1164">
你的瀏覽器居然不支持Canvas?!趕快換一個吧!!
</canvas>
let c = document.getElementById("canvas");
let ctx = c.getContext("2d");
文本繪制
官方文檔如圖
詳細文檔請參考 canvas手冊
代碼示例
ctx.fillStyle = "#fff";
ctx.font = "32px PingFangSC-Regular";
ctx.textAlign = "left";
ctx.fillText("這是一些文字", 280, 755);
圖片繪制
官方文檔如圖
詳細文檔請參考 canvas手冊
注意事項
- 圖片需要進行跨域處理,否則后期無法生成圖片,也就是在img標簽中增加crossOrigin屬性,值為anonymous
const instBanner = document.getElementById("instBanner");
instBanner.crossOrigin = "anonymous";
- 需要等到圖片加載完成再畫到畫布上,否則有可能沒畫上去
const posterBg = new Image();
posterBg.src = mainBg;
posterBg.onload = () => {
ctx.drawImage(posterBg, 0, 0, 750, 1164);
}
完整代碼示例
const posterBg = new Image();
posterBg.src = 'https:....'; //這里是圖片url
posterBg.crossOrigin = "anonymous";
posterBg.onload = () => {
ctx.drawImage(posterBg, 0, 0, 750, 1164);
}
生成圖片
替換img src
let dataURL = c.toDataURL("image/png");
let canvasImg = document.getElementById("canvasImg");
canvas.src = dataURL;
上傳服務器,得到img url(可作為參數,保存圖片)
let dataURL = c.toDataURL("image/png");
function getImgUrl(dataURL){
//一些上傳服務器的代碼
return imgUrl
}
let imgUrl = getImgUrl();
let canvasImg = document.getElementById("canvasImg");
canvas.src = imgUrl;
最后奉上一些,常用的canvas處理方法
圓形圖片的繪制
ctx.save();
ctx.beginPath(); //開始繪制
//先畫個圓 前兩個參數確定了圓心 (x,y) 坐標 第三個參數是圓的半徑 四參數是繪圖方向 默認是false,即順時針
ctx.arc(60, 60, 30, 0 * Math.PI, 2 * Math.PI);
ctx.clip();//畫好了圓 剪切 原始畫布中剪切任意形狀和尺寸。一旦剪切了某個區域,則所有之后的繪圖都會被限制在被剪切的區域內 這也是我們要save上下文的原因
ctx.drawImage('https:....', 30, 30, 60, 60);
contex.restore(); //恢復之前保存的繪圖上下文 恢復之前保存的繪圖上下午即狀態 還可以繼續繪制
圓角矩形繪制
/**該方法用來繪制圓角矩形
*@param cxt:canvas的上下文環境
*@param x:左上角x軸坐標
*@param y:左上角y軸坐標
*@param width:矩形的寬度
*@param height:矩形的高度
*@param radius:圓的半徑
*@param lineWidth:線條粗細
*@param strokeColor:線條顏色
**/
function strokeRoundRect(cxt,x,y,width,height,radius,/*optional*/lineWidth,/*optional*/strokeColor){
//圓的直徑必然要小於矩形的寬高
if(2*radius>width || 2*radius>height){return false;}
cxt.save();
cxt.translate(x,y);
//繪制圓角矩形的各個邊
drawRoundRectPath(cxt,width,height,radius);
cxt.lineWidth = lineWidth||2;//若是給定了值就用給定的值否則給予默認值2
cxt.strokeStyle=strokeColor||"#000";
cxt.stroke();
cxt.restore();
}
/**該方法用來繪制一個有填充色的圓角矩形
*@param cxt:canvas的上下文環境
*@param x:左上角x軸坐標
*@param y:左上角y軸坐標
*@param width:矩形的寬度
*@param height:矩形的高度
*@param radius:圓的半徑
*@param fillColor:填充顏色
**/
function fillRoundRect(cxt,x,y,width,height,radius,/*optional*/fillColor){
//圓的直徑必然要小於矩形的寬高
if(2*radius>width || 2*radius>height){return false;}
cxt.save();
cxt.translate(x,y);
//繪制圓角矩形的各個邊
drawRoundRectPath(cxt,width,height,radius);
cxt.fillStyle=fillColor||"#000";//若是給定了值就用給定的值否則給予默認值
cxt.fill();
cxt.restore();
}
function drawRoundRectPath(cxt,width,height,radius){
cxt.beginPath(0);
//從右下角順時針繪制,弧度從0到1/2PI
cxt.arc(width-radius,height-radius,radius,0,Math.PI/2);
//矩形下邊線
cxt.lineTo(radius,height);
//左下角圓弧,弧度從1/2PI到PI
cxt.arc(radius,height-radius,radius,Math.PI/2,Math.PI);
//矩形左邊線
cxt.lineTo(0,radius);
//左上角圓弧,弧度從PI到3/2PI
cxt.arc(radius,radius,radius,Math.PI,Math.PI*3/2);
//上邊線
cxt.lineTo(width-radius,0);
//右上角圓弧
cxt.arc(width-radius,radius,radius,Math.PI*3/2,Math.PI*2);
//右邊線
cxt.lineTo(width,height-radius);
cxt.closePath();
}
» 點擊閱讀原文