Prevent HTML click through

I’m dynamically creating a fullscreen overlay for the user to enter a name.

The overlay does however not block mouse events on the canvas. I can still rotate my Orbit Camera.

If i enable the profiler i can’t click through that. I would like to achieve the same behaviour with my overlay.

Here is how i create the overlay:

LoginMask.prototype.addUI = function() {
    // Add css
    let style = document.createElement('style');
    document.head.appendChild(style);
    style.innerHTML = this.css.resource || '';
    
    // Add HTML
    let frag = document.createRange().createContextualFragment(this.html.resource || '');
    document.body.appendChild(frag);
    
    let self = this;
    document.getElementById('login').addEventListener('click', function() {
        let username = document.getElementById('username').value;
        
        let payload = { username: username };
        self.app.fire("login", payload);
        
        document.getElementById('login-mask').remove();
    },{once: true});
};

HTML:

<div id="login-mask" class="container-login">
    <div>
        <label for="username">USERNAME</label>
        <input id="username" type="text" name="username">
        <button id="login" type="button">Ready</button>
    </div>
</div>

CSS:

.container-login{
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    display: flex;
    justify-content: center;
    align-items: center;
    background-color: #000000E1;
    color: white;
    z-index: 1000;
}

label{
    display: block;
    margin-bottom: .5rem;
}

input{
    display: block;
    margin-bottom: 1rem;
    outline: 0;
    border: 0;
    background-color: #646464;
    color: white;
    padding: .5rem .5rem;
}

input:-webkit-autofill,
input:-webkit-autofill:hover, 
input:-webkit-autofill:focus, 
input:-webkit-autofill:active
{
    -webkit-box-shadow: 0 0 0px 1000px #646464 inset;
    -webkit-text-fill-color: white;
    transition: background-color 5000s ease-in-out 0s;
    caret-color: white;
}

button{
    border: 2px solid #C00222;
    border-radius: 10px;
}

#login{
    display: block;
    margin: 0 auto;
    padding: .4rem 1.333rem;
    background-color: transparent;
    color: white;
    font-size: 16px;
    cursor: pointer;
}

#login:hover{
    background-color: #C00222;
}
1 Like

Try adding pointer events none to the overlay: pointer-events | CSS-Tricks

pointer-events does the opposite of what i want.

I want my overlay to catch all pointer-events. (Prevent clicking through)

EDIT: I want it to behave like the profiler. I tried event.stopPropagation() which doesn’t work, because for some reason the playcanvas event gets executed before the event on the html element.

Ah yes, I forgot you need pointer events on the overlay to use for the login.

I’m surprised that the PlayCanvas mouse event gets executed before the overlay as it’s listening to the canvas events :thinking:

In the absolute worse case, you could detach the mouse from the canvas and attach afterwards: https://developer.playcanvas.com/en/api/pc.Mouse.html#attach

You can also create a global variable in your overlay script that is set to true when there is a click event on it.

Then use that global variable in your regular input scripts (e.g. camera) to bypass input if the overlay has received input.

That would work but is quite a ugly workaround.

Hmm that looks promising.

But I’m still sure that I’m doing something wrong here, because this behaviour does not happen with the profiler. Somehow the profiler blocks the mouse events.

Looking at the code, all the profiler does is use stopPropagation like you have done as well:

root.addEventListener('mousemove', function (evt) {
        evt.stopPropagation();

        var rect = root.getBoundingClientRect();
        mouse.x = evt.clientX - (rect.left + 300);
        mouse.y = evt.clientY - rect.top;
        mouse.hover = mouse.x > 0;
        if (mouse.y < 23) {
            timeHover = Math.floor((mouse.x / (width - 300)) * timeNow);
        } else {
            timeHover = Math.floor(mouse.x / scale + scroll.time);
        }
    }, false);

    root.addEventListener('mousedown', function (evt) {
        evt.stopPropagation();
        evt.preventDefault();

        if (evt.button !== 0 || mouse.click || mouse.down || ! mouse.hover)
            return;

        mouse.click = true;
    }, false);

    root.addEventListener('mouseup', function (evt) {
        evt.stopPropagation();

        if (evt.button !== 0 || ! mouse.down)
            return;

        mouse.down = false;
        mouse.up = true;
    }, false);

    root.addEventListener('mouseleave', function (evt) {
        mouse.hover = false;
        timeHover = 0;
        if (! mouse.down)
            return;

        mouse.down = false;
        mouse.up = true;
    }, false);

    root.addEventListener('mousewheel', function (evt) {
        evt.stopPropagation();

        if (! mouse.hover)
            return;

        scroll.time = Math.max(0, Math.min(timeNow - capacity, Math.floor(scroll.time + evt.deltaX / scale)));
        if (evt.deltaX < 0) {
            scroll.auto = false;
        } else if (Math.abs((scroll.time + capacity) - timeNow) < 16) {
            scroll.auto = true;
        }
    }, false);
2 Likes

Thanks for leading me in the right direction!
I only tested preventing the click event, which didn’t work.
But mousedown and mouseup work as expected!

1 Like

FYI, the Editor and launch page JS code is not minimised so you can inspect via devtools and poke around a bit if you need to :slight_smile:

1 Like