bubkoo / html-to-image

✂️ Generates an image from a DOM node using HTML5 canvas and SVG.
MIT License
5.79k stars 544 forks source link

Can you provide an example using React? #122

Closed chriswalz-bg closed 3 years ago

chriswalz-bg commented 3 years ago

I'm not sure how to get it working without using findDomNode in conjunction with RootRef

biiibooo[bot] commented 3 years ago

👋 @chriswalz-bg

Thanks for opening your first issue here! If you're reporting a 🐞 bug, please make sure you include steps to reproduce it. To help make it easier for us to investigate your issue, please follow the contributing guidelines.

We get a lot of issues on this repo, so please be patient and we will get back to you as soon as we can.

hdoro commented 3 years ago

Hey Chris 👋

Maybe this snippet can give you a north?

Here's what a useScreenshot hook could look like:

import download from 'downloadjs'
import { toPng } from 'html-to-image'
import React from 'react'

/**
 * Hook to generate screenshot
 */
function useScreenshot() {
  const captureRef = React.useRef()

  const [status, setStatus] = React.useState('idle')

  async function generateImage(e) {
    e.preventDefault()
    if (!captureRef?.current) {
      return
    }
    try {
      setStatus('loading')
      const imgBase64 = await toPng(captureRef.current, {
        quality: 1,
        pixelRatio: 1,
      })
      setStatus('success')
      download(imgBase64, 'generated.png')
    } catch (error) {
      setStatus('error')
      console.error(error)
    }
  }

  return {
    generateImage,
    captureRef,
    status,
  }
}

export default useScreenshot

And how a component could consume it:

import React from "react";
import useScreenshot from "./useScreenshot";

const MyComponent = () => {
  const { generateImage, captureRef, status } = useScreenshot();
  return (
    <>
      <div ref={captureRef}>
        <h1>I'll become an image!!</h1>
      </div>
      <button disabled={status === "loading"} onClick={generateImage}>
        Generate image
      </button>
    </>
  );
};

export default MyComponent;
Vordty commented 3 years ago

@hdoro

Hey, thanks for the example. I came across an issue while using your code. toPng does not seem to work for specific refs such as the button in the example, but works fine if I just pass "document.body" to it. By not work I mean - function returns base64 but image is empty, it took a screenshot of nothing.

Do you have any clue what could be the issue? Thanks for help.

Vordty commented 3 years ago

If anyone's wondering I fixed it.

Just wrap another container/div around the element you want to capture and attach ref to that outer container. I think this was intended in the example above, my bad.

ndisisnd commented 3 years ago

Absolutely amazing. That helped me a lot as well—any chance of creating an integration guide for different frameworks?

biiibooo[bot] commented 3 years ago

Hiya! This issue has gone quiet. Spooky quiet. 👻 We get a lot of issues, so we currently close issues after 60 days of inactivity. It’s been at least 20 days since the last update here. If we missed this issue or if you want to keep it open, please reply here. You can also add the label "not-stale" to keep this issue open! As a friendly reminder: the best way to see this issue, or any other, fixed is to open a Pull Request.

Thanks for being a part of the Antv community! 💪💯

mgw-sbex commented 3 years ago

Hi All, Hoping to get this great lib to work. I have a probably silly question... I'm importing into my container like this: import htmlToImage from 'html-to-image'; import { toPng, toJpeg, toBlob, toPixelData, toSvg } from 'html-to-image';

I'm invoking it like this: capture = (id) => { htmlToImage.toPng(document.getElementById(id)) .then(function (dataUrl) { var img = new Image(); img.src = dataURL; document.body.appendChild(img); saveImgAs(dataUrl, 'my-node.png'); }) .catch(function (error) { console.error('capture error', error); }); };

and the button to fire it is like this: <button id="snap" className="snapfs" onClick={this.capture.bind(this,'upper-container')} allow="fullscreen">

When I click the button I get: react-dom.production.min.js?ca5d:21 Uncaught TypeError: Cannot read property 'toPng' of undefined at ConferencePage.eval [as capture] (index.js?2994:1175)<-- where I called htmlToImage above at Object.ca (react-dom.production.min.js?ca5d:14) at ja (react-dom.production.min.js?ca5d:15) at ka (react-dom.production.min.js?ca5d:15) at wa (react-dom.production.min.js?ca5d:17) at Aa (react-dom.production.min.js?ca5d:18) at ya (react-dom.production.min.js?ca5d:18) at Da (react-dom.production.min.js?ca5d:21) at Ad (react-dom.production.min.js?ca5d:84) at Gi (react-dom.production.min.js?ca5d:250)

Any idea what I'm doing wrong when importing?

biiibooo[bot] commented 3 years ago

Hiya! This issue has gone quiet. Spooky quiet. 👻 We get a lot of issues, so we currently close issues after 60 days of inactivity. It’s been at least 20 days since the last update here. If we missed this issue or if you want to keep it open, please reply here. You can also add the label "not-stale" to keep this issue open! As a friendly reminder: the best way to see this issue, or any other, fixed is to open a Pull Request.

Thanks for being a part of the Antv community! 💪💯

biiibooo[bot] commented 3 years ago

Hey again! It’s been 60 days since anything happened on this issue, so our friendly neighborhood robot (that’s me!) is going to close it. Please keep in mind that I’m only a robot, so if I’ve closed this issue in error, I’m HUMAN_EMOTION_SORRY. Please feel free to comment on this issue or create a new one if you need anything else. As a friendly reminder: the best way to see this issue, or any other, fixed is to open a Pull Request. Thanks again for being part of the Antv community! 💪💯

biiibooo[bot] commented 2 years ago

This thread has been automatically locked because it has not had recent activity. Please open a new issue for related bugs and link to relevant comments in this thread.