All files index.js

95.38% Statements 62/65
71.43% Branches 10/14
100% Functions 20/20
95.38% Lines 62/65
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174  1x 1x 1x 1x 1x             5x 5x           15x           15x     5x 5x 5x 5x                 5x 5x     5x 5x 5x     5x 5x 415x 137x 137x 137x           5x 5x     5x   5x       5x 5x       5x 5x 5x   5x 5x                     1x   1x       1x 1x 1x                         3x 3x 3x     3x 3x                     1x 1x 1x     1x                     1x   1x 1x               6x 1x 67x       6x 1x 1x     6x 6x 6x     1x  
'use strict';
const BbPromise = require('bluebird');
const jsdom = BbPromise.promisifyAll(require('jsdom'));
const fs = BbPromise.promisifyAll(require('fs'));
const streamBuffers = require('stream-buffers');
jsdom.defaultDocumentFeatures = {
    FetchExternalResources: ['script'],
    ProcessExternalResources: true
};
 
class ChartjsNode {
    constructor(width, height) {
        this._width = width;
        this._height = height;
    }
    /**
     * @returns {Number} the width of the chart/canvas in pixels
     */
    get width() {
        return this._width;
    }
    /**
     * @returns {Number} the height of the chart/canvas in pixels
     */
    get height() {
        return this._height;
    }
    _disableDynamicChartjsSettings(configuration) {
        configuration.options.responsive = false;
        configuration.options.animation = false;
        configuration.options.width = this.width;
        configuration.options.height = this.height;
    }
    /**
     * Draws the chart given the Chart.js configuration
     *
     * @returns {Promise} A promise that will resolve when the chart is completed
     */
    drawChart(configuration) {
        // ensure we clean up any existing window if drawChart was called more than once.
        this.destroy();
        return jsdom.envAsync('<html><body><div id="chart-div" style="font-size:12; width:' + this.width + '; height:' + this.height + ';"><canvas id="myChart" width="' + this.width + '" height="' + this.height + '"></canvas>></div></body></html>',
            [])
            .then(window => {
                this._window = window;
                const canvas = require('canvas');
                const canvasMethods = ['HTMLCanvasElement'];
 
                // adding window properties to global (only properties that are not already defined).
                this._windowPropertiesToDestroy = [];
                Object.keys(window).forEach(property => {
                    if (typeof global[property] === 'undefined') {
                        Eif (typeof global[property] === 'undefined') {
                            global[property] = window[property];
                            this._windowPropertiesToDestroy.push(property);
                        }
                    }
                });
 
                // adding all window.HTMLCanvasElement methods to global.HTMLCanvasElement
                canvasMethods.forEach(method =>
                    global[method] = window[method]
                );
 
                global.CanvasRenderingContext2D = canvas.Context2d;
 
                global.navigator = {
                    userAgent: 'node.js'
                };
 
                const Chartjs = require('chart.js');
                Iif (configuration.options.plugins) {
                    Chartjs.pluginService.register(configuration.options.plugins);
                }
 
                this._disableDynamicChartjsSettings(configuration);
                this._canvas = BbPromise.promisifyAll(window.document.getElementById('myChart'));
                this._ctx = this._canvas.getContext('2d');
 
                this._chart = new Chartjs(this._ctx, configuration);
                return this._chart;
            });
 
    }
    /**
     * Retrives the drawn chart as a stream
     *
     * @param {String} imageType The image type name. Valid values are image/png image/jpeg
     * @returns {Stream} The image as an in-memory stream
     */
    getImageStream(imageType) {
        return this.getImageBuffer(imageType)
        .then(buffer => {
            var readableStream = new streamBuffers.ReadableStreamBuffer({
                frequency: 10,       // in milliseconds.
                chunkSize: 2048     // in bytes.
            });
            readableStream.put(buffer);
            readableStream.stop();
            return {
                stream: readableStream,
                length: buffer.length
            };
        });
    }
    /**
     * Retrives the drawn chart as a buffer
     *
     * @param {String} imageType The image type name. Valid values are image/png image/jpeg
     * @returns {Array} The image as an in-memory buffer
     */
    getImageBuffer(imageType) {
        return new BbPromise((resolve, reject) => {
            this._canvas.toBlob((blob, err) => {
                Iif (err) {
                    return reject(err);
                }
                var buffer = jsdom.blobToBuffer(blob);
                return resolve(buffer);
            }, imageType);
        });
    }
     /**
     * Returns image in the form of Data Url
     *
     * @param {String} imageType The image type name. Valid values are image/png image/jpeg
     * @returns {Promise} A promise that resolves when the image is received in the form of data url
     */
    getImageDataUrl(imageType) {
        return new BbPromise((resolve, reject) => {
            this._canvas.toDataURL(imageType,(err, img) => {
                Iif (err) {
                    return reject(err);
                }
                return resolve(img);
            });
        });
    }
    /**
     * Writes chart to a file
     *
     * @param {String} imageType The image type name. Valid values are image/png image/jpeg
     * @returns {Promise} A promise that resolves when the image is written to a file
     */
    writeImageToFile(imageType, filePath) {
        return this.getImageBuffer(imageType)
        .then(buffer => {
            var out = fs.createWriteStream(filePath);
            return out.write(buffer);
        });
    }
    /**
     * Destroys the virtual DOM and canvas -- releasing any native resources
     */
    destroy() {
 
        if (this._windowPropertiesToDestroy) {
            this._windowPropertiesToDestroy.forEach((prop) => {
                delete global[prop];
            });
        }
 
        if (this._window) {
            this._window.close();
            delete this._window;
        }
 
        delete this._windowPropertiesToDestroy;
        delete global.navigator;
        delete global.CanvasRenderingContext2D;
    }
}
module.exports = ChartjsNode;