1.需求分析:
把用户在ueditor里面编辑好的文本的html代码转化为长图;
2.技术分析:
这里主要用到了html2canvas.js,官网地址:http://html2canvas.hertzen.com/;
3.技术支持:
Firefox 3.5+
Google Chrome
Opera 12+
IE9+
Safari 6+
4.具体实践:
(1).首先是了解对html2canvas.js的初步使用:
//参数说明:id:所需要截图的元素id
html2canvas(document.getElementById('id')).then(function(canvas){
document.body.appendChild(canvas);
});
基本参数说明,官网上都有,具体可以参照官网说明,这里不再做详细解释;
(2).通过以上的配置,其实可以简单的实现生成长图的功能,但这里有几个坑需要说明一下;
- 截图不清楚(这是很大的一个问题):
通过上网查询相关资料以及熟悉源码,发现,它是通过在canvas上模拟dom结构以及样式来绘制成的canvas画布,那么,想让画布清晰,我们可以在canvas.toDataURL(type, encoderOptions);
时做一些操作,先来看一下这个api的语法:
那么这样一看,想配置图片质量可以通过:
canvas.toDataURL("image/jpeg", 1.0);
不过在我经过大量实践之后,发现图片的清晰度并没有多大的改善,反而生成的图片越来越大,那么这肯定不是我们想要的,被pass掉;
解决方案:
通过修改源码,让canvas可以配置放大比例,主要修改的有两处:
==>代码第 999 行 renderWindow 的方法中 修改判断条件 增加一个options.scale存在的条件:
源码:
if (options.type === "view") {
canvas = crop(renderer.canvas, {width: renderer.canvas.width, height: renderer.canvas.height, top: 0, left: 0, x: 0, y: 0});
} else if (node === clonedWindow.document.body || node === clonedWindow.document.documentElement || options.canvas != null) {
canvas = renderer.canvas;
} else {
canvas = crop(renderer.canvas, {width: options.width != null ? options.width : bounds.width, height: options.height != null ? options.height : bounds.height, top: bounds.top, left: bounds.left, x: 0, y: 0});
}
修改为:
if (options.type === "view") {
canvas = crop(renderer.canvas, {width: renderer.canvas.width, height: renderer.canvas.height, top: 0, left: 0, x: 0, y: 0});
} else if (node === clonedWindow.document.body || node === clonedWindow.document.documentElement) {
canvas = renderer.canvas;
}else if(options.scale && options.canvas !=null){
log("放大canvas",options.canvas);
var scale = options.scale || 1;
canvas = crop(renderer.canvas, {width: bounds.width * scale, height:bounds.height * scale, top: bounds.top *scale, left: bounds.left *scale, x: 0, y: 0});
}
else {
canvas = crop(renderer.canvas, {width: options.width != null ? options.width : bounds.width, height: options.height != null ? options.height : bounds.height, top: bounds.top, left: bounds.left, x: 0, y: 0});
}
==>代码第 943 行 html2canvas 的方法中 修改width,height:
源码:
return renderDocument(node.ownerDocument, options, node.ownerDocument.defaultView.innerWidth, node.ownerDocument.defaultView.innerHeight, index).then(function(canvas) {
if (typeof(options.onrendered) === "function") {
log("options.onrendered is deprecated, html2canvas returns a Promise containing the canvas");
options.onrendered(canvas);
}
return canvas;
});
修改为:
width = options.width != null ? options.width : node.ownerDocument.defaultView.innerWidth;
height = options.height != null ? options.height : node.ownerDocument.defaultView.innerHeight;
return renderDocument(node.ownerDocument, options, width, height, index).then(function(canvas) {
if (typeof(options.onrendered) === "function") {
log("options.onrendered is deprecated, html2canvas returns a Promise containing the canvas");
options.onrendered(canvas);
}
return canvas;
});
使用方法:
var realHtml = document.getElementById("html-canvas");//需要截图的包裹的(原生的)DOM 对象
var width = realHtml.offsetWidth; //获取dom 宽度
var height = realHtml.offsetHeight; //获取dom 高度
var canvas = document.createElement("canvas"); //创建一个canvas节点
var scale = 2; //定义任意放大倍数 支持小数
canvas.width = width * scale; //定义canvas 宽度 * 缩放
canvas.height = height * scale; //定义canvas高度 *缩放
canvas.getContext("2d").scale(scale,scale); //获取context,设置scale
var opts = {
tainttest:true, //检测每张图片都已经加载完成
scale:scale, // 添加的scale 参数
useCORS:true,
canvas:canvas, //自定义 canvas
logging: true, //日志开关
width:width, //dom 原始宽度
height:height //dom 原始高度
};
html2canvas(realHtml, opts).then(function (canvas) {
//如果想要生成图片 引入canvas2Image.js 下载地址:
//https://github.com/hongru/canvas2image/blob/master/canvas2image.js
//var img = Canvas2Image.convertToImage(canvas, canvas.width, canvas.height);
imgUri = canvas.toDataURL("image/"+img_type).replace("image/"+img_type, "image/octet-stream");
//var saveLink = document.createElement('a');
//saveLink.href =imgUri;
//saveLink.download = 'ipaiban'+new Date().getTime()+'.'+img_type;
// saveLink.click();
$('#img').attr('src',imgUri);
//console.log(img);
//Canvas2Image.saveAsJPEG(canvas, canvas.width, canvas.height);
//localStorage.removeItem("img-html");
//localStorage.removeItem('img-type');
//localStorage.removeItem('canvas_multiple');
});
通过以上修改之后,还会出现一个更大的问题,关于截图不完整的问题:
上面的配置之后,我们的需要截取的div结构,必须是从左上角页面坐标(0,0)开始的,这里我使用定位index为负数,在Body下面用absolute定位一个层级,把ueditor中的代码取出来放到这个定位的层级中,然后拿这个层级中的div去生成长图;
事实证明,我的想法是正确的,但是实际操作中还是碰到了一个问题,我在本地测试完美,而放入编辑器页面还是会出现一些莫名其妙的问题,最后思来想去,可能是编辑器页面的结构以及样式影响到了这个,所以决定新开一个页面去生成长图,正好还可以用来后续的分享到微博使用。关于图片的跨域问题:
初步使用配置项useCORS:true,
去解决,另外,源码中我也做了一些修改,现在忘了改的哪个地方了,=0=,回头我再找找;
好了,通过以上的操作,基本已经完美解决了前端生成长图的功能,当然,具体的需求和选择样式部分还是需要具体的代码去实践的,这里不在做详细介绍;
相关文件修改目录:
页面文件:
bianji.jsp
ps:现在还属于测试期间,我又复制了一份bianji.jsp,命名为editor.jsp供用户测试使用,和bianji.jsp放在同级目录下,页面中已经做了区域注释,可以搜索关键字create-img-dialog
,可以快速找到相应的html代码;具体生成长图的文件:
imgDownload.html
ps:真正长图生成的过程在这个文件中;js需求逻辑文件:
newindex/js/page.toolbarnew_minimalist.js
ps:放在了文件的开头,我已做了详细的注释以及区域注释css样式文件:
newindex/css/page.loadnew_1.css
ps:写在了文件的最后,已经添加了区域注释,class几乎都是以ld-开头命名;img图片文件:
统一放到了images目录下,方便后期的维护;
ps:开发中想的比较多,现在总结文档可能有一些遗漏。