Subversion-Projekte lars-tiefland.cienc

Revision

Blame | Letzte Änderung | Log anzeigen | RSS feed

/**
 * @license Highstock JS v2.1.8 (2015-08-20)
 * Client side exporting module
 *
 * (c) 2015 Torstein Honsi / Oystein Moseng
 *
 * License: www.highcharts.com/license
 */

// JSLint options:
/*global Highcharts, HighchartsAdapter, document, window, Blob, MSBlobBuilder */

(function (Highcharts) {

// Dummy object so we can reuse our canvas-tools.js without errors
Highcharts.CanVGRenderer = {};

/**
 * Add a new method to the Chart object to perform a local download
 */
Highcharts.Chart.prototype.exportChartLocal = function (exportingOptions, chartOptions) {
        var chart = this,
                options = Highcharts.merge(chart.options.exporting, exportingOptions),
                webKit = navigator.userAgent.indexOf('WebKit') > -1 && navigator.userAgent.indexOf("Chrome") < 0, // Webkit and not chrome
                scale = options.scale || 2,
                chartCopyContainer,
                domurl = window.URL || window.webkitURL || window,
                images,
                imagesEmbedded = 0,
                el,
                i,
                l,
                fallbackToExportServer = function () {
                        if (options.fallbackToExportServer === false) {
                                throw 'Fallback to export server disabled';
                        }
                        chart.exportChart(options);
                },
                // Get data:URL from image URL
                // Pass in callbacks to handle results. finallyCallback is always called at the end of the process. Supplying this callback is optional.
                // All callbacks receive two arguments: imageURL, and callbackArgs. callbackArgs is used only by callbacks and can contain whatever.
                imageToDataUrl = function (imageURL, callbackArgs, successCallback, taintedCallback, noCanvasSupportCallback, failedLoadCallback, finallyCallback) {
                        var img = new Image();
                        if (!webKit) {
                                img.crossOrigin = 'Anonymous'; // For some reason Safari chokes on this attribute
                        }
                        img.onload = function () {
                                var canvas = document.createElement('canvas'),
                                        ctx = canvas.getContext && canvas.getContext('2d'),
                                        dataURL;

                                if (!ctx) {
                                        noCanvasSupportCallback(imageURL, callbackArgs);
                                } else {
                                        canvas.height = img.height * scale;
                                        canvas.width = img.width * scale;
                                        ctx.drawImage(img, 0, 0, canvas.width, canvas.height);

                                        // Now we try to get the contents of the canvas.
                                        try {
                                                dataURL = canvas.toDataURL();
                                                successCallback(dataURL, callbackArgs);
                                        } catch (e) {
                                                // Failed - either tainted canvas or something else went horribly wrong
                                                if (e.name === 'SecurityError' || e.name === 'SECURITY_ERR' || e.message === 'SecurityError') {
                                                        taintedCallback(imageURL, callbackArgs);
                                                } else {
                                                        throw e;
                                                }
                                        }
                                }
                                if (finallyCallback) {
                                        finallyCallback(imageURL, callbackArgs);
                                }
                        };
                        img.onerror = function () {
                                failedLoadCallback(imageURL, callbackArgs);
                                if (finallyCallback) {
                                        finallyCallback(imageURL, callbackArgs);
                                }
                        };
                        img.src = imageURL;
                },
                // Get blob URL from SVG code. Falls back to normal data URI.
                svgToDataUrl = function (svg) {
                        try {
                                // Safari requires data URI since it doesn't allow navigation to blob URLs
                                if (!webKit) {
                                        return domurl.createObjectURL(new Blob([svg], { type: 'image/svg+xml;charset-utf-16'}));
                                }
                        } catch (e) {
                                // Ignore
                        }
                        return 'data:image/svg+xml;charset=UTF-8,' + encodeURIComponent(svg);
                },
                // Download contents by dataURL/blob
                download = function (dataURL, extension) {
                        var a = document.createElement('a'),
                                filename = (options.filename || 'chart') + '.' + extension,
                                windowRef;

                        // IE specific blob implementation
                        if (navigator.msSaveOrOpenBlob) {
                                navigator.msSaveOrOpenBlob(dataURL, filename);
                                return;
                        }

                        // Try HTML5 download attr if supported
                        if (typeof a.download !== 'undefined') {
                                a.href = dataURL;
                                a.download = filename; // HTML5 download attribute
                                a.target = '_blank';
                                document.body.appendChild(a);
                                a.click();
                                document.body.removeChild(a);
                        } else {
                                // No download attr, just opening data URI
                                try {
                                        windowRef = window.open(dataURL, 'chart');
                                        if (typeof windowRef === 'undefined' || windowRef === null) {
                                                throw 1;
                                        }
                                } catch (e) {
                                        // window.open failed, trying location.href
                                        window.location.href = dataURL;
                                }
                        }
                },
                // Get data URL to an image of the chart and call download on it
                initiateDownload = function () {
                        var svgurl,
                                blob,
                                svg = chart.sanitizeSVG(chartCopyContainer.innerHTML); // SVG of chart copy

                        // Initiate download depending on file type
                        if (options && options.type === 'image/svg+xml') {
                                // SVG download. In this case, we want to use Microsoft specific Blob if available
                                try {
                                        if (navigator.msSaveOrOpenBlob) {
                                                blob = new MSBlobBuilder();
                                                blob.append(svg);
                                                svgurl = blob.getBlob('image/svg+xml');
                                        } else {
                                                svgurl = svgToDataUrl(svg);
                                        }
                                        download(svgurl, 'svg');
                                } catch (e) {
                                        fallbackToExportServer();
                                }
                        } else {
                                // PNG download - create bitmap from SVG
                                
                                // First, try to get PNG by rendering on canvas
                                svgurl = svgToDataUrl(svg);
                                imageToDataUrl(svgurl, { /* args */ }, function (imageURL) {
                                        // Success
                                        try {
                                                download(imageURL, 'png');
                                        } catch (e) {
                                                fallbackToExportServer();
                                        }
                                }, function () {
                                        // Failed due to tainted canvas
                                        // Create new and untainted canvas
                                        var canvas = document.createElement('canvas'),
                                                ctx = canvas.getContext('2d'),
                                                imageWidth = svg.match(/^<svg[^>]*width\s*=\s*\"?(\d+)\"?[^>]*>/)[1] * scale,
                                                imageHeight = svg.match(/^<svg[^>]*height\s*=\s*\"?(\d+)\"?[^>]*>/)[1] * scale,
                                                downloadWithCanVG = function () {
                                                        ctx.drawSvg(svg, 0, 0, imageWidth, imageHeight);
                                                        try {
                                                                download(navigator.msSaveOrOpenBlob ? canvas.msToBlob() : canvas.toDataURL('image/png'), 'png');
                                                        } catch (e) {
                                                                fallbackToExportServer();
                                                        }
                                                };

                                        canvas.width = imageWidth;
                                        canvas.height = imageHeight;
                                        if (window.canvg) {
                                                // Use preloaded canvg
                                                downloadWithCanVG();
                                        } else {
                                                // Must load canVG first
                                                chart.showLoading();
                                                HighchartsAdapter.getScript(Highcharts.getOptions().global.canvasToolsURL, function () {
                                                        chart.hideLoading();
                                                        downloadWithCanVG();
                                                });
                                        }
                                },
                                // No canvas support
                                fallbackToExportServer,
                                // Failed to load image
                                fallbackToExportServer,
                                // Finally
                                function () {
                                        try {
                                                domurl.revokeObjectURL(svgurl);
                                        } catch (e) {
                                                // Ignore
                                        }
                                });
                        }
                };

        // Hook into getSVG to get a copy of the chart copy's container
        Highcharts.wrap(Highcharts.Chart.prototype, 'getChartHTML', function (proceed) {
                chartCopyContainer = this.container.cloneNode(true);
                return proceed.apply(this, Array.prototype.slice.call(arguments, 1));
        });

        // Trigger hook to get chart copy
        chart.getSVGForExport(options, chartOptions);
        images = chartCopyContainer.getElementsByTagName('image');

        try {
                // If there are no images to embed, just go ahead and start the download process
                if (!images.length) {
                        initiateDownload();
                }

                // Success handler, we converted image to base64!
                function embeddedSuccess(imageURL, callbackArgs) {
                        ++imagesEmbedded;

                        // Change image href in chart copy
                        callbackArgs.imageElement.setAttributeNS('http://www.w3.org/1999/xlink', 'href', imageURL);

                        // Start download when done with the last image
                        if (imagesEmbedded === images.length) {
                                initiateDownload();
                        }
                }

                // Go through the images we want to embed
                for (i = 0, l = images.length; i < l; ++i) {
                        el = images[i];
                        imageToDataUrl(el.getAttributeNS('http://www.w3.org/1999/xlink', 'href'), { imageElement: el },
                                embeddedSuccess,
                                // Tainted canvas
                                fallbackToExportServer,
                                // No canvas support 
                                fallbackToExportServer,
                                // Failed to load source
                                fallbackToExportServer
                        );
                }
        } catch (e) {
                fallbackToExportServer();
        }
};

// Extend the default options to use the local exporter logic
Highcharts.getOptions().exporting.buttons.contextButton.menuItems = [{
        textKey: 'printChart',
        onclick: function () {
                this.print();
        }
}, {
        separator: true
}, {
        textKey: 'downloadPNG',
        onclick: function () {
                this.exportChartLocal();
        }
}, {
        textKey: 'downloadSVG',
        onclick: function () {
                this.exportChartLocal({
                        type: 'image/svg+xml'
                });
        }
}];

}(Highcharts));