Book Image

Three.js Cookbook

By : Jos Dirksen
Book Image

Three.js Cookbook

By: Jos Dirksen

Overview of this book

Table of Contents (15 chapters)
Three.js Cookbook
Credits
About the Author
Acknowledgments
About the Reviewers
www.PacktPub.com
Preface
Index

Dragging a file from the desktop to the scene


When you create visualizations, it is a nice feature to let your users provide their own resources. For instance, you might want to let the user specify their own textures or models. You can implement this with a traditional upload form, but with HTML5, you also have the option to let the user drag and drop a resource directly from the desktop. In this recipe, we'll explain how to provide this drag and drop functionality to your users.

Getting ready

The easiest way to prepare for this recipe is by first looking at the example we created for you. Open an example 01.14-drag-file-to-scene.html in your browser.

Note

Please note that this only works when running your own web server, or with security exceptions disabled.

When you drag and drop an image file onto the drop area (the dashed square), you'll immediately see that the texture of the rotating box is changed and the image that you provide is used.

In the following section, we'll explain how you can create this functionality.

How to do it...

To do this, please carry out the following steps:

  1. First, we have to set up the correct CSS and define the drop area. To create the dashed drop area, we add the following CSS to the style element in the head element of our page:

        #holder { border: 10px dashed #ccc; 
        width: 150px; height: 150px; 
        margin: 20px auto;}
        #holder.hover { border: 10px dashed #333; #333}

    As you can see in this CSS, we style the HTML element with ID holder to have a dashed border. The HTML for the holder div element is shown next:

      <body>
        <div id="holder"></div>
      </body>

    The drop area has been defined, so the next step is to add drag and drop the functionality to it.

  2. Then, we have to assign the correct event handlers so that we can respond to the various drag and drop related events.

  3. Just as in our previous recipes, we defined a function that contains all the required logic:

        function setupDragDrop() {
          var holder = document.getElementById('holder');
       
          holder.ondragover = function() {
            this.className = 'hover';
            return false;
          };
    
          holder.ondragend = function() {
            this.className = '';
            return false;
          };
    
          holder.ondrop = function(e) {
            ...
          }
        }

    In this code fragment, we defined three event handlers. The holder.ondragover event handler sets the class on the div element to 'hover'. This way, the user can see that they are allowed to drop the file there. The holder.ondragend event handler is called when the user moves away from the drop area. In the event handler, we remove the class of the div element. Finally, if the user drops a file in the designated area, the holder.ondrop function is called, which we use to process the dropped image.

  4. The final step is to process the dropped resource and update the material of our box. When a user drops a file, the following piece of code is executed:

          this.className = '';
          e.preventDefault();
    
          var file = e.dataTransfer.files[0],
          var reader = new FileReader();
          reader.onload = function(event) {
            holder.style.background = 
            'url(' + event.target.result + ') no-repeat center';
    
            var image = document.createElement('img');
            image.src = event.target.result;
            var texture = new THREE.Texture(image);
            texture.needsUpdate = true;
    
            scene.getObjectByName('cube').material.map = texture;
          };
          reader.readAsDataURL(file);
          return false;

    The first thing that happens is that we call e.preventDefault(). We need to do this to make sure that the browser doesn't just show the file, since that is its normal behavior. Next, we look at the event and retrieve the dropped file using e.dataTransfer.files[0]. We can't really do much with the file itself, since Three.js can't work directly with those, so we have to convert it to an img element. For this, we use a FileReader object. When the reader is done loading, we use the content to create this img element. This element is then used to create the THREE.Texture object, which we set as material for our box.

How it works...

Drag and drop functionality isn't something that is supported by Three.js out of the box. As we saw in the previous section, we use the standard HTML5 drag and drop related events. A good overview of what events are available can be found in the official HTML5 documentation at http://www.w3.org/TR/html5/editing.html#drag-and-drop-processing-model.

One interesting thing to note is the addition of texture.needsUpdate = true to the ondrop event handler. The reason we need to set this property of the texture is to inform Three.js that our texture has changed. This is needed because WebGL and also Three.js caches textures for performance reasons. If we change a texture, we have to set this property to true to make sure that WebGL knows what to render.