先說(shuō)下我的功能需求充蓝,大家看看和大家的是否相同,能否借鑒。
下面是我的整個(gè)的思路過(guò)程谓苟,如果想直接找解決方案官脓,直接看方案三。
功能需求:
添加一個(gè)按鈕涝焙,點(diǎn)擊按鈕時(shí)卑笨,將拓?fù)鋱D保存為圖片文件并導(dǎo)出。
就是將在svg畫(huà)布上畫(huà)的圖仑撞,保存成圖片并導(dǎo)出赤兴。
問(wèn)題描述:
在svg畫(huà)布上畫(huà)的拓?fù)鋱D,每個(gè)節(jié)點(diǎn)使用的是圖片隧哮,將整個(gè)svg導(dǎo)出時(shí)桶良,導(dǎo)出的圖片文件上面不顯示節(jié)點(diǎn)圖片。如圖1-1近迁、1-2:
我svg中繪制過(guò)程中艺普,引入圖片的代碼如圖1-3:
圖片放在static下面,如圖1-4:
方案思路:
方案一:無(wú)須引入插件
首先是制造一個(gè)button鉴竭,用的element的框架歧譬。
<el-button size = 'mini' type="primary" @click="saveSvgToPng" v-loading.fullscreen.lock="fullscreenLoading">導(dǎo)出圖片</el-button>
然后寫(xiě)這個(gè)點(diǎn)擊事件響應(yīng)函數(shù):
saveSvgToPng: function () {
//采用直接轉(zhuǎn)成canvas的方式
let width = 1000;
let height = 666;
var serializer = new XMLSerializer();
var source = '<?xml version="1.0" standalone="no"?>\r\n'+serializer.serializeToString(svg.node());
var image = new Image();
image.src = "data:image/svg+xml;charset=utf-8," + encodeURIComponent(source);
var canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
var context = canvas.getContext("2d")
image.onload = function(){
context.drawImage(image, 0, 0);
var a = document.createElement("a");
a.download = "aaaa.png";
a.href = canvas.toDataURL('image/png');
a.click();
}
},
導(dǎo)出內(nèi)容如圖1-2,未顯示網(wǎng)元節(jié)點(diǎn)圖片搏存。未搞清楚原因瑰步,查了一些資料,好像是因?yàn)閏anvas畫(huà)布被污染了璧眠,所以無(wú)法使用toDataURL這種方法了缩焦。而canvas畫(huà)布被污染的原因好像是因?yàn)閟vg中網(wǎng)元節(jié)點(diǎn)圖片跨域了,我現(xiàn)在有這個(gè)疑問(wèn):在static下面的圖片责静,存在跨域問(wèn)題嗎袁滥,因?yàn)槲覍?dǎo)出的時(shí)候,并沒(méi)有報(bào)出跨域的錯(cuò)誤灾螃。
然后我又嘗試了方案二:
方案二:使用插件html2canvas
按照官網(wǎng)步驟题翻,引入html2canvas插件,修改html結(jié)構(gòu)腰鬼,將svg放入一個(gè)div內(nèi)嵌赠,并給div一個(gè)ref標(biāo)簽,便于引用熄赡,如圖1-5.
然后修改點(diǎn)擊響應(yīng)函數(shù)姜挺,代碼如下:
函數(shù)1:
dataURLToBlob: function (dataurl) {
var arr = dataurl.split(',');
var mime = arr[0].match(/:(.*?);/)[1];
var bstr = atob(arr[1]);
var n = bstr.length;
var u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], {type: mime})
},
單擊響應(yīng)函數(shù)2:
catchSvgToPng: function () {
const _this = this
let a = document.createElement('a');
setTimeout(() => {
// 此處用于解決截圖不清晰問(wèn)題,將生成的canvas放大彼硫,然后再填充到原有的容器中就會(huì)清晰
const width = 1000;
const height = 400;
const canvas2 = document.createElement('canvas');
const scale = 2;
canvas2.width = width * scale;
canvas2.height = height * scale;
const context1 = canvas2.getContext('2d')
if(context1) {
context1.scale(scale, scale);
}
const opts = {
scale,
canvas: canvas2,
// logging: true, //日志開(kāi)關(guān)炊豪,便于查看html2canvas的內(nèi)部執(zhí)行流程
width,
height,
// 【重要】開(kāi)啟跨域配置
useCORS: true
};
html2canvas(_this.$refs.imageWrapper,opts).then((canvas) => {
const context = canvas2.getContext('2d');
if(context) {
context.scale(2,2);
context.mozImageSmoothingEnabled = false;
context.webkitImageSmoothingEnabled = false;
context.imageSmoothingEnabled = false;
}
// canvas轉(zhuǎn)換成url凌箕,然后利用a標(biāo)簽的download屬性,直接下載词渤,繞過(guò)上傳服務(wù)器再下載
// _this.screenUrl = canvas.toDataURL()
// var imgBlob = canvas.toDataURL('image/jpeg', 1.0); //將圖片轉(zhuǎn)為base64
// imgBlob = imgBlob.toString().substring(imgBlob.indexOf(",") + 1);//截取base64以便上傳
let blob = _this.dataURLToBlob(canvas.toDataURL('image/jpeg', 1.0));
a.setAttribute("href", URL.createObjectURL(blob));
a.setAttribute("download", "xxxxxx.png");
document.body.appendChild(a);
a.click();
URL.revokeObjectURL(blob);
document.body.removeChild(a);
});
},1000)
},
導(dǎo)出的圖片如圖1-6所示:
導(dǎo)出的圖片依然無(wú)網(wǎng)元節(jié)點(diǎn)圖片陌知,已經(jīng)按照網(wǎng)上查到的資料,對(duì)污染的canvas進(jìn)行處理掖肋,不讓canvas被污染,依然沒(méi)有效果∩筒危現(xiàn)在不清楚是什么原因?qū)е碌膶?dǎo)出的圖片無(wú)節(jié)點(diǎn)圖片志笼,因此也不知如何解決。
這個(gè)問(wèn)題到這里已經(jīng)困擾了我將近一周之久把篓,查了好多資料纫溃,試了又試,像一支無(wú)頭蒼蠅一樣撞來(lái)撞去韧掩,毫無(wú)頭緒紊浩。因?yàn)橹翱茖W(xué)上網(wǎng)的軟件到期了,一直沒(méi)有續(xù)費(fèi)疗锐,所以之前的查資料都是在百度上進(jìn)行坊谁。
在這里!;口芍!強(qiáng)烈建議大家科學(xué)上網(wǎng)!9途怼鬓椭!當(dāng)我把軟件續(xù)費(fèi)以后,用谷歌重新試著查詢(xún)之前的資料关划,發(fā)現(xiàn)之前嘗試的一種插件小染,但苦于沒(méi)有找到例子而不知道怎么使用,就一直未動(dòng)贮折。當(dāng)我谷歌出使用流程以后裤翩,我抱著試一試的心態(tài)重新試了一下,這就是我的方案三脱货。
方案二:使用插件saveSvgAsPng
廢話不多說(shuō)岛都,上個(gè)官網(wǎng)網(wǎng)址,寫(xiě)的很清楚振峻。
github:https://github.com/exupero/saveSvgAsPng
翻譯版本:https://www.helplib.com/GitHub/article_110596
按照這上面的提示臼疫,一步步操作。
1.用npm把插件裝上
npm install save-svg-as-png
2.在需要使用的vue文件中把js文件import進(jìn)來(lái)
import saveSvg from 'save-svg-as-png';
3.對(duì)之前的按鈕點(diǎn)擊響應(yīng)函數(shù)進(jìn)行編寫(xiě)
saveSvgToPng: function () {
//調(diào)研使用saveSvgAsPng 的方式
saveSvg.saveSvgAsPng(document.getElementById("topologySvg"), "diagram.png",{height:800});
},
官網(wǎng)上面給的例子直接使用的
saveSvgAsPng(document.getElementById("topologySvg"), "diagram.png")
但是這樣的話扣孟,在我的vue框架下烫堤,是顯示這個(gè)方法無(wú)效,所以需要使用前面import的文件名來(lái)進(jìn)行調(diào)用。
我們調(diào)轉(zhuǎn)這個(gè)函數(shù)鸽斟,看下怎么回事桅狠。
out$.saveSvgAsPng = (el, name, options) => {
requireDomNode(el);
out$.svgAsPngUri(el, options || {}, uri => out$.download(name, uri));
};
這個(gè)是引入插件中該方法的位置,很顯然該方法需要三個(gè)參數(shù)翁脆,操作的元素尚镰、保存的文件名稱(chēng)以及一些參數(shù)。至于具體可以設(shè)置哪些參數(shù)來(lái)控制導(dǎo)出的png圖片立倍,官網(wǎng)給了一個(gè)清單灭红,寫(xiě)的很清楚。比如我們想設(shè)置導(dǎo)出圖片的寬度和高度為我們想要的值口注,就可以這么寫(xiě):
saveSvg.saveSvgAsPng(document.getElementById("topologySvg"), "diagram.png",{height:800,width:1400});
至此变擒,該功能就實(shí)現(xiàn)了,一行代碼可以搞定的功能琢磨了一周多寝志,以后一定要科學(xué)上網(wǎng)=堪摺!材部!百度真得往后稍稍毫缆。