2

I want to render a Konva shape on top of a Google Maps layer. Since I'm using React, I use react-konva and react-google-maps/api libraries to work with.

Everytime I run yarn start, I get this error: Text components are not supported for now in ReactKonva. You text is: "Loading..."

Versions

  • react-konva: "16.13.0-6"
  • react-google-maps/api: "1.9.12"
  • konva: "7.0.6"
  • Chrome: "85.0.4183.83"

Project directory structure

It's a simple app built using create-react-app.

.
├── Makefile
├── README.md
├── Vagrantfile
├── bootstrap.sh
├── package.json
├── public
│   ├── classic-outline.png
│   ├── favicon.ico
│   ├── index.html
│   ├── logo192.png
│   ├── logo512.png
│   ├── manifest.json
│   └── robots.txt
├── src
│   ├── App.css
│   ├── App.js
│   ├── App.test.js
│   ├── components
│   │   ├── KonvaShape.js
│   │   └── Map.js
│   │  
│   ├── index.css
│   ├── index.js
│   ├── serviceWorker.js
│   └── setupTests.js
└── yarn.lock

Here are my components:

App.js

import React from 'react';

import './App.css';

import KonvaShape from './components/KonvaShape';

function App() {
    return (
        <div>
            <KonvaShape />
        </div>
    );
}

export default App;

KonvaShape.js

import React from 'react';
import { Stage, Layer } from 'react-konva';

import Map from './Map';

function KonvaShape() {

    return (
        <Stage width={window.innerWidth / 2} height={window.innerHeight / 2}>
            <Layer>
                <Map />
            </Layer>
        </Stage>
    );
}

export default KonvaShape;

Map.js

import React from 'react';
import { GoogleMap, LoadScript } from '@react-google-maps/api';

const containerStyle = {
  width: '400px',
  height: '400px'
};

const center = {
  lat: -3.745,
  lng: -38.523
};

function Map() {
  const [map, setMap] = React.useState(null);

  const onLoad = React.useCallback(function callback(map) {
    const bounds = new window.google.maps.LatLngBounds();
    map.fitBounds(bounds);
    setMap(map)
  }, [])

  const onUnmount = React.useCallback(function callback(map) {
    setMap(null)
  }, [])

  return (
    <LoadScript
      googleMapsApiKey={"ENTER YOUR GOOGLE MAPS API KEY HERE"}
    >
      <GoogleMap
        mapContainerStyle={containerStyle}
        center={center}
        zoom={10}
        onLoad={onLoad}
        onUnmount={onUnmount}
      >
        { /* Child components, such as markers, info windows, etc. */}
        <></>
      </GoogleMap>
    </LoadScript>
  )
}

export default React.memo(Map)

I am fairly new to React and Konva but my guess is that I should wait Google Maps component to mount before rendering my KonvaShape component. I tried to use KonvaShape own state to manage this trick (as this answer suggest ReactJS: How to render components only after successful asynchronous call?) but I didn't succeed much.

Gane D. Geoffrey
  • 165
  • 1
  • 4
  • 10

1 Answers1

3

You are trying inject non-konva element here:

<Stage width={window.innerWidth / 2} height={window.innerHeight / 2}>
  <Layer>
    <Map />
  </Layer>
</Stage>

It is not possible to do this directly. <Stage /> support only konva nodes. So you can use layers, groups, and shape there.

If you want to add google maps (that is probably is a DOM component) you have two ways:

  1. Place google maps on top of the stage with absolute position:
<Stage width={window.innerWidth / 2} height={window.innerHeight / 2}>
 {/* canvas internals */}
</Stage>
<div style={{ position: 'absolute', top: 0, left: 0 }}>
  <Map/>
</div>
  1. Or you can try to use the DOM portal to inject map into Konva stage. But that is just a react sugar, internally you will still have absolute position map on top of the stage.
lavrton
  • 18,973
  • 4
  • 30
  • 63
  • 1
    Thx it's pretty cool to have an answer from you! It worked like a charm ! I really thought the issue came from my lifecycle components management. Now I know I'll have to play with the absolute positions of the various elements. In fact I want to move a Konva shape on top of the Google Maps and interact with some of Maps own objetcs. Have seen this kind of thing done with your library ? – Gane D. Geoffrey Sep 11 '20 at 06:22
  • 1
    @GaneD.Geoffrey I didn't see such implementations. And I am not sure how to pass events from Konva stage (if it is on top) down to the map. It may be not trivial. – lavrton Sep 11 '20 at 13:59
  • Ok I'll try to do my best and see what I can do here. Working with shapes with Konva is really easy and natural. – Gane D. Geoffrey Sep 11 '20 at 20:40