What is a good approach to "attaching" GUI controls such as forms, buttons, checkboxes etc to objects in a three.js scene?
i.e., I'd like to show a 3D model, let the user click and pick things in that model, and see a pop-up menu that leads him to forms that let him set its properties, do other actions etc.
(A rough equivalent probably would be Nifty GUI if I were to use JMonkeyEngine.)
I use jQuery UI components with the Three.js raycaster.
In my HTML:
<div id="main-canvas">
<div id="interface">
markup for your various modals, etc...
</div>
</div>
I use the raycasting example from Mr. Doob here to handle clicks on my canvas. If the ray hits an object I fire off pieces of code for the jQuery UI components. For example, fire open a modal when the user clicks on a planet sphere object. In the modal you can trigger things to happen in your WebGL canvas.
Since my application takes up the entire window, I had to do some CSS to make sure the nested interface div didn't cause any scrollbars.
body {
background-color: black;
margin: 0px;
}
div#interface {
position:absolute;
width: 100%;
}
This has been working really well for me.
dat.GUI is a popular library among Three.js users for such things: http://code.google.com/p/dat-gui/ It's even included in Three.js distribution, under /examples/js/libs/
Here's one example of it in use: http://jabtunes.com/labs/3d/dof/webgl_postprocessing_dof2.html
The only problem I've found is that it is hard to create custom controls/widgets if you are not happy with the built-in controls. It's still pretty good.
For selecting/activating objects with mouse, there's plenty of information, just google "three.js picking" or something.
Related
I've been given a design to implement which has a lightbox which has some content inside which includes links. This is all fine and working except for when it comes to iOS where it's not possible to interact with the content of a lightbox if its position happens to be on top of a video.
It's acting as though the video is on top of the lightbox content - even though it's behind. The issue occurs even with extremely simple barebones HTML.
Stripped back HTML:
<video id="home_video" controls preload="none" poster="http://www.videojs.com/img/poster.jpg" width="500">
<!-- video sources -->
</video>
<!-- positioned over the video -->
<div id="lightbox">
Not touchable on iOS
Touchable because it's not over a video
</div>
Associated stripped back styling:
#lightbox {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(255,255,255,0.5);
}
#lightbox > a {
display: inline-block;
background: red;
padding: 20px;
}
#touchable {
margin-top: 400px; /* taller than video */
}
I've put together a jsfiddle example. It includes some JS which alerts when you've successfully clicked/touched a link. On desktop browsers it's possible to click both links, on iOS it's only possible to click the second.
It might be worth noting that the issue occurs whether the lightbox is pre-opened on page, or after being explicitly opened as in this jsfiddle
I can think of a number of ways of hacking around the problem - such as moving the video off screen, replacing it with its poster image, or by transforming the video using translateX to hide it, but I'd prefer to leave the video where it is, if possible.
Has anyone stumbled across this issue before and found a solution? Any pointers?
This is a quirk of Mobile Safari, where it intercepts all touch/click events for elements on top of a video element, regardless of z-index or DOM order, only when the controls attribute is set.
So the solution is to remove the controls attribute and implement your own custom controls wit Javascript. You can use existing open source players to provide these controls for you (e.g. jPlayer, videojs, etc.), but you need to be careful because some of them have a special case for iOS where they will just use the native player controls. I think this is because it's simpler than making those mouse-centric controls work with the quirks of iOS (like touch and lack of volume control). So you need to check the documentation to see if there's a flag to force the player to use its own controls rather than the built-in ones.
Are there any issues surrounding the use of contenteditable div elements in jQuery UI that lead to the caret not appearing. Here is a bit of code to show what I mean
<div id='diaHTMLEd' style='display:none'>
<div id='divRTE'></div>
<!--iframe src='xrte.html' height='300' width='500'></iframe-->
</div>
function openHTMLEditor( {
$('#diaHTMLEd').dialog({
height:200,
width:450,
modal:true,
open:addRTE
});
}
function addRTE() {
$('#divRTE').html("<div contenteditable='true'>Testing</div>");
return;
}
Explanation - I am opening up a modal jqUI dialog and in its :open event am adding a contenteditable div element to an inner div in the dialog. The text shows up but it does not become editable when clicked. If I replace that code and use the commented out iframe instead which contains an contenteditable drive everything works just fine.
It looks like there is something that stops content from becoming editable inside the dialog.
This question may be lacking in some detail but given the complexity of my application I am not really in a position to provide more representative code. Any help would be much appreciated.
A note for anyone running into this thread. After much work I eventually discovered the issue. Using contenteditable with jQuery UI dialogs is not by itself a problem. The problem in my case came down to some sort of conflict with the excellent jstree plugin which I am using.
As a general rule - in complex applications that use multiple plugins you are probably better off sandboxing contenteditable content inside an iframe
I have an issue where due to some elements loading faster than others, the page looks broken for a few seconds at the start. An example is the CSS Pie behavior that allows me to do curved corners in IE, it appears before it becomes curved which looks bad. What would be ideal would be it somehow knowing when everything is loaded and then appear all at once, possibly including some kind of elegant visual way of not making the user feel impatient... any ideas or common tricks for doing this?
You could add a css class to the <body> tag by default and use some javascript to remove that css class once the page is loaded?
<body class="notready" onload="this.className = '';">
</body>
with some css classes defined to hide the things you do not want to show just yet:
body.notready .myclassname { display: none; }
This is going to be fairly hard to explain, so I've put together a JsFiddle to help demonstrate. http://jsfiddle.net/j5TKr/
I've tried to include everything that I require without complicating it too much. The overall aim is to have a list of li's which can be selected (single click, ctrl-click, shift-click) or double-clicked to be opened. The selected li's can be dragged around (so that they can be moved into other folders). The JsFiddle doesn't have the li's being grouped together correctly, but I'm not worried about that as it is actually working correctly.
The problem that I have is that in Google Chrome and IE (and possibly other browsers - not Firefox) you can't drag the li's around using the image within the anchor. Or more specifically, in Chrome it doesn't drag until you release the mouse button. If I remove the image (the "This one works" text link) it works. If you drag using the image information below the actual anchor, it works as well.
I gather it's a problem to do with me wanting to be able to click and select li's without actually opening the links.
Sorry if this is all a bit confusing. I'll answer any questions that come up.
Here’s an HTML workaround effective in IE and Google Chrome.
Instead of marking your draggable elements up like so:
<div class="icon">
<a title="assets" href="[link]">
<img src="[image]" />
</a>
</div>
Mark them up like so:
<div
class="icon"
style="width: 90px; height: 90px; background: url('[image]')">
</div>
(You could, of course, separate the added CSS from the HTML.)
I use this in my Index.aspx:
<%= Html.StandardOverlayCreateButton() %>
<div class="apple_overlay" id="overlay">
<div class="contentWrap">
</div>
</div>
Which is translating into this:
<button type="button">Create</button>
<div class="apple_overlay" id="overlay">
<div class="contentWrap">
</div>
</div>
When you press the button the popup with the Create.aspx occurs. Look at this -> Loading external pages into overlay
For me it seems that the overlay performance is slow.
And there is some strange behaviour, because I can nearly everytime see the old values in the popup. If I click the edit button and then close the popup and click another edit button, I can see the old values for a short time.
Is there a better approach of doing a popup using ASP.NET MVC and jQuery?
Are there tutorials?
Everything is being done client-side so the performance is purely down to JavaScript and jQuery code and nothing to do with any server-side code such as ASP.NET MVC.
You're using quite a few sophisticated effects with that popup, I see <div /> resizing animations, transparency, drop-shadows, the works. JavaScript performance has come on leaps and bounds with recent browsers, but it's performance but still be slow for doing very extravagant visual effects. Have you tried tuning down the visual effects with whatever modal popup JavaScript library you're using.
"And there is some strange behaviour,
because I can nearly everytime see the
old values in the popup. If I click
the edit button and then close the
popup and click another edit button, I
can see the old values for a short
time."
I assume the pop-up is actually loading an iframe which points to the 'Employee/Create' page. My guess is that when the pop-up is closed and then re-opened again with a different page, the previous page will still be sitting in the pop-up's iframe, and the "load-new-page/url" event isn't fired until the pop-up re-appears, hence why you're seeing the old page very briefly.
I had a similar problem to this, you need to tune the modal pop-up behaviour slightly so that it first loads the new page then opens the pop-up, rather than the other way around which is what it's currently doing. My solution to this was a bit hacky in that the page inside the iframe has an $(document).ready({}); event that called some JavaScript function the the iframe's parent to load the pop-up. eg. put this in your page that sits inside the iframe:
<script type="text/javascript">
$(document).ready(function()
{
window.parent.openPopup();
});
</script>
Then you need to define the 'openPopup()' JavaScript method in the iframe's parent (ie. the main page the lists your records).
do you really need the animation?
maybe you don't need the effect: 'apple' attribute?
Effects are slow, especially on IE.
http://flowplayer.org/tools/overlay/index.html#api
Look here - different post but answer is related to your question about MVC & jQuery.