Search code examples
javascriptcanvashtml5-canvaskonvajsreact-konva

How to draw canvas back onto itself with React Konva Image?


I'm trying to implement this Stack Overflow questions' top answer in react-konva, but stuck on this line of code:

  ctx.drawImage(canvas,
    blurredRect.x, blurredRect.y, blurredRect.width, blurredRect.height,
    blurredRect.x, blurredRect.y, blurredRect.width, blurredRect.height
  );
  • How do we create Image component with 9 arguments?
  • Which canvas element do we add to the second Image component and how?
// draft code
import useImage from 'use-image';

const [image] = useImage(url, "anonymous");

<Stage width={width} height={height}>
  <Layer>
    <Image image={image} width={width} height={height}></Image>
    // second Image here with the blur?
    <Rect fill="rgba(255,255,255,0.2)" x={80} y={80} width={200} height={200} />
  </Layer>
</Stage>

Solution

  • You don't need to use <Rect> component from the initial question, as that you need to just create canvas element and use it for <Image> component.

    There are many ways to do that. This is example how you can use hooks to make such canvas:

    import React, { Component } from "react";
    import { render } from "react-dom";
    import { Stage, Layer, Image } from "react-konva";
    import useImage from "use-image";
    
    const useCanvas = () => {
      const [image] = useImage(
        "https://upload.wikimedia.org/wikipedia/commons/5/55/John_William_Waterhouse_A_Mermaid.jpg"
      );
      const [canvas, setCanvas] = React.useState(null);
    
      React.useEffect(() => {
        // do this only when image is loaded
        if (!image) {
          return;
        }
        var blurredRect = {
          x: 80,
          y: 80,
          height: 200,
          width: 200,
          spread: 10
        };
        const canvas = document.createElement("canvas");
        var ctx = canvas.getContext("2d");
    
        canvas.width = image.width / 2;
        canvas.height = image.height / 2;
        // first pass draw everything
        ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
        // next drawings will be blurred
        ctx.filter = "blur(" + blurredRect.spread + "px)";
        // draw the canvas over itself, cropping to our required rect
        ctx.drawImage(
          canvas,
          blurredRect.x,
          blurredRect.y,
          blurredRect.width,
          blurredRect.height,
          blurredRect.x,
          blurredRect.y,
          blurredRect.width,
          blurredRect.height
        );
        // draw the coloring (white-ish) layer, without blur
        ctx.filter = "none"; // remove filter
        ctx.fillStyle = "rgba(255,255,255,0.2)";
        ctx.fillRect(
          blurredRect.x,
          blurredRect.y,
          blurredRect.width,
          blurredRect.height
        );
    
        setCanvas(canvas);
      }, [image]);
    
      return canvas;
    };
    
    const App = () => {
      const canvas = useCanvas();
      return (
        <Stage width={window.innerWidth} height={window.innerHeight}>
          <Layer>
            <Image image={canvas} />
          </Layer>
        </Stage>
      );
    };
    
    render(<App />, document.getElementById("root"));
    

    https://codesandbox.io/s/react-konva-canvas-for-image-ypfmj