Three.js - mixing WebGL and CSS3D with iFrame - javascript

I prepared a working page that mixes WebGL and CSS3D (with a little help from SO here), and it works great. I throw in an iframe for good measure:
But it lacks the ability to interact with the iframe.
In mrdoobs pure CSS3D demo one can even scroll the pages and mark text etc:
As it seems, the combination of WebGL in front of the CSS3D renderer hinders the interaction. Is there a way around this?
Thanks,
Dirk

You can apply CSS pointer-events:none to the WebGL node, so that events go through it to reach the underlying CSS3D nodes and iframe.
You are currently attaching THREE.TrackballControls to the document itself, so no change is needed there.
Note that events over an iframe, are dispatched directly to the iframe. The parent frame cannot directly observe these, catch and forward them, or send synthetic ones. So you lose navigation control events while the pointer is over an iframe. Mousewheel events have been an exception to this in Google Chrome (forked WebKit), but perhaps not for much longer (2016-Feb). To maintain smooth navigation control, one approach is to cover the iframe with a (possibly gray) transparent div when it's "not in use". And remove this cover when you believe the user wishes to interact with the iframe, either because of a click, or based on the pointer's trajectory. A click event sequence can be split, with the parent catching the mousedown, and uncovering to leave the mouseup and click events for the iframe - but it's an imperfect illusion, depending on the the iframed site to not care about seeing the mousedown.

The issues is likely that the iframe is now covered by another element capturing mousewheel events (the whole canvas or css3d div with trackball controls).
SOLUTION 1
If that is the case you need to put an invisible plane in the webgl scene that matches the css3d object and listen for mousewheel events on the window. When a mousewheel event occurs, use a raycaster (see mr doob interactive objects examples) to see if you're hitting this invisible plane. And finally before adding the plane to the scene, you should add the element you want to control as a property of the webgl plane that gets hit by the ray. This way you can easily look it up from the intersect.
SOLUTION 2
Keep track of a point where your iframe is, and measure the distance to the iframe using THREE.Vector3().distanceTo(otherVector3). If it's close enough then scroll the iframe. You still need to listen on the window for mousewheel events.
NOTE: This does not make the iframe FULLY interactive, only for the events you capture and then trigger / pass on.
NOTE: You cannot scroll cross domain iframes...

Ok, I don't know if this will answer your question, but I just finished trying this out. The simplest solution for me was to make the WEB GL RENDER'S dom element style invisible.
As long as you have the Three.Vector2() set up you're good to go. I hope this helps.
http://adndevblog.typepad.com/cloud_and_mobile/2015/07/embedding-webpages-in-a-3d-threejs-scene.html

Related

Enable page scrolling on <canvas> element

Currently a canvas element (which is built by a third party) on my webpage is intercepting drag events (because it assumes you want to drag something within the canvas), but this can "trap" the user within the canvas, especially if they zoomed in on it on mobile. I want the user to be able to scroll/swipe up and down on the canvas to reach the rest of the page above and below it, just like it were any other HTML element. They should be able to click into the canvas still, I just don't want the canvas to intercept regular page scrolling.
EDIT: I was able to find wheel and mousewheel events in the third-party code and remove them from the canvas object, resolving the issue for desktop users. Which event would be relevant for mobile users? I tried removing touchmove without success.
your issue seems to be that you're not correctly differentiating between scrolling and dragging.
I suggest you only prevent the default scrolling when the dragging actually takes place

how do I recreate the sencha style gesture scroll for lists and content?

So... I am working on an interaction design project and I want to create a sencha-style gesture scroll for content areas. The way I've done it so far, is to attach touchmove/start/end events to the content area, and it translateY's the contents. It works in on desktop with mousemove/up/down events, but it jumps around like crazy with touch. I'm not sure whats wrong.. here is a link to a prototype.
**requires webkit.
http://apps.omorphos.com/gesture-scroll
I think it is an issue with the event response, but I tried and haven't been able to nail it down. Any help is greatly appreciated!
So, I figured this out.
What I was doing was attaching the touch event to the list tag itself.. and, that works fine on desktop with mouse events; however, with touch, the target changes and touchend doesn't fire properly.
So, what I did, and what I believe sencha does, ... and I had originally implemented but went in a different direction... is have an absolutely positioned element with a transparent background color floating above the element that will be manipulated. All of the touch events will be captured by that DIV and then the elements below can be manipulated without losing the event data.
In the new version I used HammerJs ... more info: http://eightmedia.github.io/hammer.js/
but i'm pretty sure you could just use standard events; but the good thing about hammer js, is that it will translate touch events to mouse events for testing in the browser, this also means making the coordinates for touch the same as mouse, so you can access mouse event coords via
e.gesture.touches[0].pageX
e.gesture.touches[0].pageY
which let's you write less code.
Part 2:
Additionally... part of the issue is... how do you click on the content/components(e.g. links) below the screen.
How you do this... is you take the coords from the event handler and pass them through this native Javascript function...
var a = document.elementFromPoint(x, y);
this will return the dom element. and all you have to do is trigger the click/tap event.
Which would be great, except it will pick the element with the highest z-index.. so that is your screen obj(the one that is capturing all of the touch events). So, what you need to do, is hide the screen after a tap is registered, and then execute this function 200ms later, and then bring back the screen to capture whatever events.
You can do this with this function...
$(theScreen).on('tap', function(e){
screen.hide();
var hit = document.elementFromPoint(e.gesture.touches[0].pageX, e.gesture.touches[0].pageY);
$(hit)[0].tagName !=="A" || $(hit).trigger('click');
setTimeout(function(){screen.show()},300);
});
And, that is how I solved it!
My code is not super annotated, but you can find it at the link below:
Updated example:
http://apps.omorphos.com/gesture-scroll/v2/

