Not Your Mother's Web3D:
Integrating X3DOM, jQuery and HTML5

by Sandy Ressler

National Institute of Standards and Technology

Web3D 2012, August 4-5, 2012

 

You can step through the slides with and

Hit the spacebar for an overview of the slideset (be patient wait for assets to load)

Disclaimer

Any mention of commercial products within this presentation or NIST web pages is for information only; it does not imply recommendation or endorsement by NIST.

The views expressed in this presentation are solely those of the author and do not represent any official views of NIST or the US Government.

Agenda

  • What is markup, DOM, jQuery, and X3DOM
  • Selecting DOM elements, events, moving around the DOM tree
  • Dynamically generating Geometry and Making it Interactive
  • Dynamically generating UI Controls
  • Annoying Integration Issues
  • Extending jQuery - Plugins for Dummies
  • Future

What is markup?

Markup is information that is embedded in the text of a document that is not intended for printing or display. It may consist of instructions to a printing device, commands for a Web browser, or comments to a coauthor. The form the markup takes is a function of the particular markup language used.

HTML important but not only markup language

XML

XHTML

SGML

I tend to use .xhtml because the browser (parsing) is way more informative about errors

Look Ma there's some 3D in my web pages!

What is the DOM?

  • DOM - Document Object Model
  • The structure of everything needed to render a page..and more!
  • Manipulating the DOM means you are manipulating page elements
  • Selecting elements of the DOM means you are selecting those elements of the page you wish to manipulate.

DOM Structure

dom structure

From http://www.iwein.co.uk/2006/05/30/dom-structure-visualized/

DOM Structure (simple document)

dom structure

From W3C http://www.w3.org/TR/2006/WD-DOM-Level-3-Events-20060413/events.html

DOM Events

dom events

From W3C http://www.w3.org/TR/2006/WD-DOM-Level-3-Events-20060413/events.html

DOM (HTML) Events

  • Web programming is "real time" programming
  • Actions are "event driven"
  • just like games!!
  • An event happens, you perform an action and (sometimes) you have a callback to maintain control, in an asyncronous manner
  • type of events: mouse, keyboard,

DOM Event Example here

Inside a <sphere> element define an "onclick" attribute

<sphere radius='0.26' > </sphere>
$('#dialog').html('You hit me');
onclick = "$('#dialog').html('You hit me'); "
jQuery dialogs lab

What is jQuery?

(and why should you care)

jQuery

robust, highly tested, interoperable, JavaScript framework to simplify your web development life

  • very powerful selection mechanism (selecting elements of the DOM)
  • jQuery utilizes CSS selection mechanism
    • $('sphere') - select all of the elements of type sphere
  • deals with many issues of browser interoperability
  • simplifies life with asyncronous issues (AJAX)
  • highly extensible

Selectorama

jQuery selectors lab

jQuery selectors

Selections

            radius='0.0125' 
            		onclick="$('#dialog').dialog('open'); 
                      $('#dialog').html('<p> You just selected the '+
                       $(this).parent().parent().attr('description') + 
                       ' landmark. </p>');
                      $('#dialog')
                      	.dialog( {title: $(this)
                        	.parent()
                            .parent()
                            .attr('description') });
                            
                      
            

select (pseudo english)

for each element of the type (shape)

do something fn()

Method Chaining

$('#sphere').parent().parent().attr('radius');

What is X3DOM

x3dom is not rocket science

Simply put: it's X3D in your web page

So what is X3D?

A declarative 3D markup language

...

X3D/X3DOM - Scene Graph

scene Graph

X3D/X3DOM - Event Model

Time (keeps on ticking)

X3D/X3DOM - Interactivity

X3DOM - the id versus DEF issue

  • In X3D geometry or other elements are named via the DEF construct
  • <Transform translation="1 2 3" DEF="boxTrans" >
  • Later on we might refer to it via <Transform USE="boxTrans" >
  • but HTML, the DOM and JavasScript don't know anything about the DEF/USE constructs
  • X3DOM solution is:

  • If both id and DEF are set both attrubutes will have different values
  • if only DEF is set that id is left unset
  • if only id is set then DEF and id are set to the same value

XXX Some real X3DOM code here

