原理:是使用地图的view.takeScreenshot方法返回地图的图像,再创建一个新的画布,然后把生成的地图图形putImageData到画布里。
效果图:(图上黑色是后来编辑添加上去的,怕涉密,哈哈!)
开始打印出图:
/**
* 开始执行打印出图
* @param {*} priter_width 设置图片的宽度
* @param {*} priter_height 设置图片的高度
* @param {*} pixelRatio 分辨率
*/
function startPrint(priter_width, priter_height, pixelRatio) {
require(["esri/geometry/Point",
"esri/geometry/support/webMercatorUtils",
"utils/GisCommon"], function (Point, webMercatorUtils, GisCommon) { /* code goes here */
//把度格式分为度分秒的接口
var gisUnit = new GisCommon();
var c = document.createElement("CANVAS");
c.id = "printC";
//document.body.appendChild(c);
if (true) {
var options = {
width: priter_width * pixelRatio,
height: priter_height * pixelRatio
};
//selectExtent 使用GIS的draw的Rect框选出的范围extent
if (selectExtent) {
//把点坐标转为平面坐标
var ltPoint = new Point({ x: selectExtent.xmin, y: selectExtent.ymax });
var _ltPoint = viewer.toScreen(ltPoint);
//设置打印的平面范围xy与大小
options = {};
options.area = {
x: _ltPoint.x,
y: _ltPoint.y,
width: priter_width * pixelRatio,
height: priter_height * pixelRatio
}
}
/* if(viewer.map.layers.length){
options.layers = viewer.map.layers;
} */
viewer.takeScreenshot(options).then(function (screenshot) {
var cWidth = screenshot.data.width;
var cheight = screenshot.data.height;
//第一个框的边距
var padding = (widgetConfig.mapborder && widgetConfig.mapborder.padding) ? widgetConfig.mapborder.padding : 10;
//内外边框的间隔
var borderWidth = (widgetConfig.mapborder && widgetConfig.mapborder.borderWidth) ? widgetConfig.mapborder.borderWidth : 50;
//标题高度
var titleHeight = (widgetConfig.mapborder && widgetConfig.mapborder.titleHeight) ? widgetConfig.mapborder.titleHeight : 25;
cWidth = cWidth + borderWidth + padding
cheight = cheight + borderWidth + padding + titleHeight;
c.width = cWidth;
c.height = cheight;
c.style.backgroundColor = "#FFF";
var ctx = c.getContext("2d");
ctx.rect(0, 0, cWidth, cheight);
ctx.fillStyle = "#FFF";
ctx.fill();
ctx.putImageData(screenshot.data, (padding + borderWidth) / 2, (padding + borderWidth) / 2 + titleHeight);
drawCanvas(c, ctx, cWidth, cheight, padding, titleHeight, borderWidth, webMercatorUtils, gisUnit);
});
}
});
}
制作图片的内容方法:
/**
* 生成Canvas
* @param {*} c 创建的Canvas
* @param {*} ctx Canvas的2D内容
* @param {*} cWidth 图片宽度
* @param {*} cheight 图片高度
* @param {*} padding 边距
* @param {*} titleHeight 标题高度
* @param {*} borderWidth 内外边框的间隔
* @param {*} webMercatorUtils
* @param {*} gisUnit
*/
function drawCanvas(c, ctx, cWidth, cheight, padding, titleHeight, borderWidth, webMercatorUtils, gisUnit) {
var box = 2, box2 = 5;
var sleep = 0;
var nx = (padding / 2) + (borderWidth / 2), ny = (padding + borderWidth) / 2 + titleHeight;
var nwidth = cWidth - padding - borderWidth, nheight = cheight - padding - titleHeight - borderWidth;
ctx.strokeStyle = '#000'; //strokeStyle设置边框颜色
//绘制外边框
if (borderWidth > 0) {
ctx.strokeRect((padding / 2), (padding / 2) + titleHeight, cWidth - padding, cheight - padding - titleHeight);
}
//绘制内边框
ctx.strokeRect(nx, ny, nwidth, nheight);
ctx.fillStyle = "#000";
ctx.textBaseline = "alphabetic";
ctx.texAlign = "center";
ctx.font = "bold 20px SimSun";
ctx.fillText($('.priter-title').val(), (cWidth / 2), titleHeight);
//显示内框四角坐标
if (true || widgetConfig.mapborder && widgetConfig.mapborder.bboxCoord) {
var extent = selectExtent == null ? webMercatorUtils.webMercatorToGeographic(viewer.extent) : selectExtent;
//左上角坐标
ctx.font = "14px SimSun";
ctx.fillText(gisUnit.formatDegree(extent.xmin, true), nx + box2, ny - box);
ctx.save();
var lbl = gisUnit.formatDegree(extent.ymax, true);
var strwidth = ctx.measureText(lbl).width;
ctx.translate(nx - box2, ny + strwidth);
f(-90, lbl);
ctx.restore();
//右上角坐标
ctx.fillText(gisUnit.formatDegree(extent.xmax, true), nx + nwidth - strwidth - box2 * 2, ny - box);
ctx.save();
ctx.translate(nx + nwidth + box2 * 2.5, ny + strwidth);
f(-90, lbl);
ctx.restore();
//左下角坐标
ctx.fillText(gisUnit.formatDegree(extent.xmin, true), nx, ny + nheight + box2 * 2.5);
lbl = gisUnit.formatDegree(extent.ymin, true);
strwidth = ctx.measureText(lbl).width;
ctx.save();
ctx.translate(nx - box2, ny + nheight);
f(-90, lbl);
ctx.restore();
//右下角坐标
ctx.fillText(gisUnit.formatDegree(extent.xmax, true), nx + nwidth - strwidth - box2, ny + nheight + box2 * 2.5);
ctx.save();
ctx.translate(nx + nwidth + box2 * 2.5, ny + nheight);
f(-90, lbl);
ctx.restore();
}
//图例
var leng = $(".esri-legend__service").parent();
if ($(".esri-legend__service").length || (widgetConfig.mapborder && widgetConfig.mapborder.legend)) {
ctx.save();
ctx.fillStyle = "#FFF";
var mn = 70;
var lengy = ny + nheight - leng.height() + mn;
var lengwidth = leng.width();
var length2 = lengwidth / 3;
var lengPadd = 10, lblheight = 22;
ctx.fillRect(nx + 1, lengy, lengwidth + 1, leng.height() - mn);
ctx.strokeRect(nx + 1, lengy, lengwidth + 1, leng.height() - mn);
ctx.restore();
ctx.save();
ctx.fillStyle = "#000";
ctx.textBaseline = "middle";
ctx.texAlign = "center";
var rowtotal = 0;
var loadInt = 0;
$(".esri-legend__service").each(function (i) {
sleep++;
var title = $(this).children()[0].innerHTML;
var rows = $(this).children("div.esri-legend__layer").children().children("div.esri-legend__layer-body").children();
var txty = lengy + lengPadd;
if (i > 0) {
var liney = lengy + lengPadd + (lblheight * (i + 1)) + (rowtotal * 33);
txty = lengy + lengPadd + (lblheight * (i + 1)) + (rowtotal * 33) + 10;
ctx.beginPath();
ctx.moveTo(nx, liney);
ctx.lineTo(nx + lengwidth, liney);
ctx.stroke();
}
ctx.font = "bold 14px SimSun";
ctx.fillText(title, nx + 5 + length2, txty);
rowtotal += rows.length;
ctx.font = "12px SimSun";
ctx.save();
ctx.textBaseline = "Top";
rows.map(function (index, row) {
var svg = $(row).find("svg");
var svgimg = new Image();
var rowname = $($(row).children()[1]).html();
var serializer = new XMLSerializer()
var toExport = svg[0].cloneNode(true); // 克隆
var bb = svg[0].getBBox(); // getBBox方法返回一个包含svg元素的最小矩形的坐标对象。 包含(x,y)、width、height 需要用来解决svg中的图超出边界时无法全部完整保存问题
toExport.setAttribute('viewBox', (bb.x - 20) + ' ' + (bb.y - 20) + ' ' + (bb.width + 40) + ' ' + (bb.height + 40)); // 重新设置svg目前的视口
toExport.setAttribute('width', bb.width + 36); // 重新设置svg目前的宽度
toExport.setAttribute('height', bb.height + 36); // 重新设置svg目前的高度
var source = '<?xml version="1.0" standalone="no"?>\r\n' + serializer.serializeToString(toExport);
svgimg.src = "data:image/svg+xml;charset=utf-8," + encodeURIComponent(source);
svgimg.alt = escape2Html(rowname);
svgimg.setAttribute("name", txty);
svgimg.setAttribute("i", i);
svgimg.setAttribute("index", index);
svgimg.onload = function (evt) {
var numser = parseInt($(evt.target).attr("name"));
var iI = parseInt($(evt.target).attr("i"));
var indexI = parseInt($(evt.target).attr("index"));
var svgy = numser + (23 * indexI);
ctx.drawImage(svgimg, nx, svgy + (indexI * 10));
//ctx.save();
ctx.fillText($(evt.target).attr("alt"), nx + svgimg.width - 8, svgy + (svgimg.height / 2) + 5 + (indexI * 10));
loadInt++;
if (loadInt == rowtotal) {
exportRaw("printer.png", c.toDataURL());
}
}
});
});
ctx.restore();
}
//指北针
if (true || widgetConfig.mapborder && widgetConfig.mapborder.compass) {
ctx.save();
//<img id="zhibeiz" src="images/zhibeiz64.png" style="display: none;" />
var img = document.getElementById("zhibeiz");
ctx.drawImage(img, nx + nwidth - 150, ny + 60);
ctx.restore();
}
//比例尺
if (true || widgetConfig.mapborder && widgetConfig.mapborder.scale) {
ctx.save();
var scale = "1:" + (viewer.scale).toFixed("");
ctx.fillStyle = "#FFF";
ctx.fillRect((cWidth / 2), ny + nheight - 25, ctx.measureText(scale).width + 10, 25);
ctx.strokeRect((cWidth / 2), ny + nheight - 25, ctx.measureText(scale).width + 10, 25);
ctx.fillStyle = "#000";
ctx.textBaseline = "middle";
ctx.texAlign = "center";
ctx.fillText(scale, (cWidth / 2) + 5, ny + nheight - 12);
ctx.restore();
}
if (sleep == 0) { exportRaw("printer.png", c.toDataURL()); }
function f(i, txt) {
var deg = Math.PI / 180 * i
ctx.rotate(deg)
/**
1. 中心点移动到文字正中
2. 坐标(0,0)时,中心点为文字左下角点
3. 所以:横坐标左移一半长,纵坐标下移一半宽
*/
ctx.fillText(txt, 0, 0);
}
}
/**
* html编码转html字符
* @param {*} str
* @returns
*/
function escape2Html(str) {
var arrEntities={'lt':'<','gt':'>','nbsp':' ','amp':'&','quot':'"'};
return str.replace(/&(lt|gt|nbsp|amp|quot);/ig,function(all,t){return arrEntities[t];});
}
导出下载图片:
function fakeClick(obj) {
var ev = document.createEvent("MouseEvents");
ev.initMouseEvent("click", true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
obj.dispatchEvent(ev);
selectExtent = null;
}
function exportRaw(name, data) {
//var urlObject = window.URL || window.webkitURL || window;
//var export_blob = new Blob([data]);
var save_link = document.createElementNS("http://www.w3.org/1999/xhtml", "a")
save_link.href = data;//urlObject.createObjectURL(export_blob);
save_link.download = name;
fakeClick(save_link);
}