jQuery Hover Over Image Content Only and Not Alpha

Perhaps the title isn't great, but I had a little trouble with the wording...
Basically, is it possible to have jQuery's hover only fire over the actual content of a png with an alpha channel.
So in the image below;
http://i.imgur.com/3kO7v.png
Only fire on the rectangle and not the alpha channel which make up the rest of the document bounds...
I've tried the obvious $('obj').hover(function(){stuff}) but this fires on the alpha channel too...
The final implementation of this will be for more complex shapes than just a rotated square, so css3 tricks are out for the primary basis, but could be used with a back-up/shim, plus I need to support IE7 and ipad,iphone,ipod....
If there is a CSS2 solution then that would be suitable too. Also any real guidance on this issue is more than welcome.
My backup for this will be to have an empty div, display block and position it over the shape and then use that. This will obviously not be ideal for the less square objects.
Any hits or tips are more than welcome.
Thank you
Yes it is possible depending on the stacking context of your elements. Keep in mind that when you do a focus over any particular element on a page, that you are actually focusing all other elements within the same stacking context.
So what you could do is either stop the event from bubbling up the stack (if the element you want to "hover" is lower in the stack that the elements you want to prevent hover effects on), or specifically put in prevent default for onhover events for all elements in the stacking context except for the one you want to actually get a hover effect.

Handle mouse event on irregular shaped objects with event delegation

I need to handle mouse events on a page where there are multiple irregular-shaped objects (for example, houses) are stacked on top of each other. If I use the normal way of event delegation jQuery .on(), the event source reported will always be the top most object, even if user clicked on the transparent part of the object (or image).
Example: <img> tag that contains the red triangle will always be the event source even if I click at the X position.
I can detect that mouse click is not inside the triangle. What I need is a way to "forward" the event to the green triangle below.
EDIT: My current approach is to catch the events on a big div that wraps everything, then use jQuery selector and compare coordinates to find out which object is under the mouse, then check if the mouse is in transparent part or not. It works fine, but seems to be slow and consume a lot of memory, especially with mouse move events being fired continuously.
EDIT 2:
This image was extracted from Building a game engine with jQuery, and my approach was almost identical to that. And now, this is the question:
Are you drawing complex graphics using plain HTML elements? Not sure about your exact needs, but it might make more sense to use SVG or Canvas, where catching click events on shapes becomes much easier.

multiple objects to render on very long area, canvas?

I need to display a very long area (without defined length) with many polygons (simple shapes - circles, squares, some text). Obviously I need only small fragment visible at a time. Main problems are efficient scrolling and handing mouse events. I write in GWT. Things i considered so far:
1) canvas. create a canvas with the size of visible area. Create buffer canvas larger then visible area. Render to the buffer (only changes - if something is changed in the visible area or new parts to the right/left during scrolling). And when required, render proper part of the buffer to visible canvas. This seems to work fast enough. But! I have to implement this smart buffering, decide which part needs to be rerendered and which not. And I need to remember all object to detect mouse clicks and mouseovers (and it should be some nice structure like interval tree or segment tree, as mouseover checks are very frequent - but this is already implemented in the browser, sounds like reinventing the wheel) - this is A LOT OF WORK!
Maybe there is something ready?
2) html (divs/images) - so, the idea is to render all elements with divs and images (images can be generated on canvas first, doesn't metter). Position them absolutely on a long div and use browser scrolling to scroll the div. Works until you reach the end of this long div and you need to reposition everything so there is more space to scroll (and this will freeze scrolling for some time). So maybe it would be possible to render in a second div in the meanwhile and then switch them.. It might work, but this sounds like a hack and it will probably have serious problems with multiple objects visible at a time. Plus for mouse events implemented in the browser.
3) SVG - I haven't tried, but I think I will run into the same performance problems as with html/divs (when scrolling to right/left)
Any ideas? Which approach is the best? Is there anything better? WebGL (it won't work in IE and porting to IE would be hard prob). How should I implement this?
You seem to understand the pros/cons. Canvas is faster, but it's lower level, so it's harder to code. DOM is slower but easier to code because of its event handling and object access. If DOM is too slow, you have to resort to canvas.
One possible compromise is to render the full canvas and clip it using overflow:hidden. That's what I did on a waveform display I am working on.
SVG should be easier than the DOM for shapes. Since SVG is not completely cross browser, you should use something like http://raphaeljs.com/
I would go with canvas as it's relatively fast.
As far as off-screen positioning, mouse events, and re-rendering — it could be all taken care of by using canvas library like Fabric.js. Take a look at the demos.
Event inspector demo & working with events tutorial might come in useful.
Off-screen (not) rendering is taken care of by default. Just position objects at off-screen coordinates and they won't be visible.

Categories

Resources