Place a Three.js scene within a jQuery modal dialogue box

I am attempting to integrate a Three.js scene into a jQuery modal window. The objective is to utilize the Three.js scene in a larger window size. This scene should be displayed after clicking on an image that represents the scene in a smaller dimension.

You can view an example of what I have achieved so far: here

Currently, I have an image at the center and when hovered over and clicked, the intention is for the Three.js scene to appear in a modal window.

However, upon testing, when I click on the image, things don't turn out as expected (the scene window appears at the top-left corner, overlapping with the image ...)

To explain my approach, here's the JavaScript source code link:

When a user hovers over the image and clicks it (imageElement DOM), the following code snippet is executed (based on a standard jQuery modal window implementation):

imageElement.onclick = function RaiseWindow() {                                          
      
      var popID = 'canvas'; // Identify the pop-up                                           
      var popWidth = 700; // Set width                                                  
      
      // Display the pop-up and add a closing button
      $('#' + popID).fadeIn().css({ 'width': popWidth}).prepend('<a href="#" class="close"><img src="../close_pop.png" class="btn_close" title="Close Window" alt="Close" /></a>');                                                                                        
                                                                                         
      // Calculate margin to center the window - adjust by 80px                                  
      var popMargTop = ($('#' + popID).height() + 80) / 2;                               
      var popMargLeft = ($('#' + popID).width() + 80) / 2;                               
                                                                                         
      // Apply Margin Styles to the Popup                                                           
      $('#' + popID).css({                                                               
        'margin-top' : -popMargTop,                                                      
        'margin-left' : -popMargLeft                                                     
        });                                                                              
                                                                                         
      // Show background                                                              
      $('body').append('<div id="fade"></div>');                                         
      $('#fade').css({'filter' : 'contrast(0.3)'}).fadeIn();                             
                                                                                         
      return false;                                                                      
    };                     

The container (div) with id canvas is obtained using the following:

// Div container for canvas                                                              
container = document.getElementById('canvas');                                                                                                     
container.style.display = 'none';                                                                   
                                                                                         
// Initialize WebGLRenderer renderer                                                       
renderer = new THREE.WebGLRenderer({ antialias: true });                                                                                         
renderer.setSize(CANVAS_WIDTH, CANVAS_HEIGHT);                                           
renderer.sortObjects = true;                                                             
// AppendChild renderer to container                             
container.appendChild(renderer.domElement);                                              
                                                             

Initially, I set

container.style.display = 'none';
to prevent the scene from being drawn before clicking on the image.

In the HTML source, I have added the following:

<td class="body_content"><br>
    <!-- WebGL into td body_content -->
    <div id="canvas" class="center"></div>
    <!-- Javascript -->                                                                  
    <script src="js/sphere_dev.js"></script>                                                                                     
</td>

Currently, the modal window does not appear when clicked, and the reason escapes me. After resolving this issue, I may need to remove

container.style.display = 'none';
, but doing this initially causes both Three.js and the image to appear.

How can I first display the modal window followed by the Three.js scene inside it?

Update 1

Progress has been made. I have managed to grey out the entire window, but the popup remains invisible.

In the HTML code, I have included the following:

    <!-- WebGL into td body_content -->
    <div id="canvas" data-width="500" data-rel="popup_webgl" class="center"></div>
    <!-- HTML content of popup_webgl -->
    <div id="popup_webgl" class="popup_block">
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce euismod efficitur est, eget vehicula leo volutpat ac. Nullam finibus purus nec orci consectetur, et varius urna fermentum. </p>
    </div>
    <!-- Javascript -->
    <script src="js/sphere_dev.js"></script>

In the sphere_dev.js file, I have implemented the following logic:

imageElement.onclick = function RaiseWindow() {

    var popID = $(this).data('rel'); // Retrieve pop-up ID
    var popWidth = $(this).data('width'); // Get width

    // Make the popup visible and add a close button
    $('#' + popID).fadeIn().css({ 'width': popWidth}).prepend('<a href="#" class="close"><img src="./close_pop.png" class="btn_close" title="Close Window" alt="Close" /></a>');

    // Calculate margins for centering
    var popMargTop = ($('#' + popID).height() + 80) / 2;
    var popMargLeft = ($('#' + popID).width() + 80) / 2;

    // Apply Margins to the Popup
    $('#' + popID).css({
      'margin-top' : -popMargTop,
      'margin-left' : -popMargLeft
      });

    // Show background
    $('body').append('<div id="fade"></div>');
    $('#fade').css({'filter' : 'contrast(0.8)'}).fadeIn();

    return false;
};

//Close Popups and Fade Layer
$('body').on('click', 'a.close, #fade', function() {
    $('#fade , .popup_block').fadeOut(function() {
      $('#fade, a.close').remove();
      });

    return false;
    });

You can view the updated version at this link.

Despite greying out the full window upon clicking, the popup itself is not visible. Why is this happening?

