public inbox for [email protected]
help / color / mirror / Atom feedFrom: Aditya Toshniwal <[email protected]>
To: pgadmin-hackers <[email protected]>
Subject: [pgAdmin][RM6197] Incomplete ERD image downloaded.
Date: Thu, 11 Feb 2021 16:15:34 +0530
Message-ID: <CAM9w-_=BJfbcWJ0TZ0TLzbe4KxDEY2YN=o4NO4DFOqFaZhRArg@mail.gmail.com> (raw)
Hi Hackers,
Attached patch will improve and fix things except, the links are partially
rendered in case of SVG overflow. That needs to be fixed in html2canvas
library. Ref - https://github.com/niklasvh/html2canvas/issues/1486. In
addition, safari seems to be distorting the link paths.
Considering the majority of users are on Chrome and Firefox, the fix will
help most users until issues for Safari are fixed.
Please review.
--
Thanks,
Aditya Toshniwal
pgAdmin hacker | Sr. Software Engineer | *edbpostgres.com*
<http://edbpostgres.com;
"Don't Complain about Heat, Plant a TREE"
Attachments:
[application/octet-stream] RM6197.patch (8.2K, 3-RM6197.patch)
download | inline diff:
diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/ERDCore.js b/web/pgadmin/tools/erd/static/js/erd_tool/ERDCore.js
index 3935af360..23b592149 100644
--- a/web/pgadmin/tools/erd/static/js/erd_tool/ERDCore.js
+++ b/web/pgadmin/tools/erd/static/js/erd_tool/ERDCore.js
@@ -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) => {
diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/ui_components/BodyWidget.jsx b/web/pgadmin/tools/erd/static/js/erd_tool/ui_components/BodyWidget.jsx
index 5451e868f..ff8a9c798 100644
--- a/web/pgadmin/tools/erd/static/js/erd_tool/ui_components/BodyWidget.jsx
+++ b/web/pgadmin/tools/erd/static/js/erd_tool/ui_components/BodyWidget.jsx
@@ -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);
@@ -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() {
diff --git a/web/pgadmin/tools/erd/static/scss/_erd.scss b/web/pgadmin/tools/erd/static/scss/_erd.scss
index a54df1284..f48d65b4c 100644
--- a/web/pgadmin/tools/erd/static/scss/_erd.scss
+++ b/web/pgadmin/tools/erd/static/scss/_erd.scss
@@ -74,10 +74,6 @@
.html2canvas-reset {
background-image: none !important;
overflow: auto !important;
-
- & > svg, & > div {
- transform: none !important;
- }
}
.diagram-canvas{
view thread (2+ messages) latest in thread
reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: [email protected]
Cc: [email protected]
Subject: Re: [pgAdmin][RM6197] Incomplete ERD image downloaded.
In-Reply-To: <CAM9w-_=BJfbcWJ0TZ0TLzbe4KxDEY2YN=o4NO4DFOqFaZhRArg@mail.gmail.com>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox