Mysterious transparent rectangle blocking renderring

Reposting this from SO:

I have a React-Three-Fiber map project i’m working on, but running into a weird bug that I can’t isolate.

On desktops the little map works perfectly, but once on Android, a transparent roughly 50(?)px size box in the middle of the viewport shows up and blocks and additional renderring in it until I pan the map past it.

Here’s a video of what its doing:

Heres the code i’m using:

function App({moduleData}) {
    const [floor, setFloor] = useState(1);
    const [currentFloor, setCurrentFloor] = useState(floor);
    const [riverwalkMap, setRiverwalkMap] = useState(moduleData.floor1.map_image.src);
    const [currentPinSet, setCurrentPinSet] = useState('floor1');
    const [pinInfo, setPinInfo] = useState()
    const [zoomLevel, setZoomLevel] = useState(15);
    const [pinHtml, setPinHtml] = useState("");
    const [showMap, setShowMap] = useState(true);
    const [pinHeader, setPinHeader] = useState("Unit: ");
    const [open, setOpen] = useState(false);

    const closeModal = () => setOpen(false);

    function setPinColor(pinColor){
        switch (pinColor){
            case "green":
                return 'pin_green.png'
            case "red":
                return 'pin_red.png'
            case "yellow":
                return 'pin_yellow.png'
            default:
                return 'pin_green.png'
        }
    }
    function Scene({mapImage}){
        const riverwalkMap = useLoader(TextureLoader, mapImage);

        return(
            <>
                <mesh>
                    <planeGeometry args={[70,50]}/>
                    <meshBasicMaterial map={riverwalkMap} toneMapped={false}/>
                </mesh>
            </>
        )
    }

    function Pin({props,pinInfo}){
        const [active, setActive] = useState(0);
        const [showPopup, setShowPopup] = useState(false);
        const [hovered, setHovered] = useState(false);

        useEffect(()=>{
            document.body.style.cursor = hovered ? 'pointer' : 'auto'
        },[hovered])

        const { spring } = useSpring({
            spring: active,
            onChange: () => {
                invalidate()
            },
            config: {mass:5, tension: 400, friction: 50, precision: 0.0001}
        })

        function returnPinClass(pin){
            console.log('pin is: ' + pin);
            switch (pin){
                case 'available':
                    return '<span class="greenText">Available</span>';
                default:
                    return '<span class="redText">Sold</span>';
            }
        }

        function returnPinImage(pin){
            console.log('pin image is: ' + pin);
            return `<img src=${pin.src} alt=${pin.alt}/>`;
        }

        function setHtml(){
            setPinHeader(`<h2>Unit: ${pinInfo.popup_title}</h2>`);
            setPinHtml(`

                        <div class="popupContentBlock">
                            <div class="contentBlocks"> 
                                <div class="contentBlockLeft">
                                    <div class="pdfViewer">
                                        <iframe src="${pinInfo.pdf_file}"></iframe>
                                    </div>
                                    <div class="fractionalDiv">
                                        <a href="${pinInfo.pdf_file}" target="_blank" aria-label="Download PDF">Download PDF</a>
                                    </div>
                                </div>
                            </div>
                         
                                
                    </div>
`);
        }
        const scale = spring.to([0,1], [.6,1.25]);

        const pinTexture = useLoader(TextureLoader, setPinColor(pinInfo.pin_color));


        return(
            <>
                <a.mesh {...props}
                        scale-x={scale}
                        scale-y={scale}
                        scale-z={scale}
                        onPointerOver={(e)=> {
                            setActive(Number(!active));
                        }}
                        onPointerOut={(e)=>{
                            setActive(Number(!active));
                        }}
                        onClick={e => {
                            setHtml();
                            setOpen(o => !o);
                            // setShowMap(false);
                        }}
                        onPointerMissed={() => {setShowPopup(false)}}
                        position={[pinInfo.pin_position.x_pos,pinInfo.pin_position.y_pos,0]}
                        >
                    <planeGeometry args={[5,5]}/>
                    <meshBasicMaterial map={pinTexture} toneMapped={false} transparent={true}/>

                </a.mesh>
            </>
        )
    }

    function setFloorButton(floor) {
        setFloor(floor)
        floorHeading(floor)
        changePins(floor)
        setCurrentFloor(floor)
    }

    function floorHeading(sentFloor) {
        switch (sentFloor) {
            case 1:
                changeMap(moduleData.floor1)
                return ReactHtmlParser(moduleData.floor1.heading);
            case 2:
                changeMap(moduleData.floor2)
                return ReactHtmlParser(moduleData.floor2.heading);
            case 3:
                changeMap(moduleData.floor3)
                return ReactHtmlParser(moduleData.floor3.heading);
            case 4:
                changeMap(moduleData.floor4)
                return ReactHtmlParser(moduleData.floor4.heading);
            default:
                return 'No Floor Selected';
        }
    }

    function changeMap(floorData) {
        setRiverwalkMap(floorData.map_image.src);
    }

    function changePins(sentFloor){
        setCurrentPinSet('floor'+sentFloor);
    }

    function closePop(){
        setOpen(false);
    }

    function drawPins(currentSet){
        switch (currentSet){
            case 'floor1':
                return moduleData.floor1.pins;
            case 'floor2':
                return moduleData.floor2.pins;
            case 'floor3':
                return moduleData.floor3.pins;
            case 'floor4':
                return moduleData.floor4.pins;
        }
    }
    // THREE JS STUFF

    // Drop Pins Programmatically


    console.log(moduleData);
    return (
        <div className="cms-react-boilerplate__container">
            <div className={"mapInfo"}>
                <h1>Floor {currentFloor}</h1>
                <p>Floors:</p>
                <div className={"buttonSelector"}>
                    <button onClick={(e) => {
                        setFloorButton(1);
                        setPinHtml('');
                    }}>1</button>
                    <button onClick={(e) => {
                        setFloorButton(2);
                        setPinHtml('');
                    }}>2</button>
                    <button onClick={(e) => {
                        setFloorButton(3);
                        setPinHtml('');
                    }}>3</button>
                    <button onClick={(e) => {
                        setFloorButton(4);
                        setPinHtml('');
                    }}>4</button>
                </div>
            </div>
            <div className={"mapGrid"}>
                <div className={"mapDiv"} style={{ border: "2px solid black" }}>
                    <Canvas linear flat frameloop="demand" orthographic
                            camera={{position: [0, 0, 20], zoom: zoomLevel, up: [0, 0, 1], far: 10000}}
                    >
                        {showMap ? <Suspense fallback={null}>
                            {
                                drawPins(currentPinSet).map(e =>
                                    <Pin pinInfo={e}/>
                                )}

                                <Scene mapImage={riverwalkMap}/>
                        </Suspense> : null}
                        <MapControls enableRotate={false}/>
                    </Canvas>
                </div>
                <div className={'infoLeft'} >
                    {!showMap ?
                    <div className={"infoGridBlock"}>
                        {ReactHtmlParser(pinHeader)}
                        <div className="closeButton" onClick={() => {
                            setShowMap(true);
                            setPinHtml('');
                        }}>
                            <p>✖</p>
                        </div>
                    </div>
                    : null }
                    <Popup open={open} closeOnDocumentClick onClose={closeModal} lockScroll={true}>
                        <div className={"modalBlock"} role="dialog">
                            <div className={"popupContentDiv"}>
                                <div className={"popupHeaderLeft"}>{ReactHtmlParser(pinHeader)}</div>
                                <div className={"popupHeaderRight"}><a onClick={closePop} aria-label="Close Popup">&times;</a></div>
                            </div>
                            {ReactHtmlParser(pinHtml)}
                        </div>
                    </Popup>
                </div>
            </div>
        </div>
    );
}

export default App;

What i’ve tried: I tried messing with some CSS but the closest i’ve gotten is if I force the React-Three-Fiber Canvas tag to have a unset height and width on mobile everything will render but no clickable elements will work.

Thank you for any help!

I’ve deduced that this bug is caused by:

<mesh>
                    <planeGeometry args={[70,50]}/>
                    <meshBasicMaterial map={riverwalkMap} toneMapped={false}/>
                </mesh>

as if I remove this (or the “Scene” call later on), the pins don’t get removed within the blank spot.

So do I have to do something with layers to get this to work?

there’s nothing obvious, i don’t think it can be solved just with a snippet of a plane mesh. can you reproduce in chrome dev tools > mobile view? would you make a super, super minimal 20 line of code codesandbox that exibits the problem? that would help a lot. generally it’s probably better to post in pmndrs discord, i see this here by accident, but i don’t think you’ll find that many people here that deal with jsx.

Thank you for the help drcmda! I actually just solved it I believe!

So I changed the Z position value from 20 to 15 in this:

camera={{position: [0, 0, 15], zoom: zoomLevel, up: [0, 0, 1], far: 10000}}

and that seemed to solve it.

Thanks everyone