Update 2

After following various suggestions, I have successfully displayed the Three.js scene, albeit with a centering issue.

You can see the latest results at this link

Upon clicking the image to display the popup, the layout appears off-center (observed in Firefox and Chrome):

https://i.stack.imgur.com/cIKqO.jpg

The problem lies in the misalignment of the popup (slightly shifted horizontally and vertically off-center, with the bottom portion missing).

In an attempt to correct this, I have utilized the following calculations (where mainWidth and mainHeight are global variables):

// Maintain proportions for popup (from image dimensions: width=900, height=490)
// Set popup width to 90% of available width and calculate height accordingly:
var mainWidth = 0.9*window.innerWidth,
    mainHeight = mainWidth*(490/900);


imageElement.onclick = function RaiseWindow() {

    var popWidth = mainWidth;
    var popHeight = mainHeight;
    var xPop = (window.innerWidth/2) - (popWidth/2);
    var yPop = (window.innerHeight/2) - (popHeight/2);    

    console.log('print popWidth = ', popWidth);
    console.log('print popHeight = ', popHeight);

    console.log('print x = ', xPop);
    console.log('print y = ', yPop);

    // Make the popup visible and add a closing button
    $('#' + popID).fadeIn().css({'position': 'fixed', 'width': popWidth+'px', 'height': popHeight+'px', 'top': xPop+'px', 'left': yPop+'px'}).prepend('<a href="#" class="close"><img src="./close_pop.png" class="btn_close" title="Close Window" alt="Close" /></a>');

    // Display the background
    $('body').append('<div id="fade"></div>');
    $('#fade').css({'filter' : 'contrast(0.8)'}).fadeIn();

    return false;
};

Please note that the window.offsetHeight function didn't work on Firefox and Chrome, requiring the use of window.innerHeight instead.

Below is the CSS styling applied to the popup:

.popup_block{
display: none; /* hidden by default */
background: #fff;
padding: 20px;
border: 20px solid #ddd;
font-size: 1.2em;
position: fixed;
z-index: 99999;
/*--CSS3 Shadow Definitions--*/
-webkit-box-shadow: 0px 0px 20px #000;
-moz-box-shadow: 0px 0px 20px #000;
box-shadow: 0px 0px 20px #000;
/*--CSS3 Rounded Corners--*/
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
}

You can access the complete CSS code at this link.

How can I resolve the centering issue with the popup?

Answer №1

To enhance the functionality of your existing code, consider moving your canvas element inside the popup div#fade block. Instead of completely removing it on a body click event, simply hide it by applying a fadeOut effect when either the a.close or body is clicked. Modify the image click event as follows:

$('#contrast').get(0).onclick = function RaiseWindow() {
//$('a.poplight').on('click', function() {

    var popID = $(this).data('rel'); // Obtain popup name
    var popWidth = $(this).data('width'); // Get width

    // Display and set up closing button for the popup
    $('#' + popID).fadeIn().css({ 'width': popWidth}).prepend('<a href="#" class="close"><img src="./close_pop.png" class="btn_close" title="Close Window" alt="Close" /></a>');

    // Calculate margins to center window - offset by 80 pixels
    var popMargTop = ($('#' + popID).height() + 80) / 2;
    var popMargLeft = ($('#' + popID).width() + 80) / 2;

    // Apply calculated margin to Popup
    $('#' + popID).css({ 
        'margin-top' : -popMargTop,
        'margin-left' : -popMargLeft
        });

    // Display background
    //$('body').append('<div id="fade"></div>');
    //$('#fade').css({'filter' : 'contrast(0.8)'}).fadeIn();
    //$('#fade').css({'filter' : 'alpha(opacity=0.99)'}).fadeIn();

    if($('#fade').length > 0) {
        $('#fade').fadeIn();
    } else {
        $('<div>', { id: 'fade' })
            .appendTo('body')
            .css({'filter' : 'contrast(0.8)'})
            .append($('#canvas').show())
            .fadeIn();
    }

    return false;
};

Adjust the a.close, body click event handler like this:

$('body').on('click', 'a.close, #fade', function() { // Click on body
    $('#fade , .popup_block').fadeOut(); // Fade out elements
});

Witness this implemented through my demonstration which can be seen here:

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

Sending parameters to a service's factory

Here is the HTML code I am working with: <div class='container-fluid' ng-controller="TypeaheadCtrl"> <p></p> <b>Selected User</b> Enter a name: <input type="text" ng-model="selected" typeahead="user ...

Choose the current parent item using Angular's ng-selected and $index

http://plnkr.co/edit/fwwAd4bn6z2vxVN2FUL7?p=preview On the Plunker page linked above, I am trying to achieve a specific functionality. I would like the 3 dropdown lists to display values A, B, and C initially. When a 4th dropdown option is added, it shoul ...

What is the best way to track the loading progress of an AJAX page in WordPress?

