Skip to content

Commit

Permalink
Merge pull request #198 from BornaP/export-to-image
Browse files Browse the repository at this point in the history
Export diagram to image format - .png and .jpeg
  • Loading branch information
BornaP authored Jun 15, 2016
2 parents 81d6d62 + 14a24cf commit 30dd5cf
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 9 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
"fixed-data-table": "^0.6.0",
"history": "^1.12.6",
"html-webpack-plugin": "^2.19.0",
"html2canvas": "^0.5.0-beta4",
"imports-loader": "^0.6.5",
"jointjs": "^0.9.9",
"jquery": "^2.2.0",
Expand Down
29 changes: 29 additions & 0 deletions src/renderer/actions/databases.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import path from 'path';
import html2canvas from 'html2canvas';
import { getCurrentDBConn } from './connections';
import * as FileHandler from '../utils/file-handler';

Expand All @@ -17,6 +18,9 @@ export const SAVE_DIAGRAM_FAILURE = 'SAVE_DIAGRAM_FAILURE';
export const OPEN_DIAGRAM_REQUEST = 'OPEN_DIAGRAM_REQUEST';
export const OPEN_DIAGRAM_SUCCESS = 'OPEN_DIAGRAM_SUCCESS';
export const OPEN_DIAGRAM_FAILURE = 'OPEN_DIAGRAM_FAILURE';
export const EXPORT_DIAGRAM_REQUEST = 'EXPORT_DIAGRAM_REQUEST';
export const EXPORT_DIAGRAM_SUCCESS = 'EXPORT_DIAGRAM_SUCCESS';
export const EXPORT_DIAGRAM_FAILURE = 'EXPORT_DIAGRAM_FAILURE';


export function filterDatabases(name) {
Expand Down Expand Up @@ -60,6 +64,31 @@ export function saveDatabaseDiagram(diagramJSON) {
};
}

export function exportDatabaseDiagram(diagram, imageType) {
return async (dispatch) => {
dispatch({ type: EXPORT_DIAGRAM_REQUEST });
try {
// html2canvas library only captures elements in window view
diagram.scrollIntoView();

const filters = [{ name: 'Images', extensions: [imageType] }];
const fileName = await FileHandler.showSaveDialog(filters);

// Create image
const canvas = await html2canvas(diagram, { background: '#fff' });
const image = await canvas.toDataURL(`image/${imageType}`);
const imageData = image.replace(/^data:image\/\w+;base64,/, '');
const buff = new Buffer(imageData, 'base64');

await FileHandler.saveFile(fileName, buff, 'binary');

dispatch({ type: EXPORT_DIAGRAM_SUCCESS });
} catch (error) {
dispatch({ type: EXPORT_DIAGRAM_FAILURE, error });
}
};
}

