Как сохранить paper в виде PNG картинки?

Я делаю свой редактор схем и диаграмм с использованием библиотеки JointJS. В Paper есть метод для получения JSON. А можно ли как-то получить изображение в PNG или JPEG? js:

var namespace = joint.shapes;

var link =  new namespace.standard.Link({
    labels: {
        attrs: {
            text: {
                text: 'Hello, World!'
            }
        }
    },
    router: { name: 'manhattan' }, // выбор маршрутизатора для гибкости связи
    connector: { name: 'normal' }, // выбор типа коннектора для стрелки
    attrs: {
        line: {
            stroke: 'black', // цвет стрелки
            strokeWidth: 1, // ширина стрелки
            targetMarker: {
                type: 'path',
                d: 'M 10 -5 0 0 10 5  Z', // форма маркера на конце стрелки
            },
        },
    },
    
})

var graph = new joint.dia.Graph({}, { cellNamespace: namespace });

var paper = new joint.dia.Paper({
    el: document.getElementById('canvas'),
    model: graph,
    width: 1300,
    height: 600,
    gridSize: 10,
    drawGrid: true,
    background: {
        color: 'rgba(0, 255, 0, 0.3)'
    },
    cellViewNamespace: namespace,
    defaultLink: link,
    linkPinning: false,
    
});

function createToolsForElement(element){
joint.elementTools.InfoButton = joint.elementTools.Button.extend({
        name: 'info-button',
        options: {
            markup: [{
                tagName: 'circle',
                selector: 'button',
                attributes: {
                    'r': 7,
                    'fill': '#001DFF',
                    'cursor': 'pointer'
                }
            }, {
                tagName: 'path',
                selector: 'icon',
                attributes: {
                    'd': 'M -2 4 2 4 M 0 3 0 0 M -2 -1 1 -1 M -1 -4 1 -4',
                    'fill': 'none',
                    'stroke': '#FFFFFF',
                    'stroke-width': 2,
                    'pointer-events': 'none'
                }
            }],
            x: '100%',
            y: '100%',
            offset: {
                x: 0,
                y: 0
            },
            rotate: true,
            action: function(evt) {
                alert('View id: ' + this.id + '\n' + 'Model id: ' + this.model.id);
            }
        }
    });

    var boundaryTool = new joint.elementTools.Boundary({
        focusOpacity: 1,
        rotate: true
        
    });
    var infoButton = new joint.elementTools.InfoButton();
    var removeButton = new joint.elementTools.Remove({
        focusOpacity: 0.5,
        rotate: true,
        // top-mid
        x: '0%',
        y: '0%',
    });
    var connectNode = new joint.elementTools.Connect({
        x: '110%',
        y: '55%',
        offset: { x: -5, y: -5 },
        magnet: 'body'
        
    });
   
    var toolsView = new joint.dia.ToolsView({
        tools: [
            boundaryTool,
            infoButton,
            removeButton, connectNode
        ]
    });
    
    
    var elementView = element.findView(paper);
    elementView.addTools(toolsView);
     paper.on('element:mouseenter', function(elementView) {
        elementView.showTools();
    });
     paper.on('element:mouseleave', function(elementView) {
        elementView.hideTools();
    });

    
    var mask = joint.highlighters.mask;

    paper.on('element:pointerclick', (elementView) => {
        mask.add(elementView, { selector: 'root' }, 'my-element-highlight', {
            deep: true,
            attrs: {
                'stroke': '#FF4365',
                'stroke-width': 3
            }
        });
    });
    paper.on('element:magnet:pointerclick', (elementView, magnet, evt) => {
        // Prevent highlighting the body of the element
        evt.stopPropagation();
        // Find the port ID of the selected magnet
        const port = cellView.findAttribute('port', magnet);
        mask.add(elementView, { port }, 'my-port-highlight', {
            attrs: {
                'stroke': '#FF4365',
                'stroke-width': 3
            }
        });
    });

    paper.on('link:pointerclick', (linkView) => {
        mask.add(linkView, { selector: 'line' }, 'my-link-highlight', {
            // Draw the highlighter under the LinkView
            layer: 'back',
            attrs: {
                'stroke': '#FF4365',
                'stroke-width': 3,
                'stroke-linecap': 'square'
            }
        });
    });

    paper.on('link:label:pointerdown', (linkView, evt) => {
        // Prevent highlighting the line of the link
        evt.stopPropagation();
        // Find the index of the selected label
        const label = cellView.findAttribute('label-idx', evt.target);
        mask.add(linkView, { label }, 'my-label-highlight', {
            // Decrease the gap between the label and highlighter
            padding: 1,
            attrs: {
                'stroke': '#FF4365',
                'stroke-width': 3
            }
        });
    });
    paper.on('blank:pointerclick', function() {
        // Remove all Highlighters from all cells
        graph.getCells().forEach(function(cell) {
            mask.remove(cell.findView(paper));
        });
    });


}




// Получаем все ссылки в боковой панели
const sidebarLinks = document.querySelectorAll("#sidebar .geItem");
const clearButton = document.getElementById('clear-button');
const saveButton = document.getElementById('save-button');
const openButton = document.getElementById('open-button');


// Проходимся по каждой ссылке и добавляем прослушиватель событий
sidebarLinks.forEach(link => {
    link.addEventListener("click", function() {
        // Здесь можно выполнить нужные действия при клике на ссылку
        // Например, можно получить значение атрибута data-shape
        const shape = this.getAttribute("data-shape");
        createElement(shape);
        console.log("Clicked on shape:", shape);
    });
});

clearButton.addEventListener("click", function() {
    graph.clear();
});
// Функция для сохранения JSON в файл
function saveJSONToFile(jsonData, fileName) {
    // Создаем новый объект Blob для хранения JSON данных
    const blob = new Blob([JSON.stringify(jsonData)], { type: 'application/json' });

    // Создаем ссылку для скачивания файла
    const url = URL.createObjectURL(blob);

    // Создаем элемент <a>, устанавливаем ему атрибуты для скачивания файла и кликаем на него
    const link = document.createElement('a');
    link.href = url;
    link.download = fileName;
    link.click();

    // Очищаем ссылку после завершения скачивания
    URL.revokeObjectURL(url);
}

// Функция для загрузки JSON файла
function loadJSONFromFile(callback) {
    // Создаем input элемент для выбора файла
    const input = document.createElement('input');
    input.type = 'file';
    input.accept = 'application/json';

    // Добавляем обработчик события выбора файла
    input.addEventListener('change', function() {
        // Проверяем, что файл был выбран
        if (input.files.length > 0) {
            const file = input.files[0];
            const reader = new FileReader();

            // Обработчик события загрузки файла
            reader.onload = function(event) {
                // Парсим JSON из содержимого файла
                const jsonData = JSON.parse(event.target.result);
                // Вызываем колбэк с загруженными данными
                callback(jsonData);
            };

            // Читаем содержимое файла как текст
            reader.readAsText(file);
        }
    });

    // Кликаем на input элемент, чтобы вызвать окно выбора файла
    input.click();
}

// Обработчик события нажатия на кнопку сохранения
saveButton.addEventListener("click", function() {
    // Получаем JSON данные из графа
    const jsonData = graph.toJSON();
    // Вызываем функцию сохранения JSON в файл
    saveJSONToFile(jsonData, 'graph.json');
});

saveAsPngButton.addEventListener("click", function() {
    // Получение базового изображения в формате data URL
    var imageDataURL = paper.toDataURL();

    // Создание ссылки для скачивания PNG-изображения
    var downloadLink = document.createElement('a');
    downloadLink.href = imageDataURL;
    downloadLink.download = 'diagram.png';

    // Добавление ссылки на страницу и эмуляция клика для запуска загрузки
    document.body.appendChild(downloadLink);
    downloadLink.click();
    document.body.removeChild(downloadLink);
});

// Обработчик события нажатия на кнопку загрузки
openButton.addEventListener("click", function() {
    // Вызываем функцию загрузки JSON файла
    loadJSONFromFile(function(jsonData) {
        // Подгружаем JSON данные в граф
        graph.fromJSON(jsonData);
    });
});
// Добавляем обработчики событий для движения стрелок
paper.on('link:pointerdown', function(linkView, evt) {
    const link = linkView.model;
    const startPoint = link.getSourcePoint();
    const endPoint = link.getTargetPoint();

    const dx = endPoint.x - startPoint.x;
    const dy = endPoint.y - startPoint.y;

    const handleMouseMove = function(evt) {
        const x = evt.clientX;
        const y = evt.clientY;
        const targetPoint = paper.clientToLocalPoint({ x, y });

        link.set('target', targetPoint);
    };

    const handleMouseUp = function(evt) {
        document.removeEventListener('mousemove', handleMouseMove);
        document.removeEventListener('mouseup', handleMouseUp);
    };

    document.addEventListener('mousemove', handleMouseMove);
    document.addEventListener('mouseup', handleMouseUp);
});

// Добавляем обработчик события для удаления стрелок
paper.on('link:remove', function(linkView, evt) {
    const link = linkView.model;
    link.remove();
});

Ответы (0 шт):