Retour à la documentation
define([
//mapped libs
"dojo/_base/declare", "dijit/_WidgetBase", "dojo/_base/array", "dojo/_base/lang",
"spw/api/SpwViewer", "dojo/query", "dojo/dom-style", "dojo/dom-geometry",
"dojo/dom-construct", "dojo/dom-attr", "spw/api/MessageManager", "esri/tasks/PrintTask",
"esri/tasks/PrintTemplate", "esri/tasks/PrintParameters", "dojo/Deferred", "esri/geometry/Point", "dojo/on", "esri/geometry/Extent",
"dojo/_base/config", "spw/libs/html2canvas", "spw/api/Utils",
//unmapped libs
"spw/libs/rgbcolor","spw/libs/StackBlur",
"spw/libs/canvg", "dojo/NodeList-traverse", "spw/libs/es6-promise.min", "spw/libs/es6-promise.auto.min"],
function (declare, _WidgetBase, array, lang, SpwViewer, query, domStyle, geom,
domConstruct, domAttr, MessageManager, PrintTask, PrintTemplate, PrintParameters,
Deferred, Point, on, Extent, dojoConfig, html2canvas, Utils) {
var Printer = declare("spw.api.Printer", [_WidgetBase], /** @lends spw.api.Printer */{
/**
* Permet de définir si l'image doit être redimensionnée ou coupée.
* @public
* @instance
* @type Boolean
*/
crop: true,
/**
* Element du DOM à capturer
* @public
* @instance
* @type DomElement
*/
domToPrint: null,
/**
* Fonction de retour lorsque l'image a été générée
* @private
* @instance
* @type Function
*/
successHandler: null,
/**
* Longueur de l'image à générer en pixel
* @private
* @instance
* @type Integer
*/
imageWidth: 400,
/**
* Hauteur de l'image à générer en pixel
* @private
* @instance
* @type Integer
*/
imageHeight: 400,
stylesToReset: [],
currentReportParams: null,
nodesToReposition: ['.esriControlsBR'],
/**
* @constructs
* @extends {dijit._WidgetBase}
* @classdesc Classe utilitaire pour gérer l'impression de la carte.
* @param {Object} config
* @param {Boolean} config.crop {@link spw.api.Printer#crop}
* @param {DomElement} config.domToPrint {@link spw.api.Printer#domToPrint}
*/
constructor: function(config){
this.domToPrint = SpwViewer.getInstance().get('spwMap').get('esriMap').root;
},
/**
* Permet de générer l'image de la carte sur base d'un PrintTask type Esri.
* @inner
* @param serverUrl {String} L'url du serveur "PrintTask" Esri
* @param imageWidth {Integer} Longueur de l'image à générer
* @param imageHeight {Integer} Hauteur de l'image à générer
* @param successHandler {Function} Callback de retour en cas de réussite
* @param errorHandler {Function} Callback de retour en cas d'échec
*/
getImagePrintTask: function(serverUrl, imageWidth, imageHeight, successHandler, errorHandler){
var printTask = new PrintTask(serverUrl);
var template = new PrintTemplate();
template.exportOptions = {
width: imageWidth,
height: imageHeight,
dpi: 96
};
template.format = "png32";
var params = new PrintParameters();
params.map = SpwViewer.getInstance().get('spwMap').get('esriMap');
params.outSpatialReference = SpwViewer.getInstance().get('spatialReference');
params.template = template;
printTask.execute(params, successHandler, errorHandler);
},
beforeGetImage: function(){
this.oldCenterMap = SpwViewer.getInstance().get('spwMap').getCurrentExtent().getCenter()
},
afterGetImage: function(){},
/**
* Permet de générer une image de l'élément passé en paramètre via la balise Canvas HTML5
* @param {DomElement} domToPrint l'élément à capturer
* @param {Number} imageWidth la largeur de l'image
* @param {Number} imageHeight la hauteur de l'image
* @param crop {Boolean} si l'image doit être rognée
* @param successHandler le handler en cas de réussite.
*/
getImage: function(domToPrint, imageWidth, imageHeight, crop, extent, successHandler, rosaceUrl, printComesFromIdentify) {
this.beforeGetImage();
var templateItem = {imageWidth: imageWidth, imageHeight: imageHeight};
if(rosaceUrl == null){
rosaceUrl = "./images/templates/rosaces.png";
}
this.stylesToReset.length = 0;
// compatibilité ?
var oldExtent = SpwViewer.getInstance().get('spwMap').getCurrentExtent();
if (successHandler == null && typeof(extent) === 'function') {
successHandler = extent;
extent = null;
}
if(successHandler){
this.successHandler = successHandler;
} else {
console.error("No print callback. Printing is cancelled.");
return;
}
if(domToPrint){
this.domToPrint = domToPrint;
}
if(imageWidth){
this.imageWidth = imageWidth;
}
if(imageHeight){
this.imageHeight = imageHeight;
}
this.crop = crop;
if(printComesFromIdentify){
MessageManager.getInstance().displayModalMessage("Nous préparons votre rapport.<br>Cela peut prendre quelques secondes…");
}else{
MessageManager.getInstance().displayModalMessage("Nous préparons votre carte.<br>Cela peut prendre quelques secondes…");
}
if(!this.crop){
this.renderMapCanvas(null, rosaceUrl, templateItem);
} else {
var spwMap = SpwViewer.getInstance().get('spwMap');
this.recalculateMap().then(lang.hitch(this, function(domItemOverflowed) {
if (spwMap.isUpdating()) {
var mapUpdateEndHandler = spwMap.on(spwMap.events.MapUpdateEnd, lang.hitch(this, function(){
if (!spwMap.isUpdating()) {
domStyle.set(SpwViewer.getInstance().get('spwMap').domNode, {
top: 0,
left: 0
});
this.renderMapCanvas(domItemOverflowed, rosaceUrl, templateItem).then(lang.hitch(this, function(canvas) {
MessageManager.getInstance().hideModalMessage();
successHandler(canvas);
this.afterGetImage();
}));
mapUpdateEndHandler.remove();
}
}));
}
else {
domStyle.set(SpwViewer.getInstance().get('spwMap').domNode, {
top: 0,
left: 0
});
this.renderMapCanvas(domItemOverflowed, rosaceUrl,templateItem).then(lang.hitch(this, function(canvas) {
MessageManager.getInstance().hideModalMessage();
successHandler(canvas);
this.afterGetImage();
}));
}
}));
}
},
resetWidgets: function() {
this.ws = SpwViewer.getInstance().spwWidgetsManager.getWidgets({
activated: true,
position: 'map'
});
array.forEach(this.ws, lang.hitch(this, function(w) {
w.hideOnPrint && domStyle.set(w.domNode, 'display', '');
if (w.mapPosition) {
domStyle.set(w.domNode, w.mapPosition);
}
}));
},
resetNodes: function() {
array.forEach(this.nodesToReposition, lang.hitch(this, function(nodeToReposition) {
var node = query(nodeToReposition)[0];
if (node && this.nodesOriginalPosition[nodeToReposition]) {
domStyle.set(node, this.nodesOriginalPosition[nodeToReposition]);
}
}));
},
repositionWidgets: function(imageWidth, imageHeight) {
var spwMap = SpwViewer.getInstance().get('spwMap');
var overflowW = (imageWidth - spwMap.getWidth()) / 2;
var overflowH = (imageHeight - spwMap.getHeight()) / 2;
this.ws = SpwViewer.getInstance().spwWidgetsManager.getWidgets({
activated: true,
position: 'map'
});
array.forEach(this.ws, lang.hitch(this, function(w) {
w.hideOnPrint && domStyle.set(w.domNode, 'display', 'none');
var mapPosition = w.mapPosition;
if (mapPosition) {
var top = parseInt(mapPosition.top);
var bottom = parseInt(mapPosition.bottom);
var right = parseInt(mapPosition.right);
var left = parseInt(mapPosition.left);
var style = {
top: isNaN(top) ? null : top + 'px',
left: isNaN(left) ? null : left + 'px',
right: isNaN(right) ? null : right + 'px',
bottom: isNaN(bottom) ? null : bottom + 'px'
};
if (overflowH < 0) {
if (!isNaN(bottom)) {
style.bottom = (bottom - overflowH) + 'px';
}
else if (!isNaN(top)) {
style.top = (top - overflowH) + 'px';
}
}
if (overflowW < 0) {
if (!isNaN(right)) {
style.right = (right - overflowW) + 'px';
}
else if (!isNaN(left)) {
style.left = (left - overflowW) + 'px';
}
}
domStyle.set(w.domNode, style);
}
}));
this.nodesOriginalPosition = {};
array.forEach(this.nodesToReposition, lang.hitch(this, function(nodeToReposition) {
var node = query(nodeToReposition)[0];
if (node) {
var top = parseInt(domStyle.get(node, 'top'));
var bottom = parseInt(domStyle.get(node, 'bottom'));
var right = parseInt(domStyle.get(node, 'right'));
var left = parseInt(domStyle.get(node, 'left'));
var style = {
top: isNaN(top) ? null : top + 'px',
left: isNaN(left) ? null : left + 'px',
right: isNaN(right) ? null : right + 'px',
bottom: isNaN(bottom) ? null : bottom + 'px'
};
if (style.top && style.bottom) {
delete style.top;
}
if (style.left && style.right) {
delete style.left;
}
this.nodesOriginalPosition[nodeToReposition] = lang.clone(style);
if (overflowH < 0) {
if (!isNaN(bottom)) {
style.bottom = (bottom - overflowH) + 'px';
}
else if (!isNaN(top)) {
style.top = (top - overflowH) + 'px';
}
}
if (overflowW < 0) {
if (!isNaN(right)) {
style.right = (right - overflowW) + 'px';
delete style.left;
}
else if (!isNaN(left)) {
style.left = (left - overflowW) + 'px';
}
}
domStyle.set(node, style);
}
}));
},
/**
* Transforme les éléments HTML en Canvas.
* @param domItemOverflowed les élements HTML à transformer
*/
renderMapCanvas: function(domItemOverflowed, rosaceUrl, template) {
var def = new Deferred();
this.repositionWidgets(template.imageWidth, template.imageHeight);
//var canvases = this._createSvgCanvases();
//timeout of 2 sec is set to ensure graphics are redraw on client screen => should be changed by the proper event (map-redrawed, ...)
setTimeout(function(){
query("img", this.domToPrint).forEach(function(i){
if((!i.style.opacity && i.style.opacity !== 0) && (i.parentNode.style.opacity || i.parentNode.style.opacity === 0)){
i.style.opacity = i.parentNode.style.opacity;
i.tempOpacity = true;
}
});
html2canvas(this.domToPrint, {
allowTaint: false,
logging: false,
proxy: SpwViewer.getInstance().get('proxyPageUrl'),
useCORS: true
}).then(function(canvas){
this.resetMap(domItemOverflowed);
//query('svg').forEach(function(svgTag){svgTag.style.display = svgTag['data-display'];delete svgTag['data-display'];});
//array.forEach(canvases, function(c){domConstruct.destroy(c);});
query("img", this.domToPrint).forEach(function(i){
if(i.tempOpacity){
delete i.style.opacity;
delete i.tempOpacity;
}
});
this._cropCanvas(canvas).then(lang.hitch(this, function(newCanvas) {
var isIe = Utils.testNavigatorIsIE();
if (isIe) {
require(["spw/libs/canvg"], function() {
var xmlSerializer = new XMLSerializer();
var spwMap = SpwViewer.getInstance().get('spwMap');
var overflowW = (template.imageWidth - spwMap.getWidth()) / 2;
var overflowH = (template.imageHeight - spwMap.getHeight()) / 2;
var canvasbis = document.createElement('canvas');
canvasbis.width = newCanvas.width;
canvasbis.height = newCanvas.height;
query('svg', this.domToPrint).forEach(function(svg) {
var stringSvg = xmlSerializer.serializeToString(svg);
canvg(canvasbis, stringSvg);
});
var destCtx = newCanvas.getContext('2d');
destCtx.drawImage(canvasbis, overflowW, overflowH);
this.getFinalImageCanvas(rosaceUrl, def, newCanvas);
}.bind(this))
} else {
this.getFinalImageCanvas(rosaceUrl, def, newCanvas);
}
}));
}.bind(this));
}.bind(this), 3000);
return def;
},
getFinalImageCanvas: function(rosaceUrl, def, newCanvas) {
var _rosaceUrl = './images/templates/rosaces.png';
if(rosaceUrl){
_rosaceUrl = rosaceUrl;
} else if(rosaceUrl === ""){
this.resetWidgets();
this.resetNodes();
def.resolve(newCanvas);
return;
}
try{
this.resetWidgets();
this.resetNodes();
var img = domConstruct.create('img', {
'src': _rosaceUrl
}, this.domNode);
var ctx = newCanvas.getContext('2d');
img.onload = lang.hitch(this, function () {
ctx.drawImage(img, -5, newCanvas.height - 67, 60, 60);
def.resolve(newCanvas);
})
img.onerror = lang.hitch(this, function(){
def.resolve(newCanvas);
})
}catch(e){
this.resetWidgets();
this.resetNodes();
def.resolve(newCanvas);
}
},
/**
* Transform les éléments SVG en Canvas
* @returns {Array}
*/
_createSvgCanvases: function() {
var canvases = [];
query('svg').forEach(function(svgTag){
var c = domConstruct.create('canvas', {style:'position: absolute;'}, svgTag, "after");
canvases.push(c);
var divSvg = domConstruct.create("div");
var clonedSvg = lang.clone(svgTag);
domAttr.set(clonedSvg, "xmlns:xlink","http://www.w3.org/1999/xlink");
divSvg.appendChild(clonedSvg);
canvg(c, divSvg.innerHTML);
svgTag['data-display'] = svgTag.style.display;
svgTag.style.display = 'none';
});
return canvases;
},
/**
* Recalcule la taille de la carte en fonction de la taille de l'image demandée.
* @returns {Array}
*/
recalculateMap: function() {
var spwMap = SpwViewer.getInstance().get('spwMap');
var overflowW = this.imageWidth - spwMap.getWidth();
var overflowH = this.imageHeight - spwMap.getHeight();
var node = spwMap.domNode;
var absoluteXY = {
x: 0,
y: 0
};
if (overflowW < 0) {
overflowW = 0;
}
if (overflowH < 0) {
overflowH = 0;
}
this.stylesToReset.push({
node: node,
style: {
position: domStyle.get(node, 'position'),
left: domStyle.get(node, 'left') + 'px',
top: domStyle.get(node, 'top') + 'px',
width: domStyle.get(node, 'width') + 'px',
height: domStyle.get(node, 'height') + 'px'
}
});
domStyle.set(node, {
position: 'absolute',
left: absoluteXY.x + 'px',
top: absoluteXY.y + 'px',
width: spwMap.getWidth() + overflowW + 'px',
height: spwMap.getHeight() + overflowH + 'px'
});
var domItemOverflowed = new Array();
query(SpwViewer.getInstance().get('spwMap').domNode).parents().forEach(function(item){
var overflowProp = domStyle.get(item, "overflow");
if(overflowProp == "hidden"){
domItemOverflowed.push([item, overflowProp]);
domStyle.set(item, "overflow", "visible");
}
});
var def = new Deferred();
spwMap.esriMap._decr();
var isUpdated= false;
on.once(spwMap.esriMap,'update-start',lang.hitch(this,function(){
isUpdated=true;
on.once(spwMap.esriMap, 'update-end', lang.hitch(this, function() {
this.resizeAndCenterMap(def, spwMap, overflowW, overflowH, domItemOverflowed);
}));
}))
spwMap.resize();
spwMap.esriMap.resize(true);
spwMap.esriMap.reposition();
if(!isUpdated){
this.resizeAndCenterMap(def, spwMap, overflowW, overflowH,domItemOverflowed);
}
return def;
},
//PARAMS:
//jasperServerUrl: jasper server url
//jasperTemplate: jasper template in his XML form
//Data: an array representing the data to include in the template: [{label:'', level: '', symbol: ''}]
//Properties: properties of the template
//options: options for the report: logoWallon: picture to show in header, header1: ?, rosaceUrl: url of rosaces pictures
// downloadReport: function(jasperServerUrl, jasperTemplate, Data, Properties, options) {
downloadReport: function(jasperServerUrl, jasperTemplate, Data, options) {
var defaultOptions = {
logoWallon: "images/templates/logoWallon2.png",
header1: "Géoportail de la Wallonie",
rosaceUrl: './images/templates/rosaces.png'
};
var opt = lang.mixin(defaultOptions, options);
var defaultProp = {
url: dojoConfig.geoviewerApiUrl + "/templates/JasperTemplate.jrxml",
jasperServerUrl : dojoConfig.geoviewerApiUrl + "/Report",
reportTitle: "Géoportail de la Wallonie"};
var prop = lang.mixin(defaultProp, options);
this.currentReportParams = {
jasperServerUrl: jasperServerUrl,
jasperTemplate: jasperTemplate,
Data: Data,
Properties: prop
};
var spwMap = SpwViewer.getInstance().get('spwMap');
var template = {
url: "reportA4Portrait.jrxml",
default: true,
imageWidth: 555*1.4,
imageHeight: 732*1.4,
data: {
logoWallon: opt.logoWallon,
header1: opt.header1
}
};
var min = spwMap.pointToExtent(0, 0);
var max = spwMap.pointToExtent(0 + template.imageWidth, 0 + template.imageHeight);
var extent = new Extent(min.x, min.y, max.x, max.y, spwMap.getSpatialReference());
this.getImage(spwMap.domNode, template.imageWidth, template.imageHeight, true, extent, lang.hitch(this, this.sendReport), opt.rosaceUrl, true);
},
sendReport: function(mapImage){
var hiddenDiv = domConstruct.create('div', {},document.body);
var form = domConstruct.create("form");
form.method = "post";
form.target="_blank";
form.enctype="multipart/form-data";
form["accept-charset"] = "UTF-8";
var FileName = domConstruct.create("input", {name: 'FileName', type: 'hidden'});
FileName.value = "rapport-" + new Date().toLocaleDateString().replace(/\//gim,'-').replace(/ /gim,'-');
form.appendChild(FileName);
var MapImage = domConstruct.create("input", {name: 'MapImage', type: 'hidden'});
var img = mapImage.toDataURL();
img = img.substring(img.indexOf(",") + 1);
MapImage.value = img;
form.appendChild(MapImage);
var Data = domConstruct.create("input", {name: 'Data', type: 'hidden'});
Data.value = JSON.stringify(this.currentReportParams.Data);
form.appendChild(Data);
var Properties = domConstruct.create("input", {name: 'Properties', type: 'hidden'});
Properties.value = JSON.stringify(this.currentReportParams.Properties);
form.appendChild(Properties);
var Template = domConstruct.create("input", {name: 'Template', type: 'hidden'});
Template.value = encodeURIComponent(this.currentReportParams.jasperTemplate);
form.appendChild(Template);
hiddenDiv.appendChild(form);
form.action = this.currentReportParams.jasperServerUrl;
form.submit();
document.body.removeChild(hiddenDiv);
},
resizeAndCenterMap: function(def, spwMap, overflowW, overflowH, domItemOverflowed) {
var centerMap = this.oldCenterMap = spwMap.getCurrentExtent().getCenter();
var centerScreenPt = spwMap.toScreenPoint(centerMap.x, centerMap.y);
centerScreenPt.x -= (overflowW / 2);
centerScreenPt.y -= (overflowH / 2);
var newCenterMap = spwMap.toMapPoint(centerScreenPt.x, centerScreenPt.y);
spwMap.centerAt(newCenterMap.x, newCenterMap.y);
def.resolve(domItemOverflowed);
},
/**
* Rétablit les dimensions de la carte telles qu'avant son redimensionnement.
* @param domItemOverflowed
*/
resetMap: function(domItemOverflowed){
array.forEach(domItemOverflowed, function(domItemArr){
domStyle.set(domItemArr[0], "overflow", domItemArr[1]);
});
domStyle.set(SpwViewer.getInstance().get('spwMap').getParent().domNode, {
width:"100%",
height:"100%"
});
array.forEach(this.stylesToReset, function(styleToReset) {
domStyle.set(styleToReset.node, styleToReset.style);
});
domStyle.set(SpwViewer.getInstance().get('spwMap').domNode, {
width:"100%",
height:"100%"
});
this.stylesToReset.length = 0;
SpwViewer.getInstance().spwViewerInnerBorderContainer.resize();
SpwViewer.getInstance().get('spwMap').resize();
SpwViewer.getInstance().get('spwMap').get('esriMap').resize();
if (this.oldCenterMap) {
SpwViewer.getInstance().get('spwMap').centerAt(this.oldCenterMap.x, this.oldCenterMap.y);
}
},
/**
* Rogne l'image
* @param canvas
*/
_useSpaceCanvas: function(canvas){
var newCanvas;
var imgSrc = canvas.toDataURL();
var img = new Image();
img.onload = lang.hitch(this, function(){
newCanvas = domConstruct.create('canvas', {width:this.imageWidth, height:this.imageHeight});
newCanvas.getContext("2d").drawImage (img, 0, 0, img.width, img.height);
MessageManager.getInstance().hideModalMessage();
this.successHandler(newCanvas);
});
img.src = imgSrc;
},
/**
* Dimensionne l'image en fonction de la taille demandée
* @param canvas
*/
_cropCanvas: function(canvas) {
var def = new Deferred();
var newCanvas;
var imgSrc = canvas.toDataURL();
var img = new Image();
var tw = Math.round(this.imageWidth);
var th = Math.round(this.imageHeight);
img.onload = lang.hitch(this, function(){
newCanvas = domConstruct.create('canvas', {
width:tw,
height:th
});
var srcX = Math.round((img.width / 2) - (this.imageWidth / 2));
var srcY = Math.round((img.height / 2) - (this.imageHeight / 2));
newCanvas.getContext("2d").drawImage(img, srcX, srcY, tw, th, 0, 0, tw, th);
def.resolve(newCanvas);
});
img.src = imgSrc;
return def;
}
});
return Printer;
});