Tips for placing an object within the boundaries of a canvas using three.js

At the moment, I am utilizing the threejs library to design 3D objects. However, I am facing an issue where the object is overflowing outside the canvas if it is too long. You can view my code snippet on JSFiddle.

Script

import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r127/build/three.module.js'

function create3DObject(selector, angle, depth, width, height) {
    
    let validAngles = [
        'standard-0',
        'standard-90',
        'turn-up-0',
        'turn-up-90',
        'turn-side-0',
        'turn-side-90'
    ]
  
    if(validAngles.indexOf(angle) < 0) {
        console.log("Incorrect angle")
        return false
    }

    const canvas = document.querySelector(selector)
    const renderer = new THREE.WebGLRenderer({ canvas, antialias: true })

    const canvasWidth = canvas.getBoundingClientRect().width
    const canvasHeight = canvas.getBoundingClientRect().height
    const minSize = Math.min(...[depth, width, height])
    const maxSize = Math.max(...[depth, width, height])
  
    const aspect = canvasWidth / canvasHeight
    const fov = 75
    const near = 0.1
    const far = 1000
  
    let cameraZoom = 1
    let cameraPosition = {
        left: canvasWidth / -2,
        right: canvasWidth / 2,
        top: canvasHeight / 2,
        bottom: canvasHeight / -2
    }

    const camera = new THREE.OrthographicCamera(
        cameraPosition.left,
        cameraPosition.right,
        cameraPosition.top,
        cameraPosition.bottom,
        near,
        far
    )

    camera.position.z = maxSize + minSize
    camera.zoom = cameraZoom

    camera.updateProjectionMatrix()

    const scene = new THREE.Scene()
    scene.background = new THREE.Color(0xe0e0e0)

    const geometry = new THREE.BoxGeometry(width, height, depth)

    const material = new THREE.MeshBasicMaterial({ color: 0xff4500 }) 

    const cube = new THREE.Mesh(geometry, material)

    var edge = new THREE.EdgesGeometry(cube.geometry)
    var edgeMaterial = new THREE.LineBasicMaterial({ color: 0xffffff, linewidth: 1 })
    var wireframe = new THREE.LineSegments(edge, edgeMaterial)

    scene.add(cube, wireframe)

    function animate() {
        requestAnimationFrame(animate)

        let rotationX = 0
        let rotationY = 0
        let rotationZ = 0

        if(angle == 'standard-0') {
            rotationX = 0.60
            rotationY = -0.80
            rotationZ = 0
        }
        
        if(angle == 'standard-90') {
            rotationX = 0.60
            rotationY = 0.80
            rotationZ = 0
        }
        
        if(angle == 'turn-up-0') {
            rotationX = -1.20
            rotationY = 0
            rotationZ = 0.80
        }
        
        if(angle == 'turn-up-90') {
            rotationX = -1.20
            rotationY = 0
            rotationZ = -0.80
        }

        if(angle == 'turn-side-0') {
            rotationX = 0.60
            rotationY = -0.60
            rotationZ = -1.60
        }
        
        if(angle == 'turn-side-90') {
            rotationX = 0.60
            rotationY = 0.60
            rotationZ = -1.60
        }

        cube.rotation.x = rotationX
        cube.rotation.y = rotationY
        cube.rotation.z = rotationZ
        
        wireframe.rotation.x = rotationX
        wireframe.rotation.y = rotationY
        wireframe.rotation.z = rotationZ

        renderer.render(scene, camera)
    }
  
    animate()
}

create3DObject('.standard-0', 'standard-0', 50, 45, 65)
create3DObject('.standard-90', 'standard-90', 50, 45, 65)
create3DObject('.turn-up-0', 'turn-up-0', 50, 45, 65)
create3DObject('.turn-up-90', 'turn-up-90', 50, 45, 65)
create3DObject('.turn-side-0', 'turn-side-0', 50, 45, 65)
create3DObject('.turn-side-90', 'turn-side-90', 50, 45, 65)

Desired Output

Answer №1

If you need to adjust the camera zoom based on object size, a simple formula can help. In this case, I'm using cameraZoom = 45 / maxSize. This formula adapts the camera zoom to the largest dimension of the objects. It establishes the zoom because adjusting the Z value directly doesn't seem to be effective. The choice of 45 is arbitrary and can be customized according to your requirements.

The first code snippet demonstrates how to generate 3D boxes with different orientations using Three.js. Each box is displayed in various angles such as 'standard-0', 'standard-90', 'turn-up-0', 'turn-up-90', 'turn-side-0', and 'turn-side-90'. The script calculates the camera position, sets up the scene, creates the box geometry, applies materials, handles rotations, and rendering for each box.

The second code snippet provides an alternative approach where all boxes have the same zoom level calculated based on the largest dimensions among all boxes. By iterating through an array of box data, the script dynamically generates 3D boxes with consistent zoom across different orientations by setting the camera accordingly. This method offers uniformity in zoom levels across multiple 3D boxes.

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

