Added 'Download PDF' option using jsPDF.

This commit is contained in:
Przemek Wiech
2019-03-03 01:17:44 +01:00
parent 1083708e15
commit 730642fb4e
5 changed files with 46 additions and 15 deletions

View File

@@ -8,6 +8,7 @@
"detect-browser": "^4.1.0", "detect-browser": "^4.1.0",
"file-saver": "^2.0.1", "file-saver": "^2.0.1",
"history": "^4.7.2", "history": "^4.7.2",
"jspdf": "^1.5.3",
"md5": "^2.2.1", "md5": "^2.2.1",
"query-string": "^5.1.1", "query-string": "^5.1.1",
"react": "latest", "react": "latest",
@@ -23,6 +24,7 @@
"@types/file-saver": "^2.0.0", "@types/file-saver": "^2.0.0",
"@types/history": "^4.7.2", "@types/history": "^4.7.2",
"@types/jest": "*", "@types/jest": "*",
"@types/jspdf": "^1.2.2",
"@types/md5": "^2.1.33", "@types/md5": "^2.1.33",
"@types/node": "*", "@types/node": "*",
"@types/query-string": "^6.2.0", "@types/query-string": "^6.2.0",

View File

@@ -169,8 +169,9 @@ export class App extends React.Component<RouteComponentProps, {}> {
) )
} }
onPrint={() => this.chartRef && this.chartRef.print()} onPrint={() => this.chartRef && this.chartRef.print()}
onDownloadSvg={() => this.chartRef && this.chartRef.downloadSvg()} onDownloadPdf={() => this.chartRef && this.chartRef.downloadPdf()}
onDownloadPng={() => this.chartRef && this.chartRef.downloadPng()} onDownloadPng={() => this.chartRef && this.chartRef.downloadPng()}
onDownloadSvg={() => this.chartRef && this.chartRef.downloadSvg()}
/> />
)} )}
/> />

View File

@@ -1,6 +1,6 @@
import * as d3 from 'd3'; import * as d3 from 'd3';
import * as React from 'react'; import * as React from 'react';
import canvg from 'canvg'; import jsPDF from 'jspdf';
import {intlShape} from 'react-intl'; import {intlShape} from 'react-intl';
import {saveAs} from 'file-saver'; import {saveAs} from 'file-saver';
import { import {
@@ -167,7 +167,7 @@ export class Chart extends React.PureComponent<ChartProps, {}> {
saveAs(blob, 'topola.svg'); saveAs(blob, 'topola.svg');
} }
downloadPng() { drawOnCanvas(): Promise<HTMLCanvasElement> {
const canvas = document.createElement('canvas'); const canvas = document.createElement('canvas');
// Scale image for better quality. // Scale image for better quality.
@@ -176,18 +176,41 @@ export class Chart extends React.PureComponent<ChartProps, {}> {
canvas.height = svg.getBBox().height * 2; canvas.height = svg.getBBox().height * 2;
const blob = new Blob([this.getSvgContents()], {type: 'image/svg+xml'}); const blob = new Blob([this.getSvgContents()], {type: 'image/svg+xml'});
const img = new Image(); const img = new Image();
img.onload = () => {
const ctx = canvas.getContext('2d')!;
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
const onBlob = (blob: Blob | null) => {
if (blob) {
saveAs(blob, 'topola.png');
}
};
canvas.toBlob(onBlob, 'image/png');
};
img.src = URL.createObjectURL(blob); img.src = URL.createObjectURL(blob);
return new Promise<HTMLCanvasElement>((resolve) => {
img.onload = () => {
const ctx = canvas.getContext('2d')!;
const oldFill = ctx.fillStyle;
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = oldFill;
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
resolve(canvas);
};
});
}
downloadPng() {
const onBlob = (blob: Blob | null) => {
if (blob) {
saveAs(blob, 'topola.png');
}
};
this.drawOnCanvas().then((canvas) => canvas.toBlob(onBlob, 'image/png'));
}
downloadPdf() {
this.drawOnCanvas().then((canvas) => {
const doc = new jsPDF({
orientation: canvas.width > canvas.height ? 'l' : 'p',
unit: 'pt',
format: [canvas.width, canvas.height],
});
doc.addImage(canvas, 'PNG', 0, 0, canvas.width, canvas.height, 'NONE');
doc.save('topola.pdf');
});
} }
} }

View File

@@ -24,8 +24,9 @@ interface State {
interface Props { interface Props {
showingChart: boolean; showingChart: boolean;
onPrint: () => void; onPrint: () => void;
onDownloadSvg: () => void; onDownloadPdf: () => void;
onDownloadPng: () => void; onDownloadPng: () => void;
onDownloadSvg: () => void;
} }
export class TopBar extends React.Component< export class TopBar extends React.Component<
@@ -161,6 +162,9 @@ export class TopBar extends React.Component<
className="item" className="item"
> >
<Dropdown.Menu> <Dropdown.Menu>
<Dropdown.Item onClick={() => this.props.onDownloadPdf()}>
<FormattedMessage id="menu.pdf_file" defaultMessage="PDF file" />
</Dropdown.Item>
<Dropdown.Item onClick={() => this.props.onDownloadPng()}> <Dropdown.Item onClick={() => this.props.onDownloadPng()}>
<FormattedMessage id="menu.png_file" defaultMessage="PNG file" /> <FormattedMessage id="menu.png_file" defaultMessage="PNG file" />
</Dropdown.Item> </Dropdown.Item>

View File

@@ -3,6 +3,7 @@
"menu.load_from_file": "Otwórz plik", "menu.load_from_file": "Otwórz plik",
"menu.print": "Drukuj", "menu.print": "Drukuj",
"menu.download": "Pobierz", "menu.download": "Pobierz",
"menu.pdf_file": "Plik PDF",
"menu.png_file": "Plik PNG", "menu.png_file": "Plik PNG",
"menu.svg_file": "Plik SVG", "menu.svg_file": "Plik SVG",
"menu.github": "Źródła na GitHub", "menu.github": "Źródła na GitHub",