I'm experimenting with rotating/animating an environment using CSS3 and javascript. So I have a cube object with faces, which lives inside a "rotator" object, which is the object that gets interacted with in the UI. I want to make it so that when you click a face, it appends it to a div outside of the rotator div, but applies the transformation matrices to the object from its parents, so that it appears with the same orientation on the outside of the "rotator" as it did inside, but can be animated and become independent of the rest of the objects in the "rotator" div.
Here is the function for the click event that should do this:
This depends on several custom functions, please see the fiddle for full code and reference to functions.
jQuery('#top').on('click',function(){
if(jQuery(this).parent().is('#cube')){ // only do this if it isn't already detached
M = jQuery(this).getTransMatrix(); // get the local transform of this
M = M.multiply(jQuery('#rotator').getTransMatrix()); // multiply it by the rotator's transform to get the final transform
jQuery(this).appendTo('#container'); // move this to the container div outside of the rotator
jQuery(this).css(CSS3.prefix+'transition','none'); // make sure that style changes, etc happen instantly
// wtf here
console.log(M.cssTransformString()); // just to check, we see the transform string before it is assigned. It's what it should be in my tests
jQuery(this).css(CSS3.prefix+'transform',M.cssTransformString()); // we apply the string. The wrong transformation results. If I double-check it from the console, it is NOT the string from the previous line
}
});
If you check out the fiddle, you will be able to drag around to rotate the cube. Clicking on the face will have some effect. The top face with the star is the one in question. When clicked, simply does not apply the transformation. Even if I log to console the transform string it's about to apply, the next operation does NOT result in that string being applied. It simply does not stick. HOWEVER, if I click and drag slightly, then release with the cursor still on the face, THEN the transform sticks. I have tried tracing virtually everything and I cannot figure out why the transform is only sticking if you click normally (without holding/moving at all)
Fiddle here:
http://jsfiddle.net/spaceboycoop/PWkB9/
Related
I've been having difficulty getting the expected results with setChildIndex().
In this example I have 2 MovieClip instances named redDot and yellowDot, and a black square Shape. I would expect it to place yellowDot on bottom, then square, then redDot.
//make black rectangle shape
var square = new createjs.Shape(new createjs.Graphics().f("#000000").dr(100,100,100,100));
this.addChild(square);
this.setChildIndex(this.yellowDot, 0); //set z-index towards background
this.setChildIndex(square,1);
this.setChildIndex(this.redDot, 2);//towards foreground
Instead I get redDot, yellowDot, then square. Adding this.stop() to the end seems to change it back to the expected order. It's not clear to me what is causing this discrepancy. Looping is disabled in the publish settings. Am I misunderstanding how this function and the Animate timeline work?
I wonder if the stage is not being updated? What happens if you use stage.update() at the end of your code. (or however you update the stage in an animate script).
I believe calling this.stop() is re-rendering the initial state of the clip, which uses the original z-index definition. Probably makes sense to call it before you change the contents programmatically.
I have an object created from importing an .obj
I want to clone this object and give it it's own coordinates.
To be more precise, I have a wall, for which I attach another object (a window) as a child. It all works fine when dragging the window along the wall. Now, when I want to clone the wall and rotate it 180 degrees, dragging the child along it's parent goes exactly the opposite way from the mouse movement.
I would like to reuse the same obj wall for all sides of my building.
You are describing two problems.
One is how to clone an object and give it a different position:
var wallCopy = wall.clone();
scene.add(wallCopy);
wallCopy.position.set( 10,20,30 );
The other question is moving an object in Object space instead of World space.
I.e. if you change the position.x of an object (the window) that is a child of a rotated object, the object will move relative to its rotated parent.
If you are building some sort of editor, you can use SceneUtils to make this easier...
https://threejs.org/docs/#examples/utils/SceneUtils
At the start of your edit, you would detach the window and attach it to the scene, using SceneUtils.detach... then apply your edit movement, and when the movement is done, attach it back to the wall using SceneUtils.attach.
SceneUtils takes care of keeping the visual transform consistent between the detach and attach operations between different places on the scene hierarchy.
edit: So a way to handle the case you describe in comments, without doing anything fiddly, is to just use more intermediate nodes. You can always set up your scaling and stuff on the child nodes, (You can always update thier matrices and then set their matrixAutoUpdate = false; if you're paranoid about the performance impact.}
Here's what I mean:
{"root", scale:1, children:[anchor1, anchor2]}
{"anchor1" scale:1, children:[wall]} {"anchor2" scale:1, children:[wall2]}
Then you can just manipulate the anchors or root to move things around, and the scaling of "wall" will be isolated to its own little sub tree.
I have a group of elements that are masked by a rect in SnapSVG and I want to translate the elements, bringing new ones into view (and hiding ones that are currently in view). The code is really simple - here's a codepen: http://codepen.io/austinclemens/pen/ZbpVmX
As you can see from the pen, box1, which starts outside the mask element (clip) should cross through it when animated, but it never appears. Moreover, box2, which should move out of the clipping area, remains visible.
This example seems to do a similar thing and has no problems: http://svg.dabbles.info/snaptut-masks2
Here's the code from codepen:
var t = Snap('#target')
var clip=t.rect(200,200,200,200).attr({fill:'#fff'})
var box1=t.rect(300,100,50,50).attr({fill:'#000'})
var box2=t.rect(300,300,50,50).attr({fill:'#000'})
var boxgroup=t.group(box1,box2)
boxgroup.attr({mask:clip})
boxgroup.animate({transform:'t100,300'},2000)
I notice that the svg.dabbles examples translates the clip region by 0,0 at one point, but adding something like that doesn't seem to get me anywhere.
Ok, I figured this out thanks in part to this really great article about SVG transforms: http://sarasoueidan.com/blog/svg-transformations/
The upshot is that when I translate the box group, it takes the mask with it. This is a little confusing to me still - I guess the mask attribute is causing this somehow? Anyways, the solution is to apply an opposite translation to the mask to keep it in place. Check the pen to see it in action but basically I just had to add:
clip.animate({transform:'t-100,-300'},2000)
The tricky part of this is that you now need to synchronize the movement of the mask and the movement of the box group.
edit - I now demonstrate how synchronization can be achieved using snap's set.animate method on the codepen.
I've created a 'donut' chart originally from this jsfiddle, using raphael.
I have tweaked this script to suit my needs and currently have this being rendered.
My aim is to animate each slice (at the same time); for example make the blue slice grow to 60%; and the red slice shrink to 40%.
I have been able to redraw the slices by removing the existing one and quickly re-rendering a new one with adjusted values (e.g. 51, 49). But the problem here is that it is instant.
My question is,
(a) Can I animate this without the need to redraw the object (and how)?
(b) If not, how I can animate this effect using a redraw logic?
Yes. There is an example of doing this very thing on the Raphael demos page where you got the pie chart. See the Growing Pie demo.
You should separate the code in which you generate the path into a standalone function so you can use it later to return new paths. In order to use animate(), you'll need to define a function on the customAttributes object; it should return (at least) an object with the path property set to your slice's new path.
Since you have labels, you'll probably want to modify the code such that the pie slices expand/shrink relative to their center, so that you don't have to move the labels, too, since the labels are centered on their slice's "axis."
Update
Here's a JSFiddle with a simple example, pretty much the same as Dmitri's Growing Pie demo, except more like your chart. I export a setValue() method to change slice sizes and call it when the page loads. See his blog post about adding customAttributes, too.
In my last paragraph above, I was off the mark a bit. Your chart wasn't the one with labels; I had them mixed up. Also, it would be harder to keep slices centered, so I didn't do that after all. The animate() function sets each segment to its new starting and ending points on the circle, and Raphael figures out the intermediate points. As you can see, you can pass multiple arguments in an array.
this.customAttributes.slice = function(a0, a1) { /*...*/ }
// ...
chart.push(paper.path().attr({slice:[0, Math.PI/2 ]})
Can't see all the fiddle because I'm on iPod however it sounds like you need to have an animate call inside a function that you will need to write
Use the callback parameter that calls the function it sits inside.
Code your recursively called function so it eventually completes when all the work is done.
Each call to the function will happen at the end of every elapssed time interval you specify...
I'm working on a script to do several things. In a nutshell, here's what it needs to do:
Read the coordinates from a page and be able to pop up a box within a specific region.
The pop up box needs to be able to follow the mouse around.
I need to be able to modify the box to look however I want (I was thinking a div container that is set to display:hidden, and then the JS sets the display to block when your mouse is in the specified region).
I need to be able to modify it easily (aka, add and subtract objects and coordinate sets)
I was originally using HTML maps (), and that worked great, until I resized my browser, and the div that I had following the mouse no longer lined up correctly. Something about the offset not working correctly, and I couldn't get it to work correctly, so I switched to an HTML canvas.
And now I've got the coordinates in the canvas correctly, I just can't figure out how to get something to pop up when the mouse is inside of a certain section. Here's my current code:
function drawLines(numbers, color){
//poly [x,y, x,y, x,y.....];
var poly=numbers;
context.fillStyle = color;
context.beginPath();
context.moveTo(poly[0], poly[1]);
for( item=2 ; item < poly.length-1 ; item+=2 )
{context.lineTo( poly[item] , poly[item+1] )};
context.closePath();
context.fill();
}
I've got each region inside of an array, which I then pass to the function one by one. The color was a test, and I can easily get each region to show up as a specified color, but that doesn't solve my problem. Any ideas? Thanks!
Seems strange to jump to canvas over a style issue, but ignoring that...
You could bind mousemove events on the canvas element and then do hit tests on your region to see if the mouse is inside the region.
Doing the hit test efficiently might be tricky depending on the number of regions your testing, but it's definitely doable.
The canvas is just like any other block level element, so the same events apply and are bound in the same way.
Here's one example of mouse events interacting with canvas. In this example, the events are bound to the document, but similar ideas apply.
http://dev.opera.com/articles/view/blob-sallad-canvas-tag-and-javascrip/