On my WordPress blog, I utilize a plugin known as Advanced Ajax Page Loader. This handy tool loads the next page or post through AJAX and then places it in a specific div on my site. However, I am now interested in incorporating a progress bar to show the ...

Setting line height as a pixel value does not yield the desired result

$(element).css(options.css).attr(options.attr).addClass(options.class) //ensure line-height is correctly assigned if($(element).is('p') && _.isString(options.css['line-height'])){ console.log('line-height assigned: &apos ...

displaying and concealing elements with jquery

Is there a way to hide a div if the screen size exceeds 700px, and only show it when the screen size is less than 700px? Below is the jQuery code I'm attempting to use: jQuery(document).ready(function() { if ((screen.width>701)) { $(" ...

When utilizing the dojox.grid.enhanceGrid function to delete a row, the deletion will be reflected on the server side but

I have a grid called unitsGrid that is functioning correctly. I am able to add and delete rows, but the issue arises when I try to delete rows - they do not disappear from my unitsGrid. I have spent hours trying to debug the code but I cannot seem to fin ...

Creating a dynamic select functionality in Drupal forms

Being more focused on backend development, I am facing a challenge that may be simple for jQuery experts. In Drupal, I have two arrays - one containing names of views and the other having displays for each view. To populate these arrays, here is the code s ...

Why isn't pagination typically positioned inside of a tbody element rather than before or after it?

I've created a user table that is based on the number parameter. I added a filter that listens to input and performs an AJAX call each time with the filter applied to the name field. However, the pagination is initially displayed ABOVE the entire ta ...

Tips for extracting a textfield input value and sending it using data-ajax-url="Url.Action() in a cshtml file

I have a challenge with my controller function that takes two dates as parameters. It works perfectly when I hardcode the dates, but I'm struggling to extract values from my text fields and pass them to the function. I prefer not to use a form in my c ...

Tips on how to conditionally render a button based on the presence of a link from a separate file in React

I've been working on my personal portfolio site using React and Tailwind. One challenge I'm facing is how to display the "GitHub" button for each project card only when a GitHub link is provided in my data.js file. Currently, I'm utilizing ...

How can I retrieve a specific key from a nested array while using ng-repeat to iterate through it

I have successfully created a code snippet that retrieves JSON data and displays it in HTML using AngularJS. <div class="activity" ng-app="stream" ng-controller="streamCtrl"> <ul ng-repeat="x in myData"> <p class="au ...

Background color vanishes (occasionally) on the contact section of my website when viewed in Chrome

My contact page has an issue that only occurs in Chrome, where the background disappears most of the time. This problem is not present in Firefox, Edge, or Safari on my TA's MacBook, but interestingly, hovering over a box resolves the issue on her dev ...

When using iOS, inserting an iFrame with a source URL (SRC) on a webpage will automatically open the URL

Currently facing a peculiar issue within a Cordova app, specifically on iOS. The scenario is: I have an HTML page with existing content. At a later stage, I fetch additional HTML from a remote source and inject it into the original HTML page. However, whe ...

Tips for storing a JavaScript variable or logging it to a file

Currently working with node, I have a script that requests data from an API and formats it into JSON required for dynamo. Each day generates around 23000 records which I am trying to save on my hard drive. Could someone advise me on how to save the conte ...

Achieving Automatic Scrolling of Drawer in Material UI React JS

Looking for assistance, can anyone lend a hand with this code snippet I've been working on? See it here: https://codesandbox.io/s/5xoj9zw56l I referenced this code as part of my project development: https://codesandbox.io/s/6jr75xj8y3 ...

Utilizing AngularJS filter method to populate data

Just beginning my journey with Angular js, I've got this snippet of code that is responsible for binding data to the div element, app.filter("myfilter", function () { return function (data, catName) { if (angular.isArray(data) && angular ...

Adjust the language of the submit and reset button text based on a variable

I'm facing a simple question but I'm stuck right now... and I was hoping someone could assist me. My issue is as follows: I need to switch the values of two buttons, reset and submit, from Greek to English and vice versa based on a variable retri ...

I'm perplexed as to why my JavaScript code isn't successfully adding data to my database

Recently, I delved into the world of NodeJS and Express. My goal was to utilize Node and Express along with MongoDB to establish a server and APIs for adding data to the database. Specifically, I aimed to write the code in ESmodules syntax for JavaScript. ...

Encountering a null pointer exception when using a post method, JSON, and AJAX

Implementing Server Side Logic @Path("/create") @POST @Consumes(MediaType.APPLICATION_JSON) @Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN}) public RequestStatus createData(String jsonData){ return ...

Error encountered while trying to load component: template or render function is not defined

I have set up a basic vue.js configuration using browserify and vueify. Following advice from previous tutorials, I included aliasify as a dependency to utilize the template engine. Below is my package.json file: { "name": "simple-vueify-setup", "ve ...