A method to implement an If Loop on a cube using Threejs in order to generate an interactive on-hover feature that enlarges the cube's size

Having just completed my first tutorial in threejs as a novice, I am now facing a challenge. I am trying to create a hover effect on a basic cube shape where it grows in size when the mouse pointer hovers over it and shrinks back to its original size when the pointer moves away. I believe using an If Statement would be the solution, but I am struggling to find documentation or examples on how to implement this in threejs. Below is the code I have so far:

// Scene and Camera settings
var scene = new THREE.Scene();

var camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
)
camera.position.z = 5;
// Renderer settings
var renderer = new THREE.WebGLRenderer({
  antialias: true
});
renderer.setClearColor("#e5e5e5");
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

//Prevent malforming of renderer when resizing browser
window.addEventListener('resize', () => {
  renderer.setSize(window.innerWidth, window.innerHeight);
  camera.aspect = window.innerWidth / window.innerHeight;

  camera.updateProjectionMatrix();
});

//Raycaster and mouse to detect intersections
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();

//Cube settings
var geometry = new THREE.BoxGeometry(1, 1, 1);
var material = new THREE.MeshLambertMaterial({
  color: 0xFFCC00
});
var mesh = new THREE.Mesh(geometry, material);
mesh.rotation.set(0, 1.75, 0);
scene.add(mesh);

//Light settings
var light = new THREE.PointLight(0xFFFFFF, 1, 500);
light.position.set(10, 0, 25);
scene.add(light);

//Render
var render = function() {
  requestAnimationFrame(render);
  renderer.render(scene, camera);
}

//onMouseOver event

function onMouseMove(event) {
  event.preventDefault();

  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

  raycaster.setFromCamera(mouse, camera);

  var intersects = raycaster.intersectObjects(scene.children, true);

  for (var i = 0; i < intersects.length; i++) {
    this.tl = new TimelineMax();
    this.tl.to(intersects[i].object.scale, 1, {
      x: 2,
      ease: Expo.easeOut
    });
  }

}

render();

window.addEventListener('mousemove', onMouseMove);
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.2/TweenMax.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/102/three.js"></script>

My attempts to use an If Statement on the 'intersects' index 0 to control the scale increase and decrease have been unsuccessful. I have also tried adapting code from online sources but have not achieved the desired results. Any assistance, including links to tutorials on If statement usage in threejs, would be greatly appreciated.

Answer №1

If you are dealing with a single hovered and scaled object, a straightforward boolean flag ishovering = true|false can be effective. However, when there are multiple objects involved, it is advisable to reference the specific object that was intersected on mouse hover and scaled, allowing for it to be scaled down again if the mouse intersects with another object.

I have made some modifications to your code snippet. It seems that a for loop may not be necessary. Typically, the intention is to highlight only the foremost object (intersects[0]) being hovered over by the mouse. Using a for loop would scale all objects that are behind the first one. If this is the required behavior, then you may need to keep references to all scaled objects in an array.

Below is the updated code snippet where only the foremost object is scaled:

if (!intersects[0] && hoverObj || hoverObj && intersects[0] && intersects[0].object !== hoverObj) {
        
  // reset scale of previous hovered object
  new TimelineMax().to(hoverObj.scale, 1, { x: 1, y: 1, z: 1, ease: Expo.easeOut });
  hoverObj = null;
        
}
      
if (intersects[0] && !hoverObj) {
      
  // scale the new hovered object
  hoverObj = intersects[0].object;
  new TimelineMax().to(hoverObj.scale, 1, { x: 1.2, y: 1.2, z: 1.2, ease: Expo.easeOut });
        
}

Complete revised code snippet:

// Configure the Scene and Camera
var scene = new THREE.Scene();

var camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
)
camera.position.z = 5;

// Renderer Setup
var renderer = new THREE.WebGLRenderer({
  antialias: true
});
renderer.setClearColor("#e5e5e5");
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// Prevent renderer distortion on window resize
window.addEventListener('resize', () => {
  renderer.setSize(window.innerWidth, window.innerHeight);
  camera.aspect = window.innerWidth / window.innerHeight;

  camera.updateProjectionMatrix();
});

// Raycaster and mouse for intersection detection
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();

//Cube Configurations
var geometry = new THREE.BoxGeometry(1, 1, 1);
var material = new THREE.MeshLambertMaterial({
  color: 0xFFCC00
});
var mesh1 = new THREE.Mesh(geometry, material);
mesh1.rotation.set(0, 1.75, 0);
scene.add(mesh1);
var mesh2 = new THREE.Mesh(geometry, material);
mesh2.position.set(-1.5, 0, 0);
scene.add(mesh2);

//Lighting Setup
var light = new THREE.PointLight(0xFFFFFF, 1, 500);
light.position.set(10, 0, 25);
scene.add(light);

//Rendering Function
var render = function() {
  requestAnimationFrame(render);
  renderer.render(scene, camera);
}

var hoverObj = null;

// Mouse movement event handler
function onMouseMove(event) {
  event.preventDefault();

  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

  raycaster.setFromCamera(mouse, camera);

  var intersects = raycaster.intersectObjects(scene.children, true);
  
  if (!intersects[0] && hoverObj || hoverObj && intersects[0] && intersects[0].object !== hoverObj) {
    
    // reset scale of previous hovered object
    new TimelineMax().to(hoverObj.scale, 1, { x: 1, y: 1, z: 1, ease: Expo.easeOut });
    hoverObj = null;
    
  }
  
  if (intersects[0] && !hoverObj) {
  
    // scale the new hovered object
    hoverObj = intersects[0].object;
    new TimelineMax().to(hoverObj.scale, 1, { x: 1.2, y: 1.2, z: 1.2, ease: Expo.easeOut });
    
  }

}

