shared.js

// Common functions for use across other geoApi modules
'use strict';

function getLayerTypeBuilder(esriBundle) {
    /**
    * Will return a string indicating the type of layer a layer object is.
    * @method getLayerType
    * @param  {Object} layer an ESRI API layer object
    * @return {String} layer type
    */
    return layer => {
        if (layer instanceof esriBundle.FeatureLayer) {
            return 'FeatureLayer';
        } else if (layer instanceof esriBundle.WmsLayer) {
            return 'WmsLayer';
        } else if (layer instanceof esriBundle.ArcGISDynamicMapServiceLayer) {
            return 'ArcGISDynamicMapServiceLayer';
        } else if (layer instanceof esriBundle.ArcGISTiledMapServiceLayer) {
            return 'ArcGISTiledMapServiceLayer';
        } else {
            // Can add more types above as we support them
            return 'UNKNOWN';
        }
    };

}

/**
* Get a 'good enough' uuid. For backup purposes if client does not supply its own
* unique layer id
*
* @method  generateUUID
* @returns {String} a uuid
*/
function generateUUID() {
    let d = Date.now();
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
        // do math!
        /*jslint bitwise: true */
        const r = (d + Math.random() * 16) % 16 | 0;
        d = Math.floor(d / 16);
        return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
        /*jslint bitwise: false */
    });
}

/**
* Convert an image to a canvas element
*
* @param {String} url image url to convert (result from the esri print task)
* @param {Object} canvas [optional = null] canvas to draw the image upon; if not supplied, a new canvas will be made
* @param {Boolean} crossOrigin [optional = true] when set, tries to fetch an image with crossOrigin = anonymous
* @return {Promise} conversion promise resolving into a canvas of the image
*/
function convertImageToCanvas(url, canvas = null, crossOrigin = true) {
    canvas = canvas || window.document.createElement('canvas');

    const image = window.document.createElement('img'); // create image node

    if (crossOrigin) {
        image.crossOrigin = 'Anonymous'; // configure the CORS request
    }

    const conversionPromise = new Promise((resolve, reject) => {
        image.addEventListener('load', () => {

            canvas.width = image.width; // changing canvas size will clear all previous content
            canvas.height = image.height;
            canvas.getContext('2d').drawImage(image, 0, 0); // draw image onto a canvas

            // return canvas
            resolve(canvas);
        });
        image.addEventListener('error', error =>
            reject(error));
    });

    // set image source to the one generated from the print task
    image.src = url;

    return conversionPromise;
}

/**
 * Loads an image (as crossing) and converts it to dataURL. If a supplied imageUri is already a dataURL, just return it.
 * If an image fails to load with the crossing attribute, return the original imageUri
 *
 * @function convertImagetoDataURL
 * @param {String} imageUri url of the image to load and convert
 * @param {String} imageType [optional = 'image/png'] format of the image representation
 * @return {Promise} promise resolving with the dataURL of the image
 */
function convertImagetoDataURL(imageUri, imageType = 'image/png') {
    // this is already a dataUrl, just return
    if (imageUri.startsWith('data')) {
        return Promise.resolve(imageUri);
    }

    const loadingPromise = convertImageToCanvas(imageUri)
        .then(canvas => {
            // Converting image to dataURL
            return canvas.toDataURL(imageType);
        })
        .catch(error => {
            console.error('Failed to load crossorigin image', imageUri, error);
            return imageUri;
        });

    return loadingPromise;
}

module.exports = esriBundle => ({
    getLayerType: getLayerTypeBuilder(esriBundle),
    generateUUID,
    convertImageToCanvas,
    convertImagetoDataURL
});