Navigate the div with arrow keys

Looking for an answer similar to this SO post on moving a div with arrow keys, could a simple and clear 'no' be sufficient: Is it possible to turn an overflowing div into a "default scroll target" that responds to arrow-up/down/page-down/space k ...

Error: The function pathRegexp is not defined

While attempting to conduct tests on my project with jest, I encountered an error code that seems unrelated to the actual testing process. It appears to be more of a dependency or Node Express compatibility issue. `● Test suite failed to run TypeError: ...

npm replace: troubleshooting npm script for replacing text across numerous files

I am currently attempting to swap out keywords in multiple files across various folders using regular expressions for the path: ./dist/src/**/**/**/*.scss Here is the npm script I am using: "build:src:replace:icon": "replace 'foo' 'bar&apos ...

Can an HTML DIV be resized along with its contents?

Is it possible to scale a container with animated elements inside to fit the browser window, or do you have to adjust each child element individually? ...

I am having issues with the external CSS and JS files not functioning properly in my project

I'm currently working on a project that has the following file structure: https://i.sstatic.net/ixd9M.png However, I am facing issues with loading my CSS and JS files... <link rel="stylesheet" href="./css/main.css"> <sc ...

Manipulate text within a text area using jQuery

Good afternoon. How can I use JavaScript to update the text in a textarea input? I currently have some content in my textarea that includes a PublisherImprintName tag, and I want to remove it using jQuery. <PublisherInfo> <PublisherName>A ...

Regex pattern is malfunctioning

I am having trouble understanding why this regex keeps returning false. I have an onkeydown event that should trigger it when pressing the 'w' key, but it doesn't seem to be working. var keyGLOB = ''; function editProductSearch ( ...

preclude any dates prior to the chosen date

I need a solution for a scenario where I have 5 datepickers in sequence. When I select a date on the first picker, all previous dates should be disabled when selecting on the next picker. Additionally, once a date is selected on one picker, the following ...

What is causing the issue with the setFromMatrix() function not updating the position correctly?

Recently, I encountered a problem while working with 3D objects. I've been saving my scene on the server to prevent the objects from disappearing when refreshing the webpage. However, I'm facing an issue where the objects within the scene keep re ...

Preventing Double Click Events on jQuery Spinner

I have been working on an option picker, but now there is a new requirement to make the options configurable. While this shouldn't be too difficult, I am facing some issues with the option picker: Currently, when an item is double-clicked, it will ge ...

How can I incorporate the 'client' application into the 'loading.js' file?

I implemented a Lottie component in my loading.js file. Utilizing the App router (Next13). This is the code for the lottie component: import { Player } from '@lottiefiles/react-lottie-player'; import LoadingLottie from '@/assets/loading.j ...

Generate real-time dynamic line charts using data pulled directly from a MySQL database

I am in search of guidance on developing a real-time line chart that can dynamically update based on data fetched from MySQL. I need an example or reference on how to achieve this functionality without having to refresh the webpage every time new data is ...

javascript inquiry about if statements

function checkValidity() { startChecked = false; finishChecked = false; alert("startChecked: " + startChecked); alert("finishChecked: " + finishChecked); if (document.dd.start.checked.length == undefined || document.dd.finish.checked. ...

The function of the Angular ng-include form action for posting a URL appears to be malfunctioning

When a form post is included in a parent HTML using ng-include, it does not trigger the submission action. <div ng-include src="'form.html'"></div> The code in the form.html file is as follows: <form action="next/login" method = ...

Navigating through content with scrollable views while utilizing the popular Angular framework

Being relatively new to famous and somewhat familiar with angular. Question: Given that everything in famous is fixed positioning, how should I go about creating a scrollable section using famous angular? HTML: This code snippet creates a grid of square ...

Return to the previous page with different query parameters, not the same one

When it comes to reverting state location back by 1 step in Angular, we can utilize something along the lines of this.location.back();. This method works well unless the system redirects to the same URL but with different query parameters. In such cases, ...

The Google Maps geocoding service fails to provide accurate location information

I am currently attempting to utilize the Google Maps Geocoding API within my JavaScript code. Below is the snippet I have written: var geocoder = new google.maps.Geocoder(); function geocodeAddress() { var address = document.getElementById("address").v ...

Exploring the properties within a MongoDB document using mapping functionality

I am trying to retrieve data from a document using Node.js and encountering an issue where the map operator is returning data with similar names twice. I am wondering if I can use filter instead of map to address this problem. Here is the code I am using t ...

Manipulating the DOM using a Flask route in an HTML form

I have a form that allows users to input the names of "Player A" and "Player B". When the user clicks on the "Start Game" button, the game begins by redirecting to a Flask route (/players). I want the "player-text" section to be updated with the player nam ...

Displaying React components for a brief duration of time

I have an existing React component where I need to display another component for a specific duration. Upon mounting or data loading of the parent component, the child component should become visible after 1-2 seconds and then disappear after a few more sec ...