render();

window.addEventListener('mousemove', onMouseMove);
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.2/TweenMax.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/102/three.js"></script>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

AngularJS: Monitoring $locationChangeStart for token verification

I am attempting to check if the next has a token or not, but it is not working and I am getting an error: TypeError: Cannot read property 'next' of undefined Any suggestions? app.js .run(function ($rootScope, $location,$log,User) { ...

Using Radio Buttons in a jqGrid Interface

Currently, I am attempting to integrate radio buttons within a jqGrid framework. I am aware that a custom formatter can be utilized for this purpose. Below is my code snippet, however, it fails to provide information on which radio button is selected or if ...

Ways to change the chart type in ApexCharts

I'm seeking a way to change the chart type of an existing ApexCharts that has already been rendered. After reviewing the methods, I attempted to use the updateOptions() method, but encountered the error: Uncaught TypeError: Cannot read property &apos ...

Toggle the on and off functionality of a button using ajax response for content display

I'm struggling to figure out why the button isn't working for me. I am familiar with how to enable and disable buttons using attr and prop. $(document).on("click", "#btn", function(){ $(this).html("Sending..."); $(this).prop("disabl ...

Tips for limiting the .click function to only the initial image in order to prevent loading all images within the container

I am facing a situation where multiple images are being returned into a specific div, which is working as intended. <div class="go" id="container"></div> Upon clicking on an image, it is loaded into a modal popup. However, instead of capturin ...

Is it possible to incorporate Vue and Vuetify into an existing project that requires IE compatibility?

Currently in the process of enhancing a legacy project with new functionality. The front end is currently relying solely on jQuery for all the webpages. I have been tasked with adding another webpage and would like to incorporate Vuetify + Vue due to the i ...

Receiving the result as well as encountering undefined initially during AJAX request

I have a dropdown menu, and when a user selects an option, an AJAX call is made to retrieve and display data based on the selected value. If the dropdown value is 2, it triggers the AJAX request. However, I am encountering two issues: https://i.sstatic.n ...

Having difficulty accessing the Material UI Icons

I encountered an issue when attempting to utilize Material UI icons - as soon as I added the icon component, an error occurred. https://i.stack.imgur.com/issmm.png For reference, you can find the code on CodeSandbox at the following link: https://codesand ...

What are some strategies for postponing the execution of a basic function for an

Whenever I develop microservices, I often come across situations where one function contains multiple other functions. For instance: functionA(); functionB(); functionC(); return json({status: processed}); All the functions within this block are synchro ...

Removing a specific row in a database table and sending a boolean indicator to an API, all while keeping the original object intact

I'm currently working on a spa project using AngularJS and integrating an api with mvvm in C#. One issue I am facing is that when I click the delete button, it deletes the line but I only want to change a boolean flag to true on the server side while ...

Jquery's remove function fails to function correctly when used on a cloned element

I am facing an issue where I have a list of rows that need to be deleted. However, when I attempted to use jQuery's remove function, it only removed the original row and not its clone. My goal is for the parent element of the parent to be removed when ...

WooCommerce Checkout and My Account Edit Address now feature dynamic selectable fields for improved customization options

After finding a solution on Stack Overflow to show sub Areas dropdown based on the selected city in WooCommerce checkout, I customized the code for my specific requirements: function cities_areas_settings() { $text_domain = 'woocommerce'; ...

ng-include does not incorporate a partial view

I am facing an issue with ng-include as this code is not functioning properly and I'm unable to identify the error. <select name="select" id="select" class='input-large' ng-model="selectedbien"> ...

Executing a POST request with AJAX in jQuery to communicate across different domains and fetching XML data as

Is it possible to send an AJAX request using the POST method and receive XML as a response text? If so, please provide me with the steps to achieve this. For example: url : "http://www.webservicex.net/CurrencyConvertor.asmx/ConversionRate" data ...

How to customize the arrow color of an expanded parent ExpansionPanel in material-ui

Currently facing a challenge in customizing material-ui themes to achieve the desired functionality. The goal is to have the expansion panels display a different arrow color when expanded for improved visibility. However, this customization should be appl ...

In JavaScript, can you combine values within an array of objects that share the same key value pair?

Here is the JSON data that needs to be merged based on the toolName: [ { "data": { "toolName": "Login", "data": [ { "scrapValue": " Find The ...

In search of advice on the best web-based database management technology

I'm looking to create a prototype for a web-based database manager, similar to the desktop version in the image below, with specific features in mind. Initially, the schema will be provided through a flat file. Considering HTML5 as an option, I am a ...

Troubleshooting a Vue.js formatting problem in Visual Studio 2019

Encountering an issue with VS2019 while attempting to format this code section. <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="milestone.ascx.cs" Inherits="uc.dms.milestone" %> <section class="content-header"> <h1> ...

The concept of nested views in Angular UI-Router allows for a

How can I successfully implement nested views, where after logging in the user is redirected to in.html, and all links within in.html are directed to a ui-view? Currently, all links redirect to a new page. index.html <!-- more HTML --> <body ng- ...

Adjusting the dimensions of a tri-fiber canvas prior to saving it

I have a unique inquiry regarding Three Fiber. Once the download button is clicked, it generates a base64 using toDataURL, which can then be downloaded. The resulting image adopts the height and width of the canvas, which in turn matches the height and w ...