Disable scene tumbling when HTML slider is clicked

New user to PlayCanvas here…

I have a range slider built in HTML and CSS in my scene that drives an entity’s position up and down. Simple enough. However, I also have made use of the orbit-camera.js and mouse-input.js that was provided by PlayCanvas. The problem I am having is that whenever I select and drag the range slider’s button my scene tumbles due to the mouseDown and mouseMove actions of the mouse-input.js. How can I select and drag the slider’s button without causing my scene to tumble around along with it? The simplest answer I can think of is to disable the mouse-input.js script on click, but I don’t know how to execute it. I would also like to re-enable the scene tumbling upon mouseUp from the slider button.

Thank you in advance for any help you can offer me.

HTML code:

<div class="slidecontainer" >
    <input type="range" id="rangeInput" class="slider" name="rangeInput" min="0" max="100" value="0" >                                                       
    <span id="demo"></span>
</div>

CSS code:

.slidecontainer {
    
    position: absolute;
    bottom: 60px;
    left: 25%;
    width: 50%; /* Width of the outside container */
}

/* The slider itself */
.slider {
    -webkit-appearance: none;  /* Override default CSS styles */
    appearance: none;
    width: 100%; /* Full-width */
    height: 15px; /* Specified height */
    border-radius: 15px;  
    background: #d3d3d3; /* Grey background */
    outline: none; /* Remove outline */
    opacity: 0.7; /* Set transparency (for mouse-over effects on hover) */
    -webkit-transition: .2s; /* 0.2 seconds transition on hover */
    transition: opacity .2s;
}

/* Mouse-over effects */
.slider:hover {
    opacity: 0.7; /* Fully shown on mouse-over */
}

/* The slider handle (use -webkit- (Chrome, Opera, Safari, Edge) and -moz- (Firefox) to override default look) */ 
.slider::-webkit-slider-thumb {
    -webkit-appearance: none; /* Override default look */
    appearance: none;
    width: 40px; /* Set a specific slider handle width */
    height: 40px; /* Slider handle height */
    border-radius: 20%; 
    background: #65C1FE; /* Blue background */
    cursor: pointer; /* Cursor on hover */
}

.slider::-moz-range-thumb {
    width: 40px; /* Set a specific slider handle width */
    height: 40px; /* Slider handle height */
    border-radius: 50%; 
    background: #65C1FE; /* Blue background */
    cursor: pointer; /* Cursor on hover */
}

/*On mouse down change the color of the slider button*/
.slider::-webkit-slider-thumb:active{
    background: #00008B; /* Dark blue background */
}

