在使用 Canvas 路径的 Konva 中剪辑图像?

Posted

技术标签:

【中文标题】在使用 Canvas 路径的 Konva 中剪辑图像?【英文标题】:Clip an Image in Konva that uses Canvas path? 【发布时间】:2021-05-11 04:48:15 【问题描述】:

我看到了一个类似的问题here,但我有一个半径为array 而不是number,所以它不能使用+ 运算符。

半径有4个值:[top, right, bottom, left]

<Stage width=width height=height>
  <Layer>
    <Rect
      width=width / 2
      height=height / 2
      x=20
      y=20
      fill=""
      cornerRadius=10
      shadowEnabled=true
      shadowColor="#bada41"
      shadowBlur=50
      shadowOffset= x: 10, y: 10 
      shadowOpacity=1
      shadow=10
    />
    <Rect
      width=width / 2
      height=height / 2
      x=20
      y=20
      cornerRadius=cornerRadius
      fill="palevioletred"
    />
    <Group
      clipFunc=(ctx: any) => 
        ctx.beginPath()
        ctx.moveTo(x + cornerRadius[0], y)
        ctx.lineTo(x + width - cornerRadius[0], y)
        ctx.quadraticCurveTo(x + width, y, x + width, y + cornerRadius[0])
        ctx.lineTo(x + width, y + height - cornerRadius[1])
        ctx.quadraticCurveTo(
          x + width,
          y + height,
          x + width - cornerRadius[1],
          y + height
        )
        ctx.lineTo(x + cornerRadius[1], y + height)
        ctx.quadraticCurveTo(x, y + height, x, y + height - cornerRadius[2])
        ctx.lineTo(x, y + cornerRadius[2])
        ctx.quadraticCurveTo(x, y, x + cornerRadius[3], y)
        ctx.closePath()
      
    >
      <Image
        image=img
        width=width / 4
        height=height / 4
        x=40
        y=40
        fill="blue"
      />
    </Group>
  </Layer>
</Stage>

代码沙盒 ???? https://codesandbox.io/s/clip-rounded-image-in-react-konva-09d2l?file=/src/App.tsx

如何使内部图像与外部图像的形状相同?

【问题讨论】:

【参考方案1】:
export default function App() 
  const [img] = useImage(
    "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAMAAAC6V+0/AAAABlBMVEUAAADY2NjnFMi2AAAAAXRSTlMAQObYZgAAABVJREFUGNNjYIQDBgQY0oLDxBsIQQCltADJNa/7sQAAAABJRU5ErkJggg=="
  );

  const width = window.innerWidth;
  const height = window.innerHeight;
  const x = 20;
  const y = 20;
  const cornerRadius = [0, 0, 20, 20];

  const imageWidth = width / 4;
  const imageHeight = height / 4;

  return (
    <div className="App">
      <h1
        style=
          paddingLeft: 20
        
      >
        Clip in Konva
      </h1>
      <Stage width=width height=height>
        <Layer>
          <Rect
            width=width / 2
            height=height / 2
            x=20
            y=20
            fill=""
            cornerRadius=10
            shadowEnabled=true
            shadowColor="#bada41"
            shadowBlur=50
            shadowOffset= x: 10, y: 10 
            shadowOpacity=1
            shadow=10
          />
          <Rect
            width=width / 2
            height=height / 2
            x=20
            y=20
            cornerRadius=cornerRadius
            fill="palevioletred"
          />
          <Group
            x=40
            y=40
            clipFunc=(ctx: any) => 
              ctx.beginPath();
              let topLeft = 0;
              let topRight = 0;
              let bottomLeft = 0;
              let bottomRight = 0;
              if (typeof cornerRadius === "number") 
                topLeft = topRight = bottomLeft = bottomRight = Math.min(
                  cornerRadius,
                  width / 2,
                  height / 2
                );
               else 
                topLeft = Math.min(
                  cornerRadius[0] || 0,
                  imageWidth / 2,
                  imageHeight / 2
                );
                topRight = Math.min(
                  cornerRadius[1] || 0,
                  imageWidth / 2,
                  imageHeight / 2
                );
                bottomRight = Math.min(
                  cornerRadius[2] || 0,
                  imageWidth / 2,
                  imageHeight / 2
                );
                bottomLeft = Math.min(
                  cornerRadius[3] || 0,
                  imageWidth / 2,
                  imageHeight / 2
                );
              
              ctx.moveTo(topLeft, 0);
              ctx.lineTo(imageWidth - topRight, 0);
              ctx.arc(
                imageWidth - topRight,
                topRight,
                topRight,
                (Math.PI * 3) / 2,
                0,
                false
              );
              ctx.lineTo(imageWidth, imageHeight - bottomRight);
              ctx.arc(
                imageWidth - bottomRight,
                imageHeight - bottomRight,
                bottomRight,
                0,
                Math.PI / 2,
                false
              );
              ctx.lineTo(bottomLeft, imageHeight);
              ctx.arc(
                bottomLeft,
                imageHeight - bottomLeft,
                bottomLeft,
                Math.PI / 2,
                Math.PI,
                false
              );
              ctx.lineTo(0, topLeft);
              ctx.arc(
                topLeft,
                topLeft,
                topLeft,
                Math.PI,
                (Math.PI * 3) / 2,
                false
              );
              ctx.closePath();
            
          >
            <Image
              image=img
              width=imageWidth
              height=imageHeight
              fill="blue"
            />
          </Group>
        </Layer>
      </Stage>
    </div>
  );

演示:https://codesandbox.io/s/react-konva-image-clip-demo-x4i2d?file=/src/App.tsx:99-3886

问题:Image 上的 xy 属性应该被移除并放在 Group 组件上。

【讨论】:

该死的再次感谢。如果你能添加一点解释,我会很高兴。 Nvm让它工作了,但我还是不明白哈哈。 Lmk,如果你有任何链接可以解释这个或类似事物背后的数学:)

以上是关于在使用 Canvas 路径的 Konva 中剪辑图像?的主要内容,如果未能解决你的问题,请参考以下文章

canvas中Konva使用

为啥 javascript canvas2d 剪辑需要路径?

为啥我无法在我的 React 应用程序中访问 Konva Canvas 属性?

05 canvas——Konva简单使用

Canvas系列 | 剪辑区域函数clip

开源项目精选: 基于H5 Canvas的交互框架——Konva