export function openDatabaseDiagram() {
return async (dispatch, getState) => {
dispatch({ type: OPEN_DIAGRAM_REQUEST });
Expand Down
40 changes: 36 additions & 4 deletions src/renderer/components/database-diagram-modal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ export default class DatabaseDiagramModal extends Component {
columnsByTable: PropTypes.object,
tableKeys: PropTypes.object,
diagramJSON: PropTypes.string,
isSaving: PropTypes.bool,
onGenerateDatabaseDiagram: PropTypes.func.isRequired,
addRelatedTables: PropTypes.func.isRequired,
onSaveDatabaseDiagram: PropTypes.func.isRequired,
onExportDatabaseDiagram: PropTypes.func.isRequired,
onOpenDatabaseDiagram: PropTypes.func.isRequired,
onClose: PropTypes.func.isRequired,
}
Expand Down Expand Up @@ -79,6 +81,17 @@ export default class DatabaseDiagramModal extends Component {
addRelatedTables(relatedTables);
}

onExportDatabaseDiagram(imageType) {
const { onExportDatabaseDiagram } = this.props;
const diagram = this.refs.databaseDiagram.refs.diagram;

// fix - reapply css roles which html2canvas ignores for some reason
$('.link-tools, .marker-arrowheads', diagram).css({ display: 'none' });
$('.link, .connection', diagram).css({ fill: 'none' });

onExportDatabaseDiagram(diagram, imageType);
}

showDiagramIfNeeded(props) {
if (this.isDataLoaded(props) || props.diagramJSON) {
this.setState({ showDatabaseDiagram: true });
Expand Down Expand Up @@ -165,6 +178,7 @@ export default class DatabaseDiagramModal extends Component {
columnsByTable,
tableKeys,
diagramJSON,
isSaving,
onAddRelatedTables,
} = this.props;

Expand All @@ -175,6 +189,7 @@ export default class DatabaseDiagramModal extends Component {
columnsByTable={columnsByTable}
tableKeys={tableKeys}
diagramJSON={diagramJSON}
isSaving={isSaving}
addRelatedTables={::this.onAddRelatedTables} />
);
}
Expand All @@ -184,10 +199,27 @@ export default class DatabaseDiagramModal extends Component {

return (
<div className="actions">
<div className="ui small positive button"
tabIndex="0"
onClick={() => onSaveDatabaseDiagram(this.refs.databaseDiagram.graph.toJSON())}>
Save
<div className="ui buttons">
<div className="ui small positive button"
tabIndex="0"
onClick={() => onSaveDatabaseDiagram(this.refs.databaseDiagram.graph.toJSON())}>
Save
</div>
<div className="or"></div>
<div className="ui small right labeled icon button simple upward dropdown">
Export to
<i className="caret up icon"></i>
<div className="menu">
<div className="item"
onClick={() => this.onExportDatabaseDiagram('png')}>
PNG
</div>
<div className="item"
onClick={() => this.onExportDatabaseDiagram('jpeg')}>
JPEG
</div>
</div>
</div>
</div>
</div>
);
Expand Down
4 changes: 4 additions & 0 deletions src/renderer/components/database-diagram.css
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,7 @@
.marker-arrowheads {
display: none
}

.ui.simple.upward.dropdown > .menu {
top: auto !important;
}
10 changes: 9 additions & 1 deletion src/renderer/components/database-diagram.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export default class DatabaseDiagram extends Component {
columnsByTable: PropTypes.object,
tableKeys: PropTypes.object,
diagramJSON: PropTypes.string,
isSaving: PropTypes.bool,
addRelatedTables: PropTypes.func.isRequired,
}

Expand Down Expand Up @@ -168,6 +169,13 @@ export default class DatabaseDiagram extends Component {
});
}

shouldDisableDiagram() {
const { isSaving } = this.props;
return isSaving
? { pointerEvents: 'none' }
: { pointerEvents: 'auto' };
}

onTableRightClick(table) {
const { tableKeys, addRelatedTables } = this.props;
const relatedTables = tableKeys[table].map(k => k.referencedTable).filter(rt => rt !== null);
Expand All @@ -179,6 +187,6 @@ export default class DatabaseDiagram extends Component {
return <div className="ui negative message" style={{textAlign: 'center'}}>{this.state.error}</div>;
}

return <div ref="diagram"></div>;
return <div ref="diagram" style={this.shouldDisableDiagram()}></div>;
}
}
6 changes: 6 additions & 0 deletions src/renderer/containers/query-browser.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,10 @@ class QueryBrowserContainer extends Component {
this.props.dispatch(DbAction.saveDatabaseDiagram(diagram));
}

onExportDatabaseDiagram(diagram, imageType) {
this.props.dispatch(DbAction.exportDatabaseDiagram(diagram, imageType));
}

onOpenDatabaseDiagram() {
this.props.dispatch(DbAction.openDatabaseDiagram());
}
Expand Down Expand Up @@ -313,9 +317,11 @@ class QueryBrowserContainer extends Component {
columnsByTable={columns.columnsByTable[selectedDB]}
tableKeys={keys.keysByTable[selectedDB]}
diagramJSON={databases.diagramJSON}
isSaving={databases.isSaving}
onGenerateDatabaseDiagram={::this.onGenerateDatabaseDiagram}
addRelatedTables={::this.onAddRelatedTables}
onSaveDatabaseDiagram={::this.onSaveDatabaseDiagram}
onExportDatabaseDiagram={::this.onExportDatabaseDiagram}
onOpenDatabaseDiagram={::this.onOpenDatabaseDiagram}
onClose={::this.onCloseDiagramModal} />
);
Expand Down
14 changes: 13 additions & 1 deletion src/renderer/reducers/databases.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const INITIAL_STATE = {
diagramDatabase: null,
fileName: null,
diagramJSON: null,
isSaving: false,
};


Expand Down Expand Up @@ -65,10 +66,19 @@ export default function (state = INITIAL_STATE, action) {
fileName: null,
};
}
case types.SAVE_DIAGRAM_SUCCESS: {
case types.SAVE_DIAGRAM_REQUEST:
case types.EXPORT_DIAGRAM_REQUEST: {
return {
...state,
isSaving: true,
};
}
case types.SAVE_DIAGRAM_SUCCESS:
case types.EXPORT_DIAGRAM_SUCCESS: {
return {
...state,
fileName: action.fileName,
isSaving: false,
};
}
case types.OPEN_DIAGRAM_SUCCESS: {
Expand All @@ -79,10 +89,12 @@ export default function (state = INITIAL_STATE, action) {
};
}
case types.SAVE_DIAGRAM_FAILURE:
case types.EXPORT_DIAGRAM_FAILURE:
case types.OPEN_DIAGRAM_FAILURE: {
return {
...state,
error: action.error,
isSaving: false,
};
}
case queryTypes.EXECUTE_QUERY_SUCCESS: {
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/reducers/tables.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export default function (state = INITIAL_STATE, action) {
return {
...state,
selectedTablesForDiagram: null,
}
};
}
default : return state;
}
Expand Down
4 changes: 2 additions & 2 deletions src/renderer/utils/file-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ export function showSaveDialog(filters) {
}


export function saveFile(fileName, data) {
export function saveFile(fileName, data, encoding = 'utf8') {
return new Promise((resolve, reject) => {
fs.writeFile(fileName, data, 'utf8', (err) => {
fs.writeFile(fileName, data, encoding, (err) => {
if (err) { return reject(err); }
resolve();
});
Expand Down

0 comments on commit 30dd5cf

Please sign in to comment.