Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
/*Plugin Name: amCharts ExportDescription: Adds export capabilities to amCharts productsAuthor: Benjamin Maertz, amChartsVersion: 1.4.14Author URI: http://www.amcharts.com/Copyright 2015 amChartsLicensed under the Apache License, Version 2.0 (the "License");you may not use this file except in compliance with the License.You may obtain a copy of the License athttp://www.apache.org/licenses/LICENSE-2.0Unless required by applicable law or agreed to in writing, softwaredistributed under the License is distributed on an "AS IS" BASIS,WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.See the License for the specific language governing permissions andlimitations under the License.Please note that the above license covers only this plugin. It by all means doesnot apply to any other amCharts products that are covered by different licenses.*//*** Polyfill translation*/if ( !AmCharts.translations[ "export" ] ) {AmCharts.translations[ "export" ] = {}}if ( !AmCharts.translations[ "export" ][ "en" ] ) {AmCharts.translations[ "export" ][ "en" ] = {"fallback.save.text": "CTRL + C to copy the data into the clipboard.","fallback.save.image": "Rightclick -> Save picture as... to save the image.","capturing.delayed.menu.label": "{{duration}}","capturing.delayed.menu.title": "Click to cancel","menu.label.print": "Print","menu.label.undo": "Undo","menu.label.redo": "Redo","menu.label.cancel": "Cancel","menu.label.save.image": "Download as ...","menu.label.save.data": "Save as ...","menu.label.draw": "Annotate ...","menu.label.draw.change": "Change ...","menu.label.draw.add": "Add ...","menu.label.draw.shapes": "Shape ...","menu.label.draw.colors": "Color ...","menu.label.draw.widths": "Size ...","menu.label.draw.opacities": "Opacity ...","menu.label.draw.text": "Text","menu.label.draw.modes": "Mode ...","menu.label.draw.modes.pencil": "Pencil","menu.label.draw.modes.line": "Line","menu.label.draw.modes.arrow": "Arrow"}}/*** Polyfill export class*/( function() {AmCharts[ "export" ] = function( chart, config ) {var _this = {name: "export",version: "1.4.14",libs: {async: true,autoLoad: true,reload: false,resources: [ {"pdfmake/pdfmake.js": [ "pdfmake/vfs_fonts.js" ],"jszip/jszip.js": [ "xlsx/xlsx.js" ]}, "fabric.js/fabric.js", "FileSaver.js/FileSaver.js" ],namespaces: {"pdfmake.js": "pdfMake","jszip.js": "JSZip","xlsx.js": "XLSX","fabric.js": "fabric","FileSaver.js": "saveAs"}},config: {},setup: {chart: chart,hasBlob: false,wrapper: false},drawing: {enabled: false,undos: [],redos: [],buffer: {position: {x1: 0,y1: 0,x2: 0,y2: 0,xD: 0,yD: 0}},handler: {undo: function( options, skipped ) {var item = _this.drawing.undos.pop();if ( item ) {item.selectable = true;_this.drawing.redos.push( item );if ( item.action == "added" ) {_this.setup.fabric.remove( item.target );}var state = JSON.parse( item.state );item.target.set( state );if ( item.target instanceof fabric.Group ) {_this.drawing.handler.change( {color: state.cfg.color,width: state.cfg.width,opacity: state.cfg.opacity}, true, item.target );}_this.setup.fabric.renderAll();// RECALLif ( item.state == item.target.recentState && !skipped ) {_this.drawing.handler.undo( item, true );}}},redo: function( options, skipped ) {var item = _this.drawing.redos.pop();if ( item ) {item.selectable = true;_this.drawing.undos.push( item );if ( item.action == "added" ) {_this.setup.fabric.add( item.target );}var state = JSON.parse( item.state );item.target.recentState = item.state;item.target.set( state );if ( item.target instanceof fabric.Group ) {_this.drawing.handler.change( {color: state.cfg.color,width: state.cfg.width,opacity: state.cfg.opacity}, true, item.target );}_this.setup.fabric.renderAll();// RECALLif ( item.action == "addified" ) {_this.drawing.handler.redo();}}},done: function( options ) {_this.drawing.buffer.enabled = false;_this.drawing.undos = [];_this.drawing.redos = [];_this.createMenu( _this.config.menu );_this.setup.fabric.deactivateAll();if ( _this.setup.wrapper ) {_this.setup.chart.containerDiv.removeChild( _this.setup.wrapper );_this.setup.wrapper = false;}},add: function( options ) {var cfg = _this.deepMerge( {top: _this.setup.fabric.height / 2,left: _this.setup.fabric.width / 2}, options || {} );var method = cfg.url.indexOf( ".svg" ) != -1 ? fabric.loadSVGFromURL : fabric.Image.fromURL;method( cfg.url, function( objects, options ) {var group = options !== undefined ? fabric.util.groupSVGElements( objects, options ) : objects;var ratio = false;// RESCALE ONLY IF IT EXCEEDS THE CANVASif ( group.height > _this.setup.fabric.height || group.width > _this.setup.fabric.width ) {ratio = ( _this.setup.fabric.height / 2 ) / group.height;}if ( cfg.top > _this.setup.fabric.height ) {cfg.top = _this.setup.fabric.height / 2;}if ( cfg.left > _this.setup.fabric.width ) {cfg.left = _this.setup.fabric.width / 2;}group.set( {originX: "center",originY: "center",top: cfg.top,left: cfg.left,width: ratio ? group.width * ratio : group.width,height: ratio ? group.height * ratio : group.height,fill: _this.drawing.color} );_this.setup.fabric.add( group );} );},change: function( options, skipped, target ) {var cfg = _this.deepMerge( {}, options || {} );var state, i1, rgba;var current = target || _this.drawing.buffer.target;var objects = current ? current._objects ? current._objects : [ current ] : null;// UPDATE DRAWING OBJECTif ( cfg.mode ) {_this.drawing.mode = cfg.mode;}if ( cfg.width ) {_this.drawing.width = cfg.width;_this.drawing.fontSize = cfg.width * 3;}if ( cfg.fontSize ) {_this.drawing.fontSize = cfg.fontSize;}if ( cfg.color ) {_this.drawing.color = cfg.color;}if ( cfg.opacity ) {_this.drawing.opacity = cfg.opacity;}// APPLY OPACITY ON CURRENT COLORrgba = new fabric.Color( _this.drawing.color ).getSource();rgba.pop();rgba.push( _this.drawing.opacity );_this.drawing.color = "rgba(" + rgba.join() + ")";_this.setup.fabric.freeDrawingBrush.color = _this.drawing.color;_this.setup.fabric.freeDrawingBrush.width = _this.drawing.width;// UPDATE CURRENT SELECTIONif ( current ) {state = JSON.parse( current.recentState ).cfg;// UPDATE GIVE OPTIONS ONLYif ( state ) {cfg.color = cfg.color || state.color;cfg.width = cfg.width || state.width;cfg.opacity = cfg.opacity || state.opacity;cfg.fontSize = cfg.fontSize || cfg.width * 3;rgba = new fabric.Color( cfg.color ).getSource();rgba.pop();rgba.push( cfg.opacity );cfg.color = "rgba(" + rgba.join() + ")";}// UPDATE OBJECTSfor ( i1 = 0; i1 < objects.length; i1++ ) {if (objects[ i1 ] instanceof fabric.Text ||objects[ i1 ] instanceof fabric.PathGroup ||objects[ i1 ] instanceof fabric.Triangle) {if ( cfg.color || cfg.opacity ) {objects[ i1 ].set( {fill: cfg.color} );}if ( cfg.fontSize ) {objects[ i1 ].set( {fontSize: cfg.fontSize} );}} else if (objects[ i1 ] instanceof fabric.Path ||objects[ i1 ] instanceof fabric.Line) {if ( current instanceof fabric.Group ) {if ( cfg.color || cfg.opacity ) {objects[ i1 ].set( {stroke: cfg.color} );}} else {if ( cfg.color || cfg.opacity ) {objects[ i1 ].set( {stroke: cfg.color} );}if ( cfg.width ) {objects[ i1 ].set( {strokeWidth: cfg.width} );}}}}// ADD UNDOif ( !skipped ) {state = JSON.stringify( _this.deepMerge( current.saveState().originalState, {cfg: {color: cfg.color,width: cfg.width,opacity: cfg.opacity}} ) );current.recentState = state;_this.drawing.redos = [];_this.drawing.undos.push( {action: "modified",target: current,state: state} );}_this.setup.fabric.renderAll();}},text: function( options ) {var cfg = _this.deepMerge( {text: _this.i18l( "menu.label.draw.text" ),top: _this.setup.fabric.height / 2,left: _this.setup.fabric.width / 2,fontSize: _this.drawing.fontSize,fontFamily: _this.setup.chart.fontFamily || "Verdana",fill: _this.drawing.color}, options || {} );cfg.click = function() {};var text = new fabric.IText( cfg.text, cfg );_this.setup.fabric.add( text );_this.setup.fabric.setActiveObject( text );text.selectAll();text.enterEditing();return text;},line: function( options ) {var cfg = _this.deepMerge( {x1: ( _this.setup.fabric.width / 2 ) - ( _this.setup.fabric.width / 10 ),x2: ( _this.setup.fabric.width / 2 ) + ( _this.setup.fabric.width / 10 ),y1: ( _this.setup.fabric.height / 2 ),y2: ( _this.setup.fabric.height / 2 ),angle: 90,strokeLineCap: _this.drawing.lineCap,arrow: _this.drawing.arrow,color: _this.drawing.color,width: _this.drawing.width,group: [],}, options || {} );var i1, arrow, arrowTop, arrowLeft;var line = new fabric.Line( [ cfg.x1, cfg.y1, cfg.x2, cfg.y2 ], {stroke: cfg.color,strokeWidth: cfg.width,strokeLineCap: cfg.strokeLineCap} );cfg.group.push( line );if ( cfg.arrow ) {cfg.angle = cfg.angle ? cfg.angle : _this.getAngle( cfg.x1, cfg.y1, cfg.x2, cfg.y2 );if ( cfg.arrow == "start" ) {arrowTop = cfg.y1 + ( cfg.width / 2 );arrowLeft = cfg.x1 + ( cfg.width / 2 );} else if ( cfg.arrow == "middle" ) {arrowTop = cfg.y2 + ( cfg.width / 2 ) - ( ( cfg.y2 - cfg.y1 ) / 2 );arrowLeft = cfg.x2 + ( cfg.width / 2 ) - ( ( cfg.x2 - cfg.x1 ) / 2 );} else { // arrow: endarrowTop = cfg.y2 + ( cfg.width / 2 );arrowLeft = cfg.x2 + ( cfg.width / 2 );}arrow = new fabric.Triangle( {top: arrowTop,left: arrowLeft,fill: cfg.color,height: cfg.width * 7,width: cfg.width * 7,angle: cfg.angle,originX: "center",originY: "bottom"} );cfg.group.push( arrow );}if ( cfg.action != "config" ) {if ( cfg.arrow ) {var group = new fabric.Group( cfg.group );group.set( {cfg: cfg,fill: cfg.color,action: cfg.action,selectable: true,known: cfg.action == "change"} );if ( cfg.action == "change" ) {_this.setup.fabric.setActiveObject( group );}_this.setup.fabric.add( group );return group;} else {_this.setup.fabric.add( line );return line;}} else {for ( i1 = 0; i1 < cfg.group.length; i1++ ) {cfg.group[ i1 ].noUndo = true;_this.setup.fabric.add( cfg.group[ i1 ] );}}return cfg;}}},defaults: {position: "top-right",fileName: "amCharts",action: "download",overflow: true,path: ( ( chart.path || "" ) + "plugins/export/" ),formats: {JPG: {mimeType: "image/jpg",extension: "jpg",capture: true},PNG: {mimeType: "image/png",extension: "png",capture: true},SVG: {mimeType: "text/xml",extension: "svg",capture: true},PDF: {mimeType: "application/pdf",extension: "pdf",capture: true},CSV: {mimeType: "text/plain",extension: "csv"},JSON: {mimeType: "text/plain",extension: "json"},XLSX: {mimeType: "application/octet-stream",extension: "xlsx"}},fabric: {backgroundColor: "#FFFFFF",removeImages: true,selection: false,drawing: {enabled: true,arrow: "end",lineCap: "butt",mode: "pencil",modes: [ "pencil", "line", "arrow" ],color: "#000000",colors: [ "#000000", "#FFFFFF", "#FF0000", "#00FF00", "#0000FF" ],shapes: [ "11.svg", "14.svg", "16.svg", "17.svg", "20.svg", "27.svg" ],width: 1,fontSize: 11,widths: [ 1, 5, 10, 15 ],opacity: 1,opacities: [ 1, 0.8, 0.6, 0.4, 0.2 ],menu: undefined,autoClose: true},border: {fill: "",fillOpacity: 0,stroke: "#000000",strokeWidth: 1,strokeOpacity: 1}},pdfMake: {pageSize: "A4",pageOrientation: "portrait",images: {},content: [ "Saved from:", window.location.href, {image: "reference",fit: [ 523.28, 769.89 ]} ]},menu: undefined,divId: null,menuReviver: null,menuWalker: null,fallback: true,keyListener: true,fileListener: true},/*** Returns translated message, takes english as default*/i18l: function( key, language ) {var lang = language ? langugage : _this.setup.chart.language ? _this.setup.chart.language : "en";var catalog = AmCharts.translations[ _this.name ][ lang ] || AmCharts.translations[ _this.name ][ "en" ];return catalog[ key ] || key;},/*** Generates download file; if unsupported offers fallback to save manually*/download: function( data, type, filename ) {// SAVEif ( window.saveAs && _this.setup.hasBlob ) {var blob = _this.toBlob( {data: data,type: type}, function( data ) {saveAs( data, filename );} );// FALLBACK TEXTAREA} else if ( _this.config.fallback && type == "text/plain" ) {var div = document.createElement( "div" );var msg = document.createElement( "div" );var textarea = document.createElement( "textarea" );msg.innerHTML = _this.i18l( "fallback.save.text" );div.appendChild( msg );div.appendChild( textarea );msg.setAttribute( "class", "amcharts-export-fallback-message" );div.setAttribute( "class", "amcharts-export-fallback" );_this.setup.chart.containerDiv.appendChild( div );// FULFILL TEXTAREA AND PRESELECTtextarea.setAttribute( "readonly", "" );textarea.value = data;textarea.focus();textarea.select();// UPDATE MENU_this.createMenu( [ {"class": "export-main export-close",label: "Done",click: function() {_this.createMenu( _this.config.menu );_this.setup.chart.containerDiv.removeChild( div );}} ] );// FALLBACK IMAGE} else if ( _this.config.fallback && type.split( "/" )[ 0 ] == "image" ) {var div = document.createElement( "div" );var msg = document.createElement( "div" );var img = _this.toImage( {data: data} );msg.innerHTML = _this.i18l( "fallback.save.image" );// FULFILL TEXTAREA AND PRESELECTdiv.appendChild( msg );div.appendChild( img );msg.setAttribute( "class", "amcharts-export-fallback-message" );div.setAttribute( "class", "amcharts-export-fallback" );_this.setup.chart.containerDiv.appendChild( div );// UPDATE MENU_this.createMenu( [ {"class": "export-main export-close",label: "Done",click: function() {_this.createMenu( _this.config.menu );_this.setup.chart.containerDiv.removeChild( div );}} ] );// ERROR} else {throw new Error( "Unable to create file. Ensure saveAs (FileSaver.js) is supported." );}return data;},/*** Generates script, links tags and places them into the document's head* In case of reload it replaces the node to force the download*/loadResource: function( src, addons ) {var i1, exist, node, item, check, type;var url = src.indexOf( "//" ) != -1 ? src : [ _this.libs.path, src ].join( "" );function callback() {if ( addons ) {for ( i1 = 0; i1 < addons.length; i1++ ) {_this.loadResource( addons[ i1 ] );}}}if ( src.indexOf( ".js" ) != -1 ) {node = document.createElement( "script" );node.setAttribute( "type", "text/javascript" );node.setAttribute( "src", url );if ( _this.libs.async ) {node.setAttribute( "async", "" );}} else if ( src.indexOf( ".css" ) != -1 ) {node = document.createElement( "link" );node.setAttribute( "type", "text/css" );node.setAttribute( "rel", "stylesheet" );node.setAttribute( "href", url );}// NODE CHECKfor ( i1 = 0; i1 < document.head.childNodes.length; i1++ ) {item = document.head.childNodes[ i1 ];check = item ? ( item.src || item.href ) : false;type = item ? item.tagName : false;if ( item && check && check.indexOf( src ) != -1 ) {if ( _this.libs.reload ) {document.head.removeChild( item );}exist = true;break;}}// NAMESPACE CHECKfor ( i1 in _this.libs.namespaces ) {var namespace = _this.libs.namespaces[ i1 ];var check = src.toLowerCase();var item = i1.toLowerCase();if ( check.indexOf( item ) != -1 && window[ namespace ] !== undefined ) {exist = true;break;}}if ( !exist || _this.libs.reload ) {node.addEventListener( "load", callback );document.head.appendChild( node );}},/*** Walker to generate the script,link tags*/loadDependencies: function() {var i1, i2;if ( _this.libs.autoLoad ) {for ( i1 = 0; i1 < _this.libs.resources.length; i1++ ) {if ( _this.libs.resources[ i1 ] instanceof Object ) {for ( i2 in _this.libs.resources[ i1 ] ) {_this.loadResource( i2, _this.libs.resources[ i1 ][ i2 ] );}} else {_this.loadResource( _this.libs.resources[ i1 ] );}}}},/*** Converts string to number*/pxToNumber: function( attr, returnUndefined ) {if ( !attr && returnUndefined ) {return undefined;}return Number( String( attr ).replace( "px", "" ) ) || 0;},/*** Converts number to string*/numberToPx: function( attr ) {return String( attr ) + "px";},/*** Recursive method to merge the given objects together* Overwrite flag replaces the value instead to crawl through*/deepMerge: function( a, b, overwrite ) {var i1, v, type = b instanceof Array ? "array" : "object";for ( i1 in b ) {// PREVENT METHODSif ( type == "array" && isNaN( i1 ) ) {continue;}v = b[ i1 ];// NEWif ( a[ i1 ] == undefined || overwrite ) {if ( v instanceof Array ) {a[ i1 ] = new Array();} else if ( v instanceof Function ) {a[ i1 ] = function() {};} else if ( v instanceof Date ) {a[ i1 ] = new Date();} else if ( v instanceof Object ) {a[ i1 ] = new Object();} else if ( v instanceof Number ) {a[ i1 ] = new Number();} else if ( v instanceof String ) {a[ i1 ] = new String();}}if (( a instanceof Object || a instanceof Array ) &&( v instanceof Object || v instanceof Array ) &&!( v instanceof Function || v instanceof Date || _this.isElement( v ) ) &&i1 != "chart") {_this.deepMerge( a[ i1 ], v, overwrite );} else {if ( a instanceof Array && !overwrite ) {a.push( v );} else {a[ i1 ] = v;}}}return a;},/*** Checks if given argument is a valid node*/isElement: function( thingy ) {return thingy instanceof Object && thingy && thingy.nodeType === 1;},/*** Checks if given argument contains a hashbang and returns it*/isHashbanged: function( thingy ) {var str = String( thingy ).replace( /\"/g, "" );return str.slice( 0, 3 ) == "url" ? str.slice( str.indexOf( "#" ) + 1, str.length - 1 ) : false;},/*** Checks if given event has been thrown with pressed click / touch*/isPressed: function( event ) {// IE EXCEPTIONif ( event.type == "mousemove" && event.which === 1 ) {// IGNORE// OTHERS} else if (event.type == "touchmove" ||event.buttons === 1 ||event.button === 1 ||event.which === 1) {_this.drawing.buffer.isPressed = true;} else {_this.drawing.buffer.isPressed = false;}return _this.drawing.buffer.isPressed;},/*** Checks if given source is within the current origin*/isTainted: function( source ) {var origin = String( window.location.origin || window.location.protocol + "//" + window.location.hostname + ( window.location.port ? ':' + window.location.port : '' ) );// CHECK IF TAINTEDif (source &&source.indexOf( "//" ) != -1 &&source.indexOf( origin.replace( /.*:/, "" ) ) == -1) {return true;}return false;},/*** Checks several indicators for acceptance;*/isSupported: function() {// CHECK CONFIGif ( !_this.config.enabled ) {return false;}// CHECK IE; ATTEMPT TO ACCESS HEAD ELEMENTif ( AmCharts.isIE && AmCharts.IEversion <= 9 ) {if ( !Array.prototype.indexOf || !document.head || _this.config.fallback === false ) {return false;}}return true;},getAngle: function( x1, y1, x2, y2 ) {var x = x2 - x1;var y = y2 - y1;var angle;if ( x == 0 ) {if ( y == 0 ) {angle = 0;} else if ( y > 0 ) {angle = Math.PI / 2;} else {angle = Math.PI * 3 / 2;}} else if ( y == 0 ) {if ( x > 0 ) {angle = 0;} else {angle = Math.PI;}} else {if ( x < 0 ) {angle = Math.atan( y / x ) + Math.PI;} else if ( y < 0 ) {angle = Math.atan( y / x ) + ( 2 * Math.PI );} else {angle = Math.atan( y / x );}}return angle * 180 / Math.PI;},/*** Recursive method which crawls upwards to gather the requested attribute*/gatherAttribute: function( elm, attr, limit, lvl ) {var value, lvl = lvl ? lvl : 0,limit = limit ? limit : 3;if ( elm ) {value = elm.getAttribute( attr );if ( !value && lvl < limit ) {return _this.gatherAttribute( elm.parentNode, attr, limit, lvl + 1 );}}return value;},/*** Recursive method which crawls upwards to gather the requested classname*/gatherClassName: function( elm, className, limit, lvl ) {var value, lvl = lvl ? lvl : 0,limit = limit ? limit : 3;if ( _this.isElement( elm ) ) {value = ( elm.getAttribute( "class" ) || "" ).split( " " ).indexOf( className ) != -1;if ( !value && lvl < limit ) {return _this.gatherClassName( elm.parentNode, className, limit, lvl + 1 );} else if ( value ) {value = elm;}}return value;},/*** Collects the clip-paths and patterns*/gatherElements: function( group, cfg, images ) {var i1, i2;for ( i1 = 0; i1 < group.children.length; i1++ ) {var childNode = group.children[ i1 ];// CLIPPATHif ( childNode.tagName == "clipPath" ) {var bbox = {};var transform = fabric.parseTransformAttribute( _this.gatherAttribute( childNode, "transform" ) );// HIDE SIBLINGS; GATHER IT'S DIMENSIONSfor ( i2 = 0; i2 < childNode.childNodes.length; i2++ ) {childNode.childNodes[ i2 ].setAttribute( "fill", "transparent" );bbox = {x: _this.pxToNumber( childNode.childNodes[ i2 ].getAttribute( "x" ) ),y: _this.pxToNumber( childNode.childNodes[ i2 ].getAttribute( "y" ) ),width: _this.pxToNumber( childNode.childNodes[ i2 ].getAttribute( "width" ) ),height: _this.pxToNumber( childNode.childNodes[ i2 ].getAttribute( "height" ) )}}group.clippings[ childNode.id ] = {svg: childNode,bbox: bbox,transform: transform};// PATTERN} else if ( childNode.tagName == "pattern" ) {var props = {node: childNode,source: childNode.getAttribute( "xlink:href" ),width: Number( childNode.getAttribute( "width" ) ),height: Number( childNode.getAttribute( "height" ) ),repeat: "repeat"}// GATHER BACKGROUND COLORfor ( i2 = 0; i2 < childNode.childNodes.length; i2++ ) {if ( childNode.childNodes[ i2 ].tagName == "rect" ) {props.fill = childNode.childNodes[ i2 ].getAttribute( "fill" );}}// TAINTEDif ( cfg.removeImages && _this.isTainted( props.source ) ) {group.patterns[ childNode.id ] = props.fill ? props.fill : "transparent";} else {images.included++;group.patterns[ props.node.id ] = props;}// IMAGES} else if ( childNode.tagName == "image" ) {images.included++;// LOAD IMAGE MANUALLY; TO RERENDER THE CANVASfabric.Image.fromURL( childNode.getAttribute( "xlink:href" ), function( img ) {images.loaded++;} );}}return group;},/*** GATHER MOUSE POSITION;*/gatherPosition: function( event, type ) {var ref = _this.drawing.buffer.position;var ivt = fabric.util.invertTransform( _this.setup.fabric.viewportTransform );var pos;if ( event.type == "touchmove" ) {if ( "touches" in event ) {event = event.touches[ 0 ];} else if ( "changedTouches" in event ) {event = event.changedTouches[ 0 ];}}pos = fabric.util.transformPoint( _this.setup.fabric.getPointer( event, true ), ivt );if ( type == 1 ) {ref.x1 = pos.x;ref.y1 = pos.y;}ref.x2 = pos.x;ref.y2 = pos.y;ref.xD = ( ref.x1 - ref.x2 ) < 0 ? ( ref.x1 - ref.x2 ) * -1 : ( ref.x1 - ref.x2 );ref.yD = ( ref.y1 - ref.y2 ) < 0 ? ( ref.y1 - ref.y2 ) * -1 : ( ref.y1 - ref.y2 );return ref;},/*** Method to capture the current state of the chart*/capture: function( options, callback ) {var i1;var cfg = _this.deepMerge( _this.deepMerge( {}, _this.config.fabric ), options || {} );var groups = [];var offset = {x: 0,y: 0,pX: 0,pY: 0,width: _this.setup.chart.divRealWidth,height: _this.setup.chart.divRealHeight};var images = {loaded: 0,included: 0}fabric.ElementsParser.prototype.resolveGradient = function( obj, property ) {var instanceFillValue = obj.get( property );if ( !( /^url\(/ ).test( instanceFillValue ) ) {return;}var gradientId = instanceFillValue.slice( instanceFillValue.indexOf( "#" ) + 1, instanceFillValue.length - 1 );if ( fabric.gradientDefs[ this.svgUid ][ gradientId ] ) {obj.set( property, fabric.Gradient.fromElement( fabric.gradientDefs[ this.svgUid ][ gradientId ], obj ) );}};// BEFORE CAPTURING_this.handleCallback( cfg.beforeCapture, cfg );// GATHER SVGSvar svgs = _this.setup.chart.containerDiv.getElementsByTagName( "svg" );for ( i1 = 0; i1 < svgs.length; i1++ ) {var group = {svg: svgs[ i1 ],parent: svgs[ i1 ].parentNode,children: svgs[ i1 ].getElementsByTagName( "*" ),offset: {x: 0,y: 0},patterns: {},clippings: {}}// GATHER ELEMENTSgroup = _this.gatherElements( group, cfg, images );// APPEND GROUPgroups.push( group );}// GATHER EXTERNAL LEGENDif ( _this.config.legend && _this.setup.chart.legend && _this.setup.chart.legend.position == "outside" ) {var group = {svg: _this.setup.chart.legend.container.container,parent: _this.setup.chart.legend.container.container.parentNode,children: _this.setup.chart.legend.container.container.getElementsByTagName( "*" ),offset: {x: 0,y: 0},legend: {type: [ "top", "left" ].indexOf( _this.config.legend.position ) != -1 ? "unshift" : "push",position: _this.config.legend.position,width: _this.config.legend.width ? _this.config.legend.width : _this.setup.chart.legend.container.width,height: _this.config.legend.height ? _this.config.legend.height : _this.setup.chart.legend.container.height},patterns: {},clippings: {}}// ADAPT CANVAS DIMENSIONSif ( [ "left", "right" ].indexOf( group.legend.position ) != -1 ) {offset.width += group.legend.width;offset.height = group.legend.height > offset.height ? group.legend.height : offset.height;} else if ( [ "top", "bottom" ].indexOf( group.legend.position ) != -1 ) {offset.height += group.legend.height;}// GATHER ELEMENTSgroup = _this.gatherElements( group, cfg, images );// PRE/APPEND SVGgroups[ group.legend.type ]( group );}// CLEAR IF EXIST_this.drawing.buffer.enabled = cfg.action == "draw";_this.setup.wrapper = document.createElement( "div" );_this.setup.wrapper.setAttribute( "class", _this.setup.chart.classNamePrefix + "-export-canvas" );_this.setup.chart.containerDiv.appendChild( _this.setup.wrapper );// STOCK CHART; SELECTOR OFFSETif ( _this.setup.chart.type == "stock" ) {var padding = {top: 0,right: 0,bottom: 0,left: 0}if ( _this.setup.chart.leftContainer ) {offset.width -= _this.setup.chart.leftContainer.offsetWidth;padding.left = _this.setup.chart.leftContainer.offsetWidth + ( _this.setup.chart.panelsSettings.panelSpacing * 2 );}if ( _this.setup.chart.rightContainer ) {offset.width -= _this.setup.chart.rightContainer.offsetWidth;padding.right = _this.setup.chart.rightContainer.offsetWidth + ( _this.setup.chart.panelsSettings.panelSpacing * 2 );}if ( _this.setup.chart.periodSelector && [ "top", "bottom" ].indexOf( _this.setup.chart.periodSelector.position ) != -1 ) {offset.height -= _this.setup.chart.periodSelector.offsetHeight + _this.setup.chart.panelsSettings.panelSpacing;padding[ _this.setup.chart.periodSelector.position ] += _this.setup.chart.periodSelector.offsetHeight + _this.setup.chart.panelsSettings.panelSpacing;}if ( _this.setup.chart.dataSetSelector && [ "top", "bottom" ].indexOf( _this.setup.chart.dataSetSelector.position ) != -1 ) {offset.height -= _this.setup.chart.dataSetSelector.offsetHeight;padding[ _this.setup.chart.dataSetSelector.position ] += _this.setup.chart.dataSetSelector.offsetHeight;}// APPLY OFFSET ON WRAPPER_this.setup.wrapper.style.paddingTop = _this.numberToPx( padding.top );_this.setup.wrapper.style.paddingRight = _this.numberToPx( padding.right );_this.setup.wrapper.style.paddingBottom = _this.numberToPx( padding.bottom );_this.setup.wrapper.style.paddingLeft = _this.numberToPx( padding.left );}// CREATE CANVAS_this.setup.canvas = document.createElement( "canvas" );_this.setup.wrapper.appendChild( _this.setup.canvas );_this.setup.fabric = new fabric.Canvas( _this.setup.canvas, _this.deepMerge( {width: offset.width,height: offset.height,isDrawingMode: true}, cfg ) );// REAPPLY FOR SOME REASON_this.deepMerge( _this.setup.fabric, cfg );_this.deepMerge( _this.setup.fabric.freeDrawingBrush, cfg.drawing );// RELIABLE VARIABLES; UPDATE DRAWING_this.deepMerge( _this.drawing, cfg.drawing );_this.drawing.handler.change( cfg.drawing );// OBSERVE MOUSE EVENTS_this.setup.fabric.on( "mouse:down", function( e ) {var p = _this.gatherPosition( e.e, 1 );_this.drawing.buffer.pressedTS = Number( new Date() );_this.isPressed( e.e );} );_this.setup.fabric.on( "mouse:move", function( e ) {var p = _this.gatherPosition( e.e, 2 );_this.isPressed( e.e );// CREATE INITIAL LINE / ARROW; JUST ON LEFT CLICKif ( _this.drawing.buffer.isPressed && !_this.drawing.buffer.line ) {if ( !_this.drawing.buffer.isSelected && _this.drawing.mode != "pencil" && ( p.xD > 5 || p.xD > 5 ) ) {_this.drawing.buffer.hasLine = true;_this.setup.fabric.isDrawingMode = false;_this.setup.fabric._onMouseUpInDrawingMode( e );_this.drawing.buffer.line = _this.drawing.handler.line( {x1: p.x1,y1: p.y1,x2: p.x2,y2: p.y2,arrow: _this.drawing.mode == "line" ? false : _this.drawing.arrow,action: "config"} );}}// UPDATE LINE / ARROWif ( _this.drawing.buffer.line ) {var obj, top, left;var l = _this.drawing.buffer.line;l.x2 = p.x2;l.y2 = p.y2;for ( i1 = 0; i1 < l.group.length; i1++ ) {obj = l.group[ i1 ];if ( obj instanceof fabric.Line ) {obj.set( {x2: l.x2,y2: l.y2} );} else if ( obj instanceof fabric.Triangle ) {l.angle = ( _this.getAngle( l.x1, l.y1, l.x2, l.y2 ) + 90 );if ( l.arrow == "start" ) {top = l.y1 + ( l.width / 2 );left = l.x1 + ( l.width / 2 );} else if ( l.arrow == "middle" ) {top = l.y2 + ( l.width / 2 ) - ( ( l.y2 - l.y1 ) / 2 );left = l.x2 + ( l.width / 2 ) - ( ( l.x2 - l.x1 ) / 2 );} else { // arrow: endtop = l.y2 + ( l.width / 2 );left = l.x2 + ( l.width / 2 );}obj.set( {top: top,left: left,angle: l.angle} );}}_this.setup.fabric.renderAll();}} );_this.setup.fabric.on( "mouse:up", function( e ) {// SELECT TARGETif ( Number( new Date() ) - _this.drawing.buffer.pressedTS < 200 ) {var target = _this.setup.fabric.findTarget( e.e );if ( target && target.selectable ) {_this.setup.fabric.setActiveObject( target );}}// UPDATE LINE / ARROWif ( _this.drawing.buffer.line ) {for ( i1 = 0; i1 < _this.drawing.buffer.line.group.length; i1++ ) {_this.drawing.buffer.line.group[ i1 ].remove();}delete _this.drawing.buffer.line.action;delete _this.drawing.buffer.line.group;_this.drawing.handler.line( _this.drawing.buffer.line );}_this.drawing.buffer.line = false;_this.drawing.buffer.hasLine = false;_this.drawing.buffer.isPressed = false;} );// OBSERVE OBJECT SELECTION_this.setup.fabric.on( "object:selected", function( e ) {_this.drawing.buffer.isSelected = true;_this.drawing.buffer.target = e.target;_this.setup.fabric.isDrawingMode = false;} );_this.setup.fabric.on( "selection:cleared", function( e ) {_this.drawing.buffer.onMouseDown = _this.setup.fabric.freeDrawingBrush.onMouseDown;_this.drawing.buffer.target = false;// FREEHAND WORKAROUNDif ( _this.drawing.buffer.isSelected ) {_this.setup.fabric._isCurrentlyDrawing = false;_this.setup.fabric.freeDrawingBrush.onMouseDown = function() {};}// DELAYED DESELECTION TO PREVENT DRAWINGsetTimeout( function() {_this.drawing.buffer.isSelected = false;_this.setup.fabric.isDrawingMode = true;_this.setup.fabric.freeDrawingBrush.onMouseDown = _this.drawing.buffer.onMouseDown;}, 10 );} );_this.setup.fabric.on( "path:created", function( e ) {var item = e.path;if ( Number( new Date() ) - _this.drawing.buffer.pressedTS < 200 || _this.drawing.buffer.hasLine ) {_this.setup.fabric.remove( item );_this.setup.fabric.renderAll();return;}} );// OBSERVE OBJECT MODIFICATIONS_this.setup.fabric.on( "object:added", function( e ) {var item = e.target;var state = _this.deepMerge( item.saveState().originalState, {cfg: {color: _this.drawing.color,width: _this.drawing.width,opacity: _this.drawing.opacity,fontSize: _this.drawing.fontSize}} );if ( Number( new Date() ) - _this.drawing.buffer.pressedTS < 200 && !item.noUndo ) {_this.setup.fabric.remove( item );_this.setup.fabric.renderAll();return;}state = JSON.stringify( state );item.recentState = state;if ( item.selectable && !item.known && !item.noUndo ) {_this.drawing.undos.push( {action: "added",target: item,state: state} );_this.drawing.undos.push( {action: "addified",target: item,state: state} );_this.drawing.redos = [];}item.known = true;_this.setup.fabric.isDrawingMode = true;} );_this.setup.fabric.on( "object:modified", function( e ) {var item = e.target;var recentState = JSON.parse( item.recentState );var state = _this.deepMerge( item.saveState().originalState, {cfg: recentState.cfg} );state = JSON.stringify( state );item.recentState = state;_this.drawing.undos.push( {action: "modified",target: item,state: state} );_this.drawing.redos = [];} );_this.setup.fabric.on( "text:changed", function( e ) {var item = e.target;clearTimeout( item.timer );item.timer = setTimeout( function() {var state = JSON.stringify( item.saveState().originalState );item.recentState = state;_this.drawing.redos = [];_this.drawing.undos.push( {action: "modified",target: item,state: state} );}, 250 );} );// DRAWINGif ( _this.drawing.buffer.enabled ) {_this.setup.wrapper.setAttribute( "class", _this.setup.chart.classNamePrefix + "-export-canvas active" );_this.setup.wrapper.style.backgroundColor = cfg.backgroundColor;_this.setup.wrapper.style.display = "block";} else {_this.setup.wrapper.setAttribute( "class", _this.setup.chart.classNamePrefix + "-export-canvas" );_this.setup.wrapper.style.display = "none";}for ( i1 = 0; i1 < groups.length; i1++ ) {var group = groups[ i1 ];var isLegend = _this.gatherClassName( group.parent, _this.setup.chart.classNamePrefix + "-legend-div", 1 );var isPanel = _this.gatherClassName( group.parent, _this.setup.chart.classNamePrefix + "-stock-panel-div" );var isScrollbar = _this.gatherClassName( group.parent, _this.setup.chart.classNamePrefix + "-scrollbar-chart-div" );// STOCK CHART; SVG OFFSET;; SVG OFFSETif ( _this.setup.chart.type == "stock" && _this.setup.chart.legendSettings.position ) {// TOP / BOTTOMif ( [ "top", "bottom" ].indexOf( _this.setup.chart.legendSettings.position ) != -1 ) {// POSITION; ABSOLUTEif ( group.parent.style.top && group.parent.style.left ) {group.offset.y = _this.pxToNumber( group.parent.style.top );group.offset.x = _this.pxToNumber( group.parent.style.left );// POSITION; RELATIVE} else {group.offset.x = offset.x;group.offset.y = offset.y;offset.y += _this.pxToNumber( group.parent.style.height );// LEGEND; OFFSETif ( isPanel ) {offset.pY = _this.pxToNumber( isPanel.style.marginTop );group.offset.y += offset.pY;// SCROLLBAR; OFFSET} else if ( isScrollbar ) {group.offset.y += offset.pY;}}// LEFT / RIGHT} else if ( [ "left", "right" ].indexOf( _this.setup.chart.legendSettings.position ) != -1 ) {group.offset.y = _this.pxToNumber( group.parent.style.top ) + offset.pY;group.offset.x = _this.pxToNumber( group.parent.style.left ) + offset.pX;// LEGEND; OFFSETif ( isLegend ) {offset.pY += _this.pxToNumber( isPanel.style.height ) + _this.setup.chart.panelsSettings.panelSpacing;// SCROLLBAR; OFFSET} else if ( isScrollbar ) {group.offset.y -= _this.setup.chart.panelsSettings.panelSpacing;}}// REGULAR CHARTS; SVG OFFSET} else {// POSITION; ABSOLUTEif ( group.parent.style.position == "absolute" ) {group.offset.absolute = true;group.offset.top = _this.pxToNumber( group.parent.style.top );group.offset.right = _this.pxToNumber( group.parent.style.right, true );group.offset.bottom = _this.pxToNumber( group.parent.style.bottom, true );group.offset.left = _this.pxToNumber( group.parent.style.left );group.offset.width = _this.pxToNumber( group.parent.style.width );group.offset.height = _this.pxToNumber( group.parent.style.height );// POSITION; RELATIVE} else if ( group.parent.style.top && group.parent.style.left ) {group.offset.y = _this.pxToNumber( group.parent.style.top );group.offset.x = _this.pxToNumber( group.parent.style.left );// POSITION; GENERIC} else {// EXTERNAL LEGENDif ( group.legend ) {if ( group.legend.position == "left" ) {offset.x += group.legend.width;} else if ( group.legend.position == "right" ) {group.offset.x += offset.width - group.legend.width;} else if ( group.legend.position == "top" ) {offset.y += group.legend.height;} else if ( group.legend.position == "bottom" ) {group.offset.y += offset.height - group.legend.height; // OFFSET.Y}// NORMAL} else {group.offset.x = offset.x;group.offset.y = offset.y + offset.pY;offset.y += _this.pxToNumber( group.parent.style.height );}}// PANELif ( isLegend && isPanel && isPanel.style.marginTop ) {offset.y += _this.pxToNumber( isPanel.style.marginTop );group.offset.y += _this.pxToNumber( isPanel.style.marginTop );}}// ADD TO CANVASfabric.parseSVGDocument( group.svg, ( function( group ) {return function( objects, options ) {var i1;var g = fabric.util.groupSVGElements( objects, options );var paths = [];var tmp = {selectable: false};// GROUP OFFSET; ABSOLUTEif ( group.offset.absolute ) {if ( group.offset.bottom !== undefined ) {tmp.top = offset.height - group.offset.height - group.offset.bottom;} else {tmp.top = group.offset.top;}if ( group.offset.right !== undefined ) {tmp.left = offset.width - group.offset.width - group.offset.right;} else {tmp.left = group.offset.left;}// GROUP OFFSET; REGULAR} else {tmp.top = group.offset.y;tmp.left = group.offset.x;}// WALKTHROUGH ELEMENTSfor ( i1 = 0; i1 < g.paths.length; i1++ ) {var PID = null;// OPACITY; TODO: DISTINGUISH OPACITY TYPESif ( g.paths[ i1 ] ) {// CHECK ORIGIN; REMOVE TAINTEDif ( cfg.removeImages && _this.isTainted( g.paths[ i1 ][ "xlink:href" ] ) ) {continue;}// SET OPACITYif ( g.paths[ i1 ].fill instanceof Object ) {// MISINTERPRETATION OF FABRICif ( g.paths[ i1 ].fill.type == "radial" ) {// PIE EXCEPTIONif ( _this.setup.chart.type == "pie" ) {var tmp_n = g.paths[ i1 ];var tmp_c = tmp_n.getCenterPoint();var tmp_cp = tmp_n.group.getCenterPoint();var tmp_cd = {x: tmp_n.pathOffset.x - tmp_cp.x,y: tmp_n.pathOffset.y - tmp_cp.y};g.paths[ i1 ].fill.gradientTransform[ 4 ] = tmp_n.pathOffset.x - tmp_cd.x;g.paths[ i1 ].fill.gradientTransform[ 5 ] = tmp_n.pathOffset.y - tmp_cd.y;// OTHERS} else {g.paths[ i1 ].fill.coords.r2 = g.paths[ i1 ].fill.coords.r1 * -1;g.paths[ i1 ].fill.coords.r1 = 0;g.paths[ i1 ].set( {opacity: g.paths[ i1 ].fillOpacity} );}}// FILLING; TODO: DISTINGUISH OPACITY TYPES} else if ( PID = _this.isHashbanged( g.paths[ i1 ].fill ) ) {// PATTERNif ( group.patterns && group.patterns[ PID ] ) {var props = group.patterns[ PID ];// LOAD IMAGE MANUALLY; TO RERENDER THE CANVASfabric.Image.fromURL( props.source, ( function( props, i1 ) {return function( img ) {images.loaded++;var pattern = null;var patternSourceCanvas = new fabric.StaticCanvas( undefined, {backgroundColor: props.fill} );patternSourceCanvas.add( img );pattern = new fabric.Pattern( {source: function() {patternSourceCanvas.setDimensions( {width: props.width,height: props.height} );return patternSourceCanvas.getElement();},repeat: 'repeat'} );g.paths[ i1 ].set( {fill: pattern,opacity: g.paths[ i1 ].fillOpacity} );}} )( props, i1 ) );}}// CLIPPATH;if ( PID = _this.isHashbanged( g.paths[ i1 ].clipPath ) ) {if ( group.clippings && group.clippings[ PID ] ) {// TODO: WAIT UNTIL FABRICJS HANDLES CLIPPATH FOR SVG OUTPUT( function( i1, PID ) {var toSVG = g.paths[ i1 ].toSVG;g.paths[ i1 ].toSVG = function( original_reviver ) {return toSVG.apply(this, [ function( string ) {return original_reviver( string, group.clippings[ PID ] );} ] );}} )( i1, PID );g.paths[ i1 ].set( {clipTo: ( function( i1, PID ) {return function( ctx ) {var cp = group.clippings[ PID ];var tm = this.transformMatrix || [ 1, 0, 0, 1, 0, 0 ];var dim = {top: ( cp.bbox.y - tm[ 5 ] ) + cp.transform[ 5 ],left: ( cp.bbox.x - tm[ 4 ] ) + cp.transform[ 4 ],width: cp.bbox.width,height: cp.bbox.height}ctx.rect( dim.left, dim.top, dim.width, dim.height );}} )( i1, PID )} );}}// TODO; WAIT FOR TSPAN SUPPORT FROM FABRICJS SIDEif ( g.paths[ i1 ].TSPANWORKAROUND ) {var parsedAttributes = fabric.parseAttributes( g.paths[ i1 ].svg, fabric.Text.ATTRIBUTE_NAMES );var options = fabric.util.object.extend( {}, parsedAttributes );// CREATE NEW SETvar tmpBuffer = [];for ( var i = 0; i < g.paths[ i1 ].svg.childNodes.length; i++ ) {var textNode = g.paths[ i1 ].svg.childNodes[ i ];var textElement = fabric.Text.fromElement( textNode, options );textElement.set( {left: 0} );tmpBuffer.push( textElement );}// HIDE ORIGINAL ELEMENTg.paths[ i1 ].set( {opacity: 0} );// REPLACE BY GROUP AND CANCEL FIRST OFFSETvar tmpGroup = new fabric.Group( tmpBuffer, {top: g.paths[ i1 ].top * -1} );g.paths[ i1 ] = tmpGroup;}}paths.push( g.paths[ i1 ] );}// REPLACE WITH WHITELISTg.paths = paths;// SET PROPSg.set( tmp );// ADD TO CANVAS_this.setup.fabric.add( g );// ADD BALLOONSif ( group.svg.parentNode && group.svg.parentNode.getElementsByTagName ) {var balloons = group.svg.parentNode.getElementsByClassName( _this.setup.chart.classNamePrefix + "-balloon-div" );for ( i1 = 0; i1 < balloons.length; i1++ ) {if ( cfg.balloonFunction instanceof Function ) {cfg.balloonFunction.apply( _this, [ balloons[ i1 ], group ] );} else {var elm_parent = balloons[ i1 ];var style_parent = fabric.parseStyleAttribute( elm_parent );var style_text = fabric.parseStyleAttribute( elm_parent.childNodes[ 0 ] );var fabric_label = new fabric.Text( elm_parent.innerText || elm_parent.textContent || elm_parent.innerHTML, {selectable: false,top: style_parent.top + group.offset.y,left: style_parent.left + group.offset.x,fill: style_text[ "color" ],fontSize: style_text[ "fontSize" ],fontFamily: style_text[ "fontFamily" ],textAlign: style_text[ "text-align" ]} );_this.setup.fabric.add( fabric_label );}}}if ( group.svg.nextSibling && group.svg.nextSibling.tagName == "A" ) {var elm_parent = group.svg.nextSibling;var style_parent = fabric.parseStyleAttribute( elm_parent );var fabric_label = new fabric.Text( elm_parent.innerText || elm_parent.textContent || elm_parent.innerHTML, {selectable: false,top: style_parent.top + group.offset.y,left: style_parent.left + group.offset.x,fill: style_parent[ "color" ],fontSize: style_parent[ "fontSize" ],fontFamily: style_parent[ "fontFamily" ],opacity: style_parent[ "opacity" ]} );_this.setup.fabric.add( fabric_label );}groups.pop();// TRIGGER CALLBACK WITH SAFETY DELAYif ( !groups.length ) {var timer = setInterval( function() {if ( images.loaded == images.included ) {clearTimeout( timer );_this.handleBorder( cfg );_this.handleCallback( cfg.afterCapture, cfg );_this.setup.fabric.renderAll();_this.handleCallback( callback, cfg );}}, AmCharts.updateRate );}}// IDENTIFY ELEMENTS THROUGH CLASSNAMES} )( group ), function( svg, obj ) {var i1;var className = _this.gatherAttribute( svg, "class" );var visibility = _this.gatherAttribute( svg, "visibility" );var clipPath = _this.gatherAttribute( svg, "clip-path" );obj.className = String( className );obj.classList = String( className ).split( " " );obj.clipPath = clipPath;obj.svg = svg;// TODO; WAIT FOR TSPAN SUPPORT FROM FABRICJS SIDEif ( svg.tagName == "text" && svg.childNodes.length > 1 ) {obj.TSPANWORKAROUND = true;}// HIDE HIDDEN ELEMENTS; TODO: FIND A BETTER WAY TO HANDLE THATif ( visibility == "hidden" ) {obj.opacity = 0;// WALKTHROUGH ELEMENTS} else {// TRANSPORT FILL/STROKE OPACITYvar attrs = [ "fill", "stroke" ];for ( i1 = 0; i1 < attrs.length; i1++ ) {var attr = attrs[ i1 ]var attrVal = String( svg.getAttribute( attr ) || "" );var attrOpacity = Number( svg.getAttribute( attr + "-opacity" ) || "1" );var attrRGBA = fabric.Color.fromHex( attrVal ).getSource();// EXCEPTIONif ( obj.classList.indexOf( _this.setup.chart.classNamePrefix + "-guide-fill" ) != -1 && !attrVal ) {attrOpacity = 0;attrRGBA = fabric.Color.fromHex( "#000000" ).getSource();}if ( attrRGBA ) {attrRGBA.pop();attrRGBA.push( attrOpacity )obj[ attr ] = "rgba(" + attrRGBA.join() + ")";obj[ attr + _this.capitalize( "opacity" ) ] = attrOpacity;}}}// REVIVER_this.handleCallback( cfg.reviver, obj, svg );} );}},/*** Returns the current canvas*/toCanvas: function( options, callback ) {var cfg = _this.deepMerge( {// NUFFIN}, options || {} );var data = _this.setup.canvas;_this.handleCallback( callback, data );return data;},/*** Returns an image; by default PNG*/toImage: function( options, callback ) {var cfg = _this.deepMerge( {format: "png",quality: 1,multiplier: 1}, options || {} );var data = cfg.data;var img = document.createElement( "img" );if ( !cfg.data ) {if ( cfg.lossless || cfg.format == "svg" ) {data = _this.toSVG( _this.deepMerge( cfg, {getBase64: true} ) );} else {data = _this.setup.fabric.toDataURL( cfg );}}img.setAttribute( "src", data );_this.handleCallback( callback, img );return img;},/*** Generates a blob instance image; returns base64 datastring*/toBlob: function( options, callback ) {var cfg = _this.deepMerge( {data: "empty",type: "text/plain"}, options || {} );var data;var isBase64 = /^data:.+;base64,(.*)$/.exec( cfg.data );// GATHER BODYif ( isBase64 ) {cfg.data = isBase64[ 0 ];cfg.type = cfg.data.slice( 5, cfg.data.indexOf( "," ) - 7 );cfg.data = _this.toByteArray( {data: cfg.data.slice( cfg.data.indexOf( "," ) + 1, cfg.data.length )} );}if ( cfg.getByteArray ) {data = cfg.data;} else {data = new Blob( [ cfg.data ], {type: cfg.type} );}_this.handleCallback( callback, data );return data;},/*** Generates JPG image; returns base64 datastring*/toJPG: function( options, callback ) {var cfg = _this.deepMerge( {format: "jpeg",quality: 1,multiplier: 1}, options || {} );cfg.format = cfg.format.toLowerCase();var data = _this.setup.fabric.toDataURL( cfg );_this.handleCallback( callback, data );return data;},/*** Generates PNG image; returns base64 datastring*/toPNG: function( options, callback ) {var cfg = _this.deepMerge( {format: "png",quality: 1,multiplier: 1}, options || {} );var data = _this.setup.fabric.toDataURL( cfg );_this.handleCallback( callback, data );return data;},/*** Generates SVG image; returns base64 datastring*/toSVG: function( options, callback ) {var clipPaths = [];var cfg = _this.deepMerge( {reviver: function( string, clipPath ) {var matcher = new RegExp( /\bstyle=(['"])(.*?)\1/ );var match = matcher.exec( string )[ 0 ].slice( 7, -1 );var styles = match.split( ";" );var replacement = [];// BEAUTIFY STYLESfor ( i1 = 0; i1 < styles.length; i1++ ) {if ( styles[ i1 ] ) {var pair = styles[ i1 ].replace( /\s/g, "" ).split( ":" );var key = pair[ 0 ];var value = pair[ 1 ];if ( [ "fill", "stroke" ].indexOf( key ) != -1 ) {value = fabric.Color.fromRgba( value );if ( value && value._source ) {var color = "#" + value.toHex();var opacity = value._source[ 3 ];replacement.push( [ key, color ].join( ":" ) );replacement.push( [ key + "-opacity", opacity ].join( ":" ) );} else {replacement.push( styles[ i1 ] );}} else if ( key != "opactiy" ) {replacement.push( styles[ i1 ] );}}}string = string.replace( match, replacement.join( ";" ) );// TODO: WAIT UNTIL FABRICJS HANDLES CLIPPATH FOR SVG OUTPUTif ( clipPath ) {var sliceOffset = 2;var end = string.slice( - sliceOffset);if ( end != "/>" ) {sliceOffset = 3;end = string.slice( - sliceOffset);}var start = string.slice(0,string.length - sliceOffset);var clipPathAttr = " clip-path=\"url(#"+ clipPath.svg.id +")\" ";var clipPathString = new XMLSerializer().serializeToString(clipPath.svg);string = start + clipPathAttr + end;clipPaths.push(clipPathString);}return string;}}, options || {} );var data = _this.setup.fabric.toSVG( cfg, cfg.reviver );// TODO: WAIT UNTIL FABRICJS HANDLES CLIPPATH FOR SVG OUTPUTif ( clipPaths.length ) {var start = data.slice(0,data.length-6);var end = data.slice(-6);data = start + clipPaths.join("") + end;}if ( cfg.getBase64 ) {data = "data:image/svg+xml;base64," + btoa( data );}_this.handleCallback( callback, data );return data;},/*** Generates PDF; returns base64 datastring*/toPDF: function( options, callback ) {var cfg = _this.deepMerge( _this.deepMerge( {multiplier: 2}, _this.config.pdfMake ), options || {}, true );cfg.images.reference = _this.toPNG( cfg );var data = new pdfMake.createPdf( cfg );if ( callback ) {data.getDataUrl( ( function( callback ) {return function() {callback.apply( _this, arguments );}} )( callback ) );}return data;},/*** Generates an image; hides all elements on page to trigger native print method*/toPRINT: function( options, callback ) {var i1;var cfg = _this.deepMerge( {delay: 1,lossless: false}, options || {} );var data = _this.toImage( cfg );var states = [];var items = document.body.childNodes;data.setAttribute( "style", "width: 100%; max-height: 100%;" );for ( i1 = 0; i1 < items.length; i1++ ) {if ( _this.isElement( items[ i1 ] ) ) {states[ i1 ] = items[ i1 ].style.display;items[ i1 ].style.display = "none";}}document.body.appendChild( data );window.print();setTimeout( function() {for ( i1 = 0; i1 < items.length; i1++ ) {if ( _this.isElement( items[ i1 ] ) ) {items[ i1 ].style.display = states[ i1 ];}}document.body.removeChild( data );_this.handleCallback( callback, data );}, cfg.delay );return data;},/*** Generates JSON string*/toJSON: function( options, callback ) {var cfg = _this.deepMerge( {dateFormat: _this.config.dateFormat || "dateObject",}, options || {}, true );cfg.data = cfg.data ? cfg.data : _this.getChartData( cfg );var data = JSON.stringify( cfg.data, undefined, "\t" );_this.handleCallback( callback, data );return data;},/*** Generates CSV string*/toCSV: function( options, callback ) {var row, col;var cfg = _this.deepMerge( {data: _this.getChartData( options ),delimiter: ",",quotes: true,escape: true,withHeader: true}, options || {}, true );var data = "";var cols = [];var buffer = [];function enchant( value, column ) {// WRAP IN QUOTESif ( typeof value === "string" ) {if ( cfg.escape ) {value = value.replace( '"', '""' );}if ( cfg.quotes ) {value = [ '"', value, '"' ].join( "" );}}return value;}// HEADERfor ( value in cfg.data[ 0 ] ) {buffer.push( enchant( value ) );cols.push( value );}if ( cfg.withHeader ) {data += buffer.join( cfg.delimiter ) + "\n";}// BODYfor ( row in cfg.data ) {buffer = [];if ( !isNaN( row ) ) {for ( col in cols ) {if ( !isNaN( col ) ) {var column = cols[ col ];var value = cfg.data[ row ][ column ];buffer.push( enchant( value, column ) );}}data += buffer.join( cfg.delimiter ) + "\n";}}_this.handleCallback( callback, data );return data;},/*** Generates excel sheet; returns base64 datastring*/toXLSX: function( options, callback ) {var cfg = _this.deepMerge( {name: "amCharts",dateFormat: _this.config.dateFormat || "dateObject",withHeader: true,stringify: false}, options || {}, true );var data = "";var wb = {SheetNames: [],Sheets: {}}cfg.data = cfg.data ? cfg.data : _this.getChartData( cfg );function datenum( v, date1904 ) {if ( date1904 ) v += 1462;var epoch = Date.parse( v );return ( epoch - new Date( Date.UTC( 1899, 11, 30 ) ) ) / ( 24 * 60 * 60 * 1000 );}function sheet_from_array_of_arrays( data, opts ) {var ws = {};var range = {s: {c: 10000000,r: 10000000},e: {c: 0,r: 0}};for ( var R = 0; R != data.length; ++R ) {for ( var C = 0; C != data[ R ].length; ++C ) {if ( range.s.r > R ) range.s.r = R;if ( range.s.c > C ) range.s.c = C;if ( range.e.r < R ) range.e.r = R;if ( range.e.c < C ) range.e.c = C;var cell = {v: data[ R ][ C ]};if ( cell.v == null ) continue;var cell_ref = XLSX.utils.encode_cell( {c: C,r: R} );if ( typeof cell.v === "number" ) cell.t = "n";else if ( typeof cell.v === "boolean" ) cell.t = "b";else if ( cell.v instanceof Date ) {cell.t = "n";cell.z = XLSX.SSF._table[ 14 ];cell.v = datenum( cell.v );} else cell.t = "s";ws[ cell_ref ] = cell;}}if ( range.s.c < 10000000 ) ws[ "!ref" ] = XLSX.utils.encode_range( range );return ws;}wb.SheetNames.push( cfg.name );wb.Sheets[ cfg.name ] = sheet_from_array_of_arrays( _this.toArray( cfg ) );data = XLSX.write( wb, {bookType: "xlsx",bookSST: true,type: "base64"} );data = "data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64," + data;_this.handleCallback( callback, data );return data;},/*** Generates an array of arrays*/toArray: function( options, callback ) {var row, col;var cfg = _this.deepMerge( {data: _this.getChartData( options ),withHeader: false,stringify: true}, options || {}, true );var data = [];var cols = [];// HEADERfor ( col in cfg.data[ 0 ] ) {cols.push( col );}if ( cfg.withHeader ) {data.push( cols );}// BODYfor ( row in cfg.data ) {var buffer = [];if ( !isNaN( row ) ) {for ( col in cols ) {if ( !isNaN( col ) ) {var col = cols[ col ];var value = cfg.data[ row ][ col ];if ( value == null ) {value = "";} else if ( cfg.stringify ) {value = String( value );} else {value = value;}buffer.push( value );}}data.push( buffer );}}_this.handleCallback( callback, data );return data;},/*** Generates byte array with given base64 datastring; returns byte array*/toByteArray: function( options, callback ) {var cfg = _this.deepMerge( {// NUFFIN}, options || {} );var Arr = ( typeof Uint8Array !== 'undefined' ) ? Uint8Array : Arrayvar PLUS = '+'.charCodeAt( 0 )var SLASH = '/'.charCodeAt( 0 )var NUMBER = '0'.charCodeAt( 0 )var LOWER = 'a'.charCodeAt( 0 )var UPPER = 'A'.charCodeAt( 0 )var data = b64ToByteArray( cfg.data );function decode( elt ) {var code = elt.charCodeAt( 0 )if ( code === PLUS )return 62 // '+'if ( code === SLASH )return 63 // '/'if ( code < NUMBER )return -1 //no matchif ( code < NUMBER + 10 )return code - NUMBER + 26 + 26if ( code < UPPER + 26 )return code - UPPERif ( code < LOWER + 26 )return code - LOWER + 26}function b64ToByteArray( b64 ) {var i, j, l, tmp, placeHolders, arrif ( b64.length % 4 > 0 ) {throw new Error( 'Invalid string. Length must be a multiple of 4' )}// THE NUMBER OF EQUAL SIGNS (PLACE HOLDERS)// IF THERE ARE TWO PLACEHOLDERS, THAN THE TWO CHARACTERS BEFORE IT// REPRESENT ONE BYTE// IF THERE IS ONLY ONE, THEN THE THREE CHARACTERS BEFORE IT REPRESENT 2 BYTES// THIS IS JUST A CHEAP HACK TO NOT DO INDEXOF TWICEvar len = b64.lengthplaceHolders = '=' === b64.charAt( len - 2 ) ? 2 : '=' === b64.charAt( len - 1 ) ? 1 : 0// BASE64 IS 4/3 + UP TO TWO CHARACTERS OF THE ORIGINAL DATAarr = new Arr( b64.length * 3 / 4 - placeHolders )// IF THERE ARE PLACEHOLDERS, ONLY GET UP TO THE LAST COMPLETE 4 CHARSl = placeHolders > 0 ? b64.length - 4 : b64.lengthvar L = 0function push( v ) {arr[ L++ ] = v}for ( i = 0, j = 0; i < l; i += 4, j += 3 ) {tmp = ( decode( b64.charAt( i ) ) << 18 ) | ( decode( b64.charAt( i + 1 ) ) << 12 ) | ( decode( b64.charAt( i + 2 ) ) << 6 ) | decode( b64.charAt( i + 3 ) )push( ( tmp & 0xFF0000 ) >> 16 )push( ( tmp & 0xFF00 ) >> 8 )push( tmp & 0xFF )}if ( placeHolders === 2 ) {tmp = ( decode( b64.charAt( i ) ) << 2 ) | ( decode( b64.charAt( i + 1 ) ) >> 4 )push( tmp & 0xFF )} else if ( placeHolders === 1 ) {tmp = ( decode( b64.charAt( i ) ) << 10 ) | ( decode( b64.charAt( i + 1 ) ) << 4 ) | ( decode( b64.charAt( i + 2 ) ) >> 2 )push( ( tmp >> 8 ) & 0xFF )push( tmp & 0xFF )}return arr}_this.handleCallback( callback, data );return data;},/*** Callback handler; injects additional arguments to callback*/handleCallback: function( callback ) {var i1, data = Array();if ( callback && callback instanceof Function ) {for ( i1 = 0; i1 < arguments.length; i1++ ) {if ( i1 > 0 ) {data.push( arguments[ i1 ] );}}callback.apply( _this, data );}},/*** Border handler; injects additional border to canvas*/handleBorder: function( options ) {if ( _this.config.border instanceof Object ) {var cfg = _this.deepMerge( _this.defaults.fabric.border, options.border || {}, true );var border = new fabric.Rect();cfg.width = _this.setup.fabric.width - cfg.strokeWidth;cfg.height = _this.setup.fabric.height - cfg.strokeWidth;border.set(cfg);_this.setup.fabric.add(border);}},/*** Handles drag/drop events; loads given imagery*/handleDropbox: function( e ) {if ( _this.drawing.buffer.enabled ) {e.preventDefault();e.stopPropagation();// DRAG OVERif ( e.type == "dragover" ) {_this.setup.wrapper.setAttribute( "class", _this.setup.chart.classNamePrefix + "-export-canvas active dropbox" );// DRAGLEAVE; DROP} else {_this.setup.wrapper.setAttribute( "class", _this.setup.chart.classNamePrefix + "-export-canvas active" );if ( e.type == "drop" && e.dataTransfer.files.length ) {for ( var i1 = 0; i1 < e.dataTransfer.files.length; i1++ ) {var reader = new FileReader();reader.onloadend = ( function( index ) {return function() {_this.drawing.handler.add( {url: reader.result,top: e.layerY - ( index * 10 ),left: e.layerX - ( index * 10 )} );}} )( i1 );reader.readAsDataURL( e.dataTransfer.files[ i1 ] );}}}}},/*** Gathers chart data according to its type*/getChartData: function( options ) {var cfg = _this.deepMerge( {data: [],titles: {},dateFields: [],dataFields: [],dataFieldsMap: {},exportTitles: _this.config.exportTitles,exportFields: _this.config.exportFields,exportSelection: _this.config.exportSelection,columnNames: _this.config.columnNames}, options || {}, true );var uid, i1, i2, i3;var lookupFields = [ "valueField", "openField", "closeField", "highField", "lowField", "xField", "yField" ];// HANDLE FIELDSfunction addField( field, title, type ) {function checkExistance( field, type ) {if ( cfg.dataFields.indexOf( field ) != -1 ) {return checkExistance( [ field, ".", type ].join( "" ) );}return field;}if ( field && cfg.exportTitles && _this.setup.chart.type != "gantt" ) {uid = checkExistance( field, type );cfg.dataFieldsMap[ uid ] = field;cfg.dataFields.push( uid );cfg.titles[ uid ] = title || uid;}}if ( cfg.data.length == 0 ) {// STOCK DATA; GATHER COMPARED GRAPHSif ( _this.setup.chart.type == "stock" ) {cfg.data = _this.setup.chart.mainDataSet.dataProvider;// CATEGORY AXISaddField( _this.setup.chart.mainDataSet.categoryField );cfg.dateFields.push( _this.setup.chart.mainDataSet.categoryField );// WALKTHROUGH GRAPHSfor ( i1 = 0; i1 < _this.setup.chart.mainDataSet.fieldMappings.length; i1++ ) {var fieldMap = _this.setup.chart.mainDataSet.fieldMappings[ i1 ];for ( i2 = 0; i2 < _this.setup.chart.panels.length; i2++ ) {var panel = _this.setup.chart.panels[ i2 ]for ( i3 = 0; i3 < panel.stockGraphs.length; i3++ ) {var graph = panel.stockGraphs[ i3 ];for ( i4 = 0; i4 < lookupFields.length; i4++ ) {if ( graph[ lookupFields[ i4 ] ] == fieldMap.toField ) {addField( fieldMap.fromField, graph.title, lookupFields[ i4 ] );}}}}}// WALKTHROUGH COMPARISON AND MERGE IT'S DATAfor ( i1 = 0; i1 < _this.setup.chart.comparedGraphs.length; i1++ ) {var graph = _this.setup.chart.comparedGraphs[ i1 ];for ( i2 = 0; i2 < graph.dataSet.dataProvider.length; i2++ ) {for ( i3 = 0; i3 < graph.dataSet.fieldMappings.length; i3++ ) {var fieldMap = graph.dataSet.fieldMappings[ i3 ];var uid = graph.dataSet.id + "_" + fieldMap.toField;if ( i2 < cfg.data.length ) {cfg.data[ i2 ][ uid ] = graph.dataSet.dataProvider[ i2 ][ fieldMap.fromField ];if ( !cfg.titles[ uid ] ) {addField( uid, graph.dataSet.title )}}}}}// GANTT DATA; FLATTEN SEGMENTS} else if ( _this.setup.chart.type == "gantt" ) {// CATEGORY AXISaddField( _this.setup.chart.categoryField );cfg.dateFields.push( _this.setup.chart.categoryField );var field = _this.setup.chart.segmentsField;for ( i1 = 0; i1 < _this.setup.chart.dataProvider.length; i1++ ) {var dataItem = _this.setup.chart.dataProvider[ i1 ];if ( dataItem[ field ] ) {for ( i2 = 0; i2 < dataItem[ field ].length; i2++ ) {dataItem[ field ][ i2 ][ _this.setup.chart.categoryField ] = dataItem[ _this.setup.chart.categoryField ];cfg.data.push( dataItem[ field ][ i2 ] );}}}// GRAPHSfor ( i1 = 0; i1 < _this.setup.chart.graphs.length; i1++ ) {var graph = _this.setup.chart.graphs[ i1 ];for ( i2 = 0; i2 < lookupFields.length; i2++ ) {var dataField = lookupFields[ i2 ];var graphField = graph[ dataField ];var title = graph.title;addField( graphField, graph.title, dataField );}}// PIE/FUNNEL DATA;} else if ( [ "pie", "funnel" ].indexOf( _this.setup.chart.type ) != -1 ) {cfg.data = _this.setup.chart.dataProvider;// CATEGORY AXISaddField( _this.setup.chart.titleField );cfg.dateFields.push( _this.setup.chart.titleField );// VALUEaddField( _this.setup.chart.valueField );// DEFAULT DATA;} else if ( _this.setup.chart.type != "map" ) {cfg.data = _this.setup.chart.dataProvider;// CATEGORY AXISif ( _this.setup.chart.categoryAxis ) {addField( _this.setup.chart.categoryField, _this.setup.chart.categoryAxis.title );if ( _this.setup.chart.categoryAxis.parseDates !== false ) {cfg.dateFields.push( _this.setup.chart.categoryField );}}// GRAPHSfor ( i1 = 0; i1 < _this.setup.chart.graphs.length; i1++ ) {var graph = _this.setup.chart.graphs[ i1 ];for ( i2 = 0; i2 < lookupFields.length; i2++ ) {var dataField = lookupFields[ i2 ];var graphField = graph[ dataField ];addField( graphField, graph.title, dataField );}}}}return _this.processData( cfg );},/*** Walkthrough data to format dates and titles*/processData: function( options ) {var cfg = _this.deepMerge( {data: [],titles: {},dateFields: [],dataFields: [],dataFieldsMap: {},dataDateFormat: _this.setup.chart.dataDateFormat,dateFormat: _this.config.dateFormat || _this.setup.chart.dataDateFormat || "YYYY-MM-DD",exportTitles: _this.config.exportTitles,exportFields: _this.config.exportFields,exportSelection: _this.config.exportSelection,columnNames: _this.config.columnNames}, options || {}, true );var i1, i2;if ( cfg.data.length ) {// GATHER MISSING FIELDSfor ( i1 = 0; i1 < cfg.data.length; i1++ ) {for ( i2 in cfg.data[ i1 ] ) {if ( cfg.dataFields.indexOf( i2 ) == -1 ) {cfg.dataFields.push( i2 );cfg.dataFieldsMap[ i2 ] = i2;}}}// REMOVE FIELDS SELECTIVELYif ( cfg.exportFields !== undefined ) {cfg.dataFields = cfg.dataFields.filter( function( n ) {return cfg.exportFields.indexOf( n ) != -1;} );}// REBUILD DATAvar buffer = [];for ( i1 = 0; i1 < cfg.data.length; i1++ ) {var tmp = {};var skip = false;for ( i2 = 0; i2 < cfg.dataFields.length; i2++ ) {var uniqueField = cfg.dataFields[ i2 ];var dataField = cfg.dataFieldsMap[ uniqueField ];var title = ( cfg.columnNames && cfg.columnNames[ uniqueField ] ) || cfg.titles[ uniqueField ] || uniqueField;var value = cfg.data[ i1 ][ dataField ];if ( value == null ) {value = undefined;}// TITLEFYif ( cfg.exportTitles && _this.setup.chart.type != "gantt" ) {if ( title in tmp ) {title += [ "( ", uniqueField, " )" ].join( "" );}}// PROCESS CATEGORYif ( cfg.dateFields.indexOf( dataField ) != -1 ) {// CONVERT DATESTRING TO DATE OBJECTif ( cfg.dataDateFormat && ( value instanceof String || typeof value == "string" ) ) {value = AmCharts.stringToDate( value, cfg.dataDateFormat );// CONVERT TIMESTAMP TO DATE OBJECT} else if ( cfg.dateFormat && ( value instanceof Number || typeof value == "number" ) ) {value = new Date( value );}// CATEGORY RANGEif ( cfg.exportSelection ) {if ( value instanceof Date ) {if ( value < chart.startDate || value > chart.endDate ) {skip = true;}} else if ( i1 < chart.startIndex || i1 > chart.endIndex ) {skip = true;}}// CATEGORY FORMATif ( cfg.dateFormat && cfg.dateFormat != "dateObject" && value instanceof Date ) {value = AmCharts.formatDate( value, cfg.dateFormat );}}tmp[ title ] = value;}if ( !skip ) {buffer.push( tmp );}}cfg.data = buffer;}return cfg.data;},/*** Prettifies string*/capitalize: function( string ) {return string.charAt( 0 ).toUpperCase() + string.slice( 1 ).toLowerCase();},/*** Generates export menu; returns UL node*/createMenu: function( list, container ) {var div;function buildList( list, container ) {var i1, i2, ul = document.createElement( "ul" );for ( i1 = 0; i1 < list.length; i1++ ) {var item = typeof list[ i1 ] === "string" ? {format: list[ i1 ]} : list[ i1 ];var li = document.createElement( "li" );var a = document.createElement( "a" );var img = document.createElement( "img" );var span = document.createElement( "span" );var action = String( item.action ? item.action : item.format ).toLowerCase();item.format = String( item.format ).toUpperCase();// MERGE WITH GIVEN FORMATif ( _this.config.formats[ item.format ] ) {item = _this.deepMerge( {label: item.icon ? "" : item.format,format: item.format,mimeType: _this.config.formats[ item.format ].mimeType,extension: _this.config.formats[ item.format ].extension,capture: _this.config.formats[ item.format ].capture,action: _this.config.action,fileName: _this.config.fileName}, item );} else if ( !item.label ) {item.label = item.label ? item.label : _this.i18l( "menu.label." + action );}// FILTER; TOGGLE FLAGif ( [ "CSV", "JSON", "XLSX" ].indexOf( item.format ) != -1 && [ "map", "gauge" ].indexOf( _this.setup.chart.type ) != -1 ) {continue;// BLOB EXCEPTION} else if ( !_this.setup.hasBlob && item.format != "UNDEFINED" ) {if ( item.mimeType && item.mimeType.split( "/" )[ 0 ] != "image" && item.mimeType != "text/plain" ) {continue;}}// DRAWINGif ( item.action == "draw" ) {if ( _this.config.fabric.drawing.enabled ) {item.menu = item.menu ? item.menu : _this.config.fabric.drawing.menu;item.click = ( function( item ) {return function() {this.capture( item, function() {this.createMenu( item.menu );} );}} )( item );} else {item.menu = [];}// DRAWING CHOICES} else if ( !item.populated && item.action && item.action.indexOf( "draw." ) != -1 ) {var type = item.action.split( "." )[ 1 ];var items = item[ type ] || _this.config.fabric.drawing[ type ] || [];item.menu = [];item.populated = true;for ( i2 = 0; i2 < items.length; i2++ ) {var tmp = {"label": items[ i2 ]}if ( type == "shapes" ) {var io = items[ i2 ].indexOf( "//" ) == -1;var url = ( io ? _this.config.path + "shapes/" : "" ) + items[ i2 ];tmp.action = "add";tmp.url = url;tmp.icon = url;tmp.ignore = io;tmp[ "class" ] = "export-drawing-shape";} else if ( type == "colors" ) {tmp.style = "background-color: " + items[ i2 ];tmp.action = "change";tmp.color = items[ i2 ];tmp[ "class" ] = "export-drawing-color";} else if ( type == "widths" ) {tmp.action = "change";tmp.width = items[ i2 ];tmp.label = document.createElement( "span" );tmp.label.style.width = _this.numberToPx( items[ i2 ] );tmp.label.style.height = _this.numberToPx( items[ i2 ] );tmp[ "class" ] = "export-drawing-width";} else if ( type == "opacities" ) {tmp.style = "opacity: " + items[ i2 ];tmp.action = "change";tmp.opacity = items[ i2 ];tmp.label = ( items[ i2 ] * 100 ) + "%";tmp[ "class" ] = "export-drawing-opacity";} else if ( type == "modes" ) {tmp.label = _this.i18l( "menu.label.draw.modes." + items[ i2 ] );tmp.click = ( function( mode ) {return function() {_this.drawing.mode = mode;}} )( items[ i2 ] );tmp[ "class" ] = "export-drawing-mode";}item.menu.push( tmp );}// ADD CLICK HANDLER} else if ( !item.click && !item.menu && !item.items ) {// DRAWING METHODSif ( _this.drawing.handler[ action ] instanceof Function ) {item.action = action;item.click = ( function( item ) {return function() {this.drawing.handler[ item.action ]( item );}} )( item );// DRAWING} else if ( _this.drawing.buffer.enabled ) {item.click = ( function( item ) {return function() {if ( this.config.drawing.autoClose ) {this.drawing.handler.done();}this[ "to" + item.format ]( item, function( data ) {if ( item.action == "download" ) {this.download( data, item.mimeType, [ item.fileName, item.extension ].join( "." ) );}} );}} )( item );// REGULAR} else if ( item.format != "UNDEFINED" ) {item.click = ( function( item ) {return function() {if ( item.capture || item.action == "print" || item.format == "PRINT" ) {this.capture( item, function() {if ( this.config.drawing.autoClose ) {this.drawing.handler.done();}this[ "to" + item.format ]( item, function( data ) {if ( item.action == "download" ) {this.download( data, item.mimeType, [ item.fileName, item.extension ].join( "." ) );}} );} )} else if ( this[ "to" + item.format ] ) {this[ "to" + item.format ]( item, function( data ) {this.download( data, item.mimeType, [ item.fileName, item.extension ].join( "." ) );} );} else {throw new Error( 'Invalid format. Could not determine output type.' );}}} )( item );}}// HIDE EMPTY ONESif ( item.menu !== undefined && !item.menu.length ) {continue;}// ADD LINK ATTRa.setAttribute( "href", "#" );a.addEventListener( "click", ( function( callback, item ) {return function( e ) {e.preventDefault();var args = [ e, item ];// DELAYEDif ( ( item.action == "draw" || item.format == "PRINT" || ( item.format != "UNDEFINED" && item.capture ) ) && !_this.drawing.enabled ) {item.delay = item.delay ? item.delay : _this.config.delay;if ( item.delay ) {_this.delay( item, callback );return;}}callback.apply( _this, args );}} )( item.click || function( e ) {e.preventDefault();}, item ) );li.appendChild( a );// ADD LABELif ( _this.isElement( item.label ) ) {span.appendChild( item.label );} else {span.innerHTML = item.label;}// APPEND ITEMSif ( item[ "class" ] ) {li.className = item[ "class" ];}if ( item.style ) {li.setAttribute( "style", item.style );}if ( item.icon ) {img.setAttribute( "src", ( !item.ignore && item.icon.slice( 0, 10 ).indexOf( "//" ) == -1 ? chart.pathToImages : "" ) + item.icon );a.appendChild( img );}if ( item.label ) {a.appendChild( span );}if ( item.title ) {a.setAttribute( "title", item.title );}// CALLBACK; REVIVER FOR MENU ITEMSif ( _this.config.menuReviver ) {li = _this.config.menuReviver.apply( _this, [ item, li ] );}// ADD ELEMENTS FOR EASY ACCESSitem.elements = {li: li,a: a,img: img,span: span}// ADD SUBLIST; JUST WITH ENTRIESif ( ( item.menu || item.items ) && item.action != "draw" ) {if ( buildList( item.menu || item.items, li ).childNodes.length ) {ul.appendChild( li );}} else {ul.appendChild( li );}}// JUST ADD THOSE WITH ENTRIESif ( ul.childNodes.length ) {container.appendChild( ul );}return ul;}// DETERMINE CONTAINERif ( !container ) {if ( typeof _this.config.divId == "string" ) {_this.config.divId = container = document.getElementById( _this.config.divId );} else if ( _this.isElement( _this.config.divId ) ) {container = _this.config.divId;} else {container = _this.setup.chart.containerDiv;}}// CREATE / RESET MENU CONTAINERif ( _this.isElement( _this.setup.menu ) ) {_this.setup.menu.innerHTML = "";} else {_this.setup.menu = document.createElement( "div" );}_this.setup.menu.setAttribute( "class", _this.setup.chart.classNamePrefix + "-export-menu " + _this.setup.chart.classNamePrefix + "-export-menu-" + _this.config.position + " amExportButton" );// CALLBACK; REPLACES THE MENU WALKERif ( _this.config.menuWalker ) {buildList = _this.config.menuWalker;}buildList.apply( this, [ list, _this.setup.menu ] );// JUST ADD THOSE WITH ENTRIESif ( _this.setup.menu.childNodes.length ) {container.appendChild( _this.setup.menu );}return _this.setup.menu;},/*** Method to trigger the callback delayed*/delay: function( options, callback ) {var cfg = _this.deepMerge( {delay: 3,precision: 2}, options || {} );var t1, t2, start = Number( new Date() );var menu = _this.createMenu( [ {label: _this.i18l( "capturing.delayed.menu.label" ).replace( "{{duration}}", AmCharts.toFixed( cfg.delay, cfg.precision ) ),title: _this.i18l( "capturing.delayed.menu.title" ),"class": "export-delayed-capturing",click: function() {clearTimeout( t1 );clearTimeout( t2 );_this.createMenu( _this.config.menu );}} ] );var label = menu.getElementsByTagName( "a" )[ 0 ];// MENU UPDATEt1 = setInterval( function() {var diff = cfg.delay - ( Number( new Date() ) - start ) / 1000;if ( diff <= 0 ) {clearTimeout( t1 );if ( cfg.action != "draw" ) {_this.createMenu( _this.config.menu );}} else if ( label ) {label.innerHTML = _this.i18l( "capturing.delayed.menu.label" ).replace( "{{duration}}", AmCharts.toFixed( diff, 2 ) );}}, 10 );// CALLBACKt2 = setTimeout( function() {callback.apply( _this, arguments );}, cfg.delay * 1000 );},/*** Migration method to support old export setup*/migrateSetup: function( setup ) {var cfg = {enabled: true,migrated: true,libs: {autoLoad: true},menu: []};function crawler( object ) {var key;for ( key in object ) {var value = object[ key ];if ( key.slice( 0, 6 ) == "export" && value ) {cfg.menu.push( key.slice( 6 ) );} else if ( key == "userCFG" ) {crawler( value );} else if ( key == "menuItems" ) {cfg.menu = value;} else if ( key == "libs" ) {cfg.libs = value;} else if ( typeof key == "string" ) {cfg[ key ] = value;}}}crawler( setup );return cfg;},/*** Add event listener*/loadListeners: function() {function handleClone( clone ) {if ( clone ) {clone.set( {top: clone.top + 10,left: clone.left + 10} );_this.setup.fabric.add( clone );}}// OBSERVE; KEY LISTENER; DRAWING FEATURESif ( _this.config.keyListener && _this.config.keyListener != "attached" ) {_this.config.keyListener = "attached";document.addEventListener( "keydown", function( e ) {var current = _this.drawing.buffer.target;// REMOVE; key: BACKSPACE / DELETEif ( ( e.keyCode == 8 || e.keyCode == 46 ) && current ) {e.preventDefault();_this.setup.fabric.remove( current );// ESCAPE DRAWIN MODE; key: escape} else if ( e.keyCode == 27 && _this.drawing.enabled ) {e.preventDefault();_this.drawing.handler.done();// COPY; key: C} else if ( e.keyCode == 67 && ( e.metaKey || e.ctrlKey ) && current ) {_this.drawing.buffer.copy = current;// CUT; key: X} else if ( e.keyCode == 88 && ( e.metaKey || e.ctrlKey ) && current ) {_this.drawing.buffer.copy = current;_this.setup.fabric.remove( current );// PASTE; key: V} else if ( e.keyCode == 86 && ( e.metaKey || e.ctrlKey ) ) {if ( _this.drawing.buffer.copy ) {handleClone( _this.drawing.buffer.copy.clone( handleClone ) )}// UNDO / REDO; key: Z} else if ( e.keyCode == 90 && ( e.metaKey || e.ctrlKey ) ) {e.preventDefault();if ( e.shiftKey ) {_this.drawing.handler.redo();} else {_this.drawing.handler.undo();}}} );}// OBSERVE; DRAG AND DROP LISTENER; DRAWING FEATUREif ( _this.config.fileListener ) {_this.setup.chart.containerDiv.addEventListener( "dragover", _this.handleDropbox );_this.setup.chart.containerDiv.addEventListener( "dragleave", _this.handleDropbox );_this.setup.chart.containerDiv.addEventListener( "drop", _this.handleDropbox );}},/*** Initiate export menu; waits for chart container to place menu*/init: function() {clearTimeout( _this.timer );_this.timer = setInterval( function() {if ( _this.setup.chart.containerDiv ) {clearTimeout( _this.timer );if ( _this.config.enabled ) {// CREATE REFERENCE_this.setup.chart.AmExport = _this;// OVERWRITE PARENT OVERFLOWif ( _this.config.overflow ) {_this.setup.chart.div.style.overflow = "visible";}// ATTACH EVENTS_this.loadListeners();// CREATE MENU_this.createMenu( _this.config.menu );}}}, AmCharts.updateRate );},/*** Initiates export instance; merges given config; attaches event listener*/construct: function() {// ANNOTATION; MAP "DONE"_this.drawing.handler.cancel = _this.drawing.handler.done;// CHECK BLOB CONSTRUCTORtry {_this.setup.hasBlob = !!new Blob;} catch ( e ) {}// WORK AROUND TO BYPASS FILESAVER CHECK TRYING TO OPEN THE BLOB URL IN SAFARI BROWSERwindow.safari = window.safari ? window.safari : {};// OVERTAKE CHART FONTSIZE IF GIVEN_this.defaults.fabric.drawing.fontSize = _this.setup.chart.fontSize || 11;// MERGE SETTINGS_this.config.drawing = _this.deepMerge( _this.defaults.fabric.drawing, _this.config.drawing || {}, true );if ( _this.config.border ) {_this.config.border = _this.deepMerge( _this.defaults.fabric.border, _this.config.border || {}, true );}_this.deepMerge( _this.defaults.fabric, _this.config, true );_this.deepMerge( _this.defaults.fabric, _this.config.fabric || {}, true );_this.deepMerge( _this.defaults.pdfMake, _this.config, true );_this.deepMerge( _this.defaults.pdfMake, _this.config.pdfMake || {}, true );_this.deepMerge( _this.libs, _this.config.libs || {}, true );// UPDATE CONFIG_this.config.drawing = _this.defaults.fabric.drawing;_this.config.fabric = _this.defaults.fabric;_this.config.pdfMake = _this.defaults.pdfMake;_this.config = _this.deepMerge( _this.defaults, _this.config, true );// MERGE; SETUP DRAWING MENUif ( _this.config.fabric.drawing.enabled ) {if ( _this.config.fabric.drawing.menu === undefined ) {_this.config.fabric.drawing.menu = [];_this.deepMerge( _this.config.fabric.drawing.menu, [ {"class": "export-drawing",menu: [ {label: _this.i18l( "menu.label.draw.add" ),menu: [ {label: _this.i18l( "menu.label.draw.shapes" ),action: "draw.shapes"}, {label: _this.i18l( "menu.label.draw.text" ),action: "text"} ]}, {label: _this.i18l( "menu.label.draw.change" ),menu: [ {label: _this.i18l( "menu.label.draw.modes" ),action: "draw.modes"}, {label: _this.i18l( "menu.label.draw.colors" ),action: "draw.colors"}, {label: _this.i18l( "menu.label.draw.widths" ),action: "draw.widths"}, {label: _this.i18l( "menu.label.draw.opacities" ),action: "draw.opacities"}, "UNDO", "REDO" ]}, {label: _this.i18l( "menu.label.save.image" ),menu: [ "PNG", "JPG", "SVG", "PDF" ]}, "PRINT", "CANCEL" ]} ] );}}// MERGE; SETUP MAIN MENUif ( _this.config.menu === undefined ) {_this.config.menu = [];// PARENT MENU_this.deepMerge( _this.config, {menu: [ {"class": "export-main",menu: [ {label: _this.i18l( "menu.label.save.image" ),menu: [ "PNG", "JPG", "SVG", "PDF" ]}, {label: _this.i18l( "menu.label.save.data" ),menu: [ "CSV", "XLSX", "JSON" ]}, {label: _this.i18l( "menu.label.draw" ),action: "draw",menu: _this.config.fabric.drawing.menu}, {format: "PRINT",label: _this.i18l( "menu.label.print" )} ]} ]} );}// ADD MISSING PATHif ( !_this.libs.path ) {_this.libs.path = _this.config.path + "libs/";}// CHECK ACCEPTANCEif ( _this.isSupported() ) {// LOAD DEPENDENCIES_this.loadDependencies( _this.libs.resources, _this.libs.reload );// ADD CLASSNAMES_this.setup.chart.addClassNames = true;// REFERENCE_this.setup.chart[ _this.name ] = _this;// INIT MENU; WAIT FOR CHART INSTANCE_this.init();}}}// USE GIVEN CONFIGif ( config ) {_this.config = config;// USE CHART EXPORT CONFIG} else if ( _this.setup.chart[ _this.name ] ) {_this.config = _this.setup.chart[ _this.name ];// MIGRATE OLD EXPORT CHART CONFIG} else if ( _this.setup.chart.amExport || _this.setup.chart.exportConfig ) {_this.config = _this.migrateSetup( _this.setup.chart.amExport || _this.setup.chart.exportConfig );// EXIT; NO CONFIG} else {return;}// CONSTRUCT INSTANCE_this.construct();// EXPORT SCOPEreturn _this.deepMerge( this, _this );}} )();/*** Set init handler*/AmCharts.addInitHandler( function( chart ) {new AmCharts[ "export" ]( chart );}, [ "pie", "serial", "xy", "funnel", "radar", "gauge", "stock", "map", "gantt" ] );