reactjsnext.jscanvaskonvajs

How to set React Canvas width and height to its parent div component (Konva Package)?


I placed a div in A4 format inside a fixed div with a height of 500px and dynamic width in a scrollable manner. The reason for the dynamic width of this div is that there is a sidebar on the screen, and this sidebar can expand and contract. So far, I don't have a problem. However, I am placing a Stage using the Konva library inside the A4 format div. This stage only accepts numeric values for width and height, so I can't provide values like "100%". I want this stage to adjust its width and height in the same way as its parent div. How can I achieve this? I tried referencing and managing it with state, but I couldn't get the exact result I wanted.

enter image description here

enter image description here

I want this stage to adjust its width and height in the same way as its parent div. How can I achieve this? I tried referencing and managing it with state, but I couldn't get the exact result I wanted.

const Home = () => {
  const [width, setWidth] = useState(0)
  const myComponentRef = useRef(null)
  const { sideBarStatus } = useContext(SidebarContext)
  const [rectangles, setRectangles] = useState(initialRectangles)
  const [selectedId, selectShape] = useState(null)
  useEffect(() => {
    // Function to update width
    const updateWidth = () => {
      if (myComponentRef.current) {
        setWidth(myComponentRef.current.clientWidth)
      }
    }
    updateWidth()
    window.addEventListener('resize', updateWidth)
    return () => {
      window.removeEventListener('resize', updateWidth)
    }
  }, [sideBarStatus])

  const checkDeselect = e => {
    const clickedOnEmpty = e.target === e.target.getStage()
    if (clickedOnEmpty) {
      selectShape(null)
    }
  }

  return (
    <div ref={myComponentRef} style={{ height: 500, display: 'flex', width: '100%', overflow: 'auto' }}>
      <div
        style={{
          border: '2px solid black',
          backgroundColor: 'white',
          position: 'relative',
          overflow: 'auto',
          width: '100%',
          height: width * Math.SQRT2
        }}
      >
        <Stage width={width} height={width * Math.SQRT2} onMouseDown={checkDeselect} onTouchStart={checkDeselect}>
          <Layer>
            {rectangles.map((rect, i) => {
              return (
                <Rectangle
                  key={i}
                  shapeProps={rect}
                  isSelected={rect.id === selectedId}
                  onSelect={() => {
                    selectShape(rect.id)
                  }}
                  onChange={newAttrs => {
                    const rects = rectangles.slice()
                    rects[i] = newAttrs
                    setRectangles(rects)
                  }}
                />
              )
            })}
          </Layer>
        </Stage>
      </div>
    </div>
  )
}
Home.acl = {
  action: 'read',
  subject: entitites.home
}
const initialRectangles = [
  {
    x: 10,
    y: 10,
    width: 100,
    height: 100,
    fill: 'red',
    id: 'rect1'
  },
  {
    x: 150,
    y: 150,
    width: 100,
    height: 100,
    fill: 'green',
    id: 'rect2'
  }
]
export default Home

Solution

  •   useEffect(() => {
        const updateDimensions = () => {
          if (myComponentRef.current) {
            setWidth(myComponentRef.current.clientWidth)
            setHeight(myComponentRef.current.clientHeight)
          }
        }
    
        const resizeObserver = new ResizeObserver(updateDimensions)
        if (myComponentRef.current) {
          resizeObserver.observe(myComponentRef.current)
        }
    
        updateDimensions()
    
        return () => {
          if (myComponentRef.current) {
            resizeObserver.unobserve(myComponentRef.current)
          }
        }
      }, [sideBarStatus])

    I updated my useEffect as well, adding resizeObserver solve my one step late rendering problem , I don't actually know how it works exactly but I hope It works for you too guys.