LoginSignup
0
0

More than 1 year has passed since last update.

konva+reactでreact-iconsのsvg画像をcanvasに表示したかったメモ

Posted at

概要

表題のことをしたかったが、あまり情報がなかった。
一旦renderToStaticMarkupでdata-urlに変換することで表示できたので、メモ。

もっとスマートな方法があれば知りたいです。

環境

  • "react": "^18.2.0"
  • "react-icons": "^4.4.0"
  • "react-konva": "^18.2.1"
  • "konva": "^8.3.10"

ソース

import React from 'react'

export const useImage = (
  url: string,
  crossOrigin?: 'anonymous' | 'use-credentials',
) => {
  const statusRef = React.useRef<'loading' | 'loaded' | 'failed'>('loading')
  const imageRef = React.useRef<HTMLImageElement>()
  const [_, setStateToken] = React.useState(0)

  const oldUrl = React.useRef<string>()
  const oldCrossOrigin = React.useRef<string>()
  if (oldUrl.current !== url || oldCrossOrigin.current !== crossOrigin) {
    statusRef.current = 'loading'
    imageRef.current = undefined
    oldUrl.current = url
    oldCrossOrigin.current = crossOrigin
  }

  React.useLayoutEffect(
    function () {
      if (!url) return
      const img = document.createElement('img')

      function onload() {
        statusRef.current = 'loaded'
        imageRef.current = img
        setStateToken(Math.random())
      }

      function onerror() {
        statusRef.current = 'failed'
        imageRef.current = undefined
        setStateToken(Math.random())
      }

      img.addEventListener('load', onload)
      img.addEventListener('error', onerror)
      crossOrigin && (img.crossOrigin = crossOrigin)
      img.src = url

      return function cleanup() {
        img.removeEventListener('load', onload)
        img.removeEventListener('error', onerror)
      }
    },
    [url, crossOrigin],
  )
  return [imageRef.current, statusRef.current] as const
}
icons.tsx
export { FaTag } from 'react-icons/fa'
import { renderToStaticMarkup } from 'react-dom/server'
import * as icons from '@/components/atoms/icon/icons'
import { useImage } from './useImage'
type Icons = keyof typeof icons
export const useIconImage = (icon: Icons, size?: number) => {
  const svgString = encodeURIComponent(
    renderToStaticMarkup(icons[icon]({ size })),
  )
  const dataUri = `data:image/svg+xml,${svgString}`

  return useImage(dataUri)
}
const WithIconImage: React.FC = ({ children }) => {
  const [image] = useIconImage('FaTag', 50)
  return (
    <Stage width={canvasWidth} height={canvasHight}>
      <Layer>
            <Image x={leftGap} y={pictTop} image={image} size={50} />
      </Layer>
    </Stage>
  )
}

参考

konva.js svg
svg-to-dataurl

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0