Does event.stopPropagation() help you at all (https://developer.mozilla.org/en-US/docs/Web/API/Event/stopPropagation)? Basically you’d add mousedown/touchstart listeners (whichever ones the mouseinput script is receiving) to the slider div, and in their callback stopPropagation to prevent the event going any further (i.e into PlayCanvas).

You’d probably want useCapture for this, to grab the event on it’s way ‘in’ to the DOM (https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener)

Thank you for the reply, inductible. Let me give that a try and get back to you.

So I’m missing something here. I’ve updated my html code to this:

<body onload="load();">   
<div class="slidecontainer" >
    <input type="range" id="rangeInput" class="slider" name="rangeInput" min="0" max="100" value="0" >                                             
    <span id="demo"></span>
</div>
</body>
    
<script>
  function stopEvent(ev) {
    
    ev.stopPropagation();
    alert("you moved the button");
  }
function load(){
  elem = document.getElementById("rangeInput");
  //elem.addEventListener("click", stopEvent, useCapture, false);
  elem.addEventListener("mousemove", stopEvent, useCapture, false);
  
}

</script>

When I play with the code in codepen I get the window alert as expected, yet in PlayCanvas it seems the mouse actions still reach the scene. Thoughts?

Have you tried replacing ‘useCapture’ in your example with Boolean ‘true’? I’ve not seen addeventlistener used in the way you have it written there - think the syntax may be wrong…

Typical would be eg addEventListener( “mousemove”, handler, true ); ie the third argument is useCapture

I did try it this way:

function load(){
  elem = document.getElementById("rangeInput");
  elem.addEventListener("mousemove", stopEvent, true);
}

But I get the same result. As the slider moves, the scene still tumbles.

I’m assuming the slider is ‘on top’ of the playcanvas Canvas element? I had a quick poke at the orbitcamera demo adding in your slider css and html above, and couldn’t reproduce the issue. Do you have a public link you could share, displaying the issue?

Thank you for your help, inductible.
Here’s a link to my current project:https://playcanvas.com/editor/scene/656299

Heya,

so the good news is that stopPropagation definitely works in your case - you just need to tweak where and how the handler is attached. I took a look at your HTML, and confirm it’s not working as you describe. If you open up Chrome dev tools ‘console’ (so you can edit code in realtime alongside the page), then enter:

var stopEvent = function(ev) {
ev.stopPropagation();
}

and then:

var elem = document.getElementById(‘rangeInput’);
elem.addEventListener(‘click’, stopEvent, true);
elem.addEventListener(‘mousemove’, stopEvent, true);

You can then drag the slider, which affects the model, but NOT the camera orbit, as desired. This tells me that the listener is not hooked up quite how it should be - I blame scope. In my code in this post - the scope is clear (var stopEvent = … and then immediately after an event hookup to the named function stopEvent) - I see that’s not quite the same from your html js script (the hookup occurs in ‘load’, and stopEvent is not declared as a var), maybe try adding var stopEvent = prior to the function, within ‘load’, or else making explicit: window.stopEvent = function(ev)…

Hope that makes sense!

Quick edit: is the load() function even ever getting called to perform the hookup!? I can’t see where in the code that happens, and again if I paste your code verbatim into the console (taking the listener hookup out of load()), it all starts to work.

So would the function load() look like this? I’m not quite sure how this part would be inserted into the HTML at this point.

function load(){
    var stopEvent = function(ev){
         ev.stopPropagation();
    }
    
    var elem = document.getElementById('rangeInput');
    elem.addEventListener('click', stopEvent, true);
    elem.addEventListener('mousemove', stopEvent, true);
}

Yep that sorts scope - but check that ‘load’ is even getting called (eg by body onload=“load”

You don’t really need ‘load’ because your script occurs after the slider has been declared- it’s there for getElementById to pick up immediately. Try just taking the content of ‘load’ out of the func and leaving it a bare script tag.

After updating the html to this

   
<div class="slidecontainer" >
    <input type="range" id="rangeInput" class="slider" name="rangeInput" min="0" max="100" value="0" >                                             
    <span id="demo"></span>
</div>

<script>
    var stopEvent = function(ev){
         ev.stopPropagation();
    }
    
    var elem = document.getElementById('rangeInput');
    elem.addEventListener('click', stopEvent, true);
    elem.addEventListener('mousemove', stopEvent, true);
</script>

The scene still tumbles around with the slider. I’ve cleared out my browser cache, so I’m stumped as to why it isn’t working. What else am I missing here?

Kaboom: https://stackoverflow.com/questions/1197575/can-scripts-be-inserted-with-innerhtml

You are appending a div, containing a script tag via ‘innerHTML’ - the script is never executed. Wow that was a tough one to track down!

You could ‘eval’ the code, but a thousand kittens would cry because that’s a terrible thing to do (security issues, etc - just bad practice). You need to find a way to add your script NOT via innerHTML. You can add the HTML DOM stuff that way, just employ the script in a more legitimate way.

It took me a while, but I think I got it! Thank you so much for your help, inductible. I had to create a simpler version of my scene to finally understand what to do. I may have stumbled upon the solution, but it’s fully working now! Hallelujah! I ended up taking the function out of the HTML, and placing it in the script that calls on the HTML and CSS portions to draw the slider on the screen. Thanks again for taking the time and effort to help out this newbie.

1 Like