diff --git a/package-lock.json b/package-lock.json index 991c526..9bbe46e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,7 @@ "cytoscape-bubblesets": "^3.2.0", "cytoscape-fcose": "^2.2.0", "cytoscape-layers": "^2.4.1", - "cytoscape-pdf-export": "cytoscape/cytoscape.js-pdf-export#release/0.0.1", + "cytoscape-pdf-export": "0.0.2", "dedent": "^1.5.1", "dotenv": "^6.2.0", "dotenv-defaults": "^5.0.0", @@ -6882,8 +6882,9 @@ } }, "node_modules/cytoscape-pdf-export": { - "version": "0.0.1", - "resolved": "git+ssh://git@github.com/cytoscape/cytoscape.js-pdf-export.git#597e29ab876bd77b908e54829cc2b4d7ab4e27b9", + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/cytoscape-pdf-export/-/cytoscape-pdf-export-0.0.2.tgz", + "integrity": "sha512-khmb423FkRIj2gQK843zS4SvDq3j5aB4BSvoDQgyplzb9X9hWYORuZJAmfT+GCaeuXpWHLEk0j4IpHVj3h09tw==", "dependencies": { "assert": "^2.0.0", "blob-stream": "^0.1.3", diff --git a/package.json b/package.json index 1c9d448..bcf60fa 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "cytoscape-bubblesets": "^3.2.0", "cytoscape-fcose": "^2.2.0", "cytoscape-layers": "^2.4.1", - "cytoscape-pdf-export": "cytoscape/cytoscape.js-pdf-export#release/0.0.1", + "cytoscape-pdf-export": "0.0.2", "dedent": "^1.5.1", "dotenv": "^6.2.0", "dotenv-defaults": "^5.0.0", diff --git a/src/client/components/home/content.js b/src/client/components/home/content.js index 23aa0b8..69872b7 100644 --- a/src/client/components/home/content.js +++ b/src/client/components/home/content.js @@ -141,7 +141,7 @@ const useContentStyles = makeStyles(theme => ({ }, description : { fontSize: '1rem', - color: theme.palette.secondary.main, + color: theme.palette.text.secondary, marginTop: theme.spacing(5), marginBottom: theme.spacing(5), [theme.breakpoints.down('xs')]: { @@ -179,7 +179,7 @@ const useContentStyles = makeStyles(theme => ({ sectionDescription: { maxWidth: 768, marginBottom: theme.spacing(6), - color: theme.palette.secondary.main, + color: theme.palette.text.secondary, [theme.breakpoints.down('xs')]: { fontSize: 'unset', }, diff --git a/src/client/components/home/footer.js b/src/client/components/home/footer.js index aca45fe..b3a0fb2 100644 --- a/src/client/components/home/footer.js +++ b/src/client/components/home/footer.js @@ -13,7 +13,7 @@ const useStyles = makeStyles(theme => ({ }, toolbar: { marginTop: theme.spacing(2), - color: theme.palette.secondary.main, + color: theme.palette.text.secondary, }, copyright: { [theme.breakpoints.down('sm')]: { diff --git a/src/client/components/home/recent-networks-list.js b/src/client/components/home/recent-networks-list.js index 82a643b..1a090d5 100644 --- a/src/client/components/home/recent-networks-list.js +++ b/src/client/components/home/recent-networks-list.js @@ -112,7 +112,7 @@ const useStyles = theme => ({ }, }, caption: { - color: theme.palette.secondary.main, + color: theme.palette.text.secondary, }, snackBar: { top: '10px', diff --git a/src/client/components/network-editor/bottom-drawer.js b/src/client/components/network-editor/bottom-drawer.js index 37dda4f..dbe212b 100644 --- a/src/client/components/network-editor/bottom-drawer.js +++ b/src/client/components/network-editor/bottom-drawer.js @@ -394,7 +394,7 @@ export function BottomDrawer({ controller, open, leftDrawerOpen, isMobile, isTab {open && ( <> goToNewCurrentRow(-1)} onNext={() => goToNewCurrentRow(1)} /> diff --git a/src/client/components/network-editor/controller.js b/src/client/components/network-editor/controller.js index 96a917c..32ca7cb 100644 --- a/src/client/components/network-editor/controller.js +++ b/src/client/components/network-editor/controller.js @@ -472,16 +472,14 @@ export class NetworkEditorController { return; parent.scratch(Scratch.LAYOUT_RUNNING, true); + const { cy } = this; const collapsed = parent.data('collapsed'); const shrinkFactor = 0.2; const spacingFactor = collapsed ? (1.0 / shrinkFactor) : shrinkFactor; - const nodes = parent.children(); const edges = nodes.internalEdges(); const connectedEdges = nodes.connectedEdges(); - const shouldAnimate = requestAnimate && nodes.size() < LARGE_CLUSTER_SIZE; - const automoveRule = parent.scratch(Scratch.AUTOMOVE_RULE); const layout = nodes.layout({ @@ -492,59 +490,77 @@ export class NetworkEditorController { spacingFactor }); - const onStop = layout.promiseOn('layoutstop'); + const layoutPromise = layout.promiseOn('layoutstop'); parent.data('collapsed', !collapsed); - connectedEdges.data('collapsed', !collapsed); - this.cy.edges().not(connectedEdges).data('collapsed', collapsed); + cy.edges().not(connectedEdges).data('collapsed', collapsed); if(collapsed) { edges.style('visibility', 'visible'); - onStop.then(() => { - nodes.data('collapsed', !collapsed); - }); - + layoutPromise.then(() => nodes.data('collapsed', !collapsed)); setTimeout(() => { nodes.select(); }, 0); } else { nodes.data('collapsed', !collapsed); - onStop.then(() => { - edges.style('visibility', 'hidden'); - }); + layoutPromise.then(() => edges.style('visibility', 'hidden')); } - const retPromise = onStop.then(() => { + const afterLayoutPromise = layoutPromise.then(() => { parent.scratch(Scratch.LAYOUT_RUNNING, false); this.bus.emit('toggleExpandCollapse', parent, collapsed); - if (collapsed) { + if(collapsed) { automoveRule.disable(); } else { automoveRule.enable(); } - const outOfBounds = nodes.add(parent).some(node => { // Check if any nodes are out of bounds - const extent = this.cy.extent(); - const bb = node.boundingBox(); - - return bb.x1 < extent.x1 || bb.x2 > extent.x2 || bb.y1 < extent.y1 || bb.y2 > extent.y2; - }); - - if (outOfBounds && collapsed) { - this.cy.animate({ - fit: { - eles: nodes.add(parent), - padding: DEFAULT_PADDING - }, - duration: 1200, - easing: 'spring(500, 37)' - }); + if(collapsed) { // if it was collapsed, this runs after the layout so its expanded now + const getAnimation = () => { + const bb = parent.renderedBoundingBox({ includeLabels: true }); + const extent = cy.renderedExtent(); + + // if the expanded cluster is larger than the viewport, then fit it to the viewport + if(bb.h > extent.h || bb.w > extent.w) { + return { + fit: { + eles: parent, + padding: DEFAULT_PADDING + } + }; + } + + // if the expanded cluster is out of bounds, then pan it into the viewport + const panBy = { x: 0, y: 0 }; + if(bb.x1 < extent.x1) { + panBy.x = extent.x1 - bb.x1 + DEFAULT_PADDING; + } else if(bb.x2 > extent.x2) { + panBy.x = extent.x2 - bb.x2 - DEFAULT_PADDING; + } + if(bb.y1 < extent.y1) { + panBy.y = extent.y1 - bb.y1 + DEFAULT_PADDING; + } else if(bb.y2 > extent.y2) { + panBy.y = extent.y2 - bb.y2 - DEFAULT_PADDING; + } + if(panBy.x != 0 || panBy.y != 0) { + return { panBy }; + } + }; + + const animation = getAnimation(); + if(animation) { + cy.animate({ + ...animation, + duration: 1200, + easing: 'spring(500, 37)' + }); + } } }); layout.run(); - return retPromise; + return afterLayoutPromise; } diff --git a/src/client/components/network-editor/export-controller.js b/src/client/components/network-editor/export-controller.js index 9da12c5..7e63659 100644 --- a/src/client/components/network-editor/export-controller.js +++ b/src/client/components/network-editor/export-controller.js @@ -151,6 +151,9 @@ export class ExportController { async _createNetworkPDFBlob() { const { cy } = this.controller; const blob = await cy.pdf({ + paperSize: 'LETTER', + orientation: 'LANDSCAPE', + full: true, // ignore zoom level includeSvgLayers: true, // include bubbles }); return blob; diff --git a/src/client/components/network-editor/left-drawer.js b/src/client/components/network-editor/left-drawer.js index 22b9fd8..40da171 100644 --- a/src/client/components/network-editor/left-drawer.js +++ b/src/client/components/network-editor/left-drawer.js @@ -471,14 +471,14 @@ const LeftDrawer = ({ controller, open, isMobile, isTablet, onClose }) => { renderValue={(value) => { return ( - { setOperationOptions[value].icon({color: setOperationsDisabled ? 'disabled' : 'primary'}) } + { setOperationOptions[value].icon({color: setOperationsDisabled ? 'disabled' : 'inherit'}) } ); }} > {Object.entries(setOperationOptions).map(([k, { label, description, icon }]) => ( - { icon({color: 'primary'}) } + { icon({color: 'inherit'}) } ))} diff --git a/src/client/components/network-editor/main.js b/src/client/components/network-editor/main.js index 995b450..05df144 100644 --- a/src/client/components/network-editor/main.js +++ b/src/client/components/network-editor/main.js @@ -322,21 +322,9 @@ const Main = ({ const menuDef = [ { - title: getUndoMenuTitle(undoType), - icon: , - onClick: () => controller.undoHandler.undo(), - isEnabled: () => undoEnabled, - }, - // { - // title: "Delete Selected Nodes", - // icon: , - // onClick: () => controller.deleteSelectedNodes(), - // }, - { - title: "Restore Network Layout", - icon: , - onClick: handleNetworkRestore, - unrelated: true, + title: "Zoom to Fit", + icon: , + onClick: panner.fit, }, { title: "Zoom In", icon: , @@ -345,10 +333,6 @@ const Main = ({ title: "Zoom Out", icon: , onClick: panner.zoomOut, - }, { - title: "Fit Figure to Screen", - icon: , - onClick: panner.fit, unrelated: true, }, { title: "Enable Drag-to-Select", @@ -358,6 +342,22 @@ const Main = ({ isSelected: () => !cy.userPanningEnabled(), alwaysShow: true, // always show on desktop/tablet, but still hides on mobile unrelated: true, + }, { + title: getUndoMenuTitle(undoType), + icon: , + onClick: () => controller.undoHandler.undo(), + isEnabled: () => undoEnabled, + }, + // { + // title: "Delete Selected Nodes", + // icon: , + // onClick: () => controller.deleteSelectedNodes(), + // }, + { + title: "Restore Network Layout", + icon: , + onClick: handleNetworkRestore, + unrelated: true, }, { title: "Download Data and Images", icon: ,