Moving link generation into FormActions

This commit is contained in:
Jeff Avallone 2019-01-13 10:53:07 -05:00
parent f41518bd92
commit 42a1788c52
4 changed files with 111 additions and 72 deletions

View File

@ -10,54 +10,6 @@ import Message from 'components/Message';
const toUrl = params => new URLSearchParams(params).toString(); const toUrl = params => new URLSearchParams(params).toString();
const createSvgLink = async ({ svg }) => {
try {
const type = 'image/svg+xml';
const blob = new Blob([svg], { type });
return {
url: URL.createObjectURL(blob),
label: 'Download SVG',
filename: 'image.svg',
type
};
}
catch (e) {
console.error(e); // eslint-disable-line no-console
}
};
const createPngLink = async ({ svg, width, height }) => {
try {
const type = 'image/png';
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
const loader = new Image();
loader.width = canvas.width = Number(width) * 2;
loader.height = canvas.height = Number(height) * 2;
await new Promise(resolve => {
loader.onload = resolve;
loader.src = 'data:image/svg+xml,' + encodeURIComponent(svg);
});
context.drawImage(loader, 0, 0, loader.width, loader.height);
const blob = await new Promise(resolve => canvas.toBlob(resolve, type));
return {
url: URL.createObjectURL(blob),
label: 'Download PNG',
filename: 'image.png',
type
};
}
catch (e) {
console.error(e); // eslint-disable-line no-console
}
};
class App extends React.PureComponent { class App extends React.PureComponent {
state = { state = {
loading: false, loading: false,
@ -134,15 +86,7 @@ class App extends React.PureComponent {
this.handleRender(); this.handleRender();
} }
handleSvgMarkup = async ({ svg, width, height }) => { handleSvg = imageDetails => this.setState({ imageDetails });
if (svg !== this.state.svg) {
this.setState({
svg,
svgLink: await createSvgLink({ svg }),
pngLink: await createPngLink({ svg, width, height })
});
}
}
render() { render() {
const { const {
@ -154,8 +98,7 @@ class App extends React.PureComponent {
loading, loading,
loadingError, loadingError,
Render, Render,
svgLink, imageDetails
pngLink
} = this.state; } = this.state;
const formProps = { const formProps = {
@ -163,20 +106,19 @@ class App extends React.PureComponent {
syntax, syntax,
expr expr
}; };
const actions = { const actionProps = {
permalinkUrl, imageDetails,
svgLink, permalinkUrl
pngLink
}; };
const renderProps = { const renderProps = {
onRender: this.handleSvgMarkup, onRender: this.handleSvg,
syntax, syntax,
expr expr
}; };
return <> return <>
<Form { ...formProps }> <Form { ...formProps }>
<FormActions { ...actions } /> { Render && <FormActions { ...actionProps } /> }
</Form> </Form>
{ loading && <Loader /> } { loading && <Loader /> }

View File

@ -74,7 +74,7 @@ Form.propTypes = {
children: PropTypes.oneOfType([ children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node), PropTypes.arrayOf(PropTypes.node),
PropTypes.node PropTypes.node
]).isRequired ])
}; };
export default Form; export default Form;

View File

@ -6,7 +6,99 @@ import LinkIcon from 'react-feather/dist/icons/link';
import style from './style.module.css'; import style from './style.module.css';
const createSvgLink = async ({ svg }) => {
try {
const type = 'image/svg+xml';
const blob = new Blob([svg], { type });
return {
url: URL.createObjectURL(blob),
label: 'Download SVG',
filename: 'image.svg',
type
};
}
catch (e) {
console.error(e); // eslint-disable-line no-console
}
};
const createPngLink = async ({ svg, width, height }) => {
try {
const type = 'image/png';
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
const loader = new Image();
loader.width = canvas.width = width * 2;
loader.height = canvas.height = height * 2;
await new Promise(resolve => {
loader.onload = resolve;
loader.src = 'data:image/svg+xml,' + encodeURIComponent(svg);
});
context.drawImage(loader, 0, 0, loader.width, loader.height);
const blob = await new Promise(resolve => canvas.toBlob(resolve, type));
return {
url: URL.createObjectURL(blob),
label: 'Download PNG',
filename: 'image.png',
type
};
}
catch (e) {
console.error(e); // eslint-disable-line no-console
}
};
class FormActions extends React.PureComponent { class FormActions extends React.PureComponent {
state = {}
componentDidMount() {
const { imageDetails } = this.props;
if (!imageDetails) {
return;
}
if (imageDetails.svg) {
this.generateDownloadLinks();
}
}
componentDidUpdate(prevProps) {
const { imageDetails } = this.props;
const { imageDetails: prevImageDetails } = prevProps;
if (!imageDetails) {
return;
}
if (!prevImageDetails) {
this.generateDownloadLinks();
return;
}
if (imageDetails.svg !== prevImageDetails.svg
|| imageDetails.width !== prevImageDetails.width
|| imageDetails.height !== prevImageDetails.height) {
this.generateDownloadLinks();
return;
}
}
async generateDownloadLinks() {
const { imageDetails: { svg, width, height } } = this.props;
this.setState({
svgLink: await createSvgLink({ svg }),
pngLink: await createPngLink({ svg, width, height })
});
}
downloadLink({ url, filename, type, label }) { downloadLink({ url, filename, type, label }) {
return <li> return <li>
<a href={ url } download={ filename } type={ type }> <a href={ url } download={ filename } type={ type }>
@ -17,10 +109,12 @@ class FormActions extends React.PureComponent {
render() { render() {
const { const {
permalinkUrl, permalinkUrl
} = this.props;
const {
svgLink, svgLink,
pngLink pngLink
} = this.props; } = this.state;
return <ul className={ style.actions }> return <ul className={ style.actions }>
{ pngLink && this.downloadLink(pngLink) } { pngLink && this.downloadLink(pngLink) }
@ -34,8 +128,11 @@ class FormActions extends React.PureComponent {
FormActions.propTypes = { FormActions.propTypes = {
permalinkUrl: PropTypes.string, permalinkUrl: PropTypes.string,
svgLink: PropTypes.object, imageDetails: PropTypes.shape({
pngLink: PropTypes.object svg: PropTypes.string,
width: PropTypes.number,
height: PropTypes.number
})
}; };
export default FormActions; export default FormActions;

View File

@ -16,8 +16,8 @@ class Render extends React.PureComponent {
const svg = this.svgContainer.current.querySelector('svg'); const svg = this.svgContainer.current.querySelector('svg');
this.props.onRender({ this.props.onRender({
svg: svg.outerHTML, svg: svg.outerHTML,
width: svg.getAttribute('width'), width: Number(svg.getAttribute('width')),
height: svg.getAttribute('height') height: Number(svg.getAttribute('height'))
}); });
} }