infoExport.js

/**
 * @file infoExport.js
 * @description This file contains every function that allows a user to download data
 * may that be pictures or another file type (.csv, base64, etc..).
 * 
 * Functions included in this file : 
 *  - **downloadCanvasAsImage**
 *  - **copyCanvasToClipboard**
 *  - **downloadDataToCsv**
 * 
 * @version 1.0.0
 * @since 2024-05-31
 * @author Owen Pichot
 * 
 * @license Public Domain
 */

/**
 * @module Exports
 */

/**
 * Downloads the current canvas content as an image file.
 *
 * This function creates a temporary canvas element, draws the current content
 * of the global CANVAS onto it, and then converts it to a specified image format
 * (PNG or JPEG). The resulting image is then downloaded to the user's device
 * with a predefined filename based on the image type.
 *
 * @function downloadCanvasAsImage
 * @memberof module:Exports
 * @param {string} imageType - The type of the image to download. Accepted values are "png" or "jpeg".
 * @throws Will throw an error if there is an issue with the canvas conversion or download process.
 * @returns {void}
 */
function downloadCanvasAsImage(imageType) {
    try{
        let imageUrl
        let exportCanvas = document.createElement('canvas');
        exportCanvas.width = CANVAS.width;
        exportCanvas.height = CANVAS.height;
    
        let exportCtx = exportCanvas.getContext('2d');
    
        exportCtx.fillStyle = '#000000';
        exportCtx.fillRect(0, 0, exportCanvas.width, exportCanvas.height);
        
        exportCtx.drawImage(CANVAS, 0, 0);
    
        if (imageType === "png") {
            imageUrl = exportCanvas.toDataURL("image/png");
        }else if (imageType === "jpeg") {
            imageUrl = exportCanvas.toDataURL("image/jpeg");
        }

        // Create temporary link element
        let downloadLink = document.createElement('a');
        downloadLink.href = imageUrl;
    
        // set the download filename
        if (imageType === "png") {
            downloadLink.download = "oscilloscope_snapshot.png";
        }else if (imageType === "jpeg") {
            downloadLink.download = "oscilloscope_snapshot.jpeg";
        }
        
        document.body.appendChild(downloadLink);
        downloadLink.click();
        document.body.removeChild(downloadLink);
        showToast("Image downloaded successfully !", "toast-success");
    } catch (error) {
        console.error('Failed to download canvas as image', error);
        showToast("Error while downloading the image..", "toast-error");
        return;
    }
};

/**
 * Copies the canvas content to the clipboard as an image. This function uses the Clipboard API to create a blob from the canvas and then writes this blob to the clipboard as an image in PNG format.
 * It handles different scenarios including API unavailability and operational failures by displaying appropriate toast notifications.
 *
 * @function copyCanvasToClipboard
 * @memberof module:Exports
 * @throws {Error} Throws an error and warns the user if the image could not be copied to the clipboard.
 * @returns {void}
 */
function copyCanvasToClipboard() {
    // first we check in case this browser does not have the clipboard API
    if (!navigator.clipboard || !window.ClipboardItem) {
        showToast("Your browser does not support this feature", "toast-error");
        return;
    }
  
    CANVAS.toBlob(function(blob) {
      try {
        const item = new ClipboardItem({ "image/png": blob });
        navigator.clipboard.write([item]).then(function() {
          console.log('Canvas image copied to clipboard');
          showToast("Image copied to your clipboard !", "toast-success");
        }).catch(function(error) {
          console.error('Copying to clipboard failed', error);
          showToast("Error while copying to the clipboard..", "toast-error");
        });
      } catch (error) {
        console.error('Failed to copy canvas to clipboard', error);
        showToast("Error while copying to the clipboard..", "toast-error");
      }
    }, 'image/png');
};

/**
 * Takes every single point from every single channel currently on screen and maps it to a csv file.
 * 
 * Within the csv file, every column is a channel and every line is a point N from said channel.
 * 
 * We also create a pseudo/temp link element to click it and start the download as soon as possible.
 * 
 * @function downloadDataToCsv
 * @memberof module:Exports
 * @returns {void}
 * @throws {Error} Throws an error if the function fails and warns the user something went wrong.
 */
function downloadDataToCsv() {
    try {
        const channelNames = Object.keys(channelData).sort();//get channel names and sort them
        const csvHeader = channelNames.join(',') + '\n';//set csv header
        const maxPointsLength = Math.max(...channelNames.map(name => channelData[name].points.length));//get each channel max length
      
        let csvRows = [];//create csv rows
        for (let i = 0; i < maxPointsLength; i++) {
          let row = channelNames.map(name => {
            //we leave the row space blank if there are no samples at that index
            return channelData[name].points[i] || '';
          }).join(',');
          csvRows.push(row);
        }
      
        // combine headers w/ rows and create blob for the download
        const csvString = csvHeader + csvRows.join('\n');
        const blob = new Blob([csvString], { type: 'text/csv;charset=utf-8;' });
      
        //create the link for the download, then trigger it
        const url = URL.createObjectURL(blob);
        const link = document.createElement('a');
        link.setAttribute('href', url);
        link.setAttribute('download', 'channels_data.csv');
        document.body.appendChild(link); // needed with firefox
        link.click();
        document.body.removeChild(link);
        URL.revokeObjectURL(url);
        showToast("Data downloaded successfully !", "toast-success");
    } catch (error) {
        console.error('Failed to download data to CSV', error);
        showToast("Error while downloading the data..", "toast-error");
    }
};