diff --git a/src/components/App/index.js b/src/components/App/index.js index 336bf57..b4a7303 100644 --- a/src/components/App/index.js +++ b/src/components/App/index.js @@ -10,54 +10,6 @@ import Message from 'components/Message'; 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 { state = { loading: false, @@ -134,15 +86,7 @@ class App extends React.PureComponent { this.handleRender(); } - handleSvgMarkup = async ({ svg, width, height }) => { - if (svg !== this.state.svg) { - this.setState({ - svg, - svgLink: await createSvgLink({ svg }), - pngLink: await createPngLink({ svg, width, height }) - }); - } - } + handleSvg = imageDetails => this.setState({ imageDetails }); render() { const { @@ -154,8 +98,7 @@ class App extends React.PureComponent { loading, loadingError, Render, - svgLink, - pngLink + imageDetails } = this.state; const formProps = { @@ -163,20 +106,19 @@ class App extends React.PureComponent { syntax, expr }; - const actions = { - permalinkUrl, - svgLink, - pngLink + const actionProps = { + imageDetails, + permalinkUrl }; const renderProps = { - onRender: this.handleSvgMarkup, + onRender: this.handleSvg, syntax, expr }; return <>
- + { Render && } { loading && } diff --git a/src/components/Form/index.js b/src/components/Form/index.js index b366275..5a25b6f 100644 --- a/src/components/Form/index.js +++ b/src/components/Form/index.js @@ -74,7 +74,7 @@ Form.propTypes = { children: PropTypes.oneOfType([ PropTypes.arrayOf(PropTypes.node), PropTypes.node - ]).isRequired + ]) }; export default Form; diff --git a/src/components/FormActions/index.js b/src/components/FormActions/index.js index 2616188..3495328 100644 --- a/src/components/FormActions/index.js +++ b/src/components/FormActions/index.js @@ -6,7 +6,99 @@ import LinkIcon from 'react-feather/dist/icons/link'; 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 { + 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 }) { return
  • @@ -17,10 +109,12 @@ class FormActions extends React.PureComponent { render() { const { - permalinkUrl, + permalinkUrl + } = this.props; + const { svgLink, pngLink - } = this.props; + } = this.state; return
      { pngLink && this.downloadLink(pngLink) } @@ -34,8 +128,11 @@ class FormActions extends React.PureComponent { FormActions.propTypes = { permalinkUrl: PropTypes.string, - svgLink: PropTypes.object, - pngLink: PropTypes.object + imageDetails: PropTypes.shape({ + svg: PropTypes.string, + width: PropTypes.number, + height: PropTypes.number + }) }; export default FormActions; diff --git a/src/components/Render/index.js b/src/components/Render/index.js index 39e5184..d531580 100644 --- a/src/components/Render/index.js +++ b/src/components/Render/index.js @@ -16,8 +16,8 @@ class Render extends React.PureComponent { const svg = this.svgContainer.current.querySelector('svg'); this.props.onRender({ svg: svg.outerHTML, - width: svg.getAttribute('width'), - height: svg.getAttribute('height') + width: Number(svg.getAttribute('width')), + height: Number(svg.getAttribute('height')) }); }