mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2024-11-26 02:30:21 -06:00
Fixed an issue in ERD tool where the downloaded images have a few links cut. #4995
This commit is contained in:
parent
9666bd6c8d
commit
5d2ce142dd
@ -33,6 +33,7 @@ Housekeeping
|
||||
Bug fixes
|
||||
*********
|
||||
|
||||
| `Issue #4995 <https://github.com/pgadmin-org/pgadmin4/issues/4995>`_ - Fixed an issue in ERD tool where the downloaded images have a few links cut.
|
||||
| `Issue #6482 <https://github.com/pgadmin-org/pgadmin4/issues/6482>`_ - Fixed an issue where the wrong message "Current database has been moved or renamed" is displayed when debugging any function.
|
||||
| `Issue #6674 <https://github.com/pgadmin-org/pgadmin4/issues/6674>`_ - Fix an issue where foreign table column name becomes "none" if the user changes any column data type.
|
||||
| `Issue #6718 <https://github.com/pgadmin-org/pgadmin4/issues/6718>`_ - Pin the cryptography version to fix PyO3 modules initialisation error.
|
||||
|
@ -116,7 +116,7 @@
|
||||
"dagre": "^0.8.4",
|
||||
"date-fns": "^2.24.0",
|
||||
"diff-arrays-of-objects": "^1.1.8",
|
||||
"html2canvas": "^1.0.0-rc.7",
|
||||
"html-to-image": "^1.11.11",
|
||||
"immutability-helper": "^3.0.0",
|
||||
"insert-if": "^1.1.0",
|
||||
"ip-address": "^7.1.0",
|
||||
|
@ -22,6 +22,7 @@ import ForeignKeySchema from '../../../../../browser/server_groups/servers/datab
|
||||
import diffArray from 'diff-arrays-of-objects';
|
||||
import TableSchema from '../../../../../browser/server_groups/servers/databases/schemas/tables/static/js/table.ui';
|
||||
import ColumnSchema from '../../../../../browser/server_groups/servers/databases/schemas/tables/columns/static/js/column.ui';
|
||||
import { Polygon } from '@projectstorm/geometry';
|
||||
|
||||
export default class ERDCore {
|
||||
constructor() {
|
||||
@ -175,6 +176,11 @@ export default class ERDCore {
|
||||
|
||||
getModel() {return this.getEngine().getModel();}
|
||||
|
||||
getBoundingLinksRect() {
|
||||
return Polygon.boundingBoxFromPolygons(
|
||||
this.getEngine().getModel().getLinks().map((l)=>l.getBoundingBox()));
|
||||
}
|
||||
|
||||
getNewNode(initData, dataUrl=null) {
|
||||
return this.getEngine().getNodeFactories().getFactory('table').generateModel({
|
||||
initialConfig: {
|
||||
|
@ -11,7 +11,7 @@ import * as React from 'react';
|
||||
import { CanvasWidget, Action, InputType } from '@projectstorm/react-canvas-core';
|
||||
import PropTypes from 'prop-types';
|
||||
import _ from 'lodash';
|
||||
import html2canvas from 'html2canvas';
|
||||
import {toPng} from 'html-to-image';
|
||||
|
||||
import ERDCore from '../ERDCore';
|
||||
import ConnectionBar, { STATUS as CONNECT_STATUS } from './ConnectionBar';
|
||||
@ -76,7 +76,7 @@ const styles = ((theme)=>({
|
||||
diagramContainer: {
|
||||
position: 'relative',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
flexGrow: 1,
|
||||
minHeight: 0,
|
||||
},
|
||||
diagramCanvas: {
|
||||
@ -722,66 +722,49 @@ class ERDTool extends React.Component {
|
||||
* the canvas back to original state.
|
||||
* Code referred from - zoomToFitNodes function.
|
||||
*/
|
||||
let nodesRect = this.diagram.getEngine().getBoundingNodesRect(this.diagram.getModel().getNodes(), 10);
|
||||
this.diagramContainerRef.current?.classList.add(this.props.classes.html2canvasReset);
|
||||
const margin = 10;
|
||||
let nodesRect = this.diagram.getEngine().getBoundingNodesRect(this.diagram.getModel().getNodes());
|
||||
let linksRect = this.diagram.getBoundingLinksRect();
|
||||
|
||||
// Check what is to the most top left - links or nodes?
|
||||
let topLeftXY = {
|
||||
x: nodesRect.getTopLeft().x,
|
||||
y: nodesRect.getTopLeft().y
|
||||
};
|
||||
if(topLeftXY.x > linksRect.getTopLeft().x) {
|
||||
topLeftXY.x = linksRect.getTopLeft().x;
|
||||
}
|
||||
if(topLeftXY.y > linksRect.getTopLeft().y) {
|
||||
topLeftXY.y = linksRect.getTopLeft().y;
|
||||
}
|
||||
topLeftXY.x -= margin;
|
||||
topLeftXY.y -= margin;
|
||||
|
||||
let canvasRect = this.canvasEle.getBoundingClientRect();
|
||||
let canvasTopLeftPoint = {
|
||||
let canvasTopLeftOnScreen = {
|
||||
x: canvasRect.left,
|
||||
y: canvasRect.top
|
||||
};
|
||||
let nodeLayerTopLeftPoint = {
|
||||
x: canvasTopLeftPoint.x + this.diagram.getModel().getOffsetX(),
|
||||
y: canvasTopLeftPoint.y + this.diagram.getModel().getOffsetY()
|
||||
x: canvasTopLeftOnScreen.x + this.diagram.getModel().getOffsetX(),
|
||||
y: canvasTopLeftOnScreen.y + this.diagram.getModel().getOffsetY()
|
||||
};
|
||||
let nodesRectTopLeftPoint = {
|
||||
x: nodeLayerTopLeftPoint.x + nodesRect.getTopLeft().x,
|
||||
y: nodeLayerTopLeftPoint.y + nodesRect.getTopLeft().y
|
||||
x: nodeLayerTopLeftPoint.x + topLeftXY.x,
|
||||
y: nodeLayerTopLeftPoint.y + topLeftXY.y
|
||||
};
|
||||
|
||||
let prevTransform = this.canvasEle.querySelector('div').style.transform;
|
||||
this.canvasEle.childNodes.forEach((ele)=>{
|
||||
ele.style.transform = `translate(${nodeLayerTopLeftPoint.x - nodesRectTopLeftPoint.x}px, ${nodeLayerTopLeftPoint.y - nodesRectTopLeftPoint.y}px) scale(1.0)`;
|
||||
});
|
||||
|
||||
/* Change the styles for suiting html2canvas */
|
||||
this.canvasEle.classList.add(this.props.classes.html2canvasReset);
|
||||
this.canvasEle.style.width = this.canvasEle.scrollWidth + 'px';
|
||||
this.canvasEle.style.height = this.canvasEle.scrollHeight + 'px';
|
||||
|
||||
/* html2canvas ignores CSS styles, set the CSS styles to inline */
|
||||
const setSvgInlineStyles = (targetElem) => {
|
||||
const transformProperties = [
|
||||
'fill',
|
||||
'color',
|
||||
'font-size',
|
||||
'stroke',
|
||||
'font',
|
||||
'display',
|
||||
];
|
||||
let svgElems = Array.from(targetElem.getElementsByTagName('svg'));
|
||||
for (let svgEle of svgElems) {
|
||||
svgEle.setAttribute('width', svgEle.clientWidth);
|
||||
svgEle.setAttribute('height', svgEle.clientHeight);
|
||||
/* Wrap the SVG in a div tag so that transforms are consistent with html */
|
||||
let wrap = document.createElement('div');
|
||||
wrap.setAttribute('style', svgEle.getAttribute('style'));
|
||||
svgEle.setAttribute('style', null);
|
||||
svgEle.style.display = 'block';
|
||||
svgEle.parentNode.insertBefore(wrap, svgEle);
|
||||
wrap.appendChild(svgEle);
|
||||
recurseElementChildren(svgEle);
|
||||
}
|
||||
function recurseElementChildren(node) {
|
||||
if (!node.style)
|
||||
return;
|
||||
|
||||
let styles = getComputedStyle(node);
|
||||
for (let transformProperty of transformProperties) {
|
||||
node.style[transformProperty] = styles[transformProperty];
|
||||
}
|
||||
for (let child of Array.from(node.childNodes)) {
|
||||
recurseElementChildren(child);
|
||||
}
|
||||
}
|
||||
};
|
||||
// Capture the links beyond the nodes as well.
|
||||
const linkOutsideWidth = linksRect.getBottomRight().x - nodesRect.getBottomRight().x;
|
||||
const linkOutsideHeight = linksRect.getBottomRight().y - nodesRect.getBottomRight().y;
|
||||
this.canvasEle.style.width = this.canvasEle.scrollWidth + (linkOutsideWidth > 0 ? linkOutsideWidth : 0) + margin + 'px';
|
||||
this.canvasEle.style.height = this.canvasEle.scrollHeight + (linkOutsideHeight > 0 ? linkOutsideHeight : 0) + margin + 'px';
|
||||
|
||||
setTimeout(()=>{
|
||||
let width = this.canvasEle.scrollWidth + 10;
|
||||
@ -796,46 +779,34 @@ class ERDTool extends React.Component {
|
||||
height = 32766;
|
||||
isCut = true;
|
||||
}
|
||||
html2canvas(this.canvasEle, {
|
||||
width: width,
|
||||
height: height,
|
||||
scrollX: 0,
|
||||
scrollY: 0,
|
||||
scale: 1,
|
||||
useCORS: true,
|
||||
allowTaint: true,
|
||||
backgroundColor: window.getComputedStyle(this.canvasEle).backgroundColor,
|
||||
onclone: (clonedEle)=>{
|
||||
setSvgInlineStyles(clonedEle.body.querySelector('div[data-test="diagram-container"]'));
|
||||
return clonedEle;
|
||||
},
|
||||
}).then((canvas)=>{
|
||||
let link = document.createElement('a');
|
||||
link.setAttribute('href', canvas.toDataURL('image/png'));
|
||||
link.setAttribute('download', this.getCurrentProjectName() + '.png');
|
||||
link.click();
|
||||
link.remove();
|
||||
}).catch((err)=>{
|
||||
console.error(err);
|
||||
let msg = gettext('Unknown error. Check console logs');
|
||||
if(err.name) {
|
||||
msg = `${err.name}: ${err.message}`;
|
||||
}
|
||||
Notify.alert(gettext('Error'), msg);
|
||||
}).then(()=>{
|
||||
/* Revert back to the original CSS styles */
|
||||
this.canvasEle.classList.remove(this.props.classes.html2canvasReset);
|
||||
this.canvasEle.style.width = '';
|
||||
this.canvasEle.style.height = '';
|
||||
this.canvasEle.childNodes.forEach((ele)=>{
|
||||
ele.style.transform = prevTransform;
|
||||
toPng(this.canvasEle)
|
||||
.then((dataUrl)=>{
|
||||
let link = document.createElement('a');
|
||||
link.setAttribute('href', dataUrl);
|
||||
link.setAttribute('download', this.getCurrentProjectName() + '.png');
|
||||
link.click();
|
||||
link.remove();
|
||||
}).catch((err)=>{
|
||||
console.error(err);
|
||||
let msg = gettext('Unknown error. Check console logs');
|
||||
if(err.name) {
|
||||
msg = `${err.name}: ${err.message}`;
|
||||
}
|
||||
Notify.alert(gettext('Error'), msg);
|
||||
}).then(()=>{
|
||||
/* Revert back to the original CSS styles */
|
||||
this.diagramContainerRef.current.classList.remove(this.props.classes.html2canvasReset);
|
||||
this.canvasEle.style.width = '';
|
||||
this.canvasEle.style.height = '';
|
||||
this.canvasEle.childNodes.forEach((ele)=>{
|
||||
ele.style.transform = prevTransform;
|
||||
});
|
||||
this.setLoading(null);
|
||||
if(isCut) {
|
||||
Notify.alert(gettext('Maximum image size limit'),
|
||||
gettext('The downloaded image has exceeded the maximum size of 32767 x 32767 pixels, and has been cropped to that size.'));
|
||||
}
|
||||
});
|
||||
this.setLoading(null);
|
||||
if(isCut) {
|
||||
Notify.alert(gettext('Maximum image size limit'),
|
||||
gettext('The downloaded image has exceeded the maximum size of 32767 x 32767 pixels, and has been cropped to that size.'));
|
||||
}
|
||||
});
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
@ -959,7 +930,7 @@ class ERDTool extends React.Component {
|
||||
this.erdDialogs.modal = this.context;
|
||||
|
||||
return (
|
||||
<Box ref={this.containerRef} height="100%">
|
||||
<Box ref={this.containerRef} height="100%" display="flex" flexDirection="column">
|
||||
<ConnectionBar status={this.state.conn_status} bgcolor={this.props.params.bgcolor}
|
||||
fgcolor={this.props.params.fgcolor} title={_.unescape(this.props.params.title)}/>
|
||||
<MainToolBar preferences={this.state.preferences} eventBus={this.eventBus}
|
||||
|
@ -3984,13 +3984,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"base64-arraybuffer@npm:^1.0.2":
|
||||
version: 1.0.2
|
||||
resolution: "base64-arraybuffer@npm:1.0.2"
|
||||
checksum: 15e6400d2d028bf18be4ed97702b11418f8f8779fb8c743251c863b726638d52f69571d4cc1843224da7838abef0949c670bde46936663c45ad078e89fee5c62
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"base64-js@npm:^1.0.2, base64-js@npm:^1.3.1":
|
||||
version: 1.5.1
|
||||
resolution: "base64-js@npm:1.5.1"
|
||||
@ -5238,15 +5231,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"css-line-break@npm:^2.1.0":
|
||||
version: 2.1.0
|
||||
resolution: "css-line-break@npm:2.1.0"
|
||||
dependencies:
|
||||
utrie: ^1.0.2
|
||||
checksum: 37b1fe632b03be7a287cd394cef8b5285666343443125c510df9cfb6a4734a2c71e154ec8f7bbff72d7c339e1e5872989b1c52d86162aed27d6cc114725bb4d0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"css-loader@npm:^6.7.2":
|
||||
version: 6.8.1
|
||||
resolution: "css-loader@npm:6.8.1"
|
||||
@ -7745,13 +7729,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"html2canvas@npm:^1.0.0-rc.7":
|
||||
version: 1.4.1
|
||||
resolution: "html2canvas@npm:1.4.1"
|
||||
dependencies:
|
||||
css-line-break: ^2.1.0
|
||||
text-segmentation: ^1.0.3
|
||||
checksum: c134324af57f3262eecf982e436a4843fded3c6cf61954440ffd682527e4dd350e0c2fafd217c0b6f9a455fe345d0c67b4505689796ab160d4ca7c91c3766739
|
||||
"html-to-image@npm:^1.11.11":
|
||||
version: 1.11.11
|
||||
resolution: "html-to-image@npm:1.11.11"
|
||||
checksum: b453beca72a697bf06fae4945e5460d1d9b1751e8569a0d721dda9485df1dde093938cc9bd9172b8df5fc23133a53a4d619777b3d22f7211cd8a67e3197ab4e8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -13145,7 +13126,7 @@ __metadata:
|
||||
eslint-plugin-react-hooks: ^4.3.0
|
||||
exports-loader: ^4.0.0
|
||||
html-react-parser: ^4.2.0
|
||||
html2canvas: ^1.0.0-rc.7
|
||||
html-to-image: ^1.11.11
|
||||
image-minimizer-webpack-plugin: ^3.8.2
|
||||
imagemin: ^8.0.1
|
||||
imagemin-mozjpeg: ^10.0.0
|
||||
@ -14463,15 +14444,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"text-segmentation@npm:^1.0.3":
|
||||
version: 1.0.3
|
||||
resolution: "text-segmentation@npm:1.0.3"
|
||||
dependencies:
|
||||
utrie: ^1.0.2
|
||||
checksum: 2e24632d59567c55ab49ac324815e2f7a8043e63e26b109636322ac3e30692cee8679a448fd5d0f0598a345f407afd0e34ba612e22524cf576d382d84058c013
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"text-table@npm:^0.2.0":
|
||||
version: 0.2.0
|
||||
resolution: "text-table@npm:0.2.0"
|
||||
@ -15056,15 +15028,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"utrie@npm:^1.0.2":
|
||||
version: 1.0.2
|
||||
resolution: "utrie@npm:1.0.2"
|
||||
dependencies:
|
||||
base64-arraybuffer: ^1.0.2
|
||||
checksum: c96fbb7d4d8855a154327da0b18e39b7511cc70a7e4bcc3658e24f424bb884312d72b5ba777500b8858e34d365dc6b1a921dc5ca2f0d341182519c6b78e280a5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"uuid@npm:^3.0.1":
|
||||
version: 3.4.0
|
||||
resolution: "uuid@npm:3.4.0"
|
||||
|
Loading…
Reference in New Issue
Block a user