The case for declarative 3D markup

  • look at all that web infrastructure
  • separating content from style opens up ability for general style (origin of CSS -> DSSSL)
  • look at the CSS Zen Garden
  • Remember thouse jQuery selectors?

    Let's select geometry!

    $("#sphere")

    JSBIN demos/examples

    jsbin

    Dynamically generating geometry

    defining a sphere template
    
                     <sphere radius="0.0125" onclick="$("#dialog").dialog("open"); 
                          $(".timer").attr("cycleInterval","0");
                          $("#clock1").attr("cycleInterval","2.0");
                          $("#dialog").html("<p> You just selected the "+ $(this).parent().parent().attr("description") + " landmark. </p>");
                          $("#dialog").dialog( {title: $(this).parent().parent().attr("description") });" ></sphere>
                        </shape>
    
                    
    code to clone the landmark (sphere)
    
         function cloneLandmarks(idstr, matstr) {
    		for (var index = 0; index < OrigLandmarks[0].length; index++) {
    			$(".ball").each(function(index) {
                     newNum = new Number(index + 1);
                     newElem = $("#"+idstr+"0").clone().attr("id", "idstr" + newNum); 
                     newElem.attr("description", OrigLandmarks[0][index].description);
                     newElem.attr("translation", OrigLandmarks[0][index].translation);
                     
                     //2nd child of shape is sphere
                     
                     //replace clock1 with correct clock id
                     tmpObj = newElem.children().children(":nth-child(2)");
                     tmpClickStr = tmpObj.attr("onclick");
                     ntmpClickStr = tmpClickStr.replace(/clock1/i,"clock"+newNum);
                     newElem.children().children(":nth-child(2)").attr("onclick",ntmpClickStr);
                     //replace mat1 with mat id
                     newElem.children().children().children().attr("id",matstr+newNum);
                    $("#"+idstr+"0").after(newElem); // place the new transform
                   }
    	};
              
    Usage
    
                   cloneLandmarks('lm','mat');
                    

    Let's Generate that Geometry

    xxx example(s) here

    JavaScript DRY (Don't Repeat Yourself)

    Making Geometry Interactive

    Using the HTML onClick Event

    Using X3D's Touch events

    BUT Wait!! Which Event Works Better

    This is a point of intersection/conflict between X3DOM and the DOM that must be resolved

    Integrating UI elements

    This is how jQuery UI works

    jQuery UI Demos

    Dynamically generating user interface controls

    First some code to create some jQuery controls

    From x3dom site: jQuery Manipulation

    code for jQuery sliders manipulating 3D attributes

    
              <X3D xmlns="http://www.web3d.org/specifications/x3d-namespace" id="spheres" showStat="true" x="0px" y="0px" width="400px" height="400px" style="float:left;">
            <Scene DEF='scene'>
                <Viewpoint position='0 0 10' />
    			<Background skyColor='1 1 1' />
                <Transform id='trans'>
                    <Shape>
                        <Appearance>
                            <Material diffuseColor='0 0 0' specularColor='.2 .2 .2' />
                        </Appearance>
                        <Box DEF='box'/>
                    </Shape>
                </Transform>
            </Scene>
        </X3D>
    
        <div id="ctrlContainer">
            <p>Change the color of the cube using the RGB sliders, which updates the "diffuseColor" attribute of the Material node using jQuery.</p>
            <div id="sliderContainer">
                <ul>
                    <li><label>Red</label><div id="redSlider" class="slider"/></li>
                    <li><label>Green</label><div id="greenSlider" class="slider"/></li>
                    <li><label>Blue</label><div id="blueSlider" class="slider"/></li>
                </ul>
            </div>
        </div>
    
    
      <script type="text/javascript">
            $(document).ready(function(){
                // Create the sliders
                $(".slider").slider({min: 0, max: 1, step: 0.01, slide: function(e, ui) {
                    var newCol =   $("#redSlider").slider('option', 'value') + " " 
                                 + $("#greenSlider").slider('option', 'value') + " "  
                                 + $("#blueSlider").slider('option', 'value');              
                    $("Material").attr("diffuseColor", newCol);
                }});
            });
        </script>
    
             

    Programmatically creating controls

    AnthroGloss

    controls associated with graphical objects

    function to clone a button

    
    function cloneViewpointButtons() {
      $('#nameClone').show(); // show the button to clone	
      var Viewpoints = $("viewpoint");  //select all viewpoint elements and place into array
      // original source of clone button code
      // http://charlie.griefer.com/blog/index.cfm/2009/9/17/jQuery--Dynamically-Adding-Form-Elements
      
      //iterate through all of the viewpoints
      $("viewpoint").each( function(index) { 
        newNum = new Number(index + 1);
        newElem = $('#nameClone').clone().attr('id', 'name' + newNum); //clones only the button 
        newElem.attr('class', 'viewbutts'); // assign a classname to allow deletion of all but first button
        newElem.attr('value', $(this).attr('description'));
        
        //use the animate visual effect and
        //create an anonymous function to execute when button is clicked      
        newElem.button().click(function() {
          $(this).animate({opacity: 0.5}, 1500);
          $(Viewpoints[index]).attr('set_bind','true');  // this must be an actual viewpoint
    
          var descrip = $(Viewpoints[index]).attr('description');
          var htmlStr = "Current Viewpoint: " + descrip + "";
          $('#currViewpoint').html(htmlStr);
    });; 
          $('#nameClone').before(newElem); // place the new button after the old div
        });
        $('#nameClone').hide(); // hide the button to clone
    };	
                

    Some More Robust Examples

    CAESAR X3DOM

    Body Pose Flipper

    Let's Assemble this Thing

    What pieces do we need?

    • Libraries: jQuery, X3DOM, CSS files, fonts
    • HTML
    • code: JavaScript
    • IMPORTANT you must run on a web server! (for included "inline" files)

    Annoying Integration Issues

    name space, name space, name space

    Several types of HTML elements appear in global DOM namespace, and these can interfere with each other

    • Button elements all treated as global so the must be distinguigshed (can assign class name to solve this)

    • Dialog popups also get confused as global

    Illustrate button integration bug here

    So to fix the button integration bug...

    set of slides illustrating the button integration bug...vertical slides

    Couldn't change the viewpoint element because it's and ELEMENT and we need it.

    But we can add a new class "flipvp" to name only those viewpoint elements that we want to play with for this page

    Extending jQuery - plugIns for Dummies

    jqPlugTest.xhtml

    This is all the code for a jQuery plug-in

    
    (function($) {
    	$.fn.X3DOMgeomButton = function(options) {
    	// Extend our default options with those provided.
      	// Note that the first arg to extend is an empty object -
      	// this is to keep from overriding our "defaults" object.
      	var opts = $.extend({}, $.fn.X3DOMgeomButton.defaults, options);
    	// iterate  each matched element
      	return this.each(function() {
        	var base = $(this);
    		//var attribute = base.attr(opts);
    		var scaleOpt = opts.scale;
    		var onclickOpt = opts.onclick;
    		var diffuseColorOpt = opts.diffuseColor;
    		var translationOpt = opts.translation;
    				
    		if (scaleOpt) base.attr('scale',scaleOpt);
    		if (onclickOpt) base.attr('onclick',onclickOpt);
    		if (translationOpt) base.attr('translation',translationOpt);
    		// base is the transform then -> shape -> appearance -> material
    		if (diffuseColorOpt) base.children().children().children().attr('diffuseColor',diffuseColorOpt);
    		});
    	};
    		  
    	$.fn.X3DOMgeomButton.defaults = {
    		scale: '10 10 10',
    		onclick: 'alert("I am hit");',
    		diffuseColor: '0 1 0'
    		// do not want a default translation because generally objects exist where they should
    	};
    })(jQuery);
    
                                

    This is how to use the jQuery plug-in

    
    $('#tr0').X3DOMgeomButton(
    	{ onclick : 'alert("You hit id0 object")',
    				 diffuseColor: '0.5, 1, 1',
    				translation: '5 0 0'});
                    
    $('#tr1').X3DOMgeomButton({ onclick : 'alert("You hit id1 object")',
    				diffuseColor: '0.8 0 0',
    				scale: '10 1 10'});
                    
    $('#tr2').X3DOMgeomButton({ onclick : 'alert("You hit id2 object")',
    				diffuseColor: '0.8 0 0.8',
    				scale: '5 1 5'});
                

    jQuery plug-in Example

    The Future

    Look at D3 and what it does for SVG

    X3DOM and X3 from https://gist.github.com/ZJONSSON

    Useful Links

    Acknowledgements

    THE END

    please leave now ;-)

    twitter @email