Как сохранить 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();
});