mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Fixed an issue where the ERD image is not properly downloaded. Fixes #6197
This commit is contained in:
parent
be090552f8
commit
c1e80ac38a
@ -40,4 +40,5 @@ Bug fixes
|
||||
| `Issue #6180 <https://redmine.postgresql.org/issues/6180>`_ - Updated missing documentation for the 'Download Image' option in ERD.
|
||||
| `Issue #6187 <https://redmine.postgresql.org/issues/6187>`_ - Limit the upgrade check to run once per day.
|
||||
| `Issue #6193 <https://redmine.postgresql.org/issues/6193>`_ - Ensure that ERD throws a warning before closing unsaved changes if open in a new tab.
|
||||
| `Issue #6197 <https://redmine.postgresql.org/issues/6197>`_ - Fixed an issue where the ERD image is not properly downloaded.
|
||||
| `Issue #6208 <https://redmine.postgresql.org/issues/6208>`_ - Fixed an issue where utility(Backup, Maintenance, ...) jobs are failing when the log level is set to DEBUG.
|
||||
|
@ -53,6 +53,8 @@ export default class ERDCore {
|
||||
let model = new ERDModel();
|
||||
if(data) {
|
||||
model.deserializeModel(data, this.engine);
|
||||
this.fireEvent(model.getOptions(), 'offsetUpdated', true);
|
||||
this.fireEvent(model.getOptions(), 'zoomUpdated', true);
|
||||
}
|
||||
|
||||
const registerNodeEvents = (node) => {
|
||||
|
@ -87,22 +87,12 @@ export default class BodyWidget extends React.Component {
|
||||
this.noteNode = null;
|
||||
this.keyboardActionObj = null;
|
||||
|
||||
this.onLoadDiagram = this.onLoadDiagram.bind(this);
|
||||
this.onSaveDiagram = this.onSaveDiagram.bind(this);
|
||||
this.onSaveAsDiagram = this.onSaveAsDiagram.bind(this);
|
||||
this.onSQLClick = this.onSQLClick.bind(this);
|
||||
this.onImageClick = this.onImageClick.bind(this);
|
||||
this.onAddNewNode = this.onAddNewNode.bind(this);
|
||||
this.onEditNode = this.onEditNode.bind(this);
|
||||
this.onCloneNode = this.onCloneNode.bind(this);
|
||||
this.onDeleteNode = this.onDeleteNode.bind(this);
|
||||
this.onNoteClick = this.onNoteClick.bind(this);
|
||||
this.onNoteClose = this.onNoteClose.bind(this);
|
||||
this.onOneToManyClick = this.onOneToManyClick.bind(this);
|
||||
this.onManyToManyClick = this.onManyToManyClick.bind(this);
|
||||
this.onAutoDistribute = this.onAutoDistribute.bind(this);
|
||||
this.onDetailsToggle = this.onDetailsToggle.bind(this);
|
||||
this.onHelpClick = this.onHelpClick.bind(this);
|
||||
_.bindAll(this, ['onLoadDiagram', 'onSaveDiagram', 'onSaveAsDiagram', 'onSQLClick',
|
||||
'onImageClick', 'onAddNewNode', 'onEditNode', 'onCloneNode', 'onDeleteNode', 'onNoteClick',
|
||||
'onNoteClose', 'onOneToManyClick', 'onManyToManyClick', 'onAutoDistribute', 'onDetailsToggle',
|
||||
'onDetailsToggle', 'onHelpClick'
|
||||
]);
|
||||
|
||||
this.diagram.zoomToFit = this.diagram.zoomToFit.bind(this.diagram);
|
||||
this.diagram.zoomIn = this.diagram.zoomIn.bind(this.diagram);
|
||||
this.diagram.zoomOut = this.diagram.zoomOut.bind(this.diagram);
|
||||
@ -217,7 +207,7 @@ export default class BodyWidget extends React.Component {
|
||||
}, ()=>this.registerKeyboardShortcuts());
|
||||
});
|
||||
|
||||
this.props.panel?.on(window.wcDocker?.EVENT.CLOSING, () => {
|
||||
this.props.panel.on(window.wcDocker.EVENT.CLOSING, () => {
|
||||
if(this.state.dirty) {
|
||||
this.closeOnSave = false;
|
||||
this.confirmBeforeClose();
|
||||
@ -552,6 +542,30 @@ export default class BodyWidget extends React.Component {
|
||||
onImageClick() {
|
||||
this.setLoading(gettext('Preparing the image...'));
|
||||
|
||||
/* Move the diagram temporarily to align it to top-left of the canvas so that when
|
||||
* taking the snapshot all the nodes are covered. Once the image is taken, repaint
|
||||
* the canvas back to original state.
|
||||
* Code referred from - zoomToFitNodes function.
|
||||
*/
|
||||
let nodesRect = this.diagram.getEngine().getBoundingNodesRect(this.diagram.getModel().getNodes(), 10);
|
||||
let canvasRect = this.canvasEle.getBoundingClientRect();
|
||||
let canvasTopLeftPoint = {
|
||||
x: canvasRect.left,
|
||||
y: canvasRect.top
|
||||
};
|
||||
let nodeLayerTopLeftPoint = {
|
||||
x: canvasTopLeftPoint.x + this.diagram.getModel().getOffsetX(),
|
||||
y: canvasTopLeftPoint.y + this.diagram.getModel().getOffsetY()
|
||||
};
|
||||
let nodesRectTopLeftPoint = {
|
||||
x: nodeLayerTopLeftPoint.x + nodesRect.getTopLeft().x,
|
||||
y: nodeLayerTopLeftPoint.y + nodesRect.getTopLeft().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('html2canvas-reset');
|
||||
this.canvasEle.style.width = this.canvasEle.scrollWidth + 'px';
|
||||
@ -567,10 +581,16 @@ export default class BodyWidget extends React.Component {
|
||||
'font'
|
||||
];
|
||||
let svgElems = Array.from(targetElem.getElementsByTagName("svg"));
|
||||
for (let svgElement of svgElems) {
|
||||
svgElement.setAttribute('width', svgElement.clientWidth);
|
||||
svgElement.setAttribute('height', svgElement.clientHeight);
|
||||
recurseElementChildren(svgElement);
|
||||
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.parentNode.appendChild(wrap);
|
||||
wrap.appendChild(svgEle);
|
||||
recurseElementChildren(svgEle);
|
||||
}
|
||||
function recurseElementChildren(node) {
|
||||
if (!node.style)
|
||||
@ -586,40 +606,45 @@ export default class BodyWidget extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
html2canvas(this.canvasEle, {
|
||||
width: this.canvasEle.scrollWidth + 10,
|
||||
height: this.canvasEle.scrollHeight + 10,
|
||||
scrollX: 0,
|
||||
scrollY: 0,
|
||||
useCORS: true,
|
||||
allowTaint: true,
|
||||
backgroundColor: window.getComputedStyle(this.canvasEle).backgroundColor,
|
||||
onclone: (clonedEle)=>{
|
||||
setSvgInlineStyles(clonedEle);
|
||||
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}`;
|
||||
}
|
||||
this.props.alertify.alert()
|
||||
.set('title', gettext('Error'))
|
||||
.set('message', msg).show();
|
||||
}).then(()=>{
|
||||
/* Revert back to the original CSS styles */
|
||||
this.canvasEle.classList.remove('html2canvas-reset');
|
||||
this.canvasEle.style.width = '';
|
||||
this.canvasEle.style.height = '';
|
||||
this.setLoading(null);
|
||||
});
|
||||
setTimeout(()=>{
|
||||
html2canvas(this.canvasEle, {
|
||||
width: this.canvasEle.scrollWidth + 10,
|
||||
height: this.canvasEle.scrollHeight + 10,
|
||||
scrollX: 0,
|
||||
scrollY: 0,
|
||||
useCORS: true,
|
||||
allowTaint: true,
|
||||
backgroundColor: window.getComputedStyle(this.canvasEle).backgroundColor,
|
||||
onclone: (clonedEle)=>{
|
||||
setSvgInlineStyles(clonedEle);
|
||||
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}`;
|
||||
}
|
||||
this.props.alertify.alert()
|
||||
.set('title', gettext('Error'))
|
||||
.set('message', msg).show();
|
||||
}).then(()=>{
|
||||
/* Revert back to the original CSS styles */
|
||||
this.canvasEle.classList.remove('html2canvas-reset');
|
||||
this.canvasEle.style.width = '';
|
||||
this.canvasEle.style.height = '';
|
||||
this.canvasEle.childNodes.forEach((ele)=>{
|
||||
ele.style.transform = prevTransform;
|
||||
});
|
||||
this.setLoading(null);
|
||||
});
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
onOneToManyClick() {
|
||||
|
@ -74,10 +74,6 @@
|
||||
.html2canvas-reset {
|
||||
background-image: none !important;
|
||||
overflow: auto !important;
|
||||
|
||||
& > svg, & > div {
|
||||
transform: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.diagram-canvas{
|
||||
|
Loading…
Reference in New